From 56b6d36de2fec9590a1ad597167319234ce79c38 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 15 Jan 2013 04:39:41 -0800 Subject: [PATCH] 3.7-stable patches added patches: b43-fix-firmware-loading-when-driver-is-built-into-the-kernel.patch iwlwifi-fix-pcie-interrupt-handle-return-value.patch iwlwifi-fix-the-reclaimed-packet-tracking-upon-flush-queue.patch mac80211-fix-ibss-scanning.patch mac80211-fix-station-destruction-in-ap-mesh-modes.patch mac80211-use-del_timer_sync-for-final-sta-cleanup-timer-deletion.patch mwifiex-check-wait_event_interruptible-return-value.patch radeon-kms-force-rn50-chip-to-always-report-connected-on-analog-output.patch staging-comedi-comedi_test-fix-race-when-cancelling-command.patch staging-comedi-fix-minimum-ao-period-for-ni-625x-and-ni-628x.patch staging-comedi-kconfig-comedi_ni_at_a2150-should-select-comedi_fc.patch staging-comedi-prevent-auto-unconfig-of-manually-configured-devices.patch staging-r8712u-add-new-device-id.patch staging-speakup-avoid-out-of-range-access-in-synth_add.patch staging-speakup-avoid-out-of-range-access-in-synth_init.patch staging-zram-factor-out-zram_decompress_page-function.patch staging-zram-fix-invalid-memory-references-during-disk-write.patch --- ...when-driver-is-built-into-the-kernel.patch | 199 +++++++++++++++++ ...x-pcie-interrupt-handle-return-value.patch | 34 +++ ...med-packet-tracking-upon-flush-queue.patch | 66 ++++++ queue-3.7/mac80211-fix-ibss-scanning.patch | 130 +++++++++++ ...station-destruction-in-ap-mesh-modes.patch | 202 ++++++++++++++++++ ...for-final-sta-cleanup-timer-deletion.patch | 35 +++ ...ait_event_interruptible-return-value.patch | 73 +++++++ ...ys-report-connected-on-analog-output.patch | 38 ++++ queue-3.7/series | 17 ++ ...est-fix-race-when-cancelling-command.patch | 45 ++++ ...um-ao-period-for-ni-625x-and-ni-628x.patch | 103 +++++++++ ..._ni_at_a2150-should-select-comedi_fc.patch | 30 +++ ...onfig-of-manually-configured-devices.patch | 48 +++++ .../staging-r8712u-add-new-device-id.patch | 32 +++ ...oid-out-of-range-access-in-synth_add.patch | 30 +++ ...id-out-of-range-access-in-synth_init.patch | 30 +++ ...or-out-zram_decompress_page-function.patch | 179 ++++++++++++++++ ...-memory-references-during-disk-write.patch | 129 +++++++++++ 18 files changed, 1420 insertions(+) create mode 100644 queue-3.7/b43-fix-firmware-loading-when-driver-is-built-into-the-kernel.patch create mode 100644 queue-3.7/iwlwifi-fix-pcie-interrupt-handle-return-value.patch create mode 100644 queue-3.7/iwlwifi-fix-the-reclaimed-packet-tracking-upon-flush-queue.patch create mode 100644 queue-3.7/mac80211-fix-ibss-scanning.patch create mode 100644 queue-3.7/mac80211-fix-station-destruction-in-ap-mesh-modes.patch create mode 100644 queue-3.7/mac80211-use-del_timer_sync-for-final-sta-cleanup-timer-deletion.patch create mode 100644 queue-3.7/mwifiex-check-wait_event_interruptible-return-value.patch create mode 100644 queue-3.7/radeon-kms-force-rn50-chip-to-always-report-connected-on-analog-output.patch create mode 100644 queue-3.7/staging-comedi-comedi_test-fix-race-when-cancelling-command.patch create mode 100644 queue-3.7/staging-comedi-fix-minimum-ao-period-for-ni-625x-and-ni-628x.patch create mode 100644 queue-3.7/staging-comedi-kconfig-comedi_ni_at_a2150-should-select-comedi_fc.patch create mode 100644 queue-3.7/staging-comedi-prevent-auto-unconfig-of-manually-configured-devices.patch create mode 100644 queue-3.7/staging-r8712u-add-new-device-id.patch create mode 100644 queue-3.7/staging-speakup-avoid-out-of-range-access-in-synth_add.patch create mode 100644 queue-3.7/staging-speakup-avoid-out-of-range-access-in-synth_init.patch create mode 100644 queue-3.7/staging-zram-factor-out-zram_decompress_page-function.patch create mode 100644 queue-3.7/staging-zram-fix-invalid-memory-references-during-disk-write.patch diff --git a/queue-3.7/b43-fix-firmware-loading-when-driver-is-built-into-the-kernel.patch b/queue-3.7/b43-fix-firmware-loading-when-driver-is-built-into-the-kernel.patch new file mode 100644 index 00000000000..46339200e35 --- /dev/null +++ b/queue-3.7/b43-fix-firmware-loading-when-driver-is-built-into-the-kernel.patch @@ -0,0 +1,199 @@ +From 5e20a4b53094651d80f856ff55a916b999dbb57a Mon Sep 17 00:00:00 2001 +From: Larry Finger +Date: Thu, 20 Dec 2012 15:55:01 -0600 +Subject: b43: Fix firmware loading when driver is built into the kernel + +From: Larry Finger + +commit 5e20a4b53094651d80f856ff55a916b999dbb57a upstream. + +Recent versions of udev cause synchronous firmware loading from the +probe routine to fail because the request to user space would time +out. The original fix for b43 (commit 6b6fa58) moved the firmware +load from the probe routine to a work queue, but it still used synchronous +firmware loading. This method is OK when b43 is built as a module; +however, it fails when the driver is compiled into the kernel. + +This version changes the code to load the initial firmware file +using request_firmware_nowait(). A completion event is used to +hold the work queue until that file is available. This driver +reads several firmware files - the remainder can be read synchronously. +On some test systems, the async read fails; however, a following synch +read works, thus the async failure falls through to the sync try. + +Reported-and-Tested by: Felix Janda +Signed-off-by: Larry Finger +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/b43/b43.h | 5 +++ + drivers/net/wireless/b43/main.c | 54 ++++++++++++++++++++++++++++++---------- + drivers/net/wireless/b43/main.h | 5 +-- + 3 files changed, 48 insertions(+), 16 deletions(-) + +--- a/drivers/net/wireless/b43/b43.h ++++ b/drivers/net/wireless/b43/b43.h +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + #include "debugfs.h" +@@ -722,6 +723,10 @@ enum b43_firmware_file_type { + struct b43_request_fw_context { + /* The device we are requesting the fw for. */ + struct b43_wldev *dev; ++ /* a completion event structure needed if this call is asynchronous */ ++ struct completion fw_load_complete; ++ /* a pointer to the firmware object */ ++ const struct firmware *blob; + /* The type of firmware to request. */ + enum b43_firmware_file_type req_type; + /* Error messages for each firmware type. */ +--- a/drivers/net/wireless/b43/main.c ++++ b/drivers/net/wireless/b43/main.c +@@ -2088,11 +2088,18 @@ static void b43_print_fw_helptext(struct + b43warn(wl, text); + } + ++static void b43_fw_cb(const struct firmware *firmware, void *context) ++{ ++ struct b43_request_fw_context *ctx = context; ++ ++ ctx->blob = firmware; ++ complete(&ctx->fw_load_complete); ++} ++ + int b43_do_request_fw(struct b43_request_fw_context *ctx, + const char *name, +- struct b43_firmware_file *fw) ++ struct b43_firmware_file *fw, bool async) + { +- const struct firmware *blob; + struct b43_fw_header *hdr; + u32 size; + int err; +@@ -2131,11 +2138,31 @@ int b43_do_request_fw(struct b43_request + B43_WARN_ON(1); + return -ENOSYS; + } +- err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev); ++ if (async) { ++ /* do this part asynchronously */ ++ init_completion(&ctx->fw_load_complete); ++ err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname, ++ ctx->dev->dev->dev, GFP_KERNEL, ++ ctx, b43_fw_cb); ++ if (err < 0) { ++ pr_err("Unable to load firmware\n"); ++ return err; ++ } ++ /* stall here until fw ready */ ++ wait_for_completion(&ctx->fw_load_complete); ++ if (ctx->blob) ++ goto fw_ready; ++ /* On some ARM systems, the async request will fail, but the next sync ++ * request works. For this reason, we dall through here ++ */ ++ } ++ err = request_firmware(&ctx->blob, ctx->fwname, ++ ctx->dev->dev->dev); + if (err == -ENOENT) { + snprintf(ctx->errors[ctx->req_type], + sizeof(ctx->errors[ctx->req_type]), +- "Firmware file \"%s\" not found\n", ctx->fwname); ++ "Firmware file \"%s\" not found\n", ++ ctx->fwname); + return err; + } else if (err) { + snprintf(ctx->errors[ctx->req_type], +@@ -2144,14 +2171,15 @@ int b43_do_request_fw(struct b43_request + ctx->fwname, err); + return err; + } +- if (blob->size < sizeof(struct b43_fw_header)) ++fw_ready: ++ if (ctx->blob->size < sizeof(struct b43_fw_header)) + goto err_format; +- hdr = (struct b43_fw_header *)(blob->data); ++ hdr = (struct b43_fw_header *)(ctx->blob->data); + switch (hdr->type) { + case B43_FW_TYPE_UCODE: + case B43_FW_TYPE_PCM: + size = be32_to_cpu(hdr->size); +- if (size != blob->size - sizeof(struct b43_fw_header)) ++ if (size != ctx->blob->size - sizeof(struct b43_fw_header)) + goto err_format; + /* fallthrough */ + case B43_FW_TYPE_IV: +@@ -2162,7 +2190,7 @@ int b43_do_request_fw(struct b43_request + goto err_format; + } + +- fw->data = blob; ++ fw->data = ctx->blob; + fw->filename = name; + fw->type = ctx->req_type; + +@@ -2172,7 +2200,7 @@ err_format: + snprintf(ctx->errors[ctx->req_type], + sizeof(ctx->errors[ctx->req_type]), + "Firmware file \"%s\" format error.\n", ctx->fwname); +- release_firmware(blob); ++ release_firmware(ctx->blob); + + return -EPROTO; + } +@@ -2223,7 +2251,7 @@ static int b43_try_request_fw(struct b43 + goto err_no_ucode; + } + } +- err = b43_do_request_fw(ctx, filename, &fw->ucode); ++ err = b43_do_request_fw(ctx, filename, &fw->ucode, true); + if (err) + goto err_load; + +@@ -2235,7 +2263,7 @@ static int b43_try_request_fw(struct b43 + else + goto err_no_pcm; + fw->pcm_request_failed = false; +- err = b43_do_request_fw(ctx, filename, &fw->pcm); ++ err = b43_do_request_fw(ctx, filename, &fw->pcm, false); + if (err == -ENOENT) { + /* We did not find a PCM file? Not fatal, but + * core rev <= 10 must do without hwcrypto then. */ +@@ -2296,7 +2324,7 @@ static int b43_try_request_fw(struct b43 + default: + goto err_no_initvals; + } +- err = b43_do_request_fw(ctx, filename, &fw->initvals); ++ err = b43_do_request_fw(ctx, filename, &fw->initvals, false); + if (err) + goto err_load; + +@@ -2355,7 +2383,7 @@ static int b43_try_request_fw(struct b43 + default: + goto err_no_initvals; + } +- err = b43_do_request_fw(ctx, filename, &fw->initvals_band); ++ err = b43_do_request_fw(ctx, filename, &fw->initvals_band, false); + if (err) + goto err_load; + +--- a/drivers/net/wireless/b43/main.h ++++ b/drivers/net/wireless/b43/main.h +@@ -137,9 +137,8 @@ void b43_mac_phy_clock_set(struct b43_wl + + + struct b43_request_fw_context; +-int b43_do_request_fw(struct b43_request_fw_context *ctx, +- const char *name, +- struct b43_firmware_file *fw); ++int b43_do_request_fw(struct b43_request_fw_context *ctx, const char *name, ++ struct b43_firmware_file *fw, bool async); + void b43_do_release_fw(struct b43_firmware_file *fw); + + #endif /* B43_MAIN_H_ */ diff --git a/queue-3.7/iwlwifi-fix-pcie-interrupt-handle-return-value.patch b/queue-3.7/iwlwifi-fix-pcie-interrupt-handle-return-value.patch new file mode 100644 index 00000000000..8fbffc6dff8 --- /dev/null +++ b/queue-3.7/iwlwifi-fix-pcie-interrupt-handle-return-value.patch @@ -0,0 +1,34 @@ +From 392d4cad7907f6cb4ffc85e135a01abfddc89027 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Thu, 27 Dec 2012 21:37:04 +0100 +Subject: iwlwifi: fix PCIe interrupt handle return value + +From: Johannes Berg + +commit 392d4cad7907f6cb4ffc85e135a01abfddc89027 upstream. + +By accident, commit eb6476441bc2fecf6232a87d0313a85f8e3da7f4 +("iwlwifi: protect use_ict with irq_lock") changed the return +value of the iwl_pcie_isr() function in case it handles an +interrupt -- it now returns IRQ_NONE instead of IRQ_HANDLED. + +Put back the correct return value. + +Reviewed-by: Emmanuel Grumbach +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/iwlwifi/pcie/rx.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireless/iwlwifi/pcie/rx.c ++++ b/drivers/net/wireless/iwlwifi/pcie/rx.c +@@ -971,6 +971,7 @@ static irqreturn_t iwl_isr(int irq, void + else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && + !trans_pcie->inta) + iwl_enable_interrupts(trans); ++ return IRQ_HANDLED; + + none: + /* re-enable interrupts here since we don't have anything to service. */ diff --git a/queue-3.7/iwlwifi-fix-the-reclaimed-packet-tracking-upon-flush-queue.patch b/queue-3.7/iwlwifi-fix-the-reclaimed-packet-tracking-upon-flush-queue.patch new file mode 100644 index 00000000000..093a6b4f7e7 --- /dev/null +++ b/queue-3.7/iwlwifi-fix-the-reclaimed-packet-tracking-upon-flush-queue.patch @@ -0,0 +1,66 @@ +From f590dcec944552f9a4a61155810f3abd17d6465d Mon Sep 17 00:00:00 2001 +From: Emmanuel Grumbach +Date: Mon, 31 Dec 2012 09:26:10 +0200 +Subject: iwlwifi: fix the reclaimed packet tracking upon flush queue + +From: Emmanuel Grumbach + +commit f590dcec944552f9a4a61155810f3abd17d6465d upstream. + +There's a bug in the currently released firmware version, +the sequence control in the Tx response isn't updated in +all cases. Take it from the packet as a workaround. + +Signed-off-by: Emmanuel Grumbach +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/iwlwifi/dvm/tx.c | 24 +++++++++++++++++------- + 1 file changed, 17 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/iwlwifi/dvm/tx.c ++++ b/drivers/net/wireless/iwlwifi/dvm/tx.c +@@ -1154,13 +1154,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv * + next_reclaimed = ssn; + } + +- if (tid != IWL_TID_NON_QOS) { +- priv->tid_data[sta_id][tid].next_reclaimed = +- next_reclaimed; +- IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", +- next_reclaimed); +- } +- + iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs); + + iwlagn_check_ratid_empty(priv, sta_id, tid); +@@ -1211,11 +1204,28 @@ int iwlagn_rx_reply_tx(struct iwl_priv * + if (!is_agg) + iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); + ++ /* ++ * W/A for FW bug - the seq_ctl isn't updated when the ++ * queues are flushed. Fetch it from the packet itself ++ */ ++ if (!is_agg && status == TX_STATUS_FAIL_FIFO_FLUSHED) { ++ next_reclaimed = le16_to_cpu(hdr->seq_ctrl); ++ next_reclaimed = ++ SEQ_TO_SN(next_reclaimed + 0x10); ++ } ++ + is_offchannel_skb = + (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN); + freed++; + } + ++ if (tid != IWL_TID_NON_QOS) { ++ priv->tid_data[sta_id][tid].next_reclaimed = ++ next_reclaimed; ++ IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", ++ next_reclaimed); ++ } ++ + WARN_ON(!is_agg && freed != 1); + + /* diff --git a/queue-3.7/mac80211-fix-ibss-scanning.patch b/queue-3.7/mac80211-fix-ibss-scanning.patch new file mode 100644 index 00000000000..10023cda3aa --- /dev/null +++ b/queue-3.7/mac80211-fix-ibss-scanning.patch @@ -0,0 +1,130 @@ +From 34bcf71502413f8903ade93746f2d0f04b937a78 Mon Sep 17 00:00:00 2001 +From: Stanislaw Gruszka +Date: Tue, 11 Dec 2012 10:48:23 +0100 +Subject: mac80211: fix ibss scanning + +From: Stanislaw Gruszka + +commit 34bcf71502413f8903ade93746f2d0f04b937a78 upstream. + +Do not scan on no-IBSS and disabled channels in IBSS mode. Doing this +can trigger Microcode errors on iwlwifi and iwlegacy drivers. + +Also rename ieee80211_request_internal_scan() function since it is only +used in IBSS mode and simplify calling it from ieee80211_sta_find_ibss(). + +This patch should address: +https://bugzilla.redhat.com/show_bug.cgi?id=883414 +https://bugzilla.kernel.org/show_bug.cgi?id=49411 + +Reported-by: Jesse Kahtava +Reported-by: Mikko Rapeli +Signed-off-by: Stanislaw Gruszka +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman + +--- + net/mac80211/ibss.c | 9 ++++----- + net/mac80211/ieee80211_i.h | 6 +++--- + net/mac80211/scan.c | 34 ++++++++++++++++++++++++---------- + 3 files changed, 31 insertions(+), 18 deletions(-) + +--- a/net/mac80211/ibss.c ++++ b/net/mac80211/ibss.c +@@ -678,8 +678,8 @@ static void ieee80211_sta_merge_ibss(str + sdata_info(sdata, + "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n"); + +- ieee80211_request_internal_scan(sdata, +- ifibss->ssid, ifibss->ssid_len, NULL); ++ ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len, ++ NULL); + } + + static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) +@@ -777,9 +777,8 @@ static void ieee80211_sta_find_ibss(stru + IEEE80211_SCAN_INTERVAL)) { + sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); + +- ieee80211_request_internal_scan(sdata, +- ifibss->ssid, ifibss->ssid_len, +- ifibss->fixed_channel ? ifibss->channel : NULL); ++ ieee80211_request_ibss_scan(sdata, ifibss->ssid, ++ ifibss->ssid_len, chan); + } else { + int interval = IEEE80211_SCAN_INTERVAL; + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1247,9 +1247,9 @@ void ieee80211_mesh_rx_queued_mgmt(struc + + /* scan/BSS handling */ + void ieee80211_scan_work(struct work_struct *work); +-int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, +- const u8 *ssid, u8 ssid_len, +- struct ieee80211_channel *chan); ++int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, ++ const u8 *ssid, u8 ssid_len, ++ struct ieee80211_channel *chan); + int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, + struct cfg80211_scan_request *req); + void ieee80211_scan_cancel(struct ieee80211_local *local); +--- a/net/mac80211/scan.c ++++ b/net/mac80211/scan.c +@@ -819,9 +819,9 @@ int ieee80211_request_scan(struct ieee80 + return res; + } + +-int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, +- const u8 *ssid, u8 ssid_len, +- struct ieee80211_channel *chan) ++int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, ++ const u8 *ssid, u8 ssid_len, ++ struct ieee80211_channel *chan) + { + struct ieee80211_local *local = sdata->local; + int ret = -EBUSY; +@@ -835,22 +835,36 @@ int ieee80211_request_internal_scan(stru + + /* fill internal scan request */ + if (!chan) { +- int i, nchan = 0; ++ int i, max_n; ++ int n_ch = 0; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!local->hw.wiphy->bands[band]) + continue; +- for (i = 0; +- i < local->hw.wiphy->bands[band]->n_channels; +- i++) { +- local->int_scan_req->channels[nchan] = ++ ++ max_n = local->hw.wiphy->bands[band]->n_channels; ++ for (i = 0; i < max_n; i++) { ++ struct ieee80211_channel *tmp_ch = + &local->hw.wiphy->bands[band]->channels[i]; +- nchan++; ++ ++ if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_DISABLED)) ++ continue; ++ ++ local->int_scan_req->channels[n_ch] = tmp_ch; ++ n_ch++; + } + } + +- local->int_scan_req->n_channels = nchan; ++ if (WARN_ON_ONCE(n_ch == 0)) ++ goto unlock; ++ ++ local->int_scan_req->n_channels = n_ch; + } else { ++ if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_DISABLED))) ++ goto unlock; ++ + local->int_scan_req->channels[0] = chan; + local->int_scan_req->n_channels = 1; + } diff --git a/queue-3.7/mac80211-fix-station-destruction-in-ap-mesh-modes.patch b/queue-3.7/mac80211-fix-station-destruction-in-ap-mesh-modes.patch new file mode 100644 index 00000000000..2a092567c4c --- /dev/null +++ b/queue-3.7/mac80211-fix-station-destruction-in-ap-mesh-modes.patch @@ -0,0 +1,202 @@ +From 97f97b1f5fe0878b35c8e314f98591771696321b Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Thu, 13 Dec 2012 22:54:58 +0100 +Subject: mac80211: fix station destruction in AP/mesh modes + +From: Johannes Berg + +commit 97f97b1f5fe0878b35c8e314f98591771696321b upstream. + +Unfortunately, commit b22cfcfcae5b, intended to speed up roaming +by avoiding the synchronize_rcu() broke AP/mesh modes as it moved +some code into that work item that will still call into the driver +at a time where it's no longer expected to handle this: after the +AP or mesh has been stopped. + +To fix this problem remove the per-station work struct, maintain a +station cleanup list instead and flush this list when stations are +flushed. To keep this patch smaller for stable, do this when the +stations are flushed (sta_info_flush()). This unfortunately brings +back the original roaming delay; I'll fix that again in a separate +patch. + +Also, Ben reported that the original commit could sometimes (with +many interfaces) cause long delays when an interface is set down, +due to blocking on flush_workqueue(). Since we now maintain the +cleanup list, this particular change of the original patch can be +reverted. + +Reported-by: Ben Greear +Tested-by: Ben Greear +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman + +--- + net/mac80211/ieee80211_i.h | 4 ++++ + net/mac80211/iface.c | 28 ++++++++++++++++------------ + net/mac80211/sta_info.c | 44 ++++++++++++++++++++++++++++++++++++++++---- + net/mac80211/sta_info.h | 3 ++- + 4 files changed, 62 insertions(+), 17 deletions(-) + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -730,6 +730,10 @@ struct ieee80211_sub_if_data { + u32 mntr_flags; + } u; + ++ spinlock_t cleanup_stations_lock; ++ struct list_head cleanup_stations; ++ struct work_struct cleanup_stations_wk; ++ + #ifdef CONFIG_MAC80211_DEBUGFS + struct { + struct dentry *dir; +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -793,20 +793,11 @@ static void ieee80211_do_stop(struct iee + flush_work(&sdata->work); + /* + * When we get here, the interface is marked down. +- * Call rcu_barrier() to wait both for the RX path ++ * Call synchronize_rcu() to wait for the RX path + * should it be using the interface and enqueuing +- * frames at this very time on another CPU, and +- * for the sta free call_rcu callbacks. ++ * frames at this very time on another CPU. + */ +- rcu_barrier(); +- +- /* +- * free_sta_rcu() enqueues a work for the actual +- * sta cleanup, so we need to flush it while +- * sdata is still valid. +- */ +- flush_workqueue(local->workqueue); +- ++ synchronize_rcu(); + skb_queue_purge(&sdata->skb_queue); + + /* +@@ -1432,6 +1423,15 @@ static void ieee80211_assign_perm_addr(s + mutex_unlock(&local->iflist_mtx); + } + ++static void ieee80211_cleanup_sdata_stas_wk(struct work_struct *wk) ++{ ++ struct ieee80211_sub_if_data *sdata; ++ ++ sdata = container_of(wk, struct ieee80211_sub_if_data, cleanup_stations_wk); ++ ++ ieee80211_cleanup_sdata_stas(sdata); ++} ++ + int ieee80211_if_add(struct ieee80211_local *local, const char *name, + struct wireless_dev **new_wdev, enum nl80211_iftype type, + struct vif_params *params) +@@ -1507,6 +1507,10 @@ int ieee80211_if_add(struct ieee80211_lo + + INIT_LIST_HEAD(&sdata->key_list); + ++ spin_lock_init(&sdata->cleanup_stations_lock); ++ INIT_LIST_HEAD(&sdata->cleanup_stations); ++ INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); ++ + for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + struct ieee80211_supported_band *sband; + sband = local->hw.wiphy->bands[i]; +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -91,9 +91,8 @@ static int sta_info_hash_del(struct ieee + return -ENOENT; + } + +-static void free_sta_work(struct work_struct *wk) ++static void cleanup_single_sta(struct sta_info *sta) + { +- struct sta_info *sta = container_of(wk, struct sta_info, free_sta_wk); + int ac, i; + struct tid_ampdu_tx *tid_tx; + struct ieee80211_sub_if_data *sdata = sta->sdata; +@@ -148,11 +147,35 @@ static void free_sta_work(struct work_st + sta_info_free(local, sta); + } + ++void ieee80211_cleanup_sdata_stas(struct ieee80211_sub_if_data *sdata) ++{ ++ struct sta_info *sta; ++ ++ spin_lock_bh(&sdata->cleanup_stations_lock); ++ while (!list_empty(&sdata->cleanup_stations)) { ++ sta = list_first_entry(&sdata->cleanup_stations, ++ struct sta_info, list); ++ list_del(&sta->list); ++ spin_unlock_bh(&sdata->cleanup_stations_lock); ++ ++ cleanup_single_sta(sta); ++ ++ spin_lock_bh(&sdata->cleanup_stations_lock); ++ } ++ ++ spin_unlock_bh(&sdata->cleanup_stations_lock); ++} ++ + static void free_sta_rcu(struct rcu_head *h) + { + struct sta_info *sta = container_of(h, struct sta_info, rcu_head); ++ struct ieee80211_sub_if_data *sdata = sta->sdata; + +- ieee80211_queue_work(&sta->local->hw, &sta->free_sta_wk); ++ spin_lock(&sdata->cleanup_stations_lock); ++ list_add_tail(&sta->list, &sdata->cleanup_stations); ++ spin_unlock(&sdata->cleanup_stations_lock); ++ ++ ieee80211_queue_work(&sdata->local->hw, &sdata->cleanup_stations_wk); + } + + /* protected by RCU */ +@@ -305,7 +328,6 @@ struct sta_info *sta_info_alloc(struct i + + spin_lock_init(&sta->lock); + INIT_WORK(&sta->drv_unblock_wk, sta_unblock); +- INIT_WORK(&sta->free_sta_wk, free_sta_work); + INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); + mutex_init(&sta->ampdu_mlme.mtx); + +@@ -877,6 +899,20 @@ int sta_info_flush(struct ieee80211_loca + } + mutex_unlock(&local->sta_mtx); + ++ rcu_barrier(); ++ ++ if (sdata) { ++ ieee80211_cleanup_sdata_stas(sdata); ++ cancel_work_sync(&sdata->cleanup_stations_wk); ++ } else { ++ mutex_lock(&local->iflist_mtx); ++ list_for_each_entry(sdata, &local->interfaces, list) { ++ ieee80211_cleanup_sdata_stas(sdata); ++ cancel_work_sync(&sdata->cleanup_stations_wk); ++ } ++ mutex_unlock(&local->iflist_mtx); ++ } ++ + return ret; + } + +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -298,7 +298,6 @@ struct sta_info { + spinlock_t lock; + + struct work_struct drv_unblock_wk; +- struct work_struct free_sta_wk; + + u16 listen_interval; + +@@ -558,4 +557,6 @@ void ieee80211_sta_ps_deliver_wakeup(str + void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); + void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); + ++void ieee80211_cleanup_sdata_stas(struct ieee80211_sub_if_data *sdata); ++ + #endif /* STA_INFO_H */ diff --git a/queue-3.7/mac80211-use-del_timer_sync-for-final-sta-cleanup-timer-deletion.patch b/queue-3.7/mac80211-use-del_timer_sync-for-final-sta-cleanup-timer-deletion.patch new file mode 100644 index 00000000000..c429b069770 --- /dev/null +++ b/queue-3.7/mac80211-use-del_timer_sync-for-final-sta-cleanup-timer-deletion.patch @@ -0,0 +1,35 @@ +From a56f992cdabc63f56b4b142885deebebf936ff76 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Thu, 13 Dec 2012 23:08:52 +0100 +Subject: mac80211: use del_timer_sync for final sta cleanup timer deletion + +From: Johannes Berg + +commit a56f992cdabc63f56b4b142885deebebf936ff76 upstream. + +This is a very old bug, but there's nothing that prevents the +timer from running while the module is being removed when we +only do del_timer() instead of del_timer_sync(). + +The timer should normally not be running at this point, but +it's not clearly impossible (or we could just remove this.) + +Tested-by: Ben Greear +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman + +--- + net/mac80211/sta_info.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -870,7 +870,7 @@ void sta_info_init(struct ieee80211_loca + + void sta_info_stop(struct ieee80211_local *local) + { +- del_timer(&local->sta_cleanup); ++ del_timer_sync(&local->sta_cleanup); + sta_info_flush(local, NULL); + } + diff --git a/queue-3.7/mwifiex-check-wait_event_interruptible-return-value.patch b/queue-3.7/mwifiex-check-wait_event_interruptible-return-value.patch new file mode 100644 index 00000000000..5c33ab187f1 --- /dev/null +++ b/queue-3.7/mwifiex-check-wait_event_interruptible-return-value.patch @@ -0,0 +1,73 @@ +From 9c969d8ccb1e17bd20742f4ac9f00c1a64487234 Mon Sep 17 00:00:00 2001 +From: Bing Zhao +Date: Wed, 2 Jan 2013 16:07:35 -0800 +Subject: mwifiex: check wait_event_interruptible return value + +From: Bing Zhao + +commit 9c969d8ccb1e17bd20742f4ac9f00c1a64487234 upstream. + +wait_event_interruptible function returns -ERESTARTSYS if it's +interrupted by a signal. Driver should check the return value +and handle this case properly. + +In mwifiex_wait_queue_complete() routine, as we are now checking +wait_event_interruptible return value, the condition check is not +required. Also, we have removed mwifiex_cancel_pending_ioctl() +call to avoid a chance of sending second command to FW by other path +as soon as we clear current command node. FW can not handle two +commands simultaneously. + +Signed-off-by: Bing Zhao +Signed-off-by: Amitkumar Karwar +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mwifiex/sta_ioctl.c | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +--- a/drivers/net/wireless/mwifiex/sta_ioctl.c ++++ b/drivers/net/wireless/mwifiex/sta_ioctl.c +@@ -56,7 +56,6 @@ int mwifiex_copy_mcast_addr(struct mwifi + */ + int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) + { +- bool cancel_flag = false; + int status; + struct cmd_ctrl_node *cmd_queued; + +@@ -70,14 +69,11 @@ int mwifiex_wait_queue_complete(struct m + atomic_inc(&adapter->cmd_pending); + + /* Wait for completion */ +- wait_event_interruptible(adapter->cmd_wait_q.wait, +- *(cmd_queued->condition)); +- if (!*(cmd_queued->condition)) +- cancel_flag = true; +- +- if (cancel_flag) { +- mwifiex_cancel_pending_ioctl(adapter); +- dev_dbg(adapter->dev, "cmd cancel\n"); ++ status = wait_event_interruptible(adapter->cmd_wait_q.wait, ++ *(cmd_queued->condition)); ++ if (status) { ++ dev_err(adapter->dev, "cmd_wait_q terminated: %d\n", status); ++ return status; + } + + status = adapter->cmd_wait_q.status; +@@ -480,8 +476,11 @@ int mwifiex_enable_hs(struct mwifiex_ada + return false; + } + +- wait_event_interruptible(adapter->hs_activate_wait_q, +- adapter->hs_activate_wait_q_woken); ++ if (wait_event_interruptible(adapter->hs_activate_wait_q, ++ adapter->hs_activate_wait_q_woken)) { ++ dev_err(adapter->dev, "hs_activate_wait_q terminated\n"); ++ return false; ++ } + + return true; + } diff --git a/queue-3.7/radeon-kms-force-rn50-chip-to-always-report-connected-on-analog-output.patch b/queue-3.7/radeon-kms-force-rn50-chip-to-always-report-connected-on-analog-output.patch new file mode 100644 index 00000000000..d4879f63ea3 --- /dev/null +++ b/queue-3.7/radeon-kms-force-rn50-chip-to-always-report-connected-on-analog-output.patch @@ -0,0 +1,38 @@ +From 51861d4eebc2ddc25c77084343d060fa79f6e291 Mon Sep 17 00:00:00 2001 +From: Jerome Glisse +Date: Tue, 8 Jan 2013 18:41:01 -0500 +Subject: radeon/kms: force rn50 chip to always report connected on analog output + +From: Jerome Glisse + +commit 51861d4eebc2ddc25c77084343d060fa79f6e291 upstream. + +Those rn50 chip are often connected to console remoting hw and load +detection often fails with those. Just don't try to load detect and +report connect. + +Signed-off-by: Jerome Glisse +Signed-off-by: Alex Deucher +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c ++++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +@@ -640,6 +640,14 @@ static enum drm_connector_status radeon_ + enum drm_connector_status found = connector_status_disconnected; + bool color = true; + ++ /* just don't bother on RN50 those chip are often connected to remoting ++ * console hw and often we get failure to load detect those. So to make ++ * everyone happy report the encoder as always connected. ++ */ ++ if (ASIC_IS_RN50(rdev)) { ++ return connector_status_connected; ++ } ++ + /* save the regs we need */ + vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL); + crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); diff --git a/queue-3.7/series b/queue-3.7/series index 2ac8ad667c9..3798ef54250 100644 --- a/queue-3.7/series +++ b/queue-3.7/series @@ -137,3 +137,20 @@ revert-alsa-hda-shut-up-pins-at-power-saving-mode-with-conexnat-codecs.patch alsa-hda-disable-runtime-d3-for-intel-cpt-co.patch alsa-pxa27x-fix-ac97-cold-reset.patch alsa-pxa27x-fix-ac97-warm-reset.patch +staging-comedi-prevent-auto-unconfig-of-manually-configured-devices.patch +staging-comedi-fix-minimum-ao-period-for-ni-625x-and-ni-628x.patch +staging-comedi-kconfig-comedi_ni_at_a2150-should-select-comedi_fc.patch +staging-comedi-comedi_test-fix-race-when-cancelling-command.patch +staging-r8712u-add-new-device-id.patch +staging-speakup-avoid-out-of-range-access-in-synth_init.patch +staging-speakup-avoid-out-of-range-access-in-synth_add.patch +staging-zram-factor-out-zram_decompress_page-function.patch +staging-zram-fix-invalid-memory-references-during-disk-write.patch +radeon-kms-force-rn50-chip-to-always-report-connected-on-analog-output.patch +iwlwifi-fix-pcie-interrupt-handle-return-value.patch +iwlwifi-fix-the-reclaimed-packet-tracking-upon-flush-queue.patch +mac80211-fix-ibss-scanning.patch +mac80211-fix-station-destruction-in-ap-mesh-modes.patch +mac80211-use-del_timer_sync-for-final-sta-cleanup-timer-deletion.patch +mwifiex-check-wait_event_interruptible-return-value.patch +b43-fix-firmware-loading-when-driver-is-built-into-the-kernel.patch diff --git a/queue-3.7/staging-comedi-comedi_test-fix-race-when-cancelling-command.patch b/queue-3.7/staging-comedi-comedi_test-fix-race-when-cancelling-command.patch new file mode 100644 index 00000000000..87302f3d659 --- /dev/null +++ b/queue-3.7/staging-comedi-comedi_test-fix-race-when-cancelling-command.patch @@ -0,0 +1,45 @@ +From c0729eeefdcd76db338f635162bf0739fd2c5f6f Mon Sep 17 00:00:00 2001 +From: Ian Abbott +Date: Fri, 4 Jan 2013 11:33:21 +0000 +Subject: staging: comedi: comedi_test: fix race when cancelling command + +From: Ian Abbott + +commit c0729eeefdcd76db338f635162bf0739fd2c5f6f upstream. + +Éric Piel reported a kernel oops in the "comedi_test" module. It was a +NULL pointer dereference within `waveform_ai_interrupt()` (actually a +timer function) that sometimes occurred when a running asynchronous +command is cancelled (either by the `COMEDI_CANCEL` ioctl or by closing +the device file). + +This seems to be a race between the caller of `waveform_ai_cancel()` +which on return from that function goes and tears down the running +command, and the timer function which uses the command. In particular, +`async->cmd.chanlist` gets freed (and the pointer set to NULL) by +`do_become_nonbusy()` in "comedi_fops.c" but a previously scheduled +`waveform_ai_interrupt()` timer function will dereference that pointer +regardless, leading to the oops. + +Fix it by replacing the `del_timer()` call in `waveform_ai_cancel()` +with `del_timer_sync()`. + +Signed-off-by: Ian Abbott +Reported-by: Éric Piel +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/comedi/drivers/comedi_test.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/comedi/drivers/comedi_test.c ++++ b/drivers/staging/comedi/drivers/comedi_test.c +@@ -372,7 +372,7 @@ static int waveform_ai_cancel(struct com + struct waveform_private *devpriv = dev->private; + + devpriv->timer_running = 0; +- del_timer(&devpriv->timer); ++ del_timer_sync(&devpriv->timer); + return 0; + } + diff --git a/queue-3.7/staging-comedi-fix-minimum-ao-period-for-ni-625x-and-ni-628x.patch b/queue-3.7/staging-comedi-fix-minimum-ao-period-for-ni-625x-and-ni-628x.patch new file mode 100644 index 00000000000..29416f7d7fc --- /dev/null +++ b/queue-3.7/staging-comedi-fix-minimum-ao-period-for-ni-625x-and-ni-628x.patch @@ -0,0 +1,103 @@ +From 34b55d8c48f4f76044d8f4d6ec3dc786cf210312 Mon Sep 17 00:00:00 2001 +From: Éric Piel +Date: Wed, 19 Dec 2012 13:03:13 +0100 +Subject: staging: comedi: fix minimum AO period for NI 625x and NI 628x + +From: Éric Piel + +commit 34b55d8c48f4f76044d8f4d6ec3dc786cf210312 upstream. + +The minimum period was set to 357 ns, while the divider for these boards is 50 +ns. This prevented to output at maximum speed as ni_ao_cmdtest() would return +357 but would not accept it. + +Not sure why it was set to 357 ns (this was done before the git history, +which starts 5 years ago). My guess is that it comes from reading the +specification stating a 2.8 MHz rate (~ 357 ns). The latest +specification states a 2.86 MHz rate (~ 350 ns), which makes a lot +more sense. + +Tested on a pci-6251. + +Signed-off-by: Éric Piel +Acked-By: Ian Abbott +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/comedi/drivers/ni_pcimio.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +--- a/drivers/staging/comedi/drivers/ni_pcimio.c ++++ b/drivers/staging/comedi/drivers/ni_pcimio.c +@@ -963,7 +963,7 @@ static const struct ni_board_struct ni_b + .ao_range_table = &range_ni_M_625x_ao, + .reg_type = ni_reg_625x, + .ao_unipolar = 0, +- .ao_speed = 357, ++ .ao_speed = 350, + .num_p0_dio_channels = 8, + .caldac = {caldac_none}, + .has_8255 = 0, +@@ -982,7 +982,7 @@ static const struct ni_board_struct ni_b + .ao_range_table = &range_ni_M_625x_ao, + .reg_type = ni_reg_625x, + .ao_unipolar = 0, +- .ao_speed = 357, ++ .ao_speed = 350, + .num_p0_dio_channels = 8, + .caldac = {caldac_none}, + .has_8255 = 0, +@@ -1001,7 +1001,7 @@ static const struct ni_board_struct ni_b + .ao_range_table = &range_ni_M_625x_ao, + .reg_type = ni_reg_625x, + .ao_unipolar = 0, +- .ao_speed = 357, ++ .ao_speed = 350, + .num_p0_dio_channels = 8, + .caldac = {caldac_none}, + .has_8255 = 0, +@@ -1037,7 +1037,7 @@ static const struct ni_board_struct ni_b + .ao_range_table = &range_ni_M_625x_ao, + .reg_type = ni_reg_625x, + .ao_unipolar = 0, +- .ao_speed = 357, ++ .ao_speed = 350, + .num_p0_dio_channels = 32, + .caldac = {caldac_none}, + .has_8255 = 0, +@@ -1056,7 +1056,7 @@ static const struct ni_board_struct ni_b + .ao_range_table = &range_ni_M_625x_ao, + .reg_type = ni_reg_625x, + .ao_unipolar = 0, +- .ao_speed = 357, ++ .ao_speed = 350, + .num_p0_dio_channels = 32, + .caldac = {caldac_none}, + .has_8255 = 0, +@@ -1092,7 +1092,7 @@ static const struct ni_board_struct ni_b + .ao_range_table = &range_ni_M_628x_ao, + .reg_type = ni_reg_628x, + .ao_unipolar = 1, +- .ao_speed = 357, ++ .ao_speed = 350, + .num_p0_dio_channels = 8, + .caldac = {caldac_none}, + .has_8255 = 0, +@@ -1111,7 +1111,7 @@ static const struct ni_board_struct ni_b + .ao_range_table = &range_ni_M_628x_ao, + .reg_type = ni_reg_628x, + .ao_unipolar = 1, +- .ao_speed = 357, ++ .ao_speed = 350, + .num_p0_dio_channels = 8, + .caldac = {caldac_none}, + .has_8255 = 0, +@@ -1147,7 +1147,7 @@ static const struct ni_board_struct ni_b + .ao_range_table = &range_ni_M_628x_ao, + .reg_type = ni_reg_628x, + .ao_unipolar = 1, +- .ao_speed = 357, ++ .ao_speed = 350, + .num_p0_dio_channels = 32, + .caldac = {caldac_none}, + .has_8255 = 0, diff --git a/queue-3.7/staging-comedi-kconfig-comedi_ni_at_a2150-should-select-comedi_fc.patch b/queue-3.7/staging-comedi-kconfig-comedi_ni_at_a2150-should-select-comedi_fc.patch new file mode 100644 index 00000000000..d2b92b0eb01 --- /dev/null +++ b/queue-3.7/staging-comedi-kconfig-comedi_ni_at_a2150-should-select-comedi_fc.patch @@ -0,0 +1,30 @@ +From 34ffb33e09132401872fe79e95c30824ce194d23 Mon Sep 17 00:00:00 2001 +From: Ian Abbott +Date: Thu, 3 Jan 2013 12:15:26 +0000 +Subject: staging: comedi: Kconfig: COMEDI_NI_AT_A2150 should select COMEDI_FC + +From: Ian Abbott + +commit 34ffb33e09132401872fe79e95c30824ce194d23 upstream. + +The 'ni_at_a2150' module links to `cfc_write_to_buffer` in the +'comedi_fc' module, so selecting 'COMEDI_NI_AT_A2150' in the kernel config +needs to also select 'COMEDI_FC'. + +Signed-off-by: Ian Abbott +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/comedi/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/staging/comedi/Kconfig ++++ b/drivers/staging/comedi/Kconfig +@@ -444,6 +444,7 @@ config COMEDI_ADQ12B + + config COMEDI_NI_AT_A2150 + tristate "NI AT-A2150 ISA card support" ++ select COMEDI_FC + depends on VIRT_TO_BUS + ---help--- + Enable support for National Instruments AT-A2150 cards diff --git a/queue-3.7/staging-comedi-prevent-auto-unconfig-of-manually-configured-devices.patch b/queue-3.7/staging-comedi-prevent-auto-unconfig-of-manually-configured-devices.patch new file mode 100644 index 00000000000..e5040538311 --- /dev/null +++ b/queue-3.7/staging-comedi-prevent-auto-unconfig-of-manually-configured-devices.patch @@ -0,0 +1,48 @@ +From 7d3135af399e92cf4c9bbc5f86b6c140aab3b88c Mon Sep 17 00:00:00 2001 +From: Ian Abbott +Date: Tue, 4 Dec 2012 15:59:55 +0000 +Subject: staging: comedi: prevent auto-unconfig of manually configured devices + +From: Ian Abbott + +commit 7d3135af399e92cf4c9bbc5f86b6c140aab3b88c upstream. + +When a low-level comedi driver auto-configures a device, a `struct +comedi_dev_file_info` is allocated (as well as a `struct +comedi_device`) by `comedi_alloc_board_minor()`. A pointer to the +hardware `struct device` is stored as a cookie in the `struct +comedi_dev_file_info`. When the low-level comedi driver +auto-unconfigures the device, `comedi_auto_unconfig()` uses the cookie +to find the `struct comedi_dev_file_info` so it can detach the comedi +device from the driver, clean it up and free it. + +A problem arises if the user manually unconfigures and reconfigures the +comedi device using the `COMEDI_DEVCONFIG` ioctl so that is no longer +associated with the original hardware device. The problem is that the +cookie is not cleared, so that a call to `comedi_auto_unconfig()` from +the low-level driver will still find it, detach it, clean it up and free +it. + +Stop this problem occurring by always clearing the `hardware_device` +cookie in the `struct comedi_dev_file_info` whenever the +`COMEDI_DEVCONFIG` ioctl call is successful. + +Signed-off-by: Ian Abbott +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/comedi/comedi_fops.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/staging/comedi/comedi_fops.c ++++ b/drivers/staging/comedi/comedi_fops.c +@@ -1546,6 +1546,9 @@ static long comedi_unlocked_ioctl(struct + if (cmd == COMEDI_DEVCONFIG) { + rc = do_devconfig_ioctl(dev, + (struct comedi_devconfig __user *)arg); ++ if (rc == 0) ++ /* Evade comedi_auto_unconfig(). */ ++ dev_file_info->hardware_device = NULL; + goto done; + } + diff --git a/queue-3.7/staging-r8712u-add-new-device-id.patch b/queue-3.7/staging-r8712u-add-new-device-id.patch new file mode 100644 index 00000000000..0a0bfded65c --- /dev/null +++ b/queue-3.7/staging-r8712u-add-new-device-id.patch @@ -0,0 +1,32 @@ +From da849a92d3bafaf24d770e971c2c9e5c3f60b5d1 Mon Sep 17 00:00:00 2001 +From: Larry Finger +Date: Sat, 29 Dec 2012 11:36:53 -0600 +Subject: staging: r8712u: Add new device ID + +From: Larry Finger + +commit da849a92d3bafaf24d770e971c2c9e5c3f60b5d1 upstream. + +The ISY IWL 1000 USB WLAN stick with USB ID 050d:11f1 is a clone of +the Belkin F7D1101 V1 device. + +Reported-by: Thomas Hartmann +Signed-off-by: Larry Finger +Cc: Thomas Hartmann +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/rtl8712/usb_intf.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/staging/rtl8712/usb_intf.c ++++ b/drivers/staging/rtl8712/usb_intf.c +@@ -63,6 +63,8 @@ static struct usb_device_id rtl871x_usb_ + {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */ + /* Belkin */ + {USB_DEVICE(0x050D, 0x945A)}, ++ /* ISY IWL - Belkin clone */ ++ {USB_DEVICE(0x050D, 0x11F1)}, + /* Corega */ + {USB_DEVICE(0x07AA, 0x0047)}, + /* D-Link */ diff --git a/queue-3.7/staging-speakup-avoid-out-of-range-access-in-synth_add.patch b/queue-3.7/staging-speakup-avoid-out-of-range-access-in-synth_add.patch new file mode 100644 index 00000000000..26b556d4554 --- /dev/null +++ b/queue-3.7/staging-speakup-avoid-out-of-range-access-in-synth_add.patch @@ -0,0 +1,30 @@ +From 6102c48bd421074a33e102f2ebda3724e8d275f9 Mon Sep 17 00:00:00 2001 +From: Samuel Thibault +Date: Mon, 7 Jan 2013 22:03:51 +0100 +Subject: staging: speakup: avoid out-of-range access in synth_add() + +From: Samuel Thibault + +commit 6102c48bd421074a33e102f2ebda3724e8d275f9 upstream. + +Check that array index is in-bounds before accessing the synths[] array. + +Signed-off-by: Samuel Thibault +Cc: Nickolai Zeldovich +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/speakup/synth.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/speakup/synth.c ++++ b/drivers/staging/speakup/synth.c +@@ -423,7 +423,7 @@ int synth_add(struct spk_synth *in_synth + int i; + int status = 0; + mutex_lock(&spk_mutex); +- for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++) ++ for (i = 0; i < MAXSYNTHS && synths[i] != NULL; i++) + /* synth_remove() is responsible for rotating the array down */ + if (in_synth == synths[i]) { + mutex_unlock(&spk_mutex); diff --git a/queue-3.7/staging-speakup-avoid-out-of-range-access-in-synth_init.patch b/queue-3.7/staging-speakup-avoid-out-of-range-access-in-synth_init.patch new file mode 100644 index 00000000000..0cd3e613d8e --- /dev/null +++ b/queue-3.7/staging-speakup-avoid-out-of-range-access-in-synth_init.patch @@ -0,0 +1,30 @@ +From ae428655b826f2755a8101b27beda42a275ef8ad Mon Sep 17 00:00:00 2001 +From: Nickolai Zeldovich +Date: Sat, 5 Jan 2013 14:17:45 -0500 +Subject: staging: speakup: avoid out-of-range access in synth_init() + +From: Nickolai Zeldovich + +commit ae428655b826f2755a8101b27beda42a275ef8ad upstream. + +Check that array index is in-bounds before accessing the synths[] array. + +Signed-off-by: Nickolai Zeldovich +Cc: Samuel Thibault +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/speakup/synth.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/speakup/synth.c ++++ b/drivers/staging/speakup/synth.c +@@ -342,7 +342,7 @@ int synth_init(char *synth_name) + + mutex_lock(&spk_mutex); + /* First, check if we already have it loaded. */ +- for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++) ++ for (i = 0; i < MAXSYNTHS && synths[i] != NULL; i++) + if (strcmp(synths[i]->name, synth_name) == 0) + synth = synths[i]; + diff --git a/queue-3.7/staging-zram-factor-out-zram_decompress_page-function.patch b/queue-3.7/staging-zram-factor-out-zram_decompress_page-function.patch new file mode 100644 index 00000000000..044d0ea890f --- /dev/null +++ b/queue-3.7/staging-zram-factor-out-zram_decompress_page-function.patch @@ -0,0 +1,179 @@ +From 37b51fdddf64e7ba0971d070428655f8d6f36578 Mon Sep 17 00:00:00 2001 +From: Sergey Senozhatsky +Date: Tue, 30 Oct 2012 22:40:23 +0300 +Subject: staging: zram: factor-out zram_decompress_page() function + +From: Sergey Senozhatsky + +commit 37b51fdddf64e7ba0971d070428655f8d6f36578 upstream. + +zram_bvec_read() shared decompress functionality with zram_read_before_write() function. +Factor-out and make commonly used zram_decompress_page() function, which also simplified +error handling in zram_bvec_read(). + +Signed-off-by: Sergey Senozhatsky +Reviewed-by: Nitin Gupta +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/zram/zram_drv.c | 113 ++++++++++++++++------------------------ + 1 file changed, 48 insertions(+), 65 deletions(-) + +--- a/drivers/staging/zram/zram_drv.c ++++ b/drivers/staging/zram/zram_drv.c +@@ -183,62 +183,25 @@ static inline int is_partial_io(struct b + return bvec->bv_len != PAGE_SIZE; + } + +-static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, +- u32 index, int offset, struct bio *bio) ++static int zram_decompress_page(struct zram *zram, char *mem, u32 index) + { +- int ret; +- size_t clen; +- struct page *page; +- unsigned char *user_mem, *cmem, *uncmem = NULL; +- +- page = bvec->bv_page; +- +- if (zram_test_flag(zram, index, ZRAM_ZERO)) { +- handle_zero_page(bvec); +- return 0; +- } ++ int ret = LZO_E_OK; ++ size_t clen = PAGE_SIZE; ++ unsigned char *cmem; ++ unsigned long handle = zram->table[index].handle; + +- /* Requested page is not present in compressed area */ +- if (unlikely(!zram->table[index].handle)) { +- pr_debug("Read before write: sector=%lu, size=%u", +- (ulong)(bio->bi_sector), bio->bi_size); +- handle_zero_page(bvec); ++ if (!handle || zram_test_flag(zram, index, ZRAM_ZERO)) { ++ memset(mem, 0, PAGE_SIZE); + return 0; + } + +- if (is_partial_io(bvec)) { +- /* Use a temporary buffer to decompress the page */ +- uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL); +- if (!uncmem) { +- pr_info("Error allocating temp memory!\n"); +- return -ENOMEM; +- } +- } +- +- user_mem = kmap_atomic(page); +- if (!is_partial_io(bvec)) +- uncmem = user_mem; +- clen = PAGE_SIZE; +- +- cmem = zs_map_object(zram->mem_pool, zram->table[index].handle, +- ZS_MM_RO); +- +- if (zram->table[index].size == PAGE_SIZE) { +- memcpy(uncmem, cmem, PAGE_SIZE); +- ret = LZO_E_OK; +- } else { ++ cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_RO); ++ if (zram->table[index].size == PAGE_SIZE) ++ memcpy(mem, cmem, PAGE_SIZE); ++ else + ret = lzo1x_decompress_safe(cmem, zram->table[index].size, +- uncmem, &clen); +- } +- +- if (is_partial_io(bvec)) { +- memcpy(user_mem + bvec->bv_offset, uncmem + offset, +- bvec->bv_len); +- kfree(uncmem); +- } +- +- zs_unmap_object(zram->mem_pool, zram->table[index].handle); +- kunmap_atomic(user_mem); ++ mem, &clen); ++ zs_unmap_object(zram->mem_pool, handle); + + /* Should NEVER happen. Return bio error if it does. */ + if (unlikely(ret != LZO_E_OK)) { +@@ -247,36 +210,56 @@ static int zram_bvec_read(struct zram *z + return ret; + } + +- flush_dcache_page(page); +- + return 0; + } + +-static int zram_read_before_write(struct zram *zram, char *mem, u32 index) ++static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, ++ u32 index, int offset, struct bio *bio) + { + int ret; +- size_t clen = PAGE_SIZE; +- unsigned char *cmem; +- unsigned long handle = zram->table[index].handle; ++ struct page *page; ++ unsigned char *user_mem, *uncmem = NULL; + +- if (zram_test_flag(zram, index, ZRAM_ZERO) || !handle) { +- memset(mem, 0, PAGE_SIZE); ++ page = bvec->bv_page; ++ ++ if (unlikely(!zram->table[index].handle) || ++ zram_test_flag(zram, index, ZRAM_ZERO)) { ++ handle_zero_page(bvec); + return 0; + } + +- cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_RO); +- ret = lzo1x_decompress_safe(cmem, zram->table[index].size, +- mem, &clen); +- zs_unmap_object(zram->mem_pool, handle); ++ user_mem = kmap_atomic(page); ++ if (is_partial_io(bvec)) ++ /* Use a temporary buffer to decompress the page */ ++ uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL); ++ else ++ uncmem = user_mem; ++ ++ if (!uncmem) { ++ pr_info("Unable to allocate temp memory\n"); ++ ret = -ENOMEM; ++ goto out_cleanup; ++ } + ++ ret = zram_decompress_page(zram, uncmem, index); + /* Should NEVER happen. Return bio error if it does. */ + if (unlikely(ret != LZO_E_OK)) { + pr_err("Decompression failed! err=%d, page=%u\n", ret, index); + zram_stat64_inc(zram, &zram->stats.failed_reads); +- return ret; ++ goto out_cleanup; + } + +- return 0; ++ if (is_partial_io(bvec)) ++ memcpy(user_mem + bvec->bv_offset, uncmem + offset, ++ bvec->bv_len); ++ ++ flush_dcache_page(page); ++ ret = 0; ++out_cleanup: ++ kunmap_atomic(user_mem); ++ if (is_partial_io(bvec)) ++ kfree(uncmem); ++ return ret; + } + + static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, +@@ -302,7 +285,7 @@ static int zram_bvec_write(struct zram * + ret = -ENOMEM; + goto out; + } +- ret = zram_read_before_write(zram, uncmem, index); ++ ret = zram_decompress_page(zram, uncmem, index); + if (ret) { + kfree(uncmem); + goto out; diff --git a/queue-3.7/staging-zram-fix-invalid-memory-references-during-disk-write.patch b/queue-3.7/staging-zram-fix-invalid-memory-references-during-disk-write.patch new file mode 100644 index 00000000000..52b99e02b53 --- /dev/null +++ b/queue-3.7/staging-zram-fix-invalid-memory-references-during-disk-write.patch @@ -0,0 +1,129 @@ +From 397c60668aa5ae7130b5ad4e73870d7b8a787085 Mon Sep 17 00:00:00 2001 +From: Nitin Gupta +Date: Wed, 2 Jan 2013 08:53:41 -0800 +Subject: staging: zram: fix invalid memory references during disk write + +From: Nitin Gupta + +commit 397c60668aa5ae7130b5ad4e73870d7b8a787085 upstream. + +Fixes a bug introduced by commit c8f2f0db1 ("zram: Fix handling +of incompressible pages") which caused invalid memory references +during disk write. Invalid references could occur in two cases: + - Incoming data expands on compression: In this case, reference was +made to kunmap()'ed bio page. + - Partial (non PAGE_SIZE) write with incompressible data: In this +case, reference was made to a kfree()'ed buffer. + +Fixes bug 50081: +https://bugzilla.kernel.org/show_bug.cgi?id=50081 + +Signed-off-by: Nitin Gupta +Reported-by: Mihail Kasadjikov +Reported-by: Tomas M +Reviewed-by: Minchan Kim +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/zram/zram_drv.c | 39 ++++++++++++++++++++++++--------------- + 1 file changed, 24 insertions(+), 15 deletions(-) + +--- a/drivers/staging/zram/zram_drv.c ++++ b/drivers/staging/zram/zram_drv.c +@@ -265,7 +265,7 @@ out_cleanup: + static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, + int offset) + { +- int ret; ++ int ret = 0; + size_t clen; + unsigned long handle; + struct page *page; +@@ -286,10 +286,8 @@ static int zram_bvec_write(struct zram * + goto out; + } + ret = zram_decompress_page(zram, uncmem, index); +- if (ret) { +- kfree(uncmem); ++ if (ret) + goto out; +- } + } + + /* +@@ -302,16 +300,18 @@ static int zram_bvec_write(struct zram * + + user_mem = kmap_atomic(page); + +- if (is_partial_io(bvec)) ++ if (is_partial_io(bvec)) { + memcpy(uncmem + offset, user_mem + bvec->bv_offset, + bvec->bv_len); +- else ++ kunmap_atomic(user_mem); ++ user_mem = NULL; ++ } else { + uncmem = user_mem; ++ } + + if (page_zero_filled(uncmem)) { +- kunmap_atomic(user_mem); +- if (is_partial_io(bvec)) +- kfree(uncmem); ++ if (!is_partial_io(bvec)) ++ kunmap_atomic(user_mem); + zram_stat_inc(&zram->stats.pages_zero); + zram_set_flag(zram, index, ZRAM_ZERO); + ret = 0; +@@ -321,9 +321,11 @@ static int zram_bvec_write(struct zram * + ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen, + zram->compress_workmem); + +- kunmap_atomic(user_mem); +- if (is_partial_io(bvec)) +- kfree(uncmem); ++ if (!is_partial_io(bvec)) { ++ kunmap_atomic(user_mem); ++ user_mem = NULL; ++ uncmem = NULL; ++ } + + if (unlikely(ret != LZO_E_OK)) { + pr_err("Compression failed! err=%d\n", ret); +@@ -332,8 +334,10 @@ static int zram_bvec_write(struct zram * + + if (unlikely(clen > max_zpage_size)) { + zram_stat_inc(&zram->stats.bad_compress); +- src = uncmem; + clen = PAGE_SIZE; ++ src = NULL; ++ if (is_partial_io(bvec)) ++ src = uncmem; + } + + handle = zs_malloc(zram->mem_pool, clen); +@@ -345,7 +349,11 @@ static int zram_bvec_write(struct zram * + } + cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_WO); + ++ if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) ++ src = kmap_atomic(page); + memcpy(cmem, src, clen); ++ if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) ++ kunmap_atomic(src); + + zs_unmap_object(zram->mem_pool, handle); + +@@ -358,9 +366,10 @@ static int zram_bvec_write(struct zram * + if (clen <= PAGE_SIZE / 2) + zram_stat_inc(&zram->stats.good_compress); + +- return 0; +- + out: ++ if (is_partial_io(bvec)) ++ kfree(uncmem); ++ + if (ret) + zram_stat64_inc(zram, &zram->stats.failed_writes); + return ret; -- 2.47.3