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