summaryrefslogtreecommitdiff
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Kconfig6
-rw-r--r--drivers/char/agp/backend.c3
-rw-r--r--drivers/char/agp/hp-agp.c6
-rw-r--r--drivers/char/agp/intel-gtt.c32
-rw-r--r--drivers/char/apm-emulation.c21
-rw-r--r--drivers/char/hw_random/Kconfig28
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/atmel-rng.c158
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c33
-rw-r--r--drivers/char/random.c23
-rw-r--r--drivers/char/raw.c3
-rw-r--r--drivers/char/rtc.c7
-rw-r--r--drivers/char/scc.h613
-rw-r--r--drivers/char/tpm/tpm.c3
-rw-r--r--drivers/char/ttyprintk.c2
-rw-r--r--drivers/char/virtio_console.c120
16 files changed, 351 insertions, 708 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 423fd56bf612..43643033a3ae 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -298,7 +298,7 @@ if RTC_LIB=n
config RTC
tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)"
depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV \
- && !ARM && !SUPERH && !S390 && !AVR32 && !BLACKFIN
+ && !ARM && !SUPERH && !S390 && !AVR32 && !BLACKFIN && !UML
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -346,7 +346,7 @@ config JS_RTC
config GEN_RTC
tristate "Generic /dev/rtc emulation"
- depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH && !AVR32 && !BLACKFIN
+ depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH && !AVR32 && !BLACKFIN && !UML
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -490,7 +490,7 @@ config SCx200_GPIO
config PC8736x_GPIO
tristate "NatSemi PC8736x GPIO Support"
- depends on X86_32
+ depends on X86_32 && !UML
default SCx200_GPIO # mostly N
select NSC_GPIO # needed for support routines
help
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index f27d0d0816d3..4b71647782d0 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -171,7 +171,7 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
}
got_gatt = 1;
- bridge->key_list = vmalloc(PAGE_SIZE * 4);
+ bridge->key_list = vzalloc(PAGE_SIZE * 4);
if (bridge->key_list == NULL) {
dev_err(&bridge->dev->dev,
"can't allocate memory for key lists\n");
@@ -181,7 +181,6 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
got_keylist = 1;
/* FIXME vmalloc'd memory not guaranteed contiguous */
- memset(bridge->key_list, 0, PAGE_SIZE * 4);
if (bridge->driver->configure()) {
dev_err(&bridge->dev->dev, "error configuring host chipset\n");
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index 056b289a1e89..3695773ce7c3 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -336,7 +336,8 @@ hp_zx1_insert_memory (struct agp_memory *mem, off_t pg_start, int type)
off_t j, io_pg_start;
int io_pg_count;
- if (type != 0 || mem->type != 0) {
+ if (type != mem->type ||
+ agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) {
return -EINVAL;
}
@@ -380,7 +381,8 @@ hp_zx1_remove_memory (struct agp_memory *mem, off_t pg_start, int type)
struct _hp_private *hp = &hp_private;
int i, io_pg_start, io_pg_count;
- if (type != 0 || mem->type != 0) {
+ if (type != mem->type ||
+ agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) {
return -EINVAL;
}
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 85151019dde1..66cd0b8096ca 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -30,10 +30,10 @@
/*
* If we have Intel graphics, we're not going to have anything other than
* an Intel IOMMU. So make the correct use of the PCI DMA API contingent
- * on the Intel IOMMU support (CONFIG_DMAR).
+ * on the Intel IOMMU support (CONFIG_INTEL_IOMMU).
* Only newer chipsets need to bother with this, of course.
*/
-#ifdef CONFIG_DMAR
+#ifdef CONFIG_INTEL_IOMMU
#define USE_PCI_DMA_API 1
#else
#define USE_PCI_DMA_API 0
@@ -923,6 +923,9 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem,
{
int ret = -EINVAL;
+ if (intel_private.base.do_idle_maps)
+ return -ENODEV;
+
if (intel_private.clear_fake_agp) {
int start = intel_private.base.stolen_size / PAGE_SIZE;
int end = intel_private.base.gtt_mappable_entries;
@@ -985,6 +988,9 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem,
if (mem->page_count == 0)
return 0;
+ if (intel_private.base.do_idle_maps)
+ return -ENODEV;
+
intel_gtt_clear_range(pg_start, mem->page_count);
if (intel_private.base.needs_dmar) {
@@ -1177,6 +1183,25 @@ static void gen6_cleanup(void)
{
}
+/* Certain Gen5 chipsets require require idling the GPU before
+ * unmapping anything from the GTT when VT-d is enabled.
+ */
+extern int intel_iommu_gfx_mapped;
+static inline int needs_idle_maps(void)
+{
+ const unsigned short gpu_devid = intel_private.pcidev->device;
+
+ /* Query intel_iommu to see if we need the workaround. Presumably that
+ * was loaded first.
+ */
+ if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB ||
+ gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) &&
+ intel_iommu_gfx_mapped)
+ return 1;
+
+ return 0;
+}
+
static int i9xx_setup(void)
{
u32 reg_addr;
@@ -1211,6 +1236,9 @@ static int i9xx_setup(void)
intel_private.gtt_bus_addr = reg_addr + gtt_offset;
}
+ if (needs_idle_maps());
+ intel_private.base.do_idle_maps = 1;
+
intel_i9xx_setup_flush();
return 0;
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index a7346ab97a3c..f4837a893dfa 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -40,10 +40,7 @@
#define APM_MINOR_DEV 134
/*
- * See Documentation/Config.help for the configuration options.
- *
- * Various options can be changed at boot time as follows:
- * (We allow underscores for compatibility with the modules code)
+ * One option can be changed at boot time as follows:
* apm=on/off enable/disable APM
*/
@@ -300,17 +297,13 @@ apm_ioctl(struct file *filp, u_int cmd, u_long arg)
/*
* Wait for the suspend/resume to complete. If there
* are pending acknowledges, we wait here for them.
+ * wait_event_freezable() is interruptible and pending
+ * signal can cause busy looping. We aren't doing
+ * anything critical, chill a bit on each iteration.
*/
- freezer_do_not_count();
-
- wait_event(apm_suspend_waitqueue,
- as->suspend_state == SUSPEND_DONE);
-
- /*
- * Since we are waiting until the suspend is done, the
- * try_to_freeze() in freezer_count() will not trigger
- */
- freezer_count();
+ while (wait_event_freezable(apm_suspend_waitqueue,
+ as->suspend_state == SUSPEND_DONE))
+ msleep(10);
break;
case SUSPEND_ACKTO:
as->suspend_result = -ETIMEDOUT;
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 1d2ebc7a4947..0689bf6b0183 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -60,6 +60,19 @@ config HW_RANDOM_AMD
If unsure, say Y.
+config HW_RANDOM_ATMEL
+ tristate "Atmel Random Number Generator support"
+ depends on HW_RANDOM && ARCH_AT91SAM9G45
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on Atmel AT91 devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called atmel-rng.
+
+ If unsure, say Y.
+
config HW_RANDOM_GEODE
tristate "AMD Geode HW Random Number Generator support"
depends on HW_RANDOM && X86_32 && PCI
@@ -222,3 +235,18 @@ config HW_RANDOM_PPC4XX
module will be called ppc4xx-rng.
If unsure, say N.
+
+config UML_RANDOM
+ depends on UML
+ tristate "Hardware random number generator"
+ help
+ This option enables UML's "hardware" random number generator. It
+ attaches itself to the host's /dev/random, supplying as much entropy
+ as the host has, rather than the small amount the UML gets from its
+ own drivers. It registers itself as a standard hardware random number
+ generator, major 10, minor 183, and the canonical device name is
+ /dev/hwrng.
+ The way to make use of this is to install the rng-tools package
+ (check your distro, or download from
+ http://sourceforge.net/projects/gkernel/). rngd periodically reads
+ /dev/hwrng and injects the entropy into /dev/random.
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index c88f244c8a71..b2ff5265a996 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -7,6 +7,7 @@ rng-core-y := core.o
obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o
obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o
obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o
+obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o
obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o
n2-rng-y := n2-drv.o n2-asm.o
diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c
new file mode 100644
index 000000000000..241df2e76aba
--- /dev/null
+++ b/drivers/char/hw_random/atmel-rng.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2011 Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/hw_random.h>
+#include <linux/platform_device.h>
+
+#define TRNG_CR 0x00
+#define TRNG_ISR 0x1c
+#define TRNG_ODATA 0x50
+
+#define TRNG_KEY 0x524e4700 /* RNG */
+
+struct atmel_trng {
+ struct clk *clk;
+ void __iomem *base;
+ struct hwrng rng;
+};
+
+static int atmel_trng_read(struct hwrng *rng, void *buf, size_t max,
+ bool wait)
+{
+ struct atmel_trng *trng = container_of(rng, struct atmel_trng, rng);
+ u32 *data = buf;
+
+ /* data ready? */
+ if (readl(trng->base + TRNG_ODATA) & 1) {
+ *data = readl(trng->base + TRNG_ODATA);
+ return 4;
+ } else
+ return 0;
+}
+
+static int atmel_trng_probe(struct platform_device *pdev)
+{
+ struct atmel_trng *trng;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
+ if (!trng)
+ return -ENOMEM;
+
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), pdev->name))
+ return -EBUSY;
+
+ trng->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!trng->base)
+ return -EBUSY;
+
+ trng->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(trng->clk))
+ return PTR_ERR(trng->clk);
+
+ ret = clk_enable(trng->clk);
+ if (ret)
+ goto err_enable;
+
+ writel(TRNG_KEY | 1, trng->base + TRNG_CR);
+ trng->rng.name = pdev->name;
+ trng->rng.read = atmel_trng_read;
+
+ ret = hwrng_register(&trng->rng);
+ if (ret)
+ goto err_register;
+
+ platform_set_drvdata(pdev, trng);
+
+ return 0;
+
+err_register:
+ clk_disable(trng->clk);
+err_enable:
+ clk_put(trng->clk);
+
+ return ret;
+}
+
+static int __devexit atmel_trng_remove(struct platform_device *pdev)
+{
+ struct atmel_trng *trng = platform_get_drvdata(pdev);
+
+ hwrng_unregister(&trng->rng);
+
+ writel(TRNG_KEY, trng->base + TRNG_CR);
+ clk_disable(trng->clk);
+ clk_put(trng->clk);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int atmel_trng_suspend(struct device *dev)
+{
+ struct atmel_trng *trng = dev_get_drvdata(dev);
+
+ clk_disable(trng->clk);
+
+ return 0;
+}
+
+static int atmel_trng_resume(struct device *dev)
+{
+ struct atmel_trng *trng = dev_get_drvdata(dev);
+
+ return clk_enable(trng->clk);
+}
+
+static const struct dev_pm_ops atmel_trng_pm_ops = {
+ .suspend = atmel_trng_suspend,
+ .resume = atmel_trng_resume,
+};
+#endif /* CONFIG_PM */
+
+static struct platform_driver atmel_trng_driver = {
+ .probe = atmel_trng_probe,
+ .remove = __devexit_p(atmel_trng_remove),
+ .driver = {
+ .name = "atmel-trng",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &atmel_trng_pm_ops,
+#endif /* CONFIG_PM */
+ },
+};
+
+static int __init atmel_trng_init(void)
+{
+ return platform_driver_register(&atmel_trng_driver);
+}
+module_init(atmel_trng_init);
+
+static void __exit atmel_trng_exit(void)
+{
+ platform_driver_unregister(&atmel_trng_driver);
+}
+module_exit(atmel_trng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Atmel true random number generator driver");
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 3302586655c4..c2917ffad2c2 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -65,6 +65,7 @@
* mechanism for it at that time.
*/
#include <asm/kdebug.h>
+#include <asm/nmi.h>
#define HAVE_DIE_NMI
#endif
@@ -1077,17 +1078,8 @@ static void ipmi_unregister_watchdog(int ipmi_intf)
#ifdef HAVE_DIE_NMI
static int
-ipmi_nmi(struct notifier_block *self, unsigned long val, void *data)
+ipmi_nmi(unsigned int val, struct pt_regs *regs)
{
- struct die_args *args = data;
-
- if (val != DIE_NMIUNKNOWN)
- return NOTIFY_OK;
-
- /* Hack, if it's a memory or I/O error, ignore it. */
- if (args->err & 0xc0)
- return NOTIFY_OK;
-
/*
* If we get here, it's an NMI that's not a memory or I/O
* error. We can't truly tell if it's from IPMI or not
@@ -1097,15 +1089,15 @@ ipmi_nmi(struct notifier_block *self, unsigned long val, void *data)
if (testing_nmi) {
testing_nmi = 2;
- return NOTIFY_STOP;
+ return NMI_HANDLED;
}
/* If we are not expecting a timeout, ignore it. */
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
- return NOTIFY_OK;
+ return NMI_DONE;
if (preaction_val != WDOG_PRETIMEOUT_NMI)
- return NOTIFY_OK;
+ return NMI_DONE;
/*
* If no one else handled the NMI, we assume it was the IPMI
@@ -1120,12 +1112,8 @@ ipmi_nmi(struct notifier_block *self, unsigned long val, void *data)
panic(PFX "pre-timeout");
}
- return NOTIFY_STOP;
+ return NMI_HANDLED;
}
-
-static struct notifier_block ipmi_nmi_handler = {
- .notifier_call = ipmi_nmi
-};
#endif
static int wdog_reboot_handler(struct notifier_block *this,
@@ -1290,7 +1278,8 @@ static void check_parms(void)
}
}
if (do_nmi && !nmi_handler_registered) {
- rv = register_die_notifier(&ipmi_nmi_handler);
+ rv = register_nmi_handler(NMI_UNKNOWN, ipmi_nmi, 0,
+ "ipmi");
if (rv) {
printk(KERN_WARNING PFX
"Can't register nmi handler\n");
@@ -1298,7 +1287,7 @@ static void check_parms(void)
} else
nmi_handler_registered = 1;
} else if (!do_nmi && nmi_handler_registered) {
- unregister_die_notifier(&ipmi_nmi_handler);
+ unregister_nmi_handler(NMI_UNKNOWN, "ipmi");
nmi_handler_registered = 0;
}
#endif
@@ -1336,7 +1325,7 @@ static int __init ipmi_wdog_init(void)
if (rv) {
#ifdef HAVE_DIE_NMI
if (nmi_handler_registered)
- unregister_die_notifier(&ipmi_nmi_handler);
+ unregister_nmi_handler(NMI_UNKNOWN, "ipmi");
#endif
atomic_notifier_chain_unregister(&panic_notifier_list,
&wdog_panic_notifier);
@@ -1357,7 +1346,7 @@ static void __exit ipmi_wdog_exit(void)
#ifdef HAVE_DIE_NMI
if (nmi_handler_registered)
- unregister_die_notifier(&ipmi_nmi_handler);
+ unregister_nmi_handler(NMI_UNKNOWN, "ipmi");
#endif
atomic_notifier_chain_unregister(&panic_notifier_list,
diff --git a/drivers/char/random.c b/drivers/char/random.c
index c35a785005b0..63e19ba56bbe 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -932,7 +932,21 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
*/
void get_random_bytes(void *buf, int nbytes)
{
- extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);
+ char *p = buf;
+
+ while (nbytes) {
+ unsigned long v;
+ int chunk = min(nbytes, (int)sizeof(unsigned long));
+
+ if (!arch_get_random_long(&v))
+ break;
+
+ memcpy(buf, &v, chunk);
+ p += chunk;
+ nbytes -= chunk;
+ }
+
+ extract_entropy(&nonblocking_pool, p, nbytes, 0, 0);
}
EXPORT_SYMBOL(get_random_bytes);
@@ -1318,9 +1332,14 @@ late_initcall(random_int_secret_init);
DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash);
unsigned int get_random_int(void)
{
- __u32 *hash = get_cpu_var(get_random_int_hash);
+ __u32 *hash;
unsigned int ret;
+ if (arch_get_random_int(&ret))
+ return ret;
+
+ hash = get_cpu_var(get_random_int_hash);
+
hash[0] += current->pid + jiffies + get_cycles();
md5_transform(hash, random_int_secret);
ret = hash[0];
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index b33e8ea314ed..b6de2c047145 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -324,13 +324,12 @@ static int __init raw_init(void)
max_raw_minors = MAX_RAW_MINORS;
}
- raw_devices = vmalloc(sizeof(struct raw_device_data) * max_raw_minors);
+ raw_devices = vzalloc(sizeof(struct raw_device_data) * max_raw_minors);
if (!raw_devices) {
printk(KERN_ERR "Not enough memory for raw device structures\n");
ret = -ENOMEM;
goto error;
}
- memset(raw_devices, 0, sizeof(struct raw_device_data) * max_raw_minors);
ret = register_chrdev_region(dev, max_raw_minors, "raw");
if (ret)
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index dfa8b3062fda..ccd124ab7ca7 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -80,6 +80,7 @@
#include <linux/bcd.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
+#include <linux/ratelimit.h>
#include <asm/current.h>
#include <asm/system.h>
@@ -1195,10 +1196,8 @@ static void rtc_dropped_irq(unsigned long data)
spin_unlock_irq(&rtc_lock);
- if (printk_ratelimit()) {
- printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
- freq);
- }
+ printk_ratelimited(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
+ freq);
/* Now we have new data */
wake_up_interruptible(&rtc_wait);
diff --git a/drivers/char/scc.h b/drivers/char/scc.h
deleted file mode 100644
index 341b1142bea8..000000000000
--- a/drivers/char/scc.h
+++ /dev/null
@@ -1,613 +0,0 @@
-/*
- * atari_SCC.h: Definitions for the Am8530 Serial Communications Controller
- *
- * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- *
- */
-
-
-#ifndef _SCC_H
-#define _SCC_H
-
-#include <linux/delay.h>
-
-/* Special configuration ioctls for the Atari SCC5380 Serial
- * Communications Controller
- */
-
-/* ioctl command codes */
-
-#define TIOCGATSCC 0x54c0 /* get SCC configuration */
-#define TIOCSATSCC 0x54c1 /* set SCC configuration */
-#define TIOCDATSCC 0x54c2 /* reset configuration to defaults */
-
-/* Clock sources */
-
-#define CLK_RTxC 0
-#define CLK_TRxC 1
-#define CLK_PCLK 2
-
-/* baud_bases for the common clocks in the Atari. These are the real
- * frequencies divided by 16.
- */
-
-#define SCC_BAUD_BASE_TIMC 19200 /* 0.3072 MHz from TT-MFP, Timer C */
-#define SCC_BAUD_BASE_BCLK 153600 /* 2.4576 MHz */
-#define SCC_BAUD_BASE_PCLK4 229500 /* 3.6720 MHz */
-#define SCC_BAUD_BASE_PCLK 503374 /* 8.0539763 MHz */
-#define SCC_BAUD_BASE_NONE 0 /* for not connected or unused
- * clock sources */
-
-/* The SCC clock configuration structure */
-
-struct scc_clock_config {
- unsigned RTxC_base; /* base_baud of RTxC */
- unsigned TRxC_base; /* base_baud of TRxC */
- unsigned PCLK_base; /* base_baud of PCLK, both channels! */
- struct {
- unsigned clksrc; /* CLK_RTxC, CLK_TRxC or CLK_PCLK */
- unsigned divisor; /* divisor for base baud, valid values:
- * see below */
- } baud_table[17]; /* For 50, 75, 110, 135, 150, 200, 300,
- * 600, 1200, 1800, 2400, 4800, 9600,
- * 19200, 38400, 57600 and 115200 bps.
- * The last two could be replaced by
- * other rates > 38400 if they're not
- * possible.
- */
-};
-
-/* The following divisors are valid:
- *
- * - CLK_RTxC: 1 or even (1, 2 and 4 are the direct modes, > 4 use
- * the BRG)
- *
- * - CLK_TRxC: 1, 2 or 4 (no BRG, only direct modes possible)
- *
- * - CLK_PCLK: >= 4 and even (no direct modes, only BRG)
- *
- */
-
-struct scc_port {
- struct gs_port gs;
- volatile unsigned char *ctrlp;
- volatile unsigned char *datap;
- int x_char; /* xon/xoff character */
- int c_dcd;
- int channel;
- struct scc_port *port_a; /* Reference to port A and B */
- struct scc_port *port_b; /* structs for reg access */
-};
-
-#define SCC_MAGIC 0x52696368
-
-/***********************************************************************/
-/* */
-/* Register Names */
-/* */
-/***********************************************************************/
-
-/* The SCC documentation gives no explicit names to the registers,
- * they're just called WR0..15 and RR0..15. To make the source code
- * better readable and make the transparent write reg read access (see
- * below) possible, I christen them here with self-invented names.
- * Note that (real) read registers are assigned numbers 16..31. WR7'
- * has number 33.
- */
-
-#define COMMAND_REG 0 /* wo */
-#define INT_AND_DMA_REG 1 /* wo */
-#define INT_VECTOR_REG 2 /* rw, common to both channels */
-#define RX_CTRL_REG 3 /* rw */
-#define AUX1_CTRL_REG 4 /* rw */
-#define TX_CTRL_REG 5 /* rw */
-#define SYNC_ADR_REG 6 /* wo */
-#define SYNC_CHAR_REG 7 /* wo */
-#define SDLC_OPTION_REG 33 /* wo */
-#define TX_DATA_REG 8 /* wo */
-#define MASTER_INT_CTRL 9 /* wo, common to both channels */
-#define AUX2_CTRL_REG 10 /* rw */
-#define CLK_CTRL_REG 11 /* wo */
-#define TIMER_LOW_REG 12 /* rw */
-#define TIMER_HIGH_REG 13 /* rw */
-#define DPLL_CTRL_REG 14 /* wo */
-#define INT_CTRL_REG 15 /* rw */
-
-#define STATUS_REG 16 /* ro */
-#define SPCOND_STATUS_REG 17 /* wo */
-/* RR2 is WR2 for Channel A, Channel B gives vector + current status: */
-#define CURR_VECTOR_REG 18 /* Ch. B only, Ch. A for rw */
-#define INT_PENDING_REG 19 /* Channel A only! */
-/* RR4 is WR4, if b6(MR7') == 1 */
-/* RR5 is WR5, if b6(MR7') == 1 */
-#define FS_FIFO_LOW_REG 22 /* ro */
-#define FS_FIFO_HIGH_REG 23 /* ro */
-#define RX_DATA_REG 24 /* ro */
-/* RR9 is WR3, if b6(MR7') == 1 */
-#define DPLL_STATUS_REG 26 /* ro */
-/* RR11 is WR10, if b6(MR7') == 1 */
-/* RR12 is WR12 */
-/* RR13 is WR13 */
-/* RR14 not present */
-/* RR15 is WR15 */
-
-
-/***********************************************************************/
-/* */
-/* Register Values */
-/* */
-/***********************************************************************/
-
-
-/* WR0: COMMAND_REG "CR" */
-
-#define CR_RX_CRC_RESET 0x40
-#define CR_TX_CRC_RESET 0x80
-#define CR_TX_UNDERRUN_RESET 0xc0
-
-#define CR_EXTSTAT_RESET 0x10
-#define CR_SEND_ABORT 0x18
-#define CR_ENAB_INT_NEXT_RX 0x20
-#define CR_TX_PENDING_RESET 0x28
-#define CR_ERROR_RESET 0x30
-#define CR_HIGHEST_IUS_RESET 0x38
-
-
-/* WR1: INT_AND_DMA_REG "IDR" */
-
-#define IDR_EXTSTAT_INT_ENAB 0x01
-#define IDR_TX_INT_ENAB 0x02
-#define IDR_PARERR_AS_SPCOND 0x04
-
-#define IDR_RX_INT_DISAB 0x00
-#define IDR_RX_INT_FIRST 0x08
-#define IDR_RX_INT_ALL 0x10
-#define IDR_RX_INT_SPCOND 0x18
-#define IDR_RX_INT_MASK 0x18
-
-#define IDR_WAITREQ_RX 0x20
-#define IDR_WAITREQ_IS_REQ 0x40
-#define IDR_WAITREQ_ENAB 0x80
-
-
-/* WR3: RX_CTRL_REG "RCR" */
-
-#define RCR_RX_ENAB 0x01
-#define RCR_DISCARD_SYNC_CHARS 0x02
-#define RCR_ADDR_SEARCH 0x04
-#define RCR_CRC_ENAB 0x08
-#define RCR_SEARCH_MODE 0x10
-#define RCR_AUTO_ENAB_MODE 0x20
-
-#define RCR_CHSIZE_MASK 0xc0
-#define RCR_CHSIZE_5 0x00
-#define RCR_CHSIZE_6 0x40
-#define RCR_CHSIZE_7 0x80
-#define RCR_CHSIZE_8 0xc0
-
-
-/* WR4: AUX1_CTRL_REG "A1CR" */
-
-#define A1CR_PARITY_MASK 0x03
-#define A1CR_PARITY_NONE 0x00
-#define A1CR_PARITY_ODD 0x01
-#define A1CR_PARITY_EVEN 0x03
-
-#define A1CR_MODE_MASK 0x0c
-#define A1CR_MODE_SYNCR 0x00
-#define A1CR_MODE_ASYNC_1 0x04
-#define A1CR_MODE_ASYNC_15 0x08
-#define A1CR_MODE_ASYNC_2 0x0c
-
-#define A1CR_SYNCR_MODE_MASK 0x30
-#define A1CR_SYNCR_MONOSYNC 0x00
-#define A1CR_SYNCR_BISYNC 0x10
-#define A1CR_SYNCR_SDLC 0x20
-#define A1CR_SYNCR_EXTCSYNC 0x30
-
-#define A1CR_CLKMODE_MASK 0xc0
-#define A1CR_CLKMODE_x1 0x00
-#define A1CR_CLKMODE_x16 0x40
-#define A1CR_CLKMODE_x32 0x80
-#define A1CR_CLKMODE_x64 0xc0
-
-
-/* WR5: TX_CTRL_REG "TCR" */
-
-#define TCR_TX_CRC_ENAB 0x01
-#define TCR_RTS 0x02
-#define TCR_USE_CRC_CCITT 0x00
-#define TCR_USE_CRC_16 0x04
-#define TCR_TX_ENAB 0x08
-#define TCR_SEND_BREAK 0x10
-
-#define TCR_CHSIZE_MASK 0x60
-#define TCR_CHSIZE_5 0x00
-#define TCR_CHSIZE_6 0x20
-#define TCR_CHSIZE_7 0x40
-#define TCR_CHSIZE_8 0x60
-
-#define TCR_DTR 0x80
-
-
-/* WR7': SLDC_OPTION_REG "SOR" */
-
-#define SOR_AUTO_TX_ENAB 0x01
-#define SOR_AUTO_EOM_RESET 0x02
-#define SOR_AUTO_RTS_MODE 0x04
-#define SOR_NRZI_DISAB_HIGH 0x08
-#define SOR_ALT_DTRREQ_TIMING 0x10
-#define SOR_READ_CRC_CHARS 0x20
-#define SOR_EXTENDED_REG_ACCESS 0x40
-
-
-/* WR9: MASTER_INT_CTRL "MIC" */
-
-#define MIC_VEC_INCL_STAT 0x01
-#define MIC_NO_VECTOR 0x02
-#define MIC_DISAB_LOWER_CHAIN 0x04
-#define MIC_MASTER_INT_ENAB 0x08
-#define MIC_STATUS_HIGH 0x10
-#define MIC_IGN_INTACK 0x20
-
-#define MIC_NO_RESET 0x00
-#define MIC_CH_A_RESET 0x40
-#define MIC_CH_B_RESET 0x80
-#define MIC_HARD_RESET 0xc0
-
-
-/* WR10: AUX2_CTRL_REG "A2CR" */
-
-#define A2CR_SYNC_6 0x01
-#define A2CR_LOOP_MODE 0x02
-#define A2CR_ABORT_ON_UNDERRUN 0x04
-#define A2CR_MARK_IDLE 0x08
-#define A2CR_GO_ACTIVE_ON_POLL 0x10
-
-#define A2CR_CODING_MASK 0x60
-#define A2CR_CODING_NRZ 0x00
-#define A2CR_CODING_NRZI 0x20
-#define A2CR_CODING_FM1 0x40
-#define A2CR_CODING_FM0 0x60
-
-#define A2CR_PRESET_CRC_1 0x80
-
-
-/* WR11: CLK_CTRL_REG "CCR" */
-
-#define CCR_TRxCOUT_MASK 0x03
-#define CCR_TRxCOUT_XTAL 0x00
-#define CCR_TRxCOUT_TXCLK 0x01
-#define CCR_TRxCOUT_BRG 0x02
-#define CCR_TRxCOUT_DPLL 0x03
-
-#define CCR_TRxC_OUTPUT 0x04
-
-#define CCR_TXCLK_MASK 0x18
-#define CCR_TXCLK_RTxC 0x00
-#define CCR_TXCLK_TRxC 0x08
-#define CCR_TXCLK_BRG 0x10
-#define CCR_TXCLK_DPLL 0x18
-
-#define CCR_RXCLK_MASK 0x60
-#define CCR_RXCLK_RTxC 0x00
-#define CCR_RXCLK_TRxC 0x20
-#define CCR_RXCLK_BRG 0x40
-#define CCR_RXCLK_DPLL 0x60
-
-#define CCR_RTxC_XTAL 0x80
-
-
-/* WR14: DPLL_CTRL_REG "DCR" */
-
-#define DCR_BRG_ENAB 0x01
-#define DCR_BRG_USE_PCLK 0x02
-#define DCR_DTRREQ_IS_REQ 0x04
-#define DCR_AUTO_ECHO 0x08
-#define DCR_LOCAL_LOOPBACK 0x10
-
-#define DCR_DPLL_EDGE_SEARCH 0x20
-#define DCR_DPLL_ERR_RESET 0x40
-#define DCR_DPLL_DISAB 0x60
-#define DCR_DPLL_CLK_BRG 0x80
-#define DCR_DPLL_CLK_RTxC 0xa0
-#define DCR_DPLL_FM 0xc0
-#define DCR_DPLL_NRZI 0xe0
-
-
-/* WR15: INT_CTRL_REG "ICR" */
-
-#define ICR_OPTIONREG_SELECT 0x01
-#define ICR_ENAB_BRG_ZERO_INT 0x02
-#define ICR_USE_FS_FIFO 0x04
-#define ICR_ENAB_DCD_INT 0x08
-#define ICR_ENAB_SYNC_INT 0x10
-#define ICR_ENAB_CTS_INT 0x20
-#define ICR_ENAB_UNDERRUN_INT 0x40
-#define ICR_ENAB_BREAK_INT 0x80
-
-
-/* RR0: STATUS_REG "SR" */
-
-#define SR_CHAR_AVAIL 0x01
-#define SR_BRG_ZERO 0x02
-#define SR_TX_BUF_EMPTY 0x04
-#define SR_DCD 0x08
-#define SR_SYNC_ABORT 0x10
-#define SR_CTS 0x20
-#define SR_TX_UNDERRUN 0x40
-#define SR_BREAK 0x80
-
-
-/* RR1: SPCOND_STATUS_REG "SCSR" */
-
-#define SCSR_ALL_SENT 0x01
-#define SCSR_RESIDUAL_MASK 0x0e
-#define SCSR_PARITY_ERR 0x10
-#define SCSR_RX_OVERRUN 0x20
-#define SCSR_CRC_FRAME_ERR 0x40
-#define SCSR_END_OF_FRAME 0x80
-
-
-/* RR3: INT_PENDING_REG "IPR" */
-
-#define IPR_B_EXTSTAT 0x01
-#define IPR_B_TX 0x02
-#define IPR_B_RX 0x04
-#define IPR_A_EXTSTAT 0x08
-#define IPR_A_TX 0x10
-#define IPR_A_RX 0x20
-
-
-/* RR7: FS_FIFO_HIGH_REG "FFHR" */
-
-#define FFHR_CNT_MASK 0x3f
-#define FFHR_IS_FROM_FIFO 0x40
-#define FFHR_FIFO_OVERRUN 0x80
-
-
-/* RR10: DPLL_STATUS_REG "DSR" */
-
-#define DSR_ON_LOOP 0x02
-#define DSR_ON_LOOP_SENDING 0x10
-#define DSR_TWO_CLK_MISSING 0x40
-#define DSR_ONE_CLK_MISSING 0x80
-
-/***********************************************************************/
-/* */
-/* Register Access */
-/* */
-/***********************************************************************/
-
-
-/* The SCC needs 3.5 PCLK cycles recovery time between to register
- * accesses. PCLK runs with 8 MHz on an Atari, so this delay is 3.5 *
- * 125 ns = 437.5 ns. This is too short for udelay().
- * 10/16/95: A tstb st_mfp.par_dt_reg takes 600ns (sure?) and thus should be
- * quite right
- */
-
-#define scc_reg_delay() \
- do { \
- if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147) \
- __asm__ __volatile__ ( " nop; nop"); \
- else if (MACH_IS_ATARI) \
- __asm__ __volatile__ ( "tstb %0" : : "g" (*_scc_del) : "cc" );\
- } while (0)
-
-static unsigned char scc_shadow[2][16];
-
-/* The following functions should relax the somehow complicated
- * register access of the SCC. _SCCwrite() stores all written values
- * (except for WR0 and WR8) in shadow registers for later recall. This
- * removes the burden of remembering written values as needed. The
- * extra work of storing the value doesn't count, since a delay is
- * needed after a SCC access anyway. Additionally, _SCCwrite() manages
- * writes to WR0 and WR8 differently, because these can be accessed
- * directly with less overhead. Another special case are WR7 and WR7'.
- * _SCCwrite automatically checks what of this registers is selected
- * and changes b0 of WR15 if needed.
- *
- * _SCCread() for standard read registers is straightforward, except
- * for RR2 (split into two "virtual" registers: one for the value
- * written to WR2 (from the shadow) and one for the vector including
- * status from RR2, Ch. B) and RR3. The latter must be read from
- * Channel A, because it reads as all zeros on Ch. B. RR0 and RR8 can
- * be accessed directly as before.
- *
- * The two inline function contain complicated switch statements. But
- * I rely on regno and final_delay being constants, so gcc can reduce
- * the whole stuff to just some assembler statements.
- *
- * _SCCwrite and _SCCread aren't intended to be used directly under
- * normal circumstances. The macros SCCread[_ND] and SCCwrite[_ND] are
- * for that purpose. They assume that a local variable 'port' is
- * declared and pointing to the port's scc_struct entry. The
- * variants with "_NB" appended should be used if no other SCC
- * accesses follow immediately (within 0.5 usecs). They just skip the
- * final delay nops.
- *
- * Please note that accesses to SCC registers should only take place
- * when interrupts are turned off (at least if SCC interrupts are
- * enabled). Otherwise, an interrupt could interfere with the
- * two-stage accessing process.
- *
- */
-
-
-static __inline__ void _SCCwrite(
- struct scc_port *port,
- unsigned char *shadow,
- volatile unsigned char *_scc_del,
- int regno,
- unsigned char val, int final_delay )
-{
- switch( regno ) {
-
- case COMMAND_REG:
- /* WR0 can be written directly without pointing */
- *port->ctrlp = val;
- break;
-
- case SYNC_CHAR_REG:
- /* For WR7, first set b0 of WR15 to 0, if needed */
- if (shadow[INT_CTRL_REG] & ICR_OPTIONREG_SELECT) {
- *port->ctrlp = 15;
- shadow[INT_CTRL_REG] &= ~ICR_OPTIONREG_SELECT;
- scc_reg_delay();
- *port->ctrlp = shadow[INT_CTRL_REG];
- scc_reg_delay();
- }
- goto normal_case;
-
- case SDLC_OPTION_REG:
- /* For WR7', first set b0 of WR15 to 1, if needed */
- if (!(shadow[INT_CTRL_REG] & ICR_OPTIONREG_SELECT)) {
- *port->ctrlp = 15;
- shadow[INT_CTRL_REG] |= ICR_OPTIONREG_SELECT;
- scc_reg_delay();
- *port->ctrlp = shadow[INT_CTRL_REG];
- scc_reg_delay();
- }
- *port->ctrlp = 7;
- shadow[8] = val; /* WR7' shadowed at WR8 */
- scc_reg_delay();
- *port->ctrlp = val;
- break;
-
- case TX_DATA_REG: /* WR8 */
- /* TX_DATA_REG can be accessed directly on some h/w */
- if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147)
- {
- *port->ctrlp = regno;
- scc_reg_delay();
- *port->ctrlp = val;
- }
- else
- *port->datap = val;
- break;
-
- case MASTER_INT_CTRL:
- *port->ctrlp = regno;
- val &= 0x3f; /* bits 6..7 are the reset commands */
- scc_shadow[0][regno] = val;
- scc_reg_delay();
- *port->ctrlp = val;
- break;
-
- case DPLL_CTRL_REG:
- *port->ctrlp = regno;
- val &= 0x1f; /* bits 5..7 are the DPLL commands */
- shadow[regno] = val;
- scc_reg_delay();
- *port->ctrlp = val;
- break;
-
- case 1 ... 6:
- case 10 ... 13:
- case 15:
- normal_case:
- *port->ctrlp = regno;
- shadow[regno] = val;
- scc_reg_delay();
- *port->ctrlp = val;
- break;
-
- default:
- printk( "Bad SCC write access to WR%d\n", regno );
- break;
-
- }
-
- if (final_delay)
- scc_reg_delay();
-}
-
-
-static __inline__ unsigned char _SCCread(
- struct scc_port *port,
- unsigned char *shadow,
- volatile unsigned char *_scc_del,
- int regno, int final_delay )
-{
- unsigned char rv;
-
- switch( regno ) {
-
- /* --- real read registers --- */
- case STATUS_REG:
- rv = *port->ctrlp;
- break;
-
- case INT_PENDING_REG:
- /* RR3: read only from Channel A! */
- port = port->port_a;
- goto normal_case;
-
- case RX_DATA_REG:
- /* RR8 can be accessed directly on some h/w */
- if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147)
- {
- *port->ctrlp = 8;
- scc_reg_delay();
- rv = *port->ctrlp;
- }
- else
- rv = *port->datap;
- break;
-
- case CURR_VECTOR_REG:
- /* RR2 (vector including status) from Ch. B */
- port = port->port_b;
- goto normal_case;
-
- /* --- reading write registers: access the shadow --- */
- case 1 ... 7:
- case 10 ... 15:
- return shadow[regno]; /* no final delay! */
-
- /* WR7' is special, because it is shadowed at the place of WR8 */
- case SDLC_OPTION_REG:
- return shadow[8]; /* no final delay! */
-
- /* WR9 is special too, because it is common for both channels */
- case MASTER_INT_CTRL:
- return scc_shadow[0][9]; /* no final delay! */
-
- default:
- printk( "Bad SCC read access to %cR%d\n", (regno & 16) ? 'R' : 'W',
- regno & ~16 );
- break;
-
- case SPCOND_STATUS_REG:
- case FS_FIFO_LOW_REG:
- case FS_FIFO_HIGH_REG:
- case DPLL_STATUS_REG:
- normal_case:
- *port->ctrlp = regno & 0x0f;
- scc_reg_delay();
- rv = *port->ctrlp;
- break;
-
- }
-
- if (final_delay)
- scc_reg_delay();
- return rv;
-}
-
-#define SCC_ACCESS_INIT(port) \
- unsigned char *_scc_shadow = &scc_shadow[port->channel][0]
-
-#define SCCwrite(reg,val) _SCCwrite(port,_scc_shadow,scc_del,(reg),(val),1)
-#define SCCwrite_NB(reg,val) _SCCwrite(port,_scc_shadow,scc_del,(reg),(val),0)
-#define SCCread(reg) _SCCread(port,_scc_shadow,scc_del,(reg),1)
-#define SCCread_NB(reg) _SCCread(port,_scc_shadow,scc_del,(reg),0)
-
-#define SCCmod(reg,and,or) SCCwrite((reg),(SCCread(reg)&(and))|(or))
-
-#endif /* _SCC_H */
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 9ca5c021d0b6..361a1dff8f77 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -966,6 +966,9 @@ ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr,
{
struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip->vendor.duration[TPM_LONG] == 0)
+ return 0;
+
return sprintf(buf, "%d %d %d [%s]\n",
jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]),
jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]),
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index a1f68af4ccf4..f22861511909 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -170,7 +170,7 @@ static const struct tty_operations ttyprintk_ops = {
.ioctl = tpk_ioctl,
};
-struct tty_port_operations null_ops = { };
+static struct tty_port_operations null_ops = { };
static struct tty_driver *ttyprintk_driver;
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index fb68b1295373..4ca181f1378b 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -19,8 +19,10 @@
*/
#include <linux/cdev.h>
#include <linux/debugfs.h>
+#include <linux/completion.h>
#include <linux/device.h>
#include <linux/err.h>
+#include <linux/freezer.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/list.h>
@@ -73,6 +75,7 @@ struct ports_driver_data {
static struct ports_driver_data pdrvdata;
DEFINE_SPINLOCK(pdrvdata_lock);
+DECLARE_COMPLETION(early_console_added);
/* This struct holds information that's relevant only for console ports */
struct console {
@@ -151,6 +154,10 @@ struct ports_device {
int chr_major;
};
+struct port_stats {
+ unsigned long bytes_sent, bytes_received, bytes_discarded;
+};
+
/* This struct holds the per-port data */
struct port {
/* Next port in the list, head is in the ports_device */
@@ -179,6 +186,13 @@ struct port {
struct dentry *debugfs_file;
/*
+ * Keep count of the bytes sent, received and discarded for
+ * this port for accounting and debugging purposes. These
+ * counts are not reset across port open / close events.
+ */
+ struct port_stats stats;
+
+ /*
* The entries in this struct will be valid if this port is
* hooked up to an hvc console
*/
@@ -347,17 +361,19 @@ fail:
}
/* Callers should take appropriate locks */
-static void *get_inbuf(struct port *port)
+static struct port_buffer *get_inbuf(struct port *port)
{
struct port_buffer *buf;
- struct virtqueue *vq;
unsigned int len;
- vq = port->in_vq;
- buf = virtqueue_get_buf(vq, &len);
+ if (port->inbuf)
+ return port->inbuf;
+
+ buf = virtqueue_get_buf(port->in_vq, &len);
if (buf) {
buf->len = len;
buf->offset = 0;
+ port->stats.bytes_received += len;
}
return buf;
}
@@ -384,32 +400,27 @@ static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
static void discard_port_data(struct port *port)
{
struct port_buffer *buf;
- struct virtqueue *vq;
- unsigned int len;
- int ret;
+ unsigned int err;
if (!port->portdev) {
/* Device has been unplugged. vqs are already gone. */
return;
}
- vq = port->in_vq;
- if (port->inbuf)
- buf = port->inbuf;
- else
- buf = virtqueue_get_buf(vq, &len);
+ buf = get_inbuf(port);
- ret = 0;
+ err = 0;
while (buf) {
- if (add_inbuf(vq, buf) < 0) {
- ret++;
+ port->stats.bytes_discarded += buf->len - buf->offset;
+ if (add_inbuf(port->in_vq, buf) < 0) {
+ err++;
free_buf(buf);
}
- buf = virtqueue_get_buf(vq, &len);
+ port->inbuf = NULL;
+ buf = get_inbuf(port);
}
- port->inbuf = NULL;
- if (ret)
+ if (err)
dev_warn(port->dev, "Errors adding %d buffers back to vq\n",
- ret);
+ err);
}
static bool port_has_data(struct port *port)
@@ -417,18 +428,12 @@ static bool port_has_data(struct port *port)
unsigned long flags;
bool ret;
+ ret = false;
spin_lock_irqsave(&port->inbuf_lock, flags);
- if (port->inbuf) {
- ret = true;
- goto out;
- }
port->inbuf = get_inbuf(port);
- if (port->inbuf) {
+ if (port->inbuf)
ret = true;
- goto out;
- }
- ret = false;
-out:
+
spin_unlock_irqrestore(&port->inbuf_lock, flags);
return ret;
}
@@ -529,6 +534,8 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
cpu_relax();
done:
spin_unlock_irqrestore(&port->outvq_lock, flags);
+
+ port->stats.bytes_sent += in_count;
/*
* We're expected to return the amount of data we wrote -- all
* of it
@@ -633,8 +640,8 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
- ret = wait_event_interruptible(port->waitqueue,
- !will_read_block(port));
+ ret = wait_event_freezable(port->waitqueue,
+ !will_read_block(port));
if (ret < 0)
return ret;
}
@@ -677,8 +684,8 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
if (nonblock)
return -EAGAIN;
- ret = wait_event_interruptible(port->waitqueue,
- !will_write_block(port));
+ ret = wait_event_freezable(port->waitqueue,
+ !will_write_block(port));
if (ret < 0)
return ret;
}
@@ -1059,6 +1066,14 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
out_offset += snprintf(buf + out_offset, out_count - out_offset,
"outvq_full: %d\n", port->outvq_full);
out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "bytes_sent: %lu\n", port->stats.bytes_sent);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "bytes_received: %lu\n",
+ port->stats.bytes_received);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "bytes_discarded: %lu\n",
+ port->stats.bytes_discarded);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
"is_console: %s\n",
is_console_port(port) ? "yes" : "no");
out_offset += snprintf(buf + out_offset, out_count - out_offset,
@@ -1143,6 +1158,7 @@ static int add_port(struct ports_device *portdev, u32 id)
port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
port->host_connected = port->guest_connected = false;
+ port->stats = (struct port_stats) { 0 };
port->outvq_full = false;
@@ -1352,6 +1368,7 @@ static void handle_control_message(struct ports_device *portdev,
break;
init_port_console(port);
+ complete(&early_console_added);
/*
* Could remove the port here in case init fails - but
* have to notify the host first.
@@ -1394,6 +1411,13 @@ static void handle_control_message(struct ports_device *portdev,
break;
case VIRTIO_CONSOLE_PORT_NAME:
/*
+ * If we woke up after hibernation, we can get this
+ * again. Skip it in that case.
+ */
+ if (port->name)
+ break;
+
+ /*
* Skip the size of the header and the cpkt to get the size
* of the name that was sent
*/
@@ -1481,8 +1505,7 @@ static void in_intr(struct virtqueue *vq)
return;
spin_lock_irqsave(&port->inbuf_lock, flags);
- if (!port->inbuf)
- port->inbuf = get_inbuf(port);
+ port->inbuf = get_inbuf(port);
/*
* Don't queue up data when port is closed. This condition
@@ -1563,7 +1586,7 @@ static int init_vqs(struct ports_device *portdev)
portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
GFP_KERNEL);
if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs ||
- !portdev->out_vqs) {
+ !portdev->out_vqs) {
err = -ENOMEM;
goto free;
}
@@ -1648,6 +1671,10 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
struct ports_device *portdev;
int err;
bool multiport;
+ bool early = early_put_chars != NULL;
+
+ /* Ensure to read early_put_chars now */
+ barrier();
portdev = kmalloc(sizeof(*portdev), GFP_KERNEL);
if (!portdev) {
@@ -1675,13 +1702,11 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
multiport = false;
portdev->config.max_nr_ports = 1;
- if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
+ if (virtio_config_val(vdev, VIRTIO_CONSOLE_F_MULTIPORT,
+ offsetof(struct virtio_console_config,
+ max_nr_ports),
+ &portdev->config.max_nr_ports) == 0)
multiport = true;
- vdev->config->get(vdev, offsetof(struct virtio_console_config,
- max_nr_ports),
- &portdev->config.max_nr_ports,
- sizeof(portdev->config.max_nr_ports));
- }
err = init_vqs(portdev);
if (err < 0) {
@@ -1719,6 +1744,19 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
VIRTIO_CONSOLE_DEVICE_READY, 1);
+
+ /*
+ * If there was an early virtio console, assume that there are no
+ * other consoles. We need to wait until the hvc_alloc matches the
+ * hvc_instantiate, otherwise tty_open will complain, resulting in
+ * a "Warning: unable to open an initial console" boot failure.
+ * Without multiport this is done in add_port above. With multiport
+ * this might take some host<->guest communication - thus we have to
+ * wait.
+ */
+ if (multiport && early)
+ wait_for_completion(&early_console_added);
+
return 0;
free_vqs: