From: Greg Kroah-Hartman Date: Wed, 6 Mar 2013 04:53:30 +0000 (+0800) Subject: 3.8-stable patches X-Git-Tag: v3.8.3~37 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5dc2d9428763069e03274e879738649ae87aa795;p=thirdparty%2Fkernel%2Fstable-queue.git 3.8-stable patches added patches: hw_random-make-buffer-usable-in-scatterlist.patch iwlwifi-always-copy-first-16-bytes-of-commands.patch libertas-fix-crash-for-sd8688.patch mwifiex-correct-sleep-delay-counter.patch --- diff --git a/queue-3.8/hw_random-make-buffer-usable-in-scatterlist.patch b/queue-3.8/hw_random-make-buffer-usable-in-scatterlist.patch new file mode 100644 index 00000000000..1f537b97e56 --- /dev/null +++ b/queue-3.8/hw_random-make-buffer-usable-in-scatterlist.patch @@ -0,0 +1,75 @@ +From f7f154f1246ccc5a0a7e9ce50932627d60a0c878 Mon Sep 17 00:00:00 2001 +From: Rusty Russell +Date: Tue, 5 Mar 2013 10:07:08 +1030 +Subject: hw_random: make buffer usable in scatterlist. + +From: Rusty Russell + +commit f7f154f1246ccc5a0a7e9ce50932627d60a0c878 upstream. + +virtio_rng feeds the randomness buffer handed by the core directly +into the scatterlist, since commit bb347d98079a547e80bd4722dee1de61e4dca0e8. + +However, if CONFIG_HW_RANDOM=m, the static buffer isn't a linear address +(at least on most archs). We could fix this in virtio_rng, but it's actually +far easier to just do it in the core as virtio_rng would have to allocate +a buffer every time (it doesn't know how much the core will want to read). + +Reported-by: Aurelien Jarno +Tested-by: Aurelien Jarno +Signed-off-by: Rusty Russell +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/char/hw_random/core.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +--- a/drivers/char/hw_random/core.c ++++ b/drivers/char/hw_random/core.c +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + #include + + +@@ -52,8 +53,12 @@ static struct hwrng *current_rng; + static LIST_HEAD(rng_list); + static DEFINE_MUTEX(rng_mutex); + static int data_avail; +-static u8 rng_buffer[SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES] +- __cacheline_aligned; ++static u8 *rng_buffer; ++ ++static size_t rng_buffer_size(void) ++{ ++ return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES; ++} + + static inline int hwrng_init(struct hwrng *rng) + { +@@ -116,7 +121,7 @@ static ssize_t rng_dev_read(struct file + + if (!data_avail) { + bytes_read = rng_get_data(current_rng, rng_buffer, +- sizeof(rng_buffer), ++ rng_buffer_size(), + !(filp->f_flags & O_NONBLOCK)); + if (bytes_read < 0) { + err = bytes_read; +@@ -307,6 +312,14 @@ int hwrng_register(struct hwrng *rng) + + mutex_lock(&rng_mutex); + ++ /* kmalloc makes this safe for virt_to_page() in virtio_rng.c */ ++ err = -ENOMEM; ++ if (!rng_buffer) { ++ rng_buffer = kmalloc(rng_buffer_size(), GFP_KERNEL); ++ if (!rng_buffer) ++ goto out_unlock; ++ } ++ + /* Must not register two RNGs with the same name. */ + err = -EEXIST; + list_for_each_entry(tmp, &rng_list, list) { diff --git a/queue-3.8/iwlwifi-always-copy-first-16-bytes-of-commands.patch b/queue-3.8/iwlwifi-always-copy-first-16-bytes-of-commands.patch new file mode 100644 index 00000000000..33fa5311e8a --- /dev/null +++ b/queue-3.8/iwlwifi-always-copy-first-16-bytes-of-commands.patch @@ -0,0 +1,241 @@ +From 8a964f44e01ad3bbc208c3e80d931ba91b9ea786 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Mon, 25 Feb 2013 16:01:34 +0100 +Subject: iwlwifi: always copy first 16 bytes of commands + +From: Johannes Berg + +commit 8a964f44e01ad3bbc208c3e80d931ba91b9ea786 upstream. + +The FH hardware will always write back to the scratch field +in commands, even host commands not just TX commands, which +can overwrite parts of the command. This is problematic if +the command is re-used (with IWL_HCMD_DFL_NOCOPY) and can +cause calibration issues. + +Address this problem by always putting at least the first +16 bytes into the buffer we also use for the command header +and therefore make the DMA engine write back into this. + +For commands that are smaller than 16 bytes also always map +enough memory for the DMA engine to write back to. + +Reviewed-by: Emmanuel Grumbach +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/iwlwifi/iwl-devtrace.h | 10 +-- + drivers/net/wireless/iwlwifi/pcie/internal.h | 9 +++ + drivers/net/wireless/iwlwifi/pcie/tx.c | 75 ++++++++++++++++++++------- + 3 files changed, 71 insertions(+), 23 deletions(-) + +--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h ++++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h +@@ -349,25 +349,23 @@ TRACE_EVENT(iwlwifi_dev_rx_data, + TRACE_EVENT(iwlwifi_dev_hcmd, + TP_PROTO(const struct device *dev, + struct iwl_host_cmd *cmd, u16 total_size, +- const void *hdr, size_t hdr_len), +- TP_ARGS(dev, cmd, total_size, hdr, hdr_len), ++ struct iwl_cmd_header *hdr), ++ TP_ARGS(dev, cmd, total_size, hdr), + TP_STRUCT__entry( + DEV_ENTRY + __dynamic_array(u8, hcmd, total_size) + __field(u32, flags) + ), + TP_fast_assign( +- int i, offset = hdr_len; ++ int i, offset = sizeof(*hdr); + + DEV_ASSIGN; + __entry->flags = cmd->flags; +- memcpy(__get_dynamic_array(hcmd), hdr, hdr_len); ++ memcpy(__get_dynamic_array(hcmd), hdr, sizeof(*hdr)); + + for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { + if (!cmd->len[i]) + continue; +- if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)) +- continue; + memcpy((u8 *)__get_dynamic_array(hcmd) + offset, + cmd->data[i], cmd->len[i]); + offset += cmd->len[i]; +--- a/drivers/net/wireless/iwlwifi/pcie/internal.h ++++ b/drivers/net/wireless/iwlwifi/pcie/internal.h +@@ -182,6 +182,15 @@ struct iwl_queue { + #define TFD_TX_CMD_SLOTS 256 + #define TFD_CMD_SLOTS 32 + ++/* ++ * The FH will write back to the first TB only, so we need ++ * to copy some data into the buffer regardless of whether ++ * it should be mapped or not. This indicates how much to ++ * copy, even for HCMDs it must be big enough to fit the ++ * DRAM scratch from the TX cmd, at least 16 bytes. ++ */ ++#define IWL_HCMD_MIN_COPY_SIZE 16 ++ + struct iwl_pcie_txq_entry { + struct iwl_device_cmd *cmd; + struct iwl_device_cmd *copy_cmd; +--- a/drivers/net/wireless/iwlwifi/pcie/tx.c ++++ b/drivers/net/wireless/iwlwifi/pcie/tx.c +@@ -1131,10 +1131,12 @@ static int iwl_pcie_enqueue_hcmd(struct + void *dup_buf = NULL; + dma_addr_t phys_addr; + int idx; +- u16 copy_size, cmd_size; ++ u16 copy_size, cmd_size, dma_size; + bool had_nocopy = false; + int i; + u32 cmd_pos; ++ const u8 *cmddata[IWL_MAX_CMD_TFDS]; ++ u16 cmdlen[IWL_MAX_CMD_TFDS]; + + copy_size = sizeof(out_cmd->hdr); + cmd_size = sizeof(out_cmd->hdr); +@@ -1143,8 +1145,23 @@ static int iwl_pcie_enqueue_hcmd(struct + BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1); + + for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { ++ cmddata[i] = cmd->data[i]; ++ cmdlen[i] = cmd->len[i]; ++ + if (!cmd->len[i]) + continue; ++ ++ /* need at least IWL_HCMD_MIN_COPY_SIZE copied */ ++ if (copy_size < IWL_HCMD_MIN_COPY_SIZE) { ++ int copy = IWL_HCMD_MIN_COPY_SIZE - copy_size; ++ ++ if (copy > cmdlen[i]) ++ copy = cmdlen[i]; ++ cmdlen[i] -= copy; ++ cmddata[i] += copy; ++ copy_size += copy; ++ } ++ + if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) { + had_nocopy = true; + if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) { +@@ -1164,7 +1181,7 @@ static int iwl_pcie_enqueue_hcmd(struct + goto free_dup_buf; + } + +- dup_buf = kmemdup(cmd->data[i], cmd->len[i], ++ dup_buf = kmemdup(cmddata[i], cmdlen[i], + GFP_ATOMIC); + if (!dup_buf) + return -ENOMEM; +@@ -1174,7 +1191,7 @@ static int iwl_pcie_enqueue_hcmd(struct + idx = -EINVAL; + goto free_dup_buf; + } +- copy_size += cmd->len[i]; ++ copy_size += cmdlen[i]; + } + cmd_size += cmd->len[i]; + } +@@ -1221,14 +1238,31 @@ static int iwl_pcie_enqueue_hcmd(struct + + /* and copy the data that needs to be copied */ + cmd_pos = offsetof(struct iwl_device_cmd, payload); ++ copy_size = sizeof(out_cmd->hdr); + for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { +- if (!cmd->len[i]) ++ int copy = 0; ++ ++ if (!cmd->len) + continue; +- if (cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | +- IWL_HCMD_DFL_DUP)) +- break; +- memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]); +- cmd_pos += cmd->len[i]; ++ ++ /* need at least IWL_HCMD_MIN_COPY_SIZE copied */ ++ if (copy_size < IWL_HCMD_MIN_COPY_SIZE) { ++ copy = IWL_HCMD_MIN_COPY_SIZE - copy_size; ++ ++ if (copy > cmd->len[i]) ++ copy = cmd->len[i]; ++ } ++ ++ /* copy everything if not nocopy/dup */ ++ if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | ++ IWL_HCMD_DFL_DUP))) ++ copy = cmd->len[i]; ++ ++ if (copy) { ++ memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy); ++ cmd_pos += copy; ++ copy_size += copy; ++ } + } + + WARN_ON_ONCE(txq->entries[idx].copy_cmd); +@@ -1254,7 +1288,14 @@ static int iwl_pcie_enqueue_hcmd(struct + out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), + cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue); + +- phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size, ++ /* ++ * If the entire command is smaller than IWL_HCMD_MIN_COPY_SIZE, we must ++ * still map at least that many bytes for the hardware to write back to. ++ * We have enough space, so that's not a problem. ++ */ ++ dma_size = max_t(u16, copy_size, IWL_HCMD_MIN_COPY_SIZE); ++ ++ phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, dma_size, + DMA_BIDIRECTIONAL); + if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { + idx = -ENOMEM; +@@ -1262,14 +1303,15 @@ static int iwl_pcie_enqueue_hcmd(struct + } + + dma_unmap_addr_set(out_meta, mapping, phys_addr); +- dma_unmap_len_set(out_meta, len, copy_size); ++ dma_unmap_len_set(out_meta, len, dma_size); + + iwl_pcie_txq_build_tfd(trans, txq, phys_addr, copy_size, 1); + ++ /* map the remaining (adjusted) nocopy/dup fragments */ + for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { +- const void *data = cmd->data[i]; ++ const void *data = cmddata[i]; + +- if (!cmd->len[i]) ++ if (!cmdlen[i]) + continue; + if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | + IWL_HCMD_DFL_DUP))) +@@ -1277,7 +1319,7 @@ static int iwl_pcie_enqueue_hcmd(struct + if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP) + data = dup_buf; + phys_addr = dma_map_single(trans->dev, (void *)data, +- cmd->len[i], DMA_BIDIRECTIONAL); ++ cmdlen[i], DMA_BIDIRECTIONAL); + if (dma_mapping_error(trans->dev, phys_addr)) { + iwl_pcie_tfd_unmap(trans, out_meta, + &txq->tfds[q->write_ptr], +@@ -1286,7 +1328,7 @@ static int iwl_pcie_enqueue_hcmd(struct + goto out; + } + +- iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmd->len[i], 0); ++ iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmdlen[i], 0); + } + + out_meta->flags = cmd->flags; +@@ -1296,8 +1338,7 @@ static int iwl_pcie_enqueue_hcmd(struct + + txq->need_update = 1; + +- trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, +- &out_cmd->hdr, copy_size); ++ trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); + + /* start timer if queue currently empty */ + if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) diff --git a/queue-3.8/libertas-fix-crash-for-sd8688.patch b/queue-3.8/libertas-fix-crash-for-sd8688.patch new file mode 100644 index 00000000000..c9ec2fc8509 --- /dev/null +++ b/queue-3.8/libertas-fix-crash-for-sd8688.patch @@ -0,0 +1,63 @@ +From 466026989f112e0546ca39ab00a759af82dbe83a Mon Sep 17 00:00:00 2001 +From: Bing Zhao +Date: Tue, 26 Feb 2013 12:58:35 -0800 +Subject: libertas: fix crash for SD8688 + +From: Bing Zhao + +commit 466026989f112e0546ca39ab00a759af82dbe83a upstream. + +For SD8688, FUNC_INIT command is queued before fw_ready flag is +set. This causes the following crash as lbs_thread blocks any +command if fw_ready is not set. + +[ 209.338953] [] (__schedule+0x610/0x764) from [] (__lbs_cmd+0xb8/0x130 [libertas]) +[ 209.348340] [] (__lbs_cmd+0xb8/0x130 [libertas]) from [] (if_sdio_finish_power_on+0xec/0x1b0 [libertas_sdio]) +[ 209.360136] [] (if_sdio_finish_power_on+0xec/0x1b0 [libertas_sdio]) from [] (if_sdio_power_on+0x18c/0x20c [libertas_sdio]) +[ 209.373052] [] (if_sdio_power_on+0x18c/0x20c [libertas_sdio]) from [] (if_sdio_probe+0x200/0x31c [libertas_sdio]) +[ 209.385316] [] (if_sdio_probe+0x200/0x31c [libertas_sdio]) from [] (sdio_bus_probe+0x94/0xfc [mmc_core]) +[ 209.396748] [] (sdio_bus_probe+0x94/0xfc [mmc_core]) from [] (driver_probe_device+0x12c/0x348) +[ 209.407214] [] (driver_probe_device+0x12c/0x348) from [] (__driver_attach+0x78/0x9c) +[ 209.416798] [] (__driver_attach+0x78/0x9c) from [] (bus_for_each_dev+0x50/0x88) +[ 209.425946] [] (bus_for_each_dev+0x50/0x88) from [] (bus_add_driver+0x108/0x268) +[ 209.435180] [] (bus_add_driver+0x108/0x268) from [] (driver_register+0xa4/0x134) +[ 209.444426] [] (driver_register+0xa4/0x134) from [] (if_sdio_init_module+0x1c/0x3c [libertas_sdio]) +[ 209.455339] [] (if_sdio_init_module+0x1c/0x3c [libertas_sdio]) from [] (do_one_initcall+0x98/0x174) +[ 209.466236] [] (do_one_initcall+0x98/0x174) from [] (load_module+0x1c5c/0x1f80) +[ 209.475390] [] (load_module+0x1c5c/0x1f80) from [] (sys_init_module+0x104/0x128) +[ 209.484632] [] (sys_init_module+0x104/0x128) from [] (ret_fast_syscall+0x0/0x38) + +Fix it by setting fw_ready flag prior to queuing FUNC_INIT command. + +Reported-by: Lubomir Rintel +Tested-by: Lubomir Rintel +Signed-off-by: Bing Zhao +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/libertas/if_sdio.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/libertas/if_sdio.c ++++ b/drivers/net/wireless/libertas/if_sdio.c +@@ -825,6 +825,11 @@ static void if_sdio_finish_power_on(stru + + sdio_release_host(func); + ++ /* Set fw_ready before queuing any commands so that ++ * lbs_thread won't block from sending them to firmware. ++ */ ++ priv->fw_ready = 1; ++ + /* + * FUNC_INIT is required for SD8688 WLAN/BT multiple functions + */ +@@ -839,7 +844,6 @@ static void if_sdio_finish_power_on(stru + netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n"); + } + +- priv->fw_ready = 1; + wake_up(&card->pwron_waitq); + + if (!card->started) { diff --git a/queue-3.8/mwifiex-correct-sleep-delay-counter.patch b/queue-3.8/mwifiex-correct-sleep-delay-counter.patch new file mode 100644 index 00000000000..29b9ef099f7 --- /dev/null +++ b/queue-3.8/mwifiex-correct-sleep-delay-counter.patch @@ -0,0 +1,34 @@ +From 3e7a4ff7c5b6423ddb644df9c41b8b6d2fb79d30 Mon Sep 17 00:00:00 2001 +From: Avinash Patil +Date: Mon, 25 Feb 2013 16:01:34 -0800 +Subject: mwifiex: correct sleep delay counter + +From: Avinash Patil + +commit 3e7a4ff7c5b6423ddb644df9c41b8b6d2fb79d30 upstream. + +Maximum delay for waking up card is 50 ms. Because of typo in +counter, this delay goes to 500ms. This patch fixes the bug. + +Signed-off-by: Avinash Patil +Signed-off-by: Amitkumar Karwar +Signed-off-by: Yogesh Ashok Powar +Signed-off-by: Bing Zhao +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mwifiex/pcie.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/mwifiex/pcie.c ++++ b/drivers/net/wireless/mwifiex/pcie.c +@@ -291,7 +291,7 @@ static int mwifiex_pm_wakeup_card(struct + i++; + usleep_range(10, 20); + /* 50ms max wait */ +- if (i == 50000) ++ if (i == 5000) + break; + } + diff --git a/queue-3.8/series b/queue-3.8/series index 4e5dd74fec9..99482757d5d 100644 --- a/queue-3.8/series +++ b/queue-3.8/series @@ -27,3 +27,7 @@ nfs-don-t-allow-nfs-silly-renamed-files-to-be-deleted-no-signal.patch sunrpc-don-t-start-the-retransmission-timer-when-out-of-socket-space.patch pnfs-fix-resend_to_mds-for-directio.patch nfsv4.1-hold-reference-to-layout-hdr-in-layoutget.patch +hw_random-make-buffer-usable-in-scatterlist.patch +iwlwifi-always-copy-first-16-bytes-of-commands.patch +mwifiex-correct-sleep-delay-counter.patch +libertas-fix-crash-for-sd8688.patch