From: Greg Kroah-Hartman Date: Thu, 1 Oct 2009 22:46:22 +0000 (-0700) Subject: more .31 patches X-Git-Tag: v2.6.27.36~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3fac561da7693e841bc410791b510ca1996efa9a;p=thirdparty%2Fkernel%2Fstable-queue.git more .31 patches --- diff --git a/queue-2.6.31/drm-i915-handle-erestartsys-during-page-fault.patch b/queue-2.6.31/drm-i915-handle-erestartsys-during-page-fault.patch new file mode 100644 index 00000000000..5326df7b0cc --- /dev/null +++ b/queue-2.6.31/drm-i915-handle-erestartsys-during-page-fault.patch @@ -0,0 +1,87 @@ +From c715089f49844260f1eeae8e3b55af9468ba1325 Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Wed, 23 Sep 2009 00:43:56 +0100 +Subject: drm/i915: Handle ERESTARTSYS during page fault + +From: Chris Wilson + +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 +[anholt: Mostly squash it with another commit] +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i915/i915_gem.c | 29 ++++++++++++----------------- + 1 file changed, 12 insertions(+), 17 deletions(-) + +--- a/drivers/gpu/drm/i915/i915_gem.c ++++ b/drivers/gpu/drm/i915/i915_gem.c +@@ -1151,26 +1151,21 @@ int i915_gem_fault(struct vm_area_struct + mutex_lock(&dev->struct_mutex); + if (!obj_priv->gtt_space) { + ret = i915_gem_object_bind_to_gtt(obj, obj_priv->gtt_alignment); +- if (ret) { +- mutex_unlock(&dev->struct_mutex); +- return VM_FAULT_SIGBUS; +- } ++ if (ret) ++ goto unlock; ++ + list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list); + + ret = i915_gem_object_set_to_gtt_domain(obj, write); +- if (ret) { +- mutex_unlock(&dev->struct_mutex); +- return VM_FAULT_SIGBUS; +- } ++ if (ret) ++ goto unlock; + } + + /* Need a new fence register? */ + if (obj_priv->tiling_mode != I915_TILING_NONE) { + ret = i915_gem_object_get_fence_reg(obj); +- if (ret) { +- mutex_unlock(&dev->struct_mutex); +- return VM_FAULT_SIGBUS; +- } ++ if (ret) ++ goto unlock; + } + + pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) + +@@ -1178,18 +1173,18 @@ int i915_gem_fault(struct vm_area_struct + + /* Finally, remap it using the new GTT offset */ + ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); +- ++unlock: + mutex_unlock(&dev->struct_mutex); + + switch (ret) { ++ case 0: ++ case -ERESTARTSYS: ++ return VM_FAULT_NOPAGE; + case -ENOMEM: + case -EAGAIN: + return VM_FAULT_OOM; +- case -EFAULT: +- case -EINVAL: +- return VM_FAULT_SIGBUS; + default: +- return VM_FAULT_NOPAGE; ++ return VM_FAULT_SIGBUS; + } + } + diff --git a/queue-2.6.31/em28xx-ir-kbd-i2c-init-data-needs-a-persistent-object.patch b/queue-2.6.31/em28xx-ir-kbd-i2c-init-data-needs-a-persistent-object.patch new file mode 100644 index 00000000000..92734969534 --- /dev/null +++ b/queue-2.6.31/em28xx-ir-kbd-i2c-init-data-needs-a-persistent-object.patch @@ -0,0 +1,120 @@ +From brian@xyzw.org Thu Oct 1 15:34:18 2009 +From: Brian Rogers +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 , linux-kernel@vger.kernel.org, Brian Rogers , linux-media@vger.kernel.org +Message-ID: <1253700303-15172-1-git-send-email-brian@xyzw.org> + +From: Brian Rogers + +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 +Signed-off-by: Mauro Carvalho Chehab +[brian@xyzw.org: backported for 2.6.31] +Signed-off-by: Brian Rogers +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/media/video/em28xx/em28xx-cards.c | 32 ++++++++++++++---------------- + drivers/media/video/em28xx/em28xx.h | 4 +++ + 2 files changed, 19 insertions(+), 17 deletions(-) + +--- a/drivers/media/video/em28xx/em28xx-cards.c ++++ b/drivers/media/video/em28xx/em28xx-cards.c +@@ -2170,8 +2170,6 @@ static int em28xx_hint_board(struct em28 + /* ----------------------------------------------------------------------- */ + void em28xx_register_i2c_ir(struct em28xx *dev) + { +- struct i2c_board_info info; +- struct IR_i2c_init_data init_data; + const unsigned short addr_list[] = { + 0x30, 0x47, I2C_CLIENT_END + }; +@@ -2179,9 +2177,9 @@ void em28xx_register_i2c_ir(struct em28x + if (disable_ir) + return; + +- memset(&info, 0, sizeof(struct i2c_board_info)); +- memset(&init_data, 0, sizeof(struct IR_i2c_init_data)); +- strlcpy(info.type, "ir_video", I2C_NAME_SIZE); ++ memset(&dev->info, 0, sizeof(&dev->info)); ++ memset(&dev->init_data, 0, sizeof(dev->init_data)); ++ strlcpy(dev->info.type, "ir_video", I2C_NAME_SIZE); + + /* detect & configure */ + switch (dev->model) { +@@ -2191,19 +2189,19 @@ void em28xx_register_i2c_ir(struct em28x + break; + case (EM2800_BOARD_TERRATEC_CINERGY_200): + case (EM2820_BOARD_TERRATEC_CINERGY_250): +- init_data.ir_codes = ir_codes_em_terratec; +- init_data.get_key = em28xx_get_key_terratec; +- init_data.name = "i2c IR (EM28XX Terratec)"; ++ dev->init_data.ir_codes = ir_codes_em_terratec; ++ dev->init_data.get_key = em28xx_get_key_terratec; ++ dev->init_data.name = "i2c IR (EM28XX Terratec)"; + break; + case (EM2820_BOARD_PINNACLE_USB_2): +- init_data.ir_codes = ir_codes_pinnacle_grey; +- init_data.get_key = em28xx_get_key_pinnacle_usb_grey; +- init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; ++ dev->init_data.ir_codes = ir_codes_pinnacle_grey; ++ dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey; ++ dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; + break; + case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): +- init_data.ir_codes = ir_codes_hauppauge_new; +- init_data.get_key = em28xx_get_key_em_haup; +- init_data.name = "i2c IR (EM2840 Hauppauge)"; ++ dev->init_data.ir_codes = ir_codes_hauppauge_new; ++ dev->init_data.get_key = em28xx_get_key_em_haup; ++ dev->init_data.name = "i2c IR (EM2840 Hauppauge)"; + break; + case (EM2820_BOARD_MSI_VOX_USB_2): + break; +@@ -2215,9 +2213,9 @@ void em28xx_register_i2c_ir(struct em28x + break; + } + +- if (init_data.name) +- info.platform_data = &init_data; +- i2c_new_probed_device(&dev->i2c_adap, &info, addr_list); ++ if (dev->init_data.name) ++ dev->info.platform_data = &dev->init_data; ++ i2c_new_probed_device(&dev->i2c_adap, &dev->info, addr_list); + } + + void em28xx_card_setup(struct em28xx *dev) +--- a/drivers/media/video/em28xx/em28xx.h ++++ b/drivers/media/video/em28xx/em28xx.h +@@ -595,6 +595,10 @@ struct em28xx { + struct delayed_work sbutton_query_work; + + struct em28xx_dvb *dvb; ++ ++ /* I2C keyboard data */ ++ struct i2c_board_info info; ++ struct IR_i2c_init_data init_data; + }; + + struct em28xx_ops { diff --git a/queue-2.6.31/fix-idle-time-field-in-proc-uptime.patch b/queue-2.6.31/fix-idle-time-field-in-proc-uptime.patch new file mode 100644 index 00000000000..1f7f61acf56 --- /dev/null +++ b/queue-2.6.31/fix-idle-time-field-in-proc-uptime.patch @@ -0,0 +1,43 @@ +From 96830a57de1197519b62af6a4c9ceea556c18c3d Mon Sep 17 00:00:00 2001 +From: Michael Abbott +Date: Thu, 24 Sep 2009 10:15:19 +0200 +Subject: Fix idle time field in /proc/uptime + +From: Michael Abbott + +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 +Signed-off-by: Martin Schwidefsky +Signed-off-by: Greg Kroah-Hartman + +--- + 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 + #include + #include ++#include + #include + + static int uptime_proc_show(struct seq_file *m, void *v) + { + struct timespec uptime; + struct timespec idle; +- cputime_t idletime = cputime_add(init_task.utime, init_task.stime); ++ int i; ++ cputime_t idletime = cputime_zero; ++ ++ for_each_possible_cpu(i) ++ idletime = cputime64_add(idletime, kstat_cpu(i).cpustat.idle); + + do_posix_clock_monotonic_gettime(&uptime); + monotonic_to_bootbased(&uptime); diff --git a/queue-2.6.31/hid-completely-remove-apple-mightymouse-from-blacklist.patch b/queue-2.6.31/hid-completely-remove-apple-mightymouse-from-blacklist.patch new file mode 100644 index 00000000000..b89ad8a45c3 --- /dev/null +++ b/queue-2.6.31/hid-completely-remove-apple-mightymouse-from-blacklist.patch @@ -0,0 +1,33 @@ +From 42960a13001aa6df52ca9952ce996f94a744ea65 Mon Sep 17 00:00:00 2001 +From: Jan Scholz +Date: Wed, 26 Aug 2009 13:18:51 +0200 +Subject: HID: completely remove apple mightymouse from blacklist + +From: Jan Scholz + +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 +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hid/hid-core.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -1319,7 +1319,6 @@ static const struct hid_device_id hid_bl + { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, + +- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, + { } + }; diff --git a/queue-2.6.31/hugetlb-restore-interleaving-of-bootmem-huge-pages.patch b/queue-2.6.31/hugetlb-restore-interleaving-of-bootmem-huge-pages.patch new file mode 100644 index 00000000000..4cac521b5ca --- /dev/null +++ b/queue-2.6.31/hugetlb-restore-interleaving-of-bootmem-huge-pages.patch @@ -0,0 +1,73 @@ +From akpm@linux-foundation.org Thu Oct 1 15:24:58 2009 +From: Lee Schermerhorn +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 + +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 +Reviewed-by: Andi Kleen +Cc: Mel Gorman +Cc: David Rientjes +Cc: Adam Litke +Cc: Andy Whitcroft +Cc: Eric Whitney +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman + +--- + mm/hugetlb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -1010,6 +1010,7 @@ int __weak alloc_bootmem_huge_page(struc + NODE_DATA(h->hugetlb_next_nid), + huge_page_size(h), huge_page_size(h), 0); + ++ hstate_next_node(h); + if (addr) { + /* + * Use the beginning of the huge page to store the +@@ -1019,7 +1020,6 @@ int __weak alloc_bootmem_huge_page(struc + m = addr; + goto found; + } +- hstate_next_node(h); + nr_nodes--; + } + return 0; diff --git a/queue-2.6.31/iwlagn-modify-digital-svr-for-1000.patch b/queue-2.6.31/iwlagn-modify-digital-svr-for-1000.patch new file mode 100644 index 00000000000..532b498eb96 --- /dev/null +++ b/queue-2.6.31/iwlagn-modify-digital-svr-for-1000.patch @@ -0,0 +1,61 @@ +From 02c06e4abc0680afd31bf481a803541556757fb6 Mon Sep 17 00:00:00 2001 +From: Wey-Yi Guy +Date: Fri, 17 Jul 2009 09:30:14 -0700 +Subject: iwlagn: modify digital SVR for 1000 + +From: Wey-Yi Guy + +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 +Signed-off-by: Reinette Chatre +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/iwlwifi/iwl-5000.c | 7 +++++++ + drivers/net/wireless/iwlwifi/iwl-prph.h | 5 ++++- + 2 files changed, 11 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/iwlwifi/iwl-5000.c ++++ b/drivers/net/wireless/iwlwifi/iwl-5000.c +@@ -239,6 +239,13 @@ static void iwl5000_nic_config(struct iw + APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, + ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); + ++ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) { ++ /* Setting digital SVR for 1000 card to 1.32V */ ++ iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG, ++ APMG_SVR_DIGITAL_VOLTAGE_1_32, ++ ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); ++ } ++ + spin_unlock_irqrestore(&priv->lock, flags); + } + +--- a/drivers/net/wireless/iwlwifi/iwl-prph.h ++++ b/drivers/net/wireless/iwlwifi/iwl-prph.h +@@ -80,6 +80,8 @@ + #define APMG_RFKILL_REG (APMG_BASE + 0x0014) + #define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c) + #define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020) ++#define APMG_DIGITAL_SVR_REG (APMG_BASE + 0x0058) ++#define APMG_ANALOG_SVR_REG (APMG_BASE + 0x006C) + + #define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200) + #define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800) +@@ -91,7 +93,8 @@ + #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) + #define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */ + #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) +- ++#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ ++#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) + + #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) + diff --git a/queue-2.6.31/iwlwifi-fix-unloading-driver-while-scanning.patch b/queue-2.6.31/iwlwifi-fix-unloading-driver-while-scanning.patch new file mode 100644 index 00000000000..cab27e7227e --- /dev/null +++ b/queue-2.6.31/iwlwifi-fix-unloading-driver-while-scanning.patch @@ -0,0 +1,52 @@ +From reinette.chatre@intel.com Thu Oct 1 15:44:54 2009 +From: Wey-Yi Guy +Date: Wed, 30 Sep 2009 13:01:01 -0700 +Subject: iwlwifi: fix unloading driver while scanning +To: stable@kernel.org +Cc: Reinette Chatre , Wey-Yi Guy , "John W. Linville" +Message-ID: <1254340861-25121-1-git-send-email-reinette.chatre@intel.com> + +From: Wey-Yi Guy + +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 +Signed-off-by: Reinette Chatre +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- + drivers/net/wireless/iwlwifi/iwl-scan.c | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/iwlwifi/iwl-agn.c ++++ b/drivers/net/wireless/iwlwifi/iwl-agn.c +@@ -2215,7 +2215,7 @@ static void iwl_mac_stop(struct ieee8021 + + priv->is_open = 0; + +- if (iwl_is_ready_rf(priv)) { ++ if (iwl_is_ready_rf(priv) || test_bit(STATUS_SCAN_HW, &priv->status)) { + /* stop mac, cancel any scan request and clear + * RXON_FILTER_ASSOC_MSK BIT + */ +--- a/drivers/net/wireless/iwlwifi/iwl-scan.c ++++ b/drivers/net/wireless/iwlwifi/iwl-scan.c +@@ -799,7 +799,8 @@ void iwl_bg_abort_scan(struct work_struc + { + struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); + +- if (!iwl_is_ready(priv)) ++ if (!test_bit(STATUS_READY, &priv->status) || ++ !test_bit(STATUS_GEO_CONFIGURED, &priv->status)) + return; + + mutex_lock(&priv->mutex); diff --git a/queue-2.6.31/iwlwifi-handle-new-firmware-file-with-ucode-build-number-in-header.patch b/queue-2.6.31/iwlwifi-handle-new-firmware-file-with-ucode-build-number-in-header.patch new file mode 100644 index 00000000000..3e03a64a10f --- /dev/null +++ b/queue-2.6.31/iwlwifi-handle-new-firmware-file-with-ucode-build-number-in-header.patch @@ -0,0 +1,588 @@ +From cc0f555d511a5fe9d4519334c8f674a1dbab9e3a Mon Sep 17 00:00:00 2001 +From: Jay Sternberg +Date: Fri, 17 Jul 2009 09:30:16 -0700 +Subject: iwlwifi: Handle new firmware file with ucode build number in header + +From: Jay Sternberg + +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 +Signed-off-by: Reinette Chatre +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/iwlwifi/iwl-3945.c | 40 ++++++++++++++++++++ + drivers/net/wireless/iwlwifi/iwl-4965.c | 39 +++++++++++++++++++ + drivers/net/wireless/iwlwifi/iwl-5000.c | 51 +++++++++++++++++++++++++ + drivers/net/wireless/iwlwifi/iwl-6000.c | 5 +- + drivers/net/wireless/iwlwifi/iwl-agn.c | 55 ++++++++++++++++------------ + drivers/net/wireless/iwlwifi/iwl-core.h | 12 ++++++ + drivers/net/wireless/iwlwifi/iwl-dev.h | 31 +++++++++++---- + drivers/net/wireless/iwlwifi/iwl3945-base.c | 45 ++++++++++++---------- + 8 files changed, 224 insertions(+), 54 deletions(-) + +--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c ++++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c +@@ -2111,7 +2111,7 @@ static void iwl3945_nic_start(struct iwl + */ + static int iwl3945_read_ucode(struct iwl_priv *priv) + { +- struct iwl_ucode *ucode; ++ const struct iwl_ucode_header *ucode; + int ret = -EINVAL, index; + const struct firmware *ucode_raw; + /* firmware file name contains uCode/driver compatibility version */ +@@ -2152,22 +2152,24 @@ static int iwl3945_read_ucode(struct iwl + goto error; + + /* Make sure that we got at least our header! */ +- if (ucode_raw->size < sizeof(*ucode)) { ++ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) { + IWL_ERR(priv, "File size way too small!\n"); + ret = -EINVAL; + goto err_release; + } + + /* Data from ucode file: header followed by uCode images */ +- ucode = (void *)ucode_raw->data; ++ ucode = (struct iwl_ucode_header *)ucode_raw->data; + + priv->ucode_ver = le32_to_cpu(ucode->ver); + api_ver = IWL_UCODE_API(priv->ucode_ver); +- inst_size = le32_to_cpu(ucode->inst_size); +- data_size = le32_to_cpu(ucode->data_size); +- init_size = le32_to_cpu(ucode->init_size); +- init_data_size = le32_to_cpu(ucode->init_data_size); +- boot_size = le32_to_cpu(ucode->boot_size); ++ inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver); ++ data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver); ++ init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver); ++ init_data_size = ++ priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver); ++ boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver); ++ src = priv->cfg->ops->ucode->get_data(ucode, api_ver); + + /* api_ver should match the api version forming part of the + * firmware filename ... but we don't check for that and only rely +@@ -2208,12 +2210,13 @@ static int iwl3945_read_ucode(struct iwl + + + /* Verify size of file vs. image size info in file's header */ +- if (ucode_raw->size < sizeof(*ucode) + ++ if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) + + inst_size + data_size + init_size + + init_data_size + boot_size) { + +- IWL_DEBUG_INFO(priv, "uCode file size %zd too small\n", +- ucode_raw->size); ++ IWL_DEBUG_INFO(priv, ++ "uCode file size %zd does not match expected size\n", ++ ucode_raw->size); + ret = -EINVAL; + goto err_release; + } +@@ -2296,44 +2299,44 @@ static int iwl3945_read_ucode(struct iwl + /* Copy images into buffers for card's bus-master reads ... */ + + /* Runtime instructions (first block of data in file) */ +- src = &ucode->data[0]; +- len = priv->ucode_code.len; ++ len = inst_size; + IWL_DEBUG_INFO(priv, + "Copying (but not loading) uCode instr len %zd\n", len); + memcpy(priv->ucode_code.v_addr, src, len); ++ src += len; ++ + IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", + priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); + + /* Runtime data (2nd block) + * NOTE: Copy into backup buffer will be done in iwl3945_up() */ +- src = &ucode->data[inst_size]; +- len = priv->ucode_data.len; ++ len = data_size; + IWL_DEBUG_INFO(priv, + "Copying (but not loading) uCode data len %zd\n", len); + memcpy(priv->ucode_data.v_addr, src, len); + memcpy(priv->ucode_data_backup.v_addr, src, len); ++ src += len; + + /* Initialization instructions (3rd block) */ + if (init_size) { +- src = &ucode->data[inst_size + data_size]; +- len = priv->ucode_init.len; ++ len = init_size; + IWL_DEBUG_INFO(priv, + "Copying (but not loading) init instr len %zd\n", len); + memcpy(priv->ucode_init.v_addr, src, len); ++ src += len; + } + + /* Initialization data (4th block) */ + if (init_data_size) { +- src = &ucode->data[inst_size + data_size + init_size]; +- len = priv->ucode_init_data.len; ++ len = init_data_size; + IWL_DEBUG_INFO(priv, + "Copying (but not loading) init data len %zd\n", len); + memcpy(priv->ucode_init_data.v_addr, src, len); ++ src += len; + } + + /* Bootstrap instructions (5th block) */ +- src = &ucode->data[inst_size + data_size + init_size + init_data_size]; +- len = priv->ucode_boot.len; ++ len = boot_size; + IWL_DEBUG_INFO(priv, + "Copying (but not loading) boot instr len %zd\n", len); + memcpy(priv->ucode_boot.v_addr, src, len); +--- a/drivers/net/wireless/iwlwifi/iwl-3945.c ++++ b/drivers/net/wireless/iwlwifi/iwl-3945.c +@@ -2784,11 +2784,50 @@ static int iwl3945_load_bsm(struct iwl_p + return 0; + } + ++#define IWL3945_UCODE_GET(item) \ ++static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\ ++ u32 api_ver) \ ++{ \ ++ return le32_to_cpu(ucode->u.v1.item); \ ++} ++ ++static u32 iwl3945_ucode_get_header_size(u32 api_ver) ++{ ++ return UCODE_HEADER_SIZE(1); ++} ++static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode, ++ u32 api_ver) ++{ ++ return 0; ++} ++static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode, ++ u32 api_ver) ++{ ++ return (u8 *) ucode->u.v1.data; ++} ++ ++IWL3945_UCODE_GET(inst_size); ++IWL3945_UCODE_GET(data_size); ++IWL3945_UCODE_GET(init_size); ++IWL3945_UCODE_GET(init_data_size); ++IWL3945_UCODE_GET(boot_size); ++ + static struct iwl_hcmd_ops iwl3945_hcmd = { + .rxon_assoc = iwl3945_send_rxon_assoc, + .commit_rxon = iwl3945_commit_rxon, + }; + ++static struct iwl_ucode_ops iwl3945_ucode = { ++ .get_header_size = iwl3945_ucode_get_header_size, ++ .get_build = iwl3945_ucode_get_build, ++ .get_inst_size = iwl3945_ucode_get_inst_size, ++ .get_data_size = iwl3945_ucode_get_data_size, ++ .get_init_size = iwl3945_ucode_get_init_size, ++ .get_init_data_size = iwl3945_ucode_get_init_data_size, ++ .get_boot_size = iwl3945_ucode_get_boot_size, ++ .get_data = iwl3945_ucode_get_data, ++}; ++ + static struct iwl_lib_ops iwl3945_lib = { + .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl3945_hw_txq_free_tfd, +@@ -2829,6 +2868,7 @@ static struct iwl_hcmd_utils_ops iwl3945 + }; + + static struct iwl_ops iwl3945_ops = { ++ .ucode = &iwl3945_ucode, + .lib = &iwl3945_lib, + .hcmd = &iwl3945_hcmd, + .utils = &iwl3945_hcmd_utils, +--- a/drivers/net/wireless/iwlwifi/iwl-4965.c ++++ b/drivers/net/wireless/iwlwifi/iwl-4965.c +@@ -2221,12 +2221,50 @@ static void iwl4965_cancel_deferred_work + cancel_work_sync(&priv->txpower_work); + } + ++#define IWL4965_UCODE_GET(item) \ ++static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\ ++ u32 api_ver) \ ++{ \ ++ return le32_to_cpu(ucode->u.v1.item); \ ++} ++ ++static u32 iwl4965_ucode_get_header_size(u32 api_ver) ++{ ++ return UCODE_HEADER_SIZE(1); ++} ++static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode, ++ u32 api_ver) ++{ ++ return 0; ++} ++static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode, ++ u32 api_ver) ++{ ++ return (u8 *) ucode->u.v1.data; ++} ++ ++IWL4965_UCODE_GET(inst_size); ++IWL4965_UCODE_GET(data_size); ++IWL4965_UCODE_GET(init_size); ++IWL4965_UCODE_GET(init_data_size); ++IWL4965_UCODE_GET(boot_size); ++ + static struct iwl_hcmd_ops iwl4965_hcmd = { + .rxon_assoc = iwl4965_send_rxon_assoc, + .commit_rxon = iwl_commit_rxon, + .set_rxon_chain = iwl_set_rxon_chain, + }; + ++static struct iwl_ucode_ops iwl4965_ucode = { ++ .get_header_size = iwl4965_ucode_get_header_size, ++ .get_build = iwl4965_ucode_get_build, ++ .get_inst_size = iwl4965_ucode_get_inst_size, ++ .get_data_size = iwl4965_ucode_get_data_size, ++ .get_init_size = iwl4965_ucode_get_init_size, ++ .get_init_data_size = iwl4965_ucode_get_init_data_size, ++ .get_boot_size = iwl4965_ucode_get_boot_size, ++ .get_data = iwl4965_ucode_get_data, ++}; + static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { + .get_hcmd_size = iwl4965_get_hcmd_size, + .build_addsta_hcmd = iwl4965_build_addsta_hcmd, +@@ -2287,6 +2325,7 @@ static struct iwl_lib_ops iwl4965_lib = + }; + + static struct iwl_ops iwl4965_ops = { ++ .ucode = &iwl4965_ucode, + .lib = &iwl4965_lib, + .hcmd = &iwl4965_hcmd, + .utils = &iwl4965_hcmd_utils, +--- a/drivers/net/wireless/iwlwifi/iwl-5000.c ++++ b/drivers/net/wireless/iwlwifi/iwl-5000.c +@@ -1426,6 +1426,44 @@ int iwl5000_calc_rssi(struct iwl_priv *p + return max_rssi - agc - IWL49_RSSI_OFFSET; + } + ++#define IWL5000_UCODE_GET(item) \ ++static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\ ++ u32 api_ver) \ ++{ \ ++ if (api_ver <= 2) \ ++ return le32_to_cpu(ucode->u.v1.item); \ ++ return le32_to_cpu(ucode->u.v2.item); \ ++} ++ ++static u32 iwl5000_ucode_get_header_size(u32 api_ver) ++{ ++ if (api_ver <= 2) ++ return UCODE_HEADER_SIZE(1); ++ return UCODE_HEADER_SIZE(2); ++} ++ ++static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode, ++ u32 api_ver) ++{ ++ if (api_ver <= 2) ++ return 0; ++ return le32_to_cpu(ucode->u.v2.build); ++} ++ ++static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode, ++ u32 api_ver) ++{ ++ if (api_ver <= 2) ++ return (u8 *) ucode->u.v1.data; ++ return (u8 *) ucode->u.v2.data; ++} ++ ++IWL5000_UCODE_GET(inst_size); ++IWL5000_UCODE_GET(data_size); ++IWL5000_UCODE_GET(init_size); ++IWL5000_UCODE_GET(init_data_size); ++IWL5000_UCODE_GET(boot_size); ++ + struct iwl_hcmd_ops iwl5000_hcmd = { + .rxon_assoc = iwl5000_send_rxon_assoc, + .commit_rxon = iwl_commit_rxon, +@@ -1441,6 +1479,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_u + .calc_rssi = iwl5000_calc_rssi, + }; + ++struct iwl_ucode_ops iwl5000_ucode = { ++ .get_header_size = iwl5000_ucode_get_header_size, ++ .get_build = iwl5000_ucode_get_build, ++ .get_inst_size = iwl5000_ucode_get_inst_size, ++ .get_data_size = iwl5000_ucode_get_data_size, ++ .get_init_size = iwl5000_ucode_get_init_size, ++ .get_init_data_size = iwl5000_ucode_get_init_data_size, ++ .get_boot_size = iwl5000_ucode_get_boot_size, ++ .get_data = iwl5000_ucode_get_data, ++}; ++ + struct iwl_lib_ops iwl5000_lib = { + .set_hw_params = iwl5000_hw_set_hw_params, + .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, +@@ -1542,12 +1591,14 @@ static struct iwl_lib_ops iwl5150_lib = + }; + + struct iwl_ops iwl5000_ops = { ++ .ucode = &iwl5000_ucode, + .lib = &iwl5000_lib, + .hcmd = &iwl5000_hcmd, + .utils = &iwl5000_hcmd_utils, + }; + + static struct iwl_ops iwl5150_ops = { ++ .ucode = &iwl5000_ucode, + .lib = &iwl5150_lib, + .hcmd = &iwl5000_hcmd, + .utils = &iwl5000_hcmd_utils, +--- a/drivers/net/wireless/iwlwifi/iwl-6000.c ++++ b/drivers/net/wireless/iwlwifi/iwl-6000.c +@@ -46,8 +46,8 @@ + #include "iwl-5000-hw.h" + + /* Highest firmware API version supported */ +-#define IWL6000_UCODE_API_MAX 2 +-#define IWL6050_UCODE_API_MAX 2 ++#define IWL6000_UCODE_API_MAX 3 ++#define IWL6050_UCODE_API_MAX 3 + + /* Lowest firmware API version supported */ + #define IWL6000_UCODE_API_MIN 1 +@@ -69,6 +69,7 @@ static struct iwl_hcmd_utils_ops iwl6000 + }; + + static struct iwl_ops iwl6000_ops = { ++ .ucode = &iwl5000_ucode, + .lib = &iwl5000_lib, + .hcmd = &iwl5000_hcmd, + .utils = &iwl6000_hcmd_utils, +--- a/drivers/net/wireless/iwlwifi/iwl-agn.c ++++ b/drivers/net/wireless/iwlwifi/iwl-agn.c +@@ -1348,7 +1348,7 @@ static void iwl_nic_start(struct iwl_pri + */ + static int iwl_read_ucode(struct iwl_priv *priv) + { +- struct iwl_ucode *ucode; ++ struct iwl_ucode_header *ucode; + int ret = -EINVAL, index; + const struct firmware *ucode_raw; + const char *name_pre = priv->cfg->fw_name_pre; +@@ -1357,7 +1357,8 @@ static int iwl_read_ucode(struct iwl_pri + char buf[25]; + u8 *src; + size_t len; +- u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; ++ u32 api_ver, build; ++ u32 inst_size, data_size, init_size, init_data_size, boot_size; + + /* Ask kernel firmware_class module to get the boot firmware off disk. + * request_firmware() is synchronous, file is in memory on return. */ +@@ -1387,23 +1388,26 @@ static int iwl_read_ucode(struct iwl_pri + if (ret < 0) + goto error; + +- /* Make sure that we got at least our header! */ +- if (ucode_raw->size < sizeof(*ucode)) { ++ /* Make sure that we got at least the v1 header! */ ++ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) { + IWL_ERR(priv, "File size way too small!\n"); + ret = -EINVAL; + goto err_release; + } + + /* Data from ucode file: header followed by uCode images */ +- ucode = (void *)ucode_raw->data; ++ ucode = (struct iwl_ucode_header *)ucode_raw->data; + + priv->ucode_ver = le32_to_cpu(ucode->ver); + api_ver = IWL_UCODE_API(priv->ucode_ver); +- inst_size = le32_to_cpu(ucode->inst_size); +- data_size = le32_to_cpu(ucode->data_size); +- init_size = le32_to_cpu(ucode->init_size); +- init_data_size = le32_to_cpu(ucode->init_data_size); +- boot_size = le32_to_cpu(ucode->boot_size); ++ build = priv->cfg->ops->ucode->get_build(ucode, api_ver); ++ inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver); ++ data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver); ++ init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver); ++ init_data_size = ++ priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver); ++ boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver); ++ src = priv->cfg->ops->ucode->get_data(ucode, api_ver); + + /* api_ver should match the api version forming part of the + * firmware filename ... but we don't check for that and only rely +@@ -1429,6 +1433,9 @@ static int iwl_read_ucode(struct iwl_pri + IWL_UCODE_API(priv->ucode_ver), + IWL_UCODE_SERIAL(priv->ucode_ver)); + ++ if (build) ++ IWL_DEBUG_INFO(priv, "Build %u\n", build); ++ + IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", + priv->ucode_ver); + IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n", +@@ -1443,12 +1450,14 @@ static int iwl_read_ucode(struct iwl_pri + boot_size); + + /* Verify size of file vs. image size info in file's header */ +- if (ucode_raw->size < sizeof(*ucode) + ++ if (ucode_raw->size != ++ priv->cfg->ops->ucode->get_header_size(api_ver) + + inst_size + data_size + init_size + + init_data_size + boot_size) { + +- IWL_DEBUG_INFO(priv, "uCode file size %d too small\n", +- (int)ucode_raw->size); ++ IWL_DEBUG_INFO(priv, ++ "uCode file size %d does not match expected size\n", ++ (int)ucode_raw->size); + ret = -EINVAL; + goto err_release; + } +@@ -1528,42 +1537,42 @@ static int iwl_read_ucode(struct iwl_pri + /* Copy images into buffers for card's bus-master reads ... */ + + /* Runtime instructions (first block of data in file) */ +- src = &ucode->data[0]; +- len = priv->ucode_code.len; ++ len = inst_size; + IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len); + memcpy(priv->ucode_code.v_addr, src, len); ++ src += len; ++ + IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", + priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); + + /* Runtime data (2nd block) + * NOTE: Copy into backup buffer will be done in iwl_up() */ +- src = &ucode->data[inst_size]; +- len = priv->ucode_data.len; ++ len = data_size; + IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len); + memcpy(priv->ucode_data.v_addr, src, len); + memcpy(priv->ucode_data_backup.v_addr, src, len); ++ src += len; + + /* Initialization instructions (3rd block) */ + if (init_size) { +- src = &ucode->data[inst_size + data_size]; +- len = priv->ucode_init.len; ++ len = init_size; + IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n", + len); + memcpy(priv->ucode_init.v_addr, src, len); ++ src += len; + } + + /* Initialization data (4th block) */ + if (init_data_size) { +- src = &ucode->data[inst_size + data_size + init_size]; +- len = priv->ucode_init_data.len; ++ len = init_data_size; + IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n", + len); + memcpy(priv->ucode_init_data.v_addr, src, len); ++ src += len; + } + + /* Bootstrap instructions (5th block) */ +- src = &ucode->data[inst_size + data_size + init_size + init_data_size]; +- len = priv->ucode_boot.len; ++ len = boot_size; + IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len); + memcpy(priv->ucode_boot.v_addr, src, len); + +--- a/drivers/net/wireless/iwlwifi/iwl-core.h ++++ b/drivers/net/wireless/iwlwifi/iwl-core.h +@@ -116,6 +116,17 @@ struct iwl_temp_ops { + void (*set_ct_kill)(struct iwl_priv *priv); + }; + ++struct iwl_ucode_ops { ++ u32 (*get_header_size)(u32); ++ u32 (*get_build)(const struct iwl_ucode_header *, u32); ++ u32 (*get_inst_size)(const struct iwl_ucode_header *, u32); ++ u32 (*get_data_size)(const struct iwl_ucode_header *, u32); ++ u32 (*get_init_size)(const struct iwl_ucode_header *, u32); ++ u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32); ++ u32 (*get_boot_size)(const struct iwl_ucode_header *, u32); ++ u8 * (*get_data)(const struct iwl_ucode_header *, u32); ++}; ++ + struct iwl_lib_ops { + /* set hw dependent parameters */ + int (*set_hw_params)(struct iwl_priv *priv); +@@ -171,6 +182,7 @@ struct iwl_lib_ops { + }; + + struct iwl_ops { ++ const struct iwl_ucode_ops *ucode; + const struct iwl_lib_ops *lib; + const struct iwl_hcmd_ops *hcmd; + const struct iwl_hcmd_utils_ops *utils; +--- a/drivers/net/wireless/iwlwifi/iwl-dev.h ++++ b/drivers/net/wireless/iwlwifi/iwl-dev.h +@@ -66,6 +66,7 @@ extern struct iwl_cfg iwl1000_bgn_cfg; + /* shared structures from iwl-5000.c */ + extern struct iwl_mod_params iwl50_mod_params; + extern struct iwl_ops iwl5000_ops; ++extern struct iwl_ucode_ops iwl5000_ucode; + extern struct iwl_lib_ops iwl5000_lib; + extern struct iwl_hcmd_ops iwl5000_hcmd; + extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils; +@@ -525,15 +526,29 @@ struct fw_desc { + }; + + /* uCode file layout */ +-struct iwl_ucode { +- __le32 ver; /* major/minor/API/serial */ +- __le32 inst_size; /* bytes of runtime instructions */ +- __le32 data_size; /* bytes of runtime data */ +- __le32 init_size; /* bytes of initialization instructions */ +- __le32 init_data_size; /* bytes of initialization data */ +- __le32 boot_size; /* bytes of bootstrap instructions */ +- u8 data[0]; /* data in same order as "size" elements */ ++struct iwl_ucode_header { ++ __le32 ver; /* major/minor/API/serial */ ++ union { ++ struct { ++ __le32 inst_size; /* bytes of runtime code */ ++ __le32 data_size; /* bytes of runtime data */ ++ __le32 init_size; /* bytes of init code */ ++ __le32 init_data_size; /* bytes of init data */ ++ __le32 boot_size; /* bytes of bootstrap code */ ++ u8 data[0]; /* in same order as sizes */ ++ } v1; ++ struct { ++ __le32 build; /* build number */ ++ __le32 inst_size; /* bytes of runtime code */ ++ __le32 data_size; /* bytes of runtime data */ ++ __le32 init_size; /* bytes of init code */ ++ __le32 init_data_size; /* bytes of init data */ ++ __le32 boot_size; /* bytes of bootstrap code */ ++ u8 data[0]; /* in same order as sizes */ ++ } v2; ++ } u; + }; ++#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28) + + struct iwl4965_ibss_seq { + u8 mac[ETH_ALEN]; diff --git a/queue-2.6.31/iwlwifi-traverse-linklist-to-find-the-valid-otp-block.patch b/queue-2.6.31/iwlwifi-traverse-linklist-to-find-the-valid-otp-block.patch new file mode 100644 index 00000000000..ef2de3741f2 --- /dev/null +++ b/queue-2.6.31/iwlwifi-traverse-linklist-to-find-the-valid-otp-block.patch @@ -0,0 +1,432 @@ +From reinette.chatre@intel.com Thu Oct 1 15:42:57 2009 +From: Wey-Yi Guy +Date: Wed, 30 Sep 2009 15:36:15 -0700 +Subject: iwlwifi: traverse linklist to find the valid OTP block +To: Greg KH +Cc: "stable@kernel.org" , "linux-wireless@vger.kernel.org" +Message-ID: <1254350175.26521.1662.camel@rc-desk> + + +From: Wey-Yi Guy + +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 +Signed-off-by: Reinette Chatre +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + 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.ucode. + * @ucode_api_max: Highest version of uCode API supported by driver. + * @ucode_api_min: Lowest version of uCode API supported by driver. ++ * @max_ll_items: max number of OTP blocks ++ * @shadow_ram_support: shadow support for OTP memory + * + * We enable the driver to be backward compatible wrt API version. The + * driver specifies which APIs it supports (with @ucode_api_max being the +@@ -243,6 +245,8 @@ struct iwl_cfg { + u8 valid_rx_ant; + bool need_pll_cfg; + bool use_isr_legacy; ++ const u16 max_ll_items; ++ const bool shadow_ram_support; + }; + + /*************************** +--- a/drivers/net/wireless/iwlwifi/iwl-dev.h ++++ b/drivers/net/wireless/iwlwifi/iwl-dev.h +@@ -835,6 +835,18 @@ enum iwl_nvm_type { + NVM_DEVICE_TYPE_OTP, + }; + ++/* ++ * Two types of OTP memory access modes ++ * IWL_OTP_ACCESS_ABSOLUTE - absolute address mode, ++ * based on physical memory addressing ++ * IWL_OTP_ACCESS_RELATIVE - relative address mode, ++ * based on logical memory addressing ++ */ ++enum iwl_access_mode { ++ IWL_OTP_ACCESS_ABSOLUTE, ++ IWL_OTP_ACCESS_RELATIVE, ++}; ++ + /* interrupt statistics */ + struct isr_statistics { + u32 hw; +--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c ++++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c +@@ -152,6 +152,19 @@ int iwlcore_eeprom_verify_signature(stru + } + EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); + ++static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) ++{ ++ u32 otpgp; ++ ++ otpgp = iwl_read32(priv, CSR_OTP_GP_REG); ++ if (mode == IWL_OTP_ACCESS_ABSOLUTE) ++ iwl_clear_bit(priv, CSR_OTP_GP_REG, ++ CSR_OTP_GP_REG_OTP_ACCESS_MODE); ++ else ++ iwl_set_bit(priv, CSR_OTP_GP_REG, ++ CSR_OTP_GP_REG_OTP_ACCESS_MODE); ++} ++ + static int iwlcore_get_nvm_type(struct iwl_priv *priv) + { + u32 otpgp; +@@ -249,6 +262,124 @@ static int iwl_init_otp_access(struct iw + return ret; + } + ++static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) ++{ ++ int ret = 0; ++ u32 r; ++ u32 otpgp; ++ ++ _iwl_write32(priv, CSR_EEPROM_REG, ++ CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); ++ ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, ++ CSR_EEPROM_REG_READ_VALID_MSK, ++ IWL_EEPROM_ACCESS_TIMEOUT); ++ if (ret < 0) { ++ IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); ++ return ret; ++ } ++ r = _iwl_read_direct32(priv, CSR_EEPROM_REG); ++ /* check for ECC errors: */ ++ otpgp = iwl_read32(priv, CSR_OTP_GP_REG); ++ if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { ++ /* stop in this case */ ++ /* set the uncorrectable OTP ECC bit for acknowledgement */ ++ iwl_set_bit(priv, CSR_OTP_GP_REG, ++ CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); ++ IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n"); ++ return -EINVAL; ++ } ++ if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { ++ /* continue in this case */ ++ /* set the correctable OTP ECC bit for acknowledgement */ ++ iwl_set_bit(priv, CSR_OTP_GP_REG, ++ CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); ++ IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); ++ } ++ *eeprom_data = le16_to_cpu((__force __le16)(r >> 16)); ++ return 0; ++} ++ ++/* ++ * iwl_is_otp_empty: check for empty OTP ++ */ ++static bool iwl_is_otp_empty(struct iwl_priv *priv) ++{ ++ u16 next_link_addr = 0, link_value; ++ bool is_empty = false; ++ ++ /* locate the beginning of OTP link list */ ++ if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) { ++ if (!link_value) { ++ IWL_ERR(priv, "OTP is empty\n"); ++ is_empty = true; ++ } ++ } else { ++ IWL_ERR(priv, "Unable to read first block of OTP list.\n"); ++ is_empty = true; ++ } ++ ++ return is_empty; ++} ++ ++ ++/* ++ * iwl_find_otp_image: find EEPROM image in OTP ++ * finding the OTP block that contains the EEPROM image. ++ * the last valid block on the link list (the block _before_ the last block) ++ * is the block we should read and used to configure the device. ++ * If all the available OTP blocks are full, the last block will be the block ++ * we should read and used to configure the device. ++ * only perform this operation if shadow RAM is disabled ++ */ ++static int iwl_find_otp_image(struct iwl_priv *priv, ++ u16 *validblockaddr) ++{ ++ u16 next_link_addr = 0, link_value = 0, valid_addr; ++ int ret = 0; ++ int usedblocks = 0; ++ ++ /* set addressing mode to absolute to traverse the link list */ ++ iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE); ++ ++ /* checking for empty OTP or error */ ++ if (iwl_is_otp_empty(priv)) ++ return -EINVAL; ++ ++ /* ++ * start traverse link list ++ * until reach the max number of OTP blocks ++ * different devices have different number of OTP blocks ++ */ ++ do { ++ /* save current valid block address ++ * check for more block on the link list ++ */ ++ valid_addr = next_link_addr; ++ next_link_addr = link_value; ++ IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n", ++ usedblocks, next_link_addr); ++ if (iwl_read_otp_word(priv, next_link_addr, &link_value)) ++ return -EINVAL; ++ if (!link_value) { ++ /* ++ * reach the end of link list, ++ * set address point to the starting address ++ * of the image ++ */ ++ goto done; ++ } ++ /* more in the link list, continue */ ++ usedblocks++; ++ } while (usedblocks < priv->cfg->max_ll_items); ++ /* OTP full, use last block */ ++ IWL_DEBUG_INFO(priv, "OTP is full, use last block\n"); ++done: ++ *validblockaddr = valid_addr; ++ /* skip first 2 bytes (link list pointer) */ ++ *validblockaddr += 2; ++ return ret; ++} ++ + /** + * iwl_eeprom_init - read EEPROM contents + * +@@ -263,14 +394,13 @@ int iwl_eeprom_init(struct iwl_priv *pri + int sz; + int ret; + u16 addr; +- u32 otpgp; ++ u16 validblockaddr = 0; ++ u16 cache_addr = 0; + + priv->nvm_device_type = iwlcore_get_nvm_type(priv); + + /* allocate eeprom */ +- if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) +- priv->cfg->eeprom_size = +- OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL; ++ IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size); + sz = priv->cfg->eeprom_size; + priv->eeprom = kzalloc(sz, GFP_KERNEL); + if (!priv->eeprom) { +@@ -298,46 +428,31 @@ int iwl_eeprom_init(struct iwl_priv *pri + if (ret) { + IWL_ERR(priv, "Failed to initialize OTP access.\n"); + ret = -ENOENT; +- goto err; ++ goto done; + } + _iwl_write32(priv, CSR_EEPROM_GP, + iwl_read32(priv, CSR_EEPROM_GP) & + ~CSR_EEPROM_GP_IF_OWNER_MSK); +- /* clear */ +- _iwl_write32(priv, CSR_OTP_GP_REG, +- iwl_read32(priv, CSR_OTP_GP_REG) | ++ ++ iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | + CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); +- +- for (addr = 0; addr < sz; addr += sizeof(u16)) { +- u32 r; +- +- _iwl_write32(priv, CSR_EEPROM_REG, +- CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); +- +- ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, +- CSR_EEPROM_REG_READ_VALID_MSK, +- IWL_EEPROM_ACCESS_TIMEOUT); +- if (ret < 0) { +- IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); ++ /* traversing the linked list if no shadow ram supported */ ++ if (!priv->cfg->shadow_ram_support) { ++ if (iwl_find_otp_image(priv, &validblockaddr)) { ++ ret = -ENOENT; + goto done; + } +- r = _iwl_read_direct32(priv, CSR_EEPROM_REG); +- /* check for ECC errors: */ +- otpgp = iwl_read32(priv, CSR_OTP_GP_REG); +- if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { +- /* stop in this case */ +- IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n"); ++ } ++ for (addr = validblockaddr; addr < validblockaddr + sz; ++ addr += sizeof(u16)) { ++ u16 eeprom_data; ++ ++ ret = iwl_read_otp_word(priv, addr, &eeprom_data); ++ if (ret) + goto done; +- } +- if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { +- /* continue in this case */ +- _iwl_write32(priv, CSR_OTP_GP_REG, +- iwl_read32(priv, CSR_OTP_GP_REG) | +- CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); +- IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); +- } +- e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); ++ e[cache_addr / 2] = eeprom_data; ++ cache_addr += sizeof(u16); + } + } else { + /* eeprom is an array of 16bit values */ +--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h ++++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h +@@ -180,8 +180,14 @@ struct iwl_eeprom_channel { + #define EEPROM_5050_EEPROM_VERSION (0x21E) + + /* OTP */ +-#define OTP_LOWER_BLOCKS_TOTAL (3) +-#define OTP_BLOCK_SIZE (0x400) ++/* lower blocks contain EEPROM image and calibration data */ ++#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */ ++/* high blocks contain PAPD data */ ++#define OTP_HIGH_IMAGE_SIZE_6x00 (6 * 512 * sizeof(u16)) /* 6 KB */ ++#define OTP_HIGH_IMAGE_SIZE_1000 (0x200 * sizeof(u16)) /* 1024 bytes */ ++#define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */ ++#define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */ ++#define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */ + + /* 2.4 GHz */ + extern const u8 iwl_eeprom_band_1[14]; diff --git a/queue-2.6.31/iwlwifi-update-1000-series-api-version-to-match-firmware.patch b/queue-2.6.31/iwlwifi-update-1000-series-api-version-to-match-firmware.patch new file mode 100644 index 00000000000..339a1f6316a --- /dev/null +++ b/queue-2.6.31/iwlwifi-update-1000-series-api-version-to-match-firmware.patch @@ -0,0 +1,31 @@ +From cce53aa347c1e023d967b1cb1aa393c725aedba5 Mon Sep 17 00:00:00 2001 +From: Jay Sternberg +Date: Fri, 17 Jul 2009 09:30:22 -0700 +Subject: iwlwifi: update 1000 series API version to match firmware + +From: Jay Sternberg + +commit cce53aa347c1e023d967b1cb1aa393c725aedba5 upstream. + +firmware file now contains build number so API needs to be updated. + +Signed-off-by: Jay Sternberg +Signed-off-by: Reinette Chatre +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/iwlwifi/iwl-1000.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/iwlwifi/iwl-1000.c ++++ b/drivers/net/wireless/iwlwifi/iwl-1000.c +@@ -46,7 +46,7 @@ + #include "iwl-5000-hw.h" + + /* Highest firmware API version supported */ +-#define IWL1000_UCODE_API_MAX 2 ++#define IWL1000_UCODE_API_MAX 3 + + /* Lowest firmware API version supported */ + #define IWL1000_UCODE_API_MIN 1 diff --git a/queue-2.6.31/mm-fix-anonymous-dirtying.patch b/queue-2.6.31/mm-fix-anonymous-dirtying.patch new file mode 100644 index 00000000000..adab55830da --- /dev/null +++ b/queue-2.6.31/mm-fix-anonymous-dirtying.patch @@ -0,0 +1,43 @@ +From 1ac0cb5d0e22d5e483f56b2bc12172dec1cf7536 Mon Sep 17 00:00:00 2001 +From: Hugh Dickins +Date: Mon, 21 Sep 2009 17:03:29 -0700 +Subject: mm: fix anonymous dirtying + +From: Hugh Dickins + +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 +Acked-by: Rik van Riel +Cc: KAMEZAWA Hiroyuki +Cc: KOSAKI Motohiro +Cc: Nick Piggin +Cc: Mel Gorman +Cc: Minchan Kim +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/memory.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -2638,7 +2638,8 @@ static int do_anonymous_page(struct mm_s + goto oom_free_page; + + entry = mk_pte(page, vma->vm_page_prot); +- entry = maybe_mkwrite(pte_mkdirty(entry), vma); ++ if (vma->vm_flags & VM_WRITE) ++ entry = pte_mkwrite(pte_mkdirty(entry)); + + page_table = pte_offset_map_lock(mm, pmd, address, &ptl); + if (!pte_none(*page_table)) diff --git a/queue-2.6.31/mm-munlock-use-follow_page.patch b/queue-2.6.31/mm-munlock-use-follow_page.patch new file mode 100644 index 00000000000..ac728330f16 --- /dev/null +++ b/queue-2.6.31/mm-munlock-use-follow_page.patch @@ -0,0 +1,232 @@ +From 408e82b78bcc9f1b47c76e833c3df97f675947de Mon Sep 17 00:00:00 2001 +From: Hugh Dickins +Date: Mon, 21 Sep 2009 17:03:23 -0700 +Subject: mm: munlock use follow_page + +From: Hugh Dickins + +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 +Acked-by: Rik van Riel +Reviewed-by: Minchan Kim +Cc: KAMEZAWA Hiroyuki +Cc: KOSAKI Motohiro +Cc: Nick Piggin +Cc: Mel Gorman +Reviewed-by: Hiroaki Wakabayashi +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/mlock.c | 99 ++++++++++++++++++++++++------------------------------------- + 1 file changed, 40 insertions(+), 59 deletions(-) + +--- a/mm/mlock.c ++++ b/mm/mlock.c +@@ -139,49 +139,36 @@ static void munlock_vma_page(struct page + } + + /** +- * __mlock_vma_pages_range() - mlock/munlock a range of pages in the vma. ++ * __mlock_vma_pages_range() - mlock a range of pages in the vma. + * @vma: target vma + * @start: start address + * @end: end address +- * @mlock: 0 indicate munlock, otherwise mlock. + * +- * If @mlock == 0, unlock an mlocked range; +- * else mlock the range of pages. This takes care of making the pages present , +- * too. ++ * This takes care of making the pages present too. + * + * return 0 on success, negative error code on error. + * + * vma->vm_mm->mmap_sem must be held for at least read. + */ + static long __mlock_vma_pages_range(struct vm_area_struct *vma, +- unsigned long start, unsigned long end, +- int mlock) ++ unsigned long start, unsigned long end) + { + struct mm_struct *mm = vma->vm_mm; + unsigned long addr = start; + struct page *pages[16]; /* 16 gives a reasonable batch */ + int nr_pages = (end - start) / PAGE_SIZE; + int ret = 0; +- int gup_flags = 0; ++ int gup_flags; + + VM_BUG_ON(start & ~PAGE_MASK); + VM_BUG_ON(end & ~PAGE_MASK); + VM_BUG_ON(start < vma->vm_start); + VM_BUG_ON(end > vma->vm_end); +- VM_BUG_ON((!rwsem_is_locked(&mm->mmap_sem)) && +- (atomic_read(&mm->mm_users) != 0)); +- +- /* +- * mlock: don't page populate if vma has PROT_NONE permission. +- * munlock: always do munlock although the vma has PROT_NONE +- * permission, or SIGKILL is pending. +- */ +- if (!mlock) +- gup_flags |= GUP_FLAGS_IGNORE_VMA_PERMISSIONS | +- GUP_FLAGS_IGNORE_SIGKILL; ++ VM_BUG_ON(!rwsem_is_locked(&mm->mmap_sem)); + ++ gup_flags = 0; + if (vma->vm_flags & VM_WRITE) +- gup_flags |= GUP_FLAGS_WRITE; ++ gup_flags = GUP_FLAGS_WRITE; + + while (nr_pages > 0) { + int i; +@@ -201,19 +188,10 @@ static long __mlock_vma_pages_range(stru + * This can happen for, e.g., VM_NONLINEAR regions before + * a page has been allocated and mapped at a given offset, + * or for addresses that map beyond end of a file. +- * We'll mlock the the pages if/when they get faulted in. ++ * We'll mlock the pages if/when they get faulted in. + */ + if (ret < 0) + break; +- if (ret == 0) { +- /* +- * We know the vma is there, so the only time +- * we cannot get a single page should be an +- * error (ret < 0) case. +- */ +- WARN_ON(1); +- break; +- } + + lru_add_drain(); /* push cached pages to LRU */ + +@@ -224,28 +202,22 @@ static long __mlock_vma_pages_range(stru + /* + * Because we lock page here and migration is blocked + * by the elevated reference, we need only check for +- * page truncation (file-cache only). ++ * file-cache page truncation. This page->mapping ++ * check also neatly skips over the ZERO_PAGE(), ++ * though if that's common we'd prefer not to lock it. + */ +- if (page->mapping) { +- if (mlock) +- mlock_vma_page(page); +- else +- munlock_vma_page(page); +- } ++ if (page->mapping) ++ mlock_vma_page(page); + unlock_page(page); +- put_page(page); /* ref from get_user_pages() */ +- +- /* +- * here we assume that get_user_pages() has given us +- * a list of virtually contiguous pages. +- */ +- addr += PAGE_SIZE; /* for next get_user_pages() */ +- nr_pages--; ++ put_page(page); /* ref from get_user_pages() */ + } ++ ++ addr += ret * PAGE_SIZE; ++ nr_pages -= ret; + ret = 0; + } + +- return ret; /* count entire vma as locked_vm */ ++ return ret; /* 0 or negative error code */ + } + + /* +@@ -289,7 +261,7 @@ long mlock_vma_pages_range(struct vm_are + is_vm_hugetlb_page(vma) || + vma == get_gate_vma(current))) { + +- __mlock_vma_pages_range(vma, start, end, 1); ++ __mlock_vma_pages_range(vma, start, end); + + /* Hide errors from mmap() and other callers */ + return 0; +@@ -310,7 +282,6 @@ no_mlock: + return nr_pages; /* error or pages NOT mlocked */ + } + +- + /* + * munlock_vma_pages_range() - munlock all pages in the vma range.' + * @vma - vma containing range to be munlock()ed. +@@ -330,10 +301,24 @@ no_mlock: + * free them. This will result in freeing mlocked pages. + */ + void munlock_vma_pages_range(struct vm_area_struct *vma, +- unsigned long start, unsigned long end) ++ unsigned long start, unsigned long end) + { ++ unsigned long addr; ++ ++ lru_add_drain(); + vma->vm_flags &= ~VM_LOCKED; +- __mlock_vma_pages_range(vma, start, end, 0); ++ ++ for (addr = start; addr < end; addr += PAGE_SIZE) { ++ struct page *page = follow_page(vma, addr, FOLL_GET); ++ if (page) { ++ lock_page(page); ++ if (page->mapping) ++ munlock_vma_page(page); ++ unlock_page(page); ++ put_page(page); ++ } ++ cond_resched(); ++ } + } + + /* +@@ -400,18 +385,14 @@ success: + * It's okay if try_to_unmap_one unmaps a page just after we + * set VM_LOCKED, __mlock_vma_pages_range will bring it back. + */ +- vma->vm_flags = newflags; + + if (lock) { +- ret = __mlock_vma_pages_range(vma, start, end, 1); +- +- if (ret > 0) { +- mm->locked_vm -= ret; +- ret = 0; +- } else +- ret = __mlock_posix_error_return(ret); /* translate if needed */ ++ vma->vm_flags = newflags; ++ ret = __mlock_vma_pages_range(vma, start, end); ++ if (ret < 0) ++ ret = __mlock_posix_error_return(ret); + } else { +- __mlock_vma_pages_range(vma, start, end, 0); ++ munlock_vma_pages_range(vma, start, end); + } + + out: diff --git a/queue-2.6.31/mmap-avoid-unnecessary-anon_vma-lock-acquisition-in-vma_adjust.patch b/queue-2.6.31/mmap-avoid-unnecessary-anon_vma-lock-acquisition-in-vma_adjust.patch new file mode 100644 index 00000000000..5080cffc3a4 --- /dev/null +++ b/queue-2.6.31/mmap-avoid-unnecessary-anon_vma-lock-acquisition-in-vma_adjust.patch @@ -0,0 +1,89 @@ +From 252c5f94d944487e9f50ece7942b0fbf659c5c31 Mon Sep 17 00:00:00 2001 +From: Lee Schermerhorn +Date: Mon, 21 Sep 2009 17:03:40 -0700 +Subject: mmap: avoid unnecessary anon_vma lock acquisition in vma_adjust() + +From: Lee Schermerhorn + +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 +Signed-off-by: Hugh Dickins +Cc: Nick Piggin +Cc: Eric Whitney +Tested-by: "Zhang, Yanmin" +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/mmap.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -570,9 +570,9 @@ again: remove_next = 1 + (end > next-> + + /* + * When changing only vma->vm_end, we don't really need +- * anon_vma lock: but is that case worth optimizing out? ++ * anon_vma lock. + */ +- if (vma->anon_vma) ++ if (vma->anon_vma && (insert || importer || start != vma->vm_start)) + anon_vma = vma->anon_vma; + if (anon_vma) { + spin_lock(&anon_vma->lock); diff --git a/queue-2.6.31/mptsas-pae-kernel-more-than-4-gb-kernel-panic.patch b/queue-2.6.31/mptsas-pae-kernel-more-than-4-gb-kernel-panic.patch new file mode 100644 index 00000000000..a65c739363b --- /dev/null +++ b/queue-2.6.31/mptsas-pae-kernel-more-than-4-gb-kernel-panic.patch @@ -0,0 +1,57 @@ +From c55b89fba9872ebcd5ac15cdfdad29ffb89329f0 Mon Sep 17 00:00:00 2001 +From: Kashyap, Desai +Date: Wed, 2 Sep 2009 11:44:57 +0530 +Subject: [SCSI] mptsas : PAE Kernel more than 4 GB kernel panic + +From: Kashyap, Desai + +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 +Signed-off-by: James Bottomley +Cc: Jan Beulich +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/message/fusion/mptbase.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/message/fusion/mptbase.c ++++ b/drivers/message/fusion/mptbase.c +@@ -1015,9 +1015,9 @@ mpt_add_sge_64bit(void *pAddr, u32 flags + { + SGESimple64_t *pSge = (SGESimple64_t *) pAddr; + pSge->Address.Low = cpu_to_le32 +- (lower_32_bits((unsigned long)(dma_addr))); ++ (lower_32_bits(dma_addr)); + pSge->Address.High = cpu_to_le32 +- (upper_32_bits((unsigned long)dma_addr)); ++ (upper_32_bits(dma_addr)); + pSge->FlagsLength = cpu_to_le32 + ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); + } +@@ -1038,8 +1038,8 @@ mpt_add_sge_64bit_1078(void *pAddr, u32 + u32 tmp; + + pSge->Address.Low = cpu_to_le32 +- (lower_32_bits((unsigned long)(dma_addr))); +- tmp = (u32)(upper_32_bits((unsigned long)dma_addr)); ++ (lower_32_bits(dma_addr)); ++ tmp = (u32)(upper_32_bits(dma_addr)); + + /* + * 1078 errata workaround for the 36GB limitation +@@ -1101,7 +1101,7 @@ mpt_add_chain_64bit(void *pAddr, u8 next + pChain->NextChainOffset = next; + + pChain->Address.Low = cpu_to_le32(tmp); +- tmp = (u32)(upper_32_bits((unsigned long)dma_addr)); ++ tmp = (u32)(upper_32_bits(dma_addr)); + pChain->Address.High = cpu_to_le32(tmp); + } + diff --git a/queue-2.6.31/nommu-fix-map_private-mmap-of-objects-where-the-data-can-be-mapped-directly.patch b/queue-2.6.31/nommu-fix-map_private-mmap-of-objects-where-the-data-can-be-mapped-directly.patch new file mode 100644 index 00000000000..814dd64ffe7 --- /dev/null +++ b/queue-2.6.31/nommu-fix-map_private-mmap-of-objects-where-the-data-can-be-mapped-directly.patch @@ -0,0 +1,143 @@ +From 645d83c5db970a1c57225e155113b4aa2451e920 Mon Sep 17 00:00:00 2001 +From: David Howells +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 + +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=) at mm/nommu.c:547 +(gdb) bt +#0 0xc005dce8 in add_nommu_region (region=) at mm/nommu.c:547 +#1 0xc005f168 in do_mmap_pgoff (file=0xc31a6620, addr=, 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=) 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=, argv=0xc3ad14cc, envp=0xc3ad1460, regs=0xc33fbce0) at fs/exec.c:1356 +#6 0xc0008cf0 in sys_execve (name=, 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 + Date: Sat Sep 5 11:17:07 2009 -0700 + nommu: fix error handling in do_mmap_pgoff() + +Reported-by: Graff Yang +Signed-off-by: David Howells +Acked-by: Pekka Enberg +Cc: Paul Mundt +Cc: Mel Gorman +Cc: Greg Ungerer +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/nommu.c | 34 ++++++++++++---------------------- + 1 file changed, 12 insertions(+), 22 deletions(-) + +--- a/mm/nommu.c ++++ b/mm/nommu.c +@@ -1056,7 +1056,7 @@ static int do_mmap_shared_file(struct vm + ret = vma->vm_file->f_op->mmap(vma->vm_file, vma); + if (ret == 0) { + vma->vm_region->vm_top = vma->vm_region->vm_end; +- return ret; ++ return 0; + } + if (ret != -ENOSYS) + return ret; +@@ -1073,7 +1073,8 @@ static int do_mmap_shared_file(struct vm + */ + static int do_mmap_private(struct vm_area_struct *vma, + struct vm_region *region, +- unsigned long len) ++ unsigned long len, ++ unsigned long capabilities) + { + struct page *pages; + unsigned long total, point, n, rlen; +@@ -1084,13 +1085,13 @@ static int do_mmap_private(struct vm_are + * shared mappings on devices or memory + * - VM_MAYSHARE will be set if it may attempt to share + */ +- if (vma->vm_file) { ++ if (capabilities & BDI_CAP_MAP_DIRECT) { + ret = vma->vm_file->f_op->mmap(vma->vm_file, vma); + if (ret == 0) { + /* shouldn't return success if we're not sharing */ + BUG_ON(!(vma->vm_flags & VM_MAYSHARE)); + vma->vm_region->vm_top = vma->vm_region->vm_end; +- return ret; ++ return 0; + } + if (ret != -ENOSYS) + return ret; +@@ -1328,7 +1329,7 @@ unsigned long do_mmap_pgoff(struct file + * - this is the hook for quasi-memory character devices to + * tell us the location of a shared mapping + */ +- if (file && file->f_op->get_unmapped_area) { ++ if (capabilities & BDI_CAP_MAP_DIRECT) { + addr = file->f_op->get_unmapped_area(file, addr, len, + pgoff, flags); + if (IS_ERR((void *) addr)) { +@@ -1352,15 +1353,17 @@ unsigned long do_mmap_pgoff(struct file + } + + vma->vm_region = region; +- add_nommu_region(region); + +- /* set up the mapping */ ++ /* set up the mapping ++ * - the region is filled in if BDI_CAP_MAP_DIRECT is still set ++ */ + if (file && vma->vm_flags & VM_SHARED) + ret = do_mmap_shared_file(vma); + else +- ret = do_mmap_private(vma, region, len); ++ ret = do_mmap_private(vma, region, len, capabilities); + if (ret < 0) +- goto error_put_region; ++ goto error_just_free; ++ add_nommu_region(region); + + /* okay... we have a mapping; now we have to register it */ + result = vma->vm_start; +@@ -1378,19 +1381,6 @@ share: + kleave(" = %lx", result); + return result; + +-error_put_region: +- __put_nommu_region(region); +- if (vma) { +- if (vma->vm_file) { +- fput(vma->vm_file); +- if (vma->vm_flags & VM_EXECUTABLE) +- removed_exe_file_vma(vma->vm_mm); +- } +- kmem_cache_free(vm_area_cachep, vma); +- } +- kleave(" = %d [pr]", ret); +- return ret; +- + error_just_free: + up_write(&nommu_region_sem); + error: diff --git a/queue-2.6.31/page-allocator-limit-the-number-of-migrate_reserve-pageblocks-per-zone.patch b/queue-2.6.31/page-allocator-limit-the-number-of-migrate_reserve-pageblocks-per-zone.patch new file mode 100644 index 00000000000..cdce28cead6 --- /dev/null +++ b/queue-2.6.31/page-allocator-limit-the-number-of-migrate_reserve-pageblocks-per-zone.patch @@ -0,0 +1,81 @@ +From 78986a678f6ec3759a01976749f4437d8bf2d6c3 Mon Sep 17 00:00:00 2001 +From: Mel Gorman +Date: Mon, 21 Sep 2009 17:03:02 -0700 +Subject: page-allocator: limit the number of MIGRATE_RESERVE pageblocks per zone + +From: Mel Gorman + +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 +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/page_alloc.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -2783,7 +2783,8 @@ static void setup_zone_migrate_reserve(s + { + unsigned long start_pfn, pfn, end_pfn; + struct page *page; +- unsigned long reserve, block_migratetype; ++ unsigned long block_migratetype; ++ int reserve; + + /* Get the start pfn, end pfn and the number of blocks to reserve */ + start_pfn = zone->zone_start_pfn; +@@ -2791,6 +2792,15 @@ static void setup_zone_migrate_reserve(s + reserve = roundup(min_wmark_pages(zone), pageblock_nr_pages) >> + pageblock_order; + ++ /* ++ * Reserve blocks are generally in place to help high-order atomic ++ * allocations that are short-lived. A min_free_kbytes value that ++ * would result in more than 2 reserve blocks for atomic allocations ++ * is assumed to be in place to help anti-fragmentation for the ++ * future allocation of hugepages at runtime. ++ */ ++ reserve = min(2, reserve); ++ + for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) { + if (!pfn_valid(pfn)) + continue; diff --git a/queue-2.6.31/powerpc-8xx-fix-regression-introduced-by-cache-coherency-rewrite.patch b/queue-2.6.31/powerpc-8xx-fix-regression-introduced-by-cache-coherency-rewrite.patch new file mode 100644 index 00000000000..4873d5a03cb --- /dev/null +++ b/queue-2.6.31/powerpc-8xx-fix-regression-introduced-by-cache-coherency-rewrite.patch @@ -0,0 +1,82 @@ +From benh@kernel.crashing.org Thu Oct 1 15:35:28 2009 +From: Rex Feany +Date: Thu, 24 Sep 2009 17:16:54 +1000 +Subject: powerpc/8xx: Fix regression introduced by cache coherency rewrite +To: stable +Cc: linuxppc-dev list , RFeany@mrv.com +Message-ID: <1253776614.7103.434.camel@pasglop> + +From: Rex Feany + +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 +Signed-off-by: Benjamin Herrenschmidt +Signed-off-by: Greg Kroah-Hartman + +--- + 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 + #include + ++#include "mmu_decl.h" ++ + static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur); + static unsigned long pte_freelist_forced_free; + +@@ -119,7 +121,7 @@ void pte_free_finish(void) + /* + * Handle i/d cache flushing, called from set_pte_at() or ptep_set_access_flags() + */ +-static pte_t do_dcache_icache_coherency(pte_t pte) ++static pte_t do_dcache_icache_coherency(pte_t pte, unsigned long addr) + { + unsigned long pfn = pte_pfn(pte); + struct page *page; +@@ -128,6 +130,17 @@ static pte_t do_dcache_icache_coherency( + return pte; + page = pfn_to_page(pfn); + ++#ifdef CONFIG_8xx ++ /* On 8xx, cache control instructions (particularly ++ * "dcbst" from flush_dcache_icache) fault as write ++ * operation if there is an unpopulated TLB entry ++ * for the address in question. To workaround that, ++ * we invalidate the TLB here, thus avoiding dcbst ++ * misbehaviour. ++ */ ++ _tlbil_va(addr, 0 /* 8xx doesn't care about PID */); ++#endif ++ + if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)) { + pr_devel("do_dcache_icache_coherency... flushing\n"); + flush_dcache_icache_page(page); +@@ -198,7 +211,7 @@ void set_pte_at(struct mm_struct *mm, un + */ + pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS); + if (pte_need_exec_flush(pte, 1)) +- pte = do_dcache_icache_coherency(pte); ++ pte = do_dcache_icache_coherency(pte, addr); + + /* Perform the setting of the PTE */ + __set_pte_at(mm, addr, ptep, pte, 0); +@@ -216,7 +229,7 @@ int ptep_set_access_flags(struct vm_area + { + int changed; + if (!dirty && pte_need_exec_flush(entry, 0)) +- entry = do_dcache_icache_coherency(entry); ++ entry = do_dcache_icache_coherency(entry, address); + changed = !pte_same(*(ptep), entry); + if (changed) { + if (!(vma->vm_flags & VM_HUGETLB)) diff --git a/queue-2.6.31/powerpc-fix-incorrect-setting-of-__have_arch_pte_special.patch b/queue-2.6.31/powerpc-fix-incorrect-setting-of-__have_arch_pte_special.patch new file mode 100644 index 00000000000..9cde173e755 --- /dev/null +++ b/queue-2.6.31/powerpc-fix-incorrect-setting-of-__have_arch_pte_special.patch @@ -0,0 +1,40 @@ +From benh@kernel.crashing.org Thu Oct 1 15:36:15 2009 +From: Weirich, Bernhard +Date: Thu, 24 Sep 2009 17:16:53 +1000 +Subject: powerpc: Fix incorrect setting of __HAVE_ARCH_PTE_SPECIAL +To: stable +Cc: linuxppc-dev list , bernhard.weirich@riedel.net, RFeany@mrv.com +Message-ID: <1253776613.7103.433.camel@pasglop> + + +From: Weirich, Bernhard + +[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 +Signed-off-by: Benjamin Herrenschmidt +Signed-off-by: Greg Kroah-Hartman + + +--- + arch/powerpc/include/asm/pte-common.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/powerpc/include/asm/pte-common.h ++++ b/arch/powerpc/include/asm/pte-common.h +@@ -176,7 +176,7 @@ extern unsigned long bad_call_to_PMD_PAG + #define HAVE_PAGE_AGP + + /* Advertise support for _PAGE_SPECIAL */ +-#ifdef _PAGE_SPECIAL ++#if _PAGE_SPECIAL != 0 + #define __HAVE_ARCH_PTE_SPECIAL + #endif + diff --git a/queue-2.6.31/proc-kcore-work-around-a-bug.patch b/queue-2.6.31/proc-kcore-work-around-a-bug.patch new file mode 100644 index 00000000000..b76d1130f82 --- /dev/null +++ b/queue-2.6.31/proc-kcore-work-around-a-bug.patch @@ -0,0 +1,85 @@ +From akpm@linux-foundation.org Thu Oct 1 15:23:18 2009 +From: KAMEZAWA Hiroyuki +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 + +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: [] 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:[] 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: +[] ? proc_reg_read+0x5f/0x73 +[] ? read_kcore+0x0/0x31a +[] ? proc_reg_read+0x0/0x73 +[] ? vfs_read+0x82/0xe1 +[] ? path_put+0x1a/0x1d +[] ? sys_read+0x40/0x62 +[] ? 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 a5 89 d1 83 e1 03 74 02 f3 a4 8b 00 83 7d dc 00 74 04 85 c0 +EIP: [] 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 +Tested-by: Nick Craig-Wood +Cc: Pekka Enberg +Reported-by: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman + +--- + fs/proc/kcore.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/fs/proc/kcore.c ++++ b/fs/proc/kcore.c +@@ -361,7 +361,13 @@ read_kcore(struct file *file, char __use + /* don't dump ioremap'd stuff! (TA) */ + if (m->flags & VM_IOREMAP) + continue; +- memcpy(elf_buf + (vmstart - start), ++ /* ++ * we may access memory holes, then use ++ * ex_table. checking return value just for ++ * avoid warnings. ++ */ ++ vmsize = __copy_from_user_inatomic( ++ elf_buf + (vmstart - start), + (char *)vmstart, vmsize); + } + read_unlock(&vmlist_lock); diff --git a/queue-2.6.31/saa7134-ir-kbd-i2c-init-data-needs-a-persistent-object.patch b/queue-2.6.31/saa7134-ir-kbd-i2c-init-data-needs-a-persistent-object.patch new file mode 100644 index 00000000000..59dcd47f014 --- /dev/null +++ b/queue-2.6.31/saa7134-ir-kbd-i2c-init-data-needs-a-persistent-object.patch @@ -0,0 +1,163 @@ +From brian@xyzw.org Thu Oct 1 15:34:42 2009 +From: Brian Rogers +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 , linux-kernel@vger.kernel.org, Brian Rogers , linux-media@vger.kernel.org +Message-ID: <1253700303-15172-2-git-send-email-brian@xyzw.org> + +From: Brian Rogers + +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 +Signed-off-by: Mauro Carvalho Chehab +[brian@xyzw.org: backported for 2.6.31] +Signed-off-by: Brian Rogers +Signed-off-by: Greg Kroah-Hartman + +--- + 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) diff --git a/queue-2.6.31/series b/queue-2.6.31/series index 8bb6ee149c5..ec79e00725b 100644 --- a/queue-2.6.31/series +++ b/queue-2.6.31/series @@ -114,3 +114,23 @@ usb-xhci-check-urb_short_not_ok-before-setting-short-packet-status.patch usb-xhci-set-eremoteio-when-xhc-gives-bad-transfer-length.patch usb-xhci-support-interrupt-transfers.patch usb-fix-ss-endpoint-companion-descriptor-parsing.patch +proc-kcore-work-around-a-bug.patch +hugetlb-restore-interleaving-of-bootmem-huge-pages.patch +page-allocator-limit-the-number-of-migrate_reserve-pageblocks-per-zone.patch +mm-munlock-use-follow_page.patch +mm-fix-anonymous-dirtying.patch +mmap-avoid-unnecessary-anon_vma-lock-acquisition-in-vma_adjust.patch +fix-idle-time-field-in-proc-uptime.patch +drm-i915-handle-erestartsys-during-page-fault.patch +em28xx-ir-kbd-i2c-init-data-needs-a-persistent-object.patch +saa7134-ir-kbd-i2c-init-data-needs-a-persistent-object.patch +powerpc-8xx-fix-regression-introduced-by-cache-coherency-rewrite.patch +powerpc-fix-incorrect-setting-of-__have_arch_pte_special.patch +hid-completely-remove-apple-mightymouse-from-blacklist.patch +mptsas-pae-kernel-more-than-4-gb-kernel-panic.patch +nommu-fix-map_private-mmap-of-objects-where-the-data-can-be-mapped-directly.patch +iwlwifi-handle-new-firmware-file-with-ucode-build-number-in-header.patch +iwlwifi-update-1000-series-api-version-to-match-firmware.patch +iwlagn-modify-digital-svr-for-1000.patch +iwlwifi-traverse-linklist-to-find-the-valid-otp-block.patch +iwlwifi-fix-unloading-driver-while-scanning.patch