2 * carl9170 firmware - used by the ar9170 wireless device
4 * Interface to the WLAN part of the chip
6 * Copyright (c) 2000-2005 ZyDAS Technology Corporation
7 * Copyright (c) 2007-2009 Atheros Communications, Inc.
8 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
9 * Copyright 2009-2012 Christian Lamparter <chunkeey@googlemail.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "shared/phy.h"
33 #include "linux/ieee80211.h"
36 #ifdef CONFIG_CARL9170FW_DEBUG
37 static void wlan_dump_queue(unsigned int qidx)
40 struct dma_desc *desc;
41 struct carl9170_tx_superframe *super;
44 __for_each_desc(desc, &fw.wlan.tx_queue[qidx]) {
45 super = get_super(desc);
46 DBG("%d: %p s:%x c:%x tl:%x ds:%x n:%p l:%p ", entries, desc,
47 desc->status, desc->ctrl, desc->totalLen,
48 desc->dataSize, desc->nextAddr, desc->lastAddr);
50 DBG("c:%x tr:%d ri:%d l:%x m:%x p:%x fc:%x",
51 super->s.cookie, super->s.cnt, super->s.rix,
52 super->f.hdr.length, super->f.hdr.mac.set,
53 (unsigned int) le32_to_cpu(super->f.hdr.phy.set),
54 super->f.data.i3e.frame_control);
59 desc = (struct dma_desc *)get_wlan_txq_addr(qidx);
61 DBG("Queue: %d: te:%d td:%d h:%p c:%p t:%p",
62 qidx, entries, queue_len(&fw.wlan.tx_queue[qidx]),
63 fw.wlan.tx_queue[qidx].head,
64 desc, fw.wlan.tx_queue[qidx].terminator);
66 DBG("HW: t:%x s:%x ac:%x c:%x",
67 (unsigned int) get(AR9170_MAC_REG_DMA_TRIGGER),
68 (unsigned int) get(AR9170_MAC_REG_DMA_STATUS),
69 (unsigned int) get(AR9170_MAC_REG_AMPDU_COUNT),
70 (unsigned int) get(AR9170_MAC_REG_DMA_TXQX_ADDR_CURR));
72 #endif /* CONFIG_CARL9170FW_DEBUG */
74 static void wlan_check_rx_overrun(void)
76 uint32_t overruns, total;
78 fw.tally.rx_total += total = get(AR9170_MAC_REG_RX_TOTAL);
79 fw.tally.rx_overrun += overruns = get(AR9170_MAC_REG_RX_OVERRUN);
80 if (unlikely(overruns)) {
81 if (overruns == total) {
86 wlan_trigger(AR9170_DMA_TRIGGER_RXQ);
90 static void handle_beacon_config(void)
94 bcn_count = get(AR9170_MAC_REG_BCN_COUNT);
95 send_cmd_to_host(4, CARL9170_RSP_BEACON_CONFIG, 0x00,
96 (uint8_t *) &bcn_count);
99 static void handle_pretbtt(void)
101 fw.wlan.cab_flush_time = get_clock_counter();
103 #ifdef CONFIG_CARL9170FW_RADIO_FUNCTIONS
106 send_cmd_to_host(4, CARL9170_RSP_PRETBTT, 0x00,
107 (uint8_t *) &fw.phy.psm.state);
108 #endif /* CONFIG_CARL9170FW_RADIO_FUNCTIONS */
111 static void handle_atim(void)
113 send_cmd_to_host(0, CARL9170_RSP_ATIM, 0x00, NULL);
116 #ifdef CONFIG_CARL9170FW_DEBUG
117 static void handle_qos(void)
120 * What is the QoS Bit used for?
121 * Is it only an indicator for TXOP & Burst, or
122 * should we do something here?
126 static void handle_radar(void)
128 send_cmd_to_host(0, CARL9170_RSP_RADAR, 0x00, NULL);
130 #endif /* CONFIG_CARL9170FW_DEBUG */
132 static void wlan_janitor(void)
134 wlan_send_buffered_cab();
136 wlan_send_buffered_tx_status();
138 wlan_send_buffered_ba();
143 void handle_wlan(void)
147 intr = get(AR9170_MAC_REG_INT_CTRL);
149 set(AR9170_MAC_REG_INT_CTRL, intr);
151 #define HANDLER(intr, flag, func) \
153 if ((intr & flag) != 0) { \
158 intr |= fw.wlan.soft_int;
159 fw.wlan.soft_int = 0;
161 HANDLER(intr, AR9170_MAC_INT_PRETBTT, handle_pretbtt);
163 HANDLER(intr, AR9170_MAC_INT_ATIM, handle_atim);
165 HANDLER(intr, AR9170_MAC_INT_RXC, handle_wlan_rx);
167 HANDLER(intr, (AR9170_MAC_INT_TXC | AR9170_MAC_INT_RETRY_FAIL),
168 handle_wlan_tx_completion);
170 #ifdef CONFIG_CARL9170FW_DEBUG
171 HANDLER(intr, AR9170_MAC_INT_QOS, handle_qos);
173 HANDLER(intr, AR9170_MAC_INT_RADAR, handle_radar);
174 #endif /* CONFIG_CARL9170FW_DEBUG */
176 HANDLER(intr, AR9170_MAC_INT_CFG_BCN, handle_beacon_config);
179 DBG("Unhandled Interrupt %x\n", (unsigned int) intr);
187 CARL9170FW_TX_MAC_BUMP = 4,
188 CARL9170FW_TX_MAC_DEBUG = 6,
189 CARL9170FW_TX_MAC_RESET = 7,
192 static void wlan_check_hang(void)
194 struct dma_desc *desc;
197 for (i = AR9170_TXQ_SPECIAL; i >= AR9170_TXQ0; i--) {
198 if (queue_empty(&fw.wlan.tx_queue[i])) {
199 /* Nothing to do here... move along */
203 /* fetch the current DMA queue position */
204 desc = (struct dma_desc *)get_wlan_txq_addr(i);
206 /* Stuck frame detection */
207 if (unlikely(DESC_PAYLOAD(desc) == fw.wlan.last_super[i])) {
208 fw.wlan.last_super_num[i]++;
210 if (unlikely(fw.wlan.last_super_num[i] >= CARL9170FW_TX_MAC_RESET)) {
212 * schedule MAC reset (aka OFF/ON => dead)
214 * This will almost certainly kill
215 * the device for good, but it's the
216 * recommended thing to do...
222 #ifdef CONFIG_CARL9170FW_DEBUG
223 if (unlikely(fw.wlan.last_super_num[i] >= CARL9170FW_TX_MAC_DEBUG)) {
225 * Sigh, the queue is almost certainly
226 * dead. Dump the queue content to the
227 * user, maybe we find out why it got
233 #endif /* CONFIG_CARL9170FW_DEBUG */
235 #ifdef CONFIG_CARL9170FW_DMA_QUEUE_BUMP
236 if (unlikely(fw.wlan.last_super_num[i] >= CARL9170FW_TX_MAC_BUMP)) {
238 * Hrrm, bump the queue a bit.
239 * maybe this will get it going again.
243 wlan_trigger(BIT(i));
245 #endif /* CONFIG_CARL9170FW_DMA_QUEUE_BUMP */
248 fw.wlan.last_super[i] = DESC_PAYLOAD(desc);
249 fw.wlan.last_super_num[i] = 0;
254 #ifdef CONFIG_CARL9170FW_FW_MAC_RESET
256 * NB: Resetting the MAC is a two-edged sword.
257 * On most occasions, it does what it is supposed to do.
258 * But there is a chance that this will make it
259 * even worse and the radio dies silently.
261 static void wlan_mac_reset(void)
264 uint32_t agg_wait_counter;
265 uint32_t agg_density;
266 uint32_t bcn_start_addr;
270 uint32_t rts_cts_tpc;
271 uint32_t rts_cts_rate;
274 #ifdef CONFIG_CARL9170FW_RADIO_FUNCTIONS
276 #endif /* CONFIG_CARL9170FW_RADIO_FUNCTIONS */
278 #ifdef CONFIG_CARL9170FW_NOISY_MAC_RESET
280 #endif /* CONFIG_CARL9170FW_NOISY_MAC_RESET */
282 /* Save aggregation parameters */
283 agg_wait_counter = get(AR9170_MAC_REG_AMPDU_FACTOR);
284 agg_density = get(AR9170_MAC_REG_AMPDU_DENSITY);
286 bcn_start_addr = get(AR9170_MAC_REG_BCN_ADDR);
288 cam_mode = get(AR9170_MAC_REG_CAM_MODE);
289 rctl = get(AR9170_MAC_REG_CAM_ROLL_CALL_TBL_L);
290 rcth = get(AR9170_MAC_REG_CAM_ROLL_CALL_TBL_H);
292 ack_power = get(AR9170_MAC_REG_ACK_TPC);
293 rts_cts_tpc = get(AR9170_MAC_REG_RTS_CTS_TPC);
294 rts_cts_rate = get(AR9170_MAC_REG_RTS_CTS_RATE);
296 #ifdef CONFIG_CARL9170FW_RADIO_FUNCTIONS
297 /* 0x1c8960 write only */
298 rx_BB = get(AR9170_PHY_REG_SWITCH_CHAIN_0);
299 #endif /* CONFIG_CARL9170FW_RADIO_FUNCTIONS */
301 /* TX/RX must be stopped by now */
302 val = get(AR9170_MAC_REG_POWER_STATE_CTRL);
304 val |= AR9170_MAC_POWER_STATE_CTRL_RESET;
307 * Manipulate CCA threshold to stop transmission
309 * set(AR9170_PHY_REG_CCA_THRESHOLD, 0x300);
313 * check Rx state in 0(idle) 9(disable)
315 * chState = (get(AR9170_MAC_REG_MISC_684) >> 16) & 0xf;
316 * while( (chState != 0) && (chState != 9)) {
317 * chState = (get(AR9170_MAC_REG_MISC_684) >> 16) & 0xf;
321 set(AR9170_MAC_REG_POWER_STATE_CTRL, val);
325 /* Restore aggregation parameters */
326 set(AR9170_MAC_REG_AMPDU_FACTOR, agg_wait_counter);
327 set(AR9170_MAC_REG_AMPDU_DENSITY, agg_density);
329 set(AR9170_MAC_REG_BCN_ADDR, bcn_start_addr);
330 set(AR9170_MAC_REG_CAM_MODE, cam_mode);
331 set(AR9170_MAC_REG_CAM_ROLL_CALL_TBL_L, rctl);
332 set(AR9170_MAC_REG_CAM_ROLL_CALL_TBL_H, rcth);
334 set(AR9170_MAC_REG_RTS_CTS_TPC, rts_cts_tpc);
335 set(AR9170_MAC_REG_ACK_TPC, ack_power);
336 set(AR9170_MAC_REG_RTS_CTS_RATE, rts_cts_rate);
338 #ifdef CONFIG_CARL9170FW_RADIO_FUNCTIONS
339 set(AR9170_PHY_REG_SWITCH_CHAIN_2, rx_BB);
340 #endif /* CONFIG_CARL9170FW_RADIO_FUNCTIONS */
343 * Manipulate CCA threshold to resume transmission
345 * set(AR9170_PHY_REG_CCA_THRESHOLD, 0x0);
348 val = AR9170_DMA_TRIGGER_RXQ;
349 /* Reinitialize all WLAN TX DMA queues. */
350 for (i = AR9170_TXQ_SPECIAL; i >= AR9170_TXQ0; i--) {
351 struct dma_desc *iter;
353 __for_each_desc_bits(iter, &fw.wlan.tx_queue[i], AR9170_OWN_BITS_SW);
355 /* kill the stuck frame */
356 if (!is_terminator(&fw.wlan.tx_queue[i], iter) &&
357 fw.wlan.last_super_num[i] >= CARL9170FW_TX_MAC_RESET &&
358 fw.wlan.last_super[i] == DESC_PAYLOAD(iter)) {
359 struct carl9170_tx_superframe *super = get_super(iter);
361 iter->status = AR9170_OWN_BITS_SW;
363 * Mark the frame as failed.
364 * The BAFAIL flag allows the frame to sail through
365 * wlan_tx_status without much "unstuck" trouble.
367 iter->ctrl &= ~(AR9170_CTRL_FAIL);
368 iter->ctrl |= AR9170_CTRL_BAFAIL;
370 super->s.cnt = CARL9170_TX_MAX_RATE_TRIES;
371 super->s.rix = CARL9170_TX_MAX_RETRY_RATES;
373 fw.wlan.last_super_num[i] = 0;
374 fw.wlan.last_super[i] = NULL;
375 iter = iter->lastAddr->nextAddr;
378 set_wlan_txq_dma_addr(i, (uint32_t) iter);
379 if (!is_terminator(&fw.wlan.tx_queue[i], iter))
382 DBG("Q:%d l:%d h:%p t:%p cu:%p it:%p ct:%x st:%x\n", i, queue_len(&fw.wlan.tx_queue[i]),
383 fw.wlan.tx_queue[i].head, fw.wlan.tx_queue[i].terminator,
384 get_wlan_txq_addr(i), iter, iter->ctrl, iter->status);
387 fw.wlan.soft_int |= AR9170_MAC_INT_RXC | AR9170_MAC_INT_TXC |
388 AR9170_MAC_INT_RETRY_FAIL;
390 set(AR9170_MAC_REG_DMA_RXQ_ADDR, (uint32_t) fw.wlan.rx_queue.head);
394 static void wlan_mac_reset(void)
396 /* The driver takes care of reinitializing the device */
399 #endif /* CONFIG_CARL9170FW_FW_MAC_RESET */
401 void __cold wlan_timer(void)
403 unsigned int cached_mac_reset;
405 cached_mac_reset = fw.wlan.mac_reset;
407 /* TX Queue Hang check */
410 /* RX Overrun check */
411 wlan_check_rx_overrun();
413 if (unlikely(fw.wlan.mac_reset >= CARL9170_MAC_RESET_RESET)) {
415 fw.wlan.mac_reset = CARL9170_MAC_RESET_OFF;
417 if (fw.wlan.mac_reset && cached_mac_reset == fw.wlan.mac_reset)