aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-05-13 14:57:40 -0400
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2011-05-13 15:00:41 -0400
commit4ce7cc2b09553a91d4aea014c39674685715173a (patch)
tree0a2e4b8ae8852a6404c479a7b605ae4b0af6b72d /drivers/net/wireless
parent4c42db0f04e55d48f0ea9f424144a5211b7a155c (diff)
iwlagn: support multiple TBs per command
The current "huge" command handling is a bit confusing, and very limited since only one command may be huge at a time. Additionally, we often copy data around quite pointlessly since we could instead map the existing scan buffer for example and use it directly. This patch makes that possible. The first change is that multiple buffers may be given to each command (this change was prepared earlier so callsites don't need to change). Each of those can be mapped attached to a TB in the TFD, and the command header can use a TB (the first one) in the TFD as well. Doing this allows getting rid of huge commands in favour of mapping existing buffers. The beacon transmission is also optimised to not copy the SKB at all but use multiple TBs. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-calib.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c28
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h46
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.h17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sv-open.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c231
8 files changed, 180 insertions, 152 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index 30e11c7c4144..d39efcce8ba7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
@@ -87,7 +87,6 @@ int iwl_send_calib_results(struct iwl_priv *priv)
87 87
88 struct iwl_host_cmd hcmd = { 88 struct iwl_host_cmd hcmd = {
89 .id = REPLY_PHY_CALIBRATION_CMD, 89 .id = REPLY_PHY_CALIBRATION_CMD,
90 .flags = CMD_SIZE_HUGE,
91 }; 90 };
92 91
93 for (i = 0; i < IWL_CALIB_MAX; i++) { 92 for (i = 0; i < IWL_CALIB_MAX; i++) {
@@ -95,6 +94,7 @@ int iwl_send_calib_results(struct iwl_priv *priv)
95 priv->calib_results[i].buf) { 94 priv->calib_results[i].buf) {
96 hcmd.len[0] = priv->calib_results[i].buf_len; 95 hcmd.len[0] = priv->calib_results[i].buf_len;
97 hcmd.data[0] = priv->calib_results[i].buf; 96 hcmd.data[0] = priv->calib_results[i].buf;
97 hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
98 ret = iwl_send_cmd_sync(priv, &hcmd); 98 ret = iwl_send_cmd_sync(priv, &hcmd);
99 if (ret) { 99 if (ret) {
100 IWL_ERR(priv, "Error %d iteration %d\n", 100 IWL_ERR(priv, "Error %d iteration %d\n",
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 576f45e9ab9f..f803fb62f8bc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -1141,7 +1141,6 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
1141 struct iwl_host_cmd cmd = { 1141 struct iwl_host_cmd cmd = {
1142 .id = REPLY_SCAN_CMD, 1142 .id = REPLY_SCAN_CMD,
1143 .len = { sizeof(struct iwl_scan_cmd), }, 1143 .len = { sizeof(struct iwl_scan_cmd), },
1144 .flags = CMD_SIZE_HUGE,
1145 }; 1144 };
1146 struct iwl_scan_cmd *scan; 1145 struct iwl_scan_cmd *scan;
1147 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; 1146 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
@@ -1428,6 +1427,7 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
1428 cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) + 1427 cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) +
1429 scan->channel_count * sizeof(struct iwl_scan_channel); 1428 scan->channel_count * sizeof(struct iwl_scan_channel);
1430 cmd.data[0] = scan; 1429 cmd.data[0] = scan;
1430 cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
1431 scan->len = cpu_to_le16(cmd.len[0]); 1431 scan->len = cpu_to_le16(cmd.len[0]);
1432 1432
1433 /* set scan bit here for PAN params */ 1433 /* set scan bit here for PAN params */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 2bb08d7e0674..675b9a644a0d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -134,12 +134,10 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
134 struct iwl_tx_beacon_cmd *tx_beacon_cmd; 134 struct iwl_tx_beacon_cmd *tx_beacon_cmd;
135 struct iwl_host_cmd cmd = { 135 struct iwl_host_cmd cmd = {
136 .id = REPLY_TX_BEACON, 136 .id = REPLY_TX_BEACON,
137 .flags = CMD_SIZE_HUGE,
138 }; 137 };
139 u32 frame_size; 138 u32 frame_size;
140 u32 rate_flags; 139 u32 rate_flags;
141 u32 rate; 140 u32 rate;
142 int err;
143 141
144 /* 142 /*
145 * We have to set up the TX command, the TX Beacon command, and the 143 * We have to set up the TX command, the TX Beacon command, and the
@@ -156,17 +154,15 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
156 if (WARN_ON(!priv->beacon_skb)) 154 if (WARN_ON(!priv->beacon_skb))
157 return -EINVAL; 155 return -EINVAL;
158 156
159 /* Allocate beacon memory */ 157 /* Allocate beacon command */
160 tx_beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd) + priv->beacon_skb->len, 158 if (!priv->beacon_cmd)
161 GFP_KERNEL); 159 priv->beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd), GFP_KERNEL);
160 tx_beacon_cmd = priv->beacon_cmd;
162 if (!tx_beacon_cmd) 161 if (!tx_beacon_cmd)
163 return -ENOMEM; 162 return -ENOMEM;
164 163
165 frame_size = priv->beacon_skb->len; 164 frame_size = priv->beacon_skb->len;
166 165
167 /* Set up TX beacon contents */
168 memcpy(tx_beacon_cmd->frame, priv->beacon_skb->data, frame_size);
169
170 /* Set up TX command fields */ 166 /* Set up TX command fields */
171 tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); 167 tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
172 tx_beacon_cmd->tx.sta_id = priv->beacon_ctx->bcast_sta_id; 168 tx_beacon_cmd->tx.sta_id = priv->beacon_ctx->bcast_sta_id;
@@ -175,7 +171,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
175 TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK; 171 TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
176 172
177 /* Set up TX beacon command fields */ 173 /* Set up TX beacon command fields */
178 iwl_set_beacon_tim(priv, tx_beacon_cmd, (u8 *)tx_beacon_cmd->frame, 174 iwl_set_beacon_tim(priv, tx_beacon_cmd, priv->beacon_skb->data,
179 frame_size); 175 frame_size);
180 176
181 /* Set up packet rate and flags */ 177 /* Set up packet rate and flags */
@@ -189,15 +185,14 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
189 rate_flags); 185 rate_flags);
190 186
191 /* Submit command */ 187 /* Submit command */
192 cmd.len[0] = sizeof(*tx_beacon_cmd) + frame_size; 188 cmd.len[0] = sizeof(*tx_beacon_cmd);
193 cmd.data[0] = tx_beacon_cmd; 189 cmd.data[0] = tx_beacon_cmd;
190 cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
191 cmd.len[1] = frame_size;
192 cmd.data[1] = priv->beacon_skb->data;
193 cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
194 194
195 err = iwl_send_cmd_sync(priv, &cmd); 195 return iwl_send_cmd_sync(priv, &cmd);
196
197 /* Free temporary storage */
198 kfree(tx_beacon_cmd);
199
200 return err;
201} 196}
202 197
203static void iwl_bg_beacon_update(struct work_struct *work) 198static void iwl_bg_beacon_update(struct work_struct *work)
@@ -3246,6 +3241,7 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
3246 iwlcore_free_geos(priv); 3241 iwlcore_free_geos(priv);
3247 iwl_free_channel_map(priv); 3242 iwl_free_channel_map(priv);
3248 kfree(priv->scan_cmd); 3243 kfree(priv->scan_cmd);
3244 kfree(priv->beacon_cmd);
3249} 3245}
3250 3246
3251struct ieee80211_ops iwlagn_hw_ops = { 3247struct ieee80211_ops iwlagn_hw_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 5fdad6532118..6ee5f1aa555c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -205,7 +205,6 @@ enum {
205#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) 205#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8)
206#define SEQ_TO_INDEX(s) ((s) & 0xff) 206#define SEQ_TO_INDEX(s) ((s) & 0xff)
207#define INDEX_TO_SEQ(i) ((i) & 0xff) 207#define INDEX_TO_SEQ(i) ((i) & 0xff)
208#define SEQ_HUGE_FRAME cpu_to_le16(0x4000)
209#define SEQ_RX_FRAME cpu_to_le16(0x8000) 208#define SEQ_RX_FRAME cpu_to_le16(0x8000)
210 209
211/** 210/**
@@ -234,9 +233,7 @@ struct iwl_cmd_header {
234 * 233 *
235 * 0:7 tfd index - position within TX queue 234 * 0:7 tfd index - position within TX queue
236 * 8:12 TX queue id 235 * 8:12 TX queue id
237 * 13 reserved 236 * 13:14 reserved
238 * 14 huge - driver sets this to indicate command is in the
239 * 'huge' storage at the end of the command buffers
240 * 15 unsolicited RX or uCode-originated notification 237 * 15 unsolicited RX or uCode-originated notification
241 */ 238 */
242 __le16 sequence; 239 __le16 sequence;
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 38254bdfabbb..3e3b8b8939d6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -110,8 +110,6 @@ struct iwl_cmd_meta {
110 struct iwl_device_cmd *cmd, 110 struct iwl_device_cmd *cmd,
111 struct iwl_rx_packet *pkt); 111 struct iwl_rx_packet *pkt);
112 112
113 /* The CMD_SIZE_HUGE flag bit indicates that the command
114 * structure is stored at the end of the shared queue memory. */
115 u32 flags; 113 u32 flags;
116 114
117 DEFINE_DMA_UNMAP_ADDR(mapping); 115 DEFINE_DMA_UNMAP_ADDR(mapping);
@@ -121,7 +119,23 @@ struct iwl_cmd_meta {
121/* 119/*
122 * Generic queue structure 120 * Generic queue structure
123 * 121 *
124 * Contains common data for Rx and Tx queues 122 * Contains common data for Rx and Tx queues.
123 *
124 * Note the difference between n_bd and n_window: the hardware
125 * always assumes 256 descriptors, so n_bd is always 256 (unless
126 * there might be HW changes in the future). For the normal TX
127 * queues, n_window, which is the size of the software queue data
128 * is also 256; however, for the command queue, n_window is only
129 * 32 since we don't need so many commands pending. Since the HW
130 * still uses 256 BDs for DMA though, n_bd stays 256. As a result,
131 * the software buffers (in the variables @meta, @txb in struct
132 * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds
133 * in the same struct) have 256.
134 * This means that we end up with the following:
135 * HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 |
136 * SW entries: | 0 | ... | 31 |
137 * where N is a number between 0 and 7. This means that the SW
138 * data is a window overlayed over the HW queue.
125 */ 139 */
126struct iwl_queue { 140struct iwl_queue {
127 int n_bd; /* number of BDs in this queue */ 141 int n_bd; /* number of BDs in this queue */
@@ -163,7 +177,7 @@ struct iwl_tx_info {
163 177
164struct iwl_tx_queue { 178struct iwl_tx_queue {
165 struct iwl_queue q; 179 struct iwl_queue q;
166 void *tfds; 180 struct iwl_tfd *tfds;
167 struct iwl_device_cmd **cmd; 181 struct iwl_device_cmd **cmd;
168 struct iwl_cmd_meta *meta; 182 struct iwl_cmd_meta *meta;
169 struct iwl_tx_info *txb; 183 struct iwl_tx_info *txb;
@@ -245,7 +259,6 @@ enum {
245 CMD_SYNC = 0, 259 CMD_SYNC = 0,
246 CMD_SIZE_NORMAL = 0, 260 CMD_SIZE_NORMAL = 0,
247 CMD_NO_SKB = 0, 261 CMD_NO_SKB = 0,
248 CMD_SIZE_HUGE = (1 << 0),
249 CMD_ASYNC = (1 << 1), 262 CMD_ASYNC = (1 << 1),
250 CMD_WANT_SKB = (1 << 2), 263 CMD_WANT_SKB = (1 << 2),
251 CMD_MAPPED = (1 << 3), 264 CMD_MAPPED = (1 << 3),
@@ -257,8 +270,8 @@ enum {
257 * struct iwl_device_cmd 270 * struct iwl_device_cmd
258 * 271 *
259 * For allocation of the command and tx queues, this establishes the overall 272 * For allocation of the command and tx queues, this establishes the overall
260 * size of the largest command we send to uCode, except for a scan command 273 * size of the largest command we send to uCode, except for commands that
261 * (which is relatively huge; space is allocated separately). 274 * aren't fully copied and use other TFD space.
262 */ 275 */
263struct iwl_device_cmd { 276struct iwl_device_cmd {
264 struct iwl_cmd_header hdr; /* uCode API */ 277 struct iwl_cmd_header hdr; /* uCode API */
@@ -275,7 +288,11 @@ struct iwl_device_cmd {
275 288
276#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) 289#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
277 290
278#define IWL_MAX_CMD_TFDS 1 291#define IWL_MAX_CMD_TFDS 2
292
293enum iwl_hcmd_dataflag {
294 IWL_HCMD_DFL_NOCOPY = BIT(0),
295};
279 296
280struct iwl_host_cmd { 297struct iwl_host_cmd {
281 const void *data[IWL_MAX_CMD_TFDS]; 298 const void *data[IWL_MAX_CMD_TFDS];
@@ -285,6 +302,7 @@ struct iwl_host_cmd {
285 struct iwl_rx_packet *pkt); 302 struct iwl_rx_packet *pkt);
286 u32 flags; 303 u32 flags;
287 u16 len[IWL_MAX_CMD_TFDS]; 304 u16 len[IWL_MAX_CMD_TFDS];
305 u8 dataflags[IWL_MAX_CMD_TFDS];
288 u8 id; 306 u8 id;
289}; 307};
290 308
@@ -687,17 +705,8 @@ static inline int iwl_queue_used(const struct iwl_queue *q, int i)
687} 705}
688 706
689 707
690static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) 708static inline u8 get_cmd_index(struct iwl_queue *q, u32 index)
691{ 709{
692 /*
693 * This is for init calibration result and scan command which
694 * required buffer > TFD_MAX_PAYLOAD_SIZE,
695 * the big buffer at end of command array
696 */
697 if (is_huge)
698 return q->n_window; /* must be power of 2 */
699
700 /* Otherwise, use normal size buffers */
701 return index & (q->n_window - 1); 710 return index & (q->n_window - 1);
702} 711}
703 712
@@ -1451,6 +1460,7 @@ struct iwl_priv {
1451 struct work_struct beacon_update; 1460 struct work_struct beacon_update;
1452 struct iwl_rxon_context *beacon_ctx; 1461 struct iwl_rxon_context *beacon_ctx;
1453 struct sk_buff *beacon_skb; 1462 struct sk_buff *beacon_skb;
1463 void *beacon_cmd;
1454 1464
1455 struct work_struct tt_work; 1465 struct work_struct tt_work;
1456 struct work_struct ct_enter; 1466 struct work_struct ct_enter;
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
index f00172cb8a6d..fc131867c10b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -137,20 +137,27 @@ TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
137#define TRACE_SYSTEM iwlwifi 137#define TRACE_SYSTEM iwlwifi
138 138
139TRACE_EVENT(iwlwifi_dev_hcmd, 139TRACE_EVENT(iwlwifi_dev_hcmd,
140 TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags), 140 TP_PROTO(struct iwl_priv *priv, u32 flags,
141 TP_ARGS(priv, hcmd, len, flags), 141 const void *hcmd0, size_t len0,
142 const void *hcmd1, size_t len1,
143 const void *hcmd2, size_t len2),
144 TP_ARGS(priv, flags, hcmd0, len0, hcmd1, len1, hcmd2, len2),
142 TP_STRUCT__entry( 145 TP_STRUCT__entry(
143 PRIV_ENTRY 146 PRIV_ENTRY
144 __dynamic_array(u8, hcmd, len) 147 __dynamic_array(u8, hcmd0, len0)
148 __dynamic_array(u8, hcmd1, len1)
149 __dynamic_array(u8, hcmd2, len2)
145 __field(u32, flags) 150 __field(u32, flags)
146 ), 151 ),
147 TP_fast_assign( 152 TP_fast_assign(
148 PRIV_ASSIGN; 153 PRIV_ASSIGN;
149 memcpy(__get_dynamic_array(hcmd), hcmd, len); 154 memcpy(__get_dynamic_array(hcmd0), hcmd0, len0);
155 memcpy(__get_dynamic_array(hcmd1), hcmd1, len1);
156 memcpy(__get_dynamic_array(hcmd2), hcmd2, len2);
150 __entry->flags = flags; 157 __entry->flags = flags;
151 ), 158 ),
152 TP_printk("[%p] hcmd %#.2x (%ssync)", 159 TP_printk("[%p] hcmd %#.2x (%ssync)",
153 __entry->priv, ((u8 *)__get_dynamic_array(hcmd))[0], 160 __entry->priv, ((u8 *)__get_dynamic_array(hcmd0))[0],
154 __entry->flags & CMD_ASYNC ? "a" : "") 161 __entry->flags & CMD_ASYNC ? "a" : "")
155); 162);
156 163
diff --git a/drivers/net/wireless/iwlwifi/iwl-sv-open.c b/drivers/net/wireless/iwlwifi/iwl-sv-open.c
index 01a8ec9cd6b2..dd2904aa9be2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sv-open.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sv-open.c
@@ -200,6 +200,7 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
200 cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]); 200 cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
201 cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); 201 cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
202 cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); 202 cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
203 cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
203 IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," 204 IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
204 " len %d\n", cmd.id, cmd.flags, cmd.len[0]); 205 " len %d\n", cmd.id, cmd.flags, cmd.len[0]);
205 /* ok, let's submit the command to ucode */ 206 /* ok, let's submit the command to ucode */
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index a47558f0ee3d..2f6b38cfcc13 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -125,25 +125,13 @@ static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
125 return tfd->num_tbs & 0x1f; 125 return tfd->num_tbs & 0x1f;
126} 126}
127 127
128/** 128static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta,
129 * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] 129 struct iwl_tfd *tfd)
130 * @priv - driver private data
131 * @txq - tx queue
132 *
133 * Does NOT advance any TFD circular buffer read/write indexes
134 * Does NOT free the TFD itself (which is within circular buffer)
135 */
136void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
137{ 130{
138 struct iwl_tfd *tfd_tmp = (struct iwl_tfd *)txq->tfds;
139 struct iwl_tfd *tfd;
140 struct pci_dev *dev = priv->pci_dev; 131 struct pci_dev *dev = priv->pci_dev;
141 int index = txq->q.read_ptr;
142 int i; 132 int i;
143 int num_tbs; 133 int num_tbs;
144 134
145 tfd = &tfd_tmp[index];
146
147 /* Sanity check on number of chunks */ 135 /* Sanity check on number of chunks */
148 num_tbs = iwl_tfd_get_num_tbs(tfd); 136 num_tbs = iwl_tfd_get_num_tbs(tfd);
149 137
@@ -156,14 +144,30 @@ void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
156 /* Unmap tx_cmd */ 144 /* Unmap tx_cmd */
157 if (num_tbs) 145 if (num_tbs)
158 pci_unmap_single(dev, 146 pci_unmap_single(dev,
159 dma_unmap_addr(&txq->meta[index], mapping), 147 dma_unmap_addr(meta, mapping),
160 dma_unmap_len(&txq->meta[index], len), 148 dma_unmap_len(meta, len),
161 PCI_DMA_BIDIRECTIONAL); 149 PCI_DMA_BIDIRECTIONAL);
162 150
163 /* Unmap chunks, if any. */ 151 /* Unmap chunks, if any. */
164 for (i = 1; i < num_tbs; i++) 152 for (i = 1; i < num_tbs; i++)
165 pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i), 153 pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
166 iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE); 154 iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
155}
156
157/**
158 * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
159 * @priv - driver private data
160 * @txq - tx queue
161 *
162 * Does NOT advance any TFD circular buffer read/write indexes
163 * Does NOT free the TFD itself (which is within circular buffer)
164 */
165void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
166{
167 struct iwl_tfd *tfd_tmp = txq->tfds;
168 int index = txq->q.read_ptr;
169
170 iwlagn_unmap_tfd(priv, &txq->meta[index], &tfd_tmp[index]);
167 171
168 /* free SKB */ 172 /* free SKB */
169 if (txq->txb) { 173 if (txq->txb) {
@@ -189,7 +193,7 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
189 u32 num_tbs; 193 u32 num_tbs;
190 194
191 q = &txq->q; 195 q = &txq->q;
192 tfd_tmp = (struct iwl_tfd *)txq->tfds; 196 tfd_tmp = txq->tfds;
193 tfd = &tfd_tmp[q->write_ptr]; 197 tfd = &tfd_tmp[q->write_ptr];
194 198
195 if (reset) 199 if (reset)
@@ -303,7 +307,7 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv)
303 return; 307 return;
304 308
305 while (q->read_ptr != q->write_ptr) { 309 while (q->read_ptr != q->write_ptr) {
306 i = get_cmd_index(q, q->read_ptr, 0); 310 i = get_cmd_index(q, q->read_ptr);
307 311
308 if (txq->meta[i].flags & CMD_MAPPED) { 312 if (txq->meta[i].flags & CMD_MAPPED) {
309 pci_unmap_single(priv->pci_dev, 313 pci_unmap_single(priv->pci_dev,
@@ -315,15 +319,6 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv)
315 319
316 q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); 320 q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
317 } 321 }
318
319 i = q->n_window;
320 if (txq->meta[i].flags & CMD_MAPPED) {
321 pci_unmap_single(priv->pci_dev,
322 dma_unmap_addr(&txq->meta[i], mapping),
323 dma_unmap_len(&txq->meta[i], len),
324 PCI_DMA_BIDIRECTIONAL);
325 txq->meta[i].flags = 0;
326 }
327} 322}
328 323
329/** 324/**
@@ -343,7 +338,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
343 iwl_cmd_queue_unmap(priv); 338 iwl_cmd_queue_unmap(priv);
344 339
345 /* De-alloc array of command/tx buffers */ 340 /* De-alloc array of command/tx buffers */
346 for (i = 0; i <= TFD_CMD_SLOTS; i++) 341 for (i = 0; i < TFD_CMD_SLOTS; i++)
347 kfree(txq->cmd[i]); 342 kfree(txq->cmd[i]);
348 343
349 /* De-alloc circular buffer of TFDs */ 344 /* De-alloc circular buffer of TFDs */
@@ -483,33 +478,17 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
483{ 478{
484 int i, len; 479 int i, len;
485 int ret; 480 int ret;
486 int actual_slots = slots_num;
487
488 /*
489 * Alloc buffer array for commands (Tx or other types of commands).
490 * For the command queue (#4/#9), allocate command space + one big
491 * command for scan, since scan command is very huge; the system will
492 * not have two scans at the same time, so only one is needed.
493 * For normal Tx queues (all other queues), no super-size command
494 * space is needed.
495 */
496 if (txq_id == priv->cmd_queue)
497 actual_slots++;
498 481
499 txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots, 482 txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * slots_num,
500 GFP_KERNEL); 483 GFP_KERNEL);
501 txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * actual_slots, 484 txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * slots_num,
502 GFP_KERNEL); 485 GFP_KERNEL);
503 486
504 if (!txq->meta || !txq->cmd) 487 if (!txq->meta || !txq->cmd)
505 goto out_free_arrays; 488 goto out_free_arrays;
506 489
507 len = sizeof(struct iwl_device_cmd); 490 len = sizeof(struct iwl_device_cmd);
508 for (i = 0; i < actual_slots; i++) { 491 for (i = 0; i < slots_num; i++) {
509 /* only happens for cmd queue */
510 if (i == slots_num)
511 len = IWL_MAX_CMD_SIZE;
512
513 txq->cmd[i] = kmalloc(len, GFP_KERNEL); 492 txq->cmd[i] = kmalloc(len, GFP_KERNEL);
514 if (!txq->cmd[i]) 493 if (!txq->cmd[i])
515 goto err; 494 goto err;
@@ -544,7 +523,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
544 523
545 return 0; 524 return 0;
546err: 525err:
547 for (i = 0; i < actual_slots; i++) 526 for (i = 0; i < slots_num; i++)
548 kfree(txq->cmd[i]); 527 kfree(txq->cmd[i]);
549out_free_arrays: 528out_free_arrays:
550 kfree(txq->meta); 529 kfree(txq->meta);
@@ -592,23 +571,44 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
592 dma_addr_t phys_addr; 571 dma_addr_t phys_addr;
593 unsigned long flags; 572 unsigned long flags;
594 u32 idx; 573 u32 idx;
595 u16 fix_size; 574 u16 copy_size, cmd_size;
596 bool is_ct_kill = false; 575 bool is_ct_kill = false;
576 bool had_nocopy = false;
577 int i;
578 u8 *cmd_dest;
579#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
580 const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {};
581 int trace_lens[IWL_MAX_CMD_TFDS + 1] = {};
582 int trace_idx;
583#endif
597 584
598 fix_size = (u16)(cmd->len[0] + sizeof(out_cmd->hdr)); 585 copy_size = sizeof(out_cmd->hdr);
586 cmd_size = sizeof(out_cmd->hdr);
587
588 /* need one for the header if the first is NOCOPY */
589 BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1);
590
591 for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
592 if (!cmd->len[i])
593 continue;
594 if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {
595 had_nocopy = true;
596 } else {
597 /* NOCOPY must not be followed by normal! */
598 if (WARN_ON(had_nocopy))
599 return -EINVAL;
600 copy_size += cmd->len[i];
601 }
602 cmd_size += cmd->len[i];
603 }
599 604
600 /* 605 /*
601 * If any of the command structures end up being larger than 606 * If any of the command structures end up being larger than
602 * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then 607 * the TFD_MAX_PAYLOAD_SIZE and they aren't dynamically
603 * we will need to increase the size of the TFD entries 608 * allocated into separate TFDs, then we will need to
604 * Also, check to see if command buffer should not exceed the size 609 * increase the size of the buffers.
605 * of device_cmd and max_cmd_size.
606 */ 610 */
607 if (WARN_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && 611 if (WARN_ON(copy_size > TFD_MAX_PAYLOAD_SIZE))
608 !(cmd->flags & CMD_SIZE_HUGE)))
609 return -EINVAL;
610
611 if (WARN_ON(fix_size > IWL_MAX_CMD_SIZE))
612 return -EINVAL; 612 return -EINVAL;
613 613
614 if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) { 614 if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
@@ -617,14 +617,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
617 return -EIO; 617 return -EIO;
618 } 618 }
619 619
620 /*
621 * As we only have a single huge buffer, check that the command
622 * is synchronous (otherwise buffers could end up being reused).
623 */
624
625 if (WARN_ON((cmd->flags & CMD_ASYNC) && (cmd->flags & CMD_SIZE_HUGE)))
626 return -EINVAL;
627
628 spin_lock_irqsave(&priv->hcmd_lock, flags); 620 spin_lock_irqsave(&priv->hcmd_lock, flags);
629 621
630 if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { 622 if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
@@ -639,7 +631,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
639 return -ENOSPC; 631 return -ENOSPC;
640 } 632 }
641 633
642 idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); 634 idx = get_cmd_index(q, q->write_ptr);
643 out_cmd = txq->cmd[idx]; 635 out_cmd = txq->cmd[idx];
644 out_meta = &txq->meta[idx]; 636 out_meta = &txq->meta[idx];
645 637
@@ -654,55 +646,84 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
654 if (cmd->flags & CMD_ASYNC) 646 if (cmd->flags & CMD_ASYNC)
655 out_meta->callback = cmd->callback; 647 out_meta->callback = cmd->callback;
656 648
657 out_cmd->hdr.cmd = cmd->id; 649 /* set up the header */
658 memcpy(&out_cmd->cmd.payload, cmd->data[0], cmd->len[0]);
659
660 /* At this point, the out_cmd now has all of the incoming cmd
661 * information */
662 650
651 out_cmd->hdr.cmd = cmd->id;
663 out_cmd->hdr.flags = 0; 652 out_cmd->hdr.flags = 0;
664 out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(priv->cmd_queue) | 653 out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(priv->cmd_queue) |
665 INDEX_TO_SEQ(q->write_ptr)); 654 INDEX_TO_SEQ(q->write_ptr));
666 if (cmd->flags & CMD_SIZE_HUGE) 655
667 out_cmd->hdr.sequence |= SEQ_HUGE_FRAME; 656 /* and copy the data that needs to be copied */
668 657
669#ifdef CONFIG_IWLWIFI_DEBUG 658 cmd_dest = &out_cmd->cmd.payload[0];
670 switch (out_cmd->hdr.cmd) { 659 for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
671 case REPLY_TX_LINK_QUALITY_CMD: 660 if (!cmd->len[i])
672 case SENSITIVITY_CMD: 661 continue;
673 IWL_DEBUG_HC_DUMP(priv, "Sending command %s (#%x), seq: 0x%04X, " 662 if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)
674 "%d bytes at %d[%d]:%d\n", 663 break;
675 get_cmd_string(out_cmd->hdr.cmd), 664 memcpy(cmd_dest, cmd->data[i], cmd->len[i]);
676 out_cmd->hdr.cmd, 665 cmd_dest += cmd->len[i];
677 le16_to_cpu(out_cmd->hdr.sequence), fix_size,
678 q->write_ptr, idx, priv->cmd_queue);
679 break;
680 default:
681 IWL_DEBUG_HC(priv, "Sending command %s (#%x), seq: 0x%04X, "
682 "%d bytes at %d[%d]:%d\n",
683 get_cmd_string(out_cmd->hdr.cmd),
684 out_cmd->hdr.cmd,
685 le16_to_cpu(out_cmd->hdr.sequence), fix_size,
686 q->write_ptr, idx, priv->cmd_queue);
687 } 666 }
688#endif 667
668 IWL_DEBUG_HC(priv, "Sending command %s (#%x), seq: 0x%04X, "
669 "%d bytes at %d[%d]:%d\n",
670 get_cmd_string(out_cmd->hdr.cmd),
671 out_cmd->hdr.cmd,
672 le16_to_cpu(out_cmd->hdr.sequence), cmd_size,
673 q->write_ptr, idx, priv->cmd_queue);
674
689 phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr, 675 phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
690 fix_size, PCI_DMA_BIDIRECTIONAL); 676 copy_size, PCI_DMA_BIDIRECTIONAL);
691 if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) { 677 if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) {
692 idx = -ENOMEM; 678 idx = -ENOMEM;
693 goto out; 679 goto out;
694 } 680 }
695 681
696 dma_unmap_addr_set(out_meta, mapping, phys_addr); 682 dma_unmap_addr_set(out_meta, mapping, phys_addr);
697 dma_unmap_len_set(out_meta, len, fix_size); 683 dma_unmap_len_set(out_meta, len, copy_size);
684
685 iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr, copy_size, 1);
686#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
687 trace_bufs[0] = &out_cmd->hdr;
688 trace_lens[0] = copy_size;
689 trace_idx = 1;
690#endif
691
692 for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
693 if (!cmd->len[i])
694 continue;
695 if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
696 continue;
697 phys_addr = pci_map_single(priv->pci_dev, (void *)cmd->data[i],
698 cmd->len[i], PCI_DMA_TODEVICE);
699 if (pci_dma_mapping_error(priv->pci_dev, phys_addr)) {
700 iwlagn_unmap_tfd(priv, out_meta,
701 &txq->tfds[q->write_ptr]);
702 idx = -ENOMEM;
703 goto out;
704 }
705
706 iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr,
707 cmd->len[i], 0);
708#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
709 trace_bufs[trace_idx] = cmd->data[i];
710 trace_lens[trace_idx] = cmd->len[i];
711 trace_idx++;
712#endif
713 }
698 714
699 out_meta->flags = cmd->flags | CMD_MAPPED; 715 out_meta->flags = cmd->flags | CMD_MAPPED;
700 716
701 txq->need_update = 1; 717 txq->need_update = 1;
702 718
703 trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags); 719 /* check that tracing gets all possible blocks */
704 720 BUILD_BUG_ON(IWL_MAX_CMD_TFDS + 1 != 3);
705 iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr, fix_size, 1); 721#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
722 trace_iwlwifi_dev_hcmd(priv, cmd->flags,
723 trace_bufs[0], trace_lens[0],
724 trace_bufs[1], trace_lens[1],
725 trace_bufs[2], trace_lens[2]);
726#endif
706 727
707 /* Increment and update queue's write index */ 728 /* Increment and update queue's write index */
708 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); 729 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
@@ -761,7 +782,6 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
761 int txq_id = SEQ_TO_QUEUE(sequence); 782 int txq_id = SEQ_TO_QUEUE(sequence);
762 int index = SEQ_TO_INDEX(sequence); 783 int index = SEQ_TO_INDEX(sequence);
763 int cmd_index; 784 int cmd_index;
764 bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
765 struct iwl_device_cmd *cmd; 785 struct iwl_device_cmd *cmd;
766 struct iwl_cmd_meta *meta; 786 struct iwl_cmd_meta *meta;
767 struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; 787 struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
@@ -779,14 +799,11 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
779 return; 799 return;
780 } 800 }
781 801
782 cmd_index = get_cmd_index(&txq->q, index, huge); 802 cmd_index = get_cmd_index(&txq->q, index);
783 cmd = txq->cmd[cmd_index]; 803 cmd = txq->cmd[cmd_index];
784 meta = &txq->meta[cmd_index]; 804 meta = &txq->meta[cmd_index];
785 805
786 pci_unmap_single(priv->pci_dev, 806 iwlagn_unmap_tfd(priv, meta, &txq->tfds[index]);
787 dma_unmap_addr(meta, mapping),
788 dma_unmap_len(meta, len),
789 PCI_DMA_BIDIRECTIONAL);
790 807
791 /* Input error checking is done when commands are added to queue. */ 808 /* Input error checking is done when commands are added to queue. */
792 if (meta->flags & CMD_WANT_SKB) { 809 if (meta->flags & CMD_WANT_SKB) {