diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-rx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rx.c | 212 |
1 files changed, 67 insertions, 145 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index f3f3efe38ce2..8e314003b63a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -41,142 +41,6 @@ | |||
41 | #include "iwl-agn-calib.h" | 41 | #include "iwl-agn-calib.h" |
42 | #include "iwl-agn.h" | 42 | #include "iwl-agn.h" |
43 | 43 | ||
44 | /****************************************************************************** | ||
45 | * | ||
46 | * RX path functions | ||
47 | * | ||
48 | ******************************************************************************/ | ||
49 | |||
50 | /* | ||
51 | * Rx theory of operation | ||
52 | * | ||
53 | * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs), | ||
54 | * each of which point to Receive Buffers to be filled by the NIC. These get | ||
55 | * used not only for Rx frames, but for any command response or notification | ||
56 | * from the NIC. The driver and NIC manage the Rx buffers by means | ||
57 | * of indexes into the circular buffer. | ||
58 | * | ||
59 | * Rx Queue Indexes | ||
60 | * The host/firmware share two index registers for managing the Rx buffers. | ||
61 | * | ||
62 | * The READ index maps to the first position that the firmware may be writing | ||
63 | * to -- the driver can read up to (but not including) this position and get | ||
64 | * good data. | ||
65 | * The READ index is managed by the firmware once the card is enabled. | ||
66 | * | ||
67 | * The WRITE index maps to the last position the driver has read from -- the | ||
68 | * position preceding WRITE is the last slot the firmware can place a packet. | ||
69 | * | ||
70 | * The queue is empty (no good data) if WRITE = READ - 1, and is full if | ||
71 | * WRITE = READ. | ||
72 | * | ||
73 | * During initialization, the host sets up the READ queue position to the first | ||
74 | * INDEX position, and WRITE to the last (READ - 1 wrapped) | ||
75 | * | ||
76 | * When the firmware places a packet in a buffer, it will advance the READ index | ||
77 | * and fire the RX interrupt. The driver can then query the READ index and | ||
78 | * process as many packets as possible, moving the WRITE index forward as it | ||
79 | * resets the Rx queue buffers with new memory. | ||
80 | * | ||
81 | * The management in the driver is as follows: | ||
82 | * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When | ||
83 | * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled | ||
84 | * to replenish the iwl->rxq->rx_free. | ||
85 | * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the | ||
86 | * iwl->rxq is replenished and the READ INDEX is updated (updating the | ||
87 | * 'processed' and 'read' driver indexes as well) | ||
88 | * + A received packet is processed and handed to the kernel network stack, | ||
89 | * detached from the iwl->rxq. The driver 'processed' index is updated. | ||
90 | * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free | ||
91 | * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ | ||
92 | * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there | ||
93 | * were enough free buffers and RX_STALLED is set it is cleared. | ||
94 | * | ||
95 | * | ||
96 | * Driver sequence: | ||
97 | * | ||
98 | * iwl_rx_queue_alloc() Allocates rx_free | ||
99 | * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls | ||
100 | * iwl_rx_queue_restock | ||
101 | * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx | ||
102 | * queue, updates firmware pointers, and updates | ||
103 | * the WRITE index. If insufficient rx_free buffers | ||
104 | * are available, schedules iwl_rx_replenish | ||
105 | * | ||
106 | * -- enable interrupts -- | ||
107 | * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the | ||
108 | * READ INDEX, detaching the SKB from the pool. | ||
109 | * Moves the packet buffer from queue to rx_used. | ||
110 | * Calls iwl_rx_queue_restock to refill any empty | ||
111 | * slots. | ||
112 | * ... | ||
113 | * | ||
114 | */ | ||
115 | |||
116 | /** | ||
117 | * iwl_rx_queue_space - Return number of free slots available in queue. | ||
118 | */ | ||
119 | int iwl_rx_queue_space(const struct iwl_rx_queue *q) | ||
120 | { | ||
121 | int s = q->read - q->write; | ||
122 | if (s <= 0) | ||
123 | s += RX_QUEUE_SIZE; | ||
124 | /* keep some buffer to not confuse full and empty queue */ | ||
125 | s -= 2; | ||
126 | if (s < 0) | ||
127 | s = 0; | ||
128 | return s; | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue | ||
133 | */ | ||
134 | void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) | ||
135 | { | ||
136 | unsigned long flags; | ||
137 | u32 reg; | ||
138 | |||
139 | spin_lock_irqsave(&q->lock, flags); | ||
140 | |||
141 | if (q->need_update == 0) | ||
142 | goto exit_unlock; | ||
143 | |||
144 | if (priv->cfg->base_params->shadow_reg_enable) { | ||
145 | /* shadow register enabled */ | ||
146 | /* Device expects a multiple of 8 */ | ||
147 | q->write_actual = (q->write & ~0x7); | ||
148 | iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write_actual); | ||
149 | } else { | ||
150 | /* If power-saving is in use, make sure device is awake */ | ||
151 | if (test_bit(STATUS_POWER_PMI, &priv->status)) { | ||
152 | reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); | ||
153 | |||
154 | if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { | ||
155 | IWL_DEBUG_INFO(priv, | ||
156 | "Rx queue requesting wakeup," | ||
157 | " GP1 = 0x%x\n", reg); | ||
158 | iwl_set_bit(priv, CSR_GP_CNTRL, | ||
159 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
160 | goto exit_unlock; | ||
161 | } | ||
162 | |||
163 | q->write_actual = (q->write & ~0x7); | ||
164 | iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, | ||
165 | q->write_actual); | ||
166 | |||
167 | /* Else device is assumed to be awake */ | ||
168 | } else { | ||
169 | /* Device expects a multiple of 8 */ | ||
170 | q->write_actual = (q->write & ~0x7); | ||
171 | iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, | ||
172 | q->write_actual); | ||
173 | } | ||
174 | } | ||
175 | q->need_update = 0; | ||
176 | |||
177 | exit_unlock: | ||
178 | spin_unlock_irqrestore(&q->lock, flags); | ||
179 | } | ||
180 | 44 | ||
181 | /****************************************************************************** | 45 | /****************************************************************************** |
182 | * | 46 | * |
@@ -306,7 +170,7 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, | |||
306 | int actual_delta, expected_delta, ba_timeout_delta; | 170 | int actual_delta, expected_delta, ba_timeout_delta; |
307 | struct statistics_tx *old; | 171 | struct statistics_tx *old; |
308 | 172 | ||
309 | if (priv->_agn.agg_tids_count) | 173 | if (priv->agg_tids_count) |
310 | return true; | 174 | return true; |
311 | 175 | ||
312 | old = &priv->statistics.tx; | 176 | old = &priv->statistics.tx; |
@@ -624,8 +488,8 @@ static void iwl_rx_statistics(struct iwl_priv *priv, | |||
624 | iwl_rx_calc_noise(priv); | 488 | iwl_rx_calc_noise(priv); |
625 | queue_work(priv->workqueue, &priv->run_time_calib_work); | 489 | queue_work(priv->workqueue, &priv->run_time_calib_work); |
626 | } | 490 | } |
627 | if (priv->cfg->ops->lib->temperature && change) | 491 | if (priv->cfg->lib->temperature && change) |
628 | priv->cfg->ops->lib->temperature(priv); | 492 | priv->cfg->lib->temperature(priv); |
629 | } | 493 | } |
630 | 494 | ||
631 | static void iwl_rx_reply_statistics(struct iwl_priv *priv, | 495 | static void iwl_rx_reply_statistics(struct iwl_priv *priv, |
@@ -728,8 +592,8 @@ static void iwl_rx_reply_rx_phy(struct iwl_priv *priv, | |||
728 | { | 592 | { |
729 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 593 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
730 | 594 | ||
731 | priv->_agn.last_phy_res_valid = true; | 595 | priv->last_phy_res_valid = true; |
732 | memcpy(&priv->_agn.last_phy_res, pkt->u.raw, | 596 | memcpy(&priv->last_phy_res, pkt->u.raw, |
733 | sizeof(struct iwl_rx_phy_res)); | 597 | sizeof(struct iwl_rx_phy_res)); |
734 | } | 598 | } |
735 | 599 | ||
@@ -977,11 +841,11 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv, | |||
977 | phy_res->cfg_phy_cnt + len); | 841 | phy_res->cfg_phy_cnt + len); |
978 | ampdu_status = le32_to_cpu(rx_pkt_status); | 842 | ampdu_status = le32_to_cpu(rx_pkt_status); |
979 | } else { | 843 | } else { |
980 | if (!priv->_agn.last_phy_res_valid) { | 844 | if (!priv->last_phy_res_valid) { |
981 | IWL_ERR(priv, "MPDU frame without cached PHY data\n"); | 845 | IWL_ERR(priv, "MPDU frame without cached PHY data\n"); |
982 | return; | 846 | return; |
983 | } | 847 | } |
984 | phy_res = &priv->_agn.last_phy_res; | 848 | phy_res = &priv->last_phy_res; |
985 | amsdu = (struct iwl_rx_mpdu_res_start *)pkt->u.raw; | 849 | amsdu = (struct iwl_rx_mpdu_res_start *)pkt->u.raw; |
986 | header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); | 850 | header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); |
987 | len = le16_to_cpu(amsdu->byte_count); | 851 | len = le16_to_cpu(amsdu->byte_count); |
@@ -1102,6 +966,64 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) | |||
1102 | /* block ack */ | 966 | /* block ack */ |
1103 | handlers[REPLY_COMPRESSED_BA] = iwlagn_rx_reply_compressed_ba; | 967 | handlers[REPLY_COMPRESSED_BA] = iwlagn_rx_reply_compressed_ba; |
1104 | 968 | ||
1105 | /* Set up hardware specific Rx handlers */ | 969 | /* init calibration handlers */ |
1106 | priv->cfg->ops->lib->rx_handler_setup(priv); | 970 | priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = |
971 | iwlagn_rx_calib_result; | ||
972 | priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; | ||
973 | |||
974 | /* set up notification wait support */ | ||
975 | spin_lock_init(&priv->notif_wait_lock); | ||
976 | INIT_LIST_HEAD(&priv->notif_waits); | ||
977 | init_waitqueue_head(&priv->notif_waitq); | ||
978 | |||
979 | /* Set up BT Rx handlers */ | ||
980 | if (priv->cfg->lib->bt_rx_handler_setup) | ||
981 | priv->cfg->lib->bt_rx_handler_setup(priv); | ||
982 | |||
983 | } | ||
984 | |||
985 | void iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | ||
986 | { | ||
987 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
988 | |||
989 | /* | ||
990 | * Do the notification wait before RX handlers so | ||
991 | * even if the RX handler consumes the RXB we have | ||
992 | * access to it in the notification wait entry. | ||
993 | */ | ||
994 | if (!list_empty(&priv->notif_waits)) { | ||
995 | struct iwl_notification_wait *w; | ||
996 | |||
997 | spin_lock(&priv->notif_wait_lock); | ||
998 | list_for_each_entry(w, &priv->notif_waits, list) { | ||
999 | if (w->cmd != pkt->hdr.cmd) | ||
1000 | continue; | ||
1001 | IWL_DEBUG_RX(priv, | ||
1002 | "Notif: %s, 0x%02x - wake the callers up\n", | ||
1003 | get_cmd_string(pkt->hdr.cmd), | ||
1004 | pkt->hdr.cmd); | ||
1005 | w->triggered = true; | ||
1006 | if (w->fn) | ||
1007 | w->fn(priv, pkt, w->fn_data); | ||
1008 | } | ||
1009 | spin_unlock(&priv->notif_wait_lock); | ||
1010 | |||
1011 | wake_up_all(&priv->notif_waitq); | ||
1012 | } | ||
1013 | |||
1014 | if (priv->pre_rx_handler) | ||
1015 | priv->pre_rx_handler(priv, rxb); | ||
1016 | |||
1017 | /* Based on type of command response or notification, | ||
1018 | * handle those that need handling via function in | ||
1019 | * rx_handlers table. See iwl_setup_rx_handlers() */ | ||
1020 | if (priv->rx_handlers[pkt->hdr.cmd]) { | ||
1021 | priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; | ||
1022 | priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); | ||
1023 | } else { | ||
1024 | /* No handling needed */ | ||
1025 | IWL_DEBUG_RX(priv, | ||
1026 | "No handler needed for %s, 0x%02x\n", | ||
1027 | get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); | ||
1028 | } | ||
1107 | } | 1029 | } |