diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-3945.c | 28 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-3945.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-5000.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 120 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-tx.c | 134 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 34 |
8 files changed, 176 insertions, 163 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index e6d4503cd213..18e0f0e3a74f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -318,7 +318,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv, | |||
318 | tx_info = &txq->txb[txq->q.read_ptr]; | 318 | tx_info = &txq->txb[txq->q.read_ptr]; |
319 | ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); | 319 | ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); |
320 | tx_info->skb[0] = NULL; | 320 | tx_info->skb[0] = NULL; |
321 | iwl3945_hw_txq_free_tfd(priv, txq); | 321 | priv->cfg->ops->lib->txq_free_tfd(priv, txq); |
322 | } | 322 | } |
323 | 323 | ||
324 | if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) && | 324 | if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) && |
@@ -724,15 +724,21 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, | |||
724 | iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); | 724 | iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); |
725 | } | 725 | } |
726 | 726 | ||
727 | int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, | 727 | int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, |
728 | dma_addr_t addr, u16 len) | 728 | struct iwl_tx_queue *txq, |
729 | dma_addr_t addr, u16 len, u8 reset, u8 pad) | ||
729 | { | 730 | { |
730 | int count; | 731 | int count; |
731 | u32 pad; | 732 | struct iwl_queue *q; |
732 | struct iwl3945_tfd *tfd = (struct iwl3945_tfd *)ptr; | 733 | struct iwl3945_tfd *tfd; |
734 | |||
735 | q = &txq->q; | ||
736 | tfd = &txq->tfds39[q->write_ptr]; | ||
737 | |||
738 | if (reset) | ||
739 | memset(tfd, 0, sizeof(*tfd)); | ||
733 | 740 | ||
734 | count = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags)); | 741 | count = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags)); |
735 | pad = TFD_CTL_PAD_GET(le32_to_cpu(tfd->control_flags)); | ||
736 | 742 | ||
737 | if ((count >= NUM_TFD_CHUNKS) || (count < 0)) { | 743 | if ((count >= NUM_TFD_CHUNKS) || (count < 0)) { |
738 | IWL_ERR(priv, "Error can not send more than %d chunks\n", | 744 | IWL_ERR(priv, "Error can not send more than %d chunks\n", |
@@ -756,7 +762,7 @@ int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, | |||
756 | * | 762 | * |
757 | * Does NOT advance any indexes | 763 | * Does NOT advance any indexes |
758 | */ | 764 | */ |
759 | int iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) | 765 | void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) |
760 | { | 766 | { |
761 | struct iwl3945_tfd *tfd_tmp = (struct iwl3945_tfd *)&txq->tfds39[0]; | 767 | struct iwl3945_tfd *tfd_tmp = (struct iwl3945_tfd *)&txq->tfds39[0]; |
762 | struct iwl3945_tfd *tfd = &tfd_tmp[txq->q.read_ptr]; | 768 | struct iwl3945_tfd *tfd = &tfd_tmp[txq->q.read_ptr]; |
@@ -767,14 +773,14 @@ int iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) | |||
767 | /* classify bd */ | 773 | /* classify bd */ |
768 | if (txq->q.id == IWL_CMD_QUEUE_NUM) | 774 | if (txq->q.id == IWL_CMD_QUEUE_NUM) |
769 | /* nothing to cleanup after for host commands */ | 775 | /* nothing to cleanup after for host commands */ |
770 | return 0; | 776 | return; |
771 | 777 | ||
772 | /* sanity check */ | 778 | /* sanity check */ |
773 | counter = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags)); | 779 | counter = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags)); |
774 | if (counter > NUM_TFD_CHUNKS) { | 780 | if (counter > NUM_TFD_CHUNKS) { |
775 | IWL_ERR(priv, "Too many chunks: %i\n", counter); | 781 | IWL_ERR(priv, "Too many chunks: %i\n", counter); |
776 | /* @todo issue fatal error, it is quite serious situation */ | 782 | /* @todo issue fatal error, it is quite serious situation */ |
777 | return 0; | 783 | return; |
778 | } | 784 | } |
779 | 785 | ||
780 | /* unmap chunks if any */ | 786 | /* unmap chunks if any */ |
@@ -791,7 +797,7 @@ int iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) | |||
791 | } | 797 | } |
792 | } | 798 | } |
793 | } | 799 | } |
794 | return 0; | 800 | return ; |
795 | } | 801 | } |
796 | 802 | ||
797 | u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *addr) | 803 | u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *addr) |
@@ -2697,6 +2703,8 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) | |||
2697 | } | 2703 | } |
2698 | 2704 | ||
2699 | static struct iwl_lib_ops iwl3945_lib = { | 2705 | static struct iwl_lib_ops iwl3945_lib = { |
2706 | .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd, | ||
2707 | .txq_free_tfd = iwl3945_hw_txq_free_tfd, | ||
2700 | .load_ucode = iwl3945_load_bsm, | 2708 | .load_ucode = iwl3945_load_bsm, |
2701 | .apm_ops = { | 2709 | .apm_ops = { |
2702 | .init = iwl3945_apm_init, | 2710 | .init = iwl3945_apm_init, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 97dfa7c5a3ce..54538df50d3e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h | |||
@@ -260,9 +260,12 @@ extern int iwl3945_hw_nic_stop_master(struct iwl_priv *priv); | |||
260 | extern void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv); | 260 | extern void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv); |
261 | extern void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv); | 261 | extern void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv); |
262 | extern int iwl3945_hw_nic_reset(struct iwl_priv *priv); | 262 | extern int iwl3945_hw_nic_reset(struct iwl_priv *priv); |
263 | extern int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, | 263 | extern int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, |
264 | dma_addr_t addr, u16 len); | 264 | struct iwl_tx_queue *txq, |
265 | extern int iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); | 265 | dma_addr_t addr, u16 len, |
266 | u8 reset, u8 pad); | ||
267 | extern void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, | ||
268 | struct iwl_tx_queue *txq); | ||
266 | extern int iwl3945_hw_get_temperature(struct iwl_priv *priv); | 269 | extern int iwl3945_hw_get_temperature(struct iwl_priv *priv); |
267 | extern int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, | 270 | extern int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, |
268 | struct iwl_tx_queue *txq); | 271 | struct iwl_tx_queue *txq); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 6171ba533f2e..31315decc07d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -2295,6 +2295,8 @@ static struct iwl_lib_ops iwl4965_lib = { | |||
2295 | .txq_set_sched = iwl4965_txq_set_sched, | 2295 | .txq_set_sched = iwl4965_txq_set_sched, |
2296 | .txq_agg_enable = iwl4965_txq_agg_enable, | 2296 | .txq_agg_enable = iwl4965_txq_agg_enable, |
2297 | .txq_agg_disable = iwl4965_txq_agg_disable, | 2297 | .txq_agg_disable = iwl4965_txq_agg_disable, |
2298 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, | ||
2299 | .txq_free_tfd = iwl_hw_txq_free_tfd, | ||
2298 | .rx_handler_setup = iwl4965_rx_handler_setup, | 2300 | .rx_handler_setup = iwl4965_rx_handler_setup, |
2299 | .setup_deferred_work = iwl4965_setup_deferred_work, | 2301 | .setup_deferred_work = iwl4965_setup_deferred_work, |
2300 | .cancel_deferred_work = iwl4965_cancel_deferred_work, | 2302 | .cancel_deferred_work = iwl4965_cancel_deferred_work, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 429dcbeff162..a35af671f850 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -1492,6 +1492,8 @@ static struct iwl_lib_ops iwl5000_lib = { | |||
1492 | .txq_set_sched = iwl5000_txq_set_sched, | 1492 | .txq_set_sched = iwl5000_txq_set_sched, |
1493 | .txq_agg_enable = iwl5000_txq_agg_enable, | 1493 | .txq_agg_enable = iwl5000_txq_agg_enable, |
1494 | .txq_agg_disable = iwl5000_txq_agg_disable, | 1494 | .txq_agg_disable = iwl5000_txq_agg_disable, |
1495 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, | ||
1496 | .txq_free_tfd = iwl_hw_txq_free_tfd, | ||
1495 | .rx_handler_setup = iwl5000_rx_handler_setup, | 1497 | .rx_handler_setup = iwl5000_rx_handler_setup, |
1496 | .setup_deferred_work = iwl5000_setup_deferred_work, | 1498 | .setup_deferred_work = iwl5000_setup_deferred_work, |
1497 | .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, | 1499 | .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7e0baf6deedf..4a15e42ad00a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -471,6 +471,126 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv) | |||
471 | return rc; | 471 | return rc; |
472 | } | 472 | } |
473 | 473 | ||
474 | static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) | ||
475 | { | ||
476 | struct iwl_tfd_tb *tb = &tfd->tbs[idx]; | ||
477 | |||
478 | dma_addr_t addr = get_unaligned_le32(&tb->lo); | ||
479 | if (sizeof(dma_addr_t) > sizeof(u32)) | ||
480 | addr |= | ||
481 | ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16; | ||
482 | |||
483 | return addr; | ||
484 | } | ||
485 | |||
486 | static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx) | ||
487 | { | ||
488 | struct iwl_tfd_tb *tb = &tfd->tbs[idx]; | ||
489 | |||
490 | return le16_to_cpu(tb->hi_n_len) >> 4; | ||
491 | } | ||
492 | |||
493 | static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx, | ||
494 | dma_addr_t addr, u16 len) | ||
495 | { | ||
496 | struct iwl_tfd_tb *tb = &tfd->tbs[idx]; | ||
497 | u16 hi_n_len = len << 4; | ||
498 | |||
499 | put_unaligned_le32(addr, &tb->lo); | ||
500 | if (sizeof(dma_addr_t) > sizeof(u32)) | ||
501 | hi_n_len |= ((addr >> 16) >> 16) & 0xF; | ||
502 | |||
503 | tb->hi_n_len = cpu_to_le16(hi_n_len); | ||
504 | |||
505 | tfd->num_tbs = idx + 1; | ||
506 | } | ||
507 | |||
508 | static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd) | ||
509 | { | ||
510 | return tfd->num_tbs & 0x1f; | ||
511 | } | ||
512 | |||
513 | /** | ||
514 | * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] | ||
515 | * @priv - driver private data | ||
516 | * @txq - tx queue | ||
517 | * | ||
518 | * Does NOT advance any TFD circular buffer read/write indexes | ||
519 | * Does NOT free the TFD itself (which is within circular buffer) | ||
520 | */ | ||
521 | void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) | ||
522 | { | ||
523 | struct iwl_tfd *tfd_tmp = (struct iwl_tfd *)&txq->tfds[0]; | ||
524 | struct iwl_tfd *tfd; | ||
525 | struct pci_dev *dev = priv->pci_dev; | ||
526 | int index = txq->q.read_ptr; | ||
527 | int i; | ||
528 | int num_tbs; | ||
529 | |||
530 | tfd = &tfd_tmp[index]; | ||
531 | |||
532 | /* Sanity check on number of chunks */ | ||
533 | num_tbs = iwl_tfd_get_num_tbs(tfd); | ||
534 | |||
535 | if (num_tbs >= IWL_NUM_OF_TBS) { | ||
536 | IWL_ERR(priv, "Too many chunks: %i\n", num_tbs); | ||
537 | /* @todo issue fatal error, it is quite serious situation */ | ||
538 | return; | ||
539 | } | ||
540 | |||
541 | /* Unmap tx_cmd */ | ||
542 | if (num_tbs) | ||
543 | pci_unmap_single(dev, | ||
544 | pci_unmap_addr(&txq->cmd[index]->meta, mapping), | ||
545 | pci_unmap_len(&txq->cmd[index]->meta, len), | ||
546 | PCI_DMA_TODEVICE); | ||
547 | |||
548 | /* Unmap chunks, if any. */ | ||
549 | for (i = 1; i < num_tbs; i++) { | ||
550 | pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i), | ||
551 | iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE); | ||
552 | |||
553 | if (txq->txb) { | ||
554 | dev_kfree_skb(txq->txb[txq->q.read_ptr].skb[i - 1]); | ||
555 | txq->txb[txq->q.read_ptr].skb[i - 1] = NULL; | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | |||
560 | int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, | ||
561 | struct iwl_tx_queue *txq, | ||
562 | dma_addr_t addr, u16 len, | ||
563 | u8 reset, u8 pad) | ||
564 | { | ||
565 | struct iwl_queue *q; | ||
566 | struct iwl_tfd *tfd; | ||
567 | u32 num_tbs; | ||
568 | |||
569 | q = &txq->q; | ||
570 | tfd = &txq->tfds[q->write_ptr]; | ||
571 | |||
572 | if (reset) | ||
573 | memset(tfd, 0, sizeof(*tfd)); | ||
574 | |||
575 | num_tbs = iwl_tfd_get_num_tbs(tfd); | ||
576 | |||
577 | /* Each TFD can point to a maximum 20 Tx buffers */ | ||
578 | if (num_tbs >= IWL_NUM_OF_TBS) { | ||
579 | IWL_ERR(priv, "Error can not send more than %d chunks\n", | ||
580 | IWL_NUM_OF_TBS); | ||
581 | return -EINVAL; | ||
582 | } | ||
583 | |||
584 | BUG_ON(addr & ~DMA_BIT_MASK(36)); | ||
585 | if (unlikely(addr & ~IWL_TX_DMA_MASK)) | ||
586 | IWL_ERR(priv, "Unaligned address = %llx\n", | ||
587 | (unsigned long long)addr); | ||
588 | |||
589 | iwl_tfd_set_tb(tfd, num_tbs, addr, len); | ||
590 | |||
591 | return 0; | ||
592 | } | ||
593 | |||
474 | /****************************************************************************** | 594 | /****************************************************************************** |
475 | * | 595 | * |
476 | * Misc. internal state and helper functions | 596 | * Misc. internal state and helper functions |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 466130ff07a9..9abdfb4acbf4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -110,6 +110,12 @@ struct iwl_lib_ops { | |||
110 | void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv, | 110 | void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv, |
111 | struct iwl_tx_queue *txq); | 111 | struct iwl_tx_queue *txq); |
112 | void (*txq_set_sched)(struct iwl_priv *priv, u32 mask); | 112 | void (*txq_set_sched)(struct iwl_priv *priv, u32 mask); |
113 | int (*txq_attach_buf_to_tfd)(struct iwl_priv *priv, | ||
114 | struct iwl_tx_queue *txq, | ||
115 | dma_addr_t addr, | ||
116 | u16 len, u8 reset, u8 pad); | ||
117 | void (*txq_free_tfd)(struct iwl_priv *priv, | ||
118 | struct iwl_tx_queue *txq); | ||
113 | /* aggregations */ | 119 | /* aggregations */ |
114 | int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo, | 120 | int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo, |
115 | int sta_id, int tid, u16 ssn_idx); | 121 | int sta_id, int tid, u16 ssn_idx); |
@@ -252,6 +258,10 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
252 | * TX | 258 | * TX |
253 | ******************************************************/ | 259 | ******************************************************/ |
254 | int iwl_txq_ctx_reset(struct iwl_priv *priv); | 260 | int iwl_txq_ctx_reset(struct iwl_priv *priv); |
261 | void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); | ||
262 | int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, | ||
263 | struct iwl_tx_queue *txq, | ||
264 | dma_addr_t addr, u16 len, u8 reset, u8 pad); | ||
255 | int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); | 265 | int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); |
256 | void iwl_hw_txq_ctx_free(struct iwl_priv *priv); | 266 | void iwl_hw_txq_ctx_free(struct iwl_priv *priv); |
257 | int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); | 267 | int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 913c77a2fea2..487a1d652292 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
@@ -76,116 +76,6 @@ static inline void iwl_free_dma_ptr(struct iwl_priv *priv, | |||
76 | memset(ptr, 0, sizeof(*ptr)); | 76 | memset(ptr, 0, sizeof(*ptr)); |
77 | } | 77 | } |
78 | 78 | ||
79 | static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) | ||
80 | { | ||
81 | struct iwl_tfd_tb *tb = &tfd->tbs[idx]; | ||
82 | |||
83 | dma_addr_t addr = get_unaligned_le32(&tb->lo); | ||
84 | if (sizeof(dma_addr_t) > sizeof(u32)) | ||
85 | addr |= | ||
86 | ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16; | ||
87 | |||
88 | return addr; | ||
89 | } | ||
90 | |||
91 | static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx) | ||
92 | { | ||
93 | struct iwl_tfd_tb *tb = &tfd->tbs[idx]; | ||
94 | |||
95 | return le16_to_cpu(tb->hi_n_len) >> 4; | ||
96 | } | ||
97 | |||
98 | static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx, | ||
99 | dma_addr_t addr, u16 len) | ||
100 | { | ||
101 | struct iwl_tfd_tb *tb = &tfd->tbs[idx]; | ||
102 | u16 hi_n_len = len << 4; | ||
103 | |||
104 | put_unaligned_le32(addr, &tb->lo); | ||
105 | if (sizeof(dma_addr_t) > sizeof(u32)) | ||
106 | hi_n_len |= ((addr >> 16) >> 16) & 0xF; | ||
107 | |||
108 | tb->hi_n_len = cpu_to_le16(hi_n_len); | ||
109 | |||
110 | tfd->num_tbs = idx + 1; | ||
111 | } | ||
112 | |||
113 | static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd) | ||
114 | { | ||
115 | return tfd->num_tbs & 0x1f; | ||
116 | } | ||
117 | |||
118 | /** | ||
119 | * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] | ||
120 | * @priv - driver private data | ||
121 | * @txq - tx queue | ||
122 | * | ||
123 | * Does NOT advance any TFD circular buffer read/write indexes | ||
124 | * Does NOT free the TFD itself (which is within circular buffer) | ||
125 | */ | ||
126 | static void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) | ||
127 | { | ||
128 | struct iwl_tfd *tfd_tmp = (struct iwl_tfd *)&txq->tfds[0]; | ||
129 | struct iwl_tfd *tfd; | ||
130 | struct pci_dev *dev = priv->pci_dev; | ||
131 | int index = txq->q.read_ptr; | ||
132 | int i; | ||
133 | int num_tbs; | ||
134 | |||
135 | tfd = &tfd_tmp[index]; | ||
136 | |||
137 | /* Sanity check on number of chunks */ | ||
138 | num_tbs = iwl_tfd_get_num_tbs(tfd); | ||
139 | |||
140 | if (num_tbs >= IWL_NUM_OF_TBS) { | ||
141 | IWL_ERR(priv, "Too many chunks: %i\n", num_tbs); | ||
142 | /* @todo issue fatal error, it is quite serious situation */ | ||
143 | return; | ||
144 | } | ||
145 | |||
146 | /* Unmap tx_cmd */ | ||
147 | if (num_tbs) | ||
148 | pci_unmap_single(dev, | ||
149 | pci_unmap_addr(&txq->cmd[index]->meta, mapping), | ||
150 | pci_unmap_len(&txq->cmd[index]->meta, len), | ||
151 | PCI_DMA_TODEVICE); | ||
152 | |||
153 | /* Unmap chunks, if any. */ | ||
154 | for (i = 1; i < num_tbs; i++) { | ||
155 | pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i), | ||
156 | iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE); | ||
157 | |||
158 | if (txq->txb) { | ||
159 | dev_kfree_skb(txq->txb[txq->q.read_ptr].skb[i - 1]); | ||
160 | txq->txb[txq->q.read_ptr].skb[i - 1] = NULL; | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
165 | static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, | ||
166 | struct iwl_tfd *tfd, | ||
167 | dma_addr_t addr, u16 len) | ||
168 | { | ||
169 | |||
170 | u32 num_tbs = iwl_tfd_get_num_tbs(tfd); | ||
171 | |||
172 | /* Each TFD can point to a maximum 20 Tx buffers */ | ||
173 | if (num_tbs >= IWL_NUM_OF_TBS) { | ||
174 | IWL_ERR(priv, "Error can not send more than %d chunks\n", | ||
175 | IWL_NUM_OF_TBS); | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | |||
179 | BUG_ON(addr & ~DMA_BIT_MASK(36)); | ||
180 | if (unlikely(addr & ~IWL_TX_DMA_MASK)) | ||
181 | IWL_ERR(priv, "Unaligned address = %llx\n", | ||
182 | (unsigned long long)addr); | ||
183 | |||
184 | iwl_tfd_set_tb(tfd, num_tbs, addr, len); | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | /** | 79 | /** |
190 | * iwl_txq_update_write_ptr - Send new write index to hardware | 80 | * iwl_txq_update_write_ptr - Send new write index to hardware |
191 | */ | 81 | */ |
@@ -254,7 +144,7 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) | |||
254 | /* first, empty all BD's */ | 144 | /* first, empty all BD's */ |
255 | for (; q->write_ptr != q->read_ptr; | 145 | for (; q->write_ptr != q->read_ptr; |
256 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) | 146 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) |
257 | iwl_hw_txq_free_tfd(priv, txq); | 147 | priv->cfg->ops->lib->txq_free_tfd(priv, txq); |
258 | 148 | ||
259 | len = sizeof(struct iwl_cmd) * q->n_window; | 149 | len = sizeof(struct iwl_cmd) * q->n_window; |
260 | 150 | ||
@@ -822,7 +712,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
822 | { | 712 | { |
823 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 713 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
824 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 714 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
825 | struct iwl_tfd *tfd; | ||
826 | struct iwl_tx_queue *txq; | 715 | struct iwl_tx_queue *txq; |
827 | struct iwl_queue *q; | 716 | struct iwl_queue *q; |
828 | struct iwl_cmd *out_cmd; | 717 | struct iwl_cmd *out_cmd; |
@@ -913,10 +802,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
913 | 802 | ||
914 | spin_lock_irqsave(&priv->lock, flags); | 803 | spin_lock_irqsave(&priv->lock, flags); |
915 | 804 | ||
916 | /* Set up first empty TFD within this queue's circular TFD buffer */ | ||
917 | tfd = &txq->tfds[q->write_ptr]; | ||
918 | memset(tfd, 0, sizeof(*tfd)); | ||
919 | |||
920 | /* Set up driver data for this TFD */ | 805 | /* Set up driver data for this TFD */ |
921 | memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); | 806 | memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); |
922 | txq->txb[q->write_ptr].skb[0] = skb; | 807 | txq->txb[q->write_ptr].skb[0] = skb; |
@@ -970,7 +855,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
970 | /* Add buffer containing Tx command and MAC(!) header to TFD's | 855 | /* Add buffer containing Tx command and MAC(!) header to TFD's |
971 | * first entry */ | 856 | * first entry */ |
972 | txcmd_phys += offsetof(struct iwl_cmd, hdr); | 857 | txcmd_phys += offsetof(struct iwl_cmd, hdr); |
973 | iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); | 858 | priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, |
859 | txcmd_phys, len, 1, 0); | ||
974 | 860 | ||
975 | if (info->control.hw_key) | 861 | if (info->control.hw_key) |
976 | iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id); | 862 | iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id); |
@@ -981,7 +867,9 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
981 | if (len) { | 867 | if (len) { |
982 | phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, | 868 | phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, |
983 | len, PCI_DMA_TODEVICE); | 869 | len, PCI_DMA_TODEVICE); |
984 | iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); | 870 | priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, |
871 | phys_addr, len, | ||
872 | 0, 0); | ||
985 | } | 873 | } |
986 | 874 | ||
987 | /* Tell NIC about any 2-byte padding after MAC header */ | 875 | /* Tell NIC about any 2-byte padding after MAC header */ |
@@ -1063,7 +951,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
1063 | { | 951 | { |
1064 | struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; | 952 | struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; |
1065 | struct iwl_queue *q = &txq->q; | 953 | struct iwl_queue *q = &txq->q; |
1066 | struct iwl_tfd *tfd; | ||
1067 | struct iwl_cmd *out_cmd; | 954 | struct iwl_cmd *out_cmd; |
1068 | dma_addr_t phys_addr; | 955 | dma_addr_t phys_addr; |
1069 | unsigned long flags; | 956 | unsigned long flags; |
@@ -1092,10 +979,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
1092 | 979 | ||
1093 | spin_lock_irqsave(&priv->hcmd_lock, flags); | 980 | spin_lock_irqsave(&priv->hcmd_lock, flags); |
1094 | 981 | ||
1095 | tfd = &txq->tfds[q->write_ptr]; | ||
1096 | memset(tfd, 0, sizeof(*tfd)); | ||
1097 | |||
1098 | |||
1099 | idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); | 982 | idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); |
1100 | out_cmd = txq->cmd[idx]; | 983 | out_cmd = txq->cmd[idx]; |
1101 | 984 | ||
@@ -1120,7 +1003,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
1120 | pci_unmap_len_set(&out_cmd->meta, len, len); | 1003 | pci_unmap_len_set(&out_cmd->meta, len, len); |
1121 | phys_addr += offsetof(struct iwl_cmd, hdr); | 1004 | phys_addr += offsetof(struct iwl_cmd, hdr); |
1122 | 1005 | ||
1123 | iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); | 1006 | priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, |
1007 | phys_addr, fix_size, 1, 0); | ||
1124 | 1008 | ||
1125 | #ifdef CONFIG_IWLWIFI_DEBUG | 1009 | #ifdef CONFIG_IWLWIFI_DEBUG |
1126 | switch (out_cmd->hdr.cmd) { | 1010 | switch (out_cmd->hdr.cmd) { |
@@ -1180,7 +1064,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) | |||
1180 | if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) | 1064 | if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) |
1181 | priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq); | 1065 | priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq); |
1182 | 1066 | ||
1183 | iwl_hw_txq_free_tfd(priv, txq); | 1067 | priv->cfg->ops->lib->txq_free_tfd(priv, txq); |
1184 | nfreed++; | 1068 | nfreed++; |
1185 | } | 1069 | } |
1186 | return nfreed; | 1070 | return nfreed; |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 66b7e22d7e84..4474a4c3ddcd 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -274,7 +274,7 @@ void iwl3945_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) | |||
274 | /* first, empty all BD's */ | 274 | /* first, empty all BD's */ |
275 | for (; q->write_ptr != q->read_ptr; | 275 | for (; q->write_ptr != q->read_ptr; |
276 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) | 276 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) |
277 | iwl3945_hw_txq_free_tfd(priv, txq); | 277 | priv->cfg->ops->lib->txq_free_tfd(priv, txq); |
278 | 278 | ||
279 | len = sizeof(struct iwl_cmd) * q->n_window; | 279 | len = sizeof(struct iwl_cmd) * q->n_window; |
280 | if (q->id == IWL_CMD_QUEUE_NUM) | 280 | if (q->id == IWL_CMD_QUEUE_NUM) |
@@ -453,12 +453,10 @@ static int iwl3945_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
453 | { | 453 | { |
454 | struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; | 454 | struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; |
455 | struct iwl_queue *q = &txq->q; | 455 | struct iwl_queue *q = &txq->q; |
456 | struct iwl3945_tfd *tfd; | ||
457 | struct iwl_cmd *out_cmd; | 456 | struct iwl_cmd *out_cmd; |
458 | u32 idx; | 457 | u32 idx; |
459 | u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); | 458 | u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); |
460 | dma_addr_t phys_addr; | 459 | dma_addr_t phys_addr; |
461 | int pad; | ||
462 | int ret, len; | 460 | int ret, len; |
463 | unsigned long flags; | 461 | unsigned long flags; |
464 | 462 | ||
@@ -481,9 +479,6 @@ static int iwl3945_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
481 | 479 | ||
482 | spin_lock_irqsave(&priv->hcmd_lock, flags); | 480 | spin_lock_irqsave(&priv->hcmd_lock, flags); |
483 | 481 | ||
484 | tfd = &txq->tfds39[q->write_ptr]; | ||
485 | memset(tfd, 0, sizeof(*tfd)); | ||
486 | |||
487 | idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); | 482 | idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); |
488 | out_cmd = txq->cmd[idx]; | 483 | out_cmd = txq->cmd[idx]; |
489 | 484 | ||
@@ -509,10 +504,9 @@ static int iwl3945_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
509 | pci_unmap_len_set(&out_cmd->meta, len, len); | 504 | pci_unmap_len_set(&out_cmd->meta, len, len); |
510 | phys_addr += offsetof(struct iwl_cmd, hdr); | 505 | phys_addr += offsetof(struct iwl_cmd, hdr); |
511 | 506 | ||
512 | iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); | 507 | priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, |
513 | 508 | phys_addr, fix_size, | |
514 | pad = U32_PAD(cmd->len); | 509 | 1, U32_PAD(cmd->len)); |
515 | tfd->control_flags |= cpu_to_le32(TFD_CTL_PAD_SET(pad)); | ||
516 | 510 | ||
517 | IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " | 511 | IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " |
518 | "%d bytes at %d[%d]:%d\n", | 512 | "%d bytes at %d[%d]:%d\n", |
@@ -2158,7 +2152,6 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
2158 | { | 2152 | { |
2159 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 2153 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
2160 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 2154 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
2161 | struct iwl3945_tfd *tfd; | ||
2162 | struct iwl3945_tx_cmd *tx; | 2155 | struct iwl3945_tx_cmd *tx; |
2163 | struct iwl_tx_queue *txq = NULL; | 2156 | struct iwl_tx_queue *txq = NULL; |
2164 | struct iwl_queue *q = NULL; | 2157 | struct iwl_queue *q = NULL; |
@@ -2243,9 +2236,6 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
2243 | 2236 | ||
2244 | spin_lock_irqsave(&priv->lock, flags); | 2237 | spin_lock_irqsave(&priv->lock, flags); |
2245 | 2238 | ||
2246 | /* Set up first empty TFD within this queue's circular TFD buffer */ | ||
2247 | tfd = &txq->tfds39[q->write_ptr]; | ||
2248 | memset(tfd, 0, sizeof(*tfd)); | ||
2249 | idx = get_cmd_index(q, q->write_ptr, 0); | 2239 | idx = get_cmd_index(q, q->write_ptr, 0); |
2250 | 2240 | ||
2251 | /* Set up driver data for this TFD */ | 2241 | /* Set up driver data for this TFD */ |
@@ -2304,7 +2294,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
2304 | 2294 | ||
2305 | /* Add buffer containing Tx command and MAC(!) header to TFD's | 2295 | /* Add buffer containing Tx command and MAC(!) header to TFD's |
2306 | * first entry */ | 2296 | * first entry */ |
2307 | iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); | 2297 | priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, |
2298 | txcmd_phys, len, 1, 0); | ||
2308 | 2299 | ||
2309 | if (info->control.hw_key) | 2300 | if (info->control.hw_key) |
2310 | iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0); | 2301 | iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0); |
@@ -2315,18 +2306,11 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
2315 | if (len) { | 2306 | if (len) { |
2316 | phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, | 2307 | phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, |
2317 | len, PCI_DMA_TODEVICE); | 2308 | len, PCI_DMA_TODEVICE); |
2318 | iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); | 2309 | priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, |
2310 | phys_addr, len, | ||
2311 | 0, U32_PAD(len)); | ||
2319 | } | 2312 | } |
2320 | 2313 | ||
2321 | if (!len) | ||
2322 | /* If there is no payload, then we use only one Tx buffer */ | ||
2323 | tfd->control_flags = cpu_to_le32(TFD_CTL_COUNT_SET(1)); | ||
2324 | else | ||
2325 | /* Else use 2 buffers. | ||
2326 | * Tell 3945 about any padding after MAC header */ | ||
2327 | tfd->control_flags = cpu_to_le32(TFD_CTL_COUNT_SET(2) | | ||
2328 | TFD_CTL_PAD_SET(U32_PAD(len))); | ||
2329 | |||
2330 | /* Total # bytes to be transmitted */ | 2314 | /* Total # bytes to be transmitted */ |
2331 | len = (u16)skb->len; | 2315 | len = (u16)skb->len; |
2332 | tx->len = cpu_to_le16(len); | 2316 | tx->len = cpu_to_le16(len); |