Commit | Line | Data |
---|---|---|
ca97b838 BZ |
1 | /* |
2 | ************************************************************************* | |
3 | * Ralink Tech Inc. | |
4 | * 5F., No.36, Taiyuan St., Jhubei City, | |
5 | * Hsinchu County 302, | |
6 | * Taiwan, R.O.C. | |
7 | * | |
8 | * (c) Copyright 2002-2007, Ralink Technology, Inc. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify * | |
11 | * it under the terms of the GNU General Public License as published by * | |
12 | * the Free Software Foundation; either version 2 of the License, or * | |
13 | * (at your option) any later version. * | |
14 | * * | |
15 | * This program is distributed in the hope that it will be useful, * | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
18 | * GNU General Public License for more details. * | |
19 | * * | |
20 | * You should have received a copy of the GNU General Public License * | |
21 | * along with this program; if not, write to the * | |
22 | * Free Software Foundation, Inc., * | |
23 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |
24 | * * | |
25 | ************************************************************************* | |
26 | ||
27 | Module Name: | |
28 | rt_pci_rbus.c | |
29 | ||
30 | Abstract: | |
31 | Create and register network interface. | |
32 | ||
33 | Revision History: | |
6ccb5d7c JM |
34 | Who When What |
35 | Justin P. Mattock 11/07/2010 Fix a typo | |
ca97b838 BZ |
36 | -------- ---------- ---------------------------------------------- |
37 | */ | |
38 | ||
39 | #include "rt_config.h" | |
40 | #include <linux/pci.h> | |
41 | ||
42 | IRQ_HANDLE_TYPE rt2860_interrupt(int irq, void *dev_instance); | |
43 | ||
44 | static void rx_done_tasklet(unsigned long data); | |
45 | static void mgmt_dma_done_tasklet(unsigned long data); | |
46 | static void ac0_dma_done_tasklet(unsigned long data); | |
47 | static void ac1_dma_done_tasklet(unsigned long data); | |
48 | static void ac2_dma_done_tasklet(unsigned long data); | |
49 | static void ac3_dma_done_tasklet(unsigned long data); | |
50 | static void fifo_statistic_full_tasklet(unsigned long data); | |
51 | ||
ca97b838 BZ |
52 | /*---------------------------------------------------------------------*/ |
53 | /* Symbol & Macro Definitions */ | |
54 | /*---------------------------------------------------------------------*/ | |
9f548a2a BZ |
55 | #define RT2860_INT_RX_DLY (1<<0) /* bit 0 */ |
56 | #define RT2860_INT_TX_DLY (1<<1) /* bit 1 */ | |
57 | #define RT2860_INT_RX_DONE (1<<2) /* bit 2 */ | |
58 | #define RT2860_INT_AC0_DMA_DONE (1<<3) /* bit 3 */ | |
59 | #define RT2860_INT_AC1_DMA_DONE (1<<4) /* bit 4 */ | |
60 | #define RT2860_INT_AC2_DMA_DONE (1<<5) /* bit 5 */ | |
61 | #define RT2860_INT_AC3_DMA_DONE (1<<6) /* bit 6 */ | |
62 | #define RT2860_INT_HCCA_DMA_DONE (1<<7) /* bit 7 */ | |
63 | #define RT2860_INT_MGMT_DONE (1<<8) /* bit 8 */ | |
ca97b838 BZ |
64 | |
65 | #define INT_RX RT2860_INT_RX_DONE | |
66 | ||
9f548a2a BZ |
67 | #define INT_AC0_DLY (RT2860_INT_AC0_DMA_DONE) /*| RT2860_INT_TX_DLY) */ |
68 | #define INT_AC1_DLY (RT2860_INT_AC1_DMA_DONE) /*| RT2860_INT_TX_DLY) */ | |
69 | #define INT_AC2_DLY (RT2860_INT_AC2_DMA_DONE) /*| RT2860_INT_TX_DLY) */ | |
70 | #define INT_AC3_DLY (RT2860_INT_AC3_DMA_DONE) /*| RT2860_INT_TX_DLY) */ | |
71 | #define INT_HCCA_DLY (RT2860_INT_HCCA_DMA_DONE) /*| RT2860_INT_TX_DLY) */ | |
ca97b838 BZ |
72 | #define INT_MGMT_DLY RT2860_INT_MGMT_DONE |
73 | ||
ca97b838 BZ |
74 | /*************************************************************************** |
75 | * | |
76 | * Interface-depended memory allocation/Free related procedures. | |
77 | * Mainly for Hardware TxDesc/RxDesc/MgmtDesc, DMA Memory for TxData/RxData, etc., | |
78 | * | |
79 | **************************************************************************/ | |
9f548a2a | 80 | /* Function for TxDesc Memory allocation. */ |
62eb734b | 81 | void RTMP_AllocateTxDescMemory(struct rt_rtmp_adapter *pAd, |
51126deb BZ |
82 | u32 Index, |
83 | unsigned long Length, | |
66cd8d6e | 84 | IN BOOLEAN Cached, |
015ffcbe | 85 | void **VirtualAddress, |
8a10a546 | 86 | dma_addr_t *PhysicalAddress) |
ca97b838 | 87 | { |
8a10a546 | 88 | struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 89 | |
66cd8d6e | 90 | *VirtualAddress = |
51126deb | 91 | (void *)pci_alloc_consistent(pObj->pci_dev, sizeof(char) * Length, |
66cd8d6e | 92 | PhysicalAddress); |
ca97b838 BZ |
93 | |
94 | } | |
95 | ||
9f548a2a | 96 | /* Function for MgmtDesc Memory allocation. */ |
62eb734b | 97 | void RTMP_AllocateMgmtDescMemory(struct rt_rtmp_adapter *pAd, |
51126deb | 98 | unsigned long Length, |
66cd8d6e | 99 | IN BOOLEAN Cached, |
015ffcbe | 100 | void **VirtualAddress, |
8a10a546 | 101 | dma_addr_t *PhysicalAddress) |
ca97b838 | 102 | { |
8a10a546 | 103 | struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 104 | |
66cd8d6e | 105 | *VirtualAddress = |
51126deb | 106 | (void *)pci_alloc_consistent(pObj->pci_dev, sizeof(char) * Length, |
66cd8d6e | 107 | PhysicalAddress); |
ca97b838 BZ |
108 | |
109 | } | |
110 | ||
9f548a2a | 111 | /* Function for RxDesc Memory allocation. */ |
62eb734b | 112 | void RTMP_AllocateRxDescMemory(struct rt_rtmp_adapter *pAd, |
51126deb | 113 | unsigned long Length, |
66cd8d6e | 114 | IN BOOLEAN Cached, |
015ffcbe | 115 | void **VirtualAddress, |
8a10a546 | 116 | dma_addr_t *PhysicalAddress) |
ca97b838 | 117 | { |
8a10a546 | 118 | struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 119 | |
66cd8d6e | 120 | *VirtualAddress = |
51126deb | 121 | (void *)pci_alloc_consistent(pObj->pci_dev, sizeof(char) * Length, |
66cd8d6e | 122 | PhysicalAddress); |
ca97b838 BZ |
123 | |
124 | } | |
125 | ||
9f548a2a | 126 | /* Function for free allocated Desc Memory. */ |
62eb734b | 127 | void RTMP_FreeDescMemory(struct rt_rtmp_adapter *pAd, |
51126deb BZ |
128 | unsigned long Length, |
129 | void *VirtualAddress, | |
8a10a546 | 130 | dma_addr_t PhysicalAddress) |
ca97b838 | 131 | { |
8a10a546 | 132 | struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 133 | |
66cd8d6e BZ |
134 | pci_free_consistent(pObj->pci_dev, Length, VirtualAddress, |
135 | PhysicalAddress); | |
ca97b838 BZ |
136 | } |
137 | ||
9f548a2a | 138 | /* Function for TxData DMA Memory allocation. */ |
62eb734b | 139 | void RTMP_AllocateFirstTxBuffer(struct rt_rtmp_adapter *pAd, |
51126deb BZ |
140 | u32 Index, |
141 | unsigned long Length, | |
66cd8d6e | 142 | IN BOOLEAN Cached, |
015ffcbe | 143 | void **VirtualAddress, |
8a10a546 | 144 | dma_addr_t *PhysicalAddress) |
ca97b838 | 145 | { |
8a10a546 | 146 | struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 147 | |
66cd8d6e | 148 | *VirtualAddress = |
51126deb | 149 | (void *)pci_alloc_consistent(pObj->pci_dev, sizeof(char) * Length, |
66cd8d6e | 150 | PhysicalAddress); |
ca97b838 BZ |
151 | } |
152 | ||
62eb734b | 153 | void RTMP_FreeFirstTxBuffer(struct rt_rtmp_adapter *pAd, |
51126deb | 154 | unsigned long Length, |
66cd8d6e | 155 | IN BOOLEAN Cached, |
51126deb | 156 | void *VirtualAddress, |
8a10a546 | 157 | dma_addr_t PhysicalAddress) |
ca97b838 | 158 | { |
8a10a546 | 159 | struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 160 | |
66cd8d6e BZ |
161 | pci_free_consistent(pObj->pci_dev, Length, VirtualAddress, |
162 | PhysicalAddress); | |
ca97b838 BZ |
163 | } |
164 | ||
ca97b838 BZ |
165 | /* |
166 | * FUNCTION: Allocate a common buffer for DMA | |
167 | * ARGUMENTS: | |
168 | * AdapterHandle: AdapterHandle | |
169 | * Length: Number of bytes to allocate | |
170 | * Cached: Whether or not the memory can be cached | |
171 | * VirtualAddress: Pointer to memory is returned here | |
172 | * PhysicalAddress: Physical address corresponding to virtual address | |
173 | */ | |
62eb734b | 174 | void RTMP_AllocateSharedMemory(struct rt_rtmp_adapter *pAd, |
51126deb | 175 | unsigned long Length, |
66cd8d6e | 176 | IN BOOLEAN Cached, |
015ffcbe | 177 | void **VirtualAddress, |
8a10a546 | 178 | dma_addr_t *PhysicalAddress) |
ca97b838 | 179 | { |
8a10a546 | 180 | struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 181 | |
66cd8d6e | 182 | *VirtualAddress = |
51126deb | 183 | (void *)pci_alloc_consistent(pObj->pci_dev, sizeof(char) * Length, |
66cd8d6e | 184 | PhysicalAddress); |
ca97b838 BZ |
185 | } |
186 | ||
ca97b838 BZ |
187 | /* |
188 | * FUNCTION: Allocate a packet buffer for DMA | |
189 | * ARGUMENTS: | |
190 | * AdapterHandle: AdapterHandle | |
191 | * Length: Number of bytes to allocate | |
192 | * Cached: Whether or not the memory can be cached | |
193 | * VirtualAddress: Pointer to memory is returned here | |
194 | * PhysicalAddress: Physical address corresponding to virtual address | |
195 | * Notes: | |
196 | * Cached is ignored: always cached memory | |
197 | */ | |
62eb734b | 198 | void *RTMP_AllocateRxPacketBuffer(struct rt_rtmp_adapter *pAd, |
51126deb | 199 | unsigned long Length, |
66cd8d6e | 200 | IN BOOLEAN Cached, |
015ffcbe | 201 | void **VirtualAddress, |
8a10a546 | 202 | OUT dma_addr_t * |
66cd8d6e | 203 | PhysicalAddress) |
ca97b838 BZ |
204 | { |
205 | struct sk_buff *pkt; | |
206 | ||
207 | pkt = dev_alloc_skb(Length); | |
208 | ||
209 | if (pkt == NULL) { | |
66cd8d6e BZ |
210 | DBGPRINT(RT_DEBUG_ERROR, |
211 | ("can't allocate rx %ld size packet\n", Length)); | |
ca97b838 BZ |
212 | } |
213 | ||
214 | if (pkt) { | |
215 | RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); | |
51126deb | 216 | *VirtualAddress = (void *)pkt->data; |
66cd8d6e BZ |
217 | *PhysicalAddress = |
218 | PCI_MAP_SINGLE(pAd, *VirtualAddress, Length, -1, | |
219 | PCI_DMA_FROMDEVICE); | |
ca97b838 | 220 | } else { |
51126deb | 221 | *VirtualAddress = (void *)NULL; |
8a10a546 | 222 | *PhysicalAddress = (dma_addr_t)NULL; |
ca97b838 BZ |
223 | } |
224 | ||
8a10a546 | 225 | return (void *)pkt; |
ca97b838 BZ |
226 | } |
227 | ||
62eb734b | 228 | void Invalid_Remaining_Packet(struct rt_rtmp_adapter *pAd, unsigned long VirtualAddress) |
ca97b838 | 229 | { |
8a10a546 | 230 | dma_addr_t PhysicalAddress; |
ca97b838 | 231 | |
66cd8d6e BZ |
232 | PhysicalAddress = |
233 | PCI_MAP_SINGLE(pAd, (void *)(VirtualAddress + 1600), | |
234 | RX_BUFFER_NORMSIZE - 1600, -1, PCI_DMA_FROMDEVICE); | |
ca97b838 BZ |
235 | } |
236 | ||
62eb734b | 237 | int RtmpNetTaskInit(struct rt_rtmp_adapter *pAd) |
ca97b838 | 238 | { |
8a10a546 | 239 | struct os_cookie *pObj; |
ca97b838 | 240 | |
8a10a546 | 241 | pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 BZ |
242 | |
243 | tasklet_init(&pObj->rx_done_task, rx_done_tasklet, (unsigned long)pAd); | |
66cd8d6e BZ |
244 | tasklet_init(&pObj->mgmt_dma_done_task, mgmt_dma_done_tasklet, |
245 | (unsigned long)pAd); | |
246 | tasklet_init(&pObj->ac0_dma_done_task, ac0_dma_done_tasklet, | |
247 | (unsigned long)pAd); | |
248 | tasklet_init(&pObj->ac1_dma_done_task, ac1_dma_done_tasklet, | |
249 | (unsigned long)pAd); | |
250 | tasklet_init(&pObj->ac2_dma_done_task, ac2_dma_done_tasklet, | |
251 | (unsigned long)pAd); | |
252 | tasklet_init(&pObj->ac3_dma_done_task, ac3_dma_done_tasklet, | |
253 | (unsigned long)pAd); | |
ca97b838 | 254 | tasklet_init(&pObj->tbtt_task, tbtt_tasklet, (unsigned long)pAd); |
66cd8d6e BZ |
255 | tasklet_init(&pObj->fifo_statistic_full_task, |
256 | fifo_statistic_full_tasklet, (unsigned long)pAd); | |
ca97b838 BZ |
257 | |
258 | return NDIS_STATUS_SUCCESS; | |
259 | } | |
260 | ||
62eb734b | 261 | void RtmpNetTaskExit(struct rt_rtmp_adapter *pAd) |
ca97b838 | 262 | { |
8a10a546 | 263 | struct os_cookie *pObj; |
ca97b838 | 264 | |
8a10a546 | 265 | pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 BZ |
266 | |
267 | tasklet_kill(&pObj->rx_done_task); | |
268 | tasklet_kill(&pObj->mgmt_dma_done_task); | |
269 | tasklet_kill(&pObj->ac0_dma_done_task); | |
270 | tasklet_kill(&pObj->ac1_dma_done_task); | |
271 | tasklet_kill(&pObj->ac2_dma_done_task); | |
272 | tasklet_kill(&pObj->ac3_dma_done_task); | |
273 | tasklet_kill(&pObj->tbtt_task); | |
274 | tasklet_kill(&pObj->fifo_statistic_full_task); | |
275 | } | |
276 | ||
62eb734b | 277 | int RtmpMgmtTaskInit(struct rt_rtmp_adapter *pAd) |
ca97b838 BZ |
278 | { |
279 | ||
ca97b838 BZ |
280 | return NDIS_STATUS_SUCCESS; |
281 | } | |
282 | ||
ca97b838 BZ |
283 | /* |
284 | ======================================================================== | |
285 | Routine Description: | |
286 | Close kernel threads. | |
287 | ||
288 | Arguments: | |
289 | *pAd the raxx interface data pointer | |
290 | ||
291 | Return Value: | |
292 | NONE | |
293 | ||
294 | Note: | |
295 | ======================================================================== | |
296 | */ | |
62eb734b | 297 | void RtmpMgmtTaskExit(struct rt_rtmp_adapter *pAd) |
ca97b838 BZ |
298 | { |
299 | ||
ca97b838 BZ |
300 | return; |
301 | } | |
302 | ||
62eb734b | 303 | static inline void rt2860_int_enable(struct rt_rtmp_adapter *pAd, unsigned int mode) |
ca97b838 BZ |
304 | { |
305 | u32 regValue; | |
306 | ||
307 | pAd->int_disable_mask &= ~(mode); | |
308 | regValue = pAd->int_enable_reg & ~(pAd->int_disable_mask); | |
9f548a2a | 309 | /*if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) */ |
ca97b838 | 310 | { |
9f548a2a | 311 | RTMP_IO_WRITE32(pAd, INT_MASK_CSR, regValue); /* 1:enable */ |
ca97b838 | 312 | } |
9f548a2a BZ |
313 | /*else */ |
314 | /* DBGPRINT(RT_DEBUG_TRACE, ("fOP_STATUS_DOZE !\n")); */ | |
ca97b838 BZ |
315 | |
316 | if (regValue != 0) | |
317 | RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE); | |
318 | } | |
319 | ||
62eb734b | 320 | static inline void rt2860_int_disable(struct rt_rtmp_adapter *pAd, unsigned int mode) |
ca97b838 BZ |
321 | { |
322 | u32 regValue; | |
323 | ||
324 | pAd->int_disable_mask |= mode; | |
66cd8d6e | 325 | regValue = pAd->int_enable_reg & ~(pAd->int_disable_mask); |
9f548a2a | 326 | RTMP_IO_WRITE32(pAd, INT_MASK_CSR, regValue); /* 0: disable */ |
ca97b838 | 327 | |
66cd8d6e | 328 | if (regValue == 0) { |
ca97b838 BZ |
329 | RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE); |
330 | } | |
331 | } | |
332 | ||
ca97b838 BZ |
333 | /*************************************************************************** |
334 | * | |
335 | * tasklet related procedures. | |
336 | * | |
337 | **************************************************************************/ | |
338 | static void mgmt_dma_done_tasklet(unsigned long data) | |
339 | { | |
340 | unsigned long flags; | |
62eb734b | 341 | struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; |
66cd8d6e | 342 | INT_SOURCE_CSR_STRUC IntSource; |
8a10a546 | 343 | struct os_cookie *pObj; |
ca97b838 | 344 | |
9f548a2a BZ |
345 | /* Do nothing if the driver is starting halt state. */ |
346 | /* This might happen when timer already been fired before cancel timer with mlmehalt */ | |
66cd8d6e BZ |
347 | if (RTMP_TEST_FLAG |
348 | (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) | |
ca97b838 BZ |
349 | return; |
350 | ||
8a10a546 | 351 | pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 352 | |
9f548a2a | 353 | /* printk("mgmt_dma_done_process\n"); */ |
ca97b838 BZ |
354 | IntSource.word = 0; |
355 | IntSource.field.MgmtDmaDone = 1; | |
356 | pAd->int_pending &= ~INT_MGMT_DLY; | |
357 | ||
358 | RTMPHandleMgmtRingDmaDoneInterrupt(pAd); | |
359 | ||
6ccb5d7c | 360 | /* if you use RTMP_SEM_LOCK, sometimes kernel will hang up, without any */ |
9f548a2a | 361 | /* bug report output */ |
ca97b838 BZ |
362 | RTMP_INT_LOCK(&pAd->irq_lock, flags); |
363 | /* | |
364 | * double check to avoid lose of interrupts | |
365 | */ | |
66cd8d6e | 366 | if (pAd->int_pending & INT_MGMT_DLY) { |
ca97b838 BZ |
367 | tasklet_hi_schedule(&pObj->mgmt_dma_done_task); |
368 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
369 | return; | |
370 | } | |
371 | ||
372 | /* enable TxDataInt again */ | |
373 | rt2860_int_enable(pAd, INT_MGMT_DLY); | |
374 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
375 | } | |
376 | ||
ca97b838 BZ |
377 | static void rx_done_tasklet(unsigned long data) |
378 | { | |
379 | unsigned long flags; | |
62eb734b | 380 | struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; |
66cd8d6e | 381 | BOOLEAN bReschedule = 0; |
8a10a546 | 382 | struct os_cookie *pObj; |
ca97b838 | 383 | |
9f548a2a BZ |
384 | /* Do nothing if the driver is starting halt state. */ |
385 | /* This might happen when timer already been fired before cancel timer with mlmehalt */ | |
66cd8d6e BZ |
386 | if (RTMP_TEST_FLAG |
387 | (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) | |
ca97b838 BZ |
388 | return; |
389 | ||
8a10a546 | 390 | pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 BZ |
391 | |
392 | pAd->int_pending &= ~(INT_RX); | |
66cd8d6e | 393 | bReschedule = STARxDoneInterruptHandle(pAd, 0); |
ca97b838 BZ |
394 | |
395 | RTMP_INT_LOCK(&pAd->irq_lock, flags); | |
396 | /* | |
397 | * double check to avoid rotting packet | |
398 | */ | |
66cd8d6e | 399 | if (pAd->int_pending & INT_RX || bReschedule) { |
ca97b838 BZ |
400 | tasklet_hi_schedule(&pObj->rx_done_task); |
401 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
402 | return; | |
403 | } | |
404 | ||
51126deb | 405 | /* enable Rxint again */ |
ca97b838 BZ |
406 | rt2860_int_enable(pAd, INT_RX); |
407 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
408 | ||
409 | } | |
410 | ||
ca97b838 BZ |
411 | void fifo_statistic_full_tasklet(unsigned long data) |
412 | { | |
413 | unsigned long flags; | |
62eb734b | 414 | struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; |
8a10a546 | 415 | struct os_cookie *pObj; |
ca97b838 | 416 | |
9f548a2a BZ |
417 | /* Do nothing if the driver is starting halt state. */ |
418 | /* This might happen when timer already been fired before cancel timer with mlmehalt */ | |
66cd8d6e BZ |
419 | if (RTMP_TEST_FLAG |
420 | (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) | |
ca97b838 BZ |
421 | return; |
422 | ||
8a10a546 | 423 | pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 BZ |
424 | |
425 | pAd->int_pending &= ~(FifoStaFullInt); | |
426 | NICUpdateFifoStaCounters(pAd); | |
427 | ||
428 | RTMP_INT_LOCK(&pAd->irq_lock, flags); | |
429 | /* | |
430 | * double check to avoid rotting packet | |
431 | */ | |
66cd8d6e | 432 | if (pAd->int_pending & FifoStaFullInt) { |
ca97b838 BZ |
433 | tasklet_hi_schedule(&pObj->fifo_statistic_full_task); |
434 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
435 | return; | |
436 | } | |
437 | ||
51126deb | 438 | /* enable Rxint again */ |
ca97b838 BZ |
439 | |
440 | rt2860_int_enable(pAd, FifoStaFullInt); | |
441 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
442 | ||
443 | } | |
444 | ||
445 | static void ac3_dma_done_tasklet(unsigned long data) | |
446 | { | |
447 | unsigned long flags; | |
62eb734b | 448 | struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; |
66cd8d6e | 449 | INT_SOURCE_CSR_STRUC IntSource; |
8a10a546 | 450 | struct os_cookie *pObj; |
ca97b838 BZ |
451 | BOOLEAN bReschedule = 0; |
452 | ||
9f548a2a BZ |
453 | /* Do nothing if the driver is starting halt state. */ |
454 | /* This might happen when timer already been fired before cancel timer with mlmehalt */ | |
66cd8d6e BZ |
455 | if (RTMP_TEST_FLAG |
456 | (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) | |
ca97b838 BZ |
457 | return; |
458 | ||
8a10a546 | 459 | pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 460 | |
9f548a2a | 461 | /* printk("ac0_dma_done_process\n"); */ |
ca97b838 BZ |
462 | IntSource.word = 0; |
463 | IntSource.field.Ac3DmaDone = 1; | |
464 | pAd->int_pending &= ~INT_AC3_DLY; | |
465 | ||
466 | bReschedule = RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource); | |
467 | ||
468 | RTMP_INT_LOCK(&pAd->irq_lock, flags); | |
469 | /* | |
470 | * double check to avoid lose of interrupts | |
471 | */ | |
66cd8d6e | 472 | if ((pAd->int_pending & INT_AC3_DLY) || bReschedule) { |
ca97b838 BZ |
473 | tasklet_hi_schedule(&pObj->ac3_dma_done_task); |
474 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
475 | return; | |
476 | } | |
477 | ||
478 | /* enable TxDataInt again */ | |
479 | rt2860_int_enable(pAd, INT_AC3_DLY); | |
480 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
481 | } | |
482 | ||
ca97b838 BZ |
483 | static void ac2_dma_done_tasklet(unsigned long data) |
484 | { | |
485 | unsigned long flags; | |
62eb734b | 486 | struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; |
66cd8d6e | 487 | INT_SOURCE_CSR_STRUC IntSource; |
8a10a546 | 488 | struct os_cookie *pObj; |
ca97b838 BZ |
489 | BOOLEAN bReschedule = 0; |
490 | ||
9f548a2a BZ |
491 | /* Do nothing if the driver is starting halt state. */ |
492 | /* This might happen when timer already been fired before cancel timer with mlmehalt */ | |
66cd8d6e BZ |
493 | if (RTMP_TEST_FLAG |
494 | (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) | |
ca97b838 BZ |
495 | return; |
496 | ||
8a10a546 | 497 | pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 BZ |
498 | |
499 | IntSource.word = 0; | |
500 | IntSource.field.Ac2DmaDone = 1; | |
501 | pAd->int_pending &= ~INT_AC2_DLY; | |
502 | ||
503 | bReschedule = RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource); | |
504 | ||
505 | RTMP_INT_LOCK(&pAd->irq_lock, flags); | |
506 | ||
507 | /* | |
508 | * double check to avoid lose of interrupts | |
509 | */ | |
66cd8d6e | 510 | if ((pAd->int_pending & INT_AC2_DLY) || bReschedule) { |
ca97b838 BZ |
511 | tasklet_hi_schedule(&pObj->ac2_dma_done_task); |
512 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
513 | return; | |
514 | } | |
515 | ||
516 | /* enable TxDataInt again */ | |
517 | rt2860_int_enable(pAd, INT_AC2_DLY); | |
518 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
519 | } | |
520 | ||
ca97b838 BZ |
521 | static void ac1_dma_done_tasklet(unsigned long data) |
522 | { | |
523 | unsigned long flags; | |
62eb734b | 524 | struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; |
66cd8d6e | 525 | INT_SOURCE_CSR_STRUC IntSource; |
8a10a546 | 526 | struct os_cookie *pObj; |
ca97b838 BZ |
527 | BOOLEAN bReschedule = 0; |
528 | ||
9f548a2a BZ |
529 | /* Do nothing if the driver is starting halt state. */ |
530 | /* This might happen when timer already been fired before cancel timer with mlmehalt */ | |
66cd8d6e BZ |
531 | if (RTMP_TEST_FLAG |
532 | (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) | |
ca97b838 BZ |
533 | return; |
534 | ||
8a10a546 | 535 | pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 536 | |
9f548a2a | 537 | /* printk("ac0_dma_done_process\n"); */ |
ca97b838 BZ |
538 | IntSource.word = 0; |
539 | IntSource.field.Ac1DmaDone = 1; | |
540 | pAd->int_pending &= ~INT_AC1_DLY; | |
541 | ||
542 | bReschedule = RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource); | |
543 | ||
544 | RTMP_INT_LOCK(&pAd->irq_lock, flags); | |
545 | /* | |
546 | * double check to avoid lose of interrupts | |
547 | */ | |
66cd8d6e | 548 | if ((pAd->int_pending & INT_AC1_DLY) || bReschedule) { |
ca97b838 BZ |
549 | tasklet_hi_schedule(&pObj->ac1_dma_done_task); |
550 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
551 | return; | |
552 | } | |
553 | ||
554 | /* enable TxDataInt again */ | |
555 | rt2860_int_enable(pAd, INT_AC1_DLY); | |
556 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
557 | } | |
558 | ||
ca97b838 BZ |
559 | static void ac0_dma_done_tasklet(unsigned long data) |
560 | { | |
561 | unsigned long flags; | |
62eb734b | 562 | struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; |
66cd8d6e | 563 | INT_SOURCE_CSR_STRUC IntSource; |
8a10a546 | 564 | struct os_cookie *pObj; |
ca97b838 BZ |
565 | BOOLEAN bReschedule = 0; |
566 | ||
9f548a2a BZ |
567 | /* Do nothing if the driver is starting halt state. */ |
568 | /* This might happen when timer already been fired before cancel timer with mlmehalt */ | |
66cd8d6e BZ |
569 | if (RTMP_TEST_FLAG |
570 | (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) | |
ca97b838 BZ |
571 | return; |
572 | ||
8a10a546 | 573 | pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 574 | |
9f548a2a | 575 | /* printk("ac0_dma_done_process\n"); */ |
ca97b838 BZ |
576 | IntSource.word = 0; |
577 | IntSource.field.Ac0DmaDone = 1; | |
578 | pAd->int_pending &= ~INT_AC0_DLY; | |
579 | ||
9f548a2a | 580 | /* RTMPHandleMgmtRingDmaDoneInterrupt(pAd); */ |
ca97b838 BZ |
581 | bReschedule = RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource); |
582 | ||
583 | RTMP_INT_LOCK(&pAd->irq_lock, flags); | |
584 | /* | |
585 | * double check to avoid lose of interrupts | |
586 | */ | |
66cd8d6e | 587 | if ((pAd->int_pending & INT_AC0_DLY) || bReschedule) { |
ca97b838 BZ |
588 | tasklet_hi_schedule(&pObj->ac0_dma_done_task); |
589 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
590 | return; | |
591 | } | |
592 | ||
593 | /* enable TxDataInt again */ | |
594 | rt2860_int_enable(pAd, INT_AC0_DLY); | |
595 | RTMP_INT_UNLOCK(&pAd->irq_lock, flags); | |
596 | } | |
597 | ||
ca97b838 BZ |
598 | /*************************************************************************** |
599 | * | |
600 | * interrupt handler related procedures. | |
601 | * | |
602 | **************************************************************************/ | |
603 | int print_int_count; | |
604 | ||
605 | IRQ_HANDLE_TYPE rt2860_interrupt(int irq, void *dev_instance) | |
606 | { | |
66cd8d6e | 607 | struct net_device *net_dev = (struct net_device *)dev_instance; |
62eb734b | 608 | struct rt_rtmp_adapter *pAd = NULL; |
66cd8d6e | 609 | INT_SOURCE_CSR_STRUC IntSource; |
8a10a546 | 610 | struct os_cookie *pObj; |
ca97b838 BZ |
611 | |
612 | GET_PAD_FROM_NET_DEV(pAd, net_dev); | |
613 | ||
8a10a546 | 614 | pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 615 | |
ca97b838 | 616 | /* Note 03312008: we can not return here before |
66cd8d6e BZ |
617 | RTMP_IO_READ32(pAd, INT_SOURCE_CSR, &IntSource.word); |
618 | RTMP_IO_WRITE32(pAd, INT_SOURCE_CSR, IntSource.word); | |
619 | Or kernel will panic after ifconfig ra0 down sometimes */ | |
ca97b838 | 620 | |
9f548a2a | 621 | /* */ |
25985edc | 622 | /* Initial the Interrupt source. */ |
9f548a2a | 623 | /* */ |
ca97b838 | 624 | IntSource.word = 0x00000000L; |
9f548a2a BZ |
625 | /* McuIntSource.word = 0x00000000L; */ |
626 | ||
627 | /* */ | |
628 | /* Get the interrupt sources & saved to local variable */ | |
629 | /* */ | |
630 | /*RTMP_IO_READ32(pAd, where, &McuIntSource.word); */ | |
631 | /*RTMP_IO_WRITE32(pAd, , McuIntSource.word); */ | |
632 | ||
633 | /* */ | |
634 | /* Flag fOP_STATUS_DOZE On, means ASIC put to sleep, elase means ASICK WakeUp */ | |
635 | /* And at the same time, clock maybe turned off that say there is no DMA service. */ | |
636 | /* when ASIC get to sleep. */ | |
637 | /* To prevent system hang on power saving. */ | |
638 | /* We need to check it before handle the INT_SOURCE_CSR, ASIC must be wake up. */ | |
639 | /* */ | |
640 | /* RT2661 => when ASIC is sleeping, MAC register cannot be read and written. */ | |
641 | /* RT2860 => when ASIC is sleeping, MAC register can be read and written. */ | |
642 | /* if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) */ | |
ca97b838 BZ |
643 | { |
644 | RTMP_IO_READ32(pAd, INT_SOURCE_CSR, &IntSource.word); | |
9f548a2a | 645 | RTMP_IO_WRITE32(pAd, INT_SOURCE_CSR, IntSource.word); /* write 1 to clear */ |
ca97b838 | 646 | } |
9f548a2a BZ |
647 | /* else */ |
648 | /* DBGPRINT(RT_DEBUG_TRACE, (">>>fOP_STATUS_DOZE<<<\n")); */ | |
ca97b838 | 649 | |
9f548a2a BZ |
650 | /* RTMP_IO_READ32(pAd, INT_SOURCE_CSR, &IsrAfterClear); */ |
651 | /* RTMP_IO_READ32(pAd, MCU_INT_SOURCE_CSR, &McuIsrAfterClear); */ | |
652 | /* DBGPRINT(RT_DEBUG_INFO, ("====> RTMPHandleInterrupt(ISR=%08x,Mcu ISR=%08x, After clear ISR=%08x, MCU ISR=%08x)\n", */ | |
653 | /* IntSource.word, McuIntSource.word, IsrAfterClear, McuIsrAfterClear)); */ | |
ca97b838 | 654 | |
9f548a2a | 655 | /* Do nothing if Reset in progress */ |
66cd8d6e BZ |
656 | if (RTMP_TEST_FLAG |
657 | (pAd, | |
658 | (fRTMP_ADAPTER_RESET_IN_PROGRESS | | |
659 | fRTMP_ADAPTER_HALT_IN_PROGRESS))) { | |
660 | return IRQ_HANDLED; | |
ca97b838 | 661 | } |
9f548a2a BZ |
662 | /* */ |
663 | /* Handle interrupt, walk through all bits */ | |
664 | /* Should start from highest priority interrupt */ | |
665 | /* The priority can be adjust by altering processing if statement */ | |
666 | /* */ | |
ca97b838 BZ |
667 | |
668 | #ifdef DBG | |
669 | ||
670 | #endif | |
671 | ||
ca97b838 BZ |
672 | pAd->bPCIclkOff = FALSE; |
673 | ||
9f548a2a BZ |
674 | /* If required spinlock, each interrupt service routine has to acquire */ |
675 | /* and release itself. */ | |
676 | /* */ | |
ca97b838 | 677 | |
9f548a2a | 678 | /* Do nothing if NIC doesn't exist */ |
66cd8d6e BZ |
679 | if (IntSource.word == 0xffffffff) { |
680 | RTMP_SET_FLAG(pAd, | |
681 | (fRTMP_ADAPTER_NIC_NOT_EXIST | | |
682 | fRTMP_ADAPTER_HALT_IN_PROGRESS)); | |
683 | return IRQ_HANDLED; | |
ca97b838 BZ |
684 | } |
685 | ||
66cd8d6e | 686 | if (IntSource.word & TxCoherent) { |
ca97b838 BZ |
687 | DBGPRINT(RT_DEBUG_ERROR, (">>>TxCoherent<<<\n")); |
688 | RTMPHandleRxCoherentInterrupt(pAd); | |
689 | } | |
690 | ||
66cd8d6e | 691 | if (IntSource.word & RxCoherent) { |
ca97b838 BZ |
692 | DBGPRINT(RT_DEBUG_ERROR, (">>>RxCoherent<<<\n")); |
693 | RTMPHandleRxCoherentInterrupt(pAd); | |
694 | } | |
695 | ||
66cd8d6e BZ |
696 | if (IntSource.word & FifoStaFullInt) { |
697 | if ((pAd->int_disable_mask & FifoStaFullInt) == 0) { | |
ca97b838 BZ |
698 | /* mask FifoStaFullInt */ |
699 | rt2860_int_disable(pAd, FifoStaFullInt); | |
700 | tasklet_hi_schedule(&pObj->fifo_statistic_full_task); | |
701 | } | |
702 | pAd->int_pending |= FifoStaFullInt; | |
703 | } | |
704 | ||
66cd8d6e BZ |
705 | if (IntSource.word & INT_MGMT_DLY) { |
706 | if ((pAd->int_disable_mask & INT_MGMT_DLY) == 0) { | |
ca97b838 BZ |
707 | rt2860_int_disable(pAd, INT_MGMT_DLY); |
708 | tasklet_hi_schedule(&pObj->mgmt_dma_done_task); | |
709 | } | |
66cd8d6e | 710 | pAd->int_pending |= INT_MGMT_DLY; |
ca97b838 BZ |
711 | } |
712 | ||
66cd8d6e BZ |
713 | if (IntSource.word & INT_RX) { |
714 | if ((pAd->int_disable_mask & INT_RX) == 0) { | |
ca97b838 | 715 | |
51126deb | 716 | /* mask Rxint */ |
ca97b838 BZ |
717 | rt2860_int_disable(pAd, INT_RX); |
718 | tasklet_hi_schedule(&pObj->rx_done_task); | |
719 | } | |
720 | pAd->int_pending |= INT_RX; | |
721 | } | |
722 | ||
66cd8d6e | 723 | if (IntSource.word & INT_AC3_DLY) { |
ca97b838 | 724 | |
66cd8d6e | 725 | if ((pAd->int_disable_mask & INT_AC3_DLY) == 0) { |
ca97b838 BZ |
726 | /* mask TxDataInt */ |
727 | rt2860_int_disable(pAd, INT_AC3_DLY); | |
728 | tasklet_hi_schedule(&pObj->ac3_dma_done_task); | |
729 | } | |
730 | pAd->int_pending |= INT_AC3_DLY; | |
731 | } | |
732 | ||
66cd8d6e | 733 | if (IntSource.word & INT_AC2_DLY) { |
ca97b838 | 734 | |
66cd8d6e | 735 | if ((pAd->int_disable_mask & INT_AC2_DLY) == 0) { |
ca97b838 BZ |
736 | /* mask TxDataInt */ |
737 | rt2860_int_disable(pAd, INT_AC2_DLY); | |
738 | tasklet_hi_schedule(&pObj->ac2_dma_done_task); | |
739 | } | |
740 | pAd->int_pending |= INT_AC2_DLY; | |
741 | } | |
742 | ||
66cd8d6e | 743 | if (IntSource.word & INT_AC1_DLY) { |
ca97b838 BZ |
744 | |
745 | pAd->int_pending |= INT_AC1_DLY; | |
746 | ||
66cd8d6e | 747 | if ((pAd->int_disable_mask & INT_AC1_DLY) == 0) { |
ca97b838 BZ |
748 | /* mask TxDataInt */ |
749 | rt2860_int_disable(pAd, INT_AC1_DLY); | |
750 | tasklet_hi_schedule(&pObj->ac1_dma_done_task); | |
751 | } | |
752 | ||
753 | } | |
754 | ||
66cd8d6e | 755 | if (IntSource.word & INT_AC0_DLY) { |
ca97b838 BZ |
756 | |
757 | /* | |
758 | if (IntSource.word & 0x2) { | |
759 | u32 reg; | |
760 | RTMP_IO_READ32(pAd, DELAY_INT_CFG, ®); | |
761 | printk("IntSource.word = %08x, DELAY_REG = %08x\n", IntSource.word, reg); | |
762 | } | |
763 | */ | |
764 | pAd->int_pending |= INT_AC0_DLY; | |
765 | ||
66cd8d6e | 766 | if ((pAd->int_disable_mask & INT_AC0_DLY) == 0) { |
ca97b838 BZ |
767 | /* mask TxDataInt */ |
768 | rt2860_int_disable(pAd, INT_AC0_DLY); | |
769 | tasklet_hi_schedule(&pObj->ac0_dma_done_task); | |
770 | } | |
771 | ||
772 | } | |
773 | ||
66cd8d6e | 774 | if (IntSource.word & PreTBTTInt) { |
ca97b838 BZ |
775 | RTMPHandlePreTBTTInterrupt(pAd); |
776 | } | |
777 | ||
66cd8d6e | 778 | if (IntSource.word & TBTTInt) { |
ca97b838 BZ |
779 | RTMPHandleTBTTInterrupt(pAd); |
780 | } | |
781 | ||
782 | { | |
783 | if (IntSource.word & AutoWakeupInt) | |
784 | RTMPHandleTwakeupInterrupt(pAd); | |
785 | } | |
786 | ||
66cd8d6e | 787 | return IRQ_HANDLED; |
ca97b838 BZ |
788 | } |
789 | ||
790 | /* | |
6ccb5d7c | 791 | * invalid or writeback cache |
ca97b838 BZ |
792 | * and convert virtual address to physical address |
793 | */ | |
9fd453c9 BH |
794 | dma_addr_t linux_pci_map_single(struct rt_rtmp_adapter *pAd, void *ptr, |
795 | size_t size, int sd_idx, int direction) | |
ca97b838 | 796 | { |
8a10a546 | 797 | struct os_cookie *pObj; |
ca97b838 BZ |
798 | |
799 | /* | |
66cd8d6e BZ |
800 | ------ Porting Information ------ |
801 | > For Tx Alloc: | |
802 | mgmt packets => sd_idx = 0 | |
803 | SwIdx: pAd->MgmtRing.TxCpuIdx | |
804 | pTxD : pAd->MgmtRing.Cell[SwIdx].AllocVa; | |
805 | ||
806 | data packets => sd_idx = 1 | |
807 | TxIdx : pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx | |
808 | QueIdx: pTxBlk->QueIdx | |
809 | pTxD : pAd->TxRing[pTxBlk->QueIdx].Cell[TxIdx].AllocVa; | |
810 | ||
811 | > For Rx Alloc: | |
812 | sd_idx = -1 | |
813 | */ | |
ca97b838 | 814 | |
8a10a546 | 815 | pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 816 | |
66cd8d6e | 817 | if (sd_idx == 1) { |
62eb734b BZ |
818 | struct rt_tx_blk *pTxBlk; |
819 | pTxBlk = (struct rt_tx_blk *)ptr; | |
66cd8d6e BZ |
820 | return pci_map_single(pObj->pci_dev, pTxBlk->pSrcBufData, |
821 | pTxBlk->SrcBufLen, direction); | |
822 | } else { | |
ca97b838 BZ |
823 | return pci_map_single(pObj->pci_dev, ptr, size, direction); |
824 | } | |
825 | ||
826 | } | |
827 | ||
9fd453c9 BH |
828 | void linux_pci_unmap_single(struct rt_rtmp_adapter *pAd, dma_addr_t dma_addr, |
829 | size_t size, int direction) | |
ca97b838 | 830 | { |
8a10a546 | 831 | struct os_cookie *pObj; |
ca97b838 | 832 | |
8a10a546 | 833 | pObj = (struct os_cookie *)pAd->OS_Cookie; |
ca97b838 | 834 | |
e44fd1cf | 835 | pci_unmap_single(pObj->pci_dev, dma_addr, size, direction); |
ca97b838 BZ |
836 | |
837 | } |