]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.2-stable patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Sat, 21 Jan 2012 15:26:28 +0000 (10:26 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Sat, 21 Jan 2012 15:26:28 +0000 (10:26 -0500)
added patches:
acpica-put-back-the-call-to-acpi_os_validate_address.patch
acpi-processor-fix-acpi_get_cpuid-for-up-processor.patch
bcma-invalidate-the-mapped-core-over-suspend-resume.patch
cx23885-dvb-check-if-dvb_attach-succeded.patch
cx88-fix-don-t-duplicate-xc4000-entry-for-radio.patch
i2c-omap-correct-sysc-register-offset-for-omap4.patch
sym53c8xx-fix-null-pointer-dereference-in-slave_destroy.patch
target-set-additional-sense-length-field-in-sense-data.patch
target-set-response-format-in-inquiry-response.patch
tracepoints-module-fix-disabling-tracepoints-with-taint-crap-or-oot.patch
tuner-fix-numberspace-conflict-between-xc4000-and-pti-5nf05-tuners.patch
x86-uv2-fix-bau-destination-timeout-initialization.patch
x86-uv2-fix-new-uv2-hardware-by-using-native-uv2-broadcast-mode.patch
x86-uv2-work-around-bau-bug.patch

15 files changed:
queue-3.2/acpi-processor-fix-acpi_get_cpuid-for-up-processor.patch [new file with mode: 0644]
queue-3.2/acpica-put-back-the-call-to-acpi_os_validate_address.patch [new file with mode: 0644]
queue-3.2/bcma-invalidate-the-mapped-core-over-suspend-resume.patch [new file with mode: 0644]
queue-3.2/cx23885-dvb-check-if-dvb_attach-succeded.patch [new file with mode: 0644]
queue-3.2/cx88-fix-don-t-duplicate-xc4000-entry-for-radio.patch [new file with mode: 0644]
queue-3.2/i2c-omap-correct-sysc-register-offset-for-omap4.patch [new file with mode: 0644]
queue-3.2/series
queue-3.2/sym53c8xx-fix-null-pointer-dereference-in-slave_destroy.patch [new file with mode: 0644]
queue-3.2/target-set-additional-sense-length-field-in-sense-data.patch [new file with mode: 0644]
queue-3.2/target-set-response-format-in-inquiry-response.patch [new file with mode: 0644]
queue-3.2/tracepoints-module-fix-disabling-tracepoints-with-taint-crap-or-oot.patch [new file with mode: 0644]
queue-3.2/tuner-fix-numberspace-conflict-between-xc4000-and-pti-5nf05-tuners.patch [new file with mode: 0644]
queue-3.2/x86-uv2-fix-bau-destination-timeout-initialization.patch [new file with mode: 0644]
queue-3.2/x86-uv2-fix-new-uv2-hardware-by-using-native-uv2-broadcast-mode.patch [new file with mode: 0644]
queue-3.2/x86-uv2-work-around-bau-bug.patch [new file with mode: 0644]

diff --git a/queue-3.2/acpi-processor-fix-acpi_get_cpuid-for-up-processor.patch b/queue-3.2/acpi-processor-fix-acpi_get_cpuid-for-up-processor.patch
new file mode 100644 (file)
index 0000000..0bdc632
--- /dev/null
@@ -0,0 +1,73 @@
+From d640113fe80e45ebd4a5b420b220d3f6bf37f682 Mon Sep 17 00:00:00 2001
+From: Lin Ming <ming.m.lin@intel.com>
+Date: Tue, 13 Dec 2011 09:36:03 +0800
+Subject: ACPI: processor: fix acpi_get_cpuid for UP processor
+
+From: Lin Ming <ming.m.lin@intel.com>
+
+commit d640113fe80e45ebd4a5b420b220d3f6bf37f682 upstream.
+
+For UP processor, it is likely that no _MAT method or MADT table defined.
+So currently acpi_get_cpuid(...) always return -1 for UP processor.
+This is wrong. It should return valid value for CPU0.
+
+In the other hand, BIOS may define multiple CPU handles even for UP
+processor, for example
+
+        Scope (_PR)
+        {
+            Processor (CPU0, 0x00, 0x00000410, 0x06) {}
+            Processor (CPU1, 0x01, 0x00000410, 0x06) {}
+            Processor (CPU2, 0x02, 0x00000410, 0x06) {}
+            Processor (CPU3, 0x03, 0x00000410, 0x06) {}
+        }
+
+We should only return valid value for CPU0's acpi handle.
+And return invalid value for others.
+
+http://marc.info/?t=132329819900003&r=1&w=2
+
+Reported-and-tested-by: wallak@free.fr
+Signed-off-by: Lin Ming <ming.m.lin@intel.com>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/processor_core.c |   26 ++++++++++++++++++++++++--
+ 1 file changed, 24 insertions(+), 2 deletions(-)
+
+--- a/drivers/acpi/processor_core.c
++++ b/drivers/acpi/processor_core.c
+@@ -173,8 +173,30 @@ int acpi_get_cpuid(acpi_handle handle, i
+       apic_id = map_mat_entry(handle, type, acpi_id);
+       if (apic_id == -1)
+               apic_id = map_madt_entry(type, acpi_id);
+-      if (apic_id == -1)
+-              return apic_id;
++      if (apic_id == -1) {
++              /*
++               * On UP processor, there is no _MAT or MADT table.
++               * So above apic_id is always set to -1.
++               *
++               * BIOS may define multiple CPU handles even for UP processor.
++               * For example,
++               *
++               * Scope (_PR)
++                 * {
++               *     Processor (CPU0, 0x00, 0x00000410, 0x06) {}
++               *     Processor (CPU1, 0x01, 0x00000410, 0x06) {}
++               *     Processor (CPU2, 0x02, 0x00000410, 0x06) {}
++               *     Processor (CPU3, 0x03, 0x00000410, 0x06) {}
++               * }
++               *
++               * Ignores apic_id and always return 0 for CPU0's handle.
++               * Return -1 for other CPU's handle.
++               */
++              if (acpi_id == 0)
++                      return acpi_id;
++              else
++                      return apic_id;
++      }
+ #ifdef CONFIG_SMP
+       for_each_possible_cpu(i) {
diff --git a/queue-3.2/acpica-put-back-the-call-to-acpi_os_validate_address.patch b/queue-3.2/acpica-put-back-the-call-to-acpi_os_validate_address.patch
new file mode 100644 (file)
index 0000000..5c26585
--- /dev/null
@@ -0,0 +1,56 @@
+From da4d8b287abe783d30e968155614531a0937d090 Mon Sep 17 00:00:00 2001
+From: Lin Ming <ming.m.lin@intel.com>
+Date: Tue, 29 Nov 2011 22:13:35 +0800
+Subject: ACPICA: Put back the call to acpi_os_validate_address
+
+From: Lin Ming <ming.m.lin@intel.com>
+
+commit da4d8b287abe783d30e968155614531a0937d090 upstream.
+
+The call to acpi_os_validate_address in acpi_ds_get_region_arguments was
+removed by mistake in commit 9ad19ac(ACPICA: Split large dsopcode and
+dsload.c files).
+
+Put it back.
+
+Reported-and-bisected-by: Luca Tettamanti <kronos.it@gmail.com>
+Signed-off-by: Lin Ming <ming.m.lin@intel.com>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/acpica/dsargs.c |   24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/drivers/acpi/acpica/dsargs.c
++++ b/drivers/acpi/acpica/dsargs.c
+@@ -387,5 +387,29 @@ acpi_status acpi_ds_get_region_arguments
+       status = acpi_ds_execute_arguments(node, node->parent,
+                                          extra_desc->extra.aml_length,
+                                          extra_desc->extra.aml_start);
++      if (ACPI_FAILURE(status)) {
++              return_ACPI_STATUS(status);
++      }
++
++      /* Validate the region address/length via the host OS */
++
++      status = acpi_os_validate_address(obj_desc->region.space_id,
++                                        obj_desc->region.address,
++                                        (acpi_size) obj_desc->region.length,
++                                        acpi_ut_get_node_name(node));
++
++      if (ACPI_FAILURE(status)) {
++              /*
++               * Invalid address/length. We will emit an error message and mark
++               * the region as invalid, so that it will cause an additional error if
++               * it is ever used. Then return AE_OK.
++               */
++              ACPI_EXCEPTION((AE_INFO, status,
++                              "During address validation of OpRegion [%4.4s]",
++                              node->name.ascii));
++              obj_desc->common.flags |= AOPOBJ_INVALID;
++              status = AE_OK;
++      }
++
+       return_ACPI_STATUS(status);
+ }
diff --git a/queue-3.2/bcma-invalidate-the-mapped-core-over-suspend-resume.patch b/queue-3.2/bcma-invalidate-the-mapped-core-over-suspend-resume.patch
new file mode 100644 (file)
index 0000000..89996e4
--- /dev/null
@@ -0,0 +1,42 @@
+From 28e7d218da975f6ae1751e293aed938952c55c98 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Fri, 13 Jan 2012 23:58:38 +0100
+Subject: bcma: invalidate the mapped core over suspend/resume
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Rafał Miłecki <zajec5@gmail.com>
+
+commit 28e7d218da975f6ae1751e293aed938952c55c98 upstream.
+
+This clears the currently mapped core when suspending, to force
+re-mapping after resume. Without that we were touching default core
+registers believing some other core is mapped. Such a behaviour
+resulted in lockups on some machines.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/bcma/host_pci.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -227,11 +227,14 @@ static void bcma_host_pci_remove(struct
+ #ifdef CONFIG_PM
+ static int bcma_host_pci_suspend(struct pci_dev *dev, pm_message_t state)
+ {
++      struct bcma_bus *bus = pci_get_drvdata(dev);
++
+       /* Host specific */
+       pci_save_state(dev);
+       pci_disable_device(dev);
+       pci_set_power_state(dev, pci_choose_state(dev, state));
++      bus->mapped_core = NULL;
+       return 0;
+ }
diff --git a/queue-3.2/cx23885-dvb-check-if-dvb_attach-succeded.patch b/queue-3.2/cx23885-dvb-check-if-dvb_attach-succeded.patch
new file mode 100644 (file)
index 0000000..a833a1b
--- /dev/null
@@ -0,0 +1,34 @@
+From a7c8aadad39428b64d26c3971d967f8314e2397d Mon Sep 17 00:00:00 2001
+From: Miroslav Slugen <thunder.mmm@gmail.com>
+Date: Sun, 11 Dec 2011 18:57:58 -0300
+Subject: [media] cx23885-dvb: check if dvb_attach() succeded
+
+From: Miroslav Slugen <thunder.mmm@gmail.com>
+
+commit a7c8aadad39428b64d26c3971d967f8314e2397d upstream.
+
+Fix possible null dereference for Leadtek DTV 3200H
+XC4000 tuner when no firmware file available.
+
+Signed-off-by: Miroslav Slugen <thunder.mmm@gmail.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/cx23885/cx23885-dvb.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/media/video/cx23885/cx23885-dvb.c
++++ b/drivers/media/video/cx23885/cx23885-dvb.c
+@@ -940,6 +940,11 @@ static int dvb_register(struct cx23885_t
+                       fe = dvb_attach(xc4000_attach, fe0->dvb.frontend,
+                                       &dev->i2c_bus[1].i2c_adap, &cfg);
++                      if (!fe) {
++                              printk(KERN_ERR "%s/2: xc4000 attach failed\n",
++                                     dev->name);
++                              goto frontend_detach;
++                      }
+               }
+               break;
+       case CX23885_BOARD_TBS_6920:
diff --git a/queue-3.2/cx88-fix-don-t-duplicate-xc4000-entry-for-radio.patch b/queue-3.2/cx88-fix-don-t-duplicate-xc4000-entry-for-radio.patch
new file mode 100644 (file)
index 0000000..34a6da8
--- /dev/null
@@ -0,0 +1,93 @@
+From b6854e3f31402476bcc9d2f41570389fa491de17 Mon Sep 17 00:00:00 2001
+From: Miroslav Slugen <thunder.mmm@gmail.com>
+Date: Sun, 11 Dec 2011 19:00:06 -0300
+Subject: [media] cx88: fix: don't duplicate xc4000 entry for radio
+
+From: Miroslav Slugen <thunder.mmm@gmail.com>
+
+commit b6854e3f31402476bcc9d2f41570389fa491de17 upstream.
+
+All radio tuners in cx88 driver using same address for radio and tuner,
+so there is no need to probe it twice for same tuner and we can use
+radio_type UNSET, this also fix broken radio since kernel 2.6.39-rc1
+for those tuners.
+
+Signed-off-by: Miroslav Slugen <thunder.mmm@gmail.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/cx88/cx88-cards.c |   24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+--- a/drivers/media/video/cx88/cx88-cards.c
++++ b/drivers/media/video/cx88/cx88-cards.c
+@@ -1573,8 +1573,8 @@ static const struct cx88_board cx88_boar
+               .name           = "Pinnacle Hybrid PCTV",
+               .tuner_type     = TUNER_XC2028,
+               .tuner_addr     = 0x61,
+-              .radio_type     = TUNER_XC2028,
+-              .radio_addr     = 0x61,
++              .radio_type     = UNSET,
++              .radio_addr     = ADDR_UNSET,
+               .input          = { {
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+@@ -1611,8 +1611,8 @@ static const struct cx88_board cx88_boar
+               .name           = "Leadtek TV2000 XP Global",
+               .tuner_type     = TUNER_XC2028,
+               .tuner_addr     = 0x61,
+-              .radio_type     = TUNER_XC2028,
+-              .radio_addr     = 0x61,
++              .radio_type     = UNSET,
++              .radio_addr     = ADDR_UNSET,
+               .input          = { {
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+@@ -2043,8 +2043,8 @@ static const struct cx88_board cx88_boar
+               .name           = "Terratec Cinergy HT PCI MKII",
+               .tuner_type     = TUNER_XC2028,
+               .tuner_addr     = 0x61,
+-              .radio_type     = TUNER_XC2028,
+-              .radio_addr     = 0x61,
++              .radio_type     = UNSET,
++              .radio_addr     = ADDR_UNSET,
+               .input          = { {
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+@@ -2082,9 +2082,9 @@ static const struct cx88_board cx88_boar
+       [CX88_BOARD_WINFAST_DTV1800H] = {
+               .name           = "Leadtek WinFast DTV1800 Hybrid",
+               .tuner_type     = TUNER_XC2028,
+-              .radio_type     = TUNER_XC2028,
++              .radio_type     = UNSET,
+               .tuner_addr     = 0x61,
+-              .radio_addr     = 0x61,
++              .radio_addr     = ADDR_UNSET,
+               /*
+                * GPIO setting
+                *
+@@ -2123,9 +2123,9 @@ static const struct cx88_board cx88_boar
+       [CX88_BOARD_WINFAST_DTV1800H_XC4000] = {
+               .name           = "Leadtek WinFast DTV1800 H (XC4000)",
+               .tuner_type     = TUNER_XC4000,
+-              .radio_type     = TUNER_XC4000,
++              .radio_type     = UNSET,
+               .tuner_addr     = 0x61,
+-              .radio_addr     = 0x61,
++              .radio_addr     = ADDR_UNSET,
+               /*
+                * GPIO setting
+                *
+@@ -2164,9 +2164,9 @@ static const struct cx88_board cx88_boar
+       [CX88_BOARD_WINFAST_DTV2000H_PLUS] = {
+               .name           = "Leadtek WinFast DTV2000 H PLUS",
+               .tuner_type     = TUNER_XC4000,
+-              .radio_type     = TUNER_XC4000,
++              .radio_type     = UNSET,
+               .tuner_addr     = 0x61,
+-              .radio_addr     = 0x61,
++              .radio_addr     = ADDR_UNSET,
+               /*
+                * GPIO
+                *   2: 1: mute audio
diff --git a/queue-3.2/i2c-omap-correct-sysc-register-offset-for-omap4.patch b/queue-3.2/i2c-omap-correct-sysc-register-offset-for-omap4.patch
new file mode 100644 (file)
index 0000000..c64405c
--- /dev/null
@@ -0,0 +1,32 @@
+From 2727b1753934e154931d6b3bdf20c9b2398457a2 Mon Sep 17 00:00:00 2001
+From: Alexander Aring <a.aring@phytec.de>
+Date: Thu, 8 Dec 2011 15:43:53 +0100
+Subject: I2C: OMAP: correct SYSC register offset for OMAP4
+
+From: Alexander Aring <a.aring@phytec.de>
+
+commit 2727b1753934e154931d6b3bdf20c9b2398457a2 upstream.
+
+Correct OMAP_I2C_SYSC_REG offset in omap4 register map.
+Offset 0x20 is reserved and OMAP_I2C_SYSC_REG has 0x10 as offset.
+
+Signed-off-by: Alexander Aring <a.aring@phytec.de>
+[khilman@ti.com: minor changelog edits]
+Signed-off-by: Kevin Hilman <khilman@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/i2c/busses/i2c-omap.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/i2c/busses/i2c-omap.c
++++ b/drivers/i2c/busses/i2c-omap.c
+@@ -235,7 +235,7 @@ static const u8 reg_map_ip_v2[] = {
+       [OMAP_I2C_BUF_REG] = 0x94,
+       [OMAP_I2C_CNT_REG] = 0x98,
+       [OMAP_I2C_DATA_REG] = 0x9c,
+-      [OMAP_I2C_SYSC_REG] = 0x20,
++      [OMAP_I2C_SYSC_REG] = 0x10,
+       [OMAP_I2C_CON_REG] = 0xa4,
+       [OMAP_I2C_OA_REG] = 0xa8,
+       [OMAP_I2C_SA_REG] = 0xac,
index 4b6bf68d7badd6c57ceb9d12f0721b96dc662213..396976a7f81215547da85e2d55a12d459c531f60 100644 (file)
@@ -100,3 +100,17 @@ intel_idle-fix-api-misuse.patch
 acpi-store-srat-table-revision.patch
 acpi-x86-use-srat-table-rev-to-use-8bit-or-32bit-pxm-fields-x86-x86-64.patch
 acpi-ia64-use-srat-table-rev-to-use-8bit-or-16-32bit-pxm-fields-ia64.patch
+acpica-put-back-the-call-to-acpi_os_validate_address.patch
+acpi-processor-fix-acpi_get_cpuid-for-up-processor.patch
+sym53c8xx-fix-null-pointer-dereference-in-slave_destroy.patch
+target-set-response-format-in-inquiry-response.patch
+target-set-additional-sense-length-field-in-sense-data.patch
+bcma-invalidate-the-mapped-core-over-suspend-resume.patch
+cx23885-dvb-check-if-dvb_attach-succeded.patch
+cx88-fix-don-t-duplicate-xc4000-entry-for-radio.patch
+tuner-fix-numberspace-conflict-between-xc4000-and-pti-5nf05-tuners.patch
+tracepoints-module-fix-disabling-tracepoints-with-taint-crap-or-oot.patch
+i2c-omap-correct-sysc-register-offset-for-omap4.patch
+x86-uv2-fix-new-uv2-hardware-by-using-native-uv2-broadcast-mode.patch
+x86-uv2-fix-bau-destination-timeout-initialization.patch
+x86-uv2-work-around-bau-bug.patch
diff --git a/queue-3.2/sym53c8xx-fix-null-pointer-dereference-in-slave_destroy.patch b/queue-3.2/sym53c8xx-fix-null-pointer-dereference-in-slave_destroy.patch
new file mode 100644 (file)
index 0000000..abe0201
--- /dev/null
@@ -0,0 +1,34 @@
+From cced5041ed5a2d1352186510944b0ddfbdbe4c0b Mon Sep 17 00:00:00 2001
+From: Stratos Psomadakis <psomas@gentoo.org>
+Date: Sun, 4 Dec 2011 02:23:54 +0200
+Subject: [SCSI] sym53c8xx: Fix NULL pointer dereference in slave_destroy
+
+From: Stratos Psomadakis <psomas@gentoo.org>
+
+commit cced5041ed5a2d1352186510944b0ddfbdbe4c0b upstream.
+
+sym53c8xx_slave_destroy unconditionally assumes that sym53c8xx_slave_alloc has
+succesesfully allocated a sym_lcb. This can lead to a NULL pointer dereference
+(exposed by commit 4e6c82b).
+
+Signed-off-by: Stratos Psomadakis <psomas@gentoo.org>
+Signed-off-by: James Bottomley <JBottomley@Parallels.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/scsi/sym53c8xx_2/sym_glue.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
++++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
+@@ -839,6 +839,10 @@ static void sym53c8xx_slave_destroy(stru
+       struct sym_lcb *lp = sym_lp(tp, sdev->lun);
+       unsigned long flags;
++      /* if slave_alloc returned before allocating a sym_lcb, return */
++      if (!lp)
++              return;
++
+       spin_lock_irqsave(np->s.host->host_lock, flags);
+       if (lp->busy_itlq || lp->busy_itl) {
diff --git a/queue-3.2/target-set-additional-sense-length-field-in-sense-data.patch b/queue-3.2/target-set-additional-sense-length-field-in-sense-data.patch
new file mode 100644 (file)
index 0000000..bbf55b7
--- /dev/null
@@ -0,0 +1,172 @@
+From 895f3022523361e9b383cf48f51feb1f7d5e7e53 Mon Sep 17 00:00:00 2001
+From: Roland Dreier <roland@purestorage.com>
+Date: Tue, 13 Dec 2011 14:55:33 -0800
+Subject: target: Set additional sense length field in sense data
+
+From: Roland Dreier <roland@purestorage.com>
+
+commit 895f3022523361e9b383cf48f51feb1f7d5e7e53 upstream.
+
+The target code was not setting the additional sense length field in the
+sense data it returned, which meant that at least the Linux stack
+ignored the ASC/ASCQ fields.  For example, without this patch, on a
+tcm_loop device:
+
+    # sg_raw -v /dev/sda 2 0 0 0 0 0
+
+gives
+
+        cdb to send: 02 00 00 00 00 00
+    SCSI Status: Check Condition
+
+    Sense Information:
+     Fixed format, current;  Sense key: Illegal Request
+      Raw sense data (in hex):
+            70 00 05 00 00 00 00 00
+
+while after the patch we correctly get the following (which matches what
+a regular disk returns):
+
+        cdb to send: 02 00 00 00 00 00
+    SCSI Status: Check Condition
+
+    Sense Information:
+     Fixed format, current;  Sense key: Illegal Request
+     Additional sense: Invalid command operation code
+     Raw sense data (in hex):
+            70 00 05 00 00 00 00 0a  00 00 00 00 20 00 00 00
+            00 00
+
+Signed-off-by: Roland Dreier <roland@purestorage.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/target/target_core_transport.c |   14 ++++++++++++++
+ include/target/target_core_base.h      |    1 +
+ 2 files changed, 15 insertions(+)
+
+--- a/drivers/target/target_core_transport.c
++++ b/drivers/target/target_core_transport.c
+@@ -4353,6 +4353,7 @@ int transport_send_check_condition_and_s
+       case TCM_NON_EXISTENT_LUN:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ILLEGAL REQUEST */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               /* LOGICAL UNIT NOT SUPPORTED */
+@@ -4362,6 +4363,7 @@ int transport_send_check_condition_and_s
+       case TCM_SECTOR_COUNT_TOO_MANY:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ILLEGAL REQUEST */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               /* INVALID COMMAND OPERATION CODE */
+@@ -4370,6 +4372,7 @@ int transport_send_check_condition_and_s
+       case TCM_UNKNOWN_MODE_PAGE:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ILLEGAL REQUEST */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               /* INVALID FIELD IN CDB */
+@@ -4378,6 +4381,7 @@ int transport_send_check_condition_and_s
+       case TCM_CHECK_CONDITION_ABORT_CMD:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ABORTED COMMAND */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+               /* BUS DEVICE RESET FUNCTION OCCURRED */
+@@ -4387,6 +4391,7 @@ int transport_send_check_condition_and_s
+       case TCM_INCORRECT_AMOUNT_OF_DATA:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ABORTED COMMAND */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+               /* WRITE ERROR */
+@@ -4397,6 +4402,7 @@ int transport_send_check_condition_and_s
+       case TCM_INVALID_CDB_FIELD:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ABORTED COMMAND */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+               /* INVALID FIELD IN CDB */
+@@ -4405,6 +4411,7 @@ int transport_send_check_condition_and_s
+       case TCM_INVALID_PARAMETER_LIST:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ABORTED COMMAND */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+               /* INVALID FIELD IN PARAMETER LIST */
+@@ -4413,6 +4420,7 @@ int transport_send_check_condition_and_s
+       case TCM_UNEXPECTED_UNSOLICITED_DATA:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ABORTED COMMAND */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+               /* WRITE ERROR */
+@@ -4423,6 +4431,7 @@ int transport_send_check_condition_and_s
+       case TCM_SERVICE_CRC_ERROR:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ABORTED COMMAND */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+               /* PROTOCOL SERVICE CRC ERROR */
+@@ -4433,6 +4442,7 @@ int transport_send_check_condition_and_s
+       case TCM_SNACK_REJECTED:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ABORTED COMMAND */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+               /* READ ERROR */
+@@ -4443,6 +4453,7 @@ int transport_send_check_condition_and_s
+       case TCM_WRITE_PROTECTED:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* DATA PROTECT */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = DATA_PROTECT;
+               /* WRITE PROTECTED */
+@@ -4451,6 +4462,7 @@ int transport_send_check_condition_and_s
+       case TCM_CHECK_CONDITION_UNIT_ATTENTION:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* UNIT ATTENTION */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
+               core_scsi3_ua_for_check_condition(cmd, &asc, &ascq);
+@@ -4460,6 +4472,7 @@ int transport_send_check_condition_and_s
+       case TCM_CHECK_CONDITION_NOT_READY:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* Not Ready */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = NOT_READY;
+               transport_get_sense_codes(cmd, &asc, &ascq);
+@@ -4470,6 +4483,7 @@ int transport_send_check_condition_and_s
+       default:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
++              buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ILLEGAL REQUEST */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               /* LOGICAL UNIT COMMUNICATION FAILURE */
+--- a/include/target/target_core_base.h
++++ b/include/target/target_core_base.h
+@@ -34,6 +34,7 @@
+ #define TRANSPORT_SENSE_BUFFER                        SCSI_SENSE_BUFFERSIZE
+ /* Used by transport_send_check_condition_and_sense() */
+ #define SPC_SENSE_KEY_OFFSET                  2
++#define SPC_ADD_SENSE_LEN_OFFSET              7
+ #define SPC_ASC_KEY_OFFSET                    12
+ #define SPC_ASCQ_KEY_OFFSET                   13
+ #define TRANSPORT_IQN_LEN                     224
diff --git a/queue-3.2/target-set-response-format-in-inquiry-response.patch b/queue-3.2/target-set-response-format-in-inquiry-response.patch
new file mode 100644 (file)
index 0000000..68ac2d1
--- /dev/null
@@ -0,0 +1,42 @@
+From ce136176fea522fc8f4c16dcae7e8ed1d890ca39 Mon Sep 17 00:00:00 2001
+From: Roland Dreier <roland@purestorage.com>
+Date: Tue, 6 Dec 2011 10:02:09 -0800
+Subject: target: Set response format in INQUIRY response
+
+From: Roland Dreier <roland@purestorage.com>
+
+commit ce136176fea522fc8f4c16dcae7e8ed1d890ca39 upstream.
+
+Current SCSI specs say that the "response format" field in the standard
+INQUIRY response should be set to 2, and all the real SCSI devices I
+have do put 2 here.  So let's do that too.
+
+Signed-off-by: Roland Dreier <roland@purestorage.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/target/target_core_cdb.c |   12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/target/target_core_cdb.c
++++ b/drivers/target/target_core_cdb.c
+@@ -94,6 +94,18 @@ target_emulate_inquiry_std(struct se_cmd
+       buf[2] = dev->transport->get_device_rev(dev);
+       /*
++       * NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2
++       *
++       * SPC4 says:
++       *   A RESPONSE DATA FORMAT field set to 2h indicates that the
++       *   standard INQUIRY data is in the format defined in this
++       *   standard. Response data format values less than 2h are
++       *   obsolete. Response data format values greater than 2h are
++       *   reserved.
++       */
++      buf[3] = 2;
++
++      /*
+        * Enable SCCS and TPGS fields for Emulated ALUA
+        */
+       if (dev->se_sub_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED)
diff --git a/queue-3.2/tracepoints-module-fix-disabling-tracepoints-with-taint-crap-or-oot.patch b/queue-3.2/tracepoints-module-fix-disabling-tracepoints-with-taint-crap-or-oot.patch
new file mode 100644 (file)
index 0000000..f0688c9
--- /dev/null
@@ -0,0 +1,47 @@
+From c10076c4304083af15a41f6bc5e657e781c1f9a6 Mon Sep 17 00:00:00 2001
+From: Steven Rostedt <srostedt@redhat.com>
+Date: Fri, 13 Jan 2012 21:40:59 -0500
+Subject: tracepoints/module: Fix disabling tracepoints with taint CRAP or OOT
+
+From: Steven Rostedt <srostedt@redhat.com>
+
+commit c10076c4304083af15a41f6bc5e657e781c1f9a6 upstream.
+
+Tracepoints are disabled for tainted modules, which is usually because the
+module is either proprietary or was forced, and we don't want either of them
+using kernel tracepoints.
+
+But, a module can also be tainted by being in the staging directory or
+compiled out of tree. Either is fine for use with tracepoints, no need
+to punish them.  I found this out when I noticed that my sample trace event
+module, when done out of tree, stopped working.
+
+Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+Cc: Ben Hutchings <ben@decadent.org.uk>
+Cc: Dave Jones <davej@redhat.com>
+Cc: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: Rusty Russell <rusty@rustcorp.com.au>
+Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ kernel/tracepoint.c |    7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/kernel/tracepoint.c
++++ b/kernel/tracepoint.c
+@@ -634,10 +634,11 @@ static int tracepoint_module_coming(stru
+       int ret = 0;
+       /*
+-       * We skip modules that tain the kernel, especially those with different
+-       * module header (for forced load), to make sure we don't cause a crash.
++       * We skip modules that taint the kernel, especially those with different
++       * module headers (for forced load), to make sure we don't cause a crash.
++       * Staging and out-of-tree GPL modules are fine.
+        */
+-      if (mod->taints)
++      if (mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP)))
+               return 0;
+       mutex_lock(&tracepoints_mutex);
+       tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL);
diff --git a/queue-3.2/tuner-fix-numberspace-conflict-between-xc4000-and-pti-5nf05-tuners.patch b/queue-3.2/tuner-fix-numberspace-conflict-between-xc4000-and-pti-5nf05-tuners.patch
new file mode 100644 (file)
index 0000000..62fa82e
--- /dev/null
@@ -0,0 +1,39 @@
+From cd4ca7afc61d3b18fcd635002459fb6b1d701099 Mon Sep 17 00:00:00 2001
+From: Miroslav Slugen <thunder.mmm@gmail.com>
+Date: Sun, 11 Dec 2011 18:47:32 -0300
+Subject: [media] tuner: Fix numberspace conflict between xc4000 and pti 5nf05 tuners
+
+From: Miroslav Slugen <thunder.mmm@gmail.com>
+
+commit cd4ca7afc61d3b18fcd635002459fb6b1d701099 upstream.
+
+Update xc4000 tuner definition, number 81 is already in use by
+TUNER_PARTSNIC_PTI_5NF05.
+
+Signed-off-by: Miroslav Slugen <thunder.mmm@gmail.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/media/tuner.h |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/include/media/tuner.h
++++ b/include/media/tuner.h
+@@ -127,7 +127,6 @@
+ #define TUNER_PHILIPS_FMD1216MEX_MK3  78
+ #define TUNER_PHILIPS_FM1216MK5               79
+ #define TUNER_PHILIPS_FQ1216LME_MK3   80      /* Active loopthrough, no FM */
+-#define TUNER_XC4000                  81      /* Xceive Silicon Tuner */
+ #define TUNER_PARTSNIC_PTI_5NF05      81
+ #define TUNER_PHILIPS_CU1216L           82
+@@ -136,6 +135,8 @@
+ #define TUNER_PHILIPS_FQ1236_MK5      85      /* NTSC, TDA9885, no FM radio */
+ #define TUNER_TENA_TNF_5337           86
++#define TUNER_XC4000                  87      /* Xceive Silicon Tuner */
++
+ /* tv card specific */
+ #define TDA9887_PRESENT               (1<<0)
+ #define TDA9887_PORT1_INACTIVE                (1<<1)
diff --git a/queue-3.2/x86-uv2-fix-bau-destination-timeout-initialization.patch b/queue-3.2/x86-uv2-fix-bau-destination-timeout-initialization.patch
new file mode 100644 (file)
index 0000000..a7856de
--- /dev/null
@@ -0,0 +1,64 @@
+From d059f9fa84a30e04279c6ff615e9e2cf3b260191 Mon Sep 17 00:00:00 2001
+From: Cliff Wickman <cpw@sgi.com>
+Date: Mon, 16 Jan 2012 15:18:48 -0600
+Subject: x86/UV2: Fix BAU destination timeout initialization
+
+From: Cliff Wickman <cpw@sgi.com>
+
+commit d059f9fa84a30e04279c6ff615e9e2cf3b260191 upstream.
+
+Move the call to enable_timeouts() forward so that
+BAU_MISC_CONTROL is initialized before using it in
+calculate_destination_timeout().
+
+Fix the calculation of a BAU destination timeout
+for UV2 (in calculate_destination_timeout()).
+
+Signed-off-by: Cliff Wickman <cpw@sgi.com>
+Link: http://lkml.kernel.org/r/20120116211848.GB5767@sgi.com
+Signed-off-by: Ingo Molnar <mingo@elte.hu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/platform/uv/tlb_uv.c |   13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+--- a/arch/x86/platform/uv/tlb_uv.c
++++ b/arch/x86/platform/uv/tlb_uv.c
+@@ -1617,14 +1617,14 @@ static int calculate_destination_timeout
+               ts_ns = base * mult1 * mult2;
+               ret = ts_ns / 1000;
+       } else {
+-              /* 4 bits  0/1 for 10/80us, 3 bits of multiplier */
+-              mmr_image = uv_read_local_mmr(UVH_AGING_PRESCALE_SEL);
++              /* 4 bits  0/1 for 10/80us base, 3 bits of multiplier */
++              mmr_image = uv_read_local_mmr(UVH_LB_BAU_MISC_CONTROL);
+               mmr_image = (mmr_image & UV_SA_MASK) >> UV_SA_SHFT;
+               if (mmr_image & (1L << UV2_ACK_UNITS_SHFT))
+-                      mult1 = 80;
++                      base = 80;
+               else
+-                      mult1 = 10;
+-              base = mmr_image & UV2_ACK_MASK;
++                      base = 10;
++              mult1 = mmr_image & UV2_ACK_MASK;
+               ret = mult1 * base;
+       }
+       return ret;
+@@ -1886,6 +1886,8 @@ static int __init uv_bau_init(void)
+                       uv_base_pnode = uv_blade_to_pnode(uvhub);
+       }
++      enable_timeouts();
++
+       if (init_per_cpu(nuvhubs, uv_base_pnode)) {
+               nobau = 1;
+               return 0;
+@@ -1896,7 +1898,6 @@ static int __init uv_bau_init(void)
+               if (uv_blade_nr_possible_cpus(uvhub))
+                       init_uvhub(uvhub, vector, uv_base_pnode);
+-      enable_timeouts();
+       alloc_intr_gate(vector, uv_bau_message_intr1);
+       for_each_possible_blade(uvhub) {
diff --git a/queue-3.2/x86-uv2-fix-new-uv2-hardware-by-using-native-uv2-broadcast-mode.patch b/queue-3.2/x86-uv2-fix-new-uv2-hardware-by-using-native-uv2-broadcast-mode.patch
new file mode 100644 (file)
index 0000000..ae36790
--- /dev/null
@@ -0,0 +1,345 @@
+From da87c937e5a2374686edd58df06cfd5050b125fa Mon Sep 17 00:00:00 2001
+From: Cliff Wickman <cpw@sgi.com>
+Date: Mon, 16 Jan 2012 15:17:50 -0600
+Subject: x86/UV2: Fix new UV2 hardware by using native UV2 broadcast mode
+
+From: Cliff Wickman <cpw@sgi.com>
+
+commit da87c937e5a2374686edd58df06cfd5050b125fa upstream.
+
+Update the use of the Broadcast Assist Unit on SGI Altix UV2 to
+the use of native UV2 mode on new hardware (not the legacy mode).
+
+UV2 native mode has a different format for a broadcast message.
+We also need quick differentiaton between UV1 and UV2.
+
+Signed-off-by: Cliff Wickman <cpw@sgi.com>
+Link: http://lkml.kernel.org/r/20120116211750.GA5767@sgi.com
+Signed-off-by: Ingo Molnar <mingo@elte.hu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/include/asm/uv/uv_bau.h |   93 ++++++++++++++++++++++++++++++++++++---
+ arch/x86/platform/uv/tlb_uv.c    |   88 +++++++++++++++++++++++++++---------
+ 2 files changed, 151 insertions(+), 30 deletions(-)
+
+--- a/arch/x86/include/asm/uv/uv_bau.h
++++ b/arch/x86/include/asm/uv/uv_bau.h
+@@ -65,7 +65,7 @@
+  * UV2: Bit 19 selects between
+  *  (0): 10 microsecond timebase and
+  *  (1): 80 microseconds
+- *  we're using 655us, similar to UV1: 65 units of 10us
++ *  we're using 560us, similar to UV1: 65 units of 10us
+  */
+ #define UV1_INTD_SOFT_ACK_TIMEOUT_PERIOD (9UL)
+ #define UV2_INTD_SOFT_ACK_TIMEOUT_PERIOD (15UL)
+@@ -235,10 +235,10 @@ struct bau_msg_payload {
+ /*
+- * Message header:  16 bytes (128 bits) (bytes 0x30-0x3f of descriptor)
++ * UV1 Message header:  16 bytes (128 bits) (bytes 0x30-0x3f of descriptor)
+  * see table 4.2.3.0.1 in broacast_assist spec.
+  */
+-struct bau_msg_header {
++struct uv1_bau_msg_header {
+       unsigned int    dest_subnodeid:6;       /* must be 0x10, for the LB */
+       /* bits 5:0 */
+       unsigned int    base_dest_nasid:15;     /* nasid of the first bit */
+@@ -318,19 +318,87 @@ struct bau_msg_header {
+ };
+ /*
++ * UV2 Message header:  16 bytes (128 bits) (bytes 0x30-0x3f of descriptor)
++ * see figure 9-2 of harp_sys.pdf
++ */
++struct uv2_bau_msg_header {
++      unsigned int    base_dest_nasid:15;     /* nasid of the first bit */
++      /* bits 14:0 */                         /* in uvhub map */
++      unsigned int    dest_subnodeid:5;       /* must be 0x10, for the LB */
++      /* bits 19:15 */
++      unsigned int    rsvd_1:1;               /* must be zero */
++      /* bit 20 */
++      /* Address bits 59:21 */
++      /* bits 25:2 of address (44:21) are payload */
++      /* these next 24 bits become bytes 12-14 of msg */
++      /* bits 28:21 land in byte 12 */
++      unsigned int    replied_to:1;           /* sent as 0 by the source to
++                                                 byte 12 */
++      /* bit 21 */
++      unsigned int    msg_type:3;             /* software type of the
++                                                 message */
++      /* bits 24:22 */
++      unsigned int    canceled:1;             /* message canceled, resource
++                                                 is to be freed*/
++      /* bit 25 */
++      unsigned int    payload_1:3;            /* not currently used */
++      /* bits 28:26 */
++
++      /* bits 36:29 land in byte 13 */
++      unsigned int    payload_2a:3;           /* not currently used */
++      unsigned int    payload_2b:5;           /* not currently used */
++      /* bits 36:29 */
++
++      /* bits 44:37 land in byte 14 */
++      unsigned int    payload_3:8;            /* not currently used */
++      /* bits 44:37 */
++
++      unsigned int    rsvd_2:7;               /* reserved */
++      /* bits 51:45 */
++      unsigned int    swack_flag:1;           /* software acknowledge flag */
++      /* bit 52 */
++      unsigned int    rsvd_3a:3;              /* must be zero */
++      unsigned int    rsvd_3b:8;              /* must be zero */
++      unsigned int    rsvd_3c:8;              /* must be zero */
++      unsigned int    rsvd_3d:3;              /* must be zero */
++      /* bits 74:53 */
++      unsigned int    fairness:3;             /* usually zero */
++      /* bits 77:75 */
++
++      unsigned int    sequence:16;            /* message sequence number */
++      /* bits 93:78  Suppl_A  */
++      unsigned int    chaining:1;             /* next descriptor is part of
++                                                 this activation*/
++      /* bit 94 */
++      unsigned int    multilevel:1;           /* multi-level multicast
++                                                 format */
++      /* bit 95 */
++      unsigned int    rsvd_4:24;              /* ordered / source node /
++                                                 source subnode / aging
++                                                 must be zero */
++      /* bits 119:96 */
++      unsigned int    command:8;              /* message type */
++      /* bits 127:120 */
++};
++
++/*
+  * The activation descriptor:
+  * The format of the message to send, plus all accompanying control
+  * Should be 64 bytes
+  */
+ struct bau_desc {
+-      struct pnmask                   distribution;
++      struct pnmask                           distribution;
+       /*
+        * message template, consisting of header and payload:
+        */
+-      struct bau_msg_header           header;
+-      struct bau_msg_payload          payload;
++      union bau_msg_header {
++              struct uv1_bau_msg_header       uv1_hdr;
++              struct uv2_bau_msg_header       uv2_hdr;
++      } header;
++
++      struct bau_msg_payload                  payload;
+ };
+-/*
++/* UV1:
+  *   -payload--    ---------header------
+  *   bytes 0-11    bits 41-56  bits 58-81
+  *       A           B  (2)      C (3)
+@@ -340,6 +408,16 @@ struct bau_desc {
+  *   bytes 0-11  bytes 12-14  bytes 16-17  (byte 15 filled in by hw as vector)
+  *   ------------payload queue-----------
+  */
++/* UV2:
++ *   -payload--    ---------header------
++ *   bytes 0-11    bits 70-78  bits 21-44
++ *       A           B  (2)      C (3)
++ *
++ *            A/B/C are moved to:
++ *       A            C          B
++ *   bytes 0-11  bytes 12-14  bytes 16-17  (byte 15 filled in by hw as vector)
++ *   ------------payload queue-----------
++ */
+ /*
+  * The payload queue on the destination side is an array of these.
+@@ -511,6 +589,7 @@ struct bau_control {
+       short                   osnode;
+       short                   uvhub_cpu;
+       short                   uvhub;
++      short                   uvhub_version;
+       short                   cpus_in_socket;
+       short                   cpus_in_uvhub;
+       short                   partition_base_pnode;
+--- a/arch/x86/platform/uv/tlb_uv.c
++++ b/arch/x86/platform/uv/tlb_uv.c
+@@ -573,7 +573,7 @@ static int wait_completion(struct bau_de
+               right_shift = ((cpu - UV_CPUS_PER_AS) * UV_ACT_STATUS_SIZE);
+       }
+-      if (is_uv1_hub())
++      if (bcp->uvhub_version == 1)
+               return uv1_wait_completion(bau_desc, mmr_offset, right_shift,
+                                                               bcp, try);
+       else
+@@ -757,15 +757,22 @@ int uv_flush_send_and_wait(struct bau_de
+ {
+       int seq_number = 0;
+       int completion_stat = 0;
++      int uv1 = 0;
+       long try = 0;
+       unsigned long index;
+       cycles_t time1;
+       cycles_t time2;
+       struct ptc_stats *stat = bcp->statp;
+       struct bau_control *hmaster = bcp->uvhub_master;
++      struct uv1_bau_msg_header *uv1_hdr = NULL;
++      struct uv2_bau_msg_header *uv2_hdr = NULL;
+-      if (is_uv1_hub())
++      if (bcp->uvhub_version == 1) {
++              uv1 = 1;
+               uv1_throttle(hmaster, stat);
++              uv1_hdr = &bau_desc->header.uv1_hdr;
++      } else
++              uv2_hdr = &bau_desc->header.uv2_hdr;
+       while (hmaster->uvhub_quiesce)
+               cpu_relax();
+@@ -773,14 +780,23 @@ int uv_flush_send_and_wait(struct bau_de
+       time1 = get_cycles();
+       do {
+               if (try == 0) {
+-                      bau_desc->header.msg_type = MSG_REGULAR;
++                      if (uv1)
++                              uv1_hdr->msg_type = MSG_REGULAR;
++                      else
++                              uv2_hdr->msg_type = MSG_REGULAR;
+                       seq_number = bcp->message_number++;
+               } else {
+-                      bau_desc->header.msg_type = MSG_RETRY;
++                      if (uv1)
++                              uv1_hdr->msg_type = MSG_RETRY;
++                      else
++                              uv2_hdr->msg_type = MSG_RETRY;
+                       stat->s_retry_messages++;
+               }
+-              bau_desc->header.sequence = seq_number;
++              if (uv1)
++                      uv1_hdr->sequence = seq_number;
++              else
++                      uv2_hdr->sequence = seq_number;
+               index = (1UL << AS_PUSH_SHIFT) | bcp->uvhub_cpu;
+               bcp->send_message = get_cycles();
+@@ -967,7 +983,7 @@ const struct cpumask *uv_flush_tlb_other
+               stat->s_ntargself++;
+       bau_desc = bcp->descriptor_base;
+-      bau_desc += ITEMS_PER_DESC * bcp->uvhub_cpu;
++      bau_desc += (ITEMS_PER_DESC * bcp->uvhub_cpu);
+       bau_uvhubs_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE);
+       if (set_distrib_bits(flush_mask, bcp, bau_desc, &locals, &remotes))
+               return NULL;
+@@ -1083,7 +1099,7 @@ static void __init enable_timeouts(void)
+                */
+               mmr_image |= (1L << SOFTACK_MSHIFT);
+               if (is_uv2_hub()) {
+-                      mmr_image |= (1L << UV2_LEG_SHFT);
++                      mmr_image &= ~(1L << UV2_LEG_SHFT);
+                       mmr_image |= (1L << UV2_EXT_SHFT);
+               }
+               write_mmr_misc_control(pnode, mmr_image);
+@@ -1432,12 +1448,15 @@ static void activation_descriptor_init(i
+ {
+       int i;
+       int cpu;
++      int uv1 = 0;
+       unsigned long gpa;
+       unsigned long m;
+       unsigned long n;
+       size_t dsize;
+       struct bau_desc *bau_desc;
+       struct bau_desc *bd2;
++      struct uv1_bau_msg_header *uv1_hdr;
++      struct uv2_bau_msg_header *uv2_hdr;
+       struct bau_control *bcp;
+       /*
+@@ -1451,6 +1470,8 @@ static void activation_descriptor_init(i
+       gpa = uv_gpa(bau_desc);
+       n = uv_gpa_to_gnode(gpa);
+       m = uv_gpa_to_offset(gpa);
++      if (is_uv1_hub())
++              uv1 = 1;
+       /* the 14-bit pnode */
+       write_mmr_descriptor_base(pnode, (n << UV_DESC_PSHIFT | m));
+@@ -1461,21 +1482,33 @@ static void activation_descriptor_init(i
+        */
+       for (i = 0, bd2 = bau_desc; i < (ADP_SZ * ITEMS_PER_DESC); i++, bd2++) {
+               memset(bd2, 0, sizeof(struct bau_desc));
+-              bd2->header.swack_flag =        1;
+-              /*
+-               * The base_dest_nasid set in the message header is the nasid
+-               * of the first uvhub in the partition. The bit map will
+-               * indicate destination pnode numbers relative to that base.
+-               * They may not be consecutive if nasid striding is being used.
+-               */
+-              bd2->header.base_dest_nasid =   UV_PNODE_TO_NASID(base_pnode);
+-              bd2->header.dest_subnodeid =    UV_LB_SUBNODEID;
+-              bd2->header.command =           UV_NET_ENDPOINT_INTD;
+-              bd2->header.int_both =          1;
+-              /*
+-               * all others need to be set to zero:
+-               *   fairness chaining multilevel count replied_to
+-               */
++              if (uv1) {
++                      uv1_hdr = &bd2->header.uv1_hdr;
++                      uv1_hdr->swack_flag =   1;
++                      /*
++                       * The base_dest_nasid set in the message header
++                       * is the nasid of the first uvhub in the partition.
++                       * The bit map will indicate destination pnode numbers
++                       * relative to that base. They may not be consecutive
++                       * if nasid striding is being used.
++                       */
++                      uv1_hdr->base_dest_nasid =
++                                              UV_PNODE_TO_NASID(base_pnode);
++                      uv1_hdr->dest_subnodeid =       UV_LB_SUBNODEID;
++                      uv1_hdr->command =              UV_NET_ENDPOINT_INTD;
++                      uv1_hdr->int_both =             1;
++                      /*
++                       * all others need to be set to zero:
++                       *   fairness chaining multilevel count replied_to
++                       */
++              } else {
++                      uv2_hdr = &bd2->header.uv2_hdr;
++                      uv2_hdr->swack_flag =   1;
++                      uv2_hdr->base_dest_nasid =
++                                              UV_PNODE_TO_NASID(base_pnode);
++                      uv2_hdr->dest_subnodeid =       UV_LB_SUBNODEID;
++                      uv2_hdr->command =              UV_NET_ENDPOINT_INTD;
++              }
+       }
+       for_each_present_cpu(cpu) {
+               if (pnode != uv_blade_to_pnode(uv_cpu_to_blade_id(cpu)))
+@@ -1728,6 +1761,14 @@ static int scan_sock(struct socket_desc
+               bcp->cpus_in_socket = sdp->num_cpus;
+               bcp->socket_master = *smasterp;
+               bcp->uvhub = bdp->uvhub;
++              if (is_uv1_hub())
++                      bcp->uvhub_version = 1;
++              else if (is_uv2_hub())
++                      bcp->uvhub_version = 2;
++              else {
++                      printk(KERN_EMERG "uvhub version not 1 or 2\n");
++                      return 1;
++              }
+               bcp->uvhub_master = *hmasterp;
+               bcp->uvhub_cpu = uv_cpu_hub_info(cpu)->blade_processor_id;
+               if (bcp->uvhub_cpu >= MAX_CPUS_PER_UVHUB) {
+@@ -1867,7 +1908,8 @@ static int __init uv_bau_init(void)
+                       val = 1L << 63;
+                       write_gmmr_activation(pnode, val);
+                       mmr = 1; /* should be 1 to broadcast to both sockets */
+-                      write_mmr_data_broadcast(pnode, mmr);
++                      if (!is_uv1_hub())
++                              write_mmr_data_broadcast(pnode, mmr);
+               }
+       }
diff --git a/queue-3.2/x86-uv2-work-around-bau-bug.patch b/queue-3.2/x86-uv2-work-around-bau-bug.patch
new file mode 100644 (file)
index 0000000..e1dfe46
--- /dev/null
@@ -0,0 +1,566 @@
+From c5d35d399e685acccc85a675e8765c26b2a9813a Mon Sep 17 00:00:00 2001
+From: Cliff Wickman <cpw@sgi.com>
+Date: Mon, 16 Jan 2012 15:19:47 -0600
+Subject: x86/UV2: Work around BAU bug
+
+From: Cliff Wickman <cpw@sgi.com>
+
+commit c5d35d399e685acccc85a675e8765c26b2a9813a upstream.
+
+This patch implements a workaround for a UV2 hardware bug.
+The bug is a non-atomic update of a memory-mapped register. When
+hardware message delivery and software message acknowledge occur
+simultaneously the pending message acknowledge for the arriving
+message may be lost.  This causes the sender's message status to
+stay busy.
+
+Part of the workaround is to not acknowledge a completed message
+until it is verified that no other message is actually using the
+resource that is mistakenly recorded in the completed message.
+
+Part of the workaround is to test for long elapsed time in such
+a busy condition, then handle it by using a spare sending
+descriptor. The stay-busy condition is eventually timed out by
+hardware, and then the original sending descriptor can be
+re-used. Most of that logic change is in keeping track of the
+current descriptor and the state of the spares.
+
+The occurrences of the workaround are added to the BAU
+statistics.
+
+Signed-off-by: Cliff Wickman <cpw@sgi.com>
+Link: http://lkml.kernel.org/r/20120116211947.GC5767@sgi.com
+Signed-off-by: Ingo Molnar <mingo@elte.hu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/include/asm/uv/uv_bau.h |   13 +
+ arch/x86/platform/uv/tlb_uv.c    |  274 ++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 254 insertions(+), 33 deletions(-)
+
+--- a/arch/x86/include/asm/uv/uv_bau.h
++++ b/arch/x86/include/asm/uv/uv_bau.h
+@@ -167,6 +167,7 @@
+ #define FLUSH_RETRY_TIMEOUT           2
+ #define FLUSH_GIVEUP                  3
+ #define FLUSH_COMPLETE                        4
++#define FLUSH_RETRY_BUSYBUG           5
+ /*
+  * tuning the action when the numalink network is extremely delayed
+@@ -463,7 +464,6 @@ struct bau_pq_entry {
+ struct msg_desc {
+       struct bau_pq_entry     *msg;
+       int                     msg_slot;
+-      int                     swack_slot;
+       struct bau_pq_entry     *queue_first;
+       struct bau_pq_entry     *queue_last;
+ };
+@@ -517,6 +517,9 @@ struct ptc_stats {
+       unsigned long   s_retry_messages;       /* retry broadcasts */
+       unsigned long   s_bau_reenabled;        /* for bau enable/disable */
+       unsigned long   s_bau_disabled;         /* for bau enable/disable */
++      unsigned long   s_uv2_wars;             /* uv2 workaround, perm. busy */
++      unsigned long   s_uv2_wars_hw;          /* uv2 workaround, hiwater */
++      unsigned long   s_uv2_war_waits;        /* uv2 workaround, long waits */
+       /* destination statistics */
+       unsigned long   d_alltlb;               /* times all tlb's on this
+                                                  cpu were flushed */
+@@ -593,6 +596,8 @@ struct bau_control {
+       short                   cpus_in_socket;
+       short                   cpus_in_uvhub;
+       short                   partition_base_pnode;
++      short                   using_desc; /* an index, like uvhub_cpu */
++      unsigned int            inuse_map;
+       unsigned short          message_number;
+       unsigned short          uvhub_quiesce;
+       short                   socket_acknowledge_count[DEST_Q_SIZE];
+@@ -610,6 +615,7 @@ struct bau_control {
+       int                     cong_response_us;
+       int                     cong_reps;
+       int                     cong_period;
++      unsigned long           clocks_per_100_usec;
+       cycles_t                period_time;
+       long                    period_requests;
+       struct hub_and_pnode    *thp;
+@@ -670,6 +676,11 @@ static inline void write_mmr_sw_ack(unsi
+       uv_write_local_mmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, mr);
+ }
++static inline void write_gmmr_sw_ack(int pnode, unsigned long mr)
++{
++      write_gmmr(pnode, UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, mr);
++}
++
+ static inline unsigned long read_mmr_sw_ack(void)
+ {
+       return read_lmmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE);
+--- a/arch/x86/platform/uv/tlb_uv.c
++++ b/arch/x86/platform/uv/tlb_uv.c
+@@ -157,13 +157,14 @@ static int __init uvhub_to_first_apicid(
+  * clear of the Timeout bit (as well) will free the resource. No reply will
+  * be sent (the hardware will only do one reply per message).
+  */
+-static void reply_to_message(struct msg_desc *mdp, struct bau_control *bcp)
++static void reply_to_message(struct msg_desc *mdp, struct bau_control *bcp,
++                                              int do_acknowledge)
+ {
+       unsigned long dw;
+       struct bau_pq_entry *msg;
+       msg = mdp->msg;
+-      if (!msg->canceled) {
++      if (!msg->canceled && do_acknowledge) {
+               dw = (msg->swack_vec << UV_SW_ACK_NPENDING) | msg->swack_vec;
+               write_mmr_sw_ack(dw);
+       }
+@@ -212,8 +213,8 @@ static void bau_process_retry_msg(struct
+                       if (mmr & (msg_res << UV_SW_ACK_NPENDING)) {
+                               unsigned long mr;
+                               /*
+-                               * is the resource timed out?
+-                               * make everyone ignore the cancelled message.
++                               * Is the resource timed out?
++                               * Make everyone ignore the cancelled message.
+                                */
+                               msg2->canceled = 1;
+                               stat->d_canceled++;
+@@ -231,8 +232,8 @@ static void bau_process_retry_msg(struct
+  * Do all the things a cpu should do for a TLB shootdown message.
+  * Other cpu's may come here at the same time for this message.
+  */
+-static void bau_process_message(struct msg_desc *mdp,
+-                                      struct bau_control *bcp)
++static void bau_process_message(struct msg_desc *mdp, struct bau_control *bcp,
++                                              int do_acknowledge)
+ {
+       short socket_ack_count = 0;
+       short *sp;
+@@ -284,8 +285,9 @@ static void bau_process_message(struct m
+               if (msg_ack_count == bcp->cpus_in_uvhub) {
+                       /*
+                        * All cpus in uvhub saw it; reply
++                       * (unless we are in the UV2 workaround)
+                        */
+-                      reply_to_message(mdp, bcp);
++                      reply_to_message(mdp, bcp, do_acknowledge);
+               }
+       }
+@@ -491,27 +493,138 @@ static int uv1_wait_completion(struct ba
+ /*
+  * UV2 has an extra bit of status in the ACTIVATION_STATUS_2 register.
+  */
+-static unsigned long uv2_read_status(unsigned long offset, int rshft, int cpu)
++static unsigned long uv2_read_status(unsigned long offset, int rshft, int desc)
+ {
+       unsigned long descriptor_status;
+       unsigned long descriptor_status2;
+       descriptor_status = ((read_lmmr(offset) >> rshft) & UV_ACT_STATUS_MASK);
+-      descriptor_status2 = (read_mmr_uv2_status() >> cpu) & 0x1UL;
++      descriptor_status2 = (read_mmr_uv2_status() >> desc) & 0x1UL;
+       descriptor_status = (descriptor_status << 1) | descriptor_status2;
+       return descriptor_status;
+ }
++/*
++ * Return whether the status of the descriptor that is normally used for this
++ * cpu (the one indexed by its hub-relative cpu number) is busy.
++ * The status of the original 32 descriptors is always reflected in the 64
++ * bits of UVH_LB_BAU_SB_ACTIVATION_STATUS_0.
++ * The bit provided by the activation_status_2 register is irrelevant to
++ * the status if it is only being tested for busy or not busy.
++ */
++int normal_busy(struct bau_control *bcp)
++{
++      int cpu = bcp->uvhub_cpu;
++      int mmr_offset;
++      int right_shift;
++
++      mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0;
++      right_shift = cpu * UV_ACT_STATUS_SIZE;
++      return (((((read_lmmr(mmr_offset) >> right_shift) &
++                              UV_ACT_STATUS_MASK)) << 1) == UV2H_DESC_BUSY);
++}
++
++/*
++ * Entered when a bau descriptor has gone into a permanent busy wait because
++ * of a hardware bug.
++ * Workaround the bug.
++ */
++int handle_uv2_busy(struct bau_control *bcp)
++{
++      int busy_one = bcp->using_desc;
++      int normal = bcp->uvhub_cpu;
++      int selected = -1;
++      int i;
++      unsigned long descriptor_status;
++      unsigned long status;
++      int mmr_offset;
++      struct bau_desc *bau_desc_old;
++      struct bau_desc *bau_desc_new;
++      struct bau_control *hmaster = bcp->uvhub_master;
++      struct ptc_stats *stat = bcp->statp;
++      cycles_t ttm;
++
++      stat->s_uv2_wars++;
++      spin_lock(&hmaster->uvhub_lock);
++      /* try for the original first */
++      if (busy_one != normal) {
++              if (!normal_busy(bcp))
++                      selected = normal;
++      }
++      if (selected < 0) {
++              /* can't use the normal, select an alternate */
++              mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1;
++              descriptor_status = read_lmmr(mmr_offset);
++
++              /* scan available descriptors 32-63 */
++              for (i = 0; i < UV_CPUS_PER_AS; i++) {
++                      if ((hmaster->inuse_map & (1 << i)) == 0) {
++                              status = ((descriptor_status >>
++                                              (i * UV_ACT_STATUS_SIZE)) &
++                                              UV_ACT_STATUS_MASK) << 1;
++                              if (status != UV2H_DESC_BUSY) {
++                                      selected = i + UV_CPUS_PER_AS;
++                                      break;
++                              }
++                      }
++              }
++      }
++
++      if (busy_one != normal)
++              /* mark the busy alternate as not in-use */
++              hmaster->inuse_map &= ~(1 << (busy_one - UV_CPUS_PER_AS));
++
++      if (selected >= 0) {
++              /* switch to the selected descriptor */
++              if (selected != normal) {
++                      /* set the selected alternate as in-use */
++                      hmaster->inuse_map |=
++                                      (1 << (selected - UV_CPUS_PER_AS));
++                      if (selected > stat->s_uv2_wars_hw)
++                              stat->s_uv2_wars_hw = selected;
++              }
++              bau_desc_old = bcp->descriptor_base;
++              bau_desc_old += (ITEMS_PER_DESC * busy_one);
++              bcp->using_desc = selected;
++              bau_desc_new = bcp->descriptor_base;
++              bau_desc_new += (ITEMS_PER_DESC * selected);
++              *bau_desc_new = *bau_desc_old;
++      } else {
++              /*
++               * All are busy. Wait for the normal one for this cpu to
++               * free up.
++               */
++              stat->s_uv2_war_waits++;
++              spin_unlock(&hmaster->uvhub_lock);
++              ttm = get_cycles();
++              do {
++                      cpu_relax();
++              } while (normal_busy(bcp));
++              spin_lock(&hmaster->uvhub_lock);
++              /* switch to the original descriptor */
++              bcp->using_desc = normal;
++              bau_desc_old = bcp->descriptor_base;
++              bau_desc_old += (ITEMS_PER_DESC * bcp->using_desc);
++              bcp->using_desc = (ITEMS_PER_DESC * normal);
++              bau_desc_new = bcp->descriptor_base;
++              bau_desc_new += (ITEMS_PER_DESC * normal);
++              *bau_desc_new = *bau_desc_old; /* copy the entire descriptor */
++      }
++      spin_unlock(&hmaster->uvhub_lock);
++      return FLUSH_RETRY_BUSYBUG;
++}
++
+ static int uv2_wait_completion(struct bau_desc *bau_desc,
+                               unsigned long mmr_offset, int right_shift,
+                               struct bau_control *bcp, long try)
+ {
+       unsigned long descriptor_stat;
+       cycles_t ttm;
+-      int cpu = bcp->uvhub_cpu;
++      int desc = bcp->using_desc;
++      long busy_reps = 0;
+       struct ptc_stats *stat = bcp->statp;
+-      descriptor_stat = uv2_read_status(mmr_offset, right_shift, cpu);
++      descriptor_stat = uv2_read_status(mmr_offset, right_shift, desc);
+       /* spin on the status MMR, waiting for it to go idle */
+       while (descriptor_stat != UV2H_DESC_IDLE) {
+@@ -542,12 +655,23 @@ static int uv2_wait_completion(struct ba
+                       bcp->conseccompletes = 0;
+                       return FLUSH_RETRY_TIMEOUT;
+               } else {
++                      busy_reps++;
++                      if (busy_reps > 1000000) {
++                              /* not to hammer on the clock */
++                              busy_reps = 0;
++                              ttm = get_cycles();
++                              if ((ttm - bcp->send_message) >
++                                      (bcp->clocks_per_100_usec)) {
++                                      return handle_uv2_busy(bcp);
++                              }
++                      }
+                       /*
+                        * descriptor_stat is still BUSY
+                        */
+                       cpu_relax();
+               }
+-              descriptor_stat = uv2_read_status(mmr_offset, right_shift, cpu);
++              descriptor_stat = uv2_read_status(mmr_offset, right_shift,
++                                                                      desc);
+       }
+       bcp->conseccompletes++;
+       return FLUSH_COMPLETE;
+@@ -563,14 +687,14 @@ static int wait_completion(struct bau_de
+ {
+       int right_shift;
+       unsigned long mmr_offset;
+-      int cpu = bcp->uvhub_cpu;
++      int desc = bcp->using_desc;
+-      if (cpu < UV_CPUS_PER_AS) {
++      if (desc < UV_CPUS_PER_AS) {
+               mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0;
+-              right_shift = cpu * UV_ACT_STATUS_SIZE;
++              right_shift = desc * UV_ACT_STATUS_SIZE;
+       } else {
+               mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1;
+-              right_shift = ((cpu - UV_CPUS_PER_AS) * UV_ACT_STATUS_SIZE);
++              right_shift = ((desc - UV_CPUS_PER_AS) * UV_ACT_STATUS_SIZE);
+       }
+       if (bcp->uvhub_version == 1)
+@@ -752,8 +876,7 @@ static void handle_cmplt(int completion_
+  * Returns 1 if it gives up entirely and the original cpu mask is to be
+  * returned to the kernel.
+  */
+-int uv_flush_send_and_wait(struct bau_desc *bau_desc,
+-                      struct cpumask *flush_mask, struct bau_control *bcp)
++int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp)
+ {
+       int seq_number = 0;
+       int completion_stat = 0;
+@@ -766,20 +889,24 @@ int uv_flush_send_and_wait(struct bau_de
+       struct bau_control *hmaster = bcp->uvhub_master;
+       struct uv1_bau_msg_header *uv1_hdr = NULL;
+       struct uv2_bau_msg_header *uv2_hdr = NULL;
++      struct bau_desc *bau_desc;
+-      if (bcp->uvhub_version == 1) {
+-              uv1 = 1;
++      if (bcp->uvhub_version == 1)
+               uv1_throttle(hmaster, stat);
+-              uv1_hdr = &bau_desc->header.uv1_hdr;
+-      } else
+-              uv2_hdr = &bau_desc->header.uv2_hdr;
+       while (hmaster->uvhub_quiesce)
+               cpu_relax();
+       time1 = get_cycles();
+       do {
+-              if (try == 0) {
++              bau_desc = bcp->descriptor_base;
++              bau_desc += (ITEMS_PER_DESC * bcp->using_desc);
++              if (bcp->uvhub_version == 1) {
++                      uv1 = 1;
++                      uv1_hdr = &bau_desc->header.uv1_hdr;
++              } else
++                      uv2_hdr = &bau_desc->header.uv2_hdr;
++              if ((try == 0) || (completion_stat == FLUSH_RETRY_BUSYBUG)) {
+                       if (uv1)
+                               uv1_hdr->msg_type = MSG_REGULAR;
+                       else
+@@ -797,13 +924,14 @@ int uv_flush_send_and_wait(struct bau_de
+                       uv1_hdr->sequence = seq_number;
+               else
+                       uv2_hdr->sequence = seq_number;
+-              index = (1UL << AS_PUSH_SHIFT) | bcp->uvhub_cpu;
++              index = (1UL << AS_PUSH_SHIFT) | bcp->using_desc;
+               bcp->send_message = get_cycles();
+               write_mmr_activation(index);
+               try++;
+               completion_stat = wait_completion(bau_desc, bcp, try);
++              /* UV2: wait_completion() may change the bcp->using_desc */
+               handle_cmplt(completion_stat, bau_desc, bcp, hmaster, stat);
+@@ -814,6 +942,7 @@ int uv_flush_send_and_wait(struct bau_de
+               }
+               cpu_relax();
+       } while ((completion_stat == FLUSH_RETRY_PLUGGED) ||
++               (completion_stat == FLUSH_RETRY_BUSYBUG) ||
+                (completion_stat == FLUSH_RETRY_TIMEOUT));
+       time2 = get_cycles();
+@@ -828,6 +957,7 @@ int uv_flush_send_and_wait(struct bau_de
+       record_send_stats(time1, time2, bcp, stat, completion_stat, try);
+       if (completion_stat == FLUSH_GIVEUP)
++              /* FLUSH_GIVEUP will fall back to using IPI's for tlb flush */
+               return 1;
+       return 0;
+ }
+@@ -983,7 +1113,7 @@ const struct cpumask *uv_flush_tlb_other
+               stat->s_ntargself++;
+       bau_desc = bcp->descriptor_base;
+-      bau_desc += (ITEMS_PER_DESC * bcp->uvhub_cpu);
++      bau_desc += (ITEMS_PER_DESC * bcp->using_desc);
+       bau_uvhubs_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE);
+       if (set_distrib_bits(flush_mask, bcp, bau_desc, &locals, &remotes))
+               return NULL;
+@@ -996,13 +1126,86 @@ const struct cpumask *uv_flush_tlb_other
+        * uv_flush_send_and_wait returns 0 if all cpu's were messaged,
+        * or 1 if it gave up and the original cpumask should be returned.
+        */
+-      if (!uv_flush_send_and_wait(bau_desc, flush_mask, bcp))
++      if (!uv_flush_send_and_wait(flush_mask, bcp))
+               return NULL;
+       else
+               return cpumask;
+ }
+ /*
++ * Search the message queue for any 'other' message with the same software
++ * acknowledge resource bit vector.
++ */
++struct bau_pq_entry *find_another_by_swack(struct bau_pq_entry *msg,
++                      struct bau_control *bcp, unsigned char swack_vec)
++{
++      struct bau_pq_entry *msg_next = msg + 1;
++
++      if (msg_next > bcp->queue_last)
++              msg_next = bcp->queue_first;
++      while ((msg_next->swack_vec != 0) && (msg_next != msg)) {
++              if (msg_next->swack_vec == swack_vec)
++                      return msg_next;
++              msg_next++;
++              if (msg_next > bcp->queue_last)
++                      msg_next = bcp->queue_first;
++      }
++      return NULL;
++}
++
++/*
++ * UV2 needs to work around a bug in which an arriving message has not
++ * set a bit in the UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE register.
++ * Such a message must be ignored.
++ */
++void process_uv2_message(struct msg_desc *mdp, struct bau_control *bcp)
++{
++      unsigned long mmr_image;
++      unsigned char swack_vec;
++      struct bau_pq_entry *msg = mdp->msg;
++      struct bau_pq_entry *other_msg;
++
++      mmr_image = read_mmr_sw_ack();
++      swack_vec = msg->swack_vec;
++
++      if ((swack_vec & mmr_image) == 0) {
++              /*
++               * This message was assigned a swack resource, but no
++               * reserved acknowlegment is pending.
++               * The bug has prevented this message from setting the MMR.
++               * And no other message has used the same sw_ack resource.
++               * Do the requested shootdown but do not reply to the msg.
++               * (the 0 means make no acknowledge)
++               */
++              bau_process_message(mdp, bcp, 0);
++              return;
++      }
++
++      /*
++       * Some message has set the MMR 'pending' bit; it might have been
++       * another message.  Look for that message.
++       */
++      other_msg = find_another_by_swack(msg, bcp, msg->swack_vec);
++      if (other_msg) {
++              /* There is another.  Do not ack the current one. */
++              bau_process_message(mdp, bcp, 0);
++              /*
++               * Let the natural processing of that message acknowledge
++               * it. Don't get the processing of sw_ack's out of order.
++               */
++              return;
++      }
++
++      /*
++       * There is no other message using this sw_ack, so it is safe to
++       * acknowledge it.
++       */
++      bau_process_message(mdp, bcp, 1);
++
++      return;
++}
++
++/*
+  * The BAU message interrupt comes here. (registered by set_intr_gate)
+  * See entry_64.S
+  *
+@@ -1038,9 +1241,11 @@ void uv_bau_message_interrupt(struct pt_
+               count++;
+               msgdesc.msg_slot = msg - msgdesc.queue_first;
+-              msgdesc.swack_slot = ffs(msg->swack_vec) - 1;
+               msgdesc.msg = msg;
+-              bau_process_message(&msgdesc, bcp);
++              if (bcp->uvhub_version == 2)
++                      process_uv2_message(&msgdesc, bcp);
++              else
++                      bau_process_message(&msgdesc, bcp, 1);
+               msg++;
+               if (msg > msgdesc.queue_last)
+@@ -1158,7 +1363,7 @@ static int ptc_seq_show(struct seq_file
+               seq_printf(file,
+                       "all one mult none retry canc nocan reset rcan ");
+               seq_printf(file,
+-                      "disable enable\n");
++                      "disable enable wars warshw warwaits\n");
+       }
+       if (cpu < num_possible_cpus() && cpu_online(cpu)) {
+               stat = &per_cpu(ptcstats, cpu);
+@@ -1189,8 +1394,10 @@ static int ptc_seq_show(struct seq_file
+                          stat->d_nomsg, stat->d_retries, stat->d_canceled,
+                          stat->d_nocanceled, stat->d_resets,
+                          stat->d_rcanceled);
+-              seq_printf(file, "%ld %ld\n",
+-                      stat->s_bau_disabled, stat->s_bau_reenabled);
++              seq_printf(file, "%ld %ld %ld %ld %ld\n",
++                      stat->s_bau_disabled, stat->s_bau_reenabled,
++                      stat->s_uv2_wars, stat->s_uv2_wars_hw,
++                      stat->s_uv2_war_waits);
+       }
+       return 0;
+ }
+@@ -1564,6 +1771,7 @@ static void pq_init(int node, int pnode)
+       write_mmr_payload_first(pnode, pn_first);
+       write_mmr_payload_tail(pnode, first);
+       write_mmr_payload_last(pnode, last);
++      write_gmmr_sw_ack(pnode, 0xffffUL);
+       /* in effect, all msg_type's are set to MSG_NOOP */
+       memset(pqp, 0, sizeof(struct bau_pq_entry) * DEST_Q_SIZE);
+@@ -1651,6 +1859,7 @@ static void __init init_per_cpu_tunables
+               bcp->cong_response_us           = congested_respns_us;
+               bcp->cong_reps                  = congested_reps;
+               bcp->cong_period                = congested_period;
++              bcp->clocks_per_100_usec =      usec_2_cycles(100);
+       }
+ }
+@@ -1771,6 +1980,7 @@ static int scan_sock(struct socket_desc
+               }
+               bcp->uvhub_master = *hmasterp;
+               bcp->uvhub_cpu = uv_cpu_hub_info(cpu)->blade_processor_id;
++              bcp->using_desc = bcp->uvhub_cpu;
+               if (bcp->uvhub_cpu >= MAX_CPUS_PER_UVHUB) {
+                       printk(KERN_EMERG "%d cpus per uvhub invalid\n",
+                               bcp->uvhub_cpu);