6207 lines
202 KiB
Diff
6207 lines
202 KiB
Diff
|
diff --git a/Documentation/virtual/lguest/lguest.c b/Documentation/virtual/lguest/lguest.c
|
||
|
index c095d79..288dba6 100644
|
||
|
--- a/Documentation/virtual/lguest/lguest.c
|
||
|
+++ b/Documentation/virtual/lguest/lguest.c
|
||
|
@@ -1299,6 +1299,7 @@ static struct device *new_device(const char *name, u16 type)
|
||
|
dev->feature_len = 0;
|
||
|
dev->num_vq = 0;
|
||
|
dev->running = false;
|
||
|
+ dev->next = NULL;
|
||
|
|
||
|
/*
|
||
|
* Append to device list. Prepending to a single-linked list is
|
||
|
diff --git a/Makefile b/Makefile
|
||
|
index fd9c414..b6d8282 100644
|
||
|
--- a/Makefile
|
||
|
+++ b/Makefile
|
||
|
@@ -1,6 +1,6 @@
|
||
|
VERSION = 3
|
||
|
PATCHLEVEL = 2
|
||
|
-SUBLEVEL = 31
|
||
|
+SUBLEVEL = 32
|
||
|
EXTRAVERSION =
|
||
|
NAME = Saber-toothed Squirrel
|
||
|
|
||
|
diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c
|
||
|
index a6cbb71..04e703a 100644
|
||
|
--- a/arch/arm/plat-omap/counter_32k.c
|
||
|
+++ b/arch/arm/plat-omap/counter_32k.c
|
||
|
@@ -82,22 +82,29 @@ static void notrace omap_update_sched_clock(void)
|
||
|
* nsecs and adds to a monotonically increasing timespec.
|
||
|
*/
|
||
|
static struct timespec persistent_ts;
|
||
|
-static cycles_t cycles, last_cycles;
|
||
|
+static cycles_t cycles;
|
||
|
static unsigned int persistent_mult, persistent_shift;
|
||
|
+static DEFINE_SPINLOCK(read_persistent_clock_lock);
|
||
|
+
|
||
|
void read_persistent_clock(struct timespec *ts)
|
||
|
{
|
||
|
unsigned long long nsecs;
|
||
|
- cycles_t delta;
|
||
|
- struct timespec *tsp = &persistent_ts;
|
||
|
+ cycles_t last_cycles;
|
||
|
+ unsigned long flags;
|
||
|
+
|
||
|
+ spin_lock_irqsave(&read_persistent_clock_lock, flags);
|
||
|
|
||
|
last_cycles = cycles;
|
||
|
cycles = timer_32k_base ? __raw_readl(timer_32k_base) : 0;
|
||
|
- delta = cycles - last_cycles;
|
||
|
|
||
|
- nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift);
|
||
|
+ nsecs = clocksource_cyc2ns(cycles - last_cycles,
|
||
|
+ persistent_mult, persistent_shift);
|
||
|
+
|
||
|
+ timespec_add_ns(&persistent_ts, nsecs);
|
||
|
+
|
||
|
+ *ts = persistent_ts;
|
||
|
|
||
|
- timespec_add_ns(tsp, nsecs);
|
||
|
- *ts = *tsp;
|
||
|
+ spin_unlock_irqrestore(&read_persistent_clock_lock, flags);
|
||
|
}
|
||
|
|
||
|
int __init omap_init_clocksource_32k(void)
|
||
|
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
|
||
|
index 0be3186..aaf7444 100644
|
||
|
--- a/arch/mips/Makefile
|
||
|
+++ b/arch/mips/Makefile
|
||
|
@@ -224,7 +224,7 @@ KBUILD_CPPFLAGS += -D"DATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0)"
|
||
|
LDFLAGS += -m $(ld-emul)
|
||
|
|
||
|
ifdef CONFIG_MIPS
|
||
|
-CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -xc /dev/null | \
|
||
|
+CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \
|
||
|
egrep -vw '__GNUC_(|MINOR_|PATCHLEVEL_)_' | \
|
||
|
sed -e "s/^\#define /-D'/" -e "s/ /'='/" -e "s/$$/'/")
|
||
|
ifdef CONFIG_64BIT
|
||
|
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
|
||
|
index 1a96618..ce7dd99 100644
|
||
|
--- a/arch/mips/kernel/Makefile
|
||
|
+++ b/arch/mips/kernel/Makefile
|
||
|
@@ -102,7 +102,7 @@ obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o
|
||
|
|
||
|
obj-$(CONFIG_OF) += prom.o
|
||
|
|
||
|
-CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
|
||
|
+CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -x c /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
|
||
|
|
||
|
obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o
|
||
|
|
||
|
diff --git a/arch/mn10300/Makefile b/arch/mn10300/Makefile
|
||
|
index 7120282..3eb4a52 100644
|
||
|
--- a/arch/mn10300/Makefile
|
||
|
+++ b/arch/mn10300/Makefile
|
||
|
@@ -26,7 +26,7 @@ CHECKFLAGS +=
|
||
|
PROCESSOR := unset
|
||
|
UNIT := unset
|
||
|
|
||
|
-KBUILD_CFLAGS += -mam33 -mmem-funcs -DCPU=AM33
|
||
|
+KBUILD_CFLAGS += -mam33 -DCPU=AM33 $(call cc-option,-mmem-funcs,)
|
||
|
KBUILD_AFLAGS += -mam33 -DCPU=AM33
|
||
|
|
||
|
ifeq ($(CONFIG_MN10300_CURRENT_IN_E2),y)
|
||
|
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
|
||
|
index 1b6cb10..a0a4e8a 100644
|
||
|
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
|
||
|
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
|
||
|
@@ -25,6 +25,7 @@
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/interrupt.h>
|
||
|
#include <linux/irq.h>
|
||
|
+#include <linux/module.h>
|
||
|
#include <linux/pci.h>
|
||
|
#include <asm/eeh.h>
|
||
|
#include <asm/eeh_event.h>
|
||
|
@@ -41,6 +42,41 @@ static inline const char * pcid_name (struct pci_dev *pdev)
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * eeh_pcid_get - Get the PCI device driver
|
||
|
+ * @pdev: PCI device
|
||
|
+ *
|
||
|
+ * The function is used to retrieve the PCI device driver for
|
||
|
+ * the indicated PCI device. Besides, we will increase the reference
|
||
|
+ * of the PCI device driver to prevent that being unloaded on
|
||
|
+ * the fly. Otherwise, kernel crash would be seen.
|
||
|
+ */
|
||
|
+static inline struct pci_driver *eeh_pcid_get(struct pci_dev *pdev)
|
||
|
+{
|
||
|
+ if (!pdev || !pdev->driver)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ if (!try_module_get(pdev->driver->driver.owner))
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ return pdev->driver;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * eeh_pcid_put - Dereference on the PCI device driver
|
||
|
+ * @pdev: PCI device
|
||
|
+ *
|
||
|
+ * The function is called to do dereference on the PCI device
|
||
|
+ * driver of the indicated PCI device.
|
||
|
+ */
|
||
|
+static inline void eeh_pcid_put(struct pci_dev *pdev)
|
||
|
+{
|
||
|
+ if (!pdev || !pdev->driver)
|
||
|
+ return;
|
||
|
+
|
||
|
+ module_put(pdev->driver->driver.owner);
|
||
|
+}
|
||
|
+
|
||
|
#if 0
|
||
|
static void print_device_node_tree(struct pci_dn *pdn, int dent)
|
||
|
{
|
||
|
@@ -109,18 +145,20 @@ static void eeh_enable_irq(struct pci_dev *dev)
|
||
|
static int eeh_report_error(struct pci_dev *dev, void *userdata)
|
||
|
{
|
||
|
enum pci_ers_result rc, *res = userdata;
|
||
|
- struct pci_driver *driver = dev->driver;
|
||
|
+ struct pci_driver *driver;
|
||
|
|
||
|
dev->error_state = pci_channel_io_frozen;
|
||
|
|
||
|
- if (!driver)
|
||
|
- return 0;
|
||
|
+ driver = eeh_pcid_get(dev);
|
||
|
+ if (!driver) return 0;
|
||
|
|
||
|
eeh_disable_irq(dev);
|
||
|
|
||
|
if (!driver->err_handler ||
|
||
|
- !driver->err_handler->error_detected)
|
||
|
+ !driver->err_handler->error_detected) {
|
||
|
+ eeh_pcid_put(dev);
|
||
|
return 0;
|
||
|
+ }
|
||
|
|
||
|
rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen);
|
||
|
|
||
|
@@ -128,6 +166,7 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata)
|
||
|
if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
|
||
|
if (*res == PCI_ERS_RESULT_NONE) *res = rc;
|
||
|
|
||
|
+ eeh_pcid_put(dev);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -142,12 +181,15 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata)
|
||
|
static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
|
||
|
{
|
||
|
enum pci_ers_result rc, *res = userdata;
|
||
|
- struct pci_driver *driver = dev->driver;
|
||
|
+ struct pci_driver *driver;
|
||
|
|
||
|
- if (!driver ||
|
||
|
- !driver->err_handler ||
|
||
|
- !driver->err_handler->mmio_enabled)
|
||
|
+ driver = eeh_pcid_get(dev);
|
||
|
+ if (!driver) return 0;
|
||
|
+ if (!driver->err_handler ||
|
||
|
+ !driver->err_handler->mmio_enabled) {
|
||
|
+ eeh_pcid_put(dev);
|
||
|
return 0;
|
||
|
+ }
|
||
|
|
||
|
rc = driver->err_handler->mmio_enabled (dev);
|
||
|
|
||
|
@@ -155,6 +197,7 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
|
||
|
if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
|
||
|
if (*res == PCI_ERS_RESULT_NONE) *res = rc;
|
||
|
|
||
|
+ eeh_pcid_put(dev);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -165,18 +208,20 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
|
||
|
static int eeh_report_reset(struct pci_dev *dev, void *userdata)
|
||
|
{
|
||
|
enum pci_ers_result rc, *res = userdata;
|
||
|
- struct pci_driver *driver = dev->driver;
|
||
|
-
|
||
|
- if (!driver)
|
||
|
- return 0;
|
||
|
+ struct pci_driver *driver;
|
||
|
|
||
|
dev->error_state = pci_channel_io_normal;
|
||
|
|
||
|
+ driver = eeh_pcid_get(dev);
|
||
|
+ if (!driver) return 0;
|
||
|
+
|
||
|
eeh_enable_irq(dev);
|
||
|
|
||
|
if (!driver->err_handler ||
|
||
|
- !driver->err_handler->slot_reset)
|
||
|
+ !driver->err_handler->slot_reset) {
|
||
|
+ eeh_pcid_put(dev);
|
||
|
return 0;
|
||
|
+ }
|
||
|
|
||
|
rc = driver->err_handler->slot_reset(dev);
|
||
|
if ((*res == PCI_ERS_RESULT_NONE) ||
|
||
|
@@ -184,6 +229,7 @@ static int eeh_report_reset(struct pci_dev *dev, void *userdata)
|
||
|
if (*res == PCI_ERS_RESULT_DISCONNECT &&
|
||
|
rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
|
||
|
|
||
|
+ eeh_pcid_put(dev);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -193,21 +239,24 @@ static int eeh_report_reset(struct pci_dev *dev, void *userdata)
|
||
|
|
||
|
static int eeh_report_resume(struct pci_dev *dev, void *userdata)
|
||
|
{
|
||
|
- struct pci_driver *driver = dev->driver;
|
||
|
+ struct pci_driver *driver;
|
||
|
|
||
|
dev->error_state = pci_channel_io_normal;
|
||
|
|
||
|
- if (!driver)
|
||
|
- return 0;
|
||
|
+ driver = eeh_pcid_get(dev);
|
||
|
+ if (!driver) return 0;
|
||
|
|
||
|
eeh_enable_irq(dev);
|
||
|
|
||
|
if (!driver->err_handler ||
|
||
|
- !driver->err_handler->resume)
|
||
|
+ !driver->err_handler->resume) {
|
||
|
+ eeh_pcid_put(dev);
|
||
|
return 0;
|
||
|
+ }
|
||
|
|
||
|
driver->err_handler->resume(dev);
|
||
|
|
||
|
+ eeh_pcid_put(dev);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -220,21 +269,24 @@ static int eeh_report_resume(struct pci_dev *dev, void *userdata)
|
||
|
|
||
|
static int eeh_report_failure(struct pci_dev *dev, void *userdata)
|
||
|
{
|
||
|
- struct pci_driver *driver = dev->driver;
|
||
|
+ struct pci_driver *driver;
|
||
|
|
||
|
dev->error_state = pci_channel_io_perm_failure;
|
||
|
|
||
|
- if (!driver)
|
||
|
- return 0;
|
||
|
+ driver = eeh_pcid_get(dev);
|
||
|
+ if (!driver) return 0;
|
||
|
|
||
|
eeh_disable_irq(dev);
|
||
|
|
||
|
if (!driver->err_handler ||
|
||
|
- !driver->err_handler->error_detected)
|
||
|
+ !driver->err_handler->error_detected) {
|
||
|
+ eeh_pcid_put(dev);
|
||
|
return 0;
|
||
|
+ }
|
||
|
|
||
|
driver->err_handler->error_detected(dev, pci_channel_io_perm_failure);
|
||
|
|
||
|
+ eeh_pcid_put(dev);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
|
||
|
index 18601c8..884507e 100644
|
||
|
--- a/arch/x86/include/asm/pgtable.h
|
||
|
+++ b/arch/x86/include/asm/pgtable.h
|
||
|
@@ -146,8 +146,7 @@ static inline unsigned long pmd_pfn(pmd_t pmd)
|
||
|
|
||
|
static inline int pmd_large(pmd_t pte)
|
||
|
{
|
||
|
- return (pmd_flags(pte) & (_PAGE_PSE | _PAGE_PRESENT)) ==
|
||
|
- (_PAGE_PSE | _PAGE_PRESENT);
|
||
|
+ return pmd_flags(pte) & _PAGE_PSE;
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||
|
@@ -415,7 +414,13 @@ static inline int pte_hidden(pte_t pte)
|
||
|
|
||
|
static inline int pmd_present(pmd_t pmd)
|
||
|
{
|
||
|
- return pmd_flags(pmd) & _PAGE_PRESENT;
|
||
|
+ /*
|
||
|
+ * Checking for _PAGE_PSE is needed too because
|
||
|
+ * split_huge_page will temporarily clear the present bit (but
|
||
|
+ * the _PAGE_PSE flag will remain set at all times while the
|
||
|
+ * _PAGE_PRESENT bit is clear).
|
||
|
+ */
|
||
|
+ return pmd_flags(pmd) & (_PAGE_PRESENT | _PAGE_PROTNONE | _PAGE_PSE);
|
||
|
}
|
||
|
|
||
|
static inline int pmd_none(pmd_t pmd)
|
||
|
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
|
||
|
index 37718f0..4d320b2 100644
|
||
|
--- a/arch/x86/platform/efi/efi.c
|
||
|
+++ b/arch/x86/platform/efi/efi.c
|
||
|
@@ -731,6 +731,7 @@ void __init efi_enter_virtual_mode(void)
|
||
|
*
|
||
|
* Call EFI services through wrapper functions.
|
||
|
*/
|
||
|
+ efi.runtime_version = efi_systab.fw_revision;
|
||
|
efi.get_time = virt_efi_get_time;
|
||
|
efi.set_time = virt_efi_set_time;
|
||
|
efi.get_wakeup_time = virt_efi_get_wakeup_time;
|
||
|
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
|
||
|
index 9ecec98..5016de5 100644
|
||
|
--- a/drivers/acpi/bus.c
|
||
|
+++ b/drivers/acpi/bus.c
|
||
|
@@ -950,8 +950,6 @@ static int __init acpi_bus_init(void)
|
||
|
status = acpi_ec_ecdt_probe();
|
||
|
/* Ignore result. Not having an ECDT is not fatal. */
|
||
|
|
||
|
- acpi_bus_osc_support();
|
||
|
-
|
||
|
status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION);
|
||
|
if (ACPI_FAILURE(status)) {
|
||
|
printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n");
|
||
|
@@ -959,6 +957,12 @@ static int __init acpi_bus_init(void)
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
+ * _OSC method may exist in module level code,
|
||
|
+ * so it must be run after ACPI_FULL_INITIALIZATION
|
||
|
+ */
|
||
|
+ acpi_bus_osc_support();
|
||
|
+
|
||
|
+ /*
|
||
|
* _PDC control method may load dynamic SSDT tables,
|
||
|
* and we need to install the table handler before that.
|
||
|
*/
|
||
|
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
|
||
|
index 6f95d98..1f90dab 100644
|
||
|
--- a/drivers/bluetooth/btusb.c
|
||
|
+++ b/drivers/bluetooth/btusb.c
|
||
|
@@ -108,7 +108,7 @@ static struct usb_device_id btusb_table[] = {
|
||
|
{ USB_DEVICE(0x413c, 0x8197) },
|
||
|
|
||
|
/* Foxconn - Hon Hai */
|
||
|
- { USB_DEVICE(0x0489, 0xe033) },
|
||
|
+ { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
|
||
|
|
||
|
/*Broadcom devices with vendor specific id */
|
||
|
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
|
||
|
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
|
||
|
index eedd547..5936691 100644
|
||
|
--- a/drivers/char/ttyprintk.c
|
||
|
+++ b/drivers/char/ttyprintk.c
|
||
|
@@ -67,7 +67,7 @@ static int tpk_printk(const unsigned char *buf, int count)
|
||
|
tmp[tpk_curr + 1] = '\0';
|
||
|
printk(KERN_INFO "%s%s", tpk_tag, tmp);
|
||
|
tpk_curr = 0;
|
||
|
- if (buf[i + 1] == '\n')
|
||
|
+ if ((i + 1) < count && buf[i + 1] == '\n')
|
||
|
i++;
|
||
|
break;
|
||
|
case '\n':
|
||
|
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
|
||
|
index b48967b..5991114 100644
|
||
|
--- a/drivers/dma/dmaengine.c
|
||
|
+++ b/drivers/dma/dmaengine.c
|
||
|
@@ -564,8 +564,8 @@ void dmaengine_get(void)
|
||
|
list_del_rcu(&device->global_node);
|
||
|
break;
|
||
|
} else if (err)
|
||
|
- pr_err("dmaengine: failed to get %s: (%d)\n",
|
||
|
- dma_chan_name(chan), err);
|
||
|
+ pr_debug("%s: failed to get %s: (%d)\n",
|
||
|
+ __func__, dma_chan_name(chan), err);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
|
||
|
index 4799393..b97d4f0 100644
|
||
|
--- a/drivers/firewire/core-cdev.c
|
||
|
+++ b/drivers/firewire/core-cdev.c
|
||
|
@@ -471,8 +471,8 @@ static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
|
||
|
client->bus_reset_closure = a->bus_reset_closure;
|
||
|
if (a->bus_reset != 0) {
|
||
|
fill_bus_reset_event(&bus_reset, client);
|
||
|
- ret = copy_to_user(u64_to_uptr(a->bus_reset),
|
||
|
- &bus_reset, sizeof(bus_reset));
|
||
|
+ /* unaligned size of bus_reset is 36 bytes */
|
||
|
+ ret = copy_to_user(u64_to_uptr(a->bus_reset), &bus_reset, 36);
|
||
|
}
|
||
|
if (ret == 0 && list_empty(&client->link))
|
||
|
list_add_tail(&client->link, &client->device->client_list);
|
||
|
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
|
||
|
index 0535c21..3e60e8d 100644
|
||
|
--- a/drivers/firmware/efivars.c
|
||
|
+++ b/drivers/firmware/efivars.c
|
||
|
@@ -435,12 +435,23 @@ efivar_attr_read(struct efivar_entry *entry, char *buf)
|
||
|
if (status != EFI_SUCCESS)
|
||
|
return -EIO;
|
||
|
|
||
|
- if (var->Attributes & 0x1)
|
||
|
+ if (var->Attributes & EFI_VARIABLE_NON_VOLATILE)
|
||
|
str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n");
|
||
|
- if (var->Attributes & 0x2)
|
||
|
+ if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)
|
||
|
str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n");
|
||
|
- if (var->Attributes & 0x4)
|
||
|
+ if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
|
||
|
str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n");
|
||
|
+ if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
|
||
|
+ str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n");
|
||
|
+ if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
|
||
|
+ str += sprintf(str,
|
||
|
+ "EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n");
|
||
|
+ if (var->Attributes &
|
||
|
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
|
||
|
+ str += sprintf(str,
|
||
|
+ "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n");
|
||
|
+ if (var->Attributes & EFI_VARIABLE_APPEND_WRITE)
|
||
|
+ str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n");
|
||
|
return str - buf;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
|
||
|
index e48e01e..33e1555 100644
|
||
|
--- a/drivers/gpu/drm/i915/i915_gem.c
|
||
|
+++ b/drivers/gpu/drm/i915/i915_gem.c
|
||
|
@@ -1543,16 +1543,19 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
|
||
|
list_move_tail(&obj->ring_list, &ring->active_list);
|
||
|
|
||
|
obj->last_rendering_seqno = seqno;
|
||
|
- if (obj->fenced_gpu_access) {
|
||
|
- struct drm_i915_fence_reg *reg;
|
||
|
-
|
||
|
- BUG_ON(obj->fence_reg == I915_FENCE_REG_NONE);
|
||
|
|
||
|
+ if (obj->fenced_gpu_access) {
|
||
|
obj->last_fenced_seqno = seqno;
|
||
|
obj->last_fenced_ring = ring;
|
||
|
|
||
|
- reg = &dev_priv->fence_regs[obj->fence_reg];
|
||
|
- list_move_tail(®->lru_list, &dev_priv->mm.fence_list);
|
||
|
+ /* Bump MRU to take account of the delayed flush */
|
||
|
+ if (obj->fence_reg != I915_FENCE_REG_NONE) {
|
||
|
+ struct drm_i915_fence_reg *reg;
|
||
|
+
|
||
|
+ reg = &dev_priv->fence_regs[obj->fence_reg];
|
||
|
+ list_move_tail(®->lru_list,
|
||
|
+ &dev_priv->mm.fence_list);
|
||
|
+ }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -1561,6 +1564,7 @@ i915_gem_object_move_off_active(struct drm_i915_gem_object *obj)
|
||
|
{
|
||
|
list_del_init(&obj->ring_list);
|
||
|
obj->last_rendering_seqno = 0;
|
||
|
+ obj->last_fenced_seqno = 0;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
@@ -1589,6 +1593,7 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
|
||
|
BUG_ON(!list_empty(&obj->gpu_write_list));
|
||
|
BUG_ON(!obj->active);
|
||
|
obj->ring = NULL;
|
||
|
+ obj->last_fenced_ring = NULL;
|
||
|
|
||
|
i915_gem_object_move_off_active(obj);
|
||
|
obj->fenced_gpu_access = false;
|
||
|
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||
|
index a6c2f7a..1202198 100644
|
||
|
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||
|
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||
|
@@ -574,7 +574,8 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
|
||
|
if (ret)
|
||
|
break;
|
||
|
}
|
||
|
- obj->pending_fenced_gpu_access = need_fence;
|
||
|
+ obj->pending_fenced_gpu_access =
|
||
|
+ !!(entry->flags & EXEC_OBJECT_NEEDS_FENCE);
|
||
|
}
|
||
|
|
||
|
entry->offset = obj->gtt_offset;
|
||
|
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
|
||
|
index 31d334d..861223b 100644
|
||
|
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
|
||
|
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
|
||
|
@@ -107,10 +107,10 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
|
||
|
*/
|
||
|
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
|
||
|
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
|
||
|
- } else if (IS_MOBILE(dev)) {
|
||
|
+ } else if (IS_MOBILE(dev) || (IS_GEN3(dev) && !IS_G33(dev))) {
|
||
|
uint32_t dcc;
|
||
|
|
||
|
- /* On mobile 9xx chipsets, channel interleave by the CPU is
|
||
|
+ /* On 9xx chipsets, channel interleave by the CPU is
|
||
|
* determined by DCC. For single-channel, neither the CPU
|
||
|
* nor the GPU do swizzling. For dual channel interleaved,
|
||
|
* the GPU's interleave is bit 9 and 10 for X tiled, and bit
|
||
|
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
|
||
|
index c8b5bc1..2812d7b 100644
|
||
|
--- a/drivers/gpu/drm/i915/i915_irq.c
|
||
|
+++ b/drivers/gpu/drm/i915/i915_irq.c
|
||
|
@@ -530,6 +530,12 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
|
||
|
if (de_iir & DE_GSE_IVB)
|
||
|
intel_opregion_gse_intr(dev);
|
||
|
|
||
|
+ if (de_iir & DE_PIPEA_VBLANK_IVB)
|
||
|
+ drm_handle_vblank(dev, 0);
|
||
|
+
|
||
|
+ if (de_iir & DE_PIPEB_VBLANK_IVB)
|
||
|
+ drm_handle_vblank(dev, 1);
|
||
|
+
|
||
|
if (de_iir & DE_PLANEA_FLIP_DONE_IVB) {
|
||
|
intel_prepare_page_flip(dev, 0);
|
||
|
intel_finish_page_flip_plane(dev, 0);
|
||
|
@@ -540,12 +546,6 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
|
||
|
intel_finish_page_flip_plane(dev, 1);
|
||
|
}
|
||
|
|
||
|
- if (de_iir & DE_PIPEA_VBLANK_IVB)
|
||
|
- drm_handle_vblank(dev, 0);
|
||
|
-
|
||
|
- if (de_iir & DE_PIPEB_VBLANK_IVB)
|
||
|
- drm_handle_vblank(dev, 1);
|
||
|
-
|
||
|
/* check event from PCH */
|
||
|
if (de_iir & DE_PCH_EVENT_IVB) {
|
||
|
if (pch_iir & SDE_HOTPLUG_MASK_CPT)
|
||
|
@@ -622,6 +622,12 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
|
||
|
if (de_iir & DE_GSE)
|
||
|
intel_opregion_gse_intr(dev);
|
||
|
|
||
|
+ if (de_iir & DE_PIPEA_VBLANK)
|
||
|
+ drm_handle_vblank(dev, 0);
|
||
|
+
|
||
|
+ if (de_iir & DE_PIPEB_VBLANK)
|
||
|
+ drm_handle_vblank(dev, 1);
|
||
|
+
|
||
|
if (de_iir & DE_PLANEA_FLIP_DONE) {
|
||
|
intel_prepare_page_flip(dev, 0);
|
||
|
intel_finish_page_flip_plane(dev, 0);
|
||
|
@@ -632,12 +638,6 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
|
||
|
intel_finish_page_flip_plane(dev, 1);
|
||
|
}
|
||
|
|
||
|
- if (de_iir & DE_PIPEA_VBLANK)
|
||
|
- drm_handle_vblank(dev, 0);
|
||
|
-
|
||
|
- if (de_iir & DE_PIPEB_VBLANK)
|
||
|
- drm_handle_vblank(dev, 1);
|
||
|
-
|
||
|
/* check event from PCH */
|
||
|
if (de_iir & DE_PCH_EVENT) {
|
||
|
if (pch_iir & hotplug_mask)
|
||
|
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
|
||
|
index 4a5e662..a294a32 100644
|
||
|
--- a/drivers/gpu/drm/i915/i915_reg.h
|
||
|
+++ b/drivers/gpu/drm/i915/i915_reg.h
|
||
|
@@ -401,6 +401,9 @@
|
||
|
# define VS_TIMER_DISPATCH (1 << 6)
|
||
|
# define MI_FLUSH_ENABLE (1 << 11)
|
||
|
|
||
|
+#define GEN6_GT_MODE 0x20d0
|
||
|
+#define GEN6_GT_MODE_HI (1 << 9)
|
||
|
+
|
||
|
#define GFX_MODE 0x02520
|
||
|
#define GFX_MODE_GEN7 0x0229c
|
||
|
#define GFX_RUN_LIST_ENABLE (1<<15)
|
||
|
@@ -1557,6 +1560,10 @@
|
||
|
|
||
|
/* Video Data Island Packet control */
|
||
|
#define VIDEO_DIP_DATA 0x61178
|
||
|
+/* Read the description of VIDEO_DIP_DATA (before Haswel) or VIDEO_DIP_ECC
|
||
|
+ * (Haswell and newer) to see which VIDEO_DIP_DATA byte corresponds to each byte
|
||
|
+ * of the infoframe structure specified by CEA-861. */
|
||
|
+#define VIDEO_DIP_DATA_SIZE 32
|
||
|
#define VIDEO_DIP_CTL 0x61170
|
||
|
#define VIDEO_DIP_ENABLE (1 << 31)
|
||
|
#define VIDEO_DIP_PORT_B (1 << 29)
|
||
|
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
|
||
|
index 6c3fb44..adac0dd 100644
|
||
|
--- a/drivers/gpu/drm/i915/intel_display.c
|
||
|
+++ b/drivers/gpu/drm/i915/intel_display.c
|
||
|
@@ -2850,13 +2850,34 @@ static void intel_clear_scanline_wait(struct drm_device *dev)
|
||
|
I915_WRITE_CTL(ring, tmp);
|
||
|
}
|
||
|
|
||
|
+static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
|
||
|
+{
|
||
|
+ struct drm_device *dev = crtc->dev;
|
||
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
||
|
+ unsigned long flags;
|
||
|
+ bool pending;
|
||
|
+
|
||
|
+ if (atomic_read(&dev_priv->mm.wedged))
|
||
|
+ return false;
|
||
|
+
|
||
|
+ spin_lock_irqsave(&dev->event_lock, flags);
|
||
|
+ pending = to_intel_crtc(crtc)->unpin_work != NULL;
|
||
|
+ spin_unlock_irqrestore(&dev->event_lock, flags);
|
||
|
+
|
||
|
+ return pending;
|
||
|
+}
|
||
|
+
|
||
|
static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
|
||
|
{
|
||
|
struct drm_device *dev = crtc->dev;
|
||
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
||
|
|
||
|
if (crtc->fb == NULL)
|
||
|
return;
|
||
|
|
||
|
+ wait_event(dev_priv->pending_flip_queue,
|
||
|
+ !intel_crtc_has_pending_flip(crtc));
|
||
|
+
|
||
|
mutex_lock(&dev->struct_mutex);
|
||
|
intel_finish_fb(crtc->fb);
|
||
|
mutex_unlock(&dev->struct_mutex);
|
||
|
@@ -5027,7 +5048,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
|
||
|
/* default to 8bpc */
|
||
|
pipeconf &= ~(PIPECONF_BPP_MASK | PIPECONF_DITHER_EN);
|
||
|
if (is_dp) {
|
||
|
- if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
|
||
|
+ if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
|
||
|
pipeconf |= PIPECONF_BPP_6 |
|
||
|
PIPECONF_DITHER_EN |
|
||
|
PIPECONF_DITHER_TYPE_SP;
|
||
|
@@ -5495,7 +5516,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
||
|
/* determine panel color depth */
|
||
|
temp = I915_READ(PIPECONF(pipe));
|
||
|
temp &= ~PIPE_BPC_MASK;
|
||
|
- dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, mode);
|
||
|
+ dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, adjusted_mode);
|
||
|
switch (pipe_bpp) {
|
||
|
case 18:
|
||
|
temp |= PIPE_6BPC;
|
||
|
@@ -6952,9 +6973,8 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
|
||
|
|
||
|
atomic_clear_mask(1 << intel_crtc->plane,
|
||
|
&obj->pending_flip.counter);
|
||
|
- if (atomic_read(&obj->pending_flip) == 0)
|
||
|
- wake_up(&dev_priv->pending_flip_queue);
|
||
|
|
||
|
+ wake_up(&dev_priv->pending_flip_queue);
|
||
|
schedule_work(&work->work);
|
||
|
|
||
|
trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
|
||
|
@@ -7193,7 +7213,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
|
||
|
default:
|
||
|
WARN_ONCE(1, "unknown plane in flip command\n");
|
||
|
ret = -ENODEV;
|
||
|
- goto err;
|
||
|
+ goto err_unpin;
|
||
|
}
|
||
|
|
||
|
ret = intel_ring_begin(ring, 4);
|
||
|
@@ -8278,6 +8298,11 @@ static void gen6_init_clock_gating(struct drm_device *dev)
|
||
|
DISPPLANE_TRICKLE_FEED_DISABLE);
|
||
|
intel_flush_display_plane(dev_priv, pipe);
|
||
|
}
|
||
|
+
|
||
|
+ /* The default value should be 0x200 according to docs, but the two
|
||
|
+ * platforms I checked have a 0 for this. (Maybe BIOS overrides?) */
|
||
|
+ I915_WRITE(GEN6_GT_MODE, 0xffff << 16);
|
||
|
+ I915_WRITE(GEN6_GT_MODE, GEN6_GT_MODE_HI << 16 | GEN6_GT_MODE_HI);
|
||
|
}
|
||
|
|
||
|
static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv)
|
||
|
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
|
||
|
index c2a64f4..497da2a 100644
|
||
|
--- a/drivers/gpu/drm/i915/intel_hdmi.c
|
||
|
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
|
||
|
@@ -138,14 +138,20 @@ static void i9xx_write_infoframe(struct drm_encoder *encoder,
|
||
|
|
||
|
I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags);
|
||
|
|
||
|
+ mmiowb();
|
||
|
for (i = 0; i < len; i += 4) {
|
||
|
I915_WRITE(VIDEO_DIP_DATA, *data);
|
||
|
data++;
|
||
|
}
|
||
|
+ /* Write every possible data byte to force correct ECC calculation. */
|
||
|
+ for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
|
||
|
+ I915_WRITE(VIDEO_DIP_DATA, 0);
|
||
|
+ mmiowb();
|
||
|
|
||
|
flags |= intel_infoframe_flags(frame);
|
||
|
|
||
|
I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags);
|
||
|
+ POSTING_READ(VIDEO_DIP_CTL);
|
||
|
}
|
||
|
|
||
|
static void ironlake_write_infoframe(struct drm_encoder *encoder,
|
||
|
@@ -168,14 +174,20 @@ static void ironlake_write_infoframe(struct drm_encoder *encoder,
|
||
|
|
||
|
I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags);
|
||
|
|
||
|
+ mmiowb();
|
||
|
for (i = 0; i < len; i += 4) {
|
||
|
I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
|
||
|
data++;
|
||
|
}
|
||
|
+ /* Write every possible data byte to force correct ECC calculation. */
|
||
|
+ for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
|
||
|
+ I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
|
||
|
+ mmiowb();
|
||
|
|
||
|
flags |= intel_infoframe_flags(frame);
|
||
|
|
||
|
I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags);
|
||
|
+ POSTING_READ(reg);
|
||
|
}
|
||
|
static void intel_set_infoframe(struct drm_encoder *encoder,
|
||
|
struct dip_infoframe *frame)
|
||
|
@@ -546,10 +558,13 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
|
||
|
if (!HAS_PCH_SPLIT(dev)) {
|
||
|
intel_hdmi->write_infoframe = i9xx_write_infoframe;
|
||
|
I915_WRITE(VIDEO_DIP_CTL, 0);
|
||
|
+ POSTING_READ(VIDEO_DIP_CTL);
|
||
|
} else {
|
||
|
intel_hdmi->write_infoframe = ironlake_write_infoframe;
|
||
|
- for_each_pipe(i)
|
||
|
+ for_each_pipe(i) {
|
||
|
I915_WRITE(TVIDEO_DIP_CTL(i), 0);
|
||
|
+ POSTING_READ(TVIDEO_DIP_CTL(i));
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
|
||
|
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
|
||
|
index fc0633c..b61f490 100644
|
||
|
--- a/drivers/gpu/drm/radeon/evergreen.c
|
||
|
+++ b/drivers/gpu/drm/radeon/evergreen.c
|
||
|
@@ -37,6 +37,16 @@
|
||
|
#define EVERGREEN_PFP_UCODE_SIZE 1120
|
||
|
#define EVERGREEN_PM4_UCODE_SIZE 1376
|
||
|
|
||
|
+static const u32 crtc_offsets[6] =
|
||
|
+{
|
||
|
+ EVERGREEN_CRTC0_REGISTER_OFFSET,
|
||
|
+ EVERGREEN_CRTC1_REGISTER_OFFSET,
|
||
|
+ EVERGREEN_CRTC2_REGISTER_OFFSET,
|
||
|
+ EVERGREEN_CRTC3_REGISTER_OFFSET,
|
||
|
+ EVERGREEN_CRTC4_REGISTER_OFFSET,
|
||
|
+ EVERGREEN_CRTC5_REGISTER_OFFSET
|
||
|
+};
|
||
|
+
|
||
|
static void evergreen_gpu_init(struct radeon_device *rdev);
|
||
|
void evergreen_fini(struct radeon_device *rdev);
|
||
|
void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
|
||
|
@@ -66,6 +76,27 @@ void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+
|
||
|
+ if (crtc >= rdev->num_crtc)
|
||
|
+ return;
|
||
|
+
|
||
|
+ if (RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[crtc]) & EVERGREEN_CRTC_MASTER_EN) {
|
||
|
+ for (i = 0; i < rdev->usec_timeout; i++) {
|
||
|
+ if (!(RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK))
|
||
|
+ break;
|
||
|
+ udelay(1);
|
||
|
+ }
|
||
|
+ for (i = 0; i < rdev->usec_timeout; i++) {
|
||
|
+ if (RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK)
|
||
|
+ break;
|
||
|
+ udelay(1);
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc)
|
||
|
{
|
||
|
/* enable the pflip int */
|
||
|
@@ -1065,116 +1096,88 @@ void evergreen_agp_enable(struct radeon_device *rdev)
|
||
|
|
||
|
void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
|
||
|
{
|
||
|
+ u32 crtc_enabled, tmp, frame_count, blackout;
|
||
|
+ int i, j;
|
||
|
+
|
||
|
save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
|
||
|
save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
|
||
|
|
||
|
- /* Stop all video */
|
||
|
+ /* disable VGA render */
|
||
|
WREG32(VGA_RENDER_CONTROL, 0);
|
||
|
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
|
||
|
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
|
||
|
- if (rdev->num_crtc >= 4) {
|
||
|
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
|
||
|
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
|
||
|
- }
|
||
|
- if (rdev->num_crtc >= 6) {
|
||
|
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
|
||
|
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
|
||
|
- }
|
||
|
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
|
||
|
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
|
||
|
- if (rdev->num_crtc >= 4) {
|
||
|
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
|
||
|
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
|
||
|
- }
|
||
|
- if (rdev->num_crtc >= 6) {
|
||
|
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
|
||
|
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
|
||
|
- }
|
||
|
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
|
||
|
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
|
||
|
- if (rdev->num_crtc >= 4) {
|
||
|
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
|
||
|
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
|
||
|
- }
|
||
|
- if (rdev->num_crtc >= 6) {
|
||
|
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
|
||
|
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
|
||
|
+ /* blank the display controllers */
|
||
|
+ for (i = 0; i < rdev->num_crtc; i++) {
|
||
|
+ crtc_enabled = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]) & EVERGREEN_CRTC_MASTER_EN;
|
||
|
+ if (crtc_enabled) {
|
||
|
+ save->crtc_enabled[i] = true;
|
||
|
+ tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
|
||
|
+ if (!(tmp & EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE)) {
|
||
|
+ dce4_wait_for_vblank(rdev, i);
|
||
|
+ tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE;
|
||
|
+ WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp);
|
||
|
+ }
|
||
|
+ /* wait for the next frame */
|
||
|
+ frame_count = radeon_get_vblank_counter(rdev, i);
|
||
|
+ for (j = 0; j < rdev->usec_timeout; j++) {
|
||
|
+ if (radeon_get_vblank_counter(rdev, i) != frame_count)
|
||
|
+ break;
|
||
|
+ udelay(1);
|
||
|
+ }
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
- WREG32(D1VGA_CONTROL, 0);
|
||
|
- WREG32(D2VGA_CONTROL, 0);
|
||
|
- if (rdev->num_crtc >= 4) {
|
||
|
- WREG32(EVERGREEN_D3VGA_CONTROL, 0);
|
||
|
- WREG32(EVERGREEN_D4VGA_CONTROL, 0);
|
||
|
- }
|
||
|
- if (rdev->num_crtc >= 6) {
|
||
|
- WREG32(EVERGREEN_D5VGA_CONTROL, 0);
|
||
|
- WREG32(EVERGREEN_D6VGA_CONTROL, 0);
|
||
|
+ evergreen_mc_wait_for_idle(rdev);
|
||
|
+
|
||
|
+ blackout = RREG32(MC_SHARED_BLACKOUT_CNTL);
|
||
|
+ if ((blackout & BLACKOUT_MODE_MASK) != 1) {
|
||
|
+ /* Block CPU access */
|
||
|
+ WREG32(BIF_FB_EN, 0);
|
||
|
+ /* blackout the MC */
|
||
|
+ blackout &= ~BLACKOUT_MODE_MASK;
|
||
|
+ WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save)
|
||
|
{
|
||
|
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET,
|
||
|
- upper_32_bits(rdev->mc.vram_start));
|
||
|
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET,
|
||
|
- upper_32_bits(rdev->mc.vram_start));
|
||
|
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET,
|
||
|
- (u32)rdev->mc.vram_start);
|
||
|
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET,
|
||
|
- (u32)rdev->mc.vram_start);
|
||
|
-
|
||
|
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET,
|
||
|
- upper_32_bits(rdev->mc.vram_start));
|
||
|
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET,
|
||
|
- upper_32_bits(rdev->mc.vram_start));
|
||
|
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET,
|
||
|
- (u32)rdev->mc.vram_start);
|
||
|
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET,
|
||
|
- (u32)rdev->mc.vram_start);
|
||
|
-
|
||
|
- if (rdev->num_crtc >= 4) {
|
||
|
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
|
||
|
- upper_32_bits(rdev->mc.vram_start));
|
||
|
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
|
||
|
- upper_32_bits(rdev->mc.vram_start));
|
||
|
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET,
|
||
|
- (u32)rdev->mc.vram_start);
|
||
|
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET,
|
||
|
- (u32)rdev->mc.vram_start);
|
||
|
-
|
||
|
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET,
|
||
|
- upper_32_bits(rdev->mc.vram_start));
|
||
|
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET,
|
||
|
- upper_32_bits(rdev->mc.vram_start));
|
||
|
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET,
|
||
|
- (u32)rdev->mc.vram_start);
|
||
|
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET,
|
||
|
- (u32)rdev->mc.vram_start);
|
||
|
- }
|
||
|
- if (rdev->num_crtc >= 6) {
|
||
|
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
|
||
|
- upper_32_bits(rdev->mc.vram_start));
|
||
|
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
|
||
|
- upper_32_bits(rdev->mc.vram_start));
|
||
|
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
|
||
|
- (u32)rdev->mc.vram_start);
|
||
|
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
|
||
|
- (u32)rdev->mc.vram_start);
|
||
|
+ u32 tmp, frame_count;
|
||
|
+ int i, j;
|
||
|
|
||
|
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
|
||
|
+ /* update crtc base addresses */
|
||
|
+ for (i = 0; i < rdev->num_crtc; i++) {
|
||
|
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
|
||
|
upper_32_bits(rdev->mc.vram_start));
|
||
|
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
|
||
|
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
|
||
|
upper_32_bits(rdev->mc.vram_start));
|
||
|
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
|
||
|
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i],
|
||
|
(u32)rdev->mc.vram_start);
|
||
|
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
|
||
|
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i],
|
||
|
(u32)rdev->mc.vram_start);
|
||
|
}
|
||
|
-
|
||
|
WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start));
|
||
|
WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start);
|
||
|
- /* Unlock host access */
|
||
|
+
|
||
|
+ /* unblackout the MC */
|
||
|
+ tmp = RREG32(MC_SHARED_BLACKOUT_CNTL);
|
||
|
+ tmp &= ~BLACKOUT_MODE_MASK;
|
||
|
+ WREG32(MC_SHARED_BLACKOUT_CNTL, tmp);
|
||
|
+ /* allow CPU access */
|
||
|
+ WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
|
||
|
+
|
||
|
+ for (i = 0; i < rdev->num_crtc; i++) {
|
||
|
+ if (save->crtc_enabled) {
|
||
|
+ tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
|
||
|
+ tmp &= ~EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE;
|
||
|
+ WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp);
|
||
|
+ /* wait for the next frame */
|
||
|
+ frame_count = radeon_get_vblank_counter(rdev, i);
|
||
|
+ for (j = 0; j < rdev->usec_timeout; j++) {
|
||
|
+ if (radeon_get_vblank_counter(rdev, i) != frame_count)
|
||
|
+ break;
|
||
|
+ udelay(1);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ /* Unlock vga access */
|
||
|
WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);
|
||
|
mdelay(1);
|
||
|
WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
|
||
|
diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h
|
||
|
index 7d7f215..e022776 100644
|
||
|
--- a/drivers/gpu/drm/radeon/evergreen_reg.h
|
||
|
+++ b/drivers/gpu/drm/radeon/evergreen_reg.h
|
||
|
@@ -210,7 +210,10 @@
|
||
|
#define EVERGREEN_CRTC_CONTROL 0x6e70
|
||
|
# define EVERGREEN_CRTC_MASTER_EN (1 << 0)
|
||
|
# define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24)
|
||
|
+#define EVERGREEN_CRTC_BLANK_CONTROL 0x6e74
|
||
|
+# define EVERGREEN_CRTC_BLANK_DATA_EN (1 << 8)
|
||
|
#define EVERGREEN_CRTC_STATUS 0x6e8c
|
||
|
+# define EVERGREEN_CRTC_V_BLANK (1 << 0)
|
||
|
#define EVERGREEN_CRTC_STATUS_POSITION 0x6e90
|
||
|
#define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8
|
||
|
#define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4
|
||
|
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
|
||
|
index 6ecd23f..fe44a95 100644
|
||
|
--- a/drivers/gpu/drm/radeon/evergreend.h
|
||
|
+++ b/drivers/gpu/drm/radeon/evergreend.h
|
||
|
@@ -77,6 +77,10 @@
|
||
|
|
||
|
#define CONFIG_MEMSIZE 0x5428
|
||
|
|
||
|
+#define BIF_FB_EN 0x5490
|
||
|
+#define FB_READ_EN (1 << 0)
|
||
|
+#define FB_WRITE_EN (1 << 1)
|
||
|
+
|
||
|
#define CP_ME_CNTL 0x86D8
|
||
|
#define CP_ME_HALT (1 << 28)
|
||
|
#define CP_PFP_HALT (1 << 26)
|
||
|
@@ -194,6 +198,9 @@
|
||
|
#define NOOFCHAN_MASK 0x00003000
|
||
|
#define MC_SHARED_CHREMAP 0x2008
|
||
|
|
||
|
+#define MC_SHARED_BLACKOUT_CNTL 0x20ac
|
||
|
+#define BLACKOUT_MODE_MASK 0x00000007
|
||
|
+
|
||
|
#define MC_ARB_RAMCFG 0x2760
|
||
|
#define NOOFBANK_SHIFT 0
|
||
|
#define NOOFBANK_MASK 0x00000003
|
||
|
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
|
||
|
index 5ce9402..5aa6670 100644
|
||
|
--- a/drivers/gpu/drm/radeon/radeon_asic.h
|
||
|
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
|
||
|
@@ -386,6 +386,7 @@ void r700_cp_fini(struct radeon_device *rdev);
|
||
|
struct evergreen_mc_save {
|
||
|
u32 vga_render_control;
|
||
|
u32 vga_hdp_control;
|
||
|
+ bool crtc_enabled[RADEON_MAX_CRTCS];
|
||
|
};
|
||
|
|
||
|
void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev);
|
||
|
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
|
||
|
index baa019e..4f9496e 100644
|
||
|
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
|
||
|
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
|
||
|
@@ -143,6 +143,16 @@ static bool radeon_msi_ok(struct radeon_device *rdev)
|
||
|
(rdev->pdev->subsystem_device == 0x01fd))
|
||
|
return true;
|
||
|
|
||
|
+ /* Gateway RS690 only seems to work with MSIs. */
|
||
|
+ if ((rdev->pdev->device == 0x791f) &&
|
||
|
+ (rdev->pdev->subsystem_vendor == 0x107b) &&
|
||
|
+ (rdev->pdev->subsystem_device == 0x0185))
|
||
|
+ return true;
|
||
|
+
|
||
|
+ /* try and enable MSIs by default on all RS690s */
|
||
|
+ if (rdev->family == CHIP_RS690)
|
||
|
+ return true;
|
||
|
+
|
||
|
/* RV515 seems to have MSI issues where it loses
|
||
|
* MSI rearms occasionally. This leads to lockups and freezes.
|
||
|
* disable it by default.
|
||
|
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
|
||
|
index 78a665b..ebd6c51 100644
|
||
|
--- a/drivers/gpu/drm/radeon/radeon_pm.c
|
||
|
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
|
||
|
@@ -553,7 +553,9 @@ void radeon_pm_suspend(struct radeon_device *rdev)
|
||
|
void radeon_pm_resume(struct radeon_device *rdev)
|
||
|
{
|
||
|
/* set up the default clocks if the MC ucode is loaded */
|
||
|
- if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) {
|
||
|
+ if ((rdev->family >= CHIP_BARTS) &&
|
||
|
+ (rdev->family <= CHIP_CAYMAN) &&
|
||
|
+ rdev->mc_fw) {
|
||
|
if (rdev->pm.default_vddc)
|
||
|
radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
|
||
|
SET_VOLTAGE_TYPE_ASIC_VDDC);
|
||
|
@@ -608,7 +610,9 @@ int radeon_pm_init(struct radeon_device *rdev)
|
||
|
radeon_pm_print_states(rdev);
|
||
|
radeon_pm_init_profile(rdev);
|
||
|
/* set up the default clocks if the MC ucode is loaded */
|
||
|
- if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) {
|
||
|
+ if ((rdev->family >= CHIP_BARTS) &&
|
||
|
+ (rdev->family <= CHIP_CAYMAN) &&
|
||
|
+ rdev->mc_fw) {
|
||
|
if (rdev->pm.default_vddc)
|
||
|
radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
|
||
|
SET_VOLTAGE_TYPE_ASIC_VDDC);
|
||
|
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
|
||
|
index fe2fdbb..1740b82 100644
|
||
|
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
|
||
|
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
|
||
|
@@ -148,7 +148,7 @@ static int ipoib_stop(struct net_device *dev)
|
||
|
|
||
|
netif_stop_queue(dev);
|
||
|
|
||
|
- ipoib_ib_dev_down(dev, 0);
|
||
|
+ ipoib_ib_dev_down(dev, 1);
|
||
|
ipoib_ib_dev_stop(dev, 0);
|
||
|
|
||
|
if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
|
||
|
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
|
||
|
index e5069b4..80799c0 100644
|
||
|
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
|
||
|
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
|
||
|
@@ -190,7 +190,9 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
|
||
|
|
||
|
mcast->mcmember = *mcmember;
|
||
|
|
||
|
- /* Set the cached Q_Key before we attach if it's the broadcast group */
|
||
|
+ /* Set the multicast MTU and cached Q_Key before we attach if it's
|
||
|
+ * the broadcast group.
|
||
|
+ */
|
||
|
if (!memcmp(mcast->mcmember.mgid.raw, priv->dev->broadcast + 4,
|
||
|
sizeof (union ib_gid))) {
|
||
|
spin_lock_irq(&priv->lock);
|
||
|
@@ -198,10 +200,17 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
|
||
|
spin_unlock_irq(&priv->lock);
|
||
|
return -EAGAIN;
|
||
|
}
|
||
|
+ priv->mcast_mtu = IPOIB_UD_MTU(ib_mtu_enum_to_int(priv->broadcast->mcmember.mtu));
|
||
|
priv->qkey = be32_to_cpu(priv->broadcast->mcmember.qkey);
|
||
|
spin_unlock_irq(&priv->lock);
|
||
|
priv->tx_wr.wr.ud.remote_qkey = priv->qkey;
|
||
|
set_qkey = 1;
|
||
|
+
|
||
|
+ if (!ipoib_cm_admin_enabled(dev)) {
|
||
|
+ rtnl_lock();
|
||
|
+ dev_set_mtu(dev, min(priv->mcast_mtu, priv->admin_mtu));
|
||
|
+ rtnl_unlock();
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
|
||
|
@@ -590,14 +599,6 @@ void ipoib_mcast_join_task(struct work_struct *work)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
- priv->mcast_mtu = IPOIB_UD_MTU(ib_mtu_enum_to_int(priv->broadcast->mcmember.mtu));
|
||
|
-
|
||
|
- if (!ipoib_cm_admin_enabled(dev)) {
|
||
|
- rtnl_lock();
|
||
|
- dev_set_mtu(dev, min(priv->mcast_mtu, priv->admin_mtu));
|
||
|
- rtnl_unlock();
|
||
|
- }
|
||
|
-
|
||
|
ipoib_dbg_mcast(priv, "successfully joined all multicast groups\n");
|
||
|
|
||
|
clear_bit(IPOIB_MCAST_RUN, &priv->flags);
|
||
|
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
|
||
|
index c76b051..4ec049d 100644
|
||
|
--- a/drivers/infiniband/ulp/srp/ib_srp.c
|
||
|
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
|
||
|
@@ -620,9 +620,9 @@ static void srp_reset_req(struct srp_target_port *target, struct srp_request *re
|
||
|
struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL);
|
||
|
|
||
|
if (scmnd) {
|
||
|
+ srp_free_req(target, req, scmnd, 0);
|
||
|
scmnd->result = DID_RESET << 16;
|
||
|
scmnd->scsi_done(scmnd);
|
||
|
- srp_free_req(target, req, scmnd, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -1669,6 +1669,7 @@ static int srp_abort(struct scsi_cmnd *scmnd)
|
||
|
SRP_TSK_ABORT_TASK);
|
||
|
srp_free_req(target, req, scmnd, 0);
|
||
|
scmnd->result = DID_ABORT << 16;
|
||
|
+ scmnd->scsi_done(scmnd);
|
||
|
|
||
|
return SUCCESS;
|
||
|
}
|
||
|
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
|
||
|
index 96532bc..7be5fd9 100644
|
||
|
--- a/drivers/input/mouse/synaptics.c
|
||
|
+++ b/drivers/input/mouse/synaptics.c
|
||
|
@@ -53,14 +53,19 @@
|
||
|
#define ABS_POS_BITS 13
|
||
|
|
||
|
/*
|
||
|
- * Any position values from the hardware above the following limits are
|
||
|
- * treated as "wrapped around negative" values that have been truncated to
|
||
|
- * the 13-bit reporting range of the hardware. These are just reasonable
|
||
|
- * guesses and can be adjusted if hardware is found that operates outside
|
||
|
- * of these parameters.
|
||
|
+ * These values should represent the absolute maximum value that will
|
||
|
+ * be reported for a positive position value. Some Synaptics firmware
|
||
|
+ * uses this value to indicate a finger near the edge of the touchpad
|
||
|
+ * whose precise position cannot be determined.
|
||
|
+ *
|
||
|
+ * At least one touchpad is known to report positions in excess of this
|
||
|
+ * value which are actually negative values truncated to the 13-bit
|
||
|
+ * reporting range. These values have never been observed to be lower
|
||
|
+ * than 8184 (i.e. -8), so we treat all values greater than 8176 as
|
||
|
+ * negative and any other value as positive.
|
||
|
*/
|
||
|
-#define X_MAX_POSITIVE (((1 << ABS_POS_BITS) + XMAX) / 2)
|
||
|
-#define Y_MAX_POSITIVE (((1 << ABS_POS_BITS) + YMAX) / 2)
|
||
|
+#define X_MAX_POSITIVE 8176
|
||
|
+#define Y_MAX_POSITIVE 8176
|
||
|
|
||
|
/*
|
||
|
* Synaptics touchpads report the y coordinate from bottom to top, which is
|
||
|
@@ -561,11 +566,21 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
|
||
|
hw->right = (buf[0] & 0x02) ? 1 : 0;
|
||
|
}
|
||
|
|
||
|
- /* Convert wrap-around values to negative */
|
||
|
+ /*
|
||
|
+ * Convert wrap-around values to negative. (X|Y)_MAX_POSITIVE
|
||
|
+ * is used by some firmware to indicate a finger at the edge of
|
||
|
+ * the touchpad whose precise position cannot be determined, so
|
||
|
+ * convert these values to the maximum axis value.
|
||
|
+ */
|
||
|
if (hw->x > X_MAX_POSITIVE)
|
||
|
hw->x -= 1 << ABS_POS_BITS;
|
||
|
+ else if (hw->x == X_MAX_POSITIVE)
|
||
|
+ hw->x = XMAX;
|
||
|
+
|
||
|
if (hw->y > Y_MAX_POSITIVE)
|
||
|
hw->y -= 1 << ABS_POS_BITS;
|
||
|
+ else if (hw->y == Y_MAX_POSITIVE)
|
||
|
+ hw->y = YMAX;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
|
||
|
index ccf347f..b9062c0 100644
|
||
|
--- a/drivers/iommu/intel-iommu.c
|
||
|
+++ b/drivers/iommu/intel-iommu.c
|
||
|
@@ -563,7 +563,9 @@ static void domain_update_iommu_coherency(struct dmar_domain *domain)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
- domain->iommu_coherency = 1;
|
||
|
+ i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
|
||
|
+
|
||
|
+ domain->iommu_coherency = i < g_num_of_iommus ? 1 : 0;
|
||
|
|
||
|
for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
|
||
|
if (!ecap_coherent(g_iommus[i]->ecap)) {
|
||
|
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
|
||
|
index 0e49c99..c06992e 100644
|
||
|
--- a/drivers/media/rc/ite-cir.c
|
||
|
+++ b/drivers/media/rc/ite-cir.c
|
||
|
@@ -1473,6 +1473,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
|
||
|
rdev = rc_allocate_device();
|
||
|
if (!rdev)
|
||
|
goto failure;
|
||
|
+ itdev->rdev = rdev;
|
||
|
|
||
|
ret = -ENODEV;
|
||
|
|
||
|
@@ -1604,7 +1605,6 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
|
||
|
if (ret)
|
||
|
goto failure;
|
||
|
|
||
|
- itdev->rdev = rdev;
|
||
|
ite_pr(KERN_NOTICE, "driver has been successfully loaded\n");
|
||
|
|
||
|
return 0;
|
||
|
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c
|
||
|
index 1c44f78..6ddc769 100644
|
||
|
--- a/drivers/media/video/gspca/pac7302.c
|
||
|
+++ b/drivers/media/video/gspca/pac7302.c
|
||
|
@@ -1197,6 +1197,8 @@ static const struct usb_device_id device_table[] = {
|
||
|
{USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
|
||
|
{USB_DEVICE(0x093a, 0x262a)},
|
||
|
{USB_DEVICE(0x093a, 0x262c)},
|
||
|
+ {USB_DEVICE(0x145f, 0x013c)},
|
||
|
+ {USB_DEVICE(0x1ae7, 0x2001)}, /* SpeedLink Snappy Mic SL-6825-SBK */
|
||
|
{}
|
||
|
};
|
||
|
MODULE_DEVICE_TABLE(usb, device_table);
|
||
|
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
|
||
|
index d5fe43d..bc27065 100644
|
||
|
--- a/drivers/mmc/host/omap_hsmmc.c
|
||
|
+++ b/drivers/mmc/host/omap_hsmmc.c
|
||
|
@@ -2188,9 +2188,7 @@ static int omap_hsmmc_suspend(struct device *dev)
|
||
|
} else {
|
||
|
host->suspended = 0;
|
||
|
if (host->pdata->resume) {
|
||
|
- ret = host->pdata->resume(&pdev->dev,
|
||
|
- host->slot_id);
|
||
|
- if (ret)
|
||
|
+ if (host->pdata->resume(&pdev->dev, host->slot_id))
|
||
|
dev_dbg(mmc_dev(host->mmc),
|
||
|
"Unmask interrupt failed\n");
|
||
|
}
|
||
|
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
|
||
|
index 0d33ff0..06af9e4 100644
|
||
|
--- a/drivers/mmc/host/sdhci-s3c.c
|
||
|
+++ b/drivers/mmc/host/sdhci-s3c.c
|
||
|
@@ -601,7 +601,7 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
|
||
|
|
||
|
sdhci_remove_host(host, 1);
|
||
|
|
||
|
- for (ptr = 0; ptr < 3; ptr++) {
|
||
|
+ for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
|
||
|
if (sc->clk_bus[ptr]) {
|
||
|
clk_disable(sc->clk_bus[ptr]);
|
||
|
clk_put(sc->clk_bus[ptr]);
|
||
|
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
|
||
|
index d5505f3..559d30d 100644
|
||
|
--- a/drivers/mmc/host/sh_mmcif.c
|
||
|
+++ b/drivers/mmc/host/sh_mmcif.c
|
||
|
@@ -1003,6 +1003,10 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
|
||
|
host->sd_error = true;
|
||
|
dev_dbg(&host->pd->dev, "int err state = %08x\n", state);
|
||
|
}
|
||
|
+ if (host->state == STATE_IDLE) {
|
||
|
+ dev_info(&host->pd->dev, "Spurious IRQ status 0x%x", state);
|
||
|
+ return IRQ_HANDLED;
|
||
|
+ }
|
||
|
if (state & ~(INT_CMD12RBE | INT_CMD12CRE))
|
||
|
complete(&host->intr_wait);
|
||
|
else
|
||
|
diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c
|
||
|
index e5bfd0e..0598d52 100644
|
||
|
--- a/drivers/mtd/maps/autcpu12-nvram.c
|
||
|
+++ b/drivers/mtd/maps/autcpu12-nvram.c
|
||
|
@@ -43,7 +43,8 @@ struct map_info autcpu12_sram_map = {
|
||
|
|
||
|
static int __init init_autcpu12_sram (void)
|
||
|
{
|
||
|
- int err, save0, save1;
|
||
|
+ map_word tmp, save0, save1;
|
||
|
+ int err;
|
||
|
|
||
|
autcpu12_sram_map.virt = ioremap(0x12000000, SZ_128K);
|
||
|
if (!autcpu12_sram_map.virt) {
|
||
|
@@ -51,7 +52,7 @@ static int __init init_autcpu12_sram (void)
|
||
|
err = -EIO;
|
||
|
goto out;
|
||
|
}
|
||
|
- simple_map_init(&autcpu_sram_map);
|
||
|
+ simple_map_init(&autcpu12_sram_map);
|
||
|
|
||
|
/*
|
||
|
* Check for 32K/128K
|
||
|
@@ -61,20 +62,22 @@ static int __init init_autcpu12_sram (void)
|
||
|
* Read and check result on ofs 0x0
|
||
|
* Restore contents
|
||
|
*/
|
||
|
- save0 = map_read32(&autcpu12_sram_map,0);
|
||
|
- save1 = map_read32(&autcpu12_sram_map,0x10000);
|
||
|
- map_write32(&autcpu12_sram_map,~save0,0x10000);
|
||
|
+ save0 = map_read(&autcpu12_sram_map, 0);
|
||
|
+ save1 = map_read(&autcpu12_sram_map, 0x10000);
|
||
|
+ tmp.x[0] = ~save0.x[0];
|
||
|
+ map_write(&autcpu12_sram_map, tmp, 0x10000);
|
||
|
/* if we find this pattern on 0x0, we have 32K size
|
||
|
* restore contents and exit
|
||
|
*/
|
||
|
- if ( map_read32(&autcpu12_sram_map,0) != save0) {
|
||
|
- map_write32(&autcpu12_sram_map,save0,0x0);
|
||
|
+ tmp = map_read(&autcpu12_sram_map, 0);
|
||
|
+ if (!map_word_equal(&autcpu12_sram_map, tmp, save0)) {
|
||
|
+ map_write(&autcpu12_sram_map, save0, 0x0);
|
||
|
goto map;
|
||
|
}
|
||
|
/* We have a 128K found, restore 0x10000 and set size
|
||
|
* to 128K
|
||
|
*/
|
||
|
- map_write32(&autcpu12_sram_map,save1,0x10000);
|
||
|
+ map_write(&autcpu12_sram_map, save1, 0x10000);
|
||
|
autcpu12_sram_map.size = SZ_128K;
|
||
|
|
||
|
map:
|
||
|
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
|
||
|
index a0bd2de..198da0a 100644
|
||
|
--- a/drivers/mtd/mtdpart.c
|
||
|
+++ b/drivers/mtd/mtdpart.c
|
||
|
@@ -748,6 +748,8 @@ static const char *default_mtd_part_types[] = {
|
||
|
* partition parsers, specified in @types. However, if @types is %NULL, then
|
||
|
* the default list of parsers is used. The default list contains only the
|
||
|
* "cmdlinepart" and "ofpart" parsers ATM.
|
||
|
+ * Note: If there are more then one parser in @types, the kernel only takes the
|
||
|
+ * partitions parsed out by the first parser.
|
||
|
*
|
||
|
* This function may return:
|
||
|
* o a negative error code in case of failure
|
||
|
@@ -772,11 +774,12 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,
|
||
|
if (!parser)
|
||
|
continue;
|
||
|
ret = (*parser->parse_fn)(master, pparts, data);
|
||
|
+ put_partition_parser(parser);
|
||
|
if (ret > 0) {
|
||
|
printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
|
||
|
ret, parser->name, master->name);
|
||
|
+ break;
|
||
|
}
|
||
|
- put_partition_parser(parser);
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
|
||
|
index f024375..532da04 100644
|
||
|
--- a/drivers/mtd/nand/nand_bbt.c
|
||
|
+++ b/drivers/mtd/nand/nand_bbt.c
|
||
|
@@ -390,7 +390,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
|
||
|
/* Read the mirror version, if available */
|
||
|
if (md && (md->options & NAND_BBT_VERSION)) {
|
||
|
scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
|
||
|
- mtd->writesize, td);
|
||
|
+ mtd->writesize, md);
|
||
|
md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
|
||
|
pr_info("Bad block table at page %d, version 0x%02X\n",
|
||
|
md->pages[0], md->version[0]);
|
||
|
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
|
||
|
index 83e8e1b..ade0da0 100644
|
||
|
--- a/drivers/mtd/nand/nandsim.c
|
||
|
+++ b/drivers/mtd/nand/nandsim.c
|
||
|
@@ -2355,6 +2355,7 @@ static int __init ns_init_module(void)
|
||
|
uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize;
|
||
|
if (new_size >> overridesize != nsmtd->erasesize) {
|
||
|
NS_ERR("overridesize is too big\n");
|
||
|
+ retval = -EINVAL;
|
||
|
goto err_exit;
|
||
|
}
|
||
|
/* N.B. This relies on nand_scan not doing anything with the size before we change it */
|
||
|
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
|
||
|
index f745f00..297c965 100644
|
||
|
--- a/drivers/mtd/nand/omap2.c
|
||
|
+++ b/drivers/mtd/nand/omap2.c
|
||
|
@@ -1132,7 +1132,8 @@ static int omap_nand_remove(struct platform_device *pdev)
|
||
|
/* Release NAND device, its internal structures and partitions */
|
||
|
nand_release(&info->mtd);
|
||
|
iounmap(info->nand.IO_ADDR_R);
|
||
|
- kfree(&info->mtd);
|
||
|
+ release_mem_region(info->phys_base, NAND_IO_SIZE);
|
||
|
+ kfree(info);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
|
||
|
index 6c3fb5a..1f9c363 100644
|
||
|
--- a/drivers/mtd/ubi/build.c
|
||
|
+++ b/drivers/mtd/ubi/build.c
|
||
|
@@ -816,6 +816,11 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
|
||
|
struct ubi_volume *vol = ubi->volumes[vol_id];
|
||
|
int err, old_reserved_pebs = vol->reserved_pebs;
|
||
|
|
||
|
+ if (ubi->ro_mode) {
|
||
|
+ ubi_warn("skip auto-resize because of R/O mode");
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
/*
|
||
|
* Clear the auto-resize flag in the volume in-memory copy of the
|
||
|
* volume table, and 'ubi_resize_volume()' will propagate this change
|
||
|
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
|
||
|
index b99318e..b2b62de 100644
|
||
|
--- a/drivers/mtd/ubi/scan.c
|
||
|
+++ b/drivers/mtd/ubi/scan.c
|
||
|
@@ -997,7 +997,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
|
||
|
return err;
|
||
|
goto adjust_mean_ec;
|
||
|
case UBI_IO_FF:
|
||
|
- if (ec_err)
|
||
|
+ if (ec_err || bitflips)
|
||
|
err = add_to_list(si, pnum, ec, 1, &si->erase);
|
||
|
else
|
||
|
err = add_to_list(si, pnum, ec, 0, &si->free);
|
||
|
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
|
||
|
index 5fedc33..d8f2b5b 100644
|
||
|
--- a/drivers/net/can/mscan/mpc5xxx_can.c
|
||
|
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
|
||
|
@@ -181,7 +181,7 @@ static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev,
|
||
|
|
||
|
if (!clock_name || !strcmp(clock_name, "sys")) {
|
||
|
sys_clk = clk_get(&ofdev->dev, "sys_clk");
|
||
|
- if (!sys_clk) {
|
||
|
+ if (IS_ERR(sys_clk)) {
|
||
|
dev_err(&ofdev->dev, "couldn't get sys_clk\n");
|
||
|
goto exit_unmap;
|
||
|
}
|
||
|
@@ -204,7 +204,7 @@ static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev,
|
||
|
|
||
|
if (clocksrc < 0) {
|
||
|
ref_clk = clk_get(&ofdev->dev, "ref_clk");
|
||
|
- if (!ref_clk) {
|
||
|
+ if (IS_ERR(ref_clk)) {
|
||
|
dev_err(&ofdev->dev, "couldn't get ref_clk\n");
|
||
|
goto exit_unmap;
|
||
|
}
|
||
|
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
|
||
|
index 0549261..c5f6b0e 100644
|
||
|
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
|
||
|
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
|
||
|
@@ -4720,8 +4720,6 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
|
||
|
|
||
|
netif_device_detach(netdev);
|
||
|
|
||
|
- mutex_lock(&adapter->mutex);
|
||
|
-
|
||
|
if (netif_running(netdev)) {
|
||
|
WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags));
|
||
|
e1000_down(adapter);
|
||
|
@@ -4729,10 +4727,8 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
|
||
|
|
||
|
#ifdef CONFIG_PM
|
||
|
retval = pci_save_state(pdev);
|
||
|
- if (retval) {
|
||
|
- mutex_unlock(&adapter->mutex);
|
||
|
+ if (retval)
|
||
|
return retval;
|
||
|
- }
|
||
|
#endif
|
||
|
|
||
|
status = er32(STATUS);
|
||
|
@@ -4789,8 +4785,6 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
|
||
|
if (netif_running(netdev))
|
||
|
e1000_free_irq(adapter);
|
||
|
|
||
|
- mutex_unlock(&adapter->mutex);
|
||
|
-
|
||
|
pci_disable_device(pdev);
|
||
|
|
||
|
return 0;
|
||
|
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
|
||
|
index ed1be8a..4b43bc5 100644
|
||
|
--- a/drivers/net/ethernet/realtek/r8169.c
|
||
|
+++ b/drivers/net/ethernet/realtek/r8169.c
|
||
|
@@ -327,6 +327,8 @@ enum rtl_registers {
|
||
|
Config0 = 0x51,
|
||
|
Config1 = 0x52,
|
||
|
Config2 = 0x53,
|
||
|
+#define PME_SIGNAL (1 << 5) /* 8168c and later */
|
||
|
+
|
||
|
Config3 = 0x54,
|
||
|
Config4 = 0x55,
|
||
|
Config5 = 0x56,
|
||
|
@@ -1360,7 +1362,6 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
|
||
|
u16 reg;
|
||
|
u8 mask;
|
||
|
} cfg[] = {
|
||
|
- { WAKE_ANY, Config1, PMEnable },
|
||
|
{ WAKE_PHY, Config3, LinkUp },
|
||
|
{ WAKE_MAGIC, Config3, MagicPacket },
|
||
|
{ WAKE_UCAST, Config5, UWF },
|
||
|
@@ -1368,16 +1369,32 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
|
||
|
{ WAKE_MCAST, Config5, MWF },
|
||
|
{ WAKE_ANY, Config5, LanWake }
|
||
|
};
|
||
|
+ u8 options;
|
||
|
|
||
|
RTL_W8(Cfg9346, Cfg9346_Unlock);
|
||
|
|
||
|
for (i = 0; i < ARRAY_SIZE(cfg); i++) {
|
||
|
- u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
|
||
|
+ options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
|
||
|
if (wolopts & cfg[i].opt)
|
||
|
options |= cfg[i].mask;
|
||
|
RTL_W8(cfg[i].reg, options);
|
||
|
}
|
||
|
|
||
|
+ switch (tp->mac_version) {
|
||
|
+ case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_17:
|
||
|
+ options = RTL_R8(Config1) & ~PMEnable;
|
||
|
+ if (wolopts)
|
||
|
+ options |= PMEnable;
|
||
|
+ RTL_W8(Config1, options);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ options = RTL_R8(Config2) & ~PME_SIGNAL;
|
||
|
+ if (wolopts)
|
||
|
+ options |= PME_SIGNAL;
|
||
|
+ RTL_W8(Config2, options);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
RTL_W8(Cfg9346, Cfg9346_Lock);
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
|
||
|
index 7145714..c0f097b 100644
|
||
|
--- a/drivers/net/rionet.c
|
||
|
+++ b/drivers/net/rionet.c
|
||
|
@@ -79,6 +79,7 @@ static int rionet_capable = 1;
|
||
|
* on system trade-offs.
|
||
|
*/
|
||
|
static struct rio_dev **rionet_active;
|
||
|
+static int nact; /* total number of active rionet peers */
|
||
|
|
||
|
#define is_rionet_capable(src_ops, dst_ops) \
|
||
|
((src_ops & RIO_SRC_OPS_DATA_MSG) && \
|
||
|
@@ -175,6 +176,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||
|
struct ethhdr *eth = (struct ethhdr *)skb->data;
|
||
|
u16 destid;
|
||
|
unsigned long flags;
|
||
|
+ int add_num = 1;
|
||
|
|
||
|
local_irq_save(flags);
|
||
|
if (!spin_trylock(&rnet->tx_lock)) {
|
||
|
@@ -182,7 +184,10 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||
|
return NETDEV_TX_LOCKED;
|
||
|
}
|
||
|
|
||
|
- if ((rnet->tx_cnt + 1) > RIONET_TX_RING_SIZE) {
|
||
|
+ if (is_multicast_ether_addr(eth->h_dest))
|
||
|
+ add_num = nact;
|
||
|
+
|
||
|
+ if ((rnet->tx_cnt + add_num) > RIONET_TX_RING_SIZE) {
|
||
|
netif_stop_queue(ndev);
|
||
|
spin_unlock_irqrestore(&rnet->tx_lock, flags);
|
||
|
printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n",
|
||
|
@@ -191,11 +196,16 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||
|
}
|
||
|
|
||
|
if (is_multicast_ether_addr(eth->h_dest)) {
|
||
|
+ int count = 0;
|
||
|
for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size);
|
||
|
i++)
|
||
|
- if (rionet_active[i])
|
||
|
+ if (rionet_active[i]) {
|
||
|
rionet_queue_tx_msg(skb, ndev,
|
||
|
rionet_active[i]);
|
||
|
+ if (count)
|
||
|
+ atomic_inc(&skb->users);
|
||
|
+ count++;
|
||
|
+ }
|
||
|
} else if (RIONET_MAC_MATCH(eth->h_dest)) {
|
||
|
destid = RIONET_GET_DESTID(eth->h_dest);
|
||
|
if (rionet_active[destid])
|
||
|
@@ -220,14 +230,17 @@ static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u
|
||
|
if (info == RIONET_DOORBELL_JOIN) {
|
||
|
if (!rionet_active[sid]) {
|
||
|
list_for_each_entry(peer, &rionet_peers, node) {
|
||
|
- if (peer->rdev->destid == sid)
|
||
|
+ if (peer->rdev->destid == sid) {
|
||
|
rionet_active[sid] = peer->rdev;
|
||
|
+ nact++;
|
||
|
+ }
|
||
|
}
|
||
|
rio_mport_send_doorbell(mport, sid,
|
||
|
RIONET_DOORBELL_JOIN);
|
||
|
}
|
||
|
} else if (info == RIONET_DOORBELL_LEAVE) {
|
||
|
rionet_active[sid] = NULL;
|
||
|
+ nact--;
|
||
|
} else {
|
||
|
if (netif_msg_intr(rnet))
|
||
|
printk(KERN_WARNING "%s: unhandled doorbell\n",
|
||
|
@@ -524,6 +537,7 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
|
||
|
|
||
|
rc = rionet_setup_netdev(rdev->net->hport, ndev);
|
||
|
rionet_check = 1;
|
||
|
+ nact = 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
|
||
|
index 1883d39..f7e17a0 100644
|
||
|
--- a/drivers/net/wireless/ath/ath9k/pci.c
|
||
|
+++ b/drivers/net/wireless/ath/ath9k/pci.c
|
||
|
@@ -122,8 +122,9 @@ static void ath_pci_aspm_init(struct ath_common *common)
|
||
|
if (!parent)
|
||
|
return;
|
||
|
|
||
|
- if (ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) {
|
||
|
- /* Bluetooth coexistance requires disabling ASPM. */
|
||
|
+ if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
|
||
|
+ (AR_SREV_9285(ah))) {
|
||
|
+ /* Bluetooth coexistance requires disabling ASPM for AR9285. */
|
||
|
pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &aspm);
|
||
|
aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
|
||
|
pci_write_config_byte(pdev, pos + PCI_EXP_LNKCTL, aspm);
|
||
|
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
|
||
|
index dfee1b3..9005380 100644
|
||
|
--- a/drivers/pci/probe.c
|
||
|
+++ b/drivers/pci/probe.c
|
||
|
@@ -658,8 +658,10 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
|
||
|
|
||
|
/* Check if setup is sensible at all */
|
||
|
if (!pass &&
|
||
|
- (primary != bus->number || secondary <= bus->number)) {
|
||
|
- dev_dbg(&dev->dev, "bus configuration invalid, reconfiguring\n");
|
||
|
+ (primary != bus->number || secondary <= bus->number ||
|
||
|
+ secondary > subordinate)) {
|
||
|
+ dev_info(&dev->dev, "bridge configuration invalid ([bus %02x-%02x]), reconfiguring\n",
|
||
|
+ secondary, subordinate);
|
||
|
broken = 1;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
|
||
|
index 0860181..4f1b10b 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_aux.c
|
||
|
+++ b/drivers/s390/scsi/zfcp_aux.c
|
||
|
@@ -519,6 +519,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
|
||
|
|
||
|
rwlock_init(&port->unit_list_lock);
|
||
|
INIT_LIST_HEAD(&port->unit_list);
|
||
|
+ atomic_set(&port->units, 0);
|
||
|
|
||
|
INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup);
|
||
|
INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work);
|
||
|
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
|
||
|
index 96f13ad8..79a6afe 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_ccw.c
|
||
|
+++ b/drivers/s390/scsi/zfcp_ccw.c
|
||
|
@@ -39,17 +39,23 @@ void zfcp_ccw_adapter_put(struct zfcp_adapter *adapter)
|
||
|
spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags);
|
||
|
}
|
||
|
|
||
|
-static int zfcp_ccw_activate(struct ccw_device *cdev)
|
||
|
-
|
||
|
+/**
|
||
|
+ * zfcp_ccw_activate - activate adapter and wait for it to finish
|
||
|
+ * @cdev: pointer to belonging ccw device
|
||
|
+ * @clear: Status flags to clear.
|
||
|
+ * @tag: s390dbf trace record tag
|
||
|
+ */
|
||
|
+static int zfcp_ccw_activate(struct ccw_device *cdev, int clear, char *tag)
|
||
|
{
|
||
|
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||
|
|
||
|
if (!adapter)
|
||
|
return 0;
|
||
|
|
||
|
+ zfcp_erp_clear_adapter_status(adapter, clear);
|
||
|
zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING);
|
||
|
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
|
||
|
- "ccresu2");
|
||
|
+ tag);
|
||
|
zfcp_erp_wait(adapter);
|
||
|
flush_work(&adapter->scan_work);
|
||
|
|
||
|
@@ -164,26 +170,29 @@ static int zfcp_ccw_set_online(struct ccw_device *cdev)
|
||
|
BUG_ON(!zfcp_reqlist_isempty(adapter->req_list));
|
||
|
adapter->req_no = 0;
|
||
|
|
||
|
- zfcp_ccw_activate(cdev);
|
||
|
+ zfcp_ccw_activate(cdev, 0, "ccsonl1");
|
||
|
zfcp_ccw_adapter_put(adapter);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
- * zfcp_ccw_set_offline - set_offline function of zfcp driver
|
||
|
+ * zfcp_ccw_offline_sync - shut down adapter and wait for it to finish
|
||
|
* @cdev: pointer to belonging ccw device
|
||
|
+ * @set: Status flags to set.
|
||
|
+ * @tag: s390dbf trace record tag
|
||
|
*
|
||
|
* This function gets called by the common i/o layer and sets an adapter
|
||
|
* into state offline.
|
||
|
*/
|
||
|
-static int zfcp_ccw_set_offline(struct ccw_device *cdev)
|
||
|
+static int zfcp_ccw_offline_sync(struct ccw_device *cdev, int set, char *tag)
|
||
|
{
|
||
|
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||
|
|
||
|
if (!adapter)
|
||
|
return 0;
|
||
|
|
||
|
- zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1");
|
||
|
+ zfcp_erp_set_adapter_status(adapter, set);
|
||
|
+ zfcp_erp_adapter_shutdown(adapter, 0, tag);
|
||
|
zfcp_erp_wait(adapter);
|
||
|
|
||
|
zfcp_ccw_adapter_put(adapter);
|
||
|
@@ -191,6 +200,18 @@ static int zfcp_ccw_set_offline(struct ccw_device *cdev)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
+ * zfcp_ccw_set_offline - set_offline function of zfcp driver
|
||
|
+ * @cdev: pointer to belonging ccw device
|
||
|
+ *
|
||
|
+ * This function gets called by the common i/o layer and sets an adapter
|
||
|
+ * into state offline.
|
||
|
+ */
|
||
|
+static int zfcp_ccw_set_offline(struct ccw_device *cdev)
|
||
|
+{
|
||
|
+ return zfcp_ccw_offline_sync(cdev, 0, "ccsoff1");
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
* zfcp_ccw_notify - ccw notify function
|
||
|
* @cdev: pointer to belonging ccw device
|
||
|
* @event: indicates if adapter was detached or attached
|
||
|
@@ -207,6 +228,11 @@ static int zfcp_ccw_notify(struct ccw_device *cdev, int event)
|
||
|
|
||
|
switch (event) {
|
||
|
case CIO_GONE:
|
||
|
+ if (atomic_read(&adapter->status) &
|
||
|
+ ZFCP_STATUS_ADAPTER_SUSPENDED) { /* notification ignore */
|
||
|
+ zfcp_dbf_hba_basic("ccnigo1", adapter);
|
||
|
+ break;
|
||
|
+ }
|
||
|
dev_warn(&cdev->dev, "The FCP device has been detached\n");
|
||
|
zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1");
|
||
|
break;
|
||
|
@@ -216,6 +242,11 @@ static int zfcp_ccw_notify(struct ccw_device *cdev, int event)
|
||
|
zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2");
|
||
|
break;
|
||
|
case CIO_OPER:
|
||
|
+ if (atomic_read(&adapter->status) &
|
||
|
+ ZFCP_STATUS_ADAPTER_SUSPENDED) { /* notification ignore */
|
||
|
+ zfcp_dbf_hba_basic("ccniop1", adapter);
|
||
|
+ break;
|
||
|
+ }
|
||
|
dev_info(&cdev->dev, "The FCP device is operational again\n");
|
||
|
zfcp_erp_set_adapter_status(adapter,
|
||
|
ZFCP_STATUS_COMMON_RUNNING);
|
||
|
@@ -251,6 +282,28 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev)
|
||
|
zfcp_ccw_adapter_put(adapter);
|
||
|
}
|
||
|
|
||
|
+static int zfcp_ccw_suspend(struct ccw_device *cdev)
|
||
|
+{
|
||
|
+ zfcp_ccw_offline_sync(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccsusp1");
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int zfcp_ccw_thaw(struct ccw_device *cdev)
|
||
|
+{
|
||
|
+ /* trace records for thaw and final shutdown during suspend
|
||
|
+ can only be found in system dump until the end of suspend
|
||
|
+ but not after resume because it's based on the memory image
|
||
|
+ right after the very first suspend (freeze) callback */
|
||
|
+ zfcp_ccw_activate(cdev, 0, "ccthaw1");
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int zfcp_ccw_resume(struct ccw_device *cdev)
|
||
|
+{
|
||
|
+ zfcp_ccw_activate(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccresu1");
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
struct ccw_driver zfcp_ccw_driver = {
|
||
|
.driver = {
|
||
|
.owner = THIS_MODULE,
|
||
|
@@ -263,7 +316,7 @@ struct ccw_driver zfcp_ccw_driver = {
|
||
|
.set_offline = zfcp_ccw_set_offline,
|
||
|
.notify = zfcp_ccw_notify,
|
||
|
.shutdown = zfcp_ccw_shutdown,
|
||
|
- .freeze = zfcp_ccw_set_offline,
|
||
|
- .thaw = zfcp_ccw_activate,
|
||
|
- .restore = zfcp_ccw_activate,
|
||
|
+ .freeze = zfcp_ccw_suspend,
|
||
|
+ .thaw = zfcp_ccw_thaw,
|
||
|
+ .restore = zfcp_ccw_resume,
|
||
|
};
|
||
|
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c
|
||
|
index fab2c25..8ed63aa 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_cfdc.c
|
||
|
+++ b/drivers/s390/scsi/zfcp_cfdc.c
|
||
|
@@ -293,7 +293,7 @@ void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *adapter)
|
||
|
}
|
||
|
read_unlock_irqrestore(&adapter->port_list_lock, flags);
|
||
|
|
||
|
- shost_for_each_device(sdev, port->adapter->scsi_host) {
|
||
|
+ shost_for_each_device(sdev, adapter->scsi_host) {
|
||
|
zfcp_sdev = sdev_to_zfcp(sdev);
|
||
|
status = atomic_read(&zfcp_sdev->status);
|
||
|
if ((status & ZFCP_STATUS_COMMON_ACCESS_DENIED) ||
|
||
|
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
|
||
|
index a9a816e..79b9848 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_dbf.c
|
||
|
+++ b/drivers/s390/scsi/zfcp_dbf.c
|
||
|
@@ -191,7 +191,7 @@ void zfcp_dbf_hba_def_err(struct zfcp_adapter *adapter, u64 req_id, u16 scount,
|
||
|
length = min((u16)sizeof(struct qdio_buffer),
|
||
|
(u16)ZFCP_DBF_PAY_MAX_REC);
|
||
|
|
||
|
- while ((char *)pl[payload->counter] && payload->counter < scount) {
|
||
|
+ while (payload->counter < scount && (char *)pl[payload->counter]) {
|
||
|
memcpy(payload->data, (char *)pl[payload->counter], length);
|
||
|
debug_event(dbf->pay, 1, payload, zfcp_dbf_plen(length));
|
||
|
payload->counter++;
|
||
|
@@ -200,6 +200,26 @@ void zfcp_dbf_hba_def_err(struct zfcp_adapter *adapter, u64 req_id, u16 scount,
|
||
|
spin_unlock_irqrestore(&dbf->pay_lock, flags);
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * zfcp_dbf_hba_basic - trace event for basic adapter events
|
||
|
+ * @adapter: pointer to struct zfcp_adapter
|
||
|
+ */
|
||
|
+void zfcp_dbf_hba_basic(char *tag, struct zfcp_adapter *adapter)
|
||
|
+{
|
||
|
+ struct zfcp_dbf *dbf = adapter->dbf;
|
||
|
+ struct zfcp_dbf_hba *rec = &dbf->hba_buf;
|
||
|
+ unsigned long flags;
|
||
|
+
|
||
|
+ spin_lock_irqsave(&dbf->hba_lock, flags);
|
||
|
+ memset(rec, 0, sizeof(*rec));
|
||
|
+
|
||
|
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
|
||
|
+ rec->id = ZFCP_DBF_HBA_BASIC;
|
||
|
+
|
||
|
+ debug_event(dbf->hba, 1, rec, sizeof(*rec));
|
||
|
+ spin_unlock_irqrestore(&dbf->hba_lock, flags);
|
||
|
+}
|
||
|
+
|
||
|
static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec,
|
||
|
struct zfcp_adapter *adapter,
|
||
|
struct zfcp_port *port,
|
||
|
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h
|
||
|
index 714f087..3ac7a4b 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_dbf.h
|
||
|
+++ b/drivers/s390/scsi/zfcp_dbf.h
|
||
|
@@ -154,6 +154,7 @@ enum zfcp_dbf_hba_id {
|
||
|
ZFCP_DBF_HBA_RES = 1,
|
||
|
ZFCP_DBF_HBA_USS = 2,
|
||
|
ZFCP_DBF_HBA_BIT = 3,
|
||
|
+ ZFCP_DBF_HBA_BASIC = 4,
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
|
||
|
index ed5d921..f172b84 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_def.h
|
||
|
+++ b/drivers/s390/scsi/zfcp_def.h
|
||
|
@@ -77,6 +77,7 @@ struct zfcp_reqlist;
|
||
|
#define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED 0x00000004
|
||
|
#define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008
|
||
|
#define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010
|
||
|
+#define ZFCP_STATUS_ADAPTER_SUSPENDED 0x00000040
|
||
|
#define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100
|
||
|
#define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200
|
||
|
#define ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED 0x00000400
|
||
|
@@ -204,6 +205,7 @@ struct zfcp_port {
|
||
|
struct zfcp_adapter *adapter; /* adapter used to access port */
|
||
|
struct list_head unit_list; /* head of logical unit list */
|
||
|
rwlock_t unit_list_lock; /* unit list lock */
|
||
|
+ atomic_t units; /* zfcp_unit count */
|
||
|
atomic_t status; /* status of this remote port */
|
||
|
u64 wwnn; /* WWNN if known */
|
||
|
u64 wwpn; /* WWPN */
|
||
|
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
|
||
|
index 2302e1c..ef9e502 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_ext.h
|
||
|
+++ b/drivers/s390/scsi/zfcp_ext.h
|
||
|
@@ -54,6 +54,7 @@ extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *);
|
||
|
extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *);
|
||
|
extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *);
|
||
|
extern void zfcp_dbf_hba_def_err(struct zfcp_adapter *, u64, u16, void **);
|
||
|
+extern void zfcp_dbf_hba_basic(char *, struct zfcp_adapter *);
|
||
|
extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32);
|
||
|
extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *);
|
||
|
extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *);
|
||
|
@@ -158,6 +159,7 @@ extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int);
|
||
|
extern struct attribute_group zfcp_sysfs_unit_attrs;
|
||
|
extern struct attribute_group zfcp_sysfs_adapter_attrs;
|
||
|
extern struct attribute_group zfcp_sysfs_port_attrs;
|
||
|
+extern struct mutex zfcp_sysfs_port_units_mutex;
|
||
|
extern struct device_attribute *zfcp_sysfs_sdev_attrs[];
|
||
|
extern struct device_attribute *zfcp_sysfs_shost_attrs[];
|
||
|
|
||
|
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
|
||
|
index e9a787e..8c849f0 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_fsf.c
|
||
|
+++ b/drivers/s390/scsi/zfcp_fsf.c
|
||
|
@@ -219,7 +219,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
- zfcp_dbf_hba_fsf_uss("fssrh_2", req);
|
||
|
+ zfcp_dbf_hba_fsf_uss("fssrh_4", req);
|
||
|
|
||
|
switch (sr_buf->status_type) {
|
||
|
case FSF_STATUS_READ_PORT_CLOSED:
|
||
|
@@ -771,12 +771,14 @@ out:
|
||
|
static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
|
||
|
{
|
||
|
struct scsi_device *sdev = req->data;
|
||
|
- struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
|
||
|
+ struct zfcp_scsi_dev *zfcp_sdev;
|
||
|
union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual;
|
||
|
|
||
|
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
|
||
|
return;
|
||
|
|
||
|
+ zfcp_sdev = sdev_to_zfcp(sdev);
|
||
|
+
|
||
|
switch (req->qtcb->header.fsf_status) {
|
||
|
case FSF_PORT_HANDLE_NOT_VALID:
|
||
|
if (fsq->word[0] == fsq->word[1]) {
|
||
|
@@ -885,7 +887,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
|
||
|
|
||
|
switch (header->fsf_status) {
|
||
|
case FSF_GOOD:
|
||
|
- zfcp_dbf_san_res("fsscth1", req);
|
||
|
+ zfcp_dbf_san_res("fsscth2", req);
|
||
|
ct->status = 0;
|
||
|
break;
|
||
|
case FSF_SERVICE_CLASS_NOT_SUPPORTED:
|
||
|
@@ -1739,13 +1741,15 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req)
|
||
|
{
|
||
|
struct zfcp_adapter *adapter = req->adapter;
|
||
|
struct scsi_device *sdev = req->data;
|
||
|
- struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
|
||
|
+ struct zfcp_scsi_dev *zfcp_sdev;
|
||
|
struct fsf_qtcb_header *header = &req->qtcb->header;
|
||
|
struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support;
|
||
|
|
||
|
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
|
||
|
return;
|
||
|
|
||
|
+ zfcp_sdev = sdev_to_zfcp(sdev);
|
||
|
+
|
||
|
atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
|
||
|
ZFCP_STATUS_COMMON_ACCESS_BOXED |
|
||
|
ZFCP_STATUS_LUN_SHARED |
|
||
|
@@ -1856,11 +1860,13 @@ out:
|
||
|
static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req)
|
||
|
{
|
||
|
struct scsi_device *sdev = req->data;
|
||
|
- struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
|
||
|
+ struct zfcp_scsi_dev *zfcp_sdev;
|
||
|
|
||
|
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
|
||
|
return;
|
||
|
|
||
|
+ zfcp_sdev = sdev_to_zfcp(sdev);
|
||
|
+
|
||
|
switch (req->qtcb->header.fsf_status) {
|
||
|
case FSF_PORT_HANDLE_NOT_VALID:
|
||
|
zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1");
|
||
|
@@ -1950,7 +1956,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
|
||
|
{
|
||
|
struct fsf_qual_latency_info *lat_in;
|
||
|
struct latency_cont *lat = NULL;
|
||
|
- struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scsi->device);
|
||
|
+ struct zfcp_scsi_dev *zfcp_sdev;
|
||
|
struct zfcp_blk_drv_data blktrc;
|
||
|
int ticks = req->adapter->timer_ticks;
|
||
|
|
||
|
@@ -1965,6 +1971,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
|
||
|
|
||
|
if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA &&
|
||
|
!(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
|
||
|
+ zfcp_sdev = sdev_to_zfcp(scsi->device);
|
||
|
blktrc.flags |= ZFCP_BLK_LAT_VALID;
|
||
|
blktrc.channel_lat = lat_in->channel_lat * ticks;
|
||
|
blktrc.fabric_lat = lat_in->fabric_lat * ticks;
|
||
|
@@ -2002,12 +2009,14 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req)
|
||
|
{
|
||
|
struct scsi_cmnd *scmnd = req->data;
|
||
|
struct scsi_device *sdev = scmnd->device;
|
||
|
- struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
|
||
|
+ struct zfcp_scsi_dev *zfcp_sdev;
|
||
|
struct fsf_qtcb_header *header = &req->qtcb->header;
|
||
|
|
||
|
if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
|
||
|
return;
|
||
|
|
||
|
+ zfcp_sdev = sdev_to_zfcp(sdev);
|
||
|
+
|
||
|
switch (header->fsf_status) {
|
||
|
case FSF_HANDLE_MISMATCH:
|
||
|
case FSF_PORT_HANDLE_NOT_VALID:
|
||
|
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
|
||
|
index e14da57..e76d003 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_qdio.c
|
||
|
+++ b/drivers/s390/scsi/zfcp_qdio.c
|
||
|
@@ -102,18 +102,22 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
|
||
|
{
|
||
|
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
|
||
|
struct zfcp_adapter *adapter = qdio->adapter;
|
||
|
- struct qdio_buffer_element *sbale;
|
||
|
int sbal_no, sbal_idx;
|
||
|
- void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1];
|
||
|
- u64 req_id;
|
||
|
- u8 scount;
|
||
|
|
||
|
if (unlikely(qdio_err)) {
|
||
|
- memset(pl, 0, ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *));
|
||
|
if (zfcp_adapter_multi_buffer_active(adapter)) {
|
||
|
+ void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1];
|
||
|
+ struct qdio_buffer_element *sbale;
|
||
|
+ u64 req_id;
|
||
|
+ u8 scount;
|
||
|
+
|
||
|
+ memset(pl, 0,
|
||
|
+ ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *));
|
||
|
sbale = qdio->res_q[idx]->element;
|
||
|
req_id = (u64) sbale->addr;
|
||
|
- scount = sbale->scount + 1; /* incl. signaling SBAL */
|
||
|
+ scount = min(sbale->scount + 1,
|
||
|
+ ZFCP_QDIO_MAX_SBALS_PER_REQ + 1);
|
||
|
+ /* incl. signaling SBAL */
|
||
|
|
||
|
for (sbal_no = 0; sbal_no < scount; sbal_no++) {
|
||
|
sbal_idx = (idx + sbal_no) %
|
||
|
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
|
||
|
index cdc4ff7..9e62210 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_sysfs.c
|
||
|
+++ b/drivers/s390/scsi/zfcp_sysfs.c
|
||
|
@@ -227,6 +227,8 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,
|
||
|
static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL,
|
||
|
zfcp_sysfs_port_rescan_store);
|
||
|
|
||
|
+DEFINE_MUTEX(zfcp_sysfs_port_units_mutex);
|
||
|
+
|
||
|
static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
const char *buf, size_t count)
|
||
|
@@ -249,6 +251,16 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
|
||
|
else
|
||
|
retval = 0;
|
||
|
|
||
|
+ mutex_lock(&zfcp_sysfs_port_units_mutex);
|
||
|
+ if (atomic_read(&port->units) > 0) {
|
||
|
+ retval = -EBUSY;
|
||
|
+ mutex_unlock(&zfcp_sysfs_port_units_mutex);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ /* port is about to be removed, so no more unit_add */
|
||
|
+ atomic_set(&port->units, -1);
|
||
|
+ mutex_unlock(&zfcp_sysfs_port_units_mutex);
|
||
|
+
|
||
|
write_lock_irq(&adapter->port_list_lock);
|
||
|
list_del(&port->list);
|
||
|
write_unlock_irq(&adapter->port_list_lock);
|
||
|
@@ -289,12 +301,14 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
|
||
|
{
|
||
|
struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
|
||
|
u64 fcp_lun;
|
||
|
+ int retval;
|
||
|
|
||
|
if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
|
||
|
return -EINVAL;
|
||
|
|
||
|
- if (zfcp_unit_add(port, fcp_lun))
|
||
|
- return -EINVAL;
|
||
|
+ retval = zfcp_unit_add(port, fcp_lun);
|
||
|
+ if (retval)
|
||
|
+ return retval;
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
diff --git a/drivers/s390/scsi/zfcp_unit.c b/drivers/s390/scsi/zfcp_unit.c
|
||
|
index 20796eb..4e6a535 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_unit.c
|
||
|
+++ b/drivers/s390/scsi/zfcp_unit.c
|
||
|
@@ -104,7 +104,7 @@ static void zfcp_unit_release(struct device *dev)
|
||
|
{
|
||
|
struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev);
|
||
|
|
||
|
- put_device(&unit->port->dev);
|
||
|
+ atomic_dec(&unit->port->units);
|
||
|
kfree(unit);
|
||
|
}
|
||
|
|
||
|
@@ -119,16 +119,27 @@ static void zfcp_unit_release(struct device *dev)
|
||
|
int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
|
||
|
{
|
||
|
struct zfcp_unit *unit;
|
||
|
+ int retval = 0;
|
||
|
+
|
||
|
+ mutex_lock(&zfcp_sysfs_port_units_mutex);
|
||
|
+ if (atomic_read(&port->units) == -1) {
|
||
|
+ /* port is already gone */
|
||
|
+ retval = -ENODEV;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
|
||
|
unit = zfcp_unit_find(port, fcp_lun);
|
||
|
if (unit) {
|
||
|
put_device(&unit->dev);
|
||
|
- return -EEXIST;
|
||
|
+ retval = -EEXIST;
|
||
|
+ goto out;
|
||
|
}
|
||
|
|
||
|
unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
|
||
|
- if (!unit)
|
||
|
- return -ENOMEM;
|
||
|
+ if (!unit) {
|
||
|
+ retval = -ENOMEM;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
|
||
|
unit->port = port;
|
||
|
unit->fcp_lun = fcp_lun;
|
||
|
@@ -139,28 +150,33 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
|
||
|
if (dev_set_name(&unit->dev, "0x%016llx",
|
||
|
(unsigned long long) fcp_lun)) {
|
||
|
kfree(unit);
|
||
|
- return -ENOMEM;
|
||
|
+ retval = -ENOMEM;
|
||
|
+ goto out;
|
||
|
}
|
||
|
|
||
|
- get_device(&port->dev);
|
||
|
-
|
||
|
if (device_register(&unit->dev)) {
|
||
|
put_device(&unit->dev);
|
||
|
- return -ENOMEM;
|
||
|
+ retval = -ENOMEM;
|
||
|
+ goto out;
|
||
|
}
|
||
|
|
||
|
if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) {
|
||
|
device_unregister(&unit->dev);
|
||
|
- return -EINVAL;
|
||
|
+ retval = -EINVAL;
|
||
|
+ goto out;
|
||
|
}
|
||
|
|
||
|
+ atomic_inc(&port->units); /* under zfcp_sysfs_port_units_mutex ! */
|
||
|
+
|
||
|
write_lock_irq(&port->unit_list_lock);
|
||
|
list_add_tail(&unit->list, &port->unit_list);
|
||
|
write_unlock_irq(&port->unit_list_lock);
|
||
|
|
||
|
zfcp_unit_scsi_scan(unit);
|
||
|
|
||
|
- return 0;
|
||
|
+out:
|
||
|
+ mutex_unlock(&zfcp_sysfs_port_units_mutex);
|
||
|
+ return retval;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
|
||
|
index 7e6eca4..59fc5a1 100644
|
||
|
--- a/drivers/scsi/atp870u.c
|
||
|
+++ b/drivers/scsi/atp870u.c
|
||
|
@@ -1174,7 +1174,16 @@ wait_io1:
|
||
|
outw(val, tmport);
|
||
|
outb(2, 0x80);
|
||
|
TCM_SYNC:
|
||
|
- udelay(0x800);
|
||
|
+ /*
|
||
|
+ * The funny division into multiple delays is to accomodate
|
||
|
+ * arches like ARM where udelay() multiplies its argument by
|
||
|
+ * a large number to initialize a loop counter. To avoid
|
||
|
+ * overflow, the maximum supported udelay is 2000 microseconds.
|
||
|
+ *
|
||
|
+ * XXX it would be more polite to find a way to use msleep()
|
||
|
+ */
|
||
|
+ mdelay(2);
|
||
|
+ udelay(48);
|
||
|
if ((inb(tmport) & 0x80) == 0x00) { /* bsy ? */
|
||
|
outw(0, tmport--);
|
||
|
outb(0, tmport);
|
||
|
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
|
||
|
index 4ef0212..e5a4423 100644
|
||
|
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
|
||
|
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
|
||
|
@@ -578,8 +578,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
|
||
|
h->state = TPGS_STATE_STANDBY;
|
||
|
break;
|
||
|
case TPGS_STATE_OFFLINE:
|
||
|
- case TPGS_STATE_UNAVAILABLE:
|
||
|
- /* Path unusable for unavailable/offline */
|
||
|
+ /* Path unusable */
|
||
|
err = SCSI_DH_DEV_OFFLINED;
|
||
|
break;
|
||
|
default:
|
||
|
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
|
||
|
index be9aad8..22523aa 100644
|
||
|
--- a/drivers/scsi/hpsa.c
|
||
|
+++ b/drivers/scsi/hpsa.c
|
||
|
@@ -532,12 +532,42 @@ static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
|
||
|
c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
|
||
|
}
|
||
|
|
||
|
+static int is_firmware_flash_cmd(u8 *cdb)
|
||
|
+{
|
||
|
+ return cdb[0] == BMIC_WRITE && cdb[6] == BMIC_FLASH_FIRMWARE;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * During firmware flash, the heartbeat register may not update as frequently
|
||
|
+ * as it should. So we dial down lockup detection during firmware flash. and
|
||
|
+ * dial it back up when firmware flash completes.
|
||
|
+ */
|
||
|
+#define HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH (240 * HZ)
|
||
|
+#define HEARTBEAT_SAMPLE_INTERVAL (30 * HZ)
|
||
|
+static void dial_down_lockup_detection_during_fw_flash(struct ctlr_info *h,
|
||
|
+ struct CommandList *c)
|
||
|
+{
|
||
|
+ if (!is_firmware_flash_cmd(c->Request.CDB))
|
||
|
+ return;
|
||
|
+ atomic_inc(&h->firmware_flash_in_progress);
|
||
|
+ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH;
|
||
|
+}
|
||
|
+
|
||
|
+static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h,
|
||
|
+ struct CommandList *c)
|
||
|
+{
|
||
|
+ if (is_firmware_flash_cmd(c->Request.CDB) &&
|
||
|
+ atomic_dec_and_test(&h->firmware_flash_in_progress))
|
||
|
+ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
|
||
|
+}
|
||
|
+
|
||
|
static void enqueue_cmd_and_start_io(struct ctlr_info *h,
|
||
|
struct CommandList *c)
|
||
|
{
|
||
|
unsigned long flags;
|
||
|
|
||
|
set_performant_mode(h, c);
|
||
|
+ dial_down_lockup_detection_during_fw_flash(h, c);
|
||
|
spin_lock_irqsave(&h->lock, flags);
|
||
|
addQ(&h->reqQ, c);
|
||
|
h->Qdepth++;
|
||
|
@@ -2926,7 +2956,7 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
|
||
|
c->Request.Timeout = 0; /* Don't time out */
|
||
|
memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
|
||
|
c->Request.CDB[0] = cmd;
|
||
|
- c->Request.CDB[1] = 0x03; /* Reset target above */
|
||
|
+ c->Request.CDB[1] = HPSA_RESET_TYPE_LUN;
|
||
|
/* If bytes 4-7 are zero, it means reset the */
|
||
|
/* LunID device */
|
||
|
c->Request.CDB[4] = 0x00;
|
||
|
@@ -3032,6 +3062,7 @@ static inline int bad_tag(struct ctlr_info *h, u32 tag_index,
|
||
|
static inline void finish_cmd(struct CommandList *c, u32 raw_tag)
|
||
|
{
|
||
|
removeQ(c);
|
||
|
+ dial_up_lockup_detection_on_fw_flash_complete(c->h, c);
|
||
|
if (likely(c->cmd_type == CMD_SCSI))
|
||
|
complete_scsi_command(c);
|
||
|
else if (c->cmd_type == CMD_IOCTL_PEND)
|
||
|
@@ -4172,9 +4203,6 @@ static void controller_lockup_detected(struct ctlr_info *h)
|
||
|
spin_unlock_irqrestore(&h->lock, flags);
|
||
|
}
|
||
|
|
||
|
-#define HEARTBEAT_SAMPLE_INTERVAL (10 * HZ)
|
||
|
-#define HEARTBEAT_CHECK_MINIMUM_INTERVAL (HEARTBEAT_SAMPLE_INTERVAL / 2)
|
||
|
-
|
||
|
static void detect_controller_lockup(struct ctlr_info *h)
|
||
|
{
|
||
|
u64 now;
|
||
|
@@ -4185,7 +4213,7 @@ static void detect_controller_lockup(struct ctlr_info *h)
|
||
|
now = get_jiffies_64();
|
||
|
/* If we've received an interrupt recently, we're ok. */
|
||
|
if (time_after64(h->last_intr_timestamp +
|
||
|
- (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now))
|
||
|
+ (h->heartbeat_sample_interval), now))
|
||
|
return;
|
||
|
|
||
|
/*
|
||
|
@@ -4194,7 +4222,7 @@ static void detect_controller_lockup(struct ctlr_info *h)
|
||
|
* otherwise don't care about signals in this thread.
|
||
|
*/
|
||
|
if (time_after64(h->last_heartbeat_timestamp +
|
||
|
- (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now))
|
||
|
+ (h->heartbeat_sample_interval), now))
|
||
|
return;
|
||
|
|
||
|
/* If heartbeat has not changed since we last looked, we're not ok. */
|
||
|
@@ -4236,6 +4264,7 @@ static void add_ctlr_to_lockup_detector_list(struct ctlr_info *h)
|
||
|
{
|
||
|
unsigned long flags;
|
||
|
|
||
|
+ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
|
||
|
spin_lock_irqsave(&lockup_detector_lock, flags);
|
||
|
list_add_tail(&h->lockup_list, &hpsa_ctlr_list);
|
||
|
spin_unlock_irqrestore(&lockup_detector_lock, flags);
|
||
|
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
|
||
|
index 91edafb..c721509 100644
|
||
|
--- a/drivers/scsi/hpsa.h
|
||
|
+++ b/drivers/scsi/hpsa.h
|
||
|
@@ -124,6 +124,8 @@ struct ctlr_info {
|
||
|
u64 last_intr_timestamp;
|
||
|
u32 last_heartbeat;
|
||
|
u64 last_heartbeat_timestamp;
|
||
|
+ u32 heartbeat_sample_interval;
|
||
|
+ atomic_t firmware_flash_in_progress;
|
||
|
u32 lockup_detected;
|
||
|
struct list_head lockup_list;
|
||
|
};
|
||
|
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
|
||
|
index 3fd4715..e4ea0a3 100644
|
||
|
--- a/drivers/scsi/hpsa_cmd.h
|
||
|
+++ b/drivers/scsi/hpsa_cmd.h
|
||
|
@@ -163,6 +163,7 @@ struct SenseSubsystem_info {
|
||
|
#define BMIC_WRITE 0x27
|
||
|
#define BMIC_CACHE_FLUSH 0xc2
|
||
|
#define HPSA_CACHE_FLUSH 0x01 /* C2 was already being used by HPSA */
|
||
|
+#define BMIC_FLASH_FIRMWARE 0xF7
|
||
|
|
||
|
/* Command List Structure */
|
||
|
union SCSI3Addr {
|
||
|
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
|
||
|
index 3d391dc..36aca4b 100644
|
||
|
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
|
||
|
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
|
||
|
@@ -1547,6 +1547,9 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
|
||
|
|
||
|
host_config = &evt_struct->iu.mad.host_config;
|
||
|
|
||
|
+ /* The transport length field is only 16-bit */
|
||
|
+ length = min(0xffff, length);
|
||
|
+
|
||
|
/* Set up a lun reset SRP command */
|
||
|
memset(host_config, 0x00, sizeof(*host_config));
|
||
|
host_config->common.type = VIOSRP_HOST_CONFIG_TYPE;
|
||
|
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
|
||
|
index 83d08b6..5c8b0dc 100644
|
||
|
--- a/drivers/scsi/isci/init.c
|
||
|
+++ b/drivers/scsi/isci/init.c
|
||
|
@@ -469,7 +469,6 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
|
||
|
if (sci_oem_parameters_validate(&orom->ctrl[i])) {
|
||
|
dev_warn(&pdev->dev,
|
||
|
"[%d]: invalid oem parameters detected, falling back to firmware\n", i);
|
||
|
- devm_kfree(&pdev->dev, orom);
|
||
|
orom = NULL;
|
||
|
break;
|
||
|
}
|
||
|
diff --git a/drivers/scsi/isci/probe_roms.c b/drivers/scsi/isci/probe_roms.c
|
||
|
index b5f4341..7cd637d 100644
|
||
|
--- a/drivers/scsi/isci/probe_roms.c
|
||
|
+++ b/drivers/scsi/isci/probe_roms.c
|
||
|
@@ -104,7 +104,6 @@ struct isci_orom *isci_request_oprom(struct pci_dev *pdev)
|
||
|
|
||
|
if (i >= len) {
|
||
|
dev_err(&pdev->dev, "oprom parse error\n");
|
||
|
- devm_kfree(&pdev->dev, rom);
|
||
|
rom = NULL;
|
||
|
}
|
||
|
pci_unmap_biosrom(oprom);
|
||
|
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
|
||
|
index bb7c482..08d48a3 100644
|
||
|
--- a/drivers/scsi/scsi_sysfs.c
|
||
|
+++ b/drivers/scsi/scsi_sysfs.c
|
||
|
@@ -1023,33 +1023,31 @@ static void __scsi_remove_target(struct scsi_target *starget)
|
||
|
void scsi_remove_target(struct device *dev)
|
||
|
{
|
||
|
struct Scsi_Host *shost = dev_to_shost(dev->parent);
|
||
|
- struct scsi_target *starget, *found;
|
||
|
+ struct scsi_target *starget, *last = NULL;
|
||
|
unsigned long flags;
|
||
|
|
||
|
- restart:
|
||
|
- found = NULL;
|
||
|
+ /* remove targets being careful to lookup next entry before
|
||
|
+ * deleting the last
|
||
|
+ */
|
||
|
spin_lock_irqsave(shost->host_lock, flags);
|
||
|
list_for_each_entry(starget, &shost->__targets, siblings) {
|
||
|
if (starget->state == STARGET_DEL)
|
||
|
continue;
|
||
|
if (starget->dev.parent == dev || &starget->dev == dev) {
|
||
|
- found = starget;
|
||
|
- found->reap_ref++;
|
||
|
- break;
|
||
|
+ /* assuming new targets arrive at the end */
|
||
|
+ starget->reap_ref++;
|
||
|
+ spin_unlock_irqrestore(shost->host_lock, flags);
|
||
|
+ if (last)
|
||
|
+ scsi_target_reap(last);
|
||
|
+ last = starget;
|
||
|
+ __scsi_remove_target(starget);
|
||
|
+ spin_lock_irqsave(shost->host_lock, flags);
|
||
|
}
|
||
|
}
|
||
|
spin_unlock_irqrestore(shost->host_lock, flags);
|
||
|
|
||
|
- if (found) {
|
||
|
- __scsi_remove_target(found);
|
||
|
- scsi_target_reap(found);
|
||
|
- /* in the case where @dev has multiple starget children,
|
||
|
- * continue removing.
|
||
|
- *
|
||
|
- * FIXME: does such a case exist?
|
||
|
- */
|
||
|
- goto restart;
|
||
|
- }
|
||
|
+ if (last)
|
||
|
+ scsi_target_reap(last);
|
||
|
}
|
||
|
EXPORT_SYMBOL(scsi_remove_target);
|
||
|
|
||
|
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
|
||
|
index 4ad2c0e..9465bce 100644
|
||
|
--- a/drivers/staging/comedi/comedi_fops.c
|
||
|
+++ b/drivers/staging/comedi/comedi_fops.c
|
||
|
@@ -843,7 +843,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
|
||
|
ret = -EAGAIN;
|
||
|
break;
|
||
|
}
|
||
|
- ret = s->async->inttrig(dev, s, insn->data[0]);
|
||
|
+ ret = s->async->inttrig(dev, s, data[0]);
|
||
|
if (ret >= 0)
|
||
|
ret = 1;
|
||
|
break;
|
||
|
@@ -1088,7 +1088,6 @@ static int do_cmd_ioctl(struct comedi_device *dev,
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
- kfree(async->cmd.chanlist);
|
||
|
async->cmd = user_cmd;
|
||
|
async->cmd.data = NULL;
|
||
|
/* load channel/gain list */
|
||
|
@@ -1833,6 +1832,8 @@ void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
|
||
|
if (async) {
|
||
|
comedi_reset_async_buf(async);
|
||
|
async->inttrig = NULL;
|
||
|
+ kfree(async->cmd.chanlist);
|
||
|
+ async->cmd.chanlist = NULL;
|
||
|
} else {
|
||
|
printk(KERN_ERR
|
||
|
"BUG: (?) do_become_nonbusy called with async=0\n");
|
||
|
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
|
||
|
index 8d98cf4..c8b7eed 100644
|
||
|
--- a/drivers/staging/comedi/drivers/jr3_pci.c
|
||
|
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
|
||
|
@@ -913,7 +913,7 @@ static int jr3_pci_attach(struct comedi_device *dev,
|
||
|
}
|
||
|
|
||
|
/* Reset DSP card */
|
||
|
- devpriv->iobase->channel[0].reset = 0;
|
||
|
+ writel(0, &devpriv->iobase->channel[0].reset);
|
||
|
|
||
|
result = comedi_load_firmware(dev, "jr3pci.idm", jr3_download_firmware);
|
||
|
printk("Firmare load %d\n", result);
|
||
|
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
|
||
|
index 23fc64b..c72128f 100644
|
||
|
--- a/drivers/staging/comedi/drivers/s626.c
|
||
|
+++ b/drivers/staging/comedi/drivers/s626.c
|
||
|
@@ -2370,7 +2370,7 @@ static int s626_enc_insn_config(struct comedi_device *dev,
|
||
|
/* (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); */
|
||
|
|
||
|
k->SetMode(dev, k, Setup, TRUE);
|
||
|
- Preload(dev, k, *(insn->data));
|
||
|
+ Preload(dev, k, data[0]);
|
||
|
k->PulseIndex(dev, k);
|
||
|
SetLatchSource(dev, k, valueSrclatch);
|
||
|
k->SetEnable(dev, k, (uint16_t) (enab != 0));
|
||
|
diff --git a/drivers/staging/speakup/speakup_soft.c b/drivers/staging/speakup/speakup_soft.c
|
||
|
index 42cdafe..b5130c8 100644
|
||
|
--- a/drivers/staging/speakup/speakup_soft.c
|
||
|
+++ b/drivers/staging/speakup/speakup_soft.c
|
||
|
@@ -40,7 +40,7 @@ static int softsynth_is_alive(struct spk_synth *synth);
|
||
|
static unsigned char get_index(void);
|
||
|
|
||
|
static struct miscdevice synth_device;
|
||
|
-static int initialized;
|
||
|
+static int init_pos;
|
||
|
static int misc_registered;
|
||
|
|
||
|
static struct var_t vars[] = {
|
||
|
@@ -194,7 +194,7 @@ static int softsynth_close(struct inode *inode, struct file *fp)
|
||
|
unsigned long flags;
|
||
|
spk_lock(flags);
|
||
|
synth_soft.alive = 0;
|
||
|
- initialized = 0;
|
||
|
+ init_pos = 0;
|
||
|
spk_unlock(flags);
|
||
|
/* Make sure we let applications go before leaving */
|
||
|
speakup_start_ttys();
|
||
|
@@ -239,13 +239,8 @@ static ssize_t softsynth_read(struct file *fp, char *buf, size_t count,
|
||
|
ch = '\x18';
|
||
|
} else if (synth_buffer_empty()) {
|
||
|
break;
|
||
|
- } else if (!initialized) {
|
||
|
- if (*init) {
|
||
|
- ch = *init;
|
||
|
- init++;
|
||
|
- } else {
|
||
|
- initialized = 1;
|
||
|
- }
|
||
|
+ } else if (init[init_pos]) {
|
||
|
+ ch = init[init_pos++];
|
||
|
} else {
|
||
|
ch = synth_buffer_getc();
|
||
|
}
|
||
|
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
|
||
|
index 2ff1255..f35cb10 100644
|
||
|
--- a/drivers/target/iscsi/iscsi_target.c
|
||
|
+++ b/drivers/target/iscsi/iscsi_target.c
|
||
|
@@ -3204,7 +3204,6 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
|
||
|
len += 1;
|
||
|
|
||
|
if ((len + payload_len) > buffer_len) {
|
||
|
- spin_unlock(&tiqn->tiqn_tpg_lock);
|
||
|
end_of_buf = 1;
|
||
|
goto eob;
|
||
|
}
|
||
|
@@ -3357,6 +3356,7 @@ static int iscsit_send_reject(
|
||
|
hdr->opcode = ISCSI_OP_REJECT;
|
||
|
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
|
||
|
hton24(hdr->dlength, ISCSI_HDR_LEN);
|
||
|
+ hdr->ffffffff = 0xffffffff;
|
||
|
cmd->stat_sn = conn->stat_sn++;
|
||
|
hdr->statsn = cpu_to_be32(cmd->stat_sn);
|
||
|
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
|
||
|
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
|
||
|
index 0f68197..dae283f 100644
|
||
|
--- a/drivers/target/iscsi/iscsi_target_core.h
|
||
|
+++ b/drivers/target/iscsi/iscsi_target_core.h
|
||
|
@@ -25,10 +25,10 @@
|
||
|
#define NA_DATAOUT_TIMEOUT_RETRIES 5
|
||
|
#define NA_DATAOUT_TIMEOUT_RETRIES_MAX 15
|
||
|
#define NA_DATAOUT_TIMEOUT_RETRIES_MIN 1
|
||
|
-#define NA_NOPIN_TIMEOUT 5
|
||
|
+#define NA_NOPIN_TIMEOUT 15
|
||
|
#define NA_NOPIN_TIMEOUT_MAX 60
|
||
|
#define NA_NOPIN_TIMEOUT_MIN 3
|
||
|
-#define NA_NOPIN_RESPONSE_TIMEOUT 5
|
||
|
+#define NA_NOPIN_RESPONSE_TIMEOUT 30
|
||
|
#define NA_NOPIN_RESPONSE_TIMEOUT_MAX 60
|
||
|
#define NA_NOPIN_RESPONSE_TIMEOUT_MIN 3
|
||
|
#define NA_RANDOM_DATAIN_PDU_OFFSETS 0
|
||
|
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
|
||
|
index d4cf2cd..309f14c 100644
|
||
|
--- a/drivers/target/iscsi/iscsi_target_tpg.c
|
||
|
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
|
||
|
@@ -674,6 +674,12 @@ int iscsit_ta_generate_node_acls(
|
||
|
pr_debug("iSCSI_TPG[%hu] - Generate Initiator Portal Group ACLs: %s\n",
|
||
|
tpg->tpgt, (a->generate_node_acls) ? "Enabled" : "Disabled");
|
||
|
|
||
|
+ if (flag == 1 && a->cache_dynamic_acls == 0) {
|
||
|
+ pr_debug("Explicitly setting cache_dynamic_acls=1 when "
|
||
|
+ "generate_node_acls=1\n");
|
||
|
+ a->cache_dynamic_acls = 1;
|
||
|
+ }
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -713,6 +719,12 @@ int iscsit_ta_cache_dynamic_acls(
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
+ if (a->generate_node_acls == 1 && flag == 0) {
|
||
|
+ pr_debug("Skipping cache_dynamic_acls=0 when"
|
||
|
+ " generate_node_acls=1\n");
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
a->cache_dynamic_acls = flag;
|
||
|
pr_debug("iSCSI_TPG[%hu] - Cache Dynamic Initiator Portal Group"
|
||
|
" ACLs %s\n", tpg->tpgt, (a->cache_dynamic_acls) ?
|
||
|
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
|
||
|
index 93d4f6a..0b01bfc 100644
|
||
|
--- a/drivers/target/target_core_configfs.c
|
||
|
+++ b/drivers/target/target_core_configfs.c
|
||
|
@@ -3123,6 +3123,7 @@ static int __init target_core_init_configfs(void)
|
||
|
GFP_KERNEL);
|
||
|
if (!target_cg->default_groups) {
|
||
|
pr_err("Unable to allocate target_cg->default_groups\n");
|
||
|
+ ret = -ENOMEM;
|
||
|
goto out_global;
|
||
|
}
|
||
|
|
||
|
@@ -3138,6 +3139,7 @@ static int __init target_core_init_configfs(void)
|
||
|
GFP_KERNEL);
|
||
|
if (!hba_cg->default_groups) {
|
||
|
pr_err("Unable to allocate hba_cg->default_groups\n");
|
||
|
+ ret = -ENOMEM;
|
||
|
goto out_global;
|
||
|
}
|
||
|
config_group_init_type_name(&alua_group,
|
||
|
@@ -3153,6 +3155,7 @@ static int __init target_core_init_configfs(void)
|
||
|
GFP_KERNEL);
|
||
|
if (!alua_cg->default_groups) {
|
||
|
pr_err("Unable to allocate alua_cg->default_groups\n");
|
||
|
+ ret = -ENOMEM;
|
||
|
goto out_global;
|
||
|
}
|
||
|
|
||
|
@@ -3164,14 +3167,17 @@ static int __init target_core_init_configfs(void)
|
||
|
* Add core/alua/lu_gps/default_lu_gp
|
||
|
*/
|
||
|
lu_gp = core_alua_allocate_lu_gp("default_lu_gp", 1);
|
||
|
- if (IS_ERR(lu_gp))
|
||
|
+ if (IS_ERR(lu_gp)) {
|
||
|
+ ret = -ENOMEM;
|
||
|
goto out_global;
|
||
|
+ }
|
||
|
|
||
|
lu_gp_cg = &alua_lu_gps_group;
|
||
|
lu_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
|
||
|
GFP_KERNEL);
|
||
|
if (!lu_gp_cg->default_groups) {
|
||
|
pr_err("Unable to allocate lu_gp_cg->default_groups\n");
|
||
|
+ ret = -ENOMEM;
|
||
|
goto out_global;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
|
||
|
index 455a251..cafa477 100644
|
||
|
--- a/drivers/target/target_core_file.c
|
||
|
+++ b/drivers/target/target_core_file.c
|
||
|
@@ -139,6 +139,19 @@ static struct se_device *fd_create_virtdevice(
|
||
|
* of pure timestamp updates.
|
||
|
*/
|
||
|
flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC;
|
||
|
+ /*
|
||
|
+ * Optionally allow fd_buffered_io=1 to be enabled for people
|
||
|
+ * who want use the fs buffer cache as an WriteCache mechanism.
|
||
|
+ *
|
||
|
+ * This means that in event of a hard failure, there is a risk
|
||
|
+ * of silent data-loss if the SCSI client has *not* performed a
|
||
|
+ * forced unit access (FUA) write, or issued SYNCHRONIZE_CACHE
|
||
|
+ * to write-out the entire device cache.
|
||
|
+ */
|
||
|
+ if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) {
|
||
|
+ pr_debug("FILEIO: Disabling O_DSYNC, using buffered FILEIO\n");
|
||
|
+ flags &= ~O_DSYNC;
|
||
|
+ }
|
||
|
|
||
|
file = filp_open(dev_p, flags, 0600);
|
||
|
if (IS_ERR(file)) {
|
||
|
@@ -206,6 +219,12 @@ static struct se_device *fd_create_virtdevice(
|
||
|
if (!dev)
|
||
|
goto fail;
|
||
|
|
||
|
+ if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) {
|
||
|
+ pr_debug("FILEIO: Forcing setting of emulate_write_cache=1"
|
||
|
+ " with FDBD_HAS_BUFFERED_IO_WCE\n");
|
||
|
+ dev->se_sub_dev->se_dev_attrib.emulate_write_cache = 1;
|
||
|
+ }
|
||
|
+
|
||
|
fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
|
||
|
fd_dev->fd_queue_depth = dev->queue_depth;
|
||
|
|
||
|
@@ -450,6 +469,7 @@ enum {
|
||
|
static match_table_t tokens = {
|
||
|
{Opt_fd_dev_name, "fd_dev_name=%s"},
|
||
|
{Opt_fd_dev_size, "fd_dev_size=%s"},
|
||
|
+ {Opt_fd_buffered_io, "fd_buffered_io=%d"},
|
||
|
{Opt_err, NULL}
|
||
|
};
|
||
|
|
||
|
@@ -461,7 +481,7 @@ static ssize_t fd_set_configfs_dev_params(
|
||
|
struct fd_dev *fd_dev = se_dev->se_dev_su_ptr;
|
||
|
char *orig, *ptr, *arg_p, *opts;
|
||
|
substring_t args[MAX_OPT_ARGS];
|
||
|
- int ret = 0, token;
|
||
|
+ int ret = 0, arg, token;
|
||
|
|
||
|
opts = kstrdup(page, GFP_KERNEL);
|
||
|
if (!opts)
|
||
|
@@ -505,6 +525,19 @@ static ssize_t fd_set_configfs_dev_params(
|
||
|
" bytes\n", fd_dev->fd_dev_size);
|
||
|
fd_dev->fbd_flags |= FBDF_HAS_SIZE;
|
||
|
break;
|
||
|
+ case Opt_fd_buffered_io:
|
||
|
+ match_int(args, &arg);
|
||
|
+ if (arg != 1) {
|
||
|
+ pr_err("bogus fd_buffered_io=%d value\n", arg);
|
||
|
+ ret = -EINVAL;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ pr_debug("FILEIO: Using buffered I/O"
|
||
|
+ " operations for struct fd_dev\n");
|
||
|
+
|
||
|
+ fd_dev->fbd_flags |= FDBD_HAS_BUFFERED_IO_WCE;
|
||
|
+ break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
@@ -536,8 +569,10 @@ static ssize_t fd_show_configfs_dev_params(
|
||
|
ssize_t bl = 0;
|
||
|
|
||
|
bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id);
|
||
|
- bl += sprintf(b + bl, " File: %s Size: %llu Mode: O_DSYNC\n",
|
||
|
- fd_dev->fd_dev_name, fd_dev->fd_dev_size);
|
||
|
+ bl += sprintf(b + bl, " File: %s Size: %llu Mode: %s\n",
|
||
|
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size,
|
||
|
+ (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) ?
|
||
|
+ "Buffered-WCE" : "O_DSYNC");
|
||
|
return bl;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h
|
||
|
index 53ece69..6b1b6a9 100644
|
||
|
--- a/drivers/target/target_core_file.h
|
||
|
+++ b/drivers/target/target_core_file.h
|
||
|
@@ -18,6 +18,7 @@ struct fd_request {
|
||
|
|
||
|
#define FBDF_HAS_PATH 0x01
|
||
|
#define FBDF_HAS_SIZE 0x02
|
||
|
+#define FDBD_HAS_BUFFERED_IO_WCE 0x04
|
||
|
|
||
|
struct fd_dev {
|
||
|
u32 fbd_flags;
|
||
|
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
|
||
|
index fc7bbba..d190269 100644
|
||
|
--- a/drivers/tty/n_gsm.c
|
||
|
+++ b/drivers/tty/n_gsm.c
|
||
|
@@ -108,7 +108,7 @@ struct gsm_mux_net {
|
||
|
*/
|
||
|
|
||
|
struct gsm_msg {
|
||
|
- struct gsm_msg *next;
|
||
|
+ struct list_head list;
|
||
|
u8 addr; /* DLCI address + flags */
|
||
|
u8 ctrl; /* Control byte + flags */
|
||
|
unsigned int len; /* Length of data block (can be zero) */
|
||
|
@@ -245,8 +245,7 @@ struct gsm_mux {
|
||
|
unsigned int tx_bytes; /* TX data outstanding */
|
||
|
#define TX_THRESH_HI 8192
|
||
|
#define TX_THRESH_LO 2048
|
||
|
- struct gsm_msg *tx_head; /* Pending data packets */
|
||
|
- struct gsm_msg *tx_tail;
|
||
|
+ struct list_head tx_list; /* Pending data packets */
|
||
|
|
||
|
/* Control messages */
|
||
|
struct timer_list t2_timer; /* Retransmit timer for commands */
|
||
|
@@ -663,7 +662,7 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
|
||
|
m->len = len;
|
||
|
m->addr = addr;
|
||
|
m->ctrl = ctrl;
|
||
|
- m->next = NULL;
|
||
|
+ INIT_LIST_HEAD(&m->list);
|
||
|
return m;
|
||
|
}
|
||
|
|
||
|
@@ -673,22 +672,21 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
|
||
|
*
|
||
|
* The tty device has called us to indicate that room has appeared in
|
||
|
* the transmit queue. Ram more data into the pipe if we have any
|
||
|
+ * If we have been flow-stopped by a CMD_FCOFF, then we can only
|
||
|
+ * send messages on DLCI0 until CMD_FCON
|
||
|
*
|
||
|
* FIXME: lock against link layer control transmissions
|
||
|
*/
|
||
|
|
||
|
static void gsm_data_kick(struct gsm_mux *gsm)
|
||
|
{
|
||
|
- struct gsm_msg *msg = gsm->tx_head;
|
||
|
+ struct gsm_msg *msg, *nmsg;
|
||
|
int len;
|
||
|
int skip_sof = 0;
|
||
|
|
||
|
- /* FIXME: We need to apply this solely to data messages */
|
||
|
- if (gsm->constipated)
|
||
|
- return;
|
||
|
-
|
||
|
- while (gsm->tx_head != NULL) {
|
||
|
- msg = gsm->tx_head;
|
||
|
+ list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) {
|
||
|
+ if (gsm->constipated && msg->addr)
|
||
|
+ continue;
|
||
|
if (gsm->encoding != 0) {
|
||
|
gsm->txframe[0] = GSM1_SOF;
|
||
|
len = gsm_stuff_frame(msg->data,
|
||
|
@@ -711,14 +709,13 @@ static void gsm_data_kick(struct gsm_mux *gsm)
|
||
|
len - skip_sof) < 0)
|
||
|
break;
|
||
|
/* FIXME: Can eliminate one SOF in many more cases */
|
||
|
- gsm->tx_head = msg->next;
|
||
|
- if (gsm->tx_head == NULL)
|
||
|
- gsm->tx_tail = NULL;
|
||
|
gsm->tx_bytes -= msg->len;
|
||
|
- kfree(msg);
|
||
|
/* For a burst of frames skip the extra SOF within the
|
||
|
burst */
|
||
|
skip_sof = 1;
|
||
|
+
|
||
|
+ list_del(&msg->list);
|
||
|
+ kfree(msg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -768,11 +765,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
|
||
|
msg->data = dp;
|
||
|
|
||
|
/* Add to the actual output queue */
|
||
|
- if (gsm->tx_tail)
|
||
|
- gsm->tx_tail->next = msg;
|
||
|
- else
|
||
|
- gsm->tx_head = msg;
|
||
|
- gsm->tx_tail = msg;
|
||
|
+ list_add_tail(&msg->list, &gsm->tx_list);
|
||
|
gsm->tx_bytes += msg->len;
|
||
|
gsm_data_kick(gsm);
|
||
|
}
|
||
|
@@ -875,7 +868,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
|
||
|
|
||
|
/* dlci->skb is locked by tx_lock */
|
||
|
if (dlci->skb == NULL) {
|
||
|
- dlci->skb = skb_dequeue(&dlci->skb_list);
|
||
|
+ dlci->skb = skb_dequeue_tail(&dlci->skb_list);
|
||
|
if (dlci->skb == NULL)
|
||
|
return 0;
|
||
|
first = 1;
|
||
|
@@ -886,7 +879,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
|
||
|
if (len > gsm->mtu) {
|
||
|
if (dlci->adaption == 3) {
|
||
|
/* Over long frame, bin it */
|
||
|
- kfree_skb(dlci->skb);
|
||
|
+ dev_kfree_skb_any(dlci->skb);
|
||
|
dlci->skb = NULL;
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -899,8 +892,11 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
|
||
|
|
||
|
/* FIXME: need a timer or something to kick this so it can't
|
||
|
get stuck with no work outstanding and no buffer free */
|
||
|
- if (msg == NULL)
|
||
|
+ if (msg == NULL) {
|
||
|
+ skb_queue_tail(&dlci->skb_list, dlci->skb);
|
||
|
+ dlci->skb = NULL;
|
||
|
return -ENOMEM;
|
||
|
+ }
|
||
|
dp = msg->data;
|
||
|
|
||
|
if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */
|
||
|
@@ -912,7 +908,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
|
||
|
skb_pull(dlci->skb, len);
|
||
|
__gsm_data_queue(dlci, msg);
|
||
|
if (last) {
|
||
|
- kfree_skb(dlci->skb);
|
||
|
+ dev_kfree_skb_any(dlci->skb);
|
||
|
dlci->skb = NULL;
|
||
|
}
|
||
|
return size;
|
||
|
@@ -971,16 +967,22 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
|
||
|
static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
|
||
|
{
|
||
|
unsigned long flags;
|
||
|
+ int sweep;
|
||
|
+
|
||
|
+ if (dlci->constipated)
|
||
|
+ return;
|
||
|
|
||
|
spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
|
||
|
/* If we have nothing running then we need to fire up */
|
||
|
+ sweep = (dlci->gsm->tx_bytes < TX_THRESH_LO);
|
||
|
if (dlci->gsm->tx_bytes == 0) {
|
||
|
if (dlci->net)
|
||
|
gsm_dlci_data_output_framed(dlci->gsm, dlci);
|
||
|
else
|
||
|
gsm_dlci_data_output(dlci->gsm, dlci);
|
||
|
- } else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
|
||
|
- gsm_dlci_data_sweep(dlci->gsm);
|
||
|
+ }
|
||
|
+ if (sweep)
|
||
|
+ gsm_dlci_data_sweep(dlci->gsm);
|
||
|
spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
|
||
|
}
|
||
|
|
||
|
@@ -1027,6 +1029,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
|
||
|
{
|
||
|
int mlines = 0;
|
||
|
u8 brk = 0;
|
||
|
+ int fc;
|
||
|
|
||
|
/* The modem status command can either contain one octet (v.24 signals)
|
||
|
or two octets (v.24 signals + break signals). The length field will
|
||
|
@@ -1038,19 +1041,21 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
|
||
|
else {
|
||
|
brk = modem & 0x7f;
|
||
|
modem = (modem >> 7) & 0x7f;
|
||
|
- };
|
||
|
+ }
|
||
|
|
||
|
/* Flow control/ready to communicate */
|
||
|
- if (modem & MDM_FC) {
|
||
|
+ fc = (modem & MDM_FC) || !(modem & MDM_RTR);
|
||
|
+ if (fc && !dlci->constipated) {
|
||
|
/* Need to throttle our output on this device */
|
||
|
dlci->constipated = 1;
|
||
|
- }
|
||
|
- if (modem & MDM_RTC) {
|
||
|
- mlines |= TIOCM_DSR | TIOCM_DTR;
|
||
|
+ } else if (!fc && dlci->constipated) {
|
||
|
dlci->constipated = 0;
|
||
|
gsm_dlci_data_kick(dlci);
|
||
|
}
|
||
|
+
|
||
|
/* Map modem bits */
|
||
|
+ if (modem & MDM_RTC)
|
||
|
+ mlines |= TIOCM_DSR | TIOCM_DTR;
|
||
|
if (modem & MDM_RTR)
|
||
|
mlines |= TIOCM_RTS | TIOCM_CTS;
|
||
|
if (modem & MDM_IC)
|
||
|
@@ -1190,6 +1195,8 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
|
||
|
u8 *data, int clen)
|
||
|
{
|
||
|
u8 buf[1];
|
||
|
+ unsigned long flags;
|
||
|
+
|
||
|
switch (command) {
|
||
|
case CMD_CLD: {
|
||
|
struct gsm_dlci *dlci = gsm->dlci[0];
|
||
|
@@ -1206,16 +1213,18 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
|
||
|
gsm_control_reply(gsm, CMD_TEST, data, clen);
|
||
|
break;
|
||
|
case CMD_FCON:
|
||
|
- /* Modem wants us to STFU */
|
||
|
- gsm->constipated = 1;
|
||
|
- gsm_control_reply(gsm, CMD_FCON, NULL, 0);
|
||
|
- break;
|
||
|
- case CMD_FCOFF:
|
||
|
/* Modem can accept data again */
|
||
|
gsm->constipated = 0;
|
||
|
- gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
|
||
|
+ gsm_control_reply(gsm, CMD_FCON, NULL, 0);
|
||
|
/* Kick the link in case it is idling */
|
||
|
+ spin_lock_irqsave(&gsm->tx_lock, flags);
|
||
|
gsm_data_kick(gsm);
|
||
|
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
|
||
|
+ break;
|
||
|
+ case CMD_FCOFF:
|
||
|
+ /* Modem wants us to STFU */
|
||
|
+ gsm->constipated = 1;
|
||
|
+ gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
|
||
|
break;
|
||
|
case CMD_MSC:
|
||
|
/* Out of band modem line change indicator for a DLCI */
|
||
|
@@ -1668,7 +1677,7 @@ static void gsm_dlci_free(struct kref *ref)
|
||
|
dlci->gsm->dlci[dlci->addr] = NULL;
|
||
|
kfifo_free(dlci->fifo);
|
||
|
while ((dlci->skb = skb_dequeue(&dlci->skb_list)))
|
||
|
- kfree_skb(dlci->skb);
|
||
|
+ dev_kfree_skb(dlci->skb);
|
||
|
kfree(dlci);
|
||
|
}
|
||
|
|
||
|
@@ -2007,7 +2016,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
|
||
|
{
|
||
|
int i;
|
||
|
struct gsm_dlci *dlci = gsm->dlci[0];
|
||
|
- struct gsm_msg *txq;
|
||
|
+ struct gsm_msg *txq, *ntxq;
|
||
|
struct gsm_control *gc;
|
||
|
|
||
|
gsm->dead = 1;
|
||
|
@@ -2042,11 +2051,9 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
|
||
|
if (gsm->dlci[i])
|
||
|
gsm_dlci_release(gsm->dlci[i]);
|
||
|
/* Now wipe the queues */
|
||
|
- for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
|
||
|
- gsm->tx_head = txq->next;
|
||
|
+ list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)
|
||
|
kfree(txq);
|
||
|
- }
|
||
|
- gsm->tx_tail = NULL;
|
||
|
+ INIT_LIST_HEAD(&gsm->tx_list);
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
|
||
|
|
||
|
@@ -2157,6 +2164,7 @@ struct gsm_mux *gsm_alloc_mux(void)
|
||
|
}
|
||
|
spin_lock_init(&gsm->lock);
|
||
|
kref_init(&gsm->ref);
|
||
|
+ INIT_LIST_HEAD(&gsm->tx_list);
|
||
|
|
||
|
gsm->t1 = T1;
|
||
|
gsm->t2 = T2;
|
||
|
@@ -2273,7 +2281,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
||
|
gsm->error(gsm, *dp, flags);
|
||
|
break;
|
||
|
default:
|
||
|
- WARN_ONCE("%s: unknown flag %d\n",
|
||
|
+ WARN_ONCE(1, "%s: unknown flag %d\n",
|
||
|
tty_name(tty, buf), flags);
|
||
|
break;
|
||
|
}
|
||
|
@@ -2377,12 +2385,12 @@ static void gsmld_write_wakeup(struct tty_struct *tty)
|
||
|
|
||
|
/* Queue poll */
|
||
|
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
|
||
|
+ spin_lock_irqsave(&gsm->tx_lock, flags);
|
||
|
gsm_data_kick(gsm);
|
||
|
if (gsm->tx_bytes < TX_THRESH_LO) {
|
||
|
- spin_lock_irqsave(&gsm->tx_lock, flags);
|
||
|
gsm_dlci_data_sweep(gsm);
|
||
|
- spin_unlock_irqrestore(&gsm->tx_lock, flags);
|
||
|
}
|
||
|
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -2889,6 +2897,10 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
|
||
|
gsm = gsm_mux[mux];
|
||
|
if (gsm->dead)
|
||
|
return -EL2HLT;
|
||
|
+ /* If DLCI 0 is not yet fully open return an error. This is ok from a locking
|
||
|
+ perspective as we don't have to worry about this if DLCI0 is lost */
|
||
|
+ if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN)
|
||
|
+ return -EL2NSYNC;
|
||
|
dlci = gsm->dlci[line];
|
||
|
if (dlci == NULL)
|
||
|
dlci = gsm_dlci_alloc(gsm, line);
|
||
|
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
|
||
|
index 39d6ab6..8481aae 100644
|
||
|
--- a/drivers/tty/n_tty.c
|
||
|
+++ b/drivers/tty/n_tty.c
|
||
|
@@ -1728,7 +1728,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||
|
|
||
|
do_it_again:
|
||
|
|
||
|
- BUG_ON(!tty->read_buf);
|
||
|
+ if (WARN_ON(!tty->read_buf))
|
||
|
+ return -EAGAIN;
|
||
|
|
||
|
c = job_control(tty, file);
|
||
|
if (c < 0)
|
||
|
diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c
|
||
|
index 482d51e..e7d82c1 100644
|
||
|
--- a/drivers/tty/serial/8250_pci.c
|
||
|
+++ b/drivers/tty/serial/8250_pci.c
|
||
|
@@ -1118,6 +1118,8 @@ pci_xr17c154_setup(struct serial_private *priv,
|
||
|
#define PCI_SUBDEVICE_ID_OCTPRO422 0x0208
|
||
|
#define PCI_SUBDEVICE_ID_POCTAL232 0x0308
|
||
|
#define PCI_SUBDEVICE_ID_POCTAL422 0x0408
|
||
|
+#define PCI_SUBDEVICE_ID_SIIG_DUAL_00 0x2500
|
||
|
+#define PCI_SUBDEVICE_ID_SIIG_DUAL_30 0x2530
|
||
|
#define PCI_VENDOR_ID_ADVANTECH 0x13fe
|
||
|
#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
|
||
|
#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620
|
||
|
@@ -3168,8 +3170,11 @@ static struct pci_device_id serial_pci_tbl[] = {
|
||
|
* For now just used the hex ID 0x950a.
|
||
|
*/
|
||
|
{ PCI_VENDOR_ID_OXSEMI, 0x950a,
|
||
|
- PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0,
|
||
|
- pbn_b0_2_115200 },
|
||
|
+ PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_00,
|
||
|
+ 0, 0, pbn_b0_2_115200 },
|
||
|
+ { PCI_VENDOR_ID_OXSEMI, 0x950a,
|
||
|
+ PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_30,
|
||
|
+ 0, 0, pbn_b0_2_115200 },
|
||
|
{ PCI_VENDOR_ID_OXSEMI, 0x950a,
|
||
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||
|
pbn_b0_2_1130000 },
|
||
|
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
|
||
|
index 6da8cf8..fe9f111 100644
|
||
|
--- a/drivers/tty/serial/amba-pl011.c
|
||
|
+++ b/drivers/tty/serial/amba-pl011.c
|
||
|
@@ -1627,13 +1627,26 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
|
||
|
old_cr &= ~ST_UART011_CR_OVSFACT;
|
||
|
}
|
||
|
|
||
|
+ /*
|
||
|
+ * Workaround for the ST Micro oversampling variants to
|
||
|
+ * increase the bitrate slightly, by lowering the divisor,
|
||
|
+ * to avoid delayed sampling of start bit at high speeds,
|
||
|
+ * else we see data corruption.
|
||
|
+ */
|
||
|
+ if (uap->vendor->oversampling) {
|
||
|
+ if ((baud >= 3000000) && (baud < 3250000) && (quot > 1))
|
||
|
+ quot -= 1;
|
||
|
+ else if ((baud > 3250000) && (quot > 2))
|
||
|
+ quot -= 2;
|
||
|
+ }
|
||
|
/* Set baud rate */
|
||
|
writew(quot & 0x3f, port->membase + UART011_FBRD);
|
||
|
writew(quot >> 6, port->membase + UART011_IBRD);
|
||
|
|
||
|
/*
|
||
|
* ----------v----------v----------v----------v-----
|
||
|
- * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
|
||
|
+ * NOTE: lcrh_tx and lcrh_rx MUST BE WRITTEN AFTER
|
||
|
+ * UART011_FBRD & UART011_IBRD.
|
||
|
* ----------^----------^----------^----------^-----
|
||
|
*/
|
||
|
writew(lcr_h, port->membase + uap->lcrh_rx);
|
||
|
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
|
||
|
index a40ab98..4cddbfc 100644
|
||
|
--- a/drivers/usb/host/xhci-mem.c
|
||
|
+++ b/drivers/usb/host/xhci-mem.c
|
||
|
@@ -1680,6 +1680,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||
|
{
|
||
|
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
|
||
|
struct dev_info *dev_info, *next;
|
||
|
+ struct xhci_cd *cur_cd, *next_cd;
|
||
|
unsigned long flags;
|
||
|
int size;
|
||
|
int i, j, num_ports;
|
||
|
@@ -1701,6 +1702,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||
|
xhci_ring_free(xhci, xhci->cmd_ring);
|
||
|
xhci->cmd_ring = NULL;
|
||
|
xhci_dbg(xhci, "Freed command ring\n");
|
||
|
+ list_for_each_entry_safe(cur_cd, next_cd,
|
||
|
+ &xhci->cancel_cmd_list, cancel_cmd_list) {
|
||
|
+ list_del(&cur_cd->cancel_cmd_list);
|
||
|
+ kfree(cur_cd);
|
||
|
+ }
|
||
|
|
||
|
for (i = 1; i < MAX_HC_SLOTS; ++i)
|
||
|
xhci_free_virt_device(xhci, i);
|
||
|
@@ -2246,6 +2252,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||
|
xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, false, flags);
|
||
|
if (!xhci->cmd_ring)
|
||
|
goto fail;
|
||
|
+ INIT_LIST_HEAD(&xhci->cancel_cmd_list);
|
||
|
xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
|
||
|
xhci_dbg(xhci, "First segment DMA is 0x%llx\n",
|
||
|
(unsigned long long)xhci->cmd_ring->first_seg->dma);
|
||
|
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
|
||
|
index bddcbfc..4ed7572 100644
|
||
|
--- a/drivers/usb/host/xhci-pci.c
|
||
|
+++ b/drivers/usb/host/xhci-pci.c
|
||
|
@@ -99,6 +99,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||
|
* PPT chipsets.
|
||
|
*/
|
||
|
xhci->quirks |= XHCI_SPURIOUS_REBOOT;
|
||
|
+ xhci->quirks |= XHCI_AVOID_BEI;
|
||
|
}
|
||
|
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
|
||
|
pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
|
||
|
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
|
||
|
index c7c530c..950aef8 100644
|
||
|
--- a/drivers/usb/host/xhci-ring.c
|
||
|
+++ b/drivers/usb/host/xhci-ring.c
|
||
|
@@ -309,12 +309,123 @@ static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||
|
/* Ring the host controller doorbell after placing a command on the ring */
|
||
|
void xhci_ring_cmd_db(struct xhci_hcd *xhci)
|
||
|
{
|
||
|
+ if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING))
|
||
|
+ return;
|
||
|
+
|
||
|
xhci_dbg(xhci, "// Ding dong!\n");
|
||
|
xhci_writel(xhci, DB_VALUE_HOST, &xhci->dba->doorbell[0]);
|
||
|
/* Flush PCI posted writes */
|
||
|
xhci_readl(xhci, &xhci->dba->doorbell[0]);
|
||
|
}
|
||
|
|
||
|
+static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
|
||
|
+{
|
||
|
+ u64 temp_64;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ xhci_dbg(xhci, "Abort command ring\n");
|
||
|
+
|
||
|
+ if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING)) {
|
||
|
+ xhci_dbg(xhci, "The command ring isn't running, "
|
||
|
+ "Have the command ring been stopped?\n");
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
|
||
|
+ if (!(temp_64 & CMD_RING_RUNNING)) {
|
||
|
+ xhci_dbg(xhci, "Command ring had been stopped\n");
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
|
||
|
+ xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
|
||
|
+ &xhci->op_regs->cmd_ring);
|
||
|
+
|
||
|
+ /* Section 4.6.1.2 of xHCI 1.0 spec says software should
|
||
|
+ * time the completion od all xHCI commands, including
|
||
|
+ * the Command Abort operation. If software doesn't see
|
||
|
+ * CRR negated in a timely manner (e.g. longer than 5
|
||
|
+ * seconds), then it should assume that the there are
|
||
|
+ * larger problems with the xHC and assert HCRST.
|
||
|
+ */
|
||
|
+ ret = handshake(xhci, &xhci->op_regs->cmd_ring,
|
||
|
+ CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
|
||
|
+ if (ret < 0) {
|
||
|
+ xhci_err(xhci, "Stopped the command ring failed, "
|
||
|
+ "maybe the host is dead\n");
|
||
|
+ xhci->xhc_state |= XHCI_STATE_DYING;
|
||
|
+ xhci_quiesce(xhci);
|
||
|
+ xhci_halt(xhci);
|
||
|
+ return -ESHUTDOWN;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int xhci_queue_cd(struct xhci_hcd *xhci,
|
||
|
+ struct xhci_command *command,
|
||
|
+ union xhci_trb *cmd_trb)
|
||
|
+{
|
||
|
+ struct xhci_cd *cd;
|
||
|
+ cd = kzalloc(sizeof(struct xhci_cd), GFP_ATOMIC);
|
||
|
+ if (!cd)
|
||
|
+ return -ENOMEM;
|
||
|
+ INIT_LIST_HEAD(&cd->cancel_cmd_list);
|
||
|
+
|
||
|
+ cd->command = command;
|
||
|
+ cd->cmd_trb = cmd_trb;
|
||
|
+ list_add_tail(&cd->cancel_cmd_list, &xhci->cancel_cmd_list);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Cancel the command which has issue.
|
||
|
+ *
|
||
|
+ * Some commands may hang due to waiting for acknowledgement from
|
||
|
+ * usb device. It is outside of the xHC's ability to control and
|
||
|
+ * will cause the command ring is blocked. When it occurs software
|
||
|
+ * should intervene to recover the command ring.
|
||
|
+ * See Section 4.6.1.1 and 4.6.1.2
|
||
|
+ */
|
||
|
+int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command,
|
||
|
+ union xhci_trb *cmd_trb)
|
||
|
+{
|
||
|
+ int retval = 0;
|
||
|
+ unsigned long flags;
|
||
|
+
|
||
|
+ spin_lock_irqsave(&xhci->lock, flags);
|
||
|
+
|
||
|
+ if (xhci->xhc_state & XHCI_STATE_DYING) {
|
||
|
+ xhci_warn(xhci, "Abort the command ring,"
|
||
|
+ " but the xHCI is dead.\n");
|
||
|
+ retval = -ESHUTDOWN;
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* queue the cmd desriptor to cancel_cmd_list */
|
||
|
+ retval = xhci_queue_cd(xhci, command, cmd_trb);
|
||
|
+ if (retval) {
|
||
|
+ xhci_warn(xhci, "Queuing command descriptor failed.\n");
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* abort command ring */
|
||
|
+ retval = xhci_abort_cmd_ring(xhci);
|
||
|
+ if (retval) {
|
||
|
+ xhci_err(xhci, "Abort command ring failed\n");
|
||
|
+ if (unlikely(retval == -ESHUTDOWN)) {
|
||
|
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
||
|
+ usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
|
||
|
+ xhci_dbg(xhci, "xHCI host controller is dead.\n");
|
||
|
+ return retval;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+fail:
|
||
|
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
|
||
|
unsigned int slot_id,
|
||
|
unsigned int ep_index,
|
||
|
@@ -1043,6 +1154,20 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+/* Complete the command and detele it from the devcie's command queue.
|
||
|
+ */
|
||
|
+static void xhci_complete_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
|
||
|
+ struct xhci_command *command, u32 status)
|
||
|
+{
|
||
|
+ command->status = status;
|
||
|
+ list_del(&command->cmd_list);
|
||
|
+ if (command->completion)
|
||
|
+ complete(command->completion);
|
||
|
+ else
|
||
|
+ xhci_free_command(xhci, command);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
/* Check to see if a command in the device's command queue matches this one.
|
||
|
* Signal the completion or free the command, and return 1. Return 0 if the
|
||
|
* completed command isn't at the head of the command list.
|
||
|
@@ -1061,15 +1186,144 @@ static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
|
||
|
if (xhci->cmd_ring->dequeue != command->command_trb)
|
||
|
return 0;
|
||
|
|
||
|
- command->status = GET_COMP_CODE(le32_to_cpu(event->status));
|
||
|
- list_del(&command->cmd_list);
|
||
|
- if (command->completion)
|
||
|
- complete(command->completion);
|
||
|
- else
|
||
|
- xhci_free_command(xhci, command);
|
||
|
+ xhci_complete_cmd_in_cmd_wait_list(xhci, command,
|
||
|
+ GET_COMP_CODE(le32_to_cpu(event->status)));
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * Finding the command trb need to be cancelled and modifying it to
|
||
|
+ * NO OP command. And if the command is in device's command wait
|
||
|
+ * list, finishing and freeing it.
|
||
|
+ *
|
||
|
+ * If we can't find the command trb, we think it had already been
|
||
|
+ * executed.
|
||
|
+ */
|
||
|
+static void xhci_cmd_to_noop(struct xhci_hcd *xhci, struct xhci_cd *cur_cd)
|
||
|
+{
|
||
|
+ struct xhci_segment *cur_seg;
|
||
|
+ union xhci_trb *cmd_trb;
|
||
|
+ u32 cycle_state;
|
||
|
+
|
||
|
+ if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue)
|
||
|
+ return;
|
||
|
+
|
||
|
+ /* find the current segment of command ring */
|
||
|
+ cur_seg = find_trb_seg(xhci->cmd_ring->first_seg,
|
||
|
+ xhci->cmd_ring->dequeue, &cycle_state);
|
||
|
+
|
||
|
+ /* find the command trb matched by cd from command ring */
|
||
|
+ for (cmd_trb = xhci->cmd_ring->dequeue;
|
||
|
+ cmd_trb != xhci->cmd_ring->enqueue;
|
||
|
+ next_trb(xhci, xhci->cmd_ring, &cur_seg, &cmd_trb)) {
|
||
|
+ /* If the trb is link trb, continue */
|
||
|
+ if (TRB_TYPE_LINK_LE32(cmd_trb->generic.field[3]))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (cur_cd->cmd_trb == cmd_trb) {
|
||
|
+
|
||
|
+ /* If the command in device's command list, we should
|
||
|
+ * finish it and free the command structure.
|
||
|
+ */
|
||
|
+ if (cur_cd->command)
|
||
|
+ xhci_complete_cmd_in_cmd_wait_list(xhci,
|
||
|
+ cur_cd->command, COMP_CMD_STOP);
|
||
|
+
|
||
|
+ /* get cycle state from the origin command trb */
|
||
|
+ cycle_state = le32_to_cpu(cmd_trb->generic.field[3])
|
||
|
+ & TRB_CYCLE;
|
||
|
+
|
||
|
+ /* modify the command trb to NO OP command */
|
||
|
+ cmd_trb->generic.field[0] = 0;
|
||
|
+ cmd_trb->generic.field[1] = 0;
|
||
|
+ cmd_trb->generic.field[2] = 0;
|
||
|
+ cmd_trb->generic.field[3] = cpu_to_le32(
|
||
|
+ TRB_TYPE(TRB_CMD_NOOP) | cycle_state);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void xhci_cancel_cmd_in_cd_list(struct xhci_hcd *xhci)
|
||
|
+{
|
||
|
+ struct xhci_cd *cur_cd, *next_cd;
|
||
|
+
|
||
|
+ if (list_empty(&xhci->cancel_cmd_list))
|
||
|
+ return;
|
||
|
+
|
||
|
+ list_for_each_entry_safe(cur_cd, next_cd,
|
||
|
+ &xhci->cancel_cmd_list, cancel_cmd_list) {
|
||
|
+ xhci_cmd_to_noop(xhci, cur_cd);
|
||
|
+ list_del(&cur_cd->cancel_cmd_list);
|
||
|
+ kfree(cur_cd);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * traversing the cancel_cmd_list. If the command descriptor according
|
||
|
+ * to cmd_trb is found, the function free it and return 1, otherwise
|
||
|
+ * return 0.
|
||
|
+ */
|
||
|
+static int xhci_search_cmd_trb_in_cd_list(struct xhci_hcd *xhci,
|
||
|
+ union xhci_trb *cmd_trb)
|
||
|
+{
|
||
|
+ struct xhci_cd *cur_cd, *next_cd;
|
||
|
+
|
||
|
+ if (list_empty(&xhci->cancel_cmd_list))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ list_for_each_entry_safe(cur_cd, next_cd,
|
||
|
+ &xhci->cancel_cmd_list, cancel_cmd_list) {
|
||
|
+ if (cur_cd->cmd_trb == cmd_trb) {
|
||
|
+ if (cur_cd->command)
|
||
|
+ xhci_complete_cmd_in_cmd_wait_list(xhci,
|
||
|
+ cur_cd->command, COMP_CMD_STOP);
|
||
|
+ list_del(&cur_cd->cancel_cmd_list);
|
||
|
+ kfree(cur_cd);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * If the cmd_trb_comp_code is COMP_CMD_ABORT, we just check whether the
|
||
|
+ * trb pointed by the command ring dequeue pointer is the trb we want to
|
||
|
+ * cancel or not. And if the cmd_trb_comp_code is COMP_CMD_STOP, we will
|
||
|
+ * traverse the cancel_cmd_list to trun the all of the commands according
|
||
|
+ * to command descriptor to NO-OP trb.
|
||
|
+ */
|
||
|
+static int handle_stopped_cmd_ring(struct xhci_hcd *xhci,
|
||
|
+ int cmd_trb_comp_code)
|
||
|
+{
|
||
|
+ int cur_trb_is_good = 0;
|
||
|
+
|
||
|
+ /* Searching the cmd trb pointed by the command ring dequeue
|
||
|
+ * pointer in command descriptor list. If it is found, free it.
|
||
|
+ */
|
||
|
+ cur_trb_is_good = xhci_search_cmd_trb_in_cd_list(xhci,
|
||
|
+ xhci->cmd_ring->dequeue);
|
||
|
+
|
||
|
+ if (cmd_trb_comp_code == COMP_CMD_ABORT)
|
||
|
+ xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
|
||
|
+ else if (cmd_trb_comp_code == COMP_CMD_STOP) {
|
||
|
+ /* traversing the cancel_cmd_list and canceling
|
||
|
+ * the command according to command descriptor
|
||
|
+ */
|
||
|
+ xhci_cancel_cmd_in_cd_list(xhci);
|
||
|
+
|
||
|
+ xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
|
||
|
+ /*
|
||
|
+ * ring command ring doorbell again to restart the
|
||
|
+ * command ring
|
||
|
+ */
|
||
|
+ if (xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue)
|
||
|
+ xhci_ring_cmd_db(xhci);
|
||
|
+ }
|
||
|
+ return cur_trb_is_good;
|
||
|
+}
|
||
|
+
|
||
|
static void handle_cmd_completion(struct xhci_hcd *xhci,
|
||
|
struct xhci_event_cmd *event)
|
||
|
{
|
||
|
@@ -1095,6 +1349,22 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
||
|
xhci->error_bitmask |= 1 << 5;
|
||
|
return;
|
||
|
}
|
||
|
+
|
||
|
+ if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) ||
|
||
|
+ (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) {
|
||
|
+ /* If the return value is 0, we think the trb pointed by
|
||
|
+ * command ring dequeue pointer is a good trb. The good
|
||
|
+ * trb means we don't want to cancel the trb, but it have
|
||
|
+ * been stopped by host. So we should handle it normally.
|
||
|
+ * Otherwise, driver should invoke inc_deq() and return.
|
||
|
+ */
|
||
|
+ if (handle_stopped_cmd_ring(xhci,
|
||
|
+ GET_COMP_CODE(le32_to_cpu(event->status)))) {
|
||
|
+ inc_deq(xhci, xhci->cmd_ring, false);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])
|
||
|
& TRB_TYPE_BITMASK) {
|
||
|
case TRB_TYPE(TRB_ENABLE_SLOT):
|
||
|
@@ -3356,7 +3626,9 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||
|
} else {
|
||
|
td->last_trb = ep_ring->enqueue;
|
||
|
field |= TRB_IOC;
|
||
|
- if (xhci->hci_version == 0x100) {
|
||
|
+ if (xhci->hci_version == 0x100 &&
|
||
|
+ !(xhci->quirks &
|
||
|
+ XHCI_AVOID_BEI)) {
|
||
|
/* Set BEI bit except for the last td */
|
||
|
if (i < num_tds - 1)
|
||
|
field |= TRB_BEI;
|
||
|
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
|
||
|
index 09872ee..f5c0f38 100644
|
||
|
--- a/drivers/usb/host/xhci.c
|
||
|
+++ b/drivers/usb/host/xhci.c
|
||
|
@@ -52,7 +52,7 @@ MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB");
|
||
|
* handshake done). There are two failure modes: "usec" have passed (major
|
||
|
* hardware flakeout), or the register reads as all-ones (hardware removed).
|
||
|
*/
|
||
|
-static int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
|
||
|
+int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
|
||
|
u32 mask, u32 done, int usec)
|
||
|
{
|
||
|
u32 result;
|
||
|
@@ -105,8 +105,12 @@ int xhci_halt(struct xhci_hcd *xhci)
|
||
|
|
||
|
ret = handshake(xhci, &xhci->op_regs->status,
|
||
|
STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
|
||
|
- if (!ret)
|
||
|
+ if (!ret) {
|
||
|
xhci->xhc_state |= XHCI_STATE_HALTED;
|
||
|
+ xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
|
||
|
+ } else
|
||
|
+ xhci_warn(xhci, "Host not halted after %u microseconds.\n",
|
||
|
+ XHCI_MAX_HALT_USEC);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
@@ -459,6 +463,8 @@ static bool compliance_mode_recovery_timer_quirk_check(void)
|
||
|
|
||
|
dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
|
||
|
dmi_sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR);
|
||
|
+ if (!dmi_product_name || !dmi_sys_vendor)
|
||
|
+ return false;
|
||
|
|
||
|
if (!(strstr(dmi_sys_vendor, "Hewlett-Packard")))
|
||
|
return false;
|
||
|
@@ -570,6 +576,7 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
|
||
|
return -ENODEV;
|
||
|
}
|
||
|
xhci->shared_hcd->state = HC_STATE_RUNNING;
|
||
|
+ xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
|
||
|
|
||
|
if (xhci->quirks & XHCI_NEC_HOST)
|
||
|
xhci_ring_cmd_db(xhci);
|
||
|
@@ -874,7 +881,7 @@ int xhci_suspend(struct xhci_hcd *xhci)
|
||
|
command &= ~CMD_RUN;
|
||
|
xhci_writel(xhci, command, &xhci->op_regs->command);
|
||
|
if (handshake(xhci, &xhci->op_regs->status,
|
||
|
- STS_HALT, STS_HALT, 100*100)) {
|
||
|
+ STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC)) {
|
||
|
xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n");
|
||
|
spin_unlock_irq(&xhci->lock);
|
||
|
return -ETIMEDOUT;
|
||
|
@@ -2506,6 +2513,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
||
|
struct completion *cmd_completion;
|
||
|
u32 *cmd_status;
|
||
|
struct xhci_virt_device *virt_dev;
|
||
|
+ union xhci_trb *cmd_trb;
|
||
|
|
||
|
spin_lock_irqsave(&xhci->lock, flags);
|
||
|
virt_dev = xhci->devs[udev->slot_id];
|
||
|
@@ -2551,6 +2559,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
||
|
}
|
||
|
init_completion(cmd_completion);
|
||
|
|
||
|
+ cmd_trb = xhci->cmd_ring->dequeue;
|
||
|
if (!ctx_change)
|
||
|
ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma,
|
||
|
udev->slot_id, must_succeed);
|
||
|
@@ -2572,14 +2581,17 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
||
|
/* Wait for the configure endpoint command to complete */
|
||
|
timeleft = wait_for_completion_interruptible_timeout(
|
||
|
cmd_completion,
|
||
|
- USB_CTRL_SET_TIMEOUT);
|
||
|
+ XHCI_CMD_DEFAULT_TIMEOUT);
|
||
|
if (timeleft <= 0) {
|
||
|
xhci_warn(xhci, "%s while waiting for %s command\n",
|
||
|
timeleft == 0 ? "Timeout" : "Signal",
|
||
|
ctx_change == 0 ?
|
||
|
"configure endpoint" :
|
||
|
"evaluate context");
|
||
|
- /* FIXME cancel the configure endpoint command */
|
||
|
+ /* cancel the configure endpoint command */
|
||
|
+ ret = xhci_cancel_cmd(xhci, command, cmd_trb);
|
||
|
+ if (ret < 0)
|
||
|
+ return ret;
|
||
|
return -ETIME;
|
||
|
}
|
||
|
|
||
|
@@ -3528,8 +3540,10 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
||
|
unsigned long flags;
|
||
|
int timeleft;
|
||
|
int ret;
|
||
|
+ union xhci_trb *cmd_trb;
|
||
|
|
||
|
spin_lock_irqsave(&xhci->lock, flags);
|
||
|
+ cmd_trb = xhci->cmd_ring->dequeue;
|
||
|
ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0);
|
||
|
if (ret) {
|
||
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||
|
@@ -3541,12 +3555,12 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
||
|
|
||
|
/* XXX: how much time for xHC slot assignment? */
|
||
|
timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
|
||
|
- USB_CTRL_SET_TIMEOUT);
|
||
|
+ XHCI_CMD_DEFAULT_TIMEOUT);
|
||
|
if (timeleft <= 0) {
|
||
|
xhci_warn(xhci, "%s while waiting for a slot\n",
|
||
|
timeleft == 0 ? "Timeout" : "Signal");
|
||
|
- /* FIXME cancel the enable slot request */
|
||
|
- return 0;
|
||
|
+ /* cancel the enable slot request */
|
||
|
+ return xhci_cancel_cmd(xhci, NULL, cmd_trb);
|
||
|
}
|
||
|
|
||
|
if (!xhci->slot_id) {
|
||
|
@@ -3607,6 +3621,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||
|
struct xhci_slot_ctx *slot_ctx;
|
||
|
struct xhci_input_control_ctx *ctrl_ctx;
|
||
|
u64 temp_64;
|
||
|
+ union xhci_trb *cmd_trb;
|
||
|
|
||
|
if (!udev->slot_id) {
|
||
|
xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id);
|
||
|
@@ -3645,6 +3660,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||
|
xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
|
||
|
|
||
|
spin_lock_irqsave(&xhci->lock, flags);
|
||
|
+ cmd_trb = xhci->cmd_ring->dequeue;
|
||
|
ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma,
|
||
|
udev->slot_id);
|
||
|
if (ret) {
|
||
|
@@ -3657,7 +3673,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||
|
|
||
|
/* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */
|
||
|
timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
|
||
|
- USB_CTRL_SET_TIMEOUT);
|
||
|
+ XHCI_CMD_DEFAULT_TIMEOUT);
|
||
|
/* FIXME: From section 4.3.4: "Software shall be responsible for timing
|
||
|
* the SetAddress() "recovery interval" required by USB and aborting the
|
||
|
* command on a timeout.
|
||
|
@@ -3665,7 +3681,10 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||
|
if (timeleft <= 0) {
|
||
|
xhci_warn(xhci, "%s while waiting for address device command\n",
|
||
|
timeleft == 0 ? "Timeout" : "Signal");
|
||
|
- /* FIXME cancel the address device command */
|
||
|
+ /* cancel the address device command */
|
||
|
+ ret = xhci_cancel_cmd(xhci, NULL, cmd_trb);
|
||
|
+ if (ret < 0)
|
||
|
+ return ret;
|
||
|
return -ETIME;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
|
||
|
index 44d518a..cc368c2 100644
|
||
|
--- a/drivers/usb/host/xhci.h
|
||
|
+++ b/drivers/usb/host/xhci.h
|
||
|
@@ -1255,6 +1255,16 @@ struct xhci_td {
|
||
|
union xhci_trb *last_trb;
|
||
|
};
|
||
|
|
||
|
+/* xHCI command default timeout value */
|
||
|
+#define XHCI_CMD_DEFAULT_TIMEOUT (5 * HZ)
|
||
|
+
|
||
|
+/* command descriptor */
|
||
|
+struct xhci_cd {
|
||
|
+ struct list_head cancel_cmd_list;
|
||
|
+ struct xhci_command *command;
|
||
|
+ union xhci_trb *cmd_trb;
|
||
|
+};
|
||
|
+
|
||
|
struct xhci_dequeue_state {
|
||
|
struct xhci_segment *new_deq_seg;
|
||
|
union xhci_trb *new_deq_ptr;
|
||
|
@@ -1402,6 +1412,11 @@ struct xhci_hcd {
|
||
|
/* data structures */
|
||
|
struct xhci_device_context_array *dcbaa;
|
||
|
struct xhci_ring *cmd_ring;
|
||
|
+ unsigned int cmd_ring_state;
|
||
|
+#define CMD_RING_STATE_RUNNING (1 << 0)
|
||
|
+#define CMD_RING_STATE_ABORTED (1 << 1)
|
||
|
+#define CMD_RING_STATE_STOPPED (1 << 2)
|
||
|
+ struct list_head cancel_cmd_list;
|
||
|
unsigned int cmd_ring_reserved_trbs;
|
||
|
struct xhci_ring *event_ring;
|
||
|
struct xhci_erst erst;
|
||
|
@@ -1473,6 +1488,7 @@ struct xhci_hcd {
|
||
|
#define XHCI_TRUST_TX_LENGTH (1 << 10)
|
||
|
#define XHCI_SPURIOUS_REBOOT (1 << 13)
|
||
|
#define XHCI_COMP_MODE_QUIRK (1 << 14)
|
||
|
+#define XHCI_AVOID_BEI (1 << 15)
|
||
|
unsigned int num_active_eps;
|
||
|
unsigned int limit_active_eps;
|
||
|
/* There are two roothubs to keep track of bus suspend info for */
|
||
|
@@ -1666,6 +1682,8 @@ static inline void xhci_unregister_pci(void) {}
|
||
|
|
||
|
/* xHCI host controller glue */
|
||
|
typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
|
||
|
+int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
|
||
|
+ u32 mask, u32 done, int usec);
|
||
|
void xhci_quiesce(struct xhci_hcd *xhci);
|
||
|
int xhci_halt(struct xhci_hcd *xhci);
|
||
|
int xhci_reset(struct xhci_hcd *xhci);
|
||
|
@@ -1756,6 +1774,8 @@ void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,
|
||
|
unsigned int slot_id, unsigned int ep_index,
|
||
|
struct xhci_dequeue_state *deq_state);
|
||
|
void xhci_stop_endpoint_command_watchdog(unsigned long arg);
|
||
|
+int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command,
|
||
|
+ union xhci_trb *cmd_trb);
|
||
|
void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
|
||
|
unsigned int ep_index, unsigned int stream_id);
|
||
|
|
||
|
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
|
||
|
index 7324bea..e29a664 100644
|
||
|
--- a/drivers/usb/serial/ftdi_sio.c
|
||
|
+++ b/drivers/usb/serial/ftdi_sio.c
|
||
|
@@ -584,6 +584,8 @@ static struct usb_device_id id_table_combined [] = {
|
||
|
{ USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
|
||
|
{ USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
|
||
|
{ USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) },
|
||
|
+ { USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID),
|
||
|
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
|
||
|
/*
|
||
|
* ELV devices:
|
||
|
*/
|
||
|
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
|
||
|
index 06f6fd2..7b5eb74 100644
|
||
|
--- a/drivers/usb/serial/ftdi_sio_ids.h
|
||
|
+++ b/drivers/usb/serial/ftdi_sio_ids.h
|
||
|
@@ -517,6 +517,11 @@
|
||
|
*/
|
||
|
#define FTDI_TAVIR_STK500_PID 0xFA33 /* STK500 AVR programmer */
|
||
|
|
||
|
+/*
|
||
|
+ * TIAO product ids (FTDI_VID)
|
||
|
+ * http://www.tiaowiki.com/w/Main_Page
|
||
|
+ */
|
||
|
+#define FTDI_TIAO_UMPA_PID 0x8a98 /* TIAO/DIYGADGET USB Multi-Protocol Adapter */
|
||
|
|
||
|
|
||
|
/********************************/
|
||
|
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
|
||
|
index c068b4d..3fd4e6f 100644
|
||
|
--- a/drivers/usb/serial/option.c
|
||
|
+++ b/drivers/usb/serial/option.c
|
||
|
@@ -870,7 +870,8 @@ static const struct usb_device_id option_ids[] = {
|
||
|
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0153, 0xff, 0xff, 0xff) },
|
||
|
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) },
|
||
|
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) },
|
||
|
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff) },
|
||
|
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff),
|
||
|
+ .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
|
||
|
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff) },
|
||
|
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0159, 0xff, 0xff, 0xff) },
|
||
|
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) },
|
||
|
diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c
|
||
|
index a348198..87271e3 100644
|
||
|
--- a/drivers/usb/serial/qcaux.c
|
||
|
+++ b/drivers/usb/serial/qcaux.c
|
||
|
@@ -36,8 +36,6 @@
|
||
|
#define UTSTARCOM_PRODUCT_UM175_V1 0x3712
|
||
|
#define UTSTARCOM_PRODUCT_UM175_V2 0x3714
|
||
|
#define UTSTARCOM_PRODUCT_UM175_ALLTEL 0x3715
|
||
|
-#define PANTECH_PRODUCT_UML190_VZW 0x3716
|
||
|
-#define PANTECH_PRODUCT_UML290_VZW 0x3718
|
||
|
|
||
|
/* CMOTECH devices */
|
||
|
#define CMOTECH_VENDOR_ID 0x16d8
|
||
|
@@ -68,11 +66,9 @@ static struct usb_device_id id_table[] = {
|
||
|
{ USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) },
|
||
|
{ USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) },
|
||
|
{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) },
|
||
|
- { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xff, 0xff) },
|
||
|
- { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xfe, 0xff) },
|
||
|
- { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfd, 0xff) }, /* NMEA */
|
||
|
- { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfe, 0xff) }, /* WMC */
|
||
|
- { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) }, /* DIAG */
|
||
|
+ { USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xfd, 0xff) }, /* NMEA */
|
||
|
+ { USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xfe, 0xff) }, /* WMC */
|
||
|
+ { USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xff, 0xff) }, /* DIAG */
|
||
|
{ },
|
||
|
};
|
||
|
MODULE_DEVICE_TABLE(usb, id_table);
|
||
|
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
|
||
|
index f55ae23..790fa63 100644
|
||
|
--- a/fs/autofs4/root.c
|
||
|
+++ b/fs/autofs4/root.c
|
||
|
@@ -392,10 +392,12 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
|
||
|
ino->flags |= AUTOFS_INF_PENDING;
|
||
|
spin_unlock(&sbi->fs_lock);
|
||
|
status = autofs4_mount_wait(dentry);
|
||
|
- if (status)
|
||
|
- return ERR_PTR(status);
|
||
|
spin_lock(&sbi->fs_lock);
|
||
|
ino->flags &= ~AUTOFS_INF_PENDING;
|
||
|
+ if (status) {
|
||
|
+ spin_unlock(&sbi->fs_lock);
|
||
|
+ return ERR_PTR(status);
|
||
|
+ }
|
||
|
}
|
||
|
done:
|
||
|
if (!(ino->flags & AUTOFS_INF_EXPIRING)) {
|
||
|
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
|
||
|
index 6ff96c6..8dd615c 100644
|
||
|
--- a/fs/binfmt_elf.c
|
||
|
+++ b/fs/binfmt_elf.c
|
||
|
@@ -1668,30 +1668,19 @@ static int elf_note_info_init(struct elf_note_info *info)
|
||
|
return 0;
|
||
|
info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL);
|
||
|
if (!info->psinfo)
|
||
|
- goto notes_free;
|
||
|
+ return 0;
|
||
|
info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL);
|
||
|
if (!info->prstatus)
|
||
|
- goto psinfo_free;
|
||
|
+ return 0;
|
||
|
info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL);
|
||
|
if (!info->fpu)
|
||
|
- goto prstatus_free;
|
||
|
+ return 0;
|
||
|
#ifdef ELF_CORE_COPY_XFPREGS
|
||
|
info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL);
|
||
|
if (!info->xfpu)
|
||
|
- goto fpu_free;
|
||
|
+ return 0;
|
||
|
#endif
|
||
|
return 1;
|
||
|
-#ifdef ELF_CORE_COPY_XFPREGS
|
||
|
- fpu_free:
|
||
|
- kfree(info->fpu);
|
||
|
-#endif
|
||
|
- prstatus_free:
|
||
|
- kfree(info->prstatus);
|
||
|
- psinfo_free:
|
||
|
- kfree(info->psinfo);
|
||
|
- notes_free:
|
||
|
- kfree(info->notes);
|
||
|
- return 0;
|
||
|
}
|
||
|
|
||
|
static int fill_note_info(struct elfhdr *elf, int phdrs,
|
||
|
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
|
||
|
index a9f29b1..2262a77 100644
|
||
|
--- a/fs/ecryptfs/ecryptfs_kernel.h
|
||
|
+++ b/fs/ecryptfs/ecryptfs_kernel.h
|
||
|
@@ -559,6 +559,8 @@ struct ecryptfs_open_req {
|
||
|
struct inode *ecryptfs_get_inode(struct inode *lower_inode,
|
||
|
struct super_block *sb);
|
||
|
void ecryptfs_i_size_init(const char *page_virt, struct inode *inode);
|
||
|
+int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
|
||
|
+ struct inode *ecryptfs_inode);
|
||
|
int ecryptfs_decode_and_decrypt_filename(char **decrypted_name,
|
||
|
size_t *decrypted_name_size,
|
||
|
struct dentry *ecryptfs_dentry,
|
||
|
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
|
||
|
index d3f95f9..841f24f 100644
|
||
|
--- a/fs/ecryptfs/file.c
|
||
|
+++ b/fs/ecryptfs/file.c
|
||
|
@@ -139,29 +139,50 @@ out:
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
-static void ecryptfs_vma_close(struct vm_area_struct *vma)
|
||
|
-{
|
||
|
- filemap_write_and_wait(vma->vm_file->f_mapping);
|
||
|
-}
|
||
|
-
|
||
|
-static const struct vm_operations_struct ecryptfs_file_vm_ops = {
|
||
|
- .close = ecryptfs_vma_close,
|
||
|
- .fault = filemap_fault,
|
||
|
-};
|
||
|
+struct kmem_cache *ecryptfs_file_info_cache;
|
||
|
|
||
|
-static int ecryptfs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
||
|
+static int read_or_initialize_metadata(struct dentry *dentry)
|
||
|
{
|
||
|
+ struct inode *inode = dentry->d_inode;
|
||
|
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
|
||
|
+ struct ecryptfs_crypt_stat *crypt_stat;
|
||
|
int rc;
|
||
|
|
||
|
- rc = generic_file_mmap(file, vma);
|
||
|
+ crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
|
||
|
+ mount_crypt_stat = &ecryptfs_superblock_to_private(
|
||
|
+ inode->i_sb)->mount_crypt_stat;
|
||
|
+ mutex_lock(&crypt_stat->cs_mutex);
|
||
|
+
|
||
|
+ if (crypt_stat->flags & ECRYPTFS_POLICY_APPLIED &&
|
||
|
+ crypt_stat->flags & ECRYPTFS_KEY_VALID) {
|
||
|
+ rc = 0;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ rc = ecryptfs_read_metadata(dentry);
|
||
|
if (!rc)
|
||
|
- vma->vm_ops = &ecryptfs_file_vm_ops;
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED) {
|
||
|
+ crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED
|
||
|
+ | ECRYPTFS_ENCRYPTED);
|
||
|
+ rc = 0;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!(mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) &&
|
||
|
+ !i_size_read(ecryptfs_inode_to_lower(inode))) {
|
||
|
+ rc = ecryptfs_initialize_file(dentry, inode);
|
||
|
+ if (!rc)
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
|
||
|
+ rc = -EIO;
|
||
|
+out:
|
||
|
+ mutex_unlock(&crypt_stat->cs_mutex);
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
-struct kmem_cache *ecryptfs_file_info_cache;
|
||
|
-
|
||
|
/**
|
||
|
* ecryptfs_open
|
||
|
* @inode: inode speciying file to open
|
||
|
@@ -237,32 +258,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
|
||
|
rc = 0;
|
||
|
goto out;
|
||
|
}
|
||
|
- mutex_lock(&crypt_stat->cs_mutex);
|
||
|
- if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)
|
||
|
- || !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) {
|
||
|
- rc = ecryptfs_read_metadata(ecryptfs_dentry);
|
||
|
- if (rc) {
|
||
|
- ecryptfs_printk(KERN_DEBUG,
|
||
|
- "Valid headers not found\n");
|
||
|
- if (!(mount_crypt_stat->flags
|
||
|
- & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
|
||
|
- rc = -EIO;
|
||
|
- printk(KERN_WARNING "Either the lower file "
|
||
|
- "is not in a valid eCryptfs format, "
|
||
|
- "or the key could not be retrieved. "
|
||
|
- "Plaintext passthrough mode is not "
|
||
|
- "enabled; returning -EIO\n");
|
||
|
- mutex_unlock(&crypt_stat->cs_mutex);
|
||
|
- goto out_put;
|
||
|
- }
|
||
|
- rc = 0;
|
||
|
- crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED
|
||
|
- | ECRYPTFS_ENCRYPTED);
|
||
|
- mutex_unlock(&crypt_stat->cs_mutex);
|
||
|
- goto out;
|
||
|
- }
|
||
|
- }
|
||
|
- mutex_unlock(&crypt_stat->cs_mutex);
|
||
|
+ rc = read_or_initialize_metadata(ecryptfs_dentry);
|
||
|
+ if (rc)
|
||
|
+ goto out_put;
|
||
|
ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = "
|
||
|
"[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino,
|
||
|
(unsigned long long)i_size_read(inode));
|
||
|
@@ -278,8 +276,14 @@ out:
|
||
|
|
||
|
static int ecryptfs_flush(struct file *file, fl_owner_t td)
|
||
|
{
|
||
|
- return file->f_mode & FMODE_WRITE
|
||
|
- ? filemap_write_and_wait(file->f_mapping) : 0;
|
||
|
+ struct file *lower_file = ecryptfs_file_to_lower(file);
|
||
|
+
|
||
|
+ if (lower_file->f_op && lower_file->f_op->flush) {
|
||
|
+ filemap_write_and_wait(file->f_mapping);
|
||
|
+ return lower_file->f_op->flush(lower_file, td);
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
static int ecryptfs_release(struct inode *inode, struct file *file)
|
||
|
@@ -293,15 +297,7 @@ static int ecryptfs_release(struct inode *inode, struct file *file)
|
||
|
static int
|
||
|
ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
||
|
{
|
||
|
- int rc = 0;
|
||
|
-
|
||
|
- rc = generic_file_fsync(file, start, end, datasync);
|
||
|
- if (rc)
|
||
|
- goto out;
|
||
|
- rc = vfs_fsync_range(ecryptfs_file_to_lower(file), start, end,
|
||
|
- datasync);
|
||
|
-out:
|
||
|
- return rc;
|
||
|
+ return vfs_fsync(ecryptfs_file_to_lower(file), datasync);
|
||
|
}
|
||
|
|
||
|
static int ecryptfs_fasync(int fd, struct file *file, int flag)
|
||
|
@@ -370,7 +366,7 @@ const struct file_operations ecryptfs_main_fops = {
|
||
|
#ifdef CONFIG_COMPAT
|
||
|
.compat_ioctl = ecryptfs_compat_ioctl,
|
||
|
#endif
|
||
|
- .mmap = ecryptfs_file_mmap,
|
||
|
+ .mmap = generic_file_mmap,
|
||
|
.open = ecryptfs_open,
|
||
|
.flush = ecryptfs_flush,
|
||
|
.release = ecryptfs_release,
|
||
|
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
|
||
|
index 7c7556b..a9be90d 100644
|
||
|
--- a/fs/ecryptfs/inode.c
|
||
|
+++ b/fs/ecryptfs/inode.c
|
||
|
@@ -161,6 +161,31 @@ ecryptfs_create_underlying_file(struct inode *lower_dir_inode,
|
||
|
return vfs_create(lower_dir_inode, lower_dentry, mode, NULL);
|
||
|
}
|
||
|
|
||
|
+static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry,
|
||
|
+ struct inode *inode)
|
||
|
+{
|
||
|
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||
|
+ struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
|
||
|
+ struct dentry *lower_dir_dentry;
|
||
|
+ int rc;
|
||
|
+
|
||
|
+ dget(lower_dentry);
|
||
|
+ lower_dir_dentry = lock_parent(lower_dentry);
|
||
|
+ rc = vfs_unlink(lower_dir_inode, lower_dentry);
|
||
|
+ if (rc) {
|
||
|
+ printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
|
||
|
+ goto out_unlock;
|
||
|
+ }
|
||
|
+ fsstack_copy_attr_times(dir, lower_dir_inode);
|
||
|
+ set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink);
|
||
|
+ inode->i_ctime = dir->i_ctime;
|
||
|
+ d_drop(dentry);
|
||
|
+out_unlock:
|
||
|
+ unlock_dir(lower_dir_dentry);
|
||
|
+ dput(lower_dentry);
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* ecryptfs_do_create
|
||
|
* @directory_inode: inode of the new file's dentry's parent in ecryptfs
|
||
|
@@ -201,8 +226,10 @@ ecryptfs_do_create(struct inode *directory_inode,
|
||
|
}
|
||
|
inode = __ecryptfs_get_inode(lower_dentry->d_inode,
|
||
|
directory_inode->i_sb);
|
||
|
- if (IS_ERR(inode))
|
||
|
+ if (IS_ERR(inode)) {
|
||
|
+ vfs_unlink(lower_dir_dentry->d_inode, lower_dentry);
|
||
|
goto out_lock;
|
||
|
+ }
|
||
|
fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode);
|
||
|
fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode);
|
||
|
out_lock:
|
||
|
@@ -219,8 +246,8 @@ out:
|
||
|
*
|
||
|
* Returns zero on success
|
||
|
*/
|
||
|
-static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
|
||
|
- struct inode *ecryptfs_inode)
|
||
|
+int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
|
||
|
+ struct inode *ecryptfs_inode)
|
||
|
{
|
||
|
struct ecryptfs_crypt_stat *crypt_stat =
|
||
|
&ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
|
||
|
@@ -284,7 +311,9 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
|
||
|
* that this on disk file is prepared to be an ecryptfs file */
|
||
|
rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode);
|
||
|
if (rc) {
|
||
|
- drop_nlink(ecryptfs_inode);
|
||
|
+ ecryptfs_do_unlink(directory_inode, ecryptfs_dentry,
|
||
|
+ ecryptfs_inode);
|
||
|
+ make_bad_inode(ecryptfs_inode);
|
||
|
unlock_new_inode(ecryptfs_inode);
|
||
|
iput(ecryptfs_inode);
|
||
|
goto out;
|
||
|
@@ -496,27 +525,7 @@ out_lock:
|
||
|
|
||
|
static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
|
||
|
{
|
||
|
- int rc = 0;
|
||
|
- struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||
|
- struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
|
||
|
- struct dentry *lower_dir_dentry;
|
||
|
-
|
||
|
- dget(lower_dentry);
|
||
|
- lower_dir_dentry = lock_parent(lower_dentry);
|
||
|
- rc = vfs_unlink(lower_dir_inode, lower_dentry);
|
||
|
- if (rc) {
|
||
|
- printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
|
||
|
- goto out_unlock;
|
||
|
- }
|
||
|
- fsstack_copy_attr_times(dir, lower_dir_inode);
|
||
|
- set_nlink(dentry->d_inode,
|
||
|
- ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink);
|
||
|
- dentry->d_inode->i_ctime = dir->i_ctime;
|
||
|
- d_drop(dentry);
|
||
|
-out_unlock:
|
||
|
- unlock_dir(lower_dir_dentry);
|
||
|
- dput(lower_dentry);
|
||
|
- return rc;
|
||
|
+ return ecryptfs_do_unlink(dir, dentry, dentry->d_inode);
|
||
|
}
|
||
|
|
||
|
static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
|
||
|
@@ -1026,12 +1035,6 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
- if (S_ISREG(inode->i_mode)) {
|
||
|
- rc = filemap_write_and_wait(inode->i_mapping);
|
||
|
- if (rc)
|
||
|
- goto out;
|
||
|
- fsstack_copy_attr_all(inode, lower_inode);
|
||
|
- }
|
||
|
memcpy(&lower_ia, ia, sizeof(lower_ia));
|
||
|
if (ia->ia_valid & ATTR_FILE)
|
||
|
lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file);
|
||
|
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
|
||
|
index b4a6bef..1cfef9f 100644
|
||
|
--- a/fs/ecryptfs/main.c
|
||
|
+++ b/fs/ecryptfs/main.c
|
||
|
@@ -162,6 +162,7 @@ void ecryptfs_put_lower_file(struct inode *inode)
|
||
|
inode_info = ecryptfs_inode_to_private(inode);
|
||
|
if (atomic_dec_and_mutex_lock(&inode_info->lower_file_count,
|
||
|
&inode_info->lower_file_mutex)) {
|
||
|
+ filemap_write_and_wait(inode->i_mapping);
|
||
|
fput(inode_info->lower_file);
|
||
|
inode_info->lower_file = NULL;
|
||
|
mutex_unlock(&inode_info->lower_file_mutex);
|
||
|
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
|
||
|
index 6a44148..93a998a 100644
|
||
|
--- a/fs/ecryptfs/mmap.c
|
||
|
+++ b/fs/ecryptfs/mmap.c
|
||
|
@@ -62,18 +62,6 @@ static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc)
|
||
|
{
|
||
|
int rc;
|
||
|
|
||
|
- /*
|
||
|
- * Refuse to write the page out if we are called from reclaim context
|
||
|
- * since our writepage() path may potentially allocate memory when
|
||
|
- * calling into the lower fs vfs_write() which may in turn invoke
|
||
|
- * us again.
|
||
|
- */
|
||
|
- if (current->flags & PF_MEMALLOC) {
|
||
|
- redirty_page_for_writepage(wbc, page);
|
||
|
- rc = 0;
|
||
|
- goto out;
|
||
|
- }
|
||
|
-
|
||
|
rc = ecryptfs_encrypt_page(page);
|
||
|
if (rc) {
|
||
|
ecryptfs_printk(KERN_WARNING, "Error encrypting "
|
||
|
@@ -498,7 +486,6 @@ static int ecryptfs_write_end(struct file *file,
|
||
|
struct ecryptfs_crypt_stat *crypt_stat =
|
||
|
&ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
|
||
|
int rc;
|
||
|
- int need_unlock_page = 1;
|
||
|
|
||
|
ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
|
||
|
"(page w/ index = [0x%.16lx], to = [%d])\n", index, to);
|
||
|
@@ -519,26 +506,26 @@ static int ecryptfs_write_end(struct file *file,
|
||
|
"zeros in page with index = [0x%.16lx]\n", index);
|
||
|
goto out;
|
||
|
}
|
||
|
- set_page_dirty(page);
|
||
|
- unlock_page(page);
|
||
|
- need_unlock_page = 0;
|
||
|
+ rc = ecryptfs_encrypt_page(page);
|
||
|
+ if (rc) {
|
||
|
+ ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper "
|
||
|
+ "index [0x%.16lx])\n", index);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
if (pos + copied > i_size_read(ecryptfs_inode)) {
|
||
|
i_size_write(ecryptfs_inode, pos + copied);
|
||
|
ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
|
||
|
"[0x%.16llx]\n",
|
||
|
(unsigned long long)i_size_read(ecryptfs_inode));
|
||
|
- balance_dirty_pages_ratelimited(mapping);
|
||
|
- rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode);
|
||
|
- if (rc) {
|
||
|
- printk(KERN_ERR "Error writing inode size to metadata; "
|
||
|
- "rc = [%d]\n", rc);
|
||
|
- goto out;
|
||
|
- }
|
||
|
}
|
||
|
- rc = copied;
|
||
|
+ rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode);
|
||
|
+ if (rc)
|
||
|
+ printk(KERN_ERR "Error writing inode size to metadata; "
|
||
|
+ "rc = [%d]\n", rc);
|
||
|
+ else
|
||
|
+ rc = copied;
|
||
|
out:
|
||
|
- if (need_unlock_page)
|
||
|
- unlock_page(page);
|
||
|
+ unlock_page(page);
|
||
|
page_cache_release(page);
|
||
|
return rc;
|
||
|
}
|
||
|
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
|
||
|
index 8b01f9f..bac2330 100644
|
||
|
--- a/fs/ext4/inode.c
|
||
|
+++ b/fs/ext4/inode.c
|
||
|
@@ -2382,6 +2382,16 @@ static int ext4_nonda_switch(struct super_block *sb)
|
||
|
free_blocks = EXT4_C2B(sbi,
|
||
|
percpu_counter_read_positive(&sbi->s_freeclusters_counter));
|
||
|
dirty_blocks = percpu_counter_read_positive(&sbi->s_dirtyclusters_counter);
|
||
|
+ /*
|
||
|
+ * Start pushing delalloc when 1/2 of free blocks are dirty.
|
||
|
+ */
|
||
|
+ if (dirty_blocks && (free_blocks < 2 * dirty_blocks) &&
|
||
|
+ !writeback_in_progress(sb->s_bdi) &&
|
||
|
+ down_read_trylock(&sb->s_umount)) {
|
||
|
+ writeback_inodes_sb(sb, WB_REASON_FS_FREE_SPACE);
|
||
|
+ up_read(&sb->s_umount);
|
||
|
+ }
|
||
|
+
|
||
|
if (2 * free_blocks < 3 * dirty_blocks ||
|
||
|
free_blocks < (dirty_blocks + EXT4_FREECLUSTERS_WATERMARK)) {
|
||
|
/*
|
||
|
@@ -2390,13 +2400,6 @@ static int ext4_nonda_switch(struct super_block *sb)
|
||
|
*/
|
||
|
return 1;
|
||
|
}
|
||
|
- /*
|
||
|
- * Even if we don't switch but are nearing capacity,
|
||
|
- * start pushing delalloc when 1/2 of free blocks are dirty.
|
||
|
- */
|
||
|
- if (free_blocks < 2 * dirty_blocks)
|
||
|
- writeback_inodes_sb_if_idle(sb, WB_REASON_FS_FREE_SPACE);
|
||
|
-
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -4004,6 +4007,7 @@ static int ext4_do_update_inode(handle_t *handle,
|
||
|
struct ext4_inode_info *ei = EXT4_I(inode);
|
||
|
struct buffer_head *bh = iloc->bh;
|
||
|
int err = 0, rc, block;
|
||
|
+ int need_datasync = 0;
|
||
|
|
||
|
/* For fields not not tracking in the in-memory inode,
|
||
|
* initialise them to zero for new inodes. */
|
||
|
@@ -4052,7 +4056,10 @@ static int ext4_do_update_inode(handle_t *handle,
|
||
|
raw_inode->i_file_acl_high =
|
||
|
cpu_to_le16(ei->i_file_acl >> 32);
|
||
|
raw_inode->i_file_acl_lo = cpu_to_le32(ei->i_file_acl);
|
||
|
- ext4_isize_set(raw_inode, ei->i_disksize);
|
||
|
+ if (ei->i_disksize != ext4_isize(raw_inode)) {
|
||
|
+ ext4_isize_set(raw_inode, ei->i_disksize);
|
||
|
+ need_datasync = 1;
|
||
|
+ }
|
||
|
if (ei->i_disksize > 0x7fffffffULL) {
|
||
|
struct super_block *sb = inode->i_sb;
|
||
|
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||
|
@@ -4105,7 +4112,7 @@ static int ext4_do_update_inode(handle_t *handle,
|
||
|
err = rc;
|
||
|
ext4_clear_inode_state(inode, EXT4_STATE_NEW);
|
||
|
|
||
|
- ext4_update_inode_fsync_trans(handle, inode, 0);
|
||
|
+ ext4_update_inode_fsync_trans(handle, inode, need_datasync);
|
||
|
out_brelse:
|
||
|
brelse(bh);
|
||
|
ext4_std_error(inode->i_sb, err);
|
||
|
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
|
||
|
index c5826c6..e2016f3 100644
|
||
|
--- a/fs/ext4/move_extent.c
|
||
|
+++ b/fs/ext4/move_extent.c
|
||
|
@@ -141,55 +141,21 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path,
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
- * mext_check_null_inode - NULL check for two inodes
|
||
|
- *
|
||
|
- * If inode1 or inode2 is NULL, return -EIO. Otherwise, return 0.
|
||
|
- */
|
||
|
-static int
|
||
|
-mext_check_null_inode(struct inode *inode1, struct inode *inode2,
|
||
|
- const char *function, unsigned int line)
|
||
|
-{
|
||
|
- int ret = 0;
|
||
|
-
|
||
|
- if (inode1 == NULL) {
|
||
|
- __ext4_error(inode2->i_sb, function, line,
|
||
|
- "Both inodes should not be NULL: "
|
||
|
- "inode1 NULL inode2 %lu", inode2->i_ino);
|
||
|
- ret = -EIO;
|
||
|
- } else if (inode2 == NULL) {
|
||
|
- __ext4_error(inode1->i_sb, function, line,
|
||
|
- "Both inodes should not be NULL: "
|
||
|
- "inode1 %lu inode2 NULL", inode1->i_ino);
|
||
|
- ret = -EIO;
|
||
|
- }
|
||
|
- return ret;
|
||
|
-}
|
||
|
-
|
||
|
-/**
|
||
|
* double_down_write_data_sem - Acquire two inodes' write lock of i_data_sem
|
||
|
*
|
||
|
- * @orig_inode: original inode structure
|
||
|
- * @donor_inode: donor inode structure
|
||
|
- * Acquire write lock of i_data_sem of the two inodes (orig and donor) by
|
||
|
- * i_ino order.
|
||
|
+ * Acquire write lock of i_data_sem of the two inodes
|
||
|
*/
|
||
|
static void
|
||
|
-double_down_write_data_sem(struct inode *orig_inode, struct inode *donor_inode)
|
||
|
+double_down_write_data_sem(struct inode *first, struct inode *second)
|
||
|
{
|
||
|
- struct inode *first = orig_inode, *second = donor_inode;
|
||
|
+ if (first < second) {
|
||
|
+ down_write(&EXT4_I(first)->i_data_sem);
|
||
|
+ down_write_nested(&EXT4_I(second)->i_data_sem, SINGLE_DEPTH_NESTING);
|
||
|
+ } else {
|
||
|
+ down_write(&EXT4_I(second)->i_data_sem);
|
||
|
+ down_write_nested(&EXT4_I(first)->i_data_sem, SINGLE_DEPTH_NESTING);
|
||
|
|
||
|
- /*
|
||
|
- * Use the inode number to provide the stable locking order instead
|
||
|
- * of its address, because the C language doesn't guarantee you can
|
||
|
- * compare pointers that don't come from the same array.
|
||
|
- */
|
||
|
- if (donor_inode->i_ino < orig_inode->i_ino) {
|
||
|
- first = donor_inode;
|
||
|
- second = orig_inode;
|
||
|
}
|
||
|
-
|
||
|
- down_write(&EXT4_I(first)->i_data_sem);
|
||
|
- down_write_nested(&EXT4_I(second)->i_data_sem, SINGLE_DEPTH_NESTING);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -969,14 +935,6 @@ mext_check_arguments(struct inode *orig_inode,
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
- /* Files should be in the same ext4 FS */
|
||
|
- if (orig_inode->i_sb != donor_inode->i_sb) {
|
||
|
- ext4_debug("ext4 move extent: The argument files "
|
||
|
- "should be in same FS [ino:orig %lu, donor %lu]\n",
|
||
|
- orig_inode->i_ino, donor_inode->i_ino);
|
||
|
- return -EINVAL;
|
||
|
- }
|
||
|
-
|
||
|
/* Ext4 move extent supports only extent based file */
|
||
|
if (!(ext4_test_inode_flag(orig_inode, EXT4_INODE_EXTENTS))) {
|
||
|
ext4_debug("ext4 move extent: orig file is not extents "
|
||
|
@@ -1072,35 +1030,19 @@ mext_check_arguments(struct inode *orig_inode,
|
||
|
* @inode1: the inode structure
|
||
|
* @inode2: the inode structure
|
||
|
*
|
||
|
- * Lock two inodes' i_mutex by i_ino order.
|
||
|
- * If inode1 or inode2 is NULL, return -EIO. Otherwise, return 0.
|
||
|
+ * Lock two inodes' i_mutex
|
||
|
*/
|
||
|
-static int
|
||
|
+static void
|
||
|
mext_inode_double_lock(struct inode *inode1, struct inode *inode2)
|
||
|
{
|
||
|
- int ret = 0;
|
||
|
-
|
||
|
- BUG_ON(inode1 == NULL && inode2 == NULL);
|
||
|
-
|
||
|
- ret = mext_check_null_inode(inode1, inode2, __func__, __LINE__);
|
||
|
- if (ret < 0)
|
||
|
- goto out;
|
||
|
-
|
||
|
- if (inode1 == inode2) {
|
||
|
- mutex_lock(&inode1->i_mutex);
|
||
|
- goto out;
|
||
|
- }
|
||
|
-
|
||
|
- if (inode1->i_ino < inode2->i_ino) {
|
||
|
+ BUG_ON(inode1 == inode2);
|
||
|
+ if (inode1 < inode2) {
|
||
|
mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT);
|
||
|
mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD);
|
||
|
} else {
|
||
|
mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT);
|
||
|
mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD);
|
||
|
}
|
||
|
-
|
||
|
-out:
|
||
|
- return ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -1109,28 +1051,13 @@ out:
|
||
|
* @inode1: the inode that is released first
|
||
|
* @inode2: the inode that is released second
|
||
|
*
|
||
|
- * If inode1 or inode2 is NULL, return -EIO. Otherwise, return 0.
|
||
|
*/
|
||
|
|
||
|
-static int
|
||
|
+static void
|
||
|
mext_inode_double_unlock(struct inode *inode1, struct inode *inode2)
|
||
|
{
|
||
|
- int ret = 0;
|
||
|
-
|
||
|
- BUG_ON(inode1 == NULL && inode2 == NULL);
|
||
|
-
|
||
|
- ret = mext_check_null_inode(inode1, inode2, __func__, __LINE__);
|
||
|
- if (ret < 0)
|
||
|
- goto out;
|
||
|
-
|
||
|
- if (inode1)
|
||
|
- mutex_unlock(&inode1->i_mutex);
|
||
|
-
|
||
|
- if (inode2 && inode2 != inode1)
|
||
|
- mutex_unlock(&inode2->i_mutex);
|
||
|
-
|
||
|
-out:
|
||
|
- return ret;
|
||
|
+ mutex_unlock(&inode1->i_mutex);
|
||
|
+ mutex_unlock(&inode2->i_mutex);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -1187,16 +1114,23 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
|
||
|
ext4_lblk_t block_end, seq_start, add_blocks, file_end, seq_blocks = 0;
|
||
|
ext4_lblk_t rest_blocks;
|
||
|
pgoff_t orig_page_offset = 0, seq_end_page;
|
||
|
- int ret1, ret2, depth, last_extent = 0;
|
||
|
+ int ret, depth, last_extent = 0;
|
||
|
int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits;
|
||
|
int data_offset_in_page;
|
||
|
int block_len_in_page;
|
||
|
int uninit;
|
||
|
|
||
|
- /* orig and donor should be different file */
|
||
|
- if (orig_inode->i_ino == donor_inode->i_ino) {
|
||
|
+ if (orig_inode->i_sb != donor_inode->i_sb) {
|
||
|
+ ext4_debug("ext4 move extent: The argument files "
|
||
|
+ "should be in same FS [ino:orig %lu, donor %lu]\n",
|
||
|
+ orig_inode->i_ino, donor_inode->i_ino);
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* orig and donor should be different inodes */
|
||
|
+ if (orig_inode == donor_inode) {
|
||
|
ext4_debug("ext4 move extent: The argument files should not "
|
||
|
- "be same file [ino:orig %lu, donor %lu]\n",
|
||
|
+ "be same inode [ino:orig %lu, donor %lu]\n",
|
||
|
orig_inode->i_ino, donor_inode->i_ino);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
@@ -1208,18 +1142,21 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
|
||
|
orig_inode->i_ino, donor_inode->i_ino);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
-
|
||
|
+ /* TODO: This is non obvious task to swap blocks for inodes with full
|
||
|
+ jornaling enabled */
|
||
|
+ if (ext4_should_journal_data(orig_inode) ||
|
||
|
+ ext4_should_journal_data(donor_inode)) {
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
/* Protect orig and donor inodes against a truncate */
|
||
|
- ret1 = mext_inode_double_lock(orig_inode, donor_inode);
|
||
|
- if (ret1 < 0)
|
||
|
- return ret1;
|
||
|
+ mext_inode_double_lock(orig_inode, donor_inode);
|
||
|
|
||
|
/* Protect extent tree against block allocations via delalloc */
|
||
|
double_down_write_data_sem(orig_inode, donor_inode);
|
||
|
/* Check the filesystem environment whether move_extent can be done */
|
||
|
- ret1 = mext_check_arguments(orig_inode, donor_inode, orig_start,
|
||
|
+ ret = mext_check_arguments(orig_inode, donor_inode, orig_start,
|
||
|
donor_start, &len);
|
||
|
- if (ret1)
|
||
|
+ if (ret)
|
||
|
goto out;
|
||
|
|
||
|
file_end = (i_size_read(orig_inode) - 1) >> orig_inode->i_blkbits;
|
||
|
@@ -1227,13 +1164,13 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
|
||
|
if (file_end < block_end)
|
||
|
len -= block_end - file_end;
|
||
|
|
||
|
- ret1 = get_ext_path(orig_inode, block_start, &orig_path);
|
||
|
- if (ret1)
|
||
|
+ ret = get_ext_path(orig_inode, block_start, &orig_path);
|
||
|
+ if (ret)
|
||
|
goto out;
|
||
|
|
||
|
/* Get path structure to check the hole */
|
||
|
- ret1 = get_ext_path(orig_inode, block_start, &holecheck_path);
|
||
|
- if (ret1)
|
||
|
+ ret = get_ext_path(orig_inode, block_start, &holecheck_path);
|
||
|
+ if (ret)
|
||
|
goto out;
|
||
|
|
||
|
depth = ext_depth(orig_inode);
|
||
|
@@ -1252,13 +1189,13 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
|
||
|
last_extent = mext_next_extent(orig_inode,
|
||
|
holecheck_path, &ext_cur);
|
||
|
if (last_extent < 0) {
|
||
|
- ret1 = last_extent;
|
||
|
+ ret = last_extent;
|
||
|
goto out;
|
||
|
}
|
||
|
last_extent = mext_next_extent(orig_inode, orig_path,
|
||
|
&ext_dummy);
|
||
|
if (last_extent < 0) {
|
||
|
- ret1 = last_extent;
|
||
|
+ ret = last_extent;
|
||
|
goto out;
|
||
|
}
|
||
|
seq_start = le32_to_cpu(ext_cur->ee_block);
|
||
|
@@ -1272,7 +1209,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
|
||
|
if (le32_to_cpu(ext_cur->ee_block) > block_end) {
|
||
|
ext4_debug("ext4 move extent: The specified range of file "
|
||
|
"may be the hole\n");
|
||
|
- ret1 = -EINVAL;
|
||
|
+ ret = -EINVAL;
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
@@ -1292,7 +1229,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
|
||
|
last_extent = mext_next_extent(orig_inode, holecheck_path,
|
||
|
&ext_cur);
|
||
|
if (last_extent < 0) {
|
||
|
- ret1 = last_extent;
|
||
|
+ ret = last_extent;
|
||
|
break;
|
||
|
}
|
||
|
add_blocks = ext4_ext_get_actual_len(ext_cur);
|
||
|
@@ -1349,18 +1286,18 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
|
||
|
orig_page_offset,
|
||
|
data_offset_in_page,
|
||
|
block_len_in_page, uninit,
|
||
|
- &ret1);
|
||
|
+ &ret);
|
||
|
|
||
|
/* Count how many blocks we have exchanged */
|
||
|
*moved_len += block_len_in_page;
|
||
|
- if (ret1 < 0)
|
||
|
+ if (ret < 0)
|
||
|
break;
|
||
|
if (*moved_len > len) {
|
||
|
EXT4_ERROR_INODE(orig_inode,
|
||
|
"We replaced blocks too much! "
|
||
|
"sum of replaced: %llu requested: %llu",
|
||
|
*moved_len, len);
|
||
|
- ret1 = -EIO;
|
||
|
+ ret = -EIO;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
@@ -1374,22 +1311,22 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
|
||
|
}
|
||
|
|
||
|
double_down_write_data_sem(orig_inode, donor_inode);
|
||
|
- if (ret1 < 0)
|
||
|
+ if (ret < 0)
|
||
|
break;
|
||
|
|
||
|
/* Decrease buffer counter */
|
||
|
if (holecheck_path)
|
||
|
ext4_ext_drop_refs(holecheck_path);
|
||
|
- ret1 = get_ext_path(orig_inode, seq_start, &holecheck_path);
|
||
|
- if (ret1)
|
||
|
+ ret = get_ext_path(orig_inode, seq_start, &holecheck_path);
|
||
|
+ if (ret)
|
||
|
break;
|
||
|
depth = holecheck_path->p_depth;
|
||
|
|
||
|
/* Decrease buffer counter */
|
||
|
if (orig_path)
|
||
|
ext4_ext_drop_refs(orig_path);
|
||
|
- ret1 = get_ext_path(orig_inode, seq_start, &orig_path);
|
||
|
- if (ret1)
|
||
|
+ ret = get_ext_path(orig_inode, seq_start, &orig_path);
|
||
|
+ if (ret)
|
||
|
break;
|
||
|
|
||
|
ext_cur = holecheck_path[depth].p_ext;
|
||
|
@@ -1412,12 +1349,7 @@ out:
|
||
|
kfree(holecheck_path);
|
||
|
}
|
||
|
double_up_write_data_sem(orig_inode, donor_inode);
|
||
|
- ret2 = mext_inode_double_unlock(orig_inode, donor_inode);
|
||
|
-
|
||
|
- if (ret1)
|
||
|
- return ret1;
|
||
|
- else if (ret2)
|
||
|
- return ret2;
|
||
|
+ mext_inode_double_unlock(orig_inode, donor_inode);
|
||
|
|
||
|
- return 0;
|
||
|
+ return ret;
|
||
|
}
|
||
|
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
|
||
|
index 4dd0890..88f97e5 100644
|
||
|
--- a/fs/ext4/namei.c
|
||
|
+++ b/fs/ext4/namei.c
|
||
|
@@ -1801,9 +1801,7 @@ retry:
|
||
|
err = PTR_ERR(inode);
|
||
|
if (!IS_ERR(inode)) {
|
||
|
init_special_inode(inode, inode->i_mode, rdev);
|
||
|
-#ifdef CONFIG_EXT4_FS_XATTR
|
||
|
inode->i_op = &ext4_special_inode_operations;
|
||
|
-#endif
|
||
|
err = ext4_add_nondir(handle, dentry, inode);
|
||
|
}
|
||
|
ext4_journal_stop(handle);
|
||
|
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
|
||
|
index 54f5786..13bfa07 100644
|
||
|
--- a/fs/fs-writeback.c
|
||
|
+++ b/fs/fs-writeback.c
|
||
|
@@ -63,6 +63,7 @@ int writeback_in_progress(struct backing_dev_info *bdi)
|
||
|
{
|
||
|
return test_bit(BDI_writeback_running, &bdi->state);
|
||
|
}
|
||
|
+EXPORT_SYMBOL(writeback_in_progress);
|
||
|
|
||
|
static inline struct backing_dev_info *inode_to_bdi(struct inode *inode)
|
||
|
{
|
||
|
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
|
||
|
index b09e51d..464cd76 100644
|
||
|
--- a/fs/jffs2/wbuf.c
|
||
|
+++ b/fs/jffs2/wbuf.c
|
||
|
@@ -1032,11 +1032,11 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c,
|
||
|
ops.datbuf = NULL;
|
||
|
|
||
|
ret = c->mtd->read_oob(c->mtd, jeb->offset, &ops);
|
||
|
- if (ret || ops.oobretlen != ops.ooblen) {
|
||
|
+ if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) {
|
||
|
printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"
|
||
|
" bytes, read %zd bytes, error %d\n",
|
||
|
jeb->offset, ops.ooblen, ops.oobretlen, ret);
|
||
|
- if (!ret)
|
||
|
+ if (!ret || mtd_is_bitflip(ret))
|
||
|
ret = -EIO;
|
||
|
return ret;
|
||
|
}
|
||
|
@@ -1075,11 +1075,11 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c,
|
||
|
ops.datbuf = NULL;
|
||
|
|
||
|
ret = c->mtd->read_oob(c->mtd, jeb->offset, &ops);
|
||
|
- if (ret || ops.oobretlen != ops.ooblen) {
|
||
|
+ if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) {
|
||
|
printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"
|
||
|
" bytes, read %zd bytes, error %d\n",
|
||
|
jeb->offset, ops.ooblen, ops.oobretlen, ret);
|
||
|
- if (!ret)
|
||
|
+ if (!ret || mtd_is_bitflip(ret))
|
||
|
ret = -EIO;
|
||
|
return ret;
|
||
|
}
|
||
|
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
|
||
|
index 23d7451..df753a1 100644
|
||
|
--- a/fs/lockd/mon.c
|
||
|
+++ b/fs/lockd/mon.c
|
||
|
@@ -40,6 +40,7 @@ struct nsm_args {
|
||
|
u32 proc;
|
||
|
|
||
|
char *mon_name;
|
||
|
+ char *nodename;
|
||
|
};
|
||
|
|
||
|
struct nsm_res {
|
||
|
@@ -93,6 +94,7 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
|
||
|
.vers = 3,
|
||
|
.proc = NLMPROC_NSM_NOTIFY,
|
||
|
.mon_name = nsm->sm_mon_name,
|
||
|
+ .nodename = utsname()->nodename,
|
||
|
};
|
||
|
struct rpc_message msg = {
|
||
|
.rpc_argp = &args,
|
||
|
@@ -429,7 +431,7 @@ static void encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp)
|
||
|
{
|
||
|
__be32 *p;
|
||
|
|
||
|
- encode_nsm_string(xdr, utsname()->nodename);
|
||
|
+ encode_nsm_string(xdr, argp->nodename);
|
||
|
p = xdr_reserve_space(xdr, 4 + 4 + 4);
|
||
|
*p++ = cpu_to_be32(argp->prog);
|
||
|
*p++ = cpu_to_be32(argp->vers);
|
||
|
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
|
||
|
index d774309..1aaa0ee 100644
|
||
|
--- a/fs/nfs/blocklayout/blocklayout.c
|
||
|
+++ b/fs/nfs/blocklayout/blocklayout.c
|
||
|
@@ -164,25 +164,39 @@ static struct bio *bl_alloc_init_bio(int npg, sector_t isect,
|
||
|
return bio;
|
||
|
}
|
||
|
|
||
|
-static struct bio *bl_add_page_to_bio(struct bio *bio, int npg, int rw,
|
||
|
+static struct bio *do_add_page_to_bio(struct bio *bio, int npg, int rw,
|
||
|
sector_t isect, struct page *page,
|
||
|
struct pnfs_block_extent *be,
|
||
|
void (*end_io)(struct bio *, int err),
|
||
|
- struct parallel_io *par)
|
||
|
+ struct parallel_io *par,
|
||
|
+ unsigned int offset, int len)
|
||
|
{
|
||
|
+ isect = isect + (offset >> SECTOR_SHIFT);
|
||
|
+ dprintk("%s: npg %d rw %d isect %llu offset %u len %d\n", __func__,
|
||
|
+ npg, rw, (unsigned long long)isect, offset, len);
|
||
|
retry:
|
||
|
if (!bio) {
|
||
|
bio = bl_alloc_init_bio(npg, isect, be, end_io, par);
|
||
|
if (!bio)
|
||
|
return ERR_PTR(-ENOMEM);
|
||
|
}
|
||
|
- if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) {
|
||
|
+ if (bio_add_page(bio, page, len, offset) < len) {
|
||
|
bio = bl_submit_bio(rw, bio);
|
||
|
goto retry;
|
||
|
}
|
||
|
return bio;
|
||
|
}
|
||
|
|
||
|
+static struct bio *bl_add_page_to_bio(struct bio *bio, int npg, int rw,
|
||
|
+ sector_t isect, struct page *page,
|
||
|
+ struct pnfs_block_extent *be,
|
||
|
+ void (*end_io)(struct bio *, int err),
|
||
|
+ struct parallel_io *par)
|
||
|
+{
|
||
|
+ return do_add_page_to_bio(bio, npg, rw, isect, page, be,
|
||
|
+ end_io, par, 0, PAGE_CACHE_SIZE);
|
||
|
+}
|
||
|
+
|
||
|
/* This is basically copied from mpage_end_io_read */
|
||
|
static void bl_end_io_read(struct bio *bio, int err)
|
||
|
{
|
||
|
@@ -446,6 +460,106 @@ map_block(struct buffer_head *bh, sector_t isect, struct pnfs_block_extent *be)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
+static void
|
||
|
+bl_read_single_end_io(struct bio *bio, int error)
|
||
|
+{
|
||
|
+ struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
|
||
|
+ struct page *page = bvec->bv_page;
|
||
|
+
|
||
|
+ /* Only one page in bvec */
|
||
|
+ unlock_page(page);
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+bl_do_readpage_sync(struct page *page, struct pnfs_block_extent *be,
|
||
|
+ unsigned int offset, unsigned int len)
|
||
|
+{
|
||
|
+ struct bio *bio;
|
||
|
+ struct page *shadow_page;
|
||
|
+ sector_t isect;
|
||
|
+ char *kaddr, *kshadow_addr;
|
||
|
+ int ret = 0;
|
||
|
+
|
||
|
+ dprintk("%s: offset %u len %u\n", __func__, offset, len);
|
||
|
+
|
||
|
+ shadow_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
|
||
|
+ if (shadow_page == NULL)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
+ bio = bio_alloc(GFP_NOIO, 1);
|
||
|
+ if (bio == NULL)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
+ isect = (page->index << PAGE_CACHE_SECTOR_SHIFT) +
|
||
|
+ (offset / SECTOR_SIZE);
|
||
|
+
|
||
|
+ bio->bi_sector = isect - be->be_f_offset + be->be_v_offset;
|
||
|
+ bio->bi_bdev = be->be_mdev;
|
||
|
+ bio->bi_end_io = bl_read_single_end_io;
|
||
|
+
|
||
|
+ lock_page(shadow_page);
|
||
|
+ if (bio_add_page(bio, shadow_page,
|
||
|
+ SECTOR_SIZE, round_down(offset, SECTOR_SIZE)) == 0) {
|
||
|
+ unlock_page(shadow_page);
|
||
|
+ bio_put(bio);
|
||
|
+ return -EIO;
|
||
|
+ }
|
||
|
+
|
||
|
+ submit_bio(READ, bio);
|
||
|
+ wait_on_page_locked(shadow_page);
|
||
|
+ if (unlikely(!test_bit(BIO_UPTODATE, &bio->bi_flags))) {
|
||
|
+ ret = -EIO;
|
||
|
+ } else {
|
||
|
+ kaddr = kmap_atomic(page);
|
||
|
+ kshadow_addr = kmap_atomic(shadow_page);
|
||
|
+ memcpy(kaddr + offset, kshadow_addr + offset, len);
|
||
|
+ kunmap_atomic(kshadow_addr);
|
||
|
+ kunmap_atomic(kaddr);
|
||
|
+ }
|
||
|
+ __free_page(shadow_page);
|
||
|
+ bio_put(bio);
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+bl_read_partial_page_sync(struct page *page, struct pnfs_block_extent *be,
|
||
|
+ unsigned int dirty_offset, unsigned int dirty_len,
|
||
|
+ bool full_page)
|
||
|
+{
|
||
|
+ int ret = 0;
|
||
|
+ unsigned int start, end;
|
||
|
+
|
||
|
+ if (full_page) {
|
||
|
+ start = 0;
|
||
|
+ end = PAGE_CACHE_SIZE;
|
||
|
+ } else {
|
||
|
+ start = round_down(dirty_offset, SECTOR_SIZE);
|
||
|
+ end = round_up(dirty_offset + dirty_len, SECTOR_SIZE);
|
||
|
+ }
|
||
|
+
|
||
|
+ dprintk("%s: offset %u len %d\n", __func__, dirty_offset, dirty_len);
|
||
|
+ if (!be) {
|
||
|
+ zero_user_segments(page, start, dirty_offset,
|
||
|
+ dirty_offset + dirty_len, end);
|
||
|
+ if (start == 0 && end == PAGE_CACHE_SIZE &&
|
||
|
+ trylock_page(page)) {
|
||
|
+ SetPageUptodate(page);
|
||
|
+ unlock_page(page);
|
||
|
+ }
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (start != dirty_offset)
|
||
|
+ ret = bl_do_readpage_sync(page, be, start, dirty_offset - start);
|
||
|
+
|
||
|
+ if (!ret && (dirty_offset + dirty_len < end))
|
||
|
+ ret = bl_do_readpage_sync(page, be, dirty_offset + dirty_len,
|
||
|
+ end - dirty_offset - dirty_len);
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
/* Given an unmapped page, zero it or read in page for COW, page is locked
|
||
|
* by caller.
|
||
|
*/
|
||
|
@@ -479,7 +593,6 @@ init_page_for_write(struct page *page, struct pnfs_block_extent *cow_read)
|
||
|
SetPageUptodate(page);
|
||
|
|
||
|
cleanup:
|
||
|
- bl_put_extent(cow_read);
|
||
|
if (bh)
|
||
|
free_buffer_head(bh);
|
||
|
if (ret) {
|
||
|
@@ -501,6 +614,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
|
||
|
struct parallel_io *par;
|
||
|
loff_t offset = wdata->args.offset;
|
||
|
size_t count = wdata->args.count;
|
||
|
+ unsigned int pg_offset, pg_len, saved_len;
|
||
|
struct page **pages = wdata->args.pages;
|
||
|
struct page *page;
|
||
|
pgoff_t index;
|
||
|
@@ -615,10 +729,11 @@ next_page:
|
||
|
if (!extent_length) {
|
||
|
/* We've used up the previous extent */
|
||
|
bl_put_extent(be);
|
||
|
+ bl_put_extent(cow_read);
|
||
|
bio = bl_submit_bio(WRITE, bio);
|
||
|
/* Get the next one */
|
||
|
be = bl_find_get_extent(BLK_LSEG2EXT(wdata->lseg),
|
||
|
- isect, NULL);
|
||
|
+ isect, &cow_read);
|
||
|
if (!be || !is_writable(be, isect)) {
|
||
|
wdata->pnfs_error = -EINVAL;
|
||
|
goto out;
|
||
|
@@ -626,7 +741,26 @@ next_page:
|
||
|
extent_length = be->be_length -
|
||
|
(isect - be->be_f_offset);
|
||
|
}
|
||
|
- if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
|
||
|
+
|
||
|
+ dprintk("%s offset %lld count %Zu\n", __func__, offset, count);
|
||
|
+ pg_offset = offset & ~PAGE_CACHE_MASK;
|
||
|
+ if (pg_offset + count > PAGE_CACHE_SIZE)
|
||
|
+ pg_len = PAGE_CACHE_SIZE - pg_offset;
|
||
|
+ else
|
||
|
+ pg_len = count;
|
||
|
+
|
||
|
+ saved_len = pg_len;
|
||
|
+ if (be->be_state == PNFS_BLOCK_INVALID_DATA &&
|
||
|
+ !bl_is_sector_init(be->be_inval, isect)) {
|
||
|
+ ret = bl_read_partial_page_sync(pages[i], cow_read,
|
||
|
+ pg_offset, pg_len, true);
|
||
|
+ if (ret) {
|
||
|
+ dprintk("%s bl_read_partial_page_sync fail %d\n",
|
||
|
+ __func__, ret);
|
||
|
+ wdata->pnfs_error = ret;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
ret = bl_mark_sectors_init(be->be_inval, isect,
|
||
|
PAGE_CACHE_SECTORS,
|
||
|
NULL);
|
||
|
@@ -636,15 +770,35 @@ next_page:
|
||
|
wdata->pnfs_error = ret;
|
||
|
goto out;
|
||
|
}
|
||
|
+
|
||
|
+ /* Expand to full page write */
|
||
|
+ pg_offset = 0;
|
||
|
+ pg_len = PAGE_CACHE_SIZE;
|
||
|
+ } else if ((pg_offset & (SECTOR_SIZE - 1)) ||
|
||
|
+ (pg_len & (SECTOR_SIZE - 1))){
|
||
|
+ /* ahh, nasty case. We have to do sync full sector
|
||
|
+ * read-modify-write cycles.
|
||
|
+ */
|
||
|
+ unsigned int saved_offset = pg_offset;
|
||
|
+ ret = bl_read_partial_page_sync(pages[i], be, pg_offset,
|
||
|
+ pg_len, false);
|
||
|
+ pg_offset = round_down(pg_offset, SECTOR_SIZE);
|
||
|
+ pg_len = round_up(saved_offset + pg_len, SECTOR_SIZE)
|
||
|
+ - pg_offset;
|
||
|
}
|
||
|
- bio = bl_add_page_to_bio(bio, wdata->npages - i, WRITE,
|
||
|
+
|
||
|
+
|
||
|
+ bio = do_add_page_to_bio(bio, wdata->npages - i, WRITE,
|
||
|
isect, pages[i], be,
|
||
|
- bl_end_io_write, par);
|
||
|
+ bl_end_io_write, par,
|
||
|
+ pg_offset, pg_len);
|
||
|
if (IS_ERR(bio)) {
|
||
|
wdata->pnfs_error = PTR_ERR(bio);
|
||
|
bio = NULL;
|
||
|
goto out;
|
||
|
}
|
||
|
+ offset += saved_len;
|
||
|
+ count -= saved_len;
|
||
|
isect += PAGE_CACHE_SECTORS;
|
||
|
last_isect = isect;
|
||
|
extent_length -= PAGE_CACHE_SECTORS;
|
||
|
@@ -662,12 +816,10 @@ next_page:
|
||
|
}
|
||
|
|
||
|
write_done:
|
||
|
- wdata->res.count = (last_isect << SECTOR_SHIFT) - (offset);
|
||
|
- if (count < wdata->res.count) {
|
||
|
- wdata->res.count = count;
|
||
|
- }
|
||
|
+ wdata->res.count = wdata->args.count;
|
||
|
out:
|
||
|
bl_put_extent(be);
|
||
|
+ bl_put_extent(cow_read);
|
||
|
bl_submit_bio(WRITE, bio);
|
||
|
put_parallel(par);
|
||
|
return PNFS_ATTEMPTED;
|
||
|
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h
|
||
|
index 42acf7e..519a9de 100644
|
||
|
--- a/fs/nfs/blocklayout/blocklayout.h
|
||
|
+++ b/fs/nfs/blocklayout/blocklayout.h
|
||
|
@@ -40,6 +40,7 @@
|
||
|
|
||
|
#define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT)
|
||
|
#define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT)
|
||
|
+#define SECTOR_SIZE (1 << SECTOR_SHIFT)
|
||
|
|
||
|
struct block_mount_id {
|
||
|
spinlock_t bm_lock; /* protects list */
|
||
|
diff --git a/fs/udf/super.c b/fs/udf/super.c
|
||
|
index 516b7f0..f66439e 100644
|
||
|
--- a/fs/udf/super.c
|
||
|
+++ b/fs/udf/super.c
|
||
|
@@ -1289,6 +1289,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
|
||
|
udf_err(sb, "error loading logical volume descriptor: "
|
||
|
"Partition table too long (%u > %lu)\n", table_len,
|
||
|
sb->s_blocksize - sizeof(*lvd));
|
||
|
+ ret = 1;
|
||
|
goto out_bh;
|
||
|
}
|
||
|
|
||
|
@@ -1333,8 +1334,10 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
|
||
|
UDF_ID_SPARABLE,
|
||
|
strlen(UDF_ID_SPARABLE))) {
|
||
|
if (udf_load_sparable_map(sb, map,
|
||
|
- (struct sparablePartitionMap *)gpm) < 0)
|
||
|
+ (struct sparablePartitionMap *)gpm) < 0) {
|
||
|
+ ret = 1;
|
||
|
goto out_bh;
|
||
|
+ }
|
||
|
} else if (!strncmp(upm2->partIdent.ident,
|
||
|
UDF_ID_METADATA,
|
||
|
strlen(UDF_ID_METADATA))) {
|
||
|
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
|
||
|
index 7978eec..3e8f2f7 100644
|
||
|
--- a/include/linux/mempolicy.h
|
||
|
+++ b/include/linux/mempolicy.h
|
||
|
@@ -188,7 +188,7 @@ struct sp_node {
|
||
|
|
||
|
struct shared_policy {
|
||
|
struct rb_root root;
|
||
|
- spinlock_t lock;
|
||
|
+ struct mutex mutex;
|
||
|
};
|
||
|
|
||
|
void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol);
|
||
|
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
|
||
|
index 67cc215..1874c5e 100644
|
||
|
--- a/include/linux/pci_ids.h
|
||
|
+++ b/include/linux/pci_ids.h
|
||
|
@@ -1823,7 +1823,6 @@
|
||
|
#define PCI_DEVICE_ID_SIIG_8S_20x_650 0x2081
|
||
|
#define PCI_DEVICE_ID_SIIG_8S_20x_850 0x2082
|
||
|
#define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050
|
||
|
-#define PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL 0x2530
|
||
|
|
||
|
#define PCI_VENDOR_ID_RADISYS 0x1331
|
||
|
|
||
|
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
|
||
|
index e5a7b9a..416dcb0 100644
|
||
|
--- a/include/net/ip_vs.h
|
||
|
+++ b/include/net/ip_vs.h
|
||
|
@@ -1353,7 +1353,7 @@ static inline void ip_vs_notrack(struct sk_buff *skb)
|
||
|
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
|
||
|
|
||
|
if (!ct || !nf_ct_is_untracked(ct)) {
|
||
|
- nf_reset(skb);
|
||
|
+ nf_conntrack_put(skb->nfct);
|
||
|
skb->nfct = &nf_ct_untracked_get()->ct_general;
|
||
|
skb->nfctinfo = IP_CT_NEW;
|
||
|
nf_conntrack_get(skb->nfct);
|
||
|
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
|
||
|
index 6b76d81..a122196 100644
|
||
|
--- a/kernel/rcutree.c
|
||
|
+++ b/kernel/rcutree.c
|
||
|
@@ -292,7 +292,9 @@ cpu_has_callbacks_ready_to_invoke(struct rcu_data *rdp)
|
||
|
static int
|
||
|
cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
|
||
|
{
|
||
|
- return *rdp->nxttail[RCU_DONE_TAIL] && !rcu_gp_in_progress(rsp);
|
||
|
+ return *rdp->nxttail[RCU_DONE_TAIL +
|
||
|
+ ACCESS_ONCE(rsp->completed) != rdp->completed] &&
|
||
|
+ !rcu_gp_in_progress(rsp);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
diff --git a/kernel/sched_stoptask.c b/kernel/sched_stoptask.c
|
||
|
index 8b44e7f..85e9da2 100644
|
||
|
--- a/kernel/sched_stoptask.c
|
||
|
+++ b/kernel/sched_stoptask.c
|
||
|
@@ -25,8 +25,10 @@ static struct task_struct *pick_next_task_stop(struct rq *rq)
|
||
|
{
|
||
|
struct task_struct *stop = rq->stop;
|
||
|
|
||
|
- if (stop && stop->on_rq)
|
||
|
+ if (stop && stop->on_rq) {
|
||
|
+ stop->se.exec_start = rq->clock_task;
|
||
|
return stop;
|
||
|
+ }
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
@@ -50,6 +52,21 @@ static void yield_task_stop(struct rq *rq)
|
||
|
|
||
|
static void put_prev_task_stop(struct rq *rq, struct task_struct *prev)
|
||
|
{
|
||
|
+ struct task_struct *curr = rq->curr;
|
||
|
+ u64 delta_exec;
|
||
|
+
|
||
|
+ delta_exec = rq->clock_task - curr->se.exec_start;
|
||
|
+ if (unlikely((s64)delta_exec < 0))
|
||
|
+ delta_exec = 0;
|
||
|
+
|
||
|
+ schedstat_set(curr->se.statistics.exec_max,
|
||
|
+ max(curr->se.statistics.exec_max, delta_exec));
|
||
|
+
|
||
|
+ curr->se.sum_exec_runtime += delta_exec;
|
||
|
+ account_group_exec_runtime(curr, delta_exec);
|
||
|
+
|
||
|
+ curr->se.exec_start = rq->clock_task;
|
||
|
+ cpuacct_charge(curr, delta_exec);
|
||
|
}
|
||
|
|
||
|
static void task_tick_stop(struct rq *rq, struct task_struct *curr, int queued)
|
||
|
@@ -58,6 +75,9 @@ static void task_tick_stop(struct rq *rq, struct task_struct *curr, int queued)
|
||
|
|
||
|
static void set_curr_task_stop(struct rq *rq)
|
||
|
{
|
||
|
+ struct task_struct *stop = rq->stop;
|
||
|
+
|
||
|
+ stop->se.exec_start = rq->clock_task;
|
||
|
}
|
||
|
|
||
|
static void switched_to_stop(struct rq *rq, struct task_struct *p)
|
||
|
diff --git a/kernel/sys.c b/kernel/sys.c
|
||
|
index 481611f..c504302 100644
|
||
|
--- a/kernel/sys.c
|
||
|
+++ b/kernel/sys.c
|
||
|
@@ -365,6 +365,7 @@ EXPORT_SYMBOL(unregister_reboot_notifier);
|
||
|
void kernel_restart(char *cmd)
|
||
|
{
|
||
|
kernel_restart_prepare(cmd);
|
||
|
+ disable_nonboot_cpus();
|
||
|
if (!cmd)
|
||
|
printk(KERN_EMERG "Restarting system.\n");
|
||
|
else
|
||
|
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
|
||
|
index b413138..43a19c5 100644
|
||
|
--- a/kernel/workqueue.c
|
||
|
+++ b/kernel/workqueue.c
|
||
|
@@ -1726,10 +1726,9 @@ static void move_linked_works(struct work_struct *work, struct list_head *head,
|
||
|
*nextp = n;
|
||
|
}
|
||
|
|
||
|
-static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq)
|
||
|
+static void cwq_activate_delayed_work(struct work_struct *work)
|
||
|
{
|
||
|
- struct work_struct *work = list_first_entry(&cwq->delayed_works,
|
||
|
- struct work_struct, entry);
|
||
|
+ struct cpu_workqueue_struct *cwq = get_work_cwq(work);
|
||
|
struct list_head *pos = gcwq_determine_ins_pos(cwq->gcwq, cwq);
|
||
|
|
||
|
trace_workqueue_activate_work(work);
|
||
|
@@ -1738,6 +1737,14 @@ static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq)
|
||
|
cwq->nr_active++;
|
||
|
}
|
||
|
|
||
|
+static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq)
|
||
|
+{
|
||
|
+ struct work_struct *work = list_first_entry(&cwq->delayed_works,
|
||
|
+ struct work_struct, entry);
|
||
|
+
|
||
|
+ cwq_activate_delayed_work(work);
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* cwq_dec_nr_in_flight - decrement cwq's nr_in_flight
|
||
|
* @cwq: cwq of interest
|
||
|
@@ -1869,7 +1876,9 @@ __acquires(&gcwq->lock)
|
||
|
|
||
|
spin_unlock_irq(&gcwq->lock);
|
||
|
|
||
|
+ smp_wmb(); /* paired with test_and_set_bit(PENDING) */
|
||
|
work_clear_pending(work);
|
||
|
+
|
||
|
lock_map_acquire_read(&cwq->wq->lockdep_map);
|
||
|
lock_map_acquire(&lockdep_map);
|
||
|
trace_workqueue_execute_start(work);
|
||
|
@@ -2626,6 +2635,18 @@ static int try_to_grab_pending(struct work_struct *work)
|
||
|
smp_rmb();
|
||
|
if (gcwq == get_work_gcwq(work)) {
|
||
|
debug_work_deactivate(work);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * A delayed work item cannot be grabbed directly
|
||
|
+ * because it might have linked NO_COLOR work items
|
||
|
+ * which, if left on the delayed_list, will confuse
|
||
|
+ * cwq->nr_active management later on and cause
|
||
|
+ * stall. Make sure the work item is activated
|
||
|
+ * before grabbing.
|
||
|
+ */
|
||
|
+ if (*work_data_bits(work) & WORK_STRUCT_DELAYED)
|
||
|
+ cwq_activate_delayed_work(work);
|
||
|
+
|
||
|
list_del_init(&work->entry);
|
||
|
cwq_dec_nr_in_flight(get_work_cwq(work),
|
||
|
get_work_color(work),
|
||
|
diff --git a/lib/gcd.c b/lib/gcd.c
|
||
|
index f879033..433d89b 100644
|
||
|
--- a/lib/gcd.c
|
||
|
+++ b/lib/gcd.c
|
||
|
@@ -9,6 +9,9 @@ unsigned long gcd(unsigned long a, unsigned long b)
|
||
|
|
||
|
if (a < b)
|
||
|
swap(a, b);
|
||
|
+
|
||
|
+ if (!b)
|
||
|
+ return a;
|
||
|
while ((r = a % b) != 0) {
|
||
|
a = b;
|
||
|
b = r;
|
||
|
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
|
||
|
index 0f897b8..d6c0fdf 100644
|
||
|
--- a/mm/hugetlb.c
|
||
|
+++ b/mm/hugetlb.c
|
||
|
@@ -2429,8 +2429,8 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
|
||
|
* from page cache lookup which is in HPAGE_SIZE units.
|
||
|
*/
|
||
|
address = address & huge_page_mask(h);
|
||
|
- pgoff = ((address - vma->vm_start) >> PAGE_SHIFT)
|
||
|
- + (vma->vm_pgoff >> PAGE_SHIFT);
|
||
|
+ pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) +
|
||
|
+ vma->vm_pgoff;
|
||
|
mapping = vma->vm_file->f_dentry->d_inode->i_mapping;
|
||
|
|
||
|
/*
|
||
|
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
|
||
|
index 11b8d47..4c82c21 100644
|
||
|
--- a/mm/mempolicy.c
|
||
|
+++ b/mm/mempolicy.c
|
||
|
@@ -607,24 +607,39 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end,
|
||
|
return first;
|
||
|
}
|
||
|
|
||
|
-/* Apply policy to a single VMA */
|
||
|
-static int policy_vma(struct vm_area_struct *vma, struct mempolicy *new)
|
||
|
+/*
|
||
|
+ * Apply policy to a single VMA
|
||
|
+ * This must be called with the mmap_sem held for writing.
|
||
|
+ */
|
||
|
+static int vma_replace_policy(struct vm_area_struct *vma,
|
||
|
+ struct mempolicy *pol)
|
||
|
{
|
||
|
- int err = 0;
|
||
|
- struct mempolicy *old = vma->vm_policy;
|
||
|
+ int err;
|
||
|
+ struct mempolicy *old;
|
||
|
+ struct mempolicy *new;
|
||
|
|
||
|
pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n",
|
||
|
vma->vm_start, vma->vm_end, vma->vm_pgoff,
|
||
|
vma->vm_ops, vma->vm_file,
|
||
|
vma->vm_ops ? vma->vm_ops->set_policy : NULL);
|
||
|
|
||
|
- if (vma->vm_ops && vma->vm_ops->set_policy)
|
||
|
+ new = mpol_dup(pol);
|
||
|
+ if (IS_ERR(new))
|
||
|
+ return PTR_ERR(new);
|
||
|
+
|
||
|
+ if (vma->vm_ops && vma->vm_ops->set_policy) {
|
||
|
err = vma->vm_ops->set_policy(vma, new);
|
||
|
- if (!err) {
|
||
|
- mpol_get(new);
|
||
|
- vma->vm_policy = new;
|
||
|
- mpol_put(old);
|
||
|
+ if (err)
|
||
|
+ goto err_out;
|
||
|
}
|
||
|
+
|
||
|
+ old = vma->vm_policy;
|
||
|
+ vma->vm_policy = new; /* protected by mmap_sem */
|
||
|
+ mpol_put(old);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+ err_out:
|
||
|
+ mpol_put(new);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
@@ -675,7 +690,7 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
|
||
|
if (err)
|
||
|
goto out;
|
||
|
}
|
||
|
- err = policy_vma(vma, new_pol);
|
||
|
+ err = vma_replace_policy(vma, new_pol);
|
||
|
if (err)
|
||
|
goto out;
|
||
|
}
|
||
|
@@ -1507,8 +1522,18 @@ struct mempolicy *get_vma_policy(struct task_struct *task,
|
||
|
addr);
|
||
|
if (vpol)
|
||
|
pol = vpol;
|
||
|
- } else if (vma->vm_policy)
|
||
|
+ } else if (vma->vm_policy) {
|
||
|
pol = vma->vm_policy;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * shmem_alloc_page() passes MPOL_F_SHARED policy with
|
||
|
+ * a pseudo vma whose vma->vm_ops=NULL. Take a reference
|
||
|
+ * count on these policies which will be dropped by
|
||
|
+ * mpol_cond_put() later
|
||
|
+ */
|
||
|
+ if (mpol_needs_cond_ref(pol))
|
||
|
+ mpol_get(pol);
|
||
|
+ }
|
||
|
}
|
||
|
if (!pol)
|
||
|
pol = &default_policy;
|
||
|
@@ -2032,7 +2057,7 @@ int __mpol_equal(struct mempolicy *a, struct mempolicy *b)
|
||
|
*/
|
||
|
|
||
|
/* lookup first element intersecting start-end */
|
||
|
-/* Caller holds sp->lock */
|
||
|
+/* Caller holds sp->mutex */
|
||
|
static struct sp_node *
|
||
|
sp_lookup(struct shared_policy *sp, unsigned long start, unsigned long end)
|
||
|
{
|
||
|
@@ -2096,36 +2121,50 @@ mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx)
|
||
|
|
||
|
if (!sp->root.rb_node)
|
||
|
return NULL;
|
||
|
- spin_lock(&sp->lock);
|
||
|
+ mutex_lock(&sp->mutex);
|
||
|
sn = sp_lookup(sp, idx, idx+1);
|
||
|
if (sn) {
|
||
|
mpol_get(sn->policy);
|
||
|
pol = sn->policy;
|
||
|
}
|
||
|
- spin_unlock(&sp->lock);
|
||
|
+ mutex_unlock(&sp->mutex);
|
||
|
return pol;
|
||
|
}
|
||
|
|
||
|
+static void sp_free(struct sp_node *n)
|
||
|
+{
|
||
|
+ mpol_put(n->policy);
|
||
|
+ kmem_cache_free(sn_cache, n);
|
||
|
+}
|
||
|
+
|
||
|
static void sp_delete(struct shared_policy *sp, struct sp_node *n)
|
||
|
{
|
||
|
pr_debug("deleting %lx-l%lx\n", n->start, n->end);
|
||
|
rb_erase(&n->nd, &sp->root);
|
||
|
- mpol_put(n->policy);
|
||
|
- kmem_cache_free(sn_cache, n);
|
||
|
+ sp_free(n);
|
||
|
}
|
||
|
|
||
|
static struct sp_node *sp_alloc(unsigned long start, unsigned long end,
|
||
|
struct mempolicy *pol)
|
||
|
{
|
||
|
- struct sp_node *n = kmem_cache_alloc(sn_cache, GFP_KERNEL);
|
||
|
+ struct sp_node *n;
|
||
|
+ struct mempolicy *newpol;
|
||
|
|
||
|
+ n = kmem_cache_alloc(sn_cache, GFP_KERNEL);
|
||
|
if (!n)
|
||
|
return NULL;
|
||
|
+
|
||
|
+ newpol = mpol_dup(pol);
|
||
|
+ if (IS_ERR(newpol)) {
|
||
|
+ kmem_cache_free(sn_cache, n);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ newpol->flags |= MPOL_F_SHARED;
|
||
|
+
|
||
|
n->start = start;
|
||
|
n->end = end;
|
||
|
- mpol_get(pol);
|
||
|
- pol->flags |= MPOL_F_SHARED; /* for unref */
|
||
|
- n->policy = pol;
|
||
|
+ n->policy = newpol;
|
||
|
+
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
@@ -2133,10 +2172,10 @@ static struct sp_node *sp_alloc(unsigned long start, unsigned long end,
|
||
|
static int shared_policy_replace(struct shared_policy *sp, unsigned long start,
|
||
|
unsigned long end, struct sp_node *new)
|
||
|
{
|
||
|
- struct sp_node *n, *new2 = NULL;
|
||
|
+ struct sp_node *n;
|
||
|
+ int ret = 0;
|
||
|
|
||
|
-restart:
|
||
|
- spin_lock(&sp->lock);
|
||
|
+ mutex_lock(&sp->mutex);
|
||
|
n = sp_lookup(sp, start, end);
|
||
|
/* Take care of old policies in the same range. */
|
||
|
while (n && n->start < end) {
|
||
|
@@ -2149,16 +2188,14 @@ restart:
|
||
|
} else {
|
||
|
/* Old policy spanning whole new range. */
|
||
|
if (n->end > end) {
|
||
|
+ struct sp_node *new2;
|
||
|
+ new2 = sp_alloc(end, n->end, n->policy);
|
||
|
if (!new2) {
|
||
|
- spin_unlock(&sp->lock);
|
||
|
- new2 = sp_alloc(end, n->end, n->policy);
|
||
|
- if (!new2)
|
||
|
- return -ENOMEM;
|
||
|
- goto restart;
|
||
|
+ ret = -ENOMEM;
|
||
|
+ goto out;
|
||
|
}
|
||
|
n->end = start;
|
||
|
sp_insert(sp, new2);
|
||
|
- new2 = NULL;
|
||
|
break;
|
||
|
} else
|
||
|
n->end = start;
|
||
|
@@ -2169,12 +2206,9 @@ restart:
|
||
|
}
|
||
|
if (new)
|
||
|
sp_insert(sp, new);
|
||
|
- spin_unlock(&sp->lock);
|
||
|
- if (new2) {
|
||
|
- mpol_put(new2->policy);
|
||
|
- kmem_cache_free(sn_cache, new2);
|
||
|
- }
|
||
|
- return 0;
|
||
|
+out:
|
||
|
+ mutex_unlock(&sp->mutex);
|
||
|
+ return ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -2192,7 +2226,7 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)
|
||
|
int ret;
|
||
|
|
||
|
sp->root = RB_ROOT; /* empty tree == default mempolicy */
|
||
|
- spin_lock_init(&sp->lock);
|
||
|
+ mutex_init(&sp->mutex);
|
||
|
|
||
|
if (mpol) {
|
||
|
struct vm_area_struct pvma;
|
||
|
@@ -2246,7 +2280,7 @@ int mpol_set_shared_policy(struct shared_policy *info,
|
||
|
}
|
||
|
err = shared_policy_replace(info, vma->vm_pgoff, vma->vm_pgoff+sz, new);
|
||
|
if (err && new)
|
||
|
- kmem_cache_free(sn_cache, new);
|
||
|
+ sp_free(new);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
@@ -2258,16 +2292,14 @@ void mpol_free_shared_policy(struct shared_policy *p)
|
||
|
|
||
|
if (!p->root.rb_node)
|
||
|
return;
|
||
|
- spin_lock(&p->lock);
|
||
|
+ mutex_lock(&p->mutex);
|
||
|
next = rb_first(&p->root);
|
||
|
while (next) {
|
||
|
n = rb_entry(next, struct sp_node, nd);
|
||
|
next = rb_next(&n->nd);
|
||
|
- rb_erase(&n->nd, &p->root);
|
||
|
- mpol_put(n->policy);
|
||
|
- kmem_cache_free(sn_cache, n);
|
||
|
+ sp_delete(p, n);
|
||
|
}
|
||
|
- spin_unlock(&p->lock);
|
||
|
+ mutex_unlock(&p->mutex);
|
||
|
}
|
||
|
|
||
|
/* assumes fs == KERNEL_DS */
|
||
|
diff --git a/mm/slab.c b/mm/slab.c
|
||
|
index cd3ab93..4c3b671 100644
|
||
|
--- a/mm/slab.c
|
||
|
+++ b/mm/slab.c
|
||
|
@@ -1669,9 +1669,6 @@ void __init kmem_cache_init_late(void)
|
||
|
|
||
|
g_cpucache_up = LATE;
|
||
|
|
||
|
- /* Annotate slab for lockdep -- annotate the malloc caches */
|
||
|
- init_lock_keys();
|
||
|
-
|
||
|
/* 6) resize the head arrays to their final sizes */
|
||
|
mutex_lock(&cache_chain_mutex);
|
||
|
list_for_each_entry(cachep, &cache_chain, next)
|
||
|
@@ -1679,6 +1676,9 @@ void __init kmem_cache_init_late(void)
|
||
|
BUG();
|
||
|
mutex_unlock(&cache_chain_mutex);
|
||
|
|
||
|
+ /* Annotate slab for lockdep -- annotate the malloc caches */
|
||
|
+ init_lock_keys();
|
||
|
+
|
||
|
/* Done! */
|
||
|
g_cpucache_up = FULL;
|
||
|
|
||
|
diff --git a/mm/truncate.c b/mm/truncate.c
|
||
|
index 632b15e..00fb58a 100644
|
||
|
--- a/mm/truncate.c
|
||
|
+++ b/mm/truncate.c
|
||
|
@@ -394,11 +394,12 @@ invalidate_complete_page2(struct address_space *mapping, struct page *page)
|
||
|
if (page_has_private(page) && !try_to_release_page(page, GFP_KERNEL))
|
||
|
return 0;
|
||
|
|
||
|
+ clear_page_mlock(page);
|
||
|
+
|
||
|
spin_lock_irq(&mapping->tree_lock);
|
||
|
if (PageDirty(page))
|
||
|
goto failed;
|
||
|
|
||
|
- clear_page_mlock(page);
|
||
|
BUG_ON(page_has_private(page));
|
||
|
__delete_from_page_cache(page);
|
||
|
spin_unlock_irq(&mapping->tree_lock);
|
||
|
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
|
||
|
index de9da21..d7d63f4 100644
|
||
|
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
|
||
|
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
|
||
|
@@ -84,6 +84,14 @@ static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
|
||
|
*dataoff = nhoff + (iph->ihl << 2);
|
||
|
*protonum = iph->protocol;
|
||
|
|
||
|
+ /* Check bogus IP headers */
|
||
|
+ if (*dataoff > skb->len) {
|
||
|
+ pr_debug("nf_conntrack_ipv4: bogus IPv4 packet: "
|
||
|
+ "nhoff %u, ihl %u, skblen %u\n",
|
||
|
+ nhoff, iph->ihl << 2, skb->len);
|
||
|
+ return -NF_ACCEPT;
|
||
|
+ }
|
||
|
+
|
||
|
return NF_ACCEPT;
|
||
|
}
|
||
|
|
||
|
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
|
||
|
index 78844d9..6609a84 100644
|
||
|
--- a/net/ipv4/netfilter/nf_nat_sip.c
|
||
|
+++ b/net/ipv4/netfilter/nf_nat_sip.c
|
||
|
@@ -148,7 +148,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
|
||
|
if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
|
||
|
hdr, NULL, &matchoff, &matchlen,
|
||
|
&addr, &port) > 0) {
|
||
|
- unsigned int matchend, poff, plen, buflen, n;
|
||
|
+ unsigned int olen, matchend, poff, plen, buflen, n;
|
||
|
char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
|
||
|
|
||
|
/* We're only interested in headers related to this
|
||
|
@@ -163,11 +163,12 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
|
||
|
goto next;
|
||
|
}
|
||
|
|
||
|
+ olen = *datalen;
|
||
|
if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
|
||
|
&addr, port))
|
||
|
return NF_DROP;
|
||
|
|
||
|
- matchend = matchoff + matchlen;
|
||
|
+ matchend = matchoff + matchlen + *datalen - olen;
|
||
|
|
||
|
/* The maddr= parameter (RFC 2361) specifies where to send
|
||
|
* the reply. */
|
||
|
@@ -501,7 +502,10 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
|
||
|
ret = nf_ct_expect_related(rtcp_exp);
|
||
|
if (ret == 0)
|
||
|
break;
|
||
|
- else if (ret != -EBUSY) {
|
||
|
+ else if (ret == -EBUSY) {
|
||
|
+ nf_ct_unexpect_related(rtp_exp);
|
||
|
+ continue;
|
||
|
+ } else if (ret < 0) {
|
||
|
nf_ct_unexpect_related(rtp_exp);
|
||
|
port = 0;
|
||
|
break;
|
||
|
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
|
||
|
index 340c80d..7918eb7 100644
|
||
|
--- a/net/netfilter/nf_conntrack_expect.c
|
||
|
+++ b/net/netfilter/nf_conntrack_expect.c
|
||
|
@@ -366,23 +366,6 @@ static void evict_oldest_expect(struct nf_conn *master,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-static inline int refresh_timer(struct nf_conntrack_expect *i)
|
||
|
-{
|
||
|
- struct nf_conn_help *master_help = nfct_help(i->master);
|
||
|
- const struct nf_conntrack_expect_policy *p;
|
||
|
-
|
||
|
- if (!del_timer(&i->timeout))
|
||
|
- return 0;
|
||
|
-
|
||
|
- p = &rcu_dereference_protected(
|
||
|
- master_help->helper,
|
||
|
- lockdep_is_held(&nf_conntrack_lock)
|
||
|
- )->expect_policy[i->class];
|
||
|
- i->timeout.expires = jiffies + p->timeout * HZ;
|
||
|
- add_timer(&i->timeout);
|
||
|
- return 1;
|
||
|
-}
|
||
|
-
|
||
|
static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
|
||
|
{
|
||
|
const struct nf_conntrack_expect_policy *p;
|
||
|
@@ -390,7 +373,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
|
||
|
struct nf_conn *master = expect->master;
|
||
|
struct nf_conn_help *master_help = nfct_help(master);
|
||
|
struct net *net = nf_ct_exp_net(expect);
|
||
|
- struct hlist_node *n;
|
||
|
+ struct hlist_node *n, *next;
|
||
|
unsigned int h;
|
||
|
int ret = 1;
|
||
|
|
||
|
@@ -401,12 +384,12 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
|
||
|
goto out;
|
||
|
}
|
||
|
h = nf_ct_expect_dst_hash(&expect->tuple);
|
||
|
- hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) {
|
||
|
+ hlist_for_each_entry_safe(i, n, next, &net->ct.expect_hash[h], hnode) {
|
||
|
if (expect_matches(i, expect)) {
|
||
|
- /* Refresh timer: if it's dying, ignore.. */
|
||
|
- if (refresh_timer(i)) {
|
||
|
- ret = 0;
|
||
|
- goto out;
|
||
|
+ if (del_timer(&i->timeout)) {
|
||
|
+ nf_ct_unlink_expect(i);
|
||
|
+ nf_ct_expect_put(i);
|
||
|
+ break;
|
||
|
}
|
||
|
} else if (expect_clash(i, expect)) {
|
||
|
ret = -EBUSY;
|
||
|
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
|
||
|
index dfd52ba..8f3f280 100644
|
||
|
--- a/net/netfilter/xt_hashlimit.c
|
||
|
+++ b/net/netfilter/xt_hashlimit.c
|
||
|
@@ -389,8 +389,7 @@ static void htable_put(struct xt_hashlimit_htable *hinfo)
|
||
|
#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
|
||
|
|
||
|
/* Precision saver. */
|
||
|
-static inline u_int32_t
|
||
|
-user2credits(u_int32_t user)
|
||
|
+static u32 user2credits(u32 user)
|
||
|
{
|
||
|
/* If multiplying would overflow... */
|
||
|
if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
|
||
|
@@ -400,7 +399,7 @@ user2credits(u_int32_t user)
|
||
|
return (user * HZ * CREDITS_PER_JIFFY) / XT_HASHLIMIT_SCALE;
|
||
|
}
|
||
|
|
||
|
-static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
|
||
|
+static void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
|
||
|
{
|
||
|
dh->rateinfo.credit += (now - dh->rateinfo.prev) * CREDITS_PER_JIFFY;
|
||
|
if (dh->rateinfo.credit > dh->rateinfo.credit_cap)
|
||
|
@@ -531,8 +530,7 @@ hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
||
|
dh->rateinfo.prev = jiffies;
|
||
|
dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
|
||
|
hinfo->cfg.burst);
|
||
|
- dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg *
|
||
|
- hinfo->cfg.burst);
|
||
|
+ dh->rateinfo.credit_cap = dh->rateinfo.credit;
|
||
|
dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
|
||
|
} else {
|
||
|
/* update expiration timeout */
|
||
|
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
|
||
|
index 32b7a57..a4c1e45 100644
|
||
|
--- a/net/netfilter/xt_limit.c
|
||
|
+++ b/net/netfilter/xt_limit.c
|
||
|
@@ -88,8 +88,7 @@ limit_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
||
|
}
|
||
|
|
||
|
/* Precision saver. */
|
||
|
-static u_int32_t
|
||
|
-user2credits(u_int32_t user)
|
||
|
+static u32 user2credits(u32 user)
|
||
|
{
|
||
|
/* If multiplying would overflow... */
|
||
|
if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
|
||
|
@@ -118,12 +117,12 @@ static int limit_mt_check(const struct xt_mtchk_param *par)
|
||
|
|
||
|
/* For SMP, we only want to use one set of state. */
|
||
|
r->master = priv;
|
||
|
+ /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies *
|
||
|
+ 128. */
|
||
|
+ priv->prev = jiffies;
|
||
|
+ priv->credit = user2credits(r->avg * r->burst); /* Credits full. */
|
||
|
if (r->cost == 0) {
|
||
|
- /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies *
|
||
|
- 128. */
|
||
|
- priv->prev = jiffies;
|
||
|
- priv->credit = user2credits(r->avg * r->burst); /* Credits full. */
|
||
|
- r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */
|
||
|
+ r->credit_cap = priv->credit; /* Credits full. */
|
||
|
r->cost = user2credits(r->avg);
|
||
|
}
|
||
|
return 0;
|
||
|
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
|
||
|
index c5391af..10a385b 100644
|
||
|
--- a/net/sunrpc/xprtsock.c
|
||
|
+++ b/net/sunrpc/xprtsock.c
|
||
|
@@ -1028,6 +1028,16 @@ static void xs_udp_data_ready(struct sock *sk, int len)
|
||
|
read_unlock_bh(&sk->sk_callback_lock);
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * Helper function to force a TCP close if the server is sending
|
||
|
+ * junk and/or it has put us in CLOSE_WAIT
|
||
|
+ */
|
||
|
+static void xs_tcp_force_close(struct rpc_xprt *xprt)
|
||
|
+{
|
||
|
+ set_bit(XPRT_CONNECTION_CLOSE, &xprt->state);
|
||
|
+ xprt_force_disconnect(xprt);
|
||
|
+}
|
||
|
+
|
||
|
static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_reader *desc)
|
||
|
{
|
||
|
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
|
||
|
@@ -1054,7 +1064,7 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_rea
|
||
|
/* Sanity check of the record length */
|
||
|
if (unlikely(transport->tcp_reclen < 8)) {
|
||
|
dprintk("RPC: invalid TCP record fragment length\n");
|
||
|
- xprt_force_disconnect(xprt);
|
||
|
+ xs_tcp_force_close(xprt);
|
||
|
return;
|
||
|
}
|
||
|
dprintk("RPC: reading TCP record fragment of length %d\n",
|
||
|
@@ -1135,7 +1145,7 @@ static inline void xs_tcp_read_calldir(struct sock_xprt *transport,
|
||
|
break;
|
||
|
default:
|
||
|
dprintk("RPC: invalid request message type\n");
|
||
|
- xprt_force_disconnect(&transport->xprt);
|
||
|
+ xs_tcp_force_close(&transport->xprt);
|
||
|
}
|
||
|
xs_tcp_check_fraghdr(transport);
|
||
|
}
|
||
|
@@ -1458,6 +1468,8 @@ static void xs_tcp_cancel_linger_timeout(struct rpc_xprt *xprt)
|
||
|
static void xs_sock_mark_closed(struct rpc_xprt *xprt)
|
||
|
{
|
||
|
smp_mb__before_clear_bit();
|
||
|
+ clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
|
||
|
+ clear_bit(XPRT_CONNECTION_CLOSE, &xprt->state);
|
||
|
clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
|
||
|
clear_bit(XPRT_CLOSING, &xprt->state);
|
||
|
smp_mb__after_clear_bit();
|
||
|
@@ -1515,8 +1527,8 @@ static void xs_tcp_state_change(struct sock *sk)
|
||
|
break;
|
||
|
case TCP_CLOSE_WAIT:
|
||
|
/* The server initiated a shutdown of the socket */
|
||
|
- xprt_force_disconnect(xprt);
|
||
|
xprt->connect_cookie++;
|
||
|
+ xs_tcp_force_close(xprt);
|
||
|
case TCP_CLOSING:
|
||
|
/*
|
||
|
* If the server closed down the connection, make sure that
|
||
|
@@ -2159,8 +2171,7 @@ static void xs_tcp_setup_socket(struct work_struct *work)
|
||
|
/* We're probably in TIME_WAIT. Get rid of existing socket,
|
||
|
* and retry
|
||
|
*/
|
||
|
- set_bit(XPRT_CONNECTION_CLOSE, &xprt->state);
|
||
|
- xprt_force_disconnect(xprt);
|
||
|
+ xs_tcp_force_close(xprt);
|
||
|
break;
|
||
|
case -ECONNREFUSED:
|
||
|
case -ECONNRESET:
|
||
|
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
|
||
|
index d897278..978416d 100644
|
||
|
--- a/scripts/Kbuild.include
|
||
|
+++ b/scripts/Kbuild.include
|
||
|
@@ -98,24 +98,24 @@ try-run = $(shell set -e; \
|
||
|
# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
|
||
|
|
||
|
as-option = $(call try-run,\
|
||
|
- $(CC) $(KBUILD_CFLAGS) $(1) -c -xassembler /dev/null -o "$$TMP",$(1),$(2))
|
||
|
+ $(CC) $(KBUILD_CFLAGS) $(1) -c -x assembler /dev/null -o "$$TMP",$(1),$(2))
|
||
|
|
||
|
# as-instr
|
||
|
# Usage: cflags-y += $(call as-instr,instr,option1,option2)
|
||
|
|
||
|
as-instr = $(call try-run,\
|
||
|
- /bin/echo -e "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3))
|
||
|
+ printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3))
|
||
|
|
||
|
# cc-option
|
||
|
# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
|
||
|
|
||
|
cc-option = $(call try-run,\
|
||
|
- $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2))
|
||
|
+ $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
|
||
|
|
||
|
# cc-option-yn
|
||
|
# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
|
||
|
cc-option-yn = $(call try-run,\
|
||
|
- $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n)
|
||
|
+ $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n)
|
||
|
|
||
|
# cc-option-align
|
||
|
# Prefix align with either -falign or -malign
|
||
|
@@ -125,7 +125,7 @@ cc-option-align = $(subst -functions=0,,\
|
||
|
# cc-disable-warning
|
||
|
# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
|
||
|
cc-disable-warning = $(call try-run,\
|
||
|
- $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1)))
|
||
|
+ $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
|
||
|
|
||
|
# cc-version
|
||
|
# Usage gcc-ver := $(call cc-version)
|
||
|
@@ -143,7 +143,7 @@ cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3))
|
||
|
# cc-ldoption
|
||
|
# Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both)
|
||
|
cc-ldoption = $(call try-run,\
|
||
|
- $(CC) $(1) -nostdlib -xc /dev/null -o "$$TMP",$(1),$(2))
|
||
|
+ $(CC) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2))
|
||
|
|
||
|
# ld-option
|
||
|
# Usage: LDFLAGS += $(call ld-option, -X)
|
||
|
@@ -209,7 +209,7 @@ endif
|
||
|
# >$< substitution to preserve $ when reloading .cmd file
|
||
|
# note: when using inline perl scripts [perl -e '...$$t=1;...']
|
||
|
# in $(cmd_xxx) double $$ your perl vars
|
||
|
-make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))
|
||
|
+make-cmd = $(subst \\,\\\\,$(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1))))))
|
||
|
|
||
|
# Find any prerequisites that is newer than target or that does not exist.
|
||
|
# PHONY targets skipped in both cases.
|
||
|
diff --git a/scripts/gcc-version.sh b/scripts/gcc-version.sh
|
||
|
index debecb5..7f2126d 100644
|
||
|
--- a/scripts/gcc-version.sh
|
||
|
+++ b/scripts/gcc-version.sh
|
||
|
@@ -22,10 +22,10 @@ if [ ${#compiler} -eq 0 ]; then
|
||
|
exit 1
|
||
|
fi
|
||
|
|
||
|
-MAJOR=$(echo __GNUC__ | $compiler -E -xc - | tail -n 1)
|
||
|
-MINOR=$(echo __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1)
|
||
|
+MAJOR=$(echo __GNUC__ | $compiler -E -x c - | tail -n 1)
|
||
|
+MINOR=$(echo __GNUC_MINOR__ | $compiler -E -x c - | tail -n 1)
|
||
|
if [ "x$with_patchlevel" != "x" ] ; then
|
||
|
- PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -xc - | tail -n 1)
|
||
|
+ PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -x c - | tail -n 1)
|
||
|
printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL
|
||
|
else
|
||
|
printf "%02d%02d\\n" $MAJOR $MINOR
|
||
|
diff --git a/scripts/gcc-x86_32-has-stack-protector.sh b/scripts/gcc-x86_32-has-stack-protector.sh
|
||
|
index 29493dc..12dbd0b 100644
|
||
|
--- a/scripts/gcc-x86_32-has-stack-protector.sh
|
||
|
+++ b/scripts/gcc-x86_32-has-stack-protector.sh
|
||
|
@@ -1,6 +1,6 @@
|
||
|
#!/bin/sh
|
||
|
|
||
|
-echo "int foo(void) { char X[200]; return 3; }" | $* -S -xc -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
|
||
|
+echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
|
||
|
if [ "$?" -eq "0" ] ; then
|
||
|
echo y
|
||
|
else
|
||
|
diff --git a/scripts/gcc-x86_64-has-stack-protector.sh b/scripts/gcc-x86_64-has-stack-protector.sh
|
||
|
index afaec61..973e8c1 100644
|
||
|
--- a/scripts/gcc-x86_64-has-stack-protector.sh
|
||
|
+++ b/scripts/gcc-x86_64-has-stack-protector.sh
|
||
|
@@ -1,6 +1,6 @@
|
||
|
#!/bin/sh
|
||
|
|
||
|
-echo "int foo(void) { char X[200]; return 3; }" | $* -S -xc -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
|
||
|
+echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
|
||
|
if [ "$?" -eq "0" ] ; then
|
||
|
echo y
|
||
|
else
|
||
|
diff --git a/scripts/kconfig/check.sh b/scripts/kconfig/check.sh
|
||
|
index fa59cbf..854d9c7 100755
|
||
|
--- a/scripts/kconfig/check.sh
|
||
|
+++ b/scripts/kconfig/check.sh
|
||
|
@@ -1,6 +1,6 @@
|
||
|
#!/bin/sh
|
||
|
# Needed for systems without gettext
|
||
|
-$* -xc -o /dev/null - > /dev/null 2>&1 << EOF
|
||
|
+$* -x c -o /dev/null - > /dev/null 2>&1 << EOF
|
||
|
#include <libintl.h>
|
||
|
int main()
|
||
|
{
|
||
|
diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh
|
||
|
index 82cc3a8..50df490 100644
|
||
|
--- a/scripts/kconfig/lxdialog/check-lxdialog.sh
|
||
|
+++ b/scripts/kconfig/lxdialog/check-lxdialog.sh
|
||
|
@@ -38,7 +38,7 @@ trap "rm -f $tmp" 0 1 2 3 15
|
||
|
|
||
|
# Check if we can link to ncurses
|
||
|
check() {
|
||
|
- $cc -xc - -o $tmp 2>/dev/null <<'EOF'
|
||
|
+ $cc -x c - -o $tmp 2>/dev/null <<'EOF'
|
||
|
#include CURSES_LOC
|
||
|
main() {}
|
||
|
EOF
|
||
|
diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl
|
||
|
index bccf07dd..3346f42 100644
|
||
|
--- a/scripts/kconfig/streamline_config.pl
|
||
|
+++ b/scripts/kconfig/streamline_config.pl
|
||
|
@@ -463,6 +463,8 @@ while(<CIN>) {
|
||
|
if (defined($configs{$1})) {
|
||
|
if ($localyesconfig) {
|
||
|
$setconfigs{$1} = 'y';
|
||
|
+ print "$1=y\n";
|
||
|
+ next;
|
||
|
} else {
|
||
|
$setconfigs{$1} = $2;
|
||
|
}
|
||
|
diff --git a/scripts/package/buildtar b/scripts/package/buildtar
|
||
|
index 8a7b155..d0d748e 100644
|
||
|
--- a/scripts/package/buildtar
|
||
|
+++ b/scripts/package/buildtar
|
||
|
@@ -109,7 +109,7 @@ esac
|
||
|
if tar --owner=root --group=root --help >/dev/null 2>&1; then
|
||
|
opts="--owner=root --group=root"
|
||
|
fi
|
||
|
- tar cf - . $opts | ${compress} > "${tarball}${file_ext}"
|
||
|
+ tar cf - boot/* lib/* $opts | ${compress} > "${tarball}${file_ext}"
|
||
|
)
|
||
|
|
||
|
echo "Tarball successfully created in ${tarball}${file_ext}"
|
||
|
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
|
||
|
index d83bafc..193ce81 100644
|
||
|
--- a/sound/drivers/aloop.c
|
||
|
+++ b/sound/drivers/aloop.c
|
||
|
@@ -119,6 +119,7 @@ struct loopback_pcm {
|
||
|
unsigned int period_size_frac;
|
||
|
unsigned long last_jiffies;
|
||
|
struct timer_list timer;
|
||
|
+ spinlock_t timer_lock;
|
||
|
};
|
||
|
|
||
|
static struct platform_device *devices[SNDRV_CARDS];
|
||
|
@@ -169,6 +170,7 @@ static void loopback_timer_start(struct loopback_pcm *dpcm)
|
||
|
unsigned long tick;
|
||
|
unsigned int rate_shift = get_rate_shift(dpcm);
|
||
|
|
||
|
+ spin_lock(&dpcm->timer_lock);
|
||
|
if (rate_shift != dpcm->pcm_rate_shift) {
|
||
|
dpcm->pcm_rate_shift = rate_shift;
|
||
|
dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size);
|
||
|
@@ -181,12 +183,15 @@ static void loopback_timer_start(struct loopback_pcm *dpcm)
|
||
|
tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;
|
||
|
dpcm->timer.expires = jiffies + tick;
|
||
|
add_timer(&dpcm->timer);
|
||
|
+ spin_unlock(&dpcm->timer_lock);
|
||
|
}
|
||
|
|
||
|
static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
|
||
|
{
|
||
|
+ spin_lock(&dpcm->timer_lock);
|
||
|
del_timer(&dpcm->timer);
|
||
|
dpcm->timer.expires = 0;
|
||
|
+ spin_unlock(&dpcm->timer_lock);
|
||
|
}
|
||
|
|
||
|
#define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK)
|
||
|
@@ -659,6 +664,7 @@ static int loopback_open(struct snd_pcm_substream *substream)
|
||
|
dpcm->substream = substream;
|
||
|
setup_timer(&dpcm->timer, loopback_timer_function,
|
||
|
(unsigned long)dpcm);
|
||
|
+ spin_lock_init(&dpcm->timer_lock);
|
||
|
|
||
|
cable = loopback->cables[substream->number][dev];
|
||
|
if (!cable) {
|
||
|
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
|
||
|
index 402f330..94f0c4a 100644
|
||
|
--- a/sound/pci/hda/patch_conexant.c
|
||
|
+++ b/sound/pci/hda/patch_conexant.c
|
||
|
@@ -139,6 +139,7 @@ struct conexant_spec {
|
||
|
unsigned int asus:1;
|
||
|
unsigned int pin_eapd_ctrls:1;
|
||
|
unsigned int single_adc_amp:1;
|
||
|
+ unsigned int fixup_stereo_dmic:1;
|
||
|
|
||
|
unsigned int adc_switching:1;
|
||
|
|
||
|
@@ -4113,9 +4114,9 @@ static int cx_auto_init(struct hda_codec *codec)
|
||
|
|
||
|
static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
|
||
|
const char *dir, int cidx,
|
||
|
- hda_nid_t nid, int hda_dir, int amp_idx)
|
||
|
+ hda_nid_t nid, int hda_dir, int amp_idx, int chs)
|
||
|
{
|
||
|
- static char name[32];
|
||
|
+ static char name[44];
|
||
|
static struct snd_kcontrol_new knew[] = {
|
||
|
HDA_CODEC_VOLUME(name, 0, 0, 0),
|
||
|
HDA_CODEC_MUTE(name, 0, 0, 0),
|
||
|
@@ -4125,7 +4126,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
|
||
|
|
||
|
for (i = 0; i < 2; i++) {
|
||
|
struct snd_kcontrol *kctl;
|
||
|
- knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx,
|
||
|
+ knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx,
|
||
|
hda_dir);
|
||
|
knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
|
||
|
knew[i].index = cidx;
|
||
|
@@ -4144,7 +4145,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
|
||
|
}
|
||
|
|
||
|
#define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \
|
||
|
- cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0)
|
||
|
+ cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0, 3)
|
||
|
|
||
|
#define cx_auto_add_pb_volume(codec, nid, str, idx) \
|
||
|
cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
|
||
|
@@ -4214,6 +4215,36 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/* Returns zero if this is a normal stereo channel, and non-zero if it should
|
||
|
+ be split in two independent channels.
|
||
|
+ dest_label must be at least 44 characters. */
|
||
|
+static int cx_auto_get_rightch_label(struct hda_codec *codec, const char *label,
|
||
|
+ char *dest_label, int nid)
|
||
|
+{
|
||
|
+ struct conexant_spec *spec = codec->spec;
|
||
|
+ int i;
|
||
|
+
|
||
|
+ if (!spec->fixup_stereo_dmic)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ for (i = 0; i < AUTO_CFG_MAX_INS; i++) {
|
||
|
+ int def_conf;
|
||
|
+ if (spec->autocfg.inputs[i].pin != nid)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (spec->autocfg.inputs[i].type != AUTO_PIN_MIC)
|
||
|
+ return 0;
|
||
|
+ def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||
|
+ if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ /* Finally found the inverted internal mic! */
|
||
|
+ snprintf(dest_label, 44, "Inverted %s", label);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
|
||
|
const char *label, const char *pfx,
|
||
|
int cidx)
|
||
|
@@ -4222,14 +4253,25 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < spec->num_adc_nids; i++) {
|
||
|
+ char rightch_label[44];
|
||
|
hda_nid_t adc_nid = spec->adc_nids[i];
|
||
|
int idx = get_input_connection(codec, adc_nid, nid);
|
||
|
if (idx < 0)
|
||
|
continue;
|
||
|
if (spec->single_adc_amp)
|
||
|
idx = 0;
|
||
|
+
|
||
|
+ if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
|
||
|
+ /* Make two independent kcontrols for left and right */
|
||
|
+ int err = cx_auto_add_volume_idx(codec, label, pfx,
|
||
|
+ cidx, adc_nid, HDA_INPUT, idx, 1);
|
||
|
+ if (err < 0)
|
||
|
+ return err;
|
||
|
+ return cx_auto_add_volume_idx(codec, rightch_label, pfx,
|
||
|
+ cidx, adc_nid, HDA_INPUT, idx, 2);
|
||
|
+ }
|
||
|
return cx_auto_add_volume_idx(codec, label, pfx,
|
||
|
- cidx, adc_nid, HDA_INPUT, idx);
|
||
|
+ cidx, adc_nid, HDA_INPUT, idx, 3);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -4242,9 +4284,19 @@ static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx,
|
||
|
int i, con;
|
||
|
|
||
|
nid = spec->imux_info[idx].pin;
|
||
|
- if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
|
||
|
+ if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
|
||
|
+ char rightch_label[44];
|
||
|
+ if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
|
||
|
+ int err = cx_auto_add_volume_idx(codec, label, " Boost",
|
||
|
+ cidx, nid, HDA_INPUT, 0, 1);
|
||
|
+ if (err < 0)
|
||
|
+ return err;
|
||
|
+ return cx_auto_add_volume_idx(codec, rightch_label, " Boost",
|
||
|
+ cidx, nid, HDA_INPUT, 0, 2);
|
||
|
+ }
|
||
|
return cx_auto_add_volume(codec, label, " Boost", cidx,
|
||
|
nid, HDA_INPUT);
|
||
|
+ }
|
||
|
con = __select_input_connection(codec, spec->imux_info[idx].adc, nid,
|
||
|
&mux, false, 0);
|
||
|
if (con < 0)
|
||
|
@@ -4398,23 +4450,31 @@ static void apply_pincfg(struct hda_codec *codec, const struct cxt_pincfg *cfg)
|
||
|
|
||
|
}
|
||
|
|
||
|
-static void apply_pin_fixup(struct hda_codec *codec,
|
||
|
+enum {
|
||
|
+ CXT_PINCFG_LENOVO_X200,
|
||
|
+ CXT_PINCFG_LENOVO_TP410,
|
||
|
+ CXT_FIXUP_STEREO_DMIC,
|
||
|
+};
|
||
|
+
|
||
|
+static void apply_fixup(struct hda_codec *codec,
|
||
|
const struct snd_pci_quirk *quirk,
|
||
|
const struct cxt_pincfg **table)
|
||
|
{
|
||
|
+ struct conexant_spec *spec = codec->spec;
|
||
|
+
|
||
|
quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
|
||
|
- if (quirk) {
|
||
|
+ if (quirk && table[quirk->value]) {
|
||
|
snd_printdd(KERN_INFO "hda_codec: applying pincfg for %s\n",
|
||
|
quirk->name);
|
||
|
apply_pincfg(codec, table[quirk->value]);
|
||
|
}
|
||
|
+ if (quirk->value == CXT_FIXUP_STEREO_DMIC) {
|
||
|
+ snd_printdd(KERN_INFO "hda_codec: applying internal mic workaround for %s\n",
|
||
|
+ quirk->name);
|
||
|
+ spec->fixup_stereo_dmic = 1;
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
-enum {
|
||
|
- CXT_PINCFG_LENOVO_X200,
|
||
|
- CXT_PINCFG_LENOVO_TP410,
|
||
|
-};
|
||
|
-
|
||
|
/* ThinkPad X200 & co with cxt5051 */
|
||
|
static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
|
||
|
{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
|
||
|
@@ -4434,6 +4494,7 @@ static const struct cxt_pincfg cxt_pincfg_lenovo_tp410[] = {
|
||
|
static const struct cxt_pincfg *cxt_pincfg_tbl[] = {
|
||
|
[CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200,
|
||
|
[CXT_PINCFG_LENOVO_TP410] = cxt_pincfg_lenovo_tp410,
|
||
|
+ [CXT_FIXUP_STEREO_DMIC] = NULL,
|
||
|
};
|
||
|
|
||
|
static const struct snd_pci_quirk cxt5051_fixups[] = {
|
||
|
@@ -4447,6 +4508,9 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
|
||
|
SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
|
||
|
SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
|
||
|
SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
|
||
|
+ SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
|
||
|
+ SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
|
||
|
+ SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
|
||
|
{}
|
||
|
};
|
||
|
|
||
|
@@ -4486,10 +4550,10 @@ static int patch_conexant_auto(struct hda_codec *codec)
|
||
|
break;
|
||
|
case 0x14f15051:
|
||
|
add_cx5051_fake_mutes(codec);
|
||
|
- apply_pin_fixup(codec, cxt5051_fixups, cxt_pincfg_tbl);
|
||
|
+ apply_fixup(codec, cxt5051_fixups, cxt_pincfg_tbl);
|
||
|
break;
|
||
|
default:
|
||
|
- apply_pin_fixup(codec, cxt5066_fixups, cxt_pincfg_tbl);
|
||
|
+ apply_fixup(codec, cxt5066_fixups, cxt_pincfg_tbl);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
|
||
|
index 323d4d9..0961d88 100644
|
||
|
--- a/tools/hv/hv_kvp_daemon.c
|
||
|
+++ b/tools/hv/hv_kvp_daemon.c
|
||
|
@@ -348,7 +348,7 @@ int main(void)
|
||
|
fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
|
||
|
if (fd < 0) {
|
||
|
syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
|
||
|
- exit(-1);
|
||
|
+ exit(EXIT_FAILURE);
|
||
|
}
|
||
|
addr.nl_family = AF_NETLINK;
|
||
|
addr.nl_pad = 0;
|
||
|
@@ -360,7 +360,7 @@ int main(void)
|
||
|
if (error < 0) {
|
||
|
syslog(LOG_ERR, "bind failed; error:%d", error);
|
||
|
close(fd);
|
||
|
- exit(-1);
|
||
|
+ exit(EXIT_FAILURE);
|
||
|
}
|
||
|
sock_opt = addr.nl_groups;
|
||
|
setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
|
||
|
@@ -378,7 +378,7 @@ int main(void)
|
||
|
if (len < 0) {
|
||
|
syslog(LOG_ERR, "netlink_send failed; error:%d", len);
|
||
|
close(fd);
|
||
|
- exit(-1);
|
||
|
+ exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
pfd.fd = fd;
|
||
|
@@ -497,7 +497,7 @@ int main(void)
|
||
|
len = netlink_send(fd, incoming_cn_msg);
|
||
|
if (len < 0) {
|
||
|
syslog(LOG_ERR, "net_link send failed; error:%d", len);
|
||
|
- exit(-1);
|
||
|
+ exit(EXIT_FAILURE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
|
||
|
index b98e307..e45d2b1 100644
|
||
|
--- a/tools/perf/Makefile
|
||
|
+++ b/tools/perf/Makefile
|
||
|
@@ -56,7 +56,7 @@ ifeq ($(ARCH),x86_64)
|
||
|
ARCH := x86
|
||
|
IS_X86_64 := 0
|
||
|
ifeq (, $(findstring m32,$(EXTRA_CFLAGS)))
|
||
|
- IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1)
|
||
|
+ IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1)
|
||
|
endif
|
||
|
ifeq (${IS_X86_64}, 1)
|
||
|
RAW_ARCH := x86_64
|
||
|
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
|
||
|
index e8a03ac..7db8da5 100644
|
||
|
--- a/tools/power/cpupower/Makefile
|
||
|
+++ b/tools/power/cpupower/Makefile
|
||
|
@@ -100,7 +100,7 @@ GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo po/$$HLANG.gmo; done;}
|
||
|
export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS
|
||
|
|
||
|
# check if compiler option is supported
|
||
|
-cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;}
|
||
|
+cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -x c /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;}
|
||
|
|
||
|
# use '-Os' optimization if available, else use -O2
|
||
|
OPTIMIZATION := $(call cc-supports,-Os,-O2)
|