aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-05-04 10:50:44 -0400
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2011-05-13 13:32:04 -0400
commit214d14d4d323aab5d455b409e279f9e1e6631123 (patch)
tree7bbdbedb41d551ed803262e3aad1ab36e0e607ba
parent3fa507386dc4cdf731344cb9361e9cca373cedb9 (diff)
iwlagn: clean up TXQ indirection
All of these functions no longer need to be accessed indirectly since they're shared in all AGN devices. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-2000.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ucode.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c149
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c160
10 files changed, 164 insertions, 203 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index b4c81931e136..61d4a11f566b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -171,10 +171,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
171 171
172static struct iwl_lib_ops iwl1000_lib = { 172static struct iwl_lib_ops iwl1000_lib = {
173 .set_hw_params = iwl1000_hw_set_hw_params, 173 .set_hw_params = iwl1000_hw_set_hw_params,
174 .txq_set_sched = iwlagn_txq_set_sched,
175 .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
176 .txq_free_tfd = iwl_hw_txq_free_tfd,
177 .txq_init = iwl_hw_tx_queue_init,
178 .rx_handler_setup = iwlagn_rx_handler_setup, 174 .rx_handler_setup = iwlagn_rx_handler_setup,
179 .setup_deferred_work = iwlagn_setup_deferred_work, 175 .setup_deferred_work = iwlagn_setup_deferred_work,
180 .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, 176 .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c
index 9f34cd7b6399..86feec86d130 100644
--- a/drivers/net/wireless/iwlwifi/iwl-2000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-2000.c
@@ -252,10 +252,6 @@ static int iwl2030_hw_channel_switch(struct iwl_priv *priv,
252 252
253static struct iwl_lib_ops iwl2000_lib = { 253static struct iwl_lib_ops iwl2000_lib = {
254 .set_hw_params = iwl2000_hw_set_hw_params, 254 .set_hw_params = iwl2000_hw_set_hw_params,
255 .txq_set_sched = iwlagn_txq_set_sched,
256 .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
257 .txq_free_tfd = iwl_hw_txq_free_tfd,
258 .txq_init = iwl_hw_tx_queue_init,
259 .rx_handler_setup = iwlagn_rx_handler_setup, 255 .rx_handler_setup = iwlagn_rx_handler_setup,
260 .setup_deferred_work = iwlagn_bt_setup_deferred_work, 256 .setup_deferred_work = iwlagn_bt_setup_deferred_work,
261 .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, 257 .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 09751f2386cb..a70b8cfafda1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -339,10 +339,6 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
339 339
340static struct iwl_lib_ops iwl5000_lib = { 340static struct iwl_lib_ops iwl5000_lib = {
341 .set_hw_params = iwl5000_hw_set_hw_params, 341 .set_hw_params = iwl5000_hw_set_hw_params,
342 .txq_set_sched = iwlagn_txq_set_sched,
343 .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
344 .txq_free_tfd = iwl_hw_txq_free_tfd,
345 .txq_init = iwl_hw_tx_queue_init,
346 .rx_handler_setup = iwlagn_rx_handler_setup, 342 .rx_handler_setup = iwlagn_rx_handler_setup,
347 .setup_deferred_work = iwlagn_setup_deferred_work, 343 .setup_deferred_work = iwlagn_setup_deferred_work,
348 .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, 344 .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
@@ -374,10 +370,6 @@ static struct iwl_lib_ops iwl5000_lib = {
374 370
375static struct iwl_lib_ops iwl5150_lib = { 371static struct iwl_lib_ops iwl5150_lib = {
376 .set_hw_params = iwl5150_hw_set_hw_params, 372 .set_hw_params = iwl5150_hw_set_hw_params,
377 .txq_set_sched = iwlagn_txq_set_sched,
378 .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
379 .txq_free_tfd = iwl_hw_txq_free_tfd,
380 .txq_init = iwl_hw_tx_queue_init,
381 .rx_handler_setup = iwlagn_rx_handler_setup, 373 .rx_handler_setup = iwlagn_rx_handler_setup,
382 .setup_deferred_work = iwlagn_setup_deferred_work, 374 .setup_deferred_work = iwlagn_setup_deferred_work,
383 .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, 375 .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 860c26e4836d..f8c710db6e6f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -278,10 +278,6 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
278 278
279static struct iwl_lib_ops iwl6000_lib = { 279static struct iwl_lib_ops iwl6000_lib = {
280 .set_hw_params = iwl6000_hw_set_hw_params, 280 .set_hw_params = iwl6000_hw_set_hw_params,
281 .txq_set_sched = iwlagn_txq_set_sched,
282 .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
283 .txq_free_tfd = iwl_hw_txq_free_tfd,
284 .txq_init = iwl_hw_tx_queue_init,
285 .rx_handler_setup = iwlagn_rx_handler_setup, 281 .rx_handler_setup = iwlagn_rx_handler_setup,
286 .setup_deferred_work = iwlagn_setup_deferred_work, 282 .setup_deferred_work = iwlagn_setup_deferred_work,
287 .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, 283 .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
@@ -314,10 +310,6 @@ static struct iwl_lib_ops iwl6000_lib = {
314 310
315static struct iwl_lib_ops iwl6030_lib = { 311static struct iwl_lib_ops iwl6030_lib = {
316 .set_hw_params = iwl6000_hw_set_hw_params, 312 .set_hw_params = iwl6000_hw_set_hw_params,
317 .txq_set_sched = iwlagn_txq_set_sched,
318 .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
319 .txq_free_tfd = iwl_hw_txq_free_tfd,
320 .txq_init = iwl_hw_tx_queue_init,
321 .rx_handler_setup = iwlagn_bt_rx_handler_setup, 313 .rx_handler_setup = iwlagn_bt_rx_handler_setup,
322 .setup_deferred_work = iwlagn_bt_setup_deferred_work, 314 .setup_deferred_work = iwlagn_bt_setup_deferred_work,
323 .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, 315 .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 7c1becf9e2c1..d34e103c71cf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -750,12 +750,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
750 spin_unlock(&priv->sta_lock); 750 spin_unlock(&priv->sta_lock);
751 751
752 /* Attach buffers to TFD */ 752 /* Attach buffers to TFD */
753 priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, 753 iwlagn_txq_attach_buf_to_tfd(priv, txq, txcmd_phys, firstlen, 1, 0);
754 txcmd_phys, firstlen, 1, 0);
755 if (secondlen > 0) 754 if (secondlen > 0)
756 priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, 755 iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr,
757 phys_addr, secondlen, 756 secondlen, 0, 0);
758 0, 0);
759 757
760 scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + 758 scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
761 offsetof(struct iwl_tx_cmd, scratch); 759 offsetof(struct iwl_tx_cmd, scratch);
@@ -911,7 +909,7 @@ int iwlagn_txq_ctx_alloc(struct iwl_priv *priv)
911 spin_lock_irqsave(&priv->lock, flags); 909 spin_lock_irqsave(&priv->lock, flags);
912 910
913 /* Turn off all Tx DMA fifos */ 911 /* Turn off all Tx DMA fifos */
914 priv->cfg->ops->lib->txq_set_sched(priv, 0); 912 iwlagn_txq_set_sched(priv, 0);
915 913
916 /* Tell NIC where to find the "keep warm" buffer */ 914 /* Tell NIC where to find the "keep warm" buffer */
917 iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); 915 iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
@@ -949,7 +947,7 @@ void iwlagn_txq_ctx_reset(struct iwl_priv *priv)
949 spin_lock_irqsave(&priv->lock, flags); 947 spin_lock_irqsave(&priv->lock, flags);
950 948
951 /* Turn off all Tx DMA fifos */ 949 /* Turn off all Tx DMA fifos */
952 priv->cfg->ops->lib->txq_set_sched(priv, 0); 950 iwlagn_txq_set_sched(priv, 0);
953 951
954 /* Tell NIC where to find the "keep warm" buffer */ 952 /* Tell NIC where to find the "keep warm" buffer */
955 iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); 953 iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
@@ -975,7 +973,7 @@ void iwlagn_txq_ctx_stop(struct iwl_priv *priv)
975 /* Turn off all Tx DMA fifos */ 973 /* Turn off all Tx DMA fifos */
976 spin_lock_irqsave(&priv->lock, flags); 974 spin_lock_irqsave(&priv->lock, flags);
977 975
978 priv->cfg->ops->lib->txq_set_sched(priv, 0); 976 iwlagn_txq_set_sched(priv, 0);
979 977
980 /* Stop each Tx DMA channel, and wait for it to be idle */ 978 /* Stop each Tx DMA channel, and wait for it to be idle */
981 for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) { 979 for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
@@ -1258,7 +1256,7 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
1258 1256
1259 iwlagn_txq_inval_byte_cnt_tbl(priv, txq); 1257 iwlagn_txq_inval_byte_cnt_tbl(priv, txq);
1260 1258
1261 priv->cfg->ops->lib->txq_free_tfd(priv, txq); 1259 iwlagn_txq_free_tfd(priv, txq);
1262 } 1260 }
1263 return nfreed; 1261 return nfreed;
1264} 1262}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index e35755c577db..97de5d9de67b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -440,7 +440,7 @@ static int iwlagn_alive_notify(struct iwl_priv *priv)
440 IWL_MASK(0, priv->hw_params.max_txq_num)); 440 IWL_MASK(0, priv->hw_params.max_txq_num));
441 441
442 /* Activate all Tx DMA/FIFO channels */ 442 /* Activate all Tx DMA/FIFO channels */
443 priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7)); 443 iwlagn_txq_set_sched(priv, IWL_MASK(0, 7));
444 444
445 /* map queues to FIFOs */ 445 /* map queues to FIFOs */
446 if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) 446 if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 2713081ed996..2bb08d7e0674 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -200,155 +200,6 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
200 return err; 200 return err;
201} 201}
202 202
203static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
204{
205 struct iwl_tfd_tb *tb = &tfd->tbs[idx];
206
207 dma_addr_t addr = get_unaligned_le32(&tb->lo);
208 if (sizeof(dma_addr_t) > sizeof(u32))
209 addr |=
210 ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16;
211
212 return addr;
213}
214
215static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
216{
217 struct iwl_tfd_tb *tb = &tfd->tbs[idx];
218
219 return le16_to_cpu(tb->hi_n_len) >> 4;
220}
221
222static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
223 dma_addr_t addr, u16 len)
224{
225 struct iwl_tfd_tb *tb = &tfd->tbs[idx];
226 u16 hi_n_len = len << 4;
227
228 put_unaligned_le32(addr, &tb->lo);
229 if (sizeof(dma_addr_t) > sizeof(u32))
230 hi_n_len |= ((addr >> 16) >> 16) & 0xF;
231
232 tb->hi_n_len = cpu_to_le16(hi_n_len);
233
234 tfd->num_tbs = idx + 1;
235}
236
237static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
238{
239 return tfd->num_tbs & 0x1f;
240}
241
242/**
243 * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
244 * @priv - driver private data
245 * @txq - tx queue
246 *
247 * Does NOT advance any TFD circular buffer read/write indexes
248 * Does NOT free the TFD itself (which is within circular buffer)
249 */
250void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
251{
252 struct iwl_tfd *tfd_tmp = (struct iwl_tfd *)txq->tfds;
253 struct iwl_tfd *tfd;
254 struct pci_dev *dev = priv->pci_dev;
255 int index = txq->q.read_ptr;
256 int i;
257 int num_tbs;
258
259 tfd = &tfd_tmp[index];
260
261 /* Sanity check on number of chunks */
262 num_tbs = iwl_tfd_get_num_tbs(tfd);
263
264 if (num_tbs >= IWL_NUM_OF_TBS) {
265 IWL_ERR(priv, "Too many chunks: %i\n", num_tbs);
266 /* @todo issue fatal error, it is quite serious situation */
267 return;
268 }
269
270 /* Unmap tx_cmd */
271 if (num_tbs)
272 pci_unmap_single(dev,
273 dma_unmap_addr(&txq->meta[index], mapping),
274 dma_unmap_len(&txq->meta[index], len),
275 PCI_DMA_BIDIRECTIONAL);
276
277 /* Unmap chunks, if any. */
278 for (i = 1; i < num_tbs; i++)
279 pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
280 iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
281
282 /* free SKB */
283 if (txq->txb) {
284 struct sk_buff *skb;
285
286 skb = txq->txb[txq->q.read_ptr].skb;
287
288 /* can be called from irqs-disabled context */
289 if (skb) {
290 dev_kfree_skb_any(skb);
291 txq->txb[txq->q.read_ptr].skb = NULL;
292 }
293 }
294}
295
296int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
297 struct iwl_tx_queue *txq,
298 dma_addr_t addr, u16 len,
299 u8 reset, u8 pad)
300{
301 struct iwl_queue *q;
302 struct iwl_tfd *tfd, *tfd_tmp;
303 u32 num_tbs;
304
305 q = &txq->q;
306 tfd_tmp = (struct iwl_tfd *)txq->tfds;
307 tfd = &tfd_tmp[q->write_ptr];
308
309 if (reset)
310 memset(tfd, 0, sizeof(*tfd));
311
312 num_tbs = iwl_tfd_get_num_tbs(tfd);
313
314 /* Each TFD can point to a maximum 20 Tx buffers */
315 if (num_tbs >= IWL_NUM_OF_TBS) {
316 IWL_ERR(priv, "Error can not send more than %d chunks\n",
317 IWL_NUM_OF_TBS);
318 return -EINVAL;
319 }
320
321 if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
322 return -EINVAL;
323
324 if (unlikely(addr & ~IWL_TX_DMA_MASK))
325 IWL_ERR(priv, "Unaligned address = %llx\n",
326 (unsigned long long)addr);
327
328 iwl_tfd_set_tb(tfd, num_tbs, addr, len);
329
330 return 0;
331}
332
333/*
334 * Tell nic where to find circular buffer of Tx Frame Descriptors for
335 * given Tx queue, and enable the DMA channel used for that queue.
336 *
337 * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
338 * channels supported in hardware.
339 */
340int iwl_hw_tx_queue_init(struct iwl_priv *priv,
341 struct iwl_tx_queue *txq)
342{
343 int txq_id = txq->q.id;
344
345 /* Circular buffer (TFD queue in DRAM) physical base address */
346 iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
347 txq->q.dma_addr >> 8);
348
349 return 0;
350}
351
352static void iwl_bg_beacon_update(struct work_struct *work) 203static void iwl_bg_beacon_update(struct work_struct *work)
353{ 204{
354 struct iwl_priv *priv = 205 struct iwl_priv *priv =
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index fe33fe8aa418..269e0c47927b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -191,12 +191,10 @@ int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
191void iwl_setup_rx_handlers(struct iwl_priv *priv); 191void iwl_setup_rx_handlers(struct iwl_priv *priv);
192 192
193/* tx */ 193/* tx */
194void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); 194void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
195int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, 195int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
196 struct iwl_tx_queue *txq, 196 struct iwl_tx_queue *txq,
197 dma_addr_t addr, u16 len, u8 reset, u8 pad); 197 dma_addr_t addr, u16 len, u8 reset, u8 pad);
198int iwl_hw_tx_queue_init(struct iwl_priv *priv,
199 struct iwl_tx_queue *txq);
200void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, 198void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
201 struct ieee80211_tx_info *info); 199 struct ieee80211_tx_info *info);
202int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); 200int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 5b5b0cce4a54..3bb76f6ea410 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -127,16 +127,6 @@ struct iwl_temp_ops {
127struct iwl_lib_ops { 127struct iwl_lib_ops {
128 /* set hw dependent parameters */ 128 /* set hw dependent parameters */
129 int (*set_hw_params)(struct iwl_priv *priv); 129 int (*set_hw_params)(struct iwl_priv *priv);
130 /* Handling TX */
131 void (*txq_set_sched)(struct iwl_priv *priv, u32 mask);
132 int (*txq_attach_buf_to_tfd)(struct iwl_priv *priv,
133 struct iwl_tx_queue *txq,
134 dma_addr_t addr,
135 u16 len, u8 reset, u8 pad);
136 void (*txq_free_tfd)(struct iwl_priv *priv,
137 struct iwl_tx_queue *txq);
138 int (*txq_init)(struct iwl_priv *priv,
139 struct iwl_tx_queue *txq);
140 /* setup Rx handler */ 130 /* setup Rx handler */
141 void (*rx_handler_setup)(struct iwl_priv *priv); 131 void (*rx_handler_setup)(struct iwl_priv *priv);
142 /* setup deferred work */ 132 /* setup deferred work */
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 7843195efb05..302284bef961 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -32,6 +32,7 @@
32#include <linux/slab.h> 32#include <linux/slab.h>
33#include <net/mac80211.h> 33#include <net/mac80211.h>
34#include "iwl-eeprom.h" 34#include "iwl-eeprom.h"
35#include "iwl-agn.h"
35#include "iwl-dev.h" 36#include "iwl-dev.h"
36#include "iwl-core.h" 37#include "iwl-core.h"
37#include "iwl-sta.h" 38#include "iwl-sta.h"
@@ -85,6 +86,154 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
85 txq->need_update = 0; 86 txq->need_update = 0;
86} 87}
87 88
89static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
90{
91 struct iwl_tfd_tb *tb = &tfd->tbs[idx];
92
93 dma_addr_t addr = get_unaligned_le32(&tb->lo);
94 if (sizeof(dma_addr_t) > sizeof(u32))
95 addr |=
96 ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16;
97
98 return addr;
99}
100
101static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
102{
103 struct iwl_tfd_tb *tb = &tfd->tbs[idx];
104
105 return le16_to_cpu(tb->hi_n_len) >> 4;
106}
107
108static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
109 dma_addr_t addr, u16 len)
110{
111 struct iwl_tfd_tb *tb = &tfd->tbs[idx];
112 u16 hi_n_len = len << 4;
113
114 put_unaligned_le32(addr, &tb->lo);
115 if (sizeof(dma_addr_t) > sizeof(u32))
116 hi_n_len |= ((addr >> 16) >> 16) & 0xF;
117
118 tb->hi_n_len = cpu_to_le16(hi_n_len);
119
120 tfd->num_tbs = idx + 1;
121}
122
123static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
124{
125 return tfd->num_tbs & 0x1f;
126}
127
128/**
129 * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
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{
138 struct iwl_tfd *tfd_tmp = (struct iwl_tfd *)txq->tfds;
139 struct iwl_tfd *tfd;
140 struct pci_dev *dev = priv->pci_dev;
141 int index = txq->q.read_ptr;
142 int i;
143 int num_tbs;
144
145 tfd = &tfd_tmp[index];
146
147 /* Sanity check on number of chunks */
148 num_tbs = iwl_tfd_get_num_tbs(tfd);
149
150 if (num_tbs >= IWL_NUM_OF_TBS) {
151 IWL_ERR(priv, "Too many chunks: %i\n", num_tbs);
152 /* @todo issue fatal error, it is quite serious situation */
153 return;
154 }
155
156 /* Unmap tx_cmd */
157 if (num_tbs)
158 pci_unmap_single(dev,
159 dma_unmap_addr(&txq->meta[index], mapping),
160 dma_unmap_len(&txq->meta[index], len),
161 PCI_DMA_BIDIRECTIONAL);
162
163 /* Unmap chunks, if any. */
164 for (i = 1; i < num_tbs; i++)
165 pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
166 iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
167
168 /* free SKB */
169 if (txq->txb) {
170 struct sk_buff *skb;
171
172 skb = txq->txb[txq->q.read_ptr].skb;
173
174 /* can be called from irqs-disabled context */
175 if (skb) {
176 dev_kfree_skb_any(skb);
177 txq->txb[txq->q.read_ptr].skb = NULL;
178 }
179 }
180}
181
182int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
183 struct iwl_tx_queue *txq,
184 dma_addr_t addr, u16 len,
185 u8 reset, u8 pad)
186{
187 struct iwl_queue *q;
188 struct iwl_tfd *tfd, *tfd_tmp;
189 u32 num_tbs;
190
191 q = &txq->q;
192 tfd_tmp = (struct iwl_tfd *)txq->tfds;
193 tfd = &tfd_tmp[q->write_ptr];
194
195 if (reset)
196 memset(tfd, 0, sizeof(*tfd));
197
198 num_tbs = iwl_tfd_get_num_tbs(tfd);
199
200 /* Each TFD can point to a maximum 20 Tx buffers */
201 if (num_tbs >= IWL_NUM_OF_TBS) {
202 IWL_ERR(priv, "Error can not send more than %d chunks\n",
203 IWL_NUM_OF_TBS);
204 return -EINVAL;
205 }
206
207 if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
208 return -EINVAL;
209
210 if (unlikely(addr & ~IWL_TX_DMA_MASK))
211 IWL_ERR(priv, "Unaligned address = %llx\n",
212 (unsigned long long)addr);
213
214 iwl_tfd_set_tb(tfd, num_tbs, addr, len);
215
216 return 0;
217}
218
219/*
220 * Tell nic where to find circular buffer of Tx Frame Descriptors for
221 * given Tx queue, and enable the DMA channel used for that queue.
222 *
223 * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
224 * channels supported in hardware.
225 */
226static int iwlagn_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
227{
228 int txq_id = txq->q.id;
229
230 /* Circular buffer (TFD queue in DRAM) physical base address */
231 iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
232 txq->q.dma_addr >> 8);
233
234 return 0;
235}
236
88/** 237/**
89 * iwl_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's 238 * iwl_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's
90 */ 239 */
@@ -97,7 +246,7 @@ void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id)
97 return; 246 return;
98 247
99 while (q->write_ptr != q->read_ptr) { 248 while (q->write_ptr != q->read_ptr) {
100 priv->cfg->ops->lib->txq_free_tfd(priv, txq); 249 iwlagn_txq_free_tfd(priv, txq);
101 q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); 250 q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
102 } 251 }
103} 252}
@@ -391,7 +540,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
391 return ret; 540 return ret;
392 541
393 /* Tell device where to find queue */ 542 /* Tell device where to find queue */
394 priv->cfg->ops->lib->txq_init(priv, txq); 543 iwlagn_tx_queue_init(priv, txq);
395 544
396 return 0; 545 return 0;
397err: 546err:
@@ -420,7 +569,7 @@ void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
420 iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); 569 iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
421 570
422 /* Tell device where to find queue */ 571 /* Tell device where to find queue */
423 priv->cfg->ops->lib->txq_init(priv, txq); 572 iwlagn_tx_queue_init(priv, txq);
424} 573}
425 574
426/*************** HOST COMMAND QUEUE FUNCTIONS *****/ 575/*************** HOST COMMAND QUEUE FUNCTIONS *****/
@@ -553,9 +702,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
553 702
554 trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags); 703 trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags);
555 704
556 priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, 705 iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr, fix_size, 1,
557 phys_addr, fix_size, 1, 706 U32_PAD(cmd->len[0]));
558 U32_PAD(cmd->len[0]));
559 707
560 /* Increment and update queue's write index */ 708 /* Increment and update queue's write index */
561 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); 709 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);