]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.8-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 6 Mar 2013 04:53:30 +0000 (12:53 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 6 Mar 2013 04:53:30 +0000 (12:53 +0800)
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

queue-3.8/hw_random-make-buffer-usable-in-scatterlist.patch [new file with mode: 0644]
queue-3.8/iwlwifi-always-copy-first-16-bytes-of-commands.patch [new file with mode: 0644]
queue-3.8/libertas-fix-crash-for-sd8688.patch [new file with mode: 0644]
queue-3.8/mwifiex-correct-sleep-delay-counter.patch [new file with mode: 0644]
queue-3.8/series

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 (file)
index 0000000..1f537b9
--- /dev/null
@@ -0,0 +1,75 @@
+From f7f154f1246ccc5a0a7e9ce50932627d60a0c878 Mon Sep 17 00:00:00 2001
+From: Rusty Russell <rusty@rustcorp.com.au>
+Date: Tue, 5 Mar 2013 10:07:08 +1030
+Subject: hw_random: make buffer usable in scatterlist.
+
+From: Rusty Russell <rusty@rustcorp.com.au>
+
+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 <aurelien@aurel32.net>
+Tested-by: Aurelien Jarno <aurelien@aurel32.net>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 <linux/init.h>
+ #include <linux/miscdevice.h>
+ #include <linux/delay.h>
++#include <linux/slab.h>
+ #include <asm/uaccess.h>
+@@ -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 (file)
index 0000000..33fa531
--- /dev/null
@@ -0,0 +1,241 @@
+From 8a964f44e01ad3bbc208c3e80d931ba91b9ea786 Mon Sep 17 00:00:00 2001
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Mon, 25 Feb 2013 16:01:34 +0100
+Subject: iwlwifi: always copy first 16 bytes of commands
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+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 <emmanuel.grumbach@intel.com>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..c9ec2fc
--- /dev/null
@@ -0,0 +1,63 @@
+From 466026989f112e0546ca39ab00a759af82dbe83a Mon Sep 17 00:00:00 2001
+From: Bing Zhao <bzhao@marvell.com>
+Date: Tue, 26 Feb 2013 12:58:35 -0800
+Subject: libertas: fix crash for SD8688
+
+From: Bing Zhao <bzhao@marvell.com>
+
+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] [<c0502248>] (__schedule+0x610/0x764) from [<bf20ae24>] (__lbs_cmd+0xb8/0x130 [libertas])
+[  209.348340] [<bf20ae24>] (__lbs_cmd+0xb8/0x130 [libertas]) from [<bf222474>] (if_sdio_finish_power_on+0xec/0x1b0 [libertas_sdio])
+[  209.360136] [<bf222474>] (if_sdio_finish_power_on+0xec/0x1b0 [libertas_sdio]) from [<bf2226c4>] (if_sdio_power_on+0x18c/0x20c [libertas_sdio])
+[  209.373052] [<bf2226c4>] (if_sdio_power_on+0x18c/0x20c [libertas_sdio]) from [<bf222944>] (if_sdio_probe+0x200/0x31c [libertas_sdio])
+[  209.385316] [<bf222944>] (if_sdio_probe+0x200/0x31c [libertas_sdio]) from [<bf01d820>] (sdio_bus_probe+0x94/0xfc [mmc_core])
+[  209.396748] [<bf01d820>] (sdio_bus_probe+0x94/0xfc [mmc_core]) from [<c02e729c>] (driver_probe_device+0x12c/0x348)
+[  209.407214] [<c02e729c>] (driver_probe_device+0x12c/0x348) from [<c02e7530>] (__driver_attach+0x78/0x9c)
+[  209.416798] [<c02e7530>] (__driver_attach+0x78/0x9c) from [<c02e5658>] (bus_for_each_dev+0x50/0x88)
+[  209.425946] [<c02e5658>] (bus_for_each_dev+0x50/0x88) from [<c02e6810>] (bus_add_driver+0x108/0x268)
+[  209.435180] [<c02e6810>] (bus_add_driver+0x108/0x268) from [<c02e782c>] (driver_register+0xa4/0x134)
+[  209.444426] [<c02e782c>] (driver_register+0xa4/0x134) from [<bf22601c>] (if_sdio_init_module+0x1c/0x3c [libertas_sdio])
+[  209.455339] [<bf22601c>] (if_sdio_init_module+0x1c/0x3c [libertas_sdio]) from [<c00085b8>] (do_one_initcall+0x98/0x174)
+[  209.466236] [<c00085b8>] (do_one_initcall+0x98/0x174) from [<c0076504>] (load_module+0x1c5c/0x1f80)
+[  209.475390] [<c0076504>] (load_module+0x1c5c/0x1f80) from [<c007692c>] (sys_init_module+0x104/0x128)
+[  209.484632] [<c007692c>] (sys_init_module+0x104/0x128) from [<c0008c40>] (ret_fast_syscall+0x0/0x38)
+
+Fix it by setting fw_ready flag prior to queuing FUNC_INIT command.
+
+Reported-by: Lubomir Rintel <lkundrak@v3.sk>
+Tested-by: Lubomir Rintel <lkundrak@v3.sk>
+Signed-off-by: Bing Zhao <bzhao@marvell.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..29b9ef0
--- /dev/null
@@ -0,0 +1,34 @@
+From 3e7a4ff7c5b6423ddb644df9c41b8b6d2fb79d30 Mon Sep 17 00:00:00 2001
+From: Avinash Patil <patila@marvell.com>
+Date: Mon, 25 Feb 2013 16:01:34 -0800
+Subject: mwifiex: correct sleep delay counter
+
+From: Avinash Patil <patila@marvell.com>
+
+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 <patila@marvell.com>
+Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
+Signed-off-by: Yogesh Ashok Powar <yogeshp@marvell.com>
+Signed-off-by: Bing Zhao <bzhao@marvell.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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;
+       }
index 4e5dd74fec97b89936b49b31b2f44928cb26b1c5..99482757d5d6c60c521b23ba3bdaec2959958de4 100644 (file)
@@ -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