]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
more .31 patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Thu, 1 Oct 2009 22:46:22 +0000 (15:46 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 1 Oct 2009 22:46:22 +0000 (15:46 -0700)
21 files changed:
queue-2.6.31/drm-i915-handle-erestartsys-during-page-fault.patch [new file with mode: 0644]
queue-2.6.31/em28xx-ir-kbd-i2c-init-data-needs-a-persistent-object.patch [new file with mode: 0644]
queue-2.6.31/fix-idle-time-field-in-proc-uptime.patch [new file with mode: 0644]
queue-2.6.31/hid-completely-remove-apple-mightymouse-from-blacklist.patch [new file with mode: 0644]
queue-2.6.31/hugetlb-restore-interleaving-of-bootmem-huge-pages.patch [new file with mode: 0644]
queue-2.6.31/iwlagn-modify-digital-svr-for-1000.patch [new file with mode: 0644]
queue-2.6.31/iwlwifi-fix-unloading-driver-while-scanning.patch [new file with mode: 0644]
queue-2.6.31/iwlwifi-handle-new-firmware-file-with-ucode-build-number-in-header.patch [new file with mode: 0644]
queue-2.6.31/iwlwifi-traverse-linklist-to-find-the-valid-otp-block.patch [new file with mode: 0644]
queue-2.6.31/iwlwifi-update-1000-series-api-version-to-match-firmware.patch [new file with mode: 0644]
queue-2.6.31/mm-fix-anonymous-dirtying.patch [new file with mode: 0644]
queue-2.6.31/mm-munlock-use-follow_page.patch [new file with mode: 0644]
queue-2.6.31/mmap-avoid-unnecessary-anon_vma-lock-acquisition-in-vma_adjust.patch [new file with mode: 0644]
queue-2.6.31/mptsas-pae-kernel-more-than-4-gb-kernel-panic.patch [new file with mode: 0644]
queue-2.6.31/nommu-fix-map_private-mmap-of-objects-where-the-data-can-be-mapped-directly.patch [new file with mode: 0644]
queue-2.6.31/page-allocator-limit-the-number-of-migrate_reserve-pageblocks-per-zone.patch [new file with mode: 0644]
queue-2.6.31/powerpc-8xx-fix-regression-introduced-by-cache-coherency-rewrite.patch [new file with mode: 0644]
queue-2.6.31/powerpc-fix-incorrect-setting-of-__have_arch_pte_special.patch [new file with mode: 0644]
queue-2.6.31/proc-kcore-work-around-a-bug.patch [new file with mode: 0644]
queue-2.6.31/saa7134-ir-kbd-i2c-init-data-needs-a-persistent-object.patch [new file with mode: 0644]
queue-2.6.31/series

diff --git a/queue-2.6.31/drm-i915-handle-erestartsys-during-page-fault.patch b/queue-2.6.31/drm-i915-handle-erestartsys-during-page-fault.patch
new file mode 100644 (file)
index 0000000..5326df7
--- /dev/null
@@ -0,0 +1,87 @@
+From c715089f49844260f1eeae8e3b55af9468ba1325 Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Wed, 23 Sep 2009 00:43:56 +0100
+Subject: drm/i915: Handle ERESTARTSYS during page fault
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit c715089f49844260f1eeae8e3b55af9468ba1325 upstream.
+
+During a page fault and rebinding the buffer there exists a window for a
+signal to arrive during the i915_wait_request() and trigger a
+ERESTARTSYS. This used to be handled by returning SIGBUS and thereby
+killing the application. Try 'cairo-perf-trace & cairo-test-suite' and
+watch X go boom!
+
+The solution as suggested by H. Peter Anvin is to simply return NOPAGE and
+leave the higher layers to spot we did not fill the page and resubmit
+the page fault.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+[anholt: Mostly squash it with another commit]
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/i915/i915_gem.c |   29 ++++++++++++-----------------
+ 1 file changed, 12 insertions(+), 17 deletions(-)
+
+--- a/drivers/gpu/drm/i915/i915_gem.c
++++ b/drivers/gpu/drm/i915/i915_gem.c
+@@ -1151,26 +1151,21 @@ int i915_gem_fault(struct vm_area_struct
+       mutex_lock(&dev->struct_mutex);
+       if (!obj_priv->gtt_space) {
+               ret = i915_gem_object_bind_to_gtt(obj, obj_priv->gtt_alignment);
+-              if (ret) {
+-                      mutex_unlock(&dev->struct_mutex);
+-                      return VM_FAULT_SIGBUS;
+-              }
++              if (ret)
++                      goto unlock;
++
+               list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+               ret = i915_gem_object_set_to_gtt_domain(obj, write);
+-              if (ret) {
+-                      mutex_unlock(&dev->struct_mutex);
+-                      return VM_FAULT_SIGBUS;
+-              }
++              if (ret)
++                      goto unlock;
+       }
+       /* Need a new fence register? */
+       if (obj_priv->tiling_mode != I915_TILING_NONE) {
+               ret = i915_gem_object_get_fence_reg(obj);
+-              if (ret) {
+-                      mutex_unlock(&dev->struct_mutex);
+-                      return VM_FAULT_SIGBUS;
+-              }
++              if (ret)
++                      goto unlock;
+       }
+       pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) +
+@@ -1178,18 +1173,18 @@ int i915_gem_fault(struct vm_area_struct
+       /* Finally, remap it using the new GTT offset */
+       ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
+-
++unlock:
+       mutex_unlock(&dev->struct_mutex);
+       switch (ret) {
++      case 0:
++      case -ERESTARTSYS:
++              return VM_FAULT_NOPAGE;
+       case -ENOMEM:
+       case -EAGAIN:
+               return VM_FAULT_OOM;
+-      case -EFAULT:
+-      case -EINVAL:
+-              return VM_FAULT_SIGBUS;
+       default:
+-              return VM_FAULT_NOPAGE;
++              return VM_FAULT_SIGBUS;
+       }
+ }
diff --git a/queue-2.6.31/em28xx-ir-kbd-i2c-init-data-needs-a-persistent-object.patch b/queue-2.6.31/em28xx-ir-kbd-i2c-init-data-needs-a-persistent-object.patch
new file mode 100644 (file)
index 0000000..9273496
--- /dev/null
@@ -0,0 +1,120 @@
+From brian@xyzw.org  Thu Oct  1 15:34:18 2009
+From: Brian Rogers <brian@xyzw.org>
+Date: Wed, 23 Sep 2009 03:05:02 -0700
+Subject: em28xx: ir-kbd-i2c init data needs a persistent object
+To: stable@kernel.org
+Cc: Mauro Carvalho Chehab <mchehab@redhat.com>, linux-kernel@vger.kernel.org, Brian Rogers <brian@xyzw.org>, linux-media@vger.kernel.org
+Message-ID: <1253700303-15172-1-git-send-email-brian@xyzw.org>
+
+From: Brian Rogers <brian@xyzw.org>
+
+commit d2ebd0f806fdb6104903365e355675934eec22b2 upstream.
+
+Original commit message:
+
+ir-kbd-i2c's ir_probe() function can be called much later (i.e. at
+ir-kbd-i2c module load), than the lifetime of a struct IR_i2c_init_data
+allocated off of the stack in cx18_i2c_new_ir() at registration time.
+Make sure we pass a pointer to a persistent IR_i2c_init_data object at
+i2c registration time.
+
+Thanks to Brian Rogers, Dustin Mitchell, Andy Walls and Jean Delvare to
+rise this question.
+
+Before this patch, if ir-kbd-i2c were probed after em28xx, trash data
+were used. After the patch, no matter what order, it is properly
+reported as tested by me:
+
+input: i2c IR (i2c IR (EM2840 Hauppaug as /class/input/input10
+ir-kbd-i2c: i2c IR (i2c IR (EM2840 Hauppaug detected at i2c-4/4-0030/ir0 [em28xx #0]
+
+Original-patch-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+[brian@xyzw.org: backported for 2.6.31]
+Signed-off-by: Brian Rogers <brian@xyzw.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/em28xx/em28xx-cards.c |   32 ++++++++++++++----------------
+ drivers/media/video/em28xx/em28xx.h       |    4 +++
+ 2 files changed, 19 insertions(+), 17 deletions(-)
+
+--- a/drivers/media/video/em28xx/em28xx-cards.c
++++ b/drivers/media/video/em28xx/em28xx-cards.c
+@@ -2170,8 +2170,6 @@ static int em28xx_hint_board(struct em28
+ /* ----------------------------------------------------------------------- */
+ void em28xx_register_i2c_ir(struct em28xx *dev)
+ {
+-      struct i2c_board_info info;
+-      struct IR_i2c_init_data init_data;
+       const unsigned short addr_list[] = {
+                0x30, 0x47, I2C_CLIENT_END
+       };
+@@ -2179,9 +2177,9 @@ void em28xx_register_i2c_ir(struct em28x
+       if (disable_ir)
+               return;
+-      memset(&info, 0, sizeof(struct i2c_board_info));
+-      memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
+-      strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
++      memset(&dev->info, 0, sizeof(&dev->info));
++      memset(&dev->init_data, 0, sizeof(dev->init_data));
++      strlcpy(dev->info.type, "ir_video", I2C_NAME_SIZE);
+       /* detect & configure */
+       switch (dev->model) {
+@@ -2191,19 +2189,19 @@ void em28xx_register_i2c_ir(struct em28x
+               break;
+       case (EM2800_BOARD_TERRATEC_CINERGY_200):
+       case (EM2820_BOARD_TERRATEC_CINERGY_250):
+-              init_data.ir_codes = ir_codes_em_terratec;
+-              init_data.get_key = em28xx_get_key_terratec;
+-              init_data.name = "i2c IR (EM28XX Terratec)";
++              dev->init_data.ir_codes = ir_codes_em_terratec;
++              dev->init_data.get_key = em28xx_get_key_terratec;
++              dev->init_data.name = "i2c IR (EM28XX Terratec)";
+               break;
+       case (EM2820_BOARD_PINNACLE_USB_2):
+-              init_data.ir_codes = ir_codes_pinnacle_grey;
+-              init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
+-              init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
++              dev->init_data.ir_codes = ir_codes_pinnacle_grey;
++              dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
++              dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
+               break;
+       case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
+-              init_data.ir_codes = ir_codes_hauppauge_new;
+-              init_data.get_key = em28xx_get_key_em_haup;
+-              init_data.name = "i2c IR (EM2840 Hauppauge)";
++              dev->init_data.ir_codes = ir_codes_hauppauge_new;
++              dev->init_data.get_key = em28xx_get_key_em_haup;
++              dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
+               break;
+       case (EM2820_BOARD_MSI_VOX_USB_2):
+               break;
+@@ -2215,9 +2213,9 @@ void em28xx_register_i2c_ir(struct em28x
+               break;
+       }
+-      if (init_data.name)
+-              info.platform_data = &init_data;
+-      i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
++      if (dev->init_data.name)
++              dev->info.platform_data = &dev->init_data;
++      i2c_new_probed_device(&dev->i2c_adap, &dev->info, addr_list);
+ }
+ void em28xx_card_setup(struct em28xx *dev)
+--- a/drivers/media/video/em28xx/em28xx.h
++++ b/drivers/media/video/em28xx/em28xx.h
+@@ -595,6 +595,10 @@ struct em28xx {
+       struct delayed_work sbutton_query_work;
+       struct em28xx_dvb *dvb;
++
++      /* I2C keyboard data */
++      struct i2c_board_info info;
++      struct IR_i2c_init_data init_data;
+ };
+ struct em28xx_ops {
diff --git a/queue-2.6.31/fix-idle-time-field-in-proc-uptime.patch b/queue-2.6.31/fix-idle-time-field-in-proc-uptime.patch
new file mode 100644 (file)
index 0000000..1f7f61a
--- /dev/null
@@ -0,0 +1,43 @@
+From 96830a57de1197519b62af6a4c9ceea556c18c3d Mon Sep 17 00:00:00 2001
+From: Michael Abbott <michael.abbott@diamond.ac.uk>
+Date: Thu, 24 Sep 2009 10:15:19 +0200
+Subject: Fix idle time field in /proc/uptime
+
+From: Michael Abbott <michael.abbott@diamond.ac.uk>
+
+commit 96830a57de1197519b62af6a4c9ceea556c18c3d upstream.
+
+Git commit 79741dd changes idle cputime accounting, but unfortunately
+the /proc/uptime file hasn't caught up.  Here the idle time calculation
+from /proc/stat is copied over.
+
+Signed-off-by: Michael Abbott <michael.abbott@diamond.ac.uk>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/proc/uptime.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/fs/proc/uptime.c
++++ b/fs/proc/uptime.c
+@@ -4,13 +4,18 @@
+ #include <linux/sched.h>
+ #include <linux/seq_file.h>
+ #include <linux/time.h>
++#include <linux/kernel_stat.h>
+ #include <asm/cputime.h>
+ static int uptime_proc_show(struct seq_file *m, void *v)
+ {
+       struct timespec uptime;
+       struct timespec idle;
+-      cputime_t idletime = cputime_add(init_task.utime, init_task.stime);
++      int i;
++      cputime_t idletime = cputime_zero;
++
++      for_each_possible_cpu(i)
++              idletime = cputime64_add(idletime, kstat_cpu(i).cpustat.idle);
+       do_posix_clock_monotonic_gettime(&uptime);
+       monotonic_to_bootbased(&uptime);
diff --git a/queue-2.6.31/hid-completely-remove-apple-mightymouse-from-blacklist.patch b/queue-2.6.31/hid-completely-remove-apple-mightymouse-from-blacklist.patch
new file mode 100644 (file)
index 0000000..b89ad8a
--- /dev/null
@@ -0,0 +1,33 @@
+From 42960a13001aa6df52ca9952ce996f94a744ea65 Mon Sep 17 00:00:00 2001
+From: Jan Scholz <Scholz@fias.uni-frankfurt.de>
+Date: Wed, 26 Aug 2009 13:18:51 +0200
+Subject: HID: completely remove apple mightymouse from blacklist
+
+From: Jan Scholz <Scholz@fias.uni-frankfurt.de>
+
+commit 42960a13001aa6df52ca9952ce996f94a744ea65 upstream.
+
+Commit fa047e4f6fa63a6e9d0ae4d7749538830d14a343 "HID: fix inverted
+wheel for bluetooth version of apple mighty mouse" is incomplete. If
+we remove Apple MightyMouse (bluetooth version) from the list of
+apple_devices in drivers/hid/hid-apple.c we have to remove it from
+hid_blacklist in drivers/hid/hid-core.c as well.
+
+Signed-off-by: Jan Scholz <Scholz@fias.uni-frankfurt.de>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hid/hid-core.c |    1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -1319,7 +1319,6 @@ static const struct hid_device_id hid_bl
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
+-      { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
+       { }
+ };
diff --git a/queue-2.6.31/hugetlb-restore-interleaving-of-bootmem-huge-pages.patch b/queue-2.6.31/hugetlb-restore-interleaving-of-bootmem-huge-pages.patch
new file mode 100644 (file)
index 0000000..4cac521
--- /dev/null
@@ -0,0 +1,73 @@
+From akpm@linux-foundation.org  Thu Oct  1 15:24:58 2009
+From: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
+Date: Mon, 21 Sep 2009 17:01:04 -0700
+Subject: hugetlb: restore interleaving of bootmem huge pages (2.6.31)
+To: torvalds@linux-foundation.org
+Cc: Lee.Schermerhorn@hp.com, lee.schermerhorn@hp.com, ak@linux.intel.com, eric.whitney@hp.com, mel@csn.ul.ie, rientjes@google.com, agl@us.ibm.com, apw@canonical.com, akpm@linux-foundation.org, stable@kernel.org
+Message-ID: <200909220001.n8M014vN026389@imap1.linux-foundation.org>
+
+
+From: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
+
+Not upstream as it is fixed differently in .32
+
+I noticed that alloc_bootmem_huge_page() will only advance to the next
+node on failure to allocate a huge page.  I asked about this on linux-mm
+and linux-numa, cc'ing the usual huge page suspects.  Mel Gorman
+responded:
+
+       I strongly suspect that the same node being used until allocation
+       failure instead of round-robin is an oversight and not deliberate
+       at all. It appears to be a side-effect of a fix made way back in
+       commit 63b4613c3f0d4b724ba259dc6c201bb68b884e1a ["hugetlb: fix
+       hugepage allocation with memoryless nodes"]. Prior to that patch
+       it looked like allocations would always round-robin even when
+       allocation was successful.
+
+Andy Whitcroft countered that the existing behavior looked like Andi
+Kleen's original implementation and suggested that we ask him.  We did and
+Andy replied that his intention was to interleave the allocations.  So,
+...
+
+This patch moves the advance of the hstate next node from which to
+allocate up before the test for success of the attempted allocation.  This
+will unconditionally advance the next node from which to alloc,
+interleaving successful allocations over the nodes with sufficient
+contiguous memory, and skipping over nodes that fail the huge page
+allocation attempt.
+
+Note that alloc_bootmem_huge_page() will only be called for huge pages of
+order > MAX_ORDER.
+
+Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com>
+Reviewed-by: Andi Kleen <ak@linux.intel.com>
+Cc: Mel Gorman <mel@csn.ul.ie>
+Cc: David Rientjes <rientjes@google.com>
+Cc: Adam Litke <agl@us.ibm.com>
+Cc: Andy Whitcroft <apw@canonical.com>
+Cc: Eric Whitney <eric.whitney@hp.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/hugetlb.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -1010,6 +1010,7 @@ int __weak alloc_bootmem_huge_page(struc
+                               NODE_DATA(h->hugetlb_next_nid),
+                               huge_page_size(h), huge_page_size(h), 0);
++              hstate_next_node(h);
+               if (addr) {
+                       /*
+                        * Use the beginning of the huge page to store the
+@@ -1019,7 +1020,6 @@ int __weak alloc_bootmem_huge_page(struc
+                       m = addr;
+                       goto found;
+               }
+-              hstate_next_node(h);
+               nr_nodes--;
+       }
+       return 0;
diff --git a/queue-2.6.31/iwlagn-modify-digital-svr-for-1000.patch b/queue-2.6.31/iwlagn-modify-digital-svr-for-1000.patch
new file mode 100644 (file)
index 0000000..532b498
--- /dev/null
@@ -0,0 +1,61 @@
+From 02c06e4abc0680afd31bf481a803541556757fb6 Mon Sep 17 00:00:00 2001
+From: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+Date: Fri, 17 Jul 2009 09:30:14 -0700
+Subject: iwlagn: modify digital SVR for 1000
+
+From: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+
+commit 02c06e4abc0680afd31bf481a803541556757fb6 upstream.
+
+On 1000, there are two Switching Voltage Regulators (SVR). The first one
+apply digital voltage level (1.32V) for PCIe block and core. We need to
+use this regulator to solve a stability issue related to noisy DC2DC
+line in the silicon.
+
+Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/wireless/iwlwifi/iwl-5000.c |    7 +++++++
+ drivers/net/wireless/iwlwifi/iwl-prph.h |    5 ++++-
+ 2 files changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
++++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
+@@ -239,6 +239,13 @@ static void iwl5000_nic_config(struct iw
+                               APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
+                               ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
++      if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) {
++              /* Setting digital SVR for 1000 card to 1.32V */
++              iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG,
++                                      APMG_SVR_DIGITAL_VOLTAGE_1_32,
++                                      ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
++      }
++
+       spin_unlock_irqrestore(&priv->lock, flags);
+ }
+--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
++++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
+@@ -80,6 +80,8 @@
+ #define APMG_RFKILL_REG                       (APMG_BASE + 0x0014)
+ #define APMG_RTC_INT_STT_REG          (APMG_BASE + 0x001c)
+ #define APMG_RTC_INT_MSK_REG          (APMG_BASE + 0x0020)
++#define APMG_DIGITAL_SVR_REG          (APMG_BASE + 0x0058)
++#define APMG_ANALOG_SVR_REG           (APMG_BASE + 0x006C)
+ #define APMG_CLK_VAL_DMA_CLK_RQT      (0x00000200)
+ #define APMG_CLK_VAL_BSM_CLK_RQT      (0x00000800)
+@@ -91,7 +93,8 @@
+ #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN                (0x00000000)
+ #define APMG_PS_CTRL_VAL_PWR_SRC_MAX          (0x01000000) /* 3945 only */
+ #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX         (0x02000000)
+-
++#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK       (0x000001E0) /* bit 8:5 */
++#define APMG_SVR_DIGITAL_VOLTAGE_1_32         (0x00000060)
+ #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS                (0x00000800)
diff --git a/queue-2.6.31/iwlwifi-fix-unloading-driver-while-scanning.patch b/queue-2.6.31/iwlwifi-fix-unloading-driver-while-scanning.patch
new file mode 100644 (file)
index 0000000..cab27e7
--- /dev/null
@@ -0,0 +1,52 @@
+From reinette.chatre@intel.com  Thu Oct  1 15:44:54 2009
+From: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+Date: Wed, 30 Sep 2009 13:01:01 -0700
+Subject: iwlwifi: fix unloading driver while scanning
+To: stable@kernel.org
+Cc: Reinette Chatre <reinette.chatre@intel.com>, Wey-Yi Guy <wey-yi.w.guy@intel.com>, "John W. Linville" <linville@tuxdriver.com>
+Message-ID: <1254340861-25121-1-git-send-email-reinette.chatre@intel.com>
+
+From: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+
+This is commit 5bddf54962bf68002816df710348ba197d6391bb in linux-2.6.
+
+If NetworkManager is busy scanning when user
+tries to unload the module, the driver can not be unloaded
+because HW still scanning.
+
+Make sure driver sends abort scan host command to uCode if it
+is in the middle of scanning during driver unload.
+
+Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/wireless/iwlwifi/iwl-agn.c  |    2 +-
+ drivers/net/wireless/iwlwifi/iwl-scan.c |    3 ++-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
++++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
+@@ -2215,7 +2215,7 @@ static void iwl_mac_stop(struct ieee8021
+       priv->is_open = 0;
+-      if (iwl_is_ready_rf(priv)) {
++      if (iwl_is_ready_rf(priv) || test_bit(STATUS_SCAN_HW, &priv->status)) {
+               /* stop mac, cancel any scan request and clear
+                * RXON_FILTER_ASSOC_MSK BIT
+                */
+--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
++++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
+@@ -799,7 +799,8 @@ void iwl_bg_abort_scan(struct work_struc
+ {
+       struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
+-      if (!iwl_is_ready(priv))
++      if (!test_bit(STATUS_READY, &priv->status) ||
++          !test_bit(STATUS_GEO_CONFIGURED, &priv->status))
+               return;
+       mutex_lock(&priv->mutex);
diff --git a/queue-2.6.31/iwlwifi-handle-new-firmware-file-with-ucode-build-number-in-header.patch b/queue-2.6.31/iwlwifi-handle-new-firmware-file-with-ucode-build-number-in-header.patch
new file mode 100644 (file)
index 0000000..3e03a64
--- /dev/null
@@ -0,0 +1,588 @@
+From cc0f555d511a5fe9d4519334c8f674a1dbab9e3a Mon Sep 17 00:00:00 2001
+From: Jay Sternberg <jay.e.sternberg@intel.com>
+Date: Fri, 17 Jul 2009 09:30:16 -0700
+Subject: iwlwifi: Handle new firmware file with ucode build number in header
+
+From: Jay Sternberg <jay.e.sternberg@intel.com>
+
+commit cc0f555d511a5fe9d4519334c8f674a1dbab9e3a upstream.
+
+Adding new API version to account for change to ucode file format.  New
+header includes the build number of the ucode.  This build number is the
+SVN revision thus allowing for exact correlation to the code that
+generated it.
+
+The header adds the build number so that older ucode images can also be
+enhanced to include the build in the future.
+
+some cleanup in iwl_read_ucode needed to ensure old header not used and
+reduce unnecessary references through pointer with the data is already
+in heap variable.
+
+Signed-off-by: Jay Sternberg <jay.e.sternberg@intel.com>
+Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/wireless/iwlwifi/iwl-3945.c     |   40 ++++++++++++++++++++
+ drivers/net/wireless/iwlwifi/iwl-4965.c     |   39 +++++++++++++++++++
+ drivers/net/wireless/iwlwifi/iwl-5000.c     |   51 +++++++++++++++++++++++++
+ drivers/net/wireless/iwlwifi/iwl-6000.c     |    5 +-
+ drivers/net/wireless/iwlwifi/iwl-agn.c      |   55 ++++++++++++++++------------
+ drivers/net/wireless/iwlwifi/iwl-core.h     |   12 ++++++
+ drivers/net/wireless/iwlwifi/iwl-dev.h      |   31 +++++++++++----
+ drivers/net/wireless/iwlwifi/iwl3945-base.c |   45 ++++++++++++----------
+ 8 files changed, 224 insertions(+), 54 deletions(-)
+
+--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
++++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
+@@ -2111,7 +2111,7 @@ static void iwl3945_nic_start(struct iwl
+  */
+ static int iwl3945_read_ucode(struct iwl_priv *priv)
+ {
+-      struct iwl_ucode *ucode;
++      const struct iwl_ucode_header *ucode;
+       int ret = -EINVAL, index;
+       const struct firmware *ucode_raw;
+       /* firmware file name contains uCode/driver compatibility version */
+@@ -2152,22 +2152,24 @@ static int iwl3945_read_ucode(struct iwl
+               goto error;
+       /* Make sure that we got at least our header! */
+-      if (ucode_raw->size < sizeof(*ucode)) {
++      if (ucode_raw->size <  priv->cfg->ops->ucode->get_header_size(1)) {
+               IWL_ERR(priv, "File size way too small!\n");
+               ret = -EINVAL;
+               goto err_release;
+       }
+       /* Data from ucode file:  header followed by uCode images */
+-      ucode = (void *)ucode_raw->data;
++      ucode = (struct iwl_ucode_header *)ucode_raw->data;
+       priv->ucode_ver = le32_to_cpu(ucode->ver);
+       api_ver = IWL_UCODE_API(priv->ucode_ver);
+-      inst_size = le32_to_cpu(ucode->inst_size);
+-      data_size = le32_to_cpu(ucode->data_size);
+-      init_size = le32_to_cpu(ucode->init_size);
+-      init_data_size = le32_to_cpu(ucode->init_data_size);
+-      boot_size = le32_to_cpu(ucode->boot_size);
++      inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
++      data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
++      init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
++      init_data_size =
++              priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
++      boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
++      src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
+       /* api_ver should match the api version forming part of the
+        * firmware filename ... but we don't check for that and only rely
+@@ -2208,12 +2210,13 @@ static int iwl3945_read_ucode(struct iwl
+       /* Verify size of file vs. image size info in file's header */
+-      if (ucode_raw->size < sizeof(*ucode) +
++      if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) +
+               inst_size + data_size + init_size +
+               init_data_size + boot_size) {
+-              IWL_DEBUG_INFO(priv, "uCode file size %zd too small\n",
+-                             ucode_raw->size);
++              IWL_DEBUG_INFO(priv,
++                      "uCode file size %zd does not match expected size\n",
++                      ucode_raw->size);
+               ret = -EINVAL;
+               goto err_release;
+       }
+@@ -2296,44 +2299,44 @@ static int iwl3945_read_ucode(struct iwl
+       /* Copy images into buffers for card's bus-master reads ... */
+       /* Runtime instructions (first block of data in file) */
+-      src = &ucode->data[0];
+-      len = priv->ucode_code.len;
++      len = inst_size;
+       IWL_DEBUG_INFO(priv,
+               "Copying (but not loading) uCode instr len %zd\n", len);
+       memcpy(priv->ucode_code.v_addr, src, len);
++      src += len;
++
+       IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
+               priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
+       /* Runtime data (2nd block)
+        * NOTE:  Copy into backup buffer will be done in iwl3945_up()  */
+-      src = &ucode->data[inst_size];
+-      len = priv->ucode_data.len;
++      len = data_size;
+       IWL_DEBUG_INFO(priv,
+               "Copying (but not loading) uCode data len %zd\n", len);
+       memcpy(priv->ucode_data.v_addr, src, len);
+       memcpy(priv->ucode_data_backup.v_addr, src, len);
++      src += len;
+       /* Initialization instructions (3rd block) */
+       if (init_size) {
+-              src = &ucode->data[inst_size + data_size];
+-              len = priv->ucode_init.len;
++              len = init_size;
+               IWL_DEBUG_INFO(priv,
+                       "Copying (but not loading) init instr len %zd\n", len);
+               memcpy(priv->ucode_init.v_addr, src, len);
++              src += len;
+       }
+       /* Initialization data (4th block) */
+       if (init_data_size) {
+-              src = &ucode->data[inst_size + data_size + init_size];
+-              len = priv->ucode_init_data.len;
++              len = init_data_size;
+               IWL_DEBUG_INFO(priv,
+                       "Copying (but not loading) init data len %zd\n", len);
+               memcpy(priv->ucode_init_data.v_addr, src, len);
++              src += len;
+       }
+       /* Bootstrap instructions (5th block) */
+-      src = &ucode->data[inst_size + data_size + init_size + init_data_size];
+-      len = priv->ucode_boot.len;
++      len = boot_size;
+       IWL_DEBUG_INFO(priv,
+               "Copying (but not loading) boot instr len %zd\n", len);
+       memcpy(priv->ucode_boot.v_addr, src, len);
+--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
++++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
+@@ -2784,11 +2784,50 @@ static int iwl3945_load_bsm(struct iwl_p
+       return 0;
+ }
++#define IWL3945_UCODE_GET(item)                                               \
++static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\
++                                  u32 api_ver)                        \
++{                                                                     \
++      return le32_to_cpu(ucode->u.v1.item);                           \
++}
++
++static u32 iwl3945_ucode_get_header_size(u32 api_ver)
++{
++      return UCODE_HEADER_SIZE(1);
++}
++static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode,
++                                 u32 api_ver)
++{
++      return 0;
++}
++static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode,
++                                u32 api_ver)
++{
++      return (u8 *) ucode->u.v1.data;
++}
++
++IWL3945_UCODE_GET(inst_size);
++IWL3945_UCODE_GET(data_size);
++IWL3945_UCODE_GET(init_size);
++IWL3945_UCODE_GET(init_data_size);
++IWL3945_UCODE_GET(boot_size);
++
+ static struct iwl_hcmd_ops iwl3945_hcmd = {
+       .rxon_assoc = iwl3945_send_rxon_assoc,
+       .commit_rxon = iwl3945_commit_rxon,
+ };
++static struct iwl_ucode_ops iwl3945_ucode = {
++      .get_header_size = iwl3945_ucode_get_header_size,
++      .get_build = iwl3945_ucode_get_build,
++      .get_inst_size = iwl3945_ucode_get_inst_size,
++      .get_data_size = iwl3945_ucode_get_data_size,
++      .get_init_size = iwl3945_ucode_get_init_size,
++      .get_init_data_size = iwl3945_ucode_get_init_data_size,
++      .get_boot_size = iwl3945_ucode_get_boot_size,
++      .get_data = iwl3945_ucode_get_data,
++};
++
+ static struct iwl_lib_ops iwl3945_lib = {
+       .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
+       .txq_free_tfd = iwl3945_hw_txq_free_tfd,
+@@ -2829,6 +2868,7 @@ static struct iwl_hcmd_utils_ops iwl3945
+ };
+ static struct iwl_ops iwl3945_ops = {
++      .ucode = &iwl3945_ucode,
+       .lib = &iwl3945_lib,
+       .hcmd = &iwl3945_hcmd,
+       .utils = &iwl3945_hcmd_utils,
+--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
++++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
+@@ -2221,12 +2221,50 @@ static void iwl4965_cancel_deferred_work
+       cancel_work_sync(&priv->txpower_work);
+ }
++#define IWL4965_UCODE_GET(item)                                               \
++static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\
++                                  u32 api_ver)                        \
++{                                                                     \
++      return le32_to_cpu(ucode->u.v1.item);                           \
++}
++
++static u32 iwl4965_ucode_get_header_size(u32 api_ver)
++{
++      return UCODE_HEADER_SIZE(1);
++}
++static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode,
++                                 u32 api_ver)
++{
++      return 0;
++}
++static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode,
++                                u32 api_ver)
++{
++      return (u8 *) ucode->u.v1.data;
++}
++
++IWL4965_UCODE_GET(inst_size);
++IWL4965_UCODE_GET(data_size);
++IWL4965_UCODE_GET(init_size);
++IWL4965_UCODE_GET(init_data_size);
++IWL4965_UCODE_GET(boot_size);
++
+ static struct iwl_hcmd_ops iwl4965_hcmd = {
+       .rxon_assoc = iwl4965_send_rxon_assoc,
+       .commit_rxon = iwl_commit_rxon,
+       .set_rxon_chain = iwl_set_rxon_chain,
+ };
++static struct iwl_ucode_ops iwl4965_ucode = {
++      .get_header_size = iwl4965_ucode_get_header_size,
++      .get_build = iwl4965_ucode_get_build,
++      .get_inst_size = iwl4965_ucode_get_inst_size,
++      .get_data_size = iwl4965_ucode_get_data_size,
++      .get_init_size = iwl4965_ucode_get_init_size,
++      .get_init_data_size = iwl4965_ucode_get_init_data_size,
++      .get_boot_size = iwl4965_ucode_get_boot_size,
++      .get_data = iwl4965_ucode_get_data,
++};
+ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
+       .get_hcmd_size = iwl4965_get_hcmd_size,
+       .build_addsta_hcmd = iwl4965_build_addsta_hcmd,
+@@ -2287,6 +2325,7 @@ static struct iwl_lib_ops iwl4965_lib = 
+ };
+ static struct iwl_ops iwl4965_ops = {
++      .ucode = &iwl4965_ucode,
+       .lib = &iwl4965_lib,
+       .hcmd = &iwl4965_hcmd,
+       .utils = &iwl4965_hcmd_utils,
+--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
++++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
+@@ -1426,6 +1426,44 @@ int iwl5000_calc_rssi(struct iwl_priv *p
+       return max_rssi - agc - IWL49_RSSI_OFFSET;
+ }
++#define IWL5000_UCODE_GET(item)                                               \
++static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
++                                  u32 api_ver)                        \
++{                                                                     \
++      if (api_ver <= 2)                                               \
++              return le32_to_cpu(ucode->u.v1.item);                   \
++      return le32_to_cpu(ucode->u.v2.item);                           \
++}
++
++static u32 iwl5000_ucode_get_header_size(u32 api_ver)
++{
++      if (api_ver <= 2)
++              return UCODE_HEADER_SIZE(1);
++      return UCODE_HEADER_SIZE(2);
++}
++
++static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode,
++                                 u32 api_ver)
++{
++      if (api_ver <= 2)
++              return 0;
++      return le32_to_cpu(ucode->u.v2.build);
++}
++
++static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode,
++                                u32 api_ver)
++{
++      if (api_ver <= 2)
++              return (u8 *) ucode->u.v1.data;
++      return (u8 *) ucode->u.v2.data;
++}
++
++IWL5000_UCODE_GET(inst_size);
++IWL5000_UCODE_GET(data_size);
++IWL5000_UCODE_GET(init_size);
++IWL5000_UCODE_GET(init_data_size);
++IWL5000_UCODE_GET(boot_size);
++
+ struct iwl_hcmd_ops iwl5000_hcmd = {
+       .rxon_assoc = iwl5000_send_rxon_assoc,
+       .commit_rxon = iwl_commit_rxon,
+@@ -1441,6 +1479,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_u
+       .calc_rssi = iwl5000_calc_rssi,
+ };
++struct iwl_ucode_ops iwl5000_ucode = {
++      .get_header_size = iwl5000_ucode_get_header_size,
++      .get_build = iwl5000_ucode_get_build,
++      .get_inst_size = iwl5000_ucode_get_inst_size,
++      .get_data_size = iwl5000_ucode_get_data_size,
++      .get_init_size = iwl5000_ucode_get_init_size,
++      .get_init_data_size = iwl5000_ucode_get_init_data_size,
++      .get_boot_size = iwl5000_ucode_get_boot_size,
++      .get_data = iwl5000_ucode_get_data,
++};
++
+ struct iwl_lib_ops iwl5000_lib = {
+       .set_hw_params = iwl5000_hw_set_hw_params,
+       .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
+@@ -1542,12 +1591,14 @@ static struct iwl_lib_ops iwl5150_lib = 
+ };
+ struct iwl_ops iwl5000_ops = {
++      .ucode = &iwl5000_ucode,
+       .lib = &iwl5000_lib,
+       .hcmd = &iwl5000_hcmd,
+       .utils = &iwl5000_hcmd_utils,
+ };
+ static struct iwl_ops iwl5150_ops = {
++      .ucode = &iwl5000_ucode,
+       .lib = &iwl5150_lib,
+       .hcmd = &iwl5000_hcmd,
+       .utils = &iwl5000_hcmd_utils,
+--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
++++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
+@@ -46,8 +46,8 @@
+ #include "iwl-5000-hw.h"
+ /* Highest firmware API version supported */
+-#define IWL6000_UCODE_API_MAX 2
+-#define IWL6050_UCODE_API_MAX 2
++#define IWL6000_UCODE_API_MAX 3
++#define IWL6050_UCODE_API_MAX 3
+ /* Lowest firmware API version supported */
+ #define IWL6000_UCODE_API_MIN 1
+@@ -69,6 +69,7 @@ static struct iwl_hcmd_utils_ops iwl6000
+ };
+ static struct iwl_ops iwl6000_ops = {
++      .ucode = &iwl5000_ucode,
+       .lib = &iwl5000_lib,
+       .hcmd = &iwl5000_hcmd,
+       .utils = &iwl6000_hcmd_utils,
+--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
++++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
+@@ -1348,7 +1348,7 @@ static void iwl_nic_start(struct iwl_pri
+  */
+ static int iwl_read_ucode(struct iwl_priv *priv)
+ {
+-      struct iwl_ucode *ucode;
++      struct iwl_ucode_header *ucode;
+       int ret = -EINVAL, index;
+       const struct firmware *ucode_raw;
+       const char *name_pre = priv->cfg->fw_name_pre;
+@@ -1357,7 +1357,8 @@ static int iwl_read_ucode(struct iwl_pri
+       char buf[25];
+       u8 *src;
+       size_t len;
+-      u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size;
++      u32 api_ver, build;
++      u32 inst_size, data_size, init_size, init_data_size, boot_size;
+       /* Ask kernel firmware_class module to get the boot firmware off disk.
+        * request_firmware() is synchronous, file is in memory on return. */
+@@ -1387,23 +1388,26 @@ static int iwl_read_ucode(struct iwl_pri
+       if (ret < 0)
+               goto error;
+-      /* Make sure that we got at least our header! */
+-      if (ucode_raw->size < sizeof(*ucode)) {
++      /* Make sure that we got at least the v1 header! */
++      if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
+               IWL_ERR(priv, "File size way too small!\n");
+               ret = -EINVAL;
+               goto err_release;
+       }
+       /* Data from ucode file:  header followed by uCode images */
+-      ucode = (void *)ucode_raw->data;
++      ucode = (struct iwl_ucode_header *)ucode_raw->data;
+       priv->ucode_ver = le32_to_cpu(ucode->ver);
+       api_ver = IWL_UCODE_API(priv->ucode_ver);
+-      inst_size = le32_to_cpu(ucode->inst_size);
+-      data_size = le32_to_cpu(ucode->data_size);
+-      init_size = le32_to_cpu(ucode->init_size);
+-      init_data_size = le32_to_cpu(ucode->init_data_size);
+-      boot_size = le32_to_cpu(ucode->boot_size);
++      build = priv->cfg->ops->ucode->get_build(ucode, api_ver);
++      inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
++      data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
++      init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
++      init_data_size =
++              priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
++      boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
++      src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
+       /* api_ver should match the api version forming part of the
+        * firmware filename ... but we don't check for that and only rely
+@@ -1429,6 +1433,9 @@ static int iwl_read_ucode(struct iwl_pri
+              IWL_UCODE_API(priv->ucode_ver),
+              IWL_UCODE_SERIAL(priv->ucode_ver));
++      if (build)
++              IWL_DEBUG_INFO(priv, "Build %u\n", build);
++
+       IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
+                      priv->ucode_ver);
+       IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
+@@ -1443,12 +1450,14 @@ static int iwl_read_ucode(struct iwl_pri
+                      boot_size);
+       /* Verify size of file vs. image size info in file's header */
+-      if (ucode_raw->size < sizeof(*ucode) +
++      if (ucode_raw->size !=
++              priv->cfg->ops->ucode->get_header_size(api_ver) +
+               inst_size + data_size + init_size +
+               init_data_size + boot_size) {
+-              IWL_DEBUG_INFO(priv, "uCode file size %d too small\n",
+-                             (int)ucode_raw->size);
++              IWL_DEBUG_INFO(priv,
++                      "uCode file size %d does not match expected size\n",
++                      (int)ucode_raw->size);
+               ret = -EINVAL;
+               goto err_release;
+       }
+@@ -1528,42 +1537,42 @@ static int iwl_read_ucode(struct iwl_pri
+       /* Copy images into buffers for card's bus-master reads ... */
+       /* Runtime instructions (first block of data in file) */
+-      src = &ucode->data[0];
+-      len = priv->ucode_code.len;
++      len = inst_size;
+       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len);
+       memcpy(priv->ucode_code.v_addr, src, len);
++      src += len;
++
+       IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
+               priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
+       /* Runtime data (2nd block)
+        * NOTE:  Copy into backup buffer will be done in iwl_up()  */
+-      src = &ucode->data[inst_size];
+-      len = priv->ucode_data.len;
++      len = data_size;
+       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len);
+       memcpy(priv->ucode_data.v_addr, src, len);
+       memcpy(priv->ucode_data_backup.v_addr, src, len);
++      src += len;
+       /* Initialization instructions (3rd block) */
+       if (init_size) {
+-              src = &ucode->data[inst_size + data_size];
+-              len = priv->ucode_init.len;
++              len = init_size;
+               IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
+                               len);
+               memcpy(priv->ucode_init.v_addr, src, len);
++              src += len;
+       }
+       /* Initialization data (4th block) */
+       if (init_data_size) {
+-              src = &ucode->data[inst_size + data_size + init_size];
+-              len = priv->ucode_init_data.len;
++              len = init_data_size;
+               IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
+                              len);
+               memcpy(priv->ucode_init_data.v_addr, src, len);
++              src += len;
+       }
+       /* Bootstrap instructions (5th block) */
+-      src = &ucode->data[inst_size + data_size + init_size + init_data_size];
+-      len = priv->ucode_boot.len;
++      len = boot_size;
+       IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
+       memcpy(priv->ucode_boot.v_addr, src, len);
+--- a/drivers/net/wireless/iwlwifi/iwl-core.h
++++ b/drivers/net/wireless/iwlwifi/iwl-core.h
+@@ -116,6 +116,17 @@ struct iwl_temp_ops {
+       void (*set_ct_kill)(struct iwl_priv *priv);
+ };
++struct iwl_ucode_ops {
++      u32 (*get_header_size)(u32);
++      u32 (*get_build)(const struct iwl_ucode_header *, u32);
++      u32 (*get_inst_size)(const struct iwl_ucode_header *, u32);
++      u32 (*get_data_size)(const struct iwl_ucode_header *, u32);
++      u32 (*get_init_size)(const struct iwl_ucode_header *, u32);
++      u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32);
++      u32 (*get_boot_size)(const struct iwl_ucode_header *, u32);
++      u8 * (*get_data)(const struct iwl_ucode_header *, u32);
++};
++
+ struct iwl_lib_ops {
+       /* set hw dependent parameters */
+       int (*set_hw_params)(struct iwl_priv *priv);
+@@ -171,6 +182,7 @@ struct iwl_lib_ops {
+ };
+ struct iwl_ops {
++      const struct iwl_ucode_ops *ucode;
+       const struct iwl_lib_ops *lib;
+       const struct iwl_hcmd_ops *hcmd;
+       const struct iwl_hcmd_utils_ops *utils;
+--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
++++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
+@@ -66,6 +66,7 @@ extern struct iwl_cfg iwl1000_bgn_cfg;
+ /* shared structures from iwl-5000.c */
+ extern struct iwl_mod_params iwl50_mod_params;
+ extern struct iwl_ops iwl5000_ops;
++extern struct iwl_ucode_ops iwl5000_ucode;
+ extern struct iwl_lib_ops iwl5000_lib;
+ extern struct iwl_hcmd_ops iwl5000_hcmd;
+ extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
+@@ -525,15 +526,29 @@ struct fw_desc {
+ };
+ /* uCode file layout */
+-struct iwl_ucode {
+-      __le32 ver;             /* major/minor/API/serial */
+-      __le32 inst_size;       /* bytes of runtime instructions */
+-      __le32 data_size;       /* bytes of runtime data */
+-      __le32 init_size;       /* bytes of initialization instructions */
+-      __le32 init_data_size;  /* bytes of initialization data */
+-      __le32 boot_size;       /* bytes of bootstrap instructions */
+-      u8 data[0];             /* data in same order as "size" elements */
++struct iwl_ucode_header {
++      __le32 ver;     /* major/minor/API/serial */
++      union {
++              struct {
++                      __le32 inst_size;       /* bytes of runtime code */
++                      __le32 data_size;       /* bytes of runtime data */
++                      __le32 init_size;       /* bytes of init code */
++                      __le32 init_data_size;  /* bytes of init data */
++                      __le32 boot_size;       /* bytes of bootstrap code */
++                      u8 data[0];             /* in same order as sizes */
++              } v1;
++              struct {
++                      __le32 build;           /* build number */
++                      __le32 inst_size;       /* bytes of runtime code */
++                      __le32 data_size;       /* bytes of runtime data */
++                      __le32 init_size;       /* bytes of init code */
++                      __le32 init_data_size;  /* bytes of init data */
++                      __le32 boot_size;       /* bytes of bootstrap code */
++                      u8 data[0];             /* in same order as sizes */
++              } v2;
++      } u;
+ };
++#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28)
+ struct iwl4965_ibss_seq {
+       u8 mac[ETH_ALEN];
diff --git a/queue-2.6.31/iwlwifi-traverse-linklist-to-find-the-valid-otp-block.patch b/queue-2.6.31/iwlwifi-traverse-linklist-to-find-the-valid-otp-block.patch
new file mode 100644 (file)
index 0000000..ef2de37
--- /dev/null
@@ -0,0 +1,432 @@
+From reinette.chatre@intel.com  Thu Oct  1 15:42:57 2009
+From: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+Date: Wed, 30 Sep 2009 15:36:15 -0700
+Subject: iwlwifi: traverse linklist to find the valid OTP block
+To: Greg KH <greg@kroah.com>
+Cc: "stable@kernel.org" <stable@kernel.org>, "linux-wireless@vger.kernel.org" <linux-wireless@vger.kernel.org>
+Message-ID: <1254350175.26521.1662.camel@rc-desk>
+
+
+From: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+
+commit 415e49936b4b29b34c2fb561eeab867d41fc43a6 upstream.
+
+For devices using OTP memory, EEPROM image can start from
+any one of the OTP blocks. If shadow RAM is disabled, we need to
+traverse link list to find the last valid block, then start the EEPROM
+image reading.
+
+If OTP is not full, the valid block is the block _before_ the last block
+on the link list; the last block on the link list is the empty block
+ready for next OTP refresh/update.
+
+If OTP is full, then the last block is the valid block to be used for
+configure the device.
+
+Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/wireless/iwlwifi/iwl-1000.c   |    4 
+ drivers/net/wireless/iwlwifi/iwl-6000.c   |   20 ++-
+ drivers/net/wireless/iwlwifi/iwl-core.h   |    4 
+ drivers/net/wireless/iwlwifi/iwl-dev.h    |   12 +
+ drivers/net/wireless/iwlwifi/iwl-eeprom.c |  185 ++++++++++++++++++++++++------
+ drivers/net/wireless/iwlwifi/iwl-eeprom.h |   10 +
+ 6 files changed, 192 insertions(+), 43 deletions(-)
+
+--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
++++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
+@@ -62,12 +62,14 @@ struct iwl_cfg iwl1000_bgn_cfg = {
+       .ucode_api_min = IWL1000_UCODE_API_MIN,
+       .sku = IWL_SKU_G|IWL_SKU_N,
+       .ops = &iwl5000_ops,
+-      .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
++      .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+       .mod_params = &iwl50_mod_params,
+       .valid_tx_ant = ANT_A,
+       .valid_rx_ant = ANT_AB,
+       .need_pll_cfg = true,
++      .max_ll_items = OTP_MAX_LL_ITEMS_1000,
++      .shadow_ram_support = false,
+ };
+--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
++++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
+@@ -82,13 +82,15 @@ struct iwl_cfg iwl6000_2ag_cfg = {
+       .ucode_api_min = IWL6000_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G,
+       .ops = &iwl6000_ops,
+-      .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
++      .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+       .mod_params = &iwl50_mod_params,
+       .valid_tx_ant = ANT_BC,
+       .valid_rx_ant = ANT_BC,
+       .need_pll_cfg = false,
++      .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
++      .shadow_ram_support = true,
+ };
+ struct iwl_cfg iwl6000_2agn_cfg = {
+@@ -98,13 +100,15 @@ struct iwl_cfg iwl6000_2agn_cfg = {
+       .ucode_api_min = IWL6000_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .ops = &iwl6000_ops,
+-      .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
++      .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+       .mod_params = &iwl50_mod_params,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_AB,
+       .need_pll_cfg = false,
++      .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
++      .shadow_ram_support = true,
+ };
+ struct iwl_cfg iwl6050_2agn_cfg = {
+@@ -114,13 +118,15 @@ struct iwl_cfg iwl6050_2agn_cfg = {
+       .ucode_api_min = IWL6050_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .ops = &iwl6000_ops,
+-      .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
++      .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+       .mod_params = &iwl50_mod_params,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_AB,
+       .need_pll_cfg = false,
++      .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
++      .shadow_ram_support = true,
+ };
+ struct iwl_cfg iwl6000_3agn_cfg = {
+@@ -130,13 +136,15 @@ struct iwl_cfg iwl6000_3agn_cfg = {
+       .ucode_api_min = IWL6000_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .ops = &iwl6000_ops,
+-      .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
++      .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+       .mod_params = &iwl50_mod_params,
+       .valid_tx_ant = ANT_ABC,
+       .valid_rx_ant = ANT_ABC,
+       .need_pll_cfg = false,
++      .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
++      .shadow_ram_support = true,
+ };
+ struct iwl_cfg iwl6050_3agn_cfg = {
+@@ -146,13 +154,15 @@ struct iwl_cfg iwl6050_3agn_cfg = {
+       .ucode_api_min = IWL6050_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .ops = &iwl6000_ops,
+-      .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
++      .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+       .mod_params = &iwl50_mod_params,
+       .valid_tx_ant = ANT_ABC,
+       .valid_rx_ant = ANT_ABC,
+       .need_pll_cfg = false,
++      .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
++      .shadow_ram_support = true,
+ };
+ MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
+--- a/drivers/net/wireless/iwlwifi/iwl-core.h
++++ b/drivers/net/wireless/iwlwifi/iwl-core.h
+@@ -207,6 +207,8 @@ struct iwl_mod_params {
+  *    filename is constructed as fw_name_pre<api>.ucode.
+  * @ucode_api_max: Highest version of uCode API supported by driver.
+  * @ucode_api_min: Lowest version of uCode API supported by driver.
++ * @max_ll_items: max number of OTP blocks
++ * @shadow_ram_support: shadow support for OTP memory
+  *
+  * We enable the driver to be backward compatible wrt API version. The
+  * driver specifies which APIs it supports (with @ucode_api_max being the
+@@ -243,6 +245,8 @@ struct iwl_cfg {
+       u8   valid_rx_ant;
+       bool need_pll_cfg;
+       bool use_isr_legacy;
++      const u16 max_ll_items;
++      const bool shadow_ram_support;
+ };
+ /***************************
+--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
++++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
+@@ -835,6 +835,18 @@ enum iwl_nvm_type {
+       NVM_DEVICE_TYPE_OTP,
+ };
++/*
++ * Two types of OTP memory access modes
++ *   IWL_OTP_ACCESS_ABSOLUTE - absolute address mode,
++ *                            based on physical memory addressing
++ *   IWL_OTP_ACCESS_RELATIVE - relative address mode,
++ *                           based on logical memory addressing
++ */
++enum iwl_access_mode {
++      IWL_OTP_ACCESS_ABSOLUTE,
++      IWL_OTP_ACCESS_RELATIVE,
++};
++
+ /* interrupt statistics */
+ struct isr_statistics {
+       u32 hw;
+--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
++++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+@@ -152,6 +152,19 @@ int iwlcore_eeprom_verify_signature(stru
+ }
+ EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
++static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
++{
++      u32 otpgp;
++
++      otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
++      if (mode == IWL_OTP_ACCESS_ABSOLUTE)
++              iwl_clear_bit(priv, CSR_OTP_GP_REG,
++                              CSR_OTP_GP_REG_OTP_ACCESS_MODE);
++      else
++              iwl_set_bit(priv, CSR_OTP_GP_REG,
++                              CSR_OTP_GP_REG_OTP_ACCESS_MODE);
++}
++
+ static int iwlcore_get_nvm_type(struct iwl_priv *priv)
+ {
+       u32 otpgp;
+@@ -249,6 +262,124 @@ static int iwl_init_otp_access(struct iw
+       return ret;
+ }
++static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data)
++{
++      int ret = 0;
++      u32 r;
++      u32 otpgp;
++
++      _iwl_write32(priv, CSR_EEPROM_REG,
++                   CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
++      ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
++                                CSR_EEPROM_REG_READ_VALID_MSK,
++                                IWL_EEPROM_ACCESS_TIMEOUT);
++      if (ret < 0) {
++              IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
++              return ret;
++      }
++      r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
++      /* check for ECC errors: */
++      otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
++      if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
++              /* stop in this case */
++              /* set the uncorrectable OTP ECC bit for acknowledgement */
++              iwl_set_bit(priv, CSR_OTP_GP_REG,
++                      CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
++              IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n");
++              return -EINVAL;
++      }
++      if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
++              /* continue in this case */
++              /* set the correctable OTP ECC bit for acknowledgement */
++              iwl_set_bit(priv, CSR_OTP_GP_REG,
++                              CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
++              IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
++      }
++      *eeprom_data = le16_to_cpu((__force __le16)(r >> 16));
++      return 0;
++}
++
++/*
++ * iwl_is_otp_empty: check for empty OTP
++ */
++static bool iwl_is_otp_empty(struct iwl_priv *priv)
++{
++      u16 next_link_addr = 0, link_value;
++      bool is_empty = false;
++
++      /* locate the beginning of OTP link list */
++      if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) {
++              if (!link_value) {
++                      IWL_ERR(priv, "OTP is empty\n");
++                      is_empty = true;
++              }
++      } else {
++              IWL_ERR(priv, "Unable to read first block of OTP list.\n");
++              is_empty = true;
++      }
++
++      return is_empty;
++}
++
++
++/*
++ * iwl_find_otp_image: find EEPROM image in OTP
++ *   finding the OTP block that contains the EEPROM image.
++ *   the last valid block on the link list (the block _before_ the last block)
++ *   is the block we should read and used to configure the device.
++ *   If all the available OTP blocks are full, the last block will be the block
++ *   we should read and used to configure the device.
++ *   only perform this operation if shadow RAM is disabled
++ */
++static int iwl_find_otp_image(struct iwl_priv *priv,
++                                      u16 *validblockaddr)
++{
++      u16 next_link_addr = 0, link_value = 0, valid_addr;
++      int ret = 0;
++      int usedblocks = 0;
++
++      /* set addressing mode to absolute to traverse the link list */
++      iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE);
++
++      /* checking for empty OTP or error */
++      if (iwl_is_otp_empty(priv))
++              return -EINVAL;
++
++      /*
++       * start traverse link list
++       * until reach the max number of OTP blocks
++       * different devices have different number of OTP blocks
++       */
++      do {
++              /* save current valid block address
++               * check for more block on the link list
++               */
++              valid_addr = next_link_addr;
++              next_link_addr = link_value;
++              IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n",
++                             usedblocks, next_link_addr);
++              if (iwl_read_otp_word(priv, next_link_addr, &link_value))
++                      return -EINVAL;
++              if (!link_value) {
++                      /*
++                       * reach the end of link list,
++                       * set address point to the starting address
++                       * of the image
++                       */
++                      goto done;
++              }
++              /* more in the link list, continue */
++              usedblocks++;
++      } while (usedblocks < priv->cfg->max_ll_items);
++      /* OTP full, use last block */
++      IWL_DEBUG_INFO(priv, "OTP is full, use last block\n");
++done:
++      *validblockaddr = valid_addr;
++      /* skip first 2 bytes (link list pointer) */
++      *validblockaddr += 2;
++      return ret;
++}
++
+ /**
+  * iwl_eeprom_init - read EEPROM contents
+  *
+@@ -263,14 +394,13 @@ int iwl_eeprom_init(struct iwl_priv *pri
+       int sz;
+       int ret;
+       u16 addr;
+-      u32 otpgp;
++      u16 validblockaddr = 0;
++      u16 cache_addr = 0;
+       priv->nvm_device_type = iwlcore_get_nvm_type(priv);
+       /* allocate eeprom */
+-      if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+-              priv->cfg->eeprom_size =
+-                      OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL;
++      IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size);
+       sz = priv->cfg->eeprom_size;
+       priv->eeprom = kzalloc(sz, GFP_KERNEL);
+       if (!priv->eeprom) {
+@@ -298,46 +428,31 @@ int iwl_eeprom_init(struct iwl_priv *pri
+               if (ret) {
+                       IWL_ERR(priv, "Failed to initialize OTP access.\n");
+                       ret = -ENOENT;
+-                      goto err;
++                      goto done;
+               }
+               _iwl_write32(priv, CSR_EEPROM_GP,
+                            iwl_read32(priv, CSR_EEPROM_GP) &
+                            ~CSR_EEPROM_GP_IF_OWNER_MSK);
+-              /* clear */
+-              _iwl_write32(priv, CSR_OTP_GP_REG,
+-                           iwl_read32(priv, CSR_OTP_GP_REG) |
++
++              iwl_set_bit(priv, CSR_OTP_GP_REG,
+                            CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
+                            CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
+-
+-              for (addr = 0; addr < sz; addr += sizeof(u16)) {
+-                      u32 r;
+-
+-                      _iwl_write32(priv, CSR_EEPROM_REG,
+-                                   CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+-
+-                      ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
+-                                                CSR_EEPROM_REG_READ_VALID_MSK,
+-                                                IWL_EEPROM_ACCESS_TIMEOUT);
+-                      if (ret < 0) {
+-                              IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
++              /* traversing the linked list if no shadow ram supported */
++              if (!priv->cfg->shadow_ram_support) {
++                      if (iwl_find_otp_image(priv, &validblockaddr)) {
++                              ret = -ENOENT;
+                               goto done;
+                       }
+-                      r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
+-                      /* check for ECC errors: */
+-                      otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
+-                      if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
+-                              /* stop in this case */
+-                              IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n");
++              }
++              for (addr = validblockaddr; addr < validblockaddr + sz;
++                   addr += sizeof(u16)) {
++                      u16 eeprom_data;
++
++                      ret = iwl_read_otp_word(priv, addr, &eeprom_data);
++                      if (ret)
+                               goto done;
+-                      }
+-                      if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
+-                              /* continue in this case */
+-                              _iwl_write32(priv, CSR_OTP_GP_REG,
+-                                           iwl_read32(priv, CSR_OTP_GP_REG) |
+-                                           CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
+-                              IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
+-                      }
+-                      e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
++                      e[cache_addr / 2] = eeprom_data;
++                      cache_addr += sizeof(u16);
+               }
+       } else {
+               /* eeprom is an array of 16bit values */
+--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
++++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+@@ -180,8 +180,14 @@ struct iwl_eeprom_channel {
+ #define EEPROM_5050_EEPROM_VERSION    (0x21E)
+ /* OTP */
+-#define OTP_LOWER_BLOCKS_TOTAL                (3)
+-#define OTP_BLOCK_SIZE                        (0x400)
++/* lower blocks contain EEPROM image and calibration data */
++#define OTP_LOW_IMAGE_SIZE            (2 * 512 * sizeof(u16)) /* 2 KB */
++/* high blocks contain PAPD data */
++#define OTP_HIGH_IMAGE_SIZE_6x00        (6 * 512 * sizeof(u16)) /* 6 KB */
++#define OTP_HIGH_IMAGE_SIZE_1000        (0x200 * sizeof(u16)) /* 1024 bytes */
++#define OTP_MAX_LL_ITEMS_1000         (3)     /* OTP blocks for 1000 */
++#define OTP_MAX_LL_ITEMS_6x00         (4)     /* OTP blocks for 6x00 */
++#define OTP_MAX_LL_ITEMS_6x50         (7)     /* OTP blocks for 6x50 */
+ /* 2.4 GHz */
+ extern const u8 iwl_eeprom_band_1[14];
diff --git a/queue-2.6.31/iwlwifi-update-1000-series-api-version-to-match-firmware.patch b/queue-2.6.31/iwlwifi-update-1000-series-api-version-to-match-firmware.patch
new file mode 100644 (file)
index 0000000..339a1f6
--- /dev/null
@@ -0,0 +1,31 @@
+From cce53aa347c1e023d967b1cb1aa393c725aedba5 Mon Sep 17 00:00:00 2001
+From: Jay Sternberg <jay.e.sternberg@intel.com>
+Date: Fri, 17 Jul 2009 09:30:22 -0700
+Subject: iwlwifi: update 1000 series API version to match firmware
+
+From: Jay Sternberg <jay.e.sternberg@intel.com>
+
+commit cce53aa347c1e023d967b1cb1aa393c725aedba5 upstream.
+
+firmware file now contains build number so API needs to be updated.
+
+Signed-off-by: Jay Sternberg <jay.e.sternberg@intel.com>
+Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/wireless/iwlwifi/iwl-1000.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
++++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
+@@ -46,7 +46,7 @@
+ #include "iwl-5000-hw.h"
+ /* Highest firmware API version supported */
+-#define IWL1000_UCODE_API_MAX 2
++#define IWL1000_UCODE_API_MAX 3
+ /* Lowest firmware API version supported */
+ #define IWL1000_UCODE_API_MIN 1
diff --git a/queue-2.6.31/mm-fix-anonymous-dirtying.patch b/queue-2.6.31/mm-fix-anonymous-dirtying.patch
new file mode 100644 (file)
index 0000000..adab558
--- /dev/null
@@ -0,0 +1,43 @@
+From 1ac0cb5d0e22d5e483f56b2bc12172dec1cf7536 Mon Sep 17 00:00:00 2001
+From: Hugh Dickins <hugh.dickins@tiscali.co.uk>
+Date: Mon, 21 Sep 2009 17:03:29 -0700
+Subject: mm: fix anonymous dirtying
+
+From: Hugh Dickins <hugh.dickins@tiscali.co.uk>
+
+commit 1ac0cb5d0e22d5e483f56b2bc12172dec1cf7536 upstream.
+
+do_anonymous_page() has been wrong to dirty the pte regardless.
+If it's not going to mark the pte writable, then it won't help
+to mark it dirty here, and clogs up memory with pages which will
+need swap instead of being thrown away.  Especially wrong if no
+overcommit is chosen, and this vma is not yet VM_ACCOUNTed -
+we could exceed the limit and OOM despite no overcommit.
+
+Signed-off-by: Hugh Dickins <hugh.dickins@tiscali.co.uk>
+Acked-by: Rik van Riel <riel@redhat.com>
+Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
+Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
+Cc: Nick Piggin <npiggin@suse.de>
+Cc: Mel Gorman <mel@csn.ul.ie>
+Cc: Minchan Kim <minchan.kim@gmail.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/memory.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/mm/memory.c
++++ b/mm/memory.c
+@@ -2638,7 +2638,8 @@ static int do_anonymous_page(struct mm_s
+               goto oom_free_page;
+       entry = mk_pte(page, vma->vm_page_prot);
+-      entry = maybe_mkwrite(pte_mkdirty(entry), vma);
++      if (vma->vm_flags & VM_WRITE)
++              entry = pte_mkwrite(pte_mkdirty(entry));
+       page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
+       if (!pte_none(*page_table))
diff --git a/queue-2.6.31/mm-munlock-use-follow_page.patch b/queue-2.6.31/mm-munlock-use-follow_page.patch
new file mode 100644 (file)
index 0000000..ac72833
--- /dev/null
@@ -0,0 +1,232 @@
+From 408e82b78bcc9f1b47c76e833c3df97f675947de Mon Sep 17 00:00:00 2001
+From: Hugh Dickins <hugh.dickins@tiscali.co.uk>
+Date: Mon, 21 Sep 2009 17:03:23 -0700
+Subject: mm: munlock use follow_page
+
+From: Hugh Dickins <hugh.dickins@tiscali.co.uk>
+
+commit 408e82b78bcc9f1b47c76e833c3df97f675947de upstream.
+
+Hiroaki Wakabayashi points out that when mlock() has been interrupted
+by SIGKILL, the subsequent munlock() takes unnecessarily long because
+its use of __get_user_pages() insists on faulting in all the pages
+which mlock() never reached.
+
+It's worse than slowness if mlock() is terminated by Out Of Memory kill:
+the munlock_vma_pages_all() in exit_mmap() insists on faulting in all the
+pages which mlock() could not find memory for; so innocent bystanders are
+killed too, and perhaps the system hangs.
+
+__get_user_pages() does a lot that's silly for munlock(): so remove the
+munlock option from __mlock_vma_pages_range(), and use a simple loop of
+follow_page()s in munlock_vma_pages_range() instead; ignoring absent
+pages, and not marking present pages as accessed or dirty.
+
+(Change munlock() to only go so far as mlock() reached?  That does not
+work out, given the convention that mlock() claims complete success even
+when it has to give up early - in part so that an underlying file can be
+extended later, and those pages locked which earlier would give SIGBUS.)
+
+Signed-off-by: Hugh Dickins <hugh.dickins@tiscali.co.uk>
+Acked-by: Rik van Riel <riel@redhat.com>
+Reviewed-by: Minchan Kim <minchan.kim@gmail.com>
+Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
+Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
+Cc: Nick Piggin <npiggin@suse.de>
+Cc: Mel Gorman <mel@csn.ul.ie>
+Reviewed-by: Hiroaki Wakabayashi <primulaelatior@gmail.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/mlock.c |   99 ++++++++++++++++++++++++-------------------------------------
+ 1 file changed, 40 insertions(+), 59 deletions(-)
+
+--- a/mm/mlock.c
++++ b/mm/mlock.c
+@@ -139,49 +139,36 @@ static void munlock_vma_page(struct page
+ }
+ /**
+- * __mlock_vma_pages_range() -  mlock/munlock a range of pages in the vma.
++ * __mlock_vma_pages_range() -  mlock a range of pages in the vma.
+  * @vma:   target vma
+  * @start: start address
+  * @end:   end address
+- * @mlock: 0 indicate munlock, otherwise mlock.
+  *
+- * If @mlock == 0, unlock an mlocked range;
+- * else mlock the range of pages.  This takes care of making the pages present ,
+- * too.
++ * This takes care of making the pages present too.
+  *
+  * return 0 on success, negative error code on error.
+  *
+  * vma->vm_mm->mmap_sem must be held for at least read.
+  */
+ static long __mlock_vma_pages_range(struct vm_area_struct *vma,
+-                                 unsigned long start, unsigned long end,
+-                                 int mlock)
++                                  unsigned long start, unsigned long end)
+ {
+       struct mm_struct *mm = vma->vm_mm;
+       unsigned long addr = start;
+       struct page *pages[16]; /* 16 gives a reasonable batch */
+       int nr_pages = (end - start) / PAGE_SIZE;
+       int ret = 0;
+-      int gup_flags = 0;
++      int gup_flags;
+       VM_BUG_ON(start & ~PAGE_MASK);
+       VM_BUG_ON(end   & ~PAGE_MASK);
+       VM_BUG_ON(start < vma->vm_start);
+       VM_BUG_ON(end   > vma->vm_end);
+-      VM_BUG_ON((!rwsem_is_locked(&mm->mmap_sem)) &&
+-                (atomic_read(&mm->mm_users) != 0));
+-
+-      /*
+-       * mlock:   don't page populate if vma has PROT_NONE permission.
+-       * munlock: always do munlock although the vma has PROT_NONE
+-       *          permission, or SIGKILL is pending.
+-       */
+-      if (!mlock)
+-              gup_flags |= GUP_FLAGS_IGNORE_VMA_PERMISSIONS |
+-                           GUP_FLAGS_IGNORE_SIGKILL;
++      VM_BUG_ON(!rwsem_is_locked(&mm->mmap_sem));
++      gup_flags = 0;
+       if (vma->vm_flags & VM_WRITE)
+-              gup_flags |= GUP_FLAGS_WRITE;
++              gup_flags = GUP_FLAGS_WRITE;
+       while (nr_pages > 0) {
+               int i;
+@@ -201,19 +188,10 @@ static long __mlock_vma_pages_range(stru
+                * This can happen for, e.g., VM_NONLINEAR regions before
+                * a page has been allocated and mapped at a given offset,
+                * or for addresses that map beyond end of a file.
+-               * We'll mlock the the pages if/when they get faulted in.
++               * We'll mlock the pages if/when they get faulted in.
+                */
+               if (ret < 0)
+                       break;
+-              if (ret == 0) {
+-                      /*
+-                       * We know the vma is there, so the only time
+-                       * we cannot get a single page should be an
+-                       * error (ret < 0) case.
+-                       */
+-                      WARN_ON(1);
+-                      break;
+-              }
+               lru_add_drain();        /* push cached pages to LRU */
+@@ -224,28 +202,22 @@ static long __mlock_vma_pages_range(stru
+                       /*
+                        * Because we lock page here and migration is blocked
+                        * by the elevated reference, we need only check for
+-                       * page truncation (file-cache only).
++                       * file-cache page truncation.  This page->mapping
++                       * check also neatly skips over the ZERO_PAGE(),
++                       * though if that's common we'd prefer not to lock it.
+                        */
+-                      if (page->mapping) {
+-                              if (mlock)
+-                                      mlock_vma_page(page);
+-                              else
+-                                      munlock_vma_page(page);
+-                      }
++                      if (page->mapping)
++                              mlock_vma_page(page);
+                       unlock_page(page);
+-                      put_page(page);         /* ref from get_user_pages() */
+-
+-                      /*
+-                       * here we assume that get_user_pages() has given us
+-                       * a list of virtually contiguous pages.
+-                       */
+-                      addr += PAGE_SIZE;      /* for next get_user_pages() */
+-                      nr_pages--;
++                      put_page(page); /* ref from get_user_pages() */
+               }
++
++              addr += ret * PAGE_SIZE;
++              nr_pages -= ret;
+               ret = 0;
+       }
+-      return ret;     /* count entire vma as locked_vm */
++      return ret;     /* 0 or negative error code */
+ }
+ /*
+@@ -289,7 +261,7 @@ long mlock_vma_pages_range(struct vm_are
+                       is_vm_hugetlb_page(vma) ||
+                       vma == get_gate_vma(current))) {
+-              __mlock_vma_pages_range(vma, start, end, 1);
++              __mlock_vma_pages_range(vma, start, end);
+               /* Hide errors from mmap() and other callers */
+               return 0;
+@@ -310,7 +282,6 @@ no_mlock:
+       return nr_pages;                /* error or pages NOT mlocked */
+ }
+-
+ /*
+  * munlock_vma_pages_range() - munlock all pages in the vma range.'
+  * @vma - vma containing range to be munlock()ed.
+@@ -330,10 +301,24 @@ no_mlock:
+  * free them.  This will result in freeing mlocked pages.
+  */
+ void munlock_vma_pages_range(struct vm_area_struct *vma,
+-                         unsigned long start, unsigned long end)
++                           unsigned long start, unsigned long end)
+ {
++      unsigned long addr;
++
++      lru_add_drain();
+       vma->vm_flags &= ~VM_LOCKED;
+-      __mlock_vma_pages_range(vma, start, end, 0);
++
++      for (addr = start; addr < end; addr += PAGE_SIZE) {
++              struct page *page = follow_page(vma, addr, FOLL_GET);
++              if (page) {
++                      lock_page(page);
++                      if (page->mapping)
++                              munlock_vma_page(page);
++                      unlock_page(page);
++                      put_page(page);
++              }
++              cond_resched();
++      }
+ }
+ /*
+@@ -400,18 +385,14 @@ success:
+        * It's okay if try_to_unmap_one unmaps a page just after we
+        * set VM_LOCKED, __mlock_vma_pages_range will bring it back.
+        */
+-      vma->vm_flags = newflags;
+       if (lock) {
+-              ret = __mlock_vma_pages_range(vma, start, end, 1);
+-
+-              if (ret > 0) {
+-                      mm->locked_vm -= ret;
+-                      ret = 0;
+-              } else
+-                      ret = __mlock_posix_error_return(ret); /* translate if needed */
++              vma->vm_flags = newflags;
++              ret = __mlock_vma_pages_range(vma, start, end);
++              if (ret < 0)
++                      ret = __mlock_posix_error_return(ret);
+       } else {
+-              __mlock_vma_pages_range(vma, start, end, 0);
++              munlock_vma_pages_range(vma, start, end);
+       }
+ out:
diff --git a/queue-2.6.31/mmap-avoid-unnecessary-anon_vma-lock-acquisition-in-vma_adjust.patch b/queue-2.6.31/mmap-avoid-unnecessary-anon_vma-lock-acquisition-in-vma_adjust.patch
new file mode 100644 (file)
index 0000000..5080cff
--- /dev/null
@@ -0,0 +1,89 @@
+From 252c5f94d944487e9f50ece7942b0fbf659c5c31 Mon Sep 17 00:00:00 2001
+From: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
+Date: Mon, 21 Sep 2009 17:03:40 -0700
+Subject: mmap: avoid unnecessary anon_vma lock acquisition in vma_adjust()
+
+From: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
+
+commit 252c5f94d944487e9f50ece7942b0fbf659c5c31 upstream.
+
+We noticed very erratic behavior [throughput] with the AIM7 shared
+workload running on recent distro [SLES11] and mainline kernels on an
+8-socket, 32-core, 256GB x86_64 platform.  On the SLES11 kernel
+[2.6.27.19+] with Barcelona processors, as we increased the load [10s of
+thousands of tasks], the throughput would vary between two "plateaus"--one
+at ~65K jobs per minute and one at ~130K jpm.  The simple patch below
+causes the results to smooth out at the ~130k plateau.
+
+But wait, there's more:
+
+We do not see this behavior on smaller platforms--e.g., 4 socket/8 core.
+This could be the result of the larger number of cpus on the larger
+platform--a scalability issue--or it could be the result of the larger
+number of interconnect "hops" between some nodes in this platform and how
+the tasks for a given load end up distributed over the nodes' cpus and
+memories--a stochastic NUMA effect.
+
+The variability in the results are less pronounced [on the same platform]
+with Shanghai processors and with mainline kernels.  With 31-rc6 on
+Shanghai processors and 288 file systems on 288 fibre attached storage
+volumes, the curves [jpm vs load] are both quite flat with the patched
+kernel consistently producing ~3.9% better throughput [~80K jpm vs ~77K
+jpm] than the unpatched kernel.
+
+Profiling indicated that the "slow" runs were incurring high[er]
+contention on an anon_vma lock in vma_adjust(), apparently called from the
+sbrk() system call.
+
+The patch:
+
+A comment in mm/mmap.c:vma_adjust() suggests that we don't really need the
+anon_vma lock when we're only adjusting the end of a vma, as is the case
+for brk().  The comment questions whether it's worth while to optimize for
+this case.  Apparently, on the newer, larger x86_64 platforms, with
+interesting NUMA topologies, it is worth while--especially considering
+that the patch [if correct!] is quite simple.
+
+We can detect this condition--no overlap with next vma--by noting a NULL
+"importer".  The anon_vma pointer will also be NULL in this case, so
+simply avoid loading vma->anon_vma to avoid the lock.
+
+However, we DO need to take the anon_vma lock when we're inserting a vma
+['insert' non-NULL] even when we have no overlap [NULL "importer"], so we
+need to check for 'insert', as well.  And Hugh points out that we should
+also take it when adjusting vm_start (so that rmap.c can rely upon
+vma_address() while it holds the anon_vma lock).
+
+akpm: Zhang Yanmin reprts a 150% throughput improvement with aim7, so it
+might be -stable material even though thiss isn't a regression: "this
+issue is not clear on dual socket Nehalem machine (2*4*2 cpu), but is
+severe on large machine (4*8*2 cpu)"
+
+[hugh.dickins@tiscali.co.uk: test vma start too]
+Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com>
+Signed-off-by: Hugh Dickins <hugh.dickins@tiscali.co.uk>
+Cc: Nick Piggin <npiggin@suse.de>
+Cc: Eric Whitney <eric.whitney@hp.com>
+Tested-by: "Zhang, Yanmin" <yanmin_zhang@linux.intel.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/mmap.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/mm/mmap.c
++++ b/mm/mmap.c
+@@ -570,9 +570,9 @@ again:                     remove_next = 1 + (end > next->
+       /*
+        * When changing only vma->vm_end, we don't really need
+-       * anon_vma lock: but is that case worth optimizing out?
++       * anon_vma lock.
+        */
+-      if (vma->anon_vma)
++      if (vma->anon_vma && (insert || importer || start != vma->vm_start))
+               anon_vma = vma->anon_vma;
+       if (anon_vma) {
+               spin_lock(&anon_vma->lock);
diff --git a/queue-2.6.31/mptsas-pae-kernel-more-than-4-gb-kernel-panic.patch b/queue-2.6.31/mptsas-pae-kernel-more-than-4-gb-kernel-panic.patch
new file mode 100644 (file)
index 0000000..a65c739
--- /dev/null
@@ -0,0 +1,57 @@
+From c55b89fba9872ebcd5ac15cdfdad29ffb89329f0 Mon Sep 17 00:00:00 2001
+From: Kashyap, Desai <kashyap.desai@lsi.com>
+Date: Wed, 2 Sep 2009 11:44:57 +0530
+Subject: [SCSI] mptsas : PAE Kernel more than 4 GB kernel panic
+
+From: Kashyap, Desai <kashyap.desai@lsi.com>
+
+commit c55b89fba9872ebcd5ac15cdfdad29ffb89329f0 upstream.
+
+This patch is solving problem for PAE kernel DMA operation.
+On PAE system dma_addr and unsigned long will have different
+values.
+Now dma_addr is not type casted using unsigned long.
+
+Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley@suse.de>
+Cc: Jan Beulich <JBeulich@novell.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/message/fusion/mptbase.c |   10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/message/fusion/mptbase.c
++++ b/drivers/message/fusion/mptbase.c
+@@ -1015,9 +1015,9 @@ mpt_add_sge_64bit(void *pAddr, u32 flags
+ {
+       SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+       pSge->Address.Low = cpu_to_le32
+-                      (lower_32_bits((unsigned long)(dma_addr)));
++                      (lower_32_bits(dma_addr));
+       pSge->Address.High = cpu_to_le32
+-                      (upper_32_bits((unsigned long)dma_addr));
++                      (upper_32_bits(dma_addr));
+       pSge->FlagsLength = cpu_to_le32
+                       ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
+ }
+@@ -1038,8 +1038,8 @@ mpt_add_sge_64bit_1078(void *pAddr, u32 
+       u32 tmp;
+       pSge->Address.Low = cpu_to_le32
+-                      (lower_32_bits((unsigned long)(dma_addr)));
+-      tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
++                      (lower_32_bits(dma_addr));
++      tmp = (u32)(upper_32_bits(dma_addr));
+       /*
+        * 1078 errata workaround for the 36GB limitation
+@@ -1101,7 +1101,7 @@ mpt_add_chain_64bit(void *pAddr, u8 next
+               pChain->NextChainOffset = next;
+               pChain->Address.Low = cpu_to_le32(tmp);
+-              tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
++              tmp = (u32)(upper_32_bits(dma_addr));
+               pChain->Address.High = cpu_to_le32(tmp);
+ }
diff --git a/queue-2.6.31/nommu-fix-map_private-mmap-of-objects-where-the-data-can-be-mapped-directly.patch b/queue-2.6.31/nommu-fix-map_private-mmap-of-objects-where-the-data-can-be-mapped-directly.patch
new file mode 100644 (file)
index 0000000..814dd64
--- /dev/null
@@ -0,0 +1,143 @@
+From 645d83c5db970a1c57225e155113b4aa2451e920 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Thu, 24 Sep 2009 15:13:10 +0100
+Subject: NOMMU: Fix MAP_PRIVATE mmap() of objects where the data can be mapped directly
+
+From: David Howells <dhowells@redhat.com>
+
+commit 645d83c5db970a1c57225e155113b4aa2451e920 upstream.
+
+Fix MAP_PRIVATE mmap() of files and devices where the data in the backing store
+might be mapped directly.  Use the BDI_CAP_MAP_DIRECT capability flag to govern
+whether or not we should be trying to map a file directly.  This can be used to
+determine whether or not a region has been filled in at the point where we call
+do_mmap_shared() or do_mmap_private().
+
+The BDI_CAP_MAP_DIRECT capability flag is cleared by validate_mmap_request() if
+there's any reason we can't use it.  It's also cleared in do_mmap_pgoff() if
+f_op->get_unmapped_area() fails.
+
+Without this fix, attempting to run a program from a RomFS image on a
+non-mappable MTD partition results in a BUG as the kernel attempts XIP, and
+this can be caught in gdb:
+
+Program received signal SIGABRT, Aborted.
+0xc005dce8 in add_nommu_region (region=<value optimized out>) at mm/nommu.c:547
+(gdb) bt
+#0  0xc005dce8 in add_nommu_region (region=<value optimized out>) at mm/nommu.c:547
+#1  0xc005f168 in do_mmap_pgoff (file=0xc31a6620, addr=<value optimized out>, len=3808, prot=3, flags=6146, pgoff=0) at mm/nommu.c:1373
+#2  0xc00a96b8 in elf_fdpic_map_file (params=0xc33fbbec, file=0xc31a6620, mm=0xc31bef60, what=0xc0213144 "executable") at mm.h:1145
+#3  0xc00aa8b4 in load_elf_fdpic_binary (bprm=0xc316cb00, regs=<value optimized out>) at fs/binfmt_elf_fdpic.c:343
+#4  0xc006b588 in search_binary_handler (bprm=0x6, regs=0xc33fbce0) at fs/exec.c:1234
+#5  0xc006c648 in do_execve (filename=<value optimized out>, argv=0xc3ad14cc, envp=0xc3ad1460, regs=0xc33fbce0) at fs/exec.c:1356
+#6  0xc0008cf0 in sys_execve (name=<value optimized out>, argv=0xc3ad14cc, envp=0xc3ad1460) at arch/frv/kernel/process.c:263
+#7  0xc00075dc in __syscall_call () at arch/frv/kernel/entry.S:897
+
+Note that this fix does the following commit differently:
+
+       commit a190887b58c32d19c2eee007c5eb8faa970a69ba
+       Author: David Howells <dhowells@redhat.com>
+       Date:   Sat Sep 5 11:17:07 2009 -0700
+       nommu: fix error handling in do_mmap_pgoff()
+
+Reported-by: Graff Yang <graff.yang@gmail.com>
+Signed-off-by: David Howells <dhowells@redhat.com>
+Acked-by: Pekka Enberg <penberg@cs.helsinki.fi>
+Cc: Paul Mundt <lethal@linux-sh.org>
+Cc: Mel Gorman <mel@csn.ul.ie>
+Cc: Greg Ungerer <gerg@snapgear.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/nommu.c |   34 ++++++++++++----------------------
+ 1 file changed, 12 insertions(+), 22 deletions(-)
+
+--- a/mm/nommu.c
++++ b/mm/nommu.c
+@@ -1056,7 +1056,7 @@ static int do_mmap_shared_file(struct vm
+       ret = vma->vm_file->f_op->mmap(vma->vm_file, vma);
+       if (ret == 0) {
+               vma->vm_region->vm_top = vma->vm_region->vm_end;
+-              return ret;
++              return 0;
+       }
+       if (ret != -ENOSYS)
+               return ret;
+@@ -1073,7 +1073,8 @@ static int do_mmap_shared_file(struct vm
+  */
+ static int do_mmap_private(struct vm_area_struct *vma,
+                          struct vm_region *region,
+-                         unsigned long len)
++                         unsigned long len,
++                         unsigned long capabilities)
+ {
+       struct page *pages;
+       unsigned long total, point, n, rlen;
+@@ -1084,13 +1085,13 @@ static int do_mmap_private(struct vm_are
+        * shared mappings on devices or memory
+        * - VM_MAYSHARE will be set if it may attempt to share
+        */
+-      if (vma->vm_file) {
++      if (capabilities & BDI_CAP_MAP_DIRECT) {
+               ret = vma->vm_file->f_op->mmap(vma->vm_file, vma);
+               if (ret == 0) {
+                       /* shouldn't return success if we're not sharing */
+                       BUG_ON(!(vma->vm_flags & VM_MAYSHARE));
+                       vma->vm_region->vm_top = vma->vm_region->vm_end;
+-                      return ret;
++                      return 0;
+               }
+               if (ret != -ENOSYS)
+                       return ret;
+@@ -1328,7 +1329,7 @@ unsigned long do_mmap_pgoff(struct file 
+                * - this is the hook for quasi-memory character devices to
+                *   tell us the location of a shared mapping
+                */
+-              if (file && file->f_op->get_unmapped_area) {
++              if (capabilities & BDI_CAP_MAP_DIRECT) {
+                       addr = file->f_op->get_unmapped_area(file, addr, len,
+                                                            pgoff, flags);
+                       if (IS_ERR((void *) addr)) {
+@@ -1352,15 +1353,17 @@ unsigned long do_mmap_pgoff(struct file 
+       }
+       vma->vm_region = region;
+-      add_nommu_region(region);
+-      /* set up the mapping */
++      /* set up the mapping
++       * - the region is filled in if BDI_CAP_MAP_DIRECT is still set
++       */
+       if (file && vma->vm_flags & VM_SHARED)
+               ret = do_mmap_shared_file(vma);
+       else
+-              ret = do_mmap_private(vma, region, len);
++              ret = do_mmap_private(vma, region, len, capabilities);
+       if (ret < 0)
+-              goto error_put_region;
++              goto error_just_free;
++      add_nommu_region(region);
+       /* okay... we have a mapping; now we have to register it */
+       result = vma->vm_start;
+@@ -1378,19 +1381,6 @@ share:
+       kleave(" = %lx", result);
+       return result;
+-error_put_region:
+-      __put_nommu_region(region);
+-      if (vma) {
+-              if (vma->vm_file) {
+-                      fput(vma->vm_file);
+-                      if (vma->vm_flags & VM_EXECUTABLE)
+-                              removed_exe_file_vma(vma->vm_mm);
+-              }
+-              kmem_cache_free(vm_area_cachep, vma);
+-      }
+-      kleave(" = %d [pr]", ret);
+-      return ret;
+-
+ error_just_free:
+       up_write(&nommu_region_sem);
+ error:
diff --git a/queue-2.6.31/page-allocator-limit-the-number-of-migrate_reserve-pageblocks-per-zone.patch b/queue-2.6.31/page-allocator-limit-the-number-of-migrate_reserve-pageblocks-per-zone.patch
new file mode 100644 (file)
index 0000000..cdce28c
--- /dev/null
@@ -0,0 +1,81 @@
+From 78986a678f6ec3759a01976749f4437d8bf2d6c3 Mon Sep 17 00:00:00 2001
+From: Mel Gorman <mel@csn.ul.ie>
+Date: Mon, 21 Sep 2009 17:03:02 -0700
+Subject: page-allocator: limit the number of MIGRATE_RESERVE pageblocks per zone
+
+From: Mel Gorman <mel@csn.ul.ie>
+
+commit 78986a678f6ec3759a01976749f4437d8bf2d6c3 upstream.
+
+After anti-fragmentation was merged, a bug was reported whereby devices
+that depended on high-order atomic allocations were failing.  The solution
+was to preserve a property in the buddy allocator which tended to keep the
+minimum number of free pages in the zone at the lower physical addresses
+and contiguous.  To preserve this property, MIGRATE_RESERVE was introduced
+and a number of pageblocks at the start of a zone would be marked
+"reserve", the number of which depended on min_free_kbytes.
+
+Anti-fragmentation works by avoiding the mixing of page migratetypes
+within the same pageblock.  One way of helping this is to increase
+min_free_kbytes because it becomes less like that it will be necessary to
+place pages of of MIGRATE_RESERVE is unbounded, the free memory is kept
+there in large contiguous blocks instead of helping anti-fragmentation as
+much as it should.  With the page-allocator tracepoint patches applied, it
+was found during anti-fragmentation tests that the number of
+fragmentation-related events were far higher than expected even with
+min_free_kbytes at higher values.
+
+This patch limits the number of MIGRATE_RESERVE blocks that exist per zone
+to two.  For example, with a sufficient min_free_kbytes, 4MB of memory
+will be kept aside on an x86-64 and remain more or less free and
+contiguous for the systems uptime.  This should be sufficient for devices
+depending on high-order atomic allocations while helping fragmentation
+control when min_free_kbytes is tuned appropriately.  As side-effect of
+this patch is that the reserve variable is converted to int as unsigned
+long was the wrong type to use when ensuring that only the required number
+of reserve blocks are created.
+
+With the patches applied, fragmentation-related events as measured by the
+page allocator tracepoints were significantly reduced when running some
+fragmentation stress-tests on systems with min_free_kbytes tuned to a
+value appropriate for hugepage allocations at runtime.  On x86, the events
+recorded were reduced by 99.8%, on x86-64 by 99.72% and on ppc64 by
+99.83%.
+
+Signed-off-by: Mel Gorman <mel@csn.ul.ie>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/page_alloc.c |   12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -2783,7 +2783,8 @@ static void setup_zone_migrate_reserve(s
+ {
+       unsigned long start_pfn, pfn, end_pfn;
+       struct page *page;
+-      unsigned long reserve, block_migratetype;
++      unsigned long block_migratetype;
++      int reserve;
+       /* Get the start pfn, end pfn and the number of blocks to reserve */
+       start_pfn = zone->zone_start_pfn;
+@@ -2791,6 +2792,15 @@ static void setup_zone_migrate_reserve(s
+       reserve = roundup(min_wmark_pages(zone), pageblock_nr_pages) >>
+                                                       pageblock_order;
++      /*
++       * Reserve blocks are generally in place to help high-order atomic
++       * allocations that are short-lived. A min_free_kbytes value that
++       * would result in more than 2 reserve blocks for atomic allocations
++       * is assumed to be in place to help anti-fragmentation for the
++       * future allocation of hugepages at runtime.
++       */
++      reserve = min(2, reserve);
++
+       for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
+               if (!pfn_valid(pfn))
+                       continue;
diff --git a/queue-2.6.31/powerpc-8xx-fix-regression-introduced-by-cache-coherency-rewrite.patch b/queue-2.6.31/powerpc-8xx-fix-regression-introduced-by-cache-coherency-rewrite.patch
new file mode 100644 (file)
index 0000000..4873d5a
--- /dev/null
@@ -0,0 +1,82 @@
+From benh@kernel.crashing.org  Thu Oct  1 15:35:28 2009
+From: Rex Feany <RFeany@mrv.com>
+Date: Thu, 24 Sep 2009 17:16:54 +1000
+Subject: powerpc/8xx: Fix regression introduced by cache coherency rewrite
+To: stable <stable@kernel.org>
+Cc: linuxppc-dev list <linuxppc-dev@ozlabs.org>, RFeany@mrv.com
+Message-ID: <1253776614.7103.434.camel@pasglop>
+
+From: Rex Feany <RFeany@mrv.com>
+
+commit e0908085fc2391c85b85fb814ae1df377c8e0dcb upstream.
+
+After upgrading to the latest kernel on my mpc875 userspace started
+running incredibly slow (hours to get to a shell, even!).
+I tracked it down to commit 8d30c14cab30d405a05f2aaceda1e9ad57800f36,
+that patch removed a work-around for the 8xx. Adding it
+back makes my problem go away.
+
+Signed-off-by: Rex Feany <rfeany@mrv.com>
+Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/powerpc/mm/pgtable.c |   19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+--- a/arch/powerpc/mm/pgtable.c
++++ b/arch/powerpc/mm/pgtable.c
+@@ -30,6 +30,8 @@
+ #include <asm/tlbflush.h>
+ #include <asm/tlb.h>
++#include "mmu_decl.h"
++
+ static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
+ static unsigned long pte_freelist_forced_free;
+@@ -119,7 +121,7 @@ void pte_free_finish(void)
+ /*
+  * Handle i/d cache flushing, called from set_pte_at() or ptep_set_access_flags()
+  */
+-static pte_t do_dcache_icache_coherency(pte_t pte)
++static pte_t do_dcache_icache_coherency(pte_t pte, unsigned long addr)
+ {
+       unsigned long pfn = pte_pfn(pte);
+       struct page *page;
+@@ -128,6 +130,17 @@ static pte_t do_dcache_icache_coherency(
+               return pte;
+       page = pfn_to_page(pfn);
++#ifdef CONFIG_8xx
++       /* On 8xx, cache control instructions (particularly
++        * "dcbst" from flush_dcache_icache) fault as write
++        * operation if there is an unpopulated TLB entry
++        * for the address in question. To workaround that,
++        * we invalidate the TLB here, thus avoiding dcbst
++        * misbehaviour.
++        */
++       _tlbil_va(addr, 0 /* 8xx doesn't care about PID */);
++#endif
++
+       if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)) {
+               pr_devel("do_dcache_icache_coherency... flushing\n");
+               flush_dcache_icache_page(page);
+@@ -198,7 +211,7 @@ void set_pte_at(struct mm_struct *mm, un
+        */
+       pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
+       if (pte_need_exec_flush(pte, 1))
+-              pte = do_dcache_icache_coherency(pte);
++              pte = do_dcache_icache_coherency(pte, addr);
+       /* Perform the setting of the PTE */
+       __set_pte_at(mm, addr, ptep, pte, 0);
+@@ -216,7 +229,7 @@ int ptep_set_access_flags(struct vm_area
+ {
+       int changed;
+       if (!dirty && pte_need_exec_flush(entry, 0))
+-              entry = do_dcache_icache_coherency(entry);
++              entry = do_dcache_icache_coherency(entry, address);
+       changed = !pte_same(*(ptep), entry);
+       if (changed) {
+               if (!(vma->vm_flags & VM_HUGETLB))
diff --git a/queue-2.6.31/powerpc-fix-incorrect-setting-of-__have_arch_pte_special.patch b/queue-2.6.31/powerpc-fix-incorrect-setting-of-__have_arch_pte_special.patch
new file mode 100644 (file)
index 0000000..9cde173
--- /dev/null
@@ -0,0 +1,40 @@
+From benh@kernel.crashing.org  Thu Oct  1 15:36:15 2009
+From: Weirich, Bernhard <Bernhard.Weirich@riedel.net>
+Date: Thu, 24 Sep 2009 17:16:53 +1000
+Subject: powerpc: Fix incorrect setting of __HAVE_ARCH_PTE_SPECIAL
+To: stable <stable@kernel.org>
+Cc: linuxppc-dev list <linuxppc-dev@ozlabs.org>, bernhard.weirich@riedel.net, RFeany@mrv.com
+Message-ID: <1253776613.7103.433.camel@pasglop>
+
+
+From: Weirich, Bernhard <Bernhard.Weirich@riedel.net>
+
+[I'm going to fix upstream differently, by having all CPU types
+actually support _PAGE_SPECIAL, but I prefer the simple and obvious
+fix for -stable. -- Ben]
+
+The test that decides whether to define __HAVE_ARCH_PTE_SPECIAL on
+powerpc is bogus and will end up always defining it, even when
+_PAGE_SPECIAL is not supported (in which case it's 0) such as on
+8xx or 40x processors.
+
+Signed-off-by: Bernhard Weirich <bernhard.weirich@riedel.net>
+Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ arch/powerpc/include/asm/pte-common.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/powerpc/include/asm/pte-common.h
++++ b/arch/powerpc/include/asm/pte-common.h
+@@ -176,7 +176,7 @@ extern unsigned long bad_call_to_PMD_PAG
+ #define HAVE_PAGE_AGP
+ /* Advertise support for _PAGE_SPECIAL */
+-#ifdef _PAGE_SPECIAL
++#if _PAGE_SPECIAL != 0
+ #define __HAVE_ARCH_PTE_SPECIAL
+ #endif
diff --git a/queue-2.6.31/proc-kcore-work-around-a-bug.patch b/queue-2.6.31/proc-kcore-work-around-a-bug.patch
new file mode 100644 (file)
index 0000000..b76d113
--- /dev/null
@@ -0,0 +1,85 @@
+From akpm@linux-foundation.org  Thu Oct  1 15:23:18 2009
+From: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
+Date: Mon, 21 Sep 2009 17:01:02 -0700
+Subject: /proc/kcore: work around a BUG()
+To: torvalds@linux-foundation.org
+Cc: nick@craig-wood.com, kbowa@tuxedu.org, penberg@cs.helsinki.fi, akpm@linux-foundation.org, stable@kernel.org, kamezawa.hiroyu@jp.fujitsu.com
+Message-ID: <200909220001.n8M01223026302@imap1.linux-foundation.org>
+
+
+From: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
+
+Not upstream due to other fixes in .32
+
+
+Works around a BUG() which is triggered when the kernel accesses holes in
+vmalloc regions.
+
+BUG: unable to handle kernel paging request at fa54c000
+IP: [<c04f687a>] read_kcore+0x260/0x31a
+*pde = 3540b067 *pte = 00000000
+Oops: 0000 [#1] SMP
+last sysfs file: /sys/devices/pci0000:00/0000:00:1c.2/0000:03:00.0/ieee80211/phy0/rfkill0/state
+Modules linked in: fuse sco bridge stp llc bnep l2cap bluetooth sunrpc nf_conntrack_ftp ip6t_REJECT nf_conntrack_ipv6 ip6table_filter ip6_tables ipv6 cpufreq_ondemand acpi_cpufreq dm_multipath uinput usb_storage arc4 ecb snd_hda_codec_realtek snd_hda_intel ath5k snd_hda_codec snd_hwdep iTCO_wdt snd_pcm iTCO_vendor_support pcspkr i2c_i801 mac80211 joydev snd_timer serio_raw r8169 snd soundcore mii snd_page_alloc ath cfg80211 ata_generic i915 drm i2c_algo_bit i2c_core video output [last unloaded: scsi_wait_scan]
+Sep  4 12:45:16 tuxedu kernel: Pid: 2266, comm: cat Not tainted (2.6.31-rc8 #2) Joybook Lite U101
+EIP: 0060:[<c04f687a>] EFLAGS: 00010286 CPU: 0
+EIP is at read_kcore+0x260/0x31a
+EAX: f5e5ea00 EBX: fa54d000 ECX: 00000400 EDX: 00001000
+ESI: fa54c000 EDI: f44ad000 EBP: e4533f4c ESP: e4533f24
+DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
+Process cat (pid: 2266, ti=e4532000 task=f09d19a0 task.ti=e4532000)
+Stack:
+00005000 00000000 f44ad000 09d9c000 00003000 fa54c000 00001000 f6d16f60
+ e4520b80 fffffffb e4533f70 c04ef8eb e4533f98 00008000 09d97000 c04f661a
+ e4520b80 09d97000 c04ef88c e4533f8c c04ba531 e4533f98 c04c0930 e4520b80
+Call Trace:
+[<c04ef8eb>] ? proc_reg_read+0x5f/0x73
+[<c04f661a>] ? read_kcore+0x0/0x31a
+[<c04ef88c>] ? proc_reg_read+0x0/0x73
+[<c04ba531>] ? vfs_read+0x82/0xe1
+[<c04c0930>] ? path_put+0x1a/0x1d
+[<c04ba62e>] ? sys_read+0x40/0x62
+[<c0403298>] ? sysenter_do_call+0x12/0x2d
+Code: 39 f3 89 ca 0f 43 f3 89 fb 29 f2 29 f3 39 cf 0f 46 d3 29 55 dc 8d 1c 32 f6 40 0c 01 75 18 89 d1 89 f7 c1 e9 02 2b 7d ec 03 7d e0 <f3> a5 89 d1 83 e1 03 74 02 f3 a4 8b 00 83 7d dc 00 74 04 85 c0
+EIP: [<c04f687a>] read_kcore+0x260/0x31a SS:ESP 0068:e4533f24
+CR2: 00000000fa54c000
+
+
+To access vmalloc area which may have memory holes, copy_from_user is
+useful.  So this:
+
+ # cat /proc/kcore > /dev/null
+
+will not panic.
+
+This is a minimal fix, suitable for 2.6.30.x and 2.6.31.  More extensive
+/proc/kcore changes are planned for 2.6.32.
+
+Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
+Tested-by: Nick Craig-Wood <nick@craig-wood.com>
+Cc: Pekka Enberg <penberg@cs.helsinki.fi>
+Reported-by: <kbowa@tuxedu.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/proc/kcore.c |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/fs/proc/kcore.c
++++ b/fs/proc/kcore.c
+@@ -361,7 +361,13 @@ read_kcore(struct file *file, char __use
+                               /* don't dump ioremap'd stuff! (TA) */
+                               if (m->flags & VM_IOREMAP)
+                                       continue;
+-                              memcpy(elf_buf + (vmstart - start),
++                              /*
++                               * we may access memory holes, then use
++                               * ex_table. checking return value just for
++                               * avoid warnings.
++                               */
++                              vmsize = __copy_from_user_inatomic(
++                                      elf_buf + (vmstart - start),
+                                       (char *)vmstart, vmsize);
+                       }
+                       read_unlock(&vmlist_lock);
diff --git a/queue-2.6.31/saa7134-ir-kbd-i2c-init-data-needs-a-persistent-object.patch b/queue-2.6.31/saa7134-ir-kbd-i2c-init-data-needs-a-persistent-object.patch
new file mode 100644 (file)
index 0000000..59dcd47
--- /dev/null
@@ -0,0 +1,163 @@
+From brian@xyzw.org  Thu Oct  1 15:34:42 2009
+From: Brian Rogers <brian@xyzw.org>
+Date: Wed, 23 Sep 2009 03:05:03 -0700
+Subject: saa7134: ir-kbd-i2c init data needs a persistent object
+To: stable@kernel.org
+Cc: Mauro Carvalho Chehab <mchehab@redhat.com>, linux-kernel@vger.kernel.org, Brian Rogers <brian@xyzw.org>, linux-media@vger.kernel.org
+Message-ID: <1253700303-15172-2-git-send-email-brian@xyzw.org>
+
+From: Brian Rogers <brian@xyzw.org>
+
+commit 7aedd5ec87686c557d48584d69ad880c11a0984d upstream.
+
+Tested on MSI TV@nywhere Plus.
+
+Original commit message:
+
+ir-kbd-i2c's ir_probe() function can be called much later (i.e. at
+ir-kbd-i2c module load), than the lifetime of a struct IR_i2c_init_data
+allocated off of the stack in cx18_i2c_new_ir() at registration time.
+Make sure we pass a pointer to a persistent IR_i2c_init_data object at
+i2c registration time.
+
+Thanks to Brian Rogers, Dustin Mitchell, Andy Walls and Jean Delvare to
+rise this question.
+
+Before this patch, if ir-kbd-i2c were probed after SAA7134, trash data
+were used.
+
+Compile tested only, but the patch is identical to em28xx one. So, it
+should work properly.
+
+Original-patch-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+[brian@xyzw.org: backported for 2.6.31]
+Signed-off-by: Brian Rogers <brian@xyzw.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/saa7134/saa7134-input.c |   56 +++++++++++++---------------
+ drivers/media/video/saa7134/saa7134.h       |    4 ++
+ 2 files changed, 31 insertions(+), 29 deletions(-)
+
+--- a/drivers/media/video/saa7134/saa7134.h
++++ b/drivers/media/video/saa7134/saa7134.h
+@@ -584,6 +584,10 @@ struct saa7134_dev {
+       int                        nosignal;
+       unsigned int               insuspend;
++      /* I2C keyboard data */
++      struct i2c_board_info      info;
++      struct IR_i2c_init_data    init_data;
++
+       /* SAA7134_MPEG_* */
+       struct saa7134_ts          ts;
+       struct saa7134_dmaqueue    ts_q;
+--- a/drivers/media/video/saa7134/saa7134-input.c
++++ b/drivers/media/video/saa7134/saa7134-input.c
+@@ -684,8 +684,6 @@ void saa7134_input_fini(struct saa7134_d
+ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
+ {
+-      struct i2c_board_info info;
+-      struct IR_i2c_init_data init_data;
+       const unsigned short addr_list[] = {
+               0x7a, 0x47, 0x71, 0x2d,
+               I2C_CLIENT_END
+@@ -705,32 +703,32 @@ void saa7134_probe_i2c_ir(struct saa7134
+               return;
+       }
+-      memset(&info, 0, sizeof(struct i2c_board_info));
+-      memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
+-      strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
++      memset(&dev->info, 0, sizeof(dev->info));
++      memset(&dev->init_data, 0, sizeof(dev->init_data));
++      strlcpy(dev->info.type, "ir_video", I2C_NAME_SIZE);
+       switch (dev->board) {
+       case SAA7134_BOARD_PINNACLE_PCTV_110i:
+       case SAA7134_BOARD_PINNACLE_PCTV_310i:
+-              init_data.name = "Pinnacle PCTV";
++              dev->init_data.name = "Pinnacle PCTV";
+               if (pinnacle_remote == 0) {
+-                      init_data.get_key = get_key_pinnacle_color;
+-                      init_data.ir_codes = ir_codes_pinnacle_color;
++                      dev->init_data.get_key = get_key_pinnacle_color;
++                      dev->init_data.ir_codes = ir_codes_pinnacle_color;
+               } else {
+-                      init_data.get_key = get_key_pinnacle_grey;
+-                      init_data.ir_codes = ir_codes_pinnacle_grey;
++                      dev->init_data.get_key = get_key_pinnacle_grey;
++                      dev->init_data.ir_codes = ir_codes_pinnacle_grey;
+               }
+               break;
+       case SAA7134_BOARD_UPMOST_PURPLE_TV:
+-              init_data.name = "Purple TV";
+-              init_data.get_key = get_key_purpletv;
+-              init_data.ir_codes = ir_codes_purpletv;
++              dev->init_data.name = "Purple TV";
++              dev->init_data.get_key = get_key_purpletv;
++              dev->init_data.ir_codes = ir_codes_purpletv;
+               break;
+       case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
+-              init_data.name = "MSI TV@nywhere Plus";
+-              init_data.get_key = get_key_msi_tvanywhere_plus;
+-              init_data.ir_codes = ir_codes_msi_tvanywhere_plus;
+-              info.addr = 0x30;
++              dev->init_data.name = "MSI TV@nywhere Plus";
++              dev->init_data.get_key = get_key_msi_tvanywhere_plus;
++              dev->init_data.ir_codes = ir_codes_msi_tvanywhere_plus;
++              dev->info.addr = 0x30;
+               /* MSI TV@nywhere Plus controller doesn't seem to
+                  respond to probes unless we read something from
+                  an existing device. Weird...
+@@ -741,9 +739,9 @@ void saa7134_probe_i2c_ir(struct saa7134
+                       (1 == rc) ? "yes" : "no");
+               break;
+       case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+-              init_data.name = "HVR 1110";
+-              init_data.get_key = get_key_hvr1110;
+-              init_data.ir_codes = ir_codes_hauppauge_new;
++              dev->init_data.name = "HVR 1110";
++              dev->init_data.get_key = get_key_hvr1110;
++              dev->init_data.ir_codes = ir_codes_hauppauge_new;
+               break;
+       case SAA7134_BOARD_BEHOLD_607FM_MK3:
+       case SAA7134_BOARD_BEHOLD_607FM_MK5:
+@@ -757,26 +755,26 @@ void saa7134_probe_i2c_ir(struct saa7134
+       case SAA7134_BOARD_BEHOLD_M63:
+       case SAA7134_BOARD_BEHOLD_M6_EXTRA:
+       case SAA7134_BOARD_BEHOLD_H6:
+-              init_data.name = "BeholdTV";
+-              init_data.get_key = get_key_beholdm6xx;
+-              init_data.ir_codes = ir_codes_behold;
++              dev->init_data.name = "BeholdTV";
++              dev->init_data.get_key = get_key_beholdm6xx;
++              dev->init_data.ir_codes = ir_codes_behold;
+               break;
+       case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
+       case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+-              info.addr = 0x40;
++              dev->info.addr = 0x40;
+               break;
+       }
+-      if (init_data.name)
+-              info.platform_data = &init_data;
++      if (dev->init_data.name)
++              dev->info.platform_data = &dev->init_data;
+       /* No need to probe if address is known */
+-      if (info.addr) {
+-              i2c_new_device(&dev->i2c_adap, &info);
++      if (dev->info.addr) {
++              i2c_new_device(&dev->i2c_adap, &dev->info);
+               return;
+       }
+       /* Address not known, fallback to probing */
+-      i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
++      i2c_new_probed_device(&dev->i2c_adap, &dev->info, addr_list);
+ }
+ static int saa7134_rc5_irq(struct saa7134_dev *dev)
index 8bb6ee149c579f60d3f9495718471d01e2dcfa3d..ec79e00725bd3d5588baeb04de5423163324d931 100644 (file)
@@ -114,3 +114,23 @@ usb-xhci-check-urb_short_not_ok-before-setting-short-packet-status.patch
 usb-xhci-set-eremoteio-when-xhc-gives-bad-transfer-length.patch
 usb-xhci-support-interrupt-transfers.patch
 usb-fix-ss-endpoint-companion-descriptor-parsing.patch
+proc-kcore-work-around-a-bug.patch
+hugetlb-restore-interleaving-of-bootmem-huge-pages.patch
+page-allocator-limit-the-number-of-migrate_reserve-pageblocks-per-zone.patch
+mm-munlock-use-follow_page.patch
+mm-fix-anonymous-dirtying.patch
+mmap-avoid-unnecessary-anon_vma-lock-acquisition-in-vma_adjust.patch
+fix-idle-time-field-in-proc-uptime.patch
+drm-i915-handle-erestartsys-during-page-fault.patch
+em28xx-ir-kbd-i2c-init-data-needs-a-persistent-object.patch
+saa7134-ir-kbd-i2c-init-data-needs-a-persistent-object.patch
+powerpc-8xx-fix-regression-introduced-by-cache-coherency-rewrite.patch
+powerpc-fix-incorrect-setting-of-__have_arch_pte_special.patch
+hid-completely-remove-apple-mightymouse-from-blacklist.patch
+mptsas-pae-kernel-more-than-4-gb-kernel-panic.patch
+nommu-fix-map_private-mmap-of-objects-where-the-data-can-be-mapped-directly.patch
+iwlwifi-handle-new-firmware-file-with-ucode-build-number-in-header.patch
+iwlwifi-update-1000-series-api-version-to-match-firmware.patch
+iwlagn-modify-digital-svr-for-1000.patch
+iwlwifi-traverse-linklist-to-find-the-valid-otp-block.patch
+iwlwifi-fix-unloading-driver-while-scanning.patch