diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 250 |
1 files changed, 49 insertions, 201 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 08e3cae4fa5a..11c6c1169e78 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,164 +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 = sizeof(*tx_beacon_cmd) + frame_size; | 188 | cmd.len[0] = sizeof(*tx_beacon_cmd); |
193 | cmd.data = tx_beacon_cmd; | 189 | cmd.data[0] = tx_beacon_cmd; |
194 | 190 | cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; | |
195 | err = iwl_send_cmd_sync(priv, &cmd); | 191 | cmd.len[1] = frame_size; |
196 | 192 | cmd.data[1] = priv->beacon_skb->data; | |
197 | /* Free temporary storage */ | 193 | cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; |
198 | kfree(tx_beacon_cmd); | ||
199 | |||
200 | return err; | ||
201 | } | ||
202 | |||
203 | static 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 | 194 | ||
207 | dma_addr_t addr = get_unaligned_le32(&tb->lo); | 195 | return iwl_send_cmd_sync(priv, &cmd); |
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 | |||
215 | static 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 | |||
222 | static 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 | |||
237 | static 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 | */ | ||
250 | void 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 | |||
296 | int 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 | */ | ||
340 | int 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 | } | 196 | } |
351 | 197 | ||
352 | static void iwl_bg_beacon_update(struct work_struct *work) | 198 | static void iwl_bg_beacon_update(struct work_struct *work) |
@@ -1776,10 +1622,7 @@ static const char *desc_lookup(u32 num) | |||
1776 | 1622 | ||
1777 | void iwl_dump_nic_error_log(struct iwl_priv *priv) | 1623 | void iwl_dump_nic_error_log(struct iwl_priv *priv) |
1778 | { | 1624 | { |
1779 | u32 data2, line; | 1625 | u32 base; |
1780 | u32 desc, time, count, base, data1; | ||
1781 | u32 blink1, blink2, ilink1, ilink2; | ||
1782 | u32 pc, hcmd; | ||
1783 | struct iwl_error_event_table table; | 1626 | struct iwl_error_event_table table; |
1784 | 1627 | ||
1785 | base = priv->device_pointers.error_event_table; | 1628 | base = priv->device_pointers.error_event_table; |
@@ -1802,37 +1645,40 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) | |||
1802 | 1645 | ||
1803 | iwl_read_targ_mem_words(priv, base, &table, sizeof(table)); | 1646 | iwl_read_targ_mem_words(priv, base, &table, sizeof(table)); |
1804 | 1647 | ||
1805 | count = table.valid; | 1648 | if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { |
1806 | |||
1807 | if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { | ||
1808 | IWL_ERR(priv, "Start IWL Error Log Dump:\n"); | 1649 | IWL_ERR(priv, "Start IWL Error Log Dump:\n"); |
1809 | IWL_ERR(priv, "Status: 0x%08lX, count: %d\n", | 1650 | IWL_ERR(priv, "Status: 0x%08lX, count: %d\n", |
1810 | priv->status, count); | 1651 | priv->status, table.valid); |
1811 | } | 1652 | } |
1812 | 1653 | ||
1813 | desc = table.error_id; | 1654 | priv->isr_stats.err_code = table.error_id; |
1814 | priv->isr_stats.err_code = desc; | 1655 | |
1815 | pc = table.pc; | 1656 | trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low, |
1816 | blink1 = table.blink1; | 1657 | table.data1, table.data2, table.line, |
1817 | blink2 = table.blink2; | 1658 | table.blink1, table.blink2, table.ilink1, |
1818 | ilink1 = table.ilink1; | 1659 | table.ilink2, table.bcon_time, table.gp1, |
1819 | ilink2 = table.ilink2; | 1660 | table.gp2, table.gp3, table.ucode_ver, |
1820 | data1 = table.data1; | 1661 | table.hw_ver, table.brd_ver); |
1821 | data2 = table.data2; | 1662 | IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id, |
1822 | line = table.line; | 1663 | desc_lookup(table.error_id)); |
1823 | time = table.tsf_low; | 1664 | IWL_ERR(priv, "0x%08X | uPc\n", table.pc); |
1824 | hcmd = table.hcmd; | 1665 | IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1); |
1825 | 1666 | IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2); | |
1826 | trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line, | 1667 | IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1); |
1827 | blink1, blink2, ilink1, ilink2); | 1668 | IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2); |
1828 | 1669 | IWL_ERR(priv, "0x%08X | data1\n", table.data1); | |
1829 | IWL_ERR(priv, "Desc Time " | 1670 | IWL_ERR(priv, "0x%08X | data2\n", table.data2); |
1830 | "data1 data2 line\n"); | 1671 | IWL_ERR(priv, "0x%08X | line\n", table.line); |
1831 | IWL_ERR(priv, "%-28s (0x%04X) %010u 0x%08X 0x%08X %u\n", | 1672 | IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time); |
1832 | desc_lookup(desc), desc, time, data1, data2, line); | 1673 | IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low); |
1833 | IWL_ERR(priv, "pc blink1 blink2 ilink1 ilink2 hcmd\n"); | 1674 | IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi); |
1834 | IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X 0x%05X 0x%05X\n", | 1675 | IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1); |
1835 | pc, blink1, blink2, ilink1, ilink2, hcmd); | 1676 | IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2); |
1677 | IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3); | ||
1678 | IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver); | ||
1679 | IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver); | ||
1680 | IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver); | ||
1681 | IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd); | ||
1836 | } | 1682 | } |
1837 | 1683 | ||
1838 | #define EVENT_START_OFFSET (4 * sizeof(u32)) | 1684 | #define EVENT_START_OFFSET (4 * sizeof(u32)) |
@@ -2114,8 +1960,8 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg) | |||
2114 | struct iwl_calib_cfg_cmd calib_cfg_cmd; | 1960 | struct iwl_calib_cfg_cmd calib_cfg_cmd; |
2115 | struct iwl_host_cmd cmd = { | 1961 | struct iwl_host_cmd cmd = { |
2116 | .id = CALIBRATION_CFG_CMD, | 1962 | .id = CALIBRATION_CFG_CMD, |
2117 | .len = sizeof(struct iwl_calib_cfg_cmd), | 1963 | .len = { sizeof(struct iwl_calib_cfg_cmd), }, |
2118 | .data = &calib_cfg_cmd, | 1964 | .data = { &calib_cfg_cmd, }, |
2119 | }; | 1965 | }; |
2120 | 1966 | ||
2121 | memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd)); | 1967 | memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd)); |
@@ -3395,6 +3241,7 @@ static void iwl_uninit_drv(struct iwl_priv *priv) | |||
3395 | iwlcore_free_geos(priv); | 3241 | iwlcore_free_geos(priv); |
3396 | iwl_free_channel_map(priv); | 3242 | iwl_free_channel_map(priv); |
3397 | kfree(priv->scan_cmd); | 3243 | kfree(priv->scan_cmd); |
3244 | kfree(priv->beacon_cmd); | ||
3398 | } | 3245 | } |
3399 | 3246 | ||
3400 | struct ieee80211_ops iwlagn_hw_ops = { | 3247 | struct ieee80211_ops iwlagn_hw_ops = { |
@@ -3812,6 +3659,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) | |||
3812 | */ | 3659 | */ |
3813 | set_bit(STATUS_EXIT_PENDING, &priv->status); | 3660 | set_bit(STATUS_EXIT_PENDING, &priv->status); |
3814 | 3661 | ||
3662 | iwl_testmode_cleanup(priv); | ||
3815 | iwl_leds_exit(priv); | 3663 | iwl_leds_exit(priv); |
3816 | 3664 | ||
3817 | if (priv->mac80211_registered) { | 3665 | if (priv->mac80211_registered) { |