--- /dev/null
+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;
+ }
+ }
+
--- /dev/null
+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 {
--- /dev/null
+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);
--- /dev/null
+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) },
+ { }
+ };
--- /dev/null
+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;
--- /dev/null
+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)
+
--- /dev/null
+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);
--- /dev/null
+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];
--- /dev/null
+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];
--- /dev/null
+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
--- /dev/null
+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))
--- /dev/null
+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:
--- /dev/null
+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);
--- /dev/null
+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);
+ }
+
--- /dev/null
+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:
--- /dev/null
+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;
--- /dev/null
+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))
--- /dev/null
+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
+
--- /dev/null
+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);
--- /dev/null
+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)
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