Original 0.2.0pre6_plus_fixes_15 tarball
[acx-mac80211.git] / src / idma.c
blob076e6bd50cb55367175afe81d8a1dce8f348a581
1 /* src/idma.c - low level rx and tx management
3 * --------------------------------------------------------------------
5 * Copyright (C) 2003 ACX100 Open Source Project
7 * The contents of this file are subject to the Mozilla Public
8 * License Version 1.1 (the "License"); you may not use this file
9 * except in compliance with the License. You may obtain a copy of
10 * the License at http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * rights and limitations under the License.
17 * Alternatively, the contents of this file may be used under the
18 * terms of the GNU Public License version 2 (the "GPL"), in which
19 * case the provisions of the GPL are applicable instead of the
20 * above. If you wish to allow the use of your version of this file
21 * only under the terms of the GPL and not to allow others to use
22 * your version of this file under the MPL, indicate your decision
23 * by deleting the provisions above and replace them with the notice
24 * and other provisions required by the GPL. If you do not delete
25 * the provisions above, a recipient may use your version of this
26 * file under either the MPL or the GPL.
28 * --------------------------------------------------------------------
30 * Inquiries regarding the ACX100 Open Source Project can be
31 * made directly to:
33 * acx100-users@lists.sf.net
34 * http://acx100.sf.net
36 * --------------------------------------------------------------------
39 #include <linux/config.h>
40 #include <linux/version.h>
42 #include <linux/module.h>
43 #include <linux/kernel.h>
45 #include <linux/sched.h>
46 #include <linux/types.h>
47 #include <linux/skbuff.h>
48 #include <linux/slab.h>
49 #include <linux/proc_fs.h>
50 #include <linux/if_arp.h>
51 #include <linux/rtnetlink.h>
52 #include <linux/wireless.h>
53 #include <linux/netdevice.h>
55 #include <wlan_compat.h>
57 #include <linux/ioport.h>
58 #include <linux/pci.h>
59 #include <linux/pm.h>
61 #include <linux/dcache.h>
62 #include <linux/highmem.h>
63 #include <linux/sched.h>
64 #include <linux/skbuff.h>
65 #include <linux/etherdevice.h>
68 /*================================================================*/
69 /* Project Includes */
71 #include <version.h>
72 #include <p80211hdr.h>
73 #include <p80211mgmt.h>
74 #include <acx100_conv.h>
75 #include <acx100.h>
76 #include <p80211types.h>
77 #include <acx100_helper.h>
78 #include <acx100_helper2.h>
79 #include <idma.h>
80 #include <ihw.h>
81 #include <monitor.h>
83 /* these used to be increased to 32 each,
84 * but several people had memory allocation issues,
85 * so back to 16 again... */
86 #if (WLAN_HOSTIF==WLAN_USB)
87 #define TXBUFFERNO 10
88 #define RXBUFFERNO 10
89 #else
90 #define RXBUFFERNO 16
91 #define TXBUFFERNO 16
92 #endif
94 #define MINFREE_TX 3
95 spinlock_t tx_lock;
96 spinlock_t rx_lock;
98 #ifdef ACX_DEBUG
99 #if (WLAN_HOSTIF==WLAN_USB)
100 extern void acx100usb_dump_bytes(void *,int);
101 #endif
102 #endif
105 /*----------------------------------------------------------------
106 * acx100_enable_irq
109 * Arguments:
111 * Returns:
113 * Side effects:
115 * Call context:
117 * STATUS:
119 * Comment:
121 *----------------------------------------------------------------*/
123 void acx100_enable_irq(wlandevice_t * wlandev)
125 FN_ENTER;
126 #if (WLAN_HOSTIF!=WLAN_USB)
127 acx100_write_reg16(wlandev, wlandev->io[IO_ACX_IRQ_MASK], wlandev->irq_mask);
128 acx100_write_reg16(wlandev, wlandev->io[IO_ACX_FEMR], 0x8000);
129 #endif
130 FN_EXIT(0, 0);
133 /*----------------------------------------------------------------
134 * acx100_disable_irq
137 * Arguments:
139 * Returns:
141 * Side effects:
143 * Call context:
145 * STATUS:
147 * Comment:
149 *----------------------------------------------------------------*/
151 void acx100_disable_irq(wlandevice_t * wlandev)
153 FN_ENTER;
154 #if (WLAN_HOSTIF!=WLAN_USB)
155 acx100_write_reg16(wlandev, wlandev->io[IO_ACX_IRQ_MASK], 0x7fff);
156 acx100_write_reg16(wlandev, wlandev->io[IO_ACX_FEMR], 0x0);
157 #endif
158 FN_EXIT(0, 0);
161 /*----------------------------------------------------------------
162 * acx100_create_dma_regions
165 * Arguments:
167 * Returns:
169 * Side effects:
171 * Call context:
173 * STATUS:
175 * Comment:
177 *----------------------------------------------------------------*/
179 int acx100_create_dma_regions(wlandevice_t * wlandev)
181 QueueConfig_t qcfg;
182 /* FIXME: way too big to reside on the stack */
183 struct {
184 UINT16 val0x0[14];
185 UINT queue_start;
186 UINT val0x20;
187 UINT val0x24;
188 UINT val0x28;
189 UINT val0x2c;
190 } MemMap;
191 struct TIWLAN_DC *pDc;
193 FN_ENTER;
195 spin_lock_init(&rx_lock);
196 spin_lock_init(&tx_lock);
198 pDc = &wlandev->dc;
199 pDc->wlandev = wlandev;
201 /* FIXME: which memmap is read here, acx100_init_memory_pools did not get called yet ? */
202 /* read out the acx100 physical start address for the queues */
203 if (!acx100_interrogate(wlandev, &MemMap, ACX100_RID_MEMORY_MAP)) {
204 acxlog(L_BINSTD, "ctlMemoryMapRead returns error\n");
205 FN_EXIT(1, 2);
206 return 2;
209 /* # of items in Rx and Tx queues */
210 wlandev->TxQueueNo = TXBUFFERNO;
211 wlandev->RxQueueNo = RXBUFFERNO;
213 /* calculate size of queues */
214 qcfg.AreaSize = (sizeof(struct txdescriptor) * TXBUFFERNO +
215 sizeof(struct rxdescriptor) * RXBUFFERNO + 8);
216 qcfg.vale = 1; /* number of tx queues */
217 qcfg.valf1=RXBUFFERNO;
219 /* sets the beginning of the tx descriptor queue */
220 pDc->ui32ACXTxQueueStart = MemMap.queue_start;
221 qcfg.TxQueueStart = pDc->ui32ACXTxQueueStart;
222 qcfg.valj = 0;
223 qcfg.valk = TXBUFFERNO;
225 /* sets the beginning of the rx descriptor queue */
226 pDc->ui32ACXRxQueueStart = wlandev->TxQueueNo * sizeof(struct txdescriptor) + MemMap.queue_start;
227 qcfg.RxQueueStart = pDc->ui32ACXRxQueueStart;
228 qcfg.vald = 1;
230 /* sets the end of the rx descriptor queue */
231 qcfg.QueueEnd = wlandev->RxQueueNo * sizeof(struct rxdescriptor) + pDc->ui32ACXRxQueueStart;
233 /* sets the beginning of the next queue */
234 qcfg.QueueEnd2 = qcfg.QueueEnd + 8;
236 acxlog(L_BINDEBUG, "<== Initialize the Queue Indicator\n");
238 if (!acx100_configure_length(wlandev, &qcfg, ACX100_RID_QUEUE_CONFIG, sizeof(QueueConfig_t)-4)){ //0x14 + (qcfg.vale * 8))) {
239 acxlog(L_BINSTD, "ctlQueueConfigurationWrite returns error\n");
240 goto error;
243 if (acx100_create_tx_host_desc_queue(pDc)) {
244 acxlog(L_BINSTD, "acx100_create_tx_host_desc_queue returns error\n");
245 goto error;
247 if (acx100_create_rx_host_desc_queue(pDc)) {
248 acxlog(L_BINSTD, "acx100_create_rx_host_desc_queue returns error\n");
249 goto error;
251 acx100_create_tx_desc_queue(pDc);
252 acx100_create_rx_desc_queue(pDc);
253 if (!acx100_interrogate(wlandev, &MemMap, ACX100_RID_MEMORY_MAP)) {
254 acxlog(L_BINSTD, "Failed to read memory map\n");
255 goto error;
258 #if (WLAN_HOSTIF==WLAN_USB)
259 acxlog(L_DEBUG,"Memory Map before configure 1\n");
260 acx100usb_dump_bytes(&MemMap,44);
261 #endif
262 if (!acx100_configure(wlandev,&MemMap,ACX100_RID_MEMORY_MAP)) {
263 acxlog(L_BINSTD,"Failed to write memory map\n");
264 goto error;
268 /* FIXME: what does this do? name the fields */
269 /* start at least 4 bytes away from the end of the last pool */
270 MemMap.val0x24 = (MemMap.val0x20 + 0x1F + 4) & 0xffffffe0;
271 #if (WLAN_HOSTIF==WLAN_USB)
272 #ifdef ACX_DEBUG
273 acxlog(L_DEBUG,"Memory map before configure:\n");
274 acx100usb_dump_bytes(&MemMap,44);
275 #endif
276 #endif
278 if (!acx100_configure(wlandev, &MemMap, ACX100_RID_MEMORY_MAP)) {
279 acxlog(L_BINSTD, "ctlMemoryMapWrite returns error\n");
280 goto error;
283 if (!acx100_init_memory_pools(wlandev, (memmap_t *) &MemMap)) {
284 acxlog(L_BINSTD, "acx100_init_memory_pools returns error\n");
285 goto error;
288 #if THIS_IS_BOGUS_ISNT_IT
289 acx100_set_defaults(wlandev);
290 #endif
292 FN_EXIT(1, 0);
293 return 0;
295 error:
296 acx100_free_desc_queues(pDc);
298 FN_EXIT(1, 1);
299 return 1;
302 /*----------------------------------------------------------------
303 * acx100_delete_dma_region
306 * Arguments:
308 * Returns:
310 * Side effects:
312 * Call context:
314 * STATUS:
316 * Comment:
318 *----------------------------------------------------------------*/
320 int acx100_delete_dma_region(wlandevice_t * wlandev)
322 FN_ENTER;
323 #if (WLAN_HOSTIF!=WLAN_USB)
324 acx100_write_reg16(wlandev, wlandev->io[IO_ACX_ENABLE], 0);
326 /* used to be a for loop 1000, do scheduled delay instead */
327 acx100_schedule(HZ / 10);
328 #endif
329 acx100_free_desc_queues(&wlandev->dc);
331 FN_EXIT(0, 0);
332 return 0;
335 /*----------------------------------------------------------------
336 * acx100_dma_tx_data
339 * Arguments:
341 * Returns:
343 * Side effects:
345 * Call context:
347 * STATUS:
349 * Comment:
351 *----------------------------------------------------------------*/
353 void acx100_dma_tx_data(wlandevice_t *wlandev, struct txdescriptor *tx_desc)
355 struct txhostdescriptor *header;
356 struct txhostdescriptor *payload;
357 unsigned long flags;
358 int i;
360 FN_ENTER;
361 #if (WLAN_HOSTIF!=WLAN_USB)
362 /* header and payload are located in adjacent descriptors */
363 header = tx_desc->host_desc;
364 payload = tx_desc->host_desc + 1;
366 tx_desc->tx_time = jiffies;
368 tx_desc->Ctl |= wlandev->preamble_flag; /* set Preamble */
369 /* It seems as if the Preamble setting was actually REVERSED:
370 * bit 0 should most likely actually be ACTIVATED
371 * for Short Preamble, not the other way around as before!
372 * This caused many Tx error 0x20 errors with APs
373 * that don't support Long Preamble, since we were
374 * thinking we are setting Long Preamble, when in fact
375 * it was Short Preamble.
376 * The flag reversal theory has been sort of confirmed
377 * by throughput measurements:
378 * ~ 680K/s with flag disabled
379 * ~ 760K/s with flag enabled
382 /* set autodma and reclaim and 1st mpdu */
383 tx_desc->Ctl |= DESC_CTL_AUTODMA | DESC_CTL_RECLAIM | DESC_CTL_FIRST_MPDU;
385 /* set rate */
386 if (WLAN_GET_FC_FTYPE(((p80211_hdr_t*)header->data)->a3.fc) == WLAN_FTYPE_MGMT) {
387 tx_desc->rate = 20; /* 2Mbps for MGMT pkt compatibility */
388 } else {
389 tx_desc->rate = wlandev->bitrateval;
392 acxlog(L_XFER | L_DATA,
393 "Tx pkt (%s): len %i, hdr_len %i, pyld_len %i, mode %d, status %d\n",
394 acx100_get_packet_type_string(((p80211_hdr_t*)header->data)->a3.fc),
395 tx_desc->total_length,
396 header->length,
397 payload->length,
398 wlandev->mode,
399 wlandev->status);
401 acxlog(L_DATA, "802.11 header[%d]: ", header->length);
402 for (i = 0; i < header->length; i++)
403 acxlog(L_DATA, "%02x ", ((UINT8 *) header->data)[i]);
404 acxlog(L_DATA, "\n");
405 acxlog(L_DATA, "802.11 payload[%d]: ", payload->length);
406 for (i = 0; i < payload->length; i++)
407 acxlog(L_DATA, "%02x ", ((UINT8 *) payload->data)[i]);
408 acxlog(L_DATA, "\n");
410 spin_lock_irqsave(&tx_lock, flags);
412 /* sets Ctl DESC_CTL_FREE to zero telling that the descriptors are now owned by the acx100 */
413 header->Ctl &= (UINT16) ~DESC_CTL_FREE;
414 payload->Ctl &= (UINT16) ~DESC_CTL_FREE;
415 tx_desc->Ctl &= (UINT16) ~DESC_CTL_FREE;
417 acx100_write_reg16(wlandev, wlandev->io[IO_ACX_INT_TRIG], 0x4);
419 spin_unlock_irqrestore(&tx_lock, flags);
420 #endif
421 FN_EXIT(0, 0);
424 /*----------------------------------------------------------------
425 * acx100_log_txbuffer
428 * Arguments:
430 * Returns:
432 * Side effects:
434 * Call context:
436 * STATUS:
438 * Comment:
440 *----------------------------------------------------------------*/
442 void acx100_log_txbuffer(TIWLAN_DC *pDc)
444 unsigned int i;
445 txdesc_t *pTxDesc;
447 FN_ENTER;
448 for (i = 0; i < pDc->tx_pool_count; i++)
450 pTxDesc = &pDc->pTxDescQPool[i];
452 if ((pTxDesc->Ctl & DESC_CTL_DONE) == DESC_CTL_DONE)
453 acxlog(L_BUF, "txbuf %d done\n", i);
455 FN_EXIT(0, 0);
458 /*----------------------------------------------------------------
459 * acx100_clean_tx_desc
462 * Arguments:
464 * Returns:
466 * Side effects:
468 * Call context:
470 * STATUS:
472 * Comment:
473 * This function probably resets the txdescs' status when the ACX100
474 * signals the TX done IRQ (txdescs have been processed), starting with
475 * the pool index of the descriptor which we would use next,
476 * in order to make sure that we can be as fast as possible
477 * in filling new txdescs.
478 * Oops, now we have our own index, so everytime we get called we know
479 * where the next packet to be cleaned is.
480 * Hmm, still need to loop through the whole ring buffer now,
481 * since we lost sync for some reason when ping flooding or so...
482 * (somehow we don't get the IRQ for acx100_clean_tx_desc any more when
483 * too many packets are being sent!)
484 * FIXME: currently we only process one packet, but this gets out of
485 * sync for some reason when ping flooding, so we need to loop,
486 * but the previous smart loop implementation causes the ping latency
487 * to rise dramatically (~3000 ms), at least on CardBus PheeNet WL-0022.
488 * Dunno what to do :-\
490 *----------------------------------------------------------------*/
492 void acx100_clean_tx_desc(wlandevice_t *wlandev)
494 TIWLAN_DC *pDc = &wlandev->dc;
495 txdesc_t *pTxDesc;
496 UINT finger, watch;
497 unsigned long flags;
499 FN_ENTER;
501 acx100_log_txbuffer(pDc);
502 acxlog(L_BUF, "cleaning up Tx bufs from %d\n", pDc->tx_tail);
504 spin_lock_irqsave(&tx_lock, flags);
506 finger = pDc->tx_tail;
507 watch = finger;
509 do {
510 pTxDesc = &pDc->pTxDescQPool[finger];
512 /* check if txdesc is marked as "Tx finished" and "owned" */
513 if ((pTxDesc->Ctl & DESC_CTL_DONE) == DESC_CTL_DONE) {
515 acxlog(L_BUF, "cleaning %d\n", finger);
517 if (pTxDesc->error != 0) {
518 char *err;
520 switch(pTxDesc->error) {
521 case 0x10:
522 err = "MSDU lifetime timeout? - change 'iwconfig retry lifetime XXX'";
523 break;
524 case 0x20:
525 err = "maybe distance too high? - change 'iwconfig txpower XXX'";
526 break;
527 default:
528 err = "unknown error";
529 break;
531 acxlog(L_STD, "Tx error occurred (error 0x%02X)!! (%s)\n", pTxDesc->error, err);
532 wlandev->stats.tx_carrier_errors++;
533 wlandev->stats.tx_errors++;
536 /* free it */
537 pTxDesc->Ctl = DESC_CTL_FREE;
539 wlandev->TxQueueFree++;
541 if ((wlandev->TxQueueFree >= MINFREE_TX + 3)
542 && (wlandev->status == ISTATUS_4_ASSOCIATED)
543 && (netif_queue_stopped(wlandev->netdev)))
545 /* FIXME: if construct is ugly:
546 * should have functions acx100_stop_queue
547 * etc. which set flag wlandev->tx_stopped
548 * to be checked here. */
549 acxlog(L_XFER, "wake queue (avail. Tx desc %d).\n", wlandev->TxQueueFree);
550 netif_wake_queue(wlandev->netdev);
553 else
554 break;
556 /* update pointer for descr to be cleaned next */
557 finger = (finger + 1) % pDc->tx_pool_count;
558 } while (watch != finger);
560 /* remember last position */
561 pDc->tx_tail = finger;
563 spin_unlock_irqrestore(&tx_lock, flags);
565 FN_EXIT(0, 0);
566 return;
568 /*----------------------------------------------------------------
569 * acx100_rxmonitor
572 * Arguments:
574 * Returns:
576 * Side effects:
578 * Call context:
580 * STATUS:
582 * Comment:
584 *----------------------------------------------------------------*/
586 void acx100_rxmonitor(wlandevice_t * wlandev, struct rxbuffer *buf)
588 unsigned long *data = (unsigned long *)buf;
589 unsigned int packet_len = data[0] & 0xFFF;
590 int sig_strength = (data[1] >> 16) & 0xFF;
591 int sig_quality = (data[1] >> 24) & 0xFF;
592 p80211msg_lnxind_wlansniffrm_t *msg;
594 int payload_offset = 0;
595 unsigned int skb_len;
596 struct sk_buff *skb;
597 void *datap;
599 FN_ENTER;
601 if (!(wlandev->rx_config_1 & RX_CFG1_PLUS_ADDIT_HDR))
603 printk("rx_config_1 misses RX_CFG1_PLUS_ADDIT_HDR\n");
604 FN_EXIT(0, 0);
605 return;
608 if (wlandev->rx_config_1 & RX_CFG1_PLUS_ADDIT_HDR)
610 payload_offset += 3*4; /* status words */
611 packet_len += 3*4; /* length is w/o status */
614 if (wlandev->rx_config_1 & RX_CFG1_INCLUDE_ADDIT_HDR)
615 payload_offset += 4; /* phy header */
617 /* we are in big luck: the acx100 doesn't modify any of the fields */
618 /* in the 802.11-frame. just pass this packet into the PF_PACKET- */
619 /* subsystem. yeah. */
621 skb_len = packet_len - payload_offset;
623 if (wlandev->netdev->type == ARPHRD_IEEE80211_PRISM)
624 skb_len += sizeof(p80211msg_lnxind_wlansniffrm_t);
626 /* sanity check */
627 if (skb_len > (WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN))
629 printk("monitor mode panic: oversized frame!\n");
630 FN_EXIT(0, 0);
631 return;
634 /* allocate skb */
635 if ( (skb = dev_alloc_skb(skb_len)) == NULL)
637 printk("alloc_skb failed trying to allocate %d bytes\n", skb_len);
638 FN_EXIT(0, 0);
639 return;
642 skb_put(skb, skb_len);
644 /* when in raw 802.11 mode, just copy frame as-is */
645 if (wlandev->netdev->type == ARPHRD_IEEE80211)
646 datap = skb->data;
647 else /* otherwise, emulate prism header */
649 msg = (p80211msg_lnxind_wlansniffrm_t*)skb->data;
650 datap = msg + 1;
652 msg->msgcode = DIDmsg_lnxind_wlansniffrm;
653 msg->msglen = sizeof(p80211msg_lnxind_wlansniffrm_t);
654 strcpy(msg->devname, wlandev->netdev->name);
656 msg->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime;
657 msg->hosttime.status = 0;
658 msg->hosttime.len = 4;
659 msg->hosttime.data = jiffies;
661 msg->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime;
662 msg->mactime.status = 0;
663 msg->mactime.len = 4;
664 msg->mactime.data = data[2];
666 msg->channel.did = DIDmsg_lnxind_wlansniffrm_channel;
667 msg->channel.status = P80211ENUM_msgitem_status_no_value;
668 msg->channel.len = 4;
669 msg->channel.data = 0;
671 msg->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi;
672 msg->rssi.status = P80211ENUM_msgitem_status_no_value;
673 msg->rssi.len = 4;
674 msg->rssi.data = 0;
676 msg->sq.did = DIDmsg_lnxind_wlansniffrm_sq;
677 msg->sq.status = P80211ENUM_msgitem_status_no_value;
678 msg->sq.len = 4;
679 msg->sq.data = 0;
681 msg->signal.did = DIDmsg_lnxind_wlansniffrm_signal;
682 msg->signal.status = 0;
683 msg->signal.len = 4;
684 msg->signal.data = sig_quality;
686 msg->noise.did = DIDmsg_lnxind_wlansniffrm_noise;
687 msg->noise.status = 0;
688 msg->noise.len = 4;
689 msg->noise.data = sig_strength;
691 msg->rate.did = DIDmsg_lnxind_wlansniffrm_rate;
692 msg->rate.status = P80211ENUM_msgitem_status_no_value;
693 msg->rate.len = 4;
694 msg->rate.data = 0;
696 msg->istx.did = DIDmsg_lnxind_wlansniffrm_istx;
697 msg->istx.status = 0;
698 msg->istx.len = 4;
699 msg->istx.data = P80211ENUM_truth_false;
701 skb_len -= sizeof(p80211msg_lnxind_wlansniffrm_t);
703 msg->frmlen.did = DIDmsg_lnxind_wlansniffrm_signal;
704 msg->frmlen.status = 0;
705 msg->frmlen.len = 4;
706 msg->frmlen.data = skb_len;
709 memcpy(datap, ((unsigned char*)buf)+payload_offset, skb_len);
711 skb->dev = wlandev->netdev;
712 skb->dev->last_rx = jiffies;
714 skb->mac.raw = skb->data;
715 skb->ip_summed = CHECKSUM_NONE;
716 skb->pkt_type = PACKET_OTHERHOST;
717 skb->protocol = htons(ETH_P_80211_RAW);
719 wlandev->stats.rx_packets++;
720 wlandev->stats.rx_bytes += skb->len;
722 netif_rx(skb);
723 FN_EXIT(0, 0);
726 /*----------------------------------------------------------------
727 * acx100_log_rxbuffer
730 * Arguments:
732 * Returns:
734 * Side effects:
736 * Call context:
738 * STATUS:
740 * Comment:
742 *----------------------------------------------------------------*/
744 void acx100_log_rxbuffer(TIWLAN_DC *pDc)
746 unsigned int i;
747 struct rxhostdescriptor *pDesc;
749 FN_ENTER;
750 for (i = 0; i < pDc->rx_pool_count; i++)
752 pDesc = &pDc->pRxHostDescQPool[i];
753 #if (WLAN_HOSTIF==WLAN_USB)
754 acxlog(L_DEBUG,"rxbuf %d Ctl=%X val0x14=%X\n",i,pDesc->Ctl,pDesc->val0x14);
755 #endif
756 if ((pDesc->Ctl & DESC_CTL_FREE) && (pDesc->val0x14 < 0))
757 acxlog(L_BUF, "rxbuf %d full\n", i);
759 FN_EXIT(0, 0);
762 /*------------------------------------------------------------------------------
763 * acx100_process_rx_desc
765 * RX path top level entry point called directly and only from the IRQ handler
767 * Arguments:
769 * Returns:
771 * Side effects:
773 * Call context: Hard IRQ
775 * STATUS:
777 * Comment:
779 *----------------------------------------------------------------------------*/
780 void acx100_process_rx_desc(wlandevice_t *wlandev)
782 struct rxhostdescriptor *RxPool;
783 TIWLAN_DC *pDc;
784 struct rxhostdescriptor *pDesc;
785 UINT16 buf_len;
786 unsigned long flags;
787 int curr_idx;
788 unsigned int count = 0;
789 p80211_hdr_t *buf;
791 FN_ENTER;
793 pDc = &wlandev->dc;
794 acx100_log_rxbuffer(pDc);
796 /* there used to be entry count code here, but because this function is called
797 * by the interrupt handler, we are sure that this will only be entered once
798 * because the kernel locks the interrupt handler */
800 RxPool = pDc->pRxHostDescQPool;
802 /* First, have a loop to determine the first descriptor that's
803 * full, just in case there's a mismatch between our current
804 * rx_tail and the full descriptor we're supposed to handle. */
805 spin_lock_irqsave(&rx_lock, flags);
806 do {
807 count++;
808 if (count > pDc->rx_pool_count)
809 { /* hmm, no luck: all descriptors empty, bail out */
810 spin_unlock_irqrestore(&rx_lock, flags);
811 FN_EXIT(0, 0);
812 return;
814 curr_idx = pDc->rx_tail;
815 pDesc = &RxPool[pDc->rx_tail];
816 pDc->rx_tail = (pDc->rx_tail + 1) % pDc->rx_pool_count;
818 /* "pDesc->val0x14 < 0" is there to check whether MSB
819 * is set or not */
820 while (!((pDesc->Ctl & DESC_CTL_FREE) && (pDesc->val0x14 < 0))); /* check whether descriptor full, advance to next one if not */
821 spin_unlock_irqrestore(&rx_lock, flags);
823 while (1)
825 acxlog(L_BUF, "%s: using curr_idx %d, rx_tail is now %d\n", __func__, curr_idx, pDc->rx_tail);
827 buf = (p80211_hdr_t *)&pDesc->data->buf;
828 if (wlandev->rx_config_1 & RX_CFG1_INCLUDE_ADDIT_HDR) {
829 /* take into account additional header in front of packet */
830 buf = (p80211_hdr_t*)((UINT8*)buf + 4);
833 buf_len = pDesc->data->status & 0xfff; /* somelength */
834 if ((WLAN_GET_FC_FSTYPE(buf->a3.fc) != WLAN_FSTYPE_BEACON)
835 || (debug & L_XFER_BEACON))
836 acxlog(L_XFER|L_DATA, "Rx pkt %02d (%s): time %lu, len %i, signal %d, SNR %d, mode %d, status %d\n",
837 curr_idx,
838 acx100_get_packet_type_string(buf->a3.fc),
839 pDesc->data->time,
840 buf_len,
841 pDesc->data->level,
842 pDesc->data->snr,
843 wlandev->mode,
844 wlandev->status);
846 /* I tried to figure out how to map these levels to dBm
847 * values, but for the life of me I really didn't
848 * manage to get it. Either these values are not meant to
849 * be expressed in dBm, or it's some pretty complicated
850 * calculation. */
851 wlandev->wstats.qual.level = pDesc->data->level * 100 / 255;
852 wlandev->wstats.qual.noise = pDesc->data->snr * 100 / 255;
853 wlandev->wstats.qual.qual =
854 (wlandev->wstats.qual.noise <= 100) ?
855 100 - wlandev->wstats.qual.noise : 0;
856 wlandev->wstats.qual.updated = 7;
858 if (wlandev->monitor) {
859 acx100_rxmonitor(wlandev, pDesc->data);
860 } else if (buf_len >= 14) {
861 acx100_rx_ieee802_11_frame(wlandev, pDesc);
862 } else {
863 acxlog(L_DEBUG | L_XFER | L_DATA,
864 "NOT receiving packet (%s): size too small (%d)\n",
865 acx100_get_packet_type_string(buf->a3.fc), buf_len);
868 pDesc->Ctl &= ~DESC_CTL_FREE; /* Host no longer owns this */
869 pDesc->val0x14 = 0;
871 /* ok, descriptor is handled, now check the next descriptor */
872 spin_lock_irqsave(&rx_lock, flags);
873 curr_idx = pDc->rx_tail;
874 pDesc = &RxPool[pDc->rx_tail];
876 /* if next descriptor is empty, then bail out */
877 if (!((pDesc->Ctl & DESC_CTL_FREE) && (pDesc->val0x14 < 0)))
879 spin_unlock_irqrestore(&rx_lock, flags);
880 break;
882 else
884 pDc->rx_tail = (pDc->rx_tail + 1) % pDc->rx_pool_count;
885 spin_unlock_irqrestore(&rx_lock, flags);
888 FN_EXIT(0, 0);
891 /*----------------------------------------------------------------
892 * acx100_create_tx_host_desc_queue
895 * Arguments:
897 * Returns:
899 * Side effects:
901 * Call context:
903 * STATUS:
905 * Comment:
907 *----------------------------------------------------------------*/
909 int acx100_create_tx_host_desc_queue(TIWLAN_DC * pDc)
911 wlandevice_t *wlandev;
913 UINT i;
914 UINT align_offs;
915 UINT alignment;
917 struct framehdr *frame_hdr;
918 struct framehdr *frame_hdr_phy;
920 UINT8 *frame_payload;
921 UINT8 *frame_payload_phy;
923 struct txhostdescriptor *host_desc;
924 struct txhostdescriptor *host_desc_phy;
926 FN_ENTER;
928 wlandev = pDc->wlandev;
930 /* allocate TX header pool */
931 pDc->FrameHdrQPoolSize = (wlandev->TxQueueNo * sizeof(struct framehdr));
932 #if (WLAN_HOSTIF!=WLAN_USB)
933 if (!(pDc->pFrameHdrQPool =
934 pci_alloc_consistent(0, pDc->FrameHdrQPoolSize, &pDc->FrameHdrQPoolPhyAddr))) {
935 acxlog(L_BINSTD, "pDc->pFrameHdrQPool memory allocation error\n");
936 FN_EXIT(1, 2);
937 return 2;
939 acxlog(L_BINDEBUG, "pDc->pFrameHdrQPool = 0x%8x\n", (UINT) pDc->pFrameHdrQPool);
940 acxlog(L_BINDEBUG, "pDc->pFrameHdrQPoolPhyAddr = 0x%8x\n", (UINT) pDc->FrameHdrQPoolPhyAddr);
941 #else
942 if ((pDc->pFrameHdrQPool=kmalloc(pDc->FrameHdrQPoolSize,GFP_KERNEL))==NULL) {
943 acxlog(L_STD,"pDc->pFrameHdrQPool memory allocation error\n");
944 FN_EXIT(1,2);
945 return(2);
947 memset(pDc->pFrameHdrQPool,0,pDc->FrameHdrQPoolSize);
948 #endif
950 /* allocate TX payload pool */
951 pDc->TxBufferPoolSize = wlandev->TxQueueNo*2 * (WLAN_MAX_ETHFRM_LEN - WLAN_ETHHDR_LEN);
952 #if (WLAN_HOSTIF!=WLAN_USB)
953 if (!(pDc->pTxBufferPool =
954 pci_alloc_consistent(0, pDc->TxBufferPoolSize, &pDc->TxBufferPoolPhyAddr))) {
955 acxlog(L_BINSTD, "pDc->pTxBufferPool memory allocation error\n");
956 pci_free_consistent(0, pDc->FrameHdrQPoolSize,
957 pDc->pFrameHdrQPool,
958 pDc->FrameHdrQPoolPhyAddr);
959 FN_EXIT(1, 2);
960 return 2;
962 acxlog(L_BINDEBUG, "pDc->TxBufferPool = 0x%8x\n", (UINT) pDc->pTxBufferPool);
963 acxlog(L_BINDEBUG, "pDc->TxBufferPoolPhyAddr = 0x%8x\n", (UINT) pDc->TxBufferPoolPhyAddr);
964 #else
965 if ((pDc->pTxBufferPool=kmalloc(pDc->TxBufferPoolSize,GFP_KERNEL))==NULL) {
966 acxlog(L_STD,"pDc->pTxBufferPool memory allocation error\n");
967 kfree(pDc->pFrameHdrQPool);
968 FN_EXIT(1,2);
969 return(2);
971 memset(pDc->pTxBufferPool,0,pDc->TxBufferPoolSize);
972 #endif
974 /* allocate the TX host descriptor queue pool */
975 pDc->TxHostDescQPoolSize = wlandev->TxQueueNo*2 * sizeof(struct txhostdescriptor) + 3;
976 #if (WLAN_HOSTIF!=WLAN_USB)
977 if (!(pDc->pTxHostDescQPool =
978 pci_alloc_consistent(0, pDc->TxHostDescQPoolSize,
979 &pDc->TxHostDescQPoolPhyAddr))) {
980 acxlog(L_BINSTD, "Failed to allocate shared memory for TxHostDesc queue\n");
981 pci_free_consistent(0, pDc->FrameHdrQPoolSize,
982 pDc->pFrameHdrQPool,
983 pDc->FrameHdrQPoolPhyAddr);
984 pci_free_consistent(0, pDc->TxBufferPoolSize,
985 pDc->pTxBufferPool,
986 pDc->TxBufferPoolPhyAddr);
987 FN_EXIT(1, 2);
988 return 2;
990 acxlog(L_BINDEBUG, "pDc->pTxHostDescQPool = 0x%8x\n", (UINT) pDc->pTxHostDescQPool);
991 acxlog(L_BINDEBUG, "pDc->TxHostDescQPoolPhyAddr = 0x%8x\n", pDc->TxHostDescQPoolPhyAddr);
992 #else
993 if ((pDc->pTxHostDescQPool=kmalloc(pDc->TxHostDescQPoolSize,GFP_KERNEL))==NULL) {
994 acxlog(L_STD,"Failed to allocate memory for TxHostDesc queue\n");
995 kfree(pDc->pFrameHdrQPool);
996 kfree(pDc->pTxBufferPool);
997 FN_EXIT(1,2);
998 return(2);
1000 memset(pDc->pTxHostDescQPool,0,pDc->TxHostDescQPoolSize);
1001 #endif
1003 #if (WLAN_HOSTIF!=WLAN_USB)
1004 /* check for proper alignment of TX host descriptor pool */
1005 alignment = (UINT) pDc->pTxHostDescQPool & 3;
1006 if (alignment) {
1007 acxlog(L_BINSTD, "%s: TxHostDescQPool not aligned properly\n", __func__);
1008 align_offs = 4 - alignment;
1009 } else {
1010 align_offs = 0;
1013 host_desc = (struct txhostdescriptor *) ((UINT8 *) pDc->pTxHostDescQPool + align_offs);
1014 host_desc_phy = (struct txhostdescriptor *) ((UINT8 *) pDc->TxHostDescQPoolPhyAddr + align_offs);
1015 #else
1016 host_desc=(struct txhostdescriptor *)pDc->pTxHostDescQPool;
1017 #endif
1018 frame_hdr = (struct framehdr *) pDc->pFrameHdrQPool;
1019 #if (WLAN_HOSTIF!=WLAN_USB)
1020 frame_hdr_phy = (struct framehdr *) pDc->FrameHdrQPoolPhyAddr;
1021 #endif
1023 frame_payload = (UINT8 *) pDc->pTxBufferPool;
1024 #if (WLAN_HOSTIF!=WLAN_USB)
1025 frame_payload_phy = (UINT8 *) pDc->TxBufferPoolPhyAddr;
1026 #endif
1028 for (i = 0; i < wlandev->TxQueueNo*2 - 1; i++)
1030 if (!(i & 1)) {
1031 #if (WLAN_HOSTIF!=WLAN_USB)
1032 host_desc->data_phy = (UINT8 *) frame_hdr_phy;
1033 #endif
1034 host_desc->data = (UINT8 *) frame_hdr;
1035 #if (WLAN_HOSTIF!=WLAN_USB)
1036 frame_hdr_phy++;
1037 #endif
1038 frame_hdr++;
1039 #if (WLAN_HOSTIF!=WLAN_USB)
1040 host_desc->val0x10 = (struct txhostdescriptor *)((UINT8 *) host_desc_phy + sizeof(struct txhostdescriptor));
1041 #endif
1042 } else {
1043 #if (WLAN_HOSTIF!=WLAN_USB)
1044 host_desc->data_phy = (UINT8 *) frame_payload_phy;
1045 #endif
1046 host_desc->data = (UINT8 *) frame_payload;
1047 #if (WLAN_HOSTIF!=WLAN_USB)
1048 frame_payload_phy += WLAN_MAX_ETHFRM_LEN - WLAN_ETHHDR_LEN;
1049 #endif
1050 frame_payload += WLAN_MAX_ETHFRM_LEN - WLAN_ETHHDR_LEN;
1052 host_desc->val0x10 = NULL;
1055 host_desc->Ctl |= DESC_CTL_FREE;
1056 #if (WLAN_HOSTIF!=WLAN_USB)
1057 host_desc->desc_phy = host_desc_phy;
1058 host_desc->desc_phy_next = (struct txhostdescriptor *)((UINT8 *) host_desc_phy + sizeof(struct txhostdescriptor));
1059 #endif
1061 host_desc++;
1062 #if (WLAN_HOSTIF!=WLAN_USB)
1063 host_desc_phy++;
1064 #endif
1066 #if (WLAN_HOSTIF!=WLAN_USB)
1067 host_desc->data_phy = (UINT8 *) frame_payload_phy;
1068 #endif
1069 host_desc->data = (UINT8 *) frame_payload;
1070 host_desc->val0x10 = 0;
1072 host_desc->Ctl |= DESC_CTL_FREE;
1073 #if (WLAN_HOSTIF!=WLAN_USB)
1074 host_desc->desc_phy = host_desc_phy;
1075 host_desc->desc_phy_next = (struct txhostdescriptor *)((UINT8 *) pDc->TxHostDescQPoolPhyAddr + align_offs);
1076 #endif
1078 FN_EXIT(0, 0);
1079 return 0;
1082 /*----------------------------------------------------------------
1083 * acx100_create_rx_host_desc_queue
1086 * Arguments:
1088 * Returns:
1090 * Side effects:
1092 * Call context:
1094 * STATUS:
1096 * Comment:
1098 *----------------------------------------------------------------*/
1100 int acx100_create_rx_host_desc_queue(TIWLAN_DC * pDc)
1102 wlandevice_t *wlandev;
1104 UINT i;
1105 UINT align_offs;
1106 UINT alignment;
1108 struct rxbuffer *data;
1109 struct rxbuffer *data_phy;
1111 struct rxhostdescriptor *host_desc;
1112 struct rxhostdescriptor *host_desc_phy;
1114 int result = 0;
1116 FN_ENTER;
1118 wlandev = pDc->wlandev;
1120 /* allocate the RX host descriptor queue pool */
1121 pDc->RxHostDescQPoolSize = (wlandev->RxQueueNo * sizeof(struct rxhostdescriptor)) + 0x3;
1122 #if (WLAN_HOSTIF!=WLAN_USB)
1123 if ((pDc->pRxHostDescQPool =
1124 pci_alloc_consistent(0, pDc->RxHostDescQPoolSize,
1125 &pDc->RxHostDescQPoolPhyAddr)) == NULL) {
1126 acxlog(L_BINSTD,
1127 "Failed to allocate shared memory for RxHostDesc queue\n");
1128 result = 2;
1129 goto fail;
1131 #else
1132 if ((pDc->pRxHostDescQPool = kmalloc(pDc->RxHostDescQPoolSize,GFP_KERNEL))==NULL) {
1133 acxlog(L_STD,"Failed to allocate memory for RxHostDesc queue\n");
1134 result=2;
1135 goto fail;
1137 memset(pDc->pRxHostDescQPool,0,pDc->RxHostDescQPoolSize);
1138 #endif
1140 /* allocate RX buffer pool */
1141 pDc->RxBufferPoolSize = (wlandev->RxQueueNo * sizeof(struct rxbuffer));
1142 #if (WLAN_HOSTIF!=WLAN_USB)
1143 if ((pDc->pRxBufferPool =
1144 pci_alloc_consistent(0, pDc->RxBufferPoolSize,
1145 &pDc->RxBufferPoolPhyAddr)) == NULL) {
1146 acxlog(L_BINSTD, "Failed to allocate shared memory for Rx buffer\n");
1147 pci_free_consistent(0, pDc->RxHostDescQPoolSize,
1148 pDc->pRxHostDescQPool,
1149 pDc->RxHostDescQPoolPhyAddr);
1150 result = 2;
1151 goto fail;
1153 #else
1154 if ((pDc->pRxBufferPool = kmalloc(pDc->RxBufferPoolSize,GFP_KERNEL))==NULL) {
1155 acxlog(L_STD,"Failed to allocate memory for Rx buffer\n");
1156 result=2;
1157 goto fail;
1159 memset(pDc->pRxBufferPool,0,pDc->RxBufferPoolSize);
1160 #endif
1162 acxlog(L_BINDEBUG, "pDc->pRxHostDescQPool = 0x%8x\n", (UINT) pDc->pRxHostDescQPool);
1163 #if (WLAN_HOSTIF!=WLAN_USB)
1164 acxlog(L_BINDEBUG, "pDc->RxHostDescQPoolPhyAddr = 0x%8x\n", (UINT) pDc->RxHostDescQPoolPhyAddr);
1165 #endif
1166 acxlog(L_BINDEBUG, "pDc->pRxBufferPool = 0x%8x\n", (UINT) pDc->pRxBufferPool);
1167 #if (WLAN_HOSTIF!=WLAN_USB)
1168 acxlog(L_BINDEBUG, "pDc->RxBufferPoolPhyAddr = 0x%8x\n", (UINT) pDc->RxBufferPoolPhyAddr);
1169 #endif
1170 #if (WLAN_HOSTIF!=WLAN_USB)
1171 /* check for proper alignment of RX host descriptor pool */
1172 if ((alignment = ((UINT) pDc->pRxHostDescQPool) & 3)) {
1173 acxlog(L_BINSTD, "acx100_create_rx_host_desc_queue: RxHostDescQPool not aligned properly\n");
1174 align_offs = 4 - alignment;
1175 } else {
1176 align_offs = 0;
1179 host_desc = (struct rxhostdescriptor *) ((UINT8 *) pDc->pRxHostDescQPool + align_offs);
1180 host_desc_phy = (struct rxhostdescriptor *) ((UINT8 *) pDc->RxHostDescQPoolPhyAddr + align_offs);
1182 wlandev->RxHostDescPoolStart = host_desc_phy;
1183 #else
1184 host_desc = (struct rxhostdescriptor *)pDc->pRxHostDescQPool;
1185 #endif
1186 data = (struct rxbuffer *) pDc->pRxBufferPool;
1187 #if (WLAN_HOSTIF!=WLAN_USB)
1188 data_phy = (struct rxbuffer *) pDc->RxBufferPoolPhyAddr;
1189 #endif
1191 if (wlandev->RxQueueNo != 1) {
1192 for (i = 0; i < wlandev->RxQueueNo - 1; i++) {
1193 host_desc->data = data;
1194 #if (WLAN_HOSTIF!=WLAN_USB)
1195 host_desc->data_phy = data_phy;
1196 #endif
1197 host_desc->length = sizeof(struct rxbuffer);
1199 data++;
1200 #if (WLAN_HOSTIF!=WLAN_USB)
1201 data_phy++;
1202 #endif
1204 /* FIXME: what do these mean ? */
1205 host_desc->val0x28 = 2;
1206 host_desc->Ctl &= ~0x80;
1207 #if (WLAN_HOSTIF!=WLAN_USB)
1208 host_desc->desc_phy = host_desc_phy;
1209 host_desc->desc_phy_next = (struct rxhostdescriptor *)((UINT8 *) host_desc_phy + sizeof(struct rxhostdescriptor));
1210 #endif
1211 host_desc++;
1212 #if (WLAN_HOSTIF!=WLAN_USB)
1213 host_desc_phy++;
1214 #endif
1217 host_desc->data = data;
1218 #if (WLAN_HOSTIF!=WLAN_USB)
1219 host_desc->data_phy = data_phy;
1220 #endif
1221 host_desc->length = sizeof(struct rxbuffer);
1223 host_desc->val0x28 = 2;
1224 host_desc->Ctl &= 0xff7f;
1225 #if (WLAN_HOSTIF!=WLAN_USB)
1226 host_desc->desc_phy = host_desc_phy;
1227 host_desc->desc_phy_next = (struct rxhostdescriptor *)((UINT8 *) pDc->RxHostDescQPoolPhyAddr + align_offs);
1228 #endif
1229 result = 0;
1230 fail:
1231 FN_EXIT(1, result);
1232 return result;
1235 /*----------------------------------------------------------------
1236 * acx100_create_tx_desc_queue
1239 * Arguments:
1241 * Returns:
1243 * Side effects:
1245 * Call context:
1247 * STATUS:
1249 * Comment:
1251 *----------------------------------------------------------------*/
1253 void acx100_create_tx_desc_queue(TIWLAN_DC * pDc)
1255 wlandevice_t *wlandev;
1257 UINT32 mem_offs;
1258 UINT32 i;
1260 struct txdescriptor *tx_desc;
1261 struct txhostdescriptor *tx_hostdesc;
1263 UINT hostmemptr;
1265 FN_ENTER;
1267 wlandev = pDc->wlandev;
1268 pDc->tx_pool_count = wlandev->TxQueueNo;
1269 #if (WLAN_HOSTIF!=WLAN_USB)
1271 pDc->pTxDescQPool = (struct txdescriptor *) (wlandev->iobase2 +
1272 pDc->ui32ACXTxQueueStart);
1274 acxlog(L_BINDEBUG, "wlandev->iobase2 = 0x%08x\n", wlandev->iobase2);
1275 acxlog(L_BINDEBUG, "pDc->ui32ACXTxQueueStart = 0x%08x\n",
1276 pDc->ui32ACXTxQueueStart);
1277 acxlog(L_BINDEBUG, "pDc->pTxDescQPool = 0x%08x\n",
1278 (UINT) pDc->pTxDescQPool);
1279 #endif
1280 wlandev->TxQueueFree = wlandev->TxQueueNo;
1281 pDc->tx_head = 0;
1282 pDc->tx_tail = 0;
1283 #if (WLAN_HOSTIF!=WLAN_USB)
1284 mem_offs = pDc->ui32ACXTxQueueStart;
1285 tx_desc = pDc->pTxDescQPool;
1287 hostmemptr = pDc->TxHostDescQPoolPhyAddr;
1288 tx_hostdesc = (struct txhostdescriptor *) pDc->pTxHostDescQPool;
1290 /* loop over complete send pool */
1291 for (i = 0; i < pDc->tx_pool_count; i++) {
1292 memset(tx_desc, 0, sizeof(struct txdescriptor));
1293 /* pointer to hostdesc memory */
1294 tx_desc->HostMemPtr = hostmemptr;
1295 /* initialise ctl */
1296 tx_desc->Ctl = DESC_CTL_INIT;
1297 tx_desc->something2 = 0;
1298 /* point to next txdesc */
1299 tx_desc->pNextDesc = mem_offs + sizeof(struct txdescriptor);
1300 /* pointer to first txhostdesc */
1301 tx_desc->host_desc = tx_hostdesc;
1303 /* reserve two (hdr desc and payload desc) */
1304 tx_hostdesc += 2;
1305 hostmemptr += 2 * sizeof(struct txhostdescriptor);
1306 /* go to the next */
1307 mem_offs += sizeof(struct txdescriptor);
1308 tx_desc++;
1310 /* go to the last one */
1311 tx_desc--;
1312 /* and point to the first making it a ring buffer */
1313 tx_desc->pNextDesc = pDc->ui32ACXTxQueueStart;
1314 #endif
1315 FN_EXIT(0, 0);
1318 /*----------------------------------------------------------------
1319 * acx100_create_rx_desc_queue
1322 * Arguments:
1324 * Returns:
1326 * Side effects:
1328 * Call context:
1330 * STATUS:
1332 * Comment:
1334 *----------------------------------------------------------------*/
1336 void acx100_create_rx_desc_queue(TIWLAN_DC * pDc)
1338 wlandevice_t *wlandev;
1340 UINT32 mem_offs;
1341 UINT32 i;
1343 struct rxdescriptor *rx_desc;
1345 FN_ENTER;
1346 wlandev = pDc->wlandev;
1347 #if (WLAN_HOSTIF!=WLAN_USB)
1348 /* WHY IS IT "TxQueueNo" ? */
1349 pDc->pRxDescQPool = (struct rxdescriptor *) ((wlandev->TxQueueNo * sizeof(struct txdescriptor)) + (UINT8 *) pDc->pTxDescQPool);
1350 #endif
1351 pDc->rx_pool_count = wlandev->RxQueueNo;
1352 pDc->rx_tail = 0;
1353 #if (WLAN_HOSTIF!=WLAN_USB)
1354 mem_offs = pDc->ui32ACXRxQueueStart;
1355 rx_desc = (struct rxdescriptor *) pDc->pRxDescQPool;
1357 /* loop over complete receive pool */
1358 for (i = 0; i < pDc->rx_pool_count; i++) {
1359 memset(rx_desc, 0, sizeof(struct rxdescriptor));
1361 /* FIXME: what is this? is it a ctl field ? */
1362 rx_desc->val0x28 = 0xc;
1364 /* point to next rxdesc */
1365 rx_desc->pNextDesc = mem_offs + sizeof(struct rxdescriptor); // next rxdesc pNextDesc
1367 /* go to the next */
1368 mem_offs += sizeof(struct rxdescriptor);
1369 rx_desc++;
1371 /* go to the last one */
1372 rx_desc--;
1373 /* and point to the first making it a ring buffer */
1374 rx_desc->pNextDesc = pDc->ui32ACXRxQueueStart;
1375 #endif
1376 FN_EXIT(0, 0);
1379 /*----------------------------------------------------------------
1380 * acx100_free_desc_queues
1382 * Releases the queues that have been allocated, the
1383 * others have been initialised to NULL in acx100.c so this
1384 * function can be used if only part of the queues where
1385 * allocated.
1387 * Arguments:
1389 * Returns:
1391 * Side effects:
1393 * Call context:
1395 * STATUS:
1397 * Comment:
1399 *----------------------------------------------------------------*/
1401 void acx100_free_desc_queues(TIWLAN_DC * pDc)
1403 FN_ENTER;
1404 if (pDc->pRxHostDescQPool) {
1405 pci_free_consistent(0,
1406 pDc->TxHostDescQPoolSize,
1407 pDc->pTxHostDescQPool,
1408 pDc->TxHostDescQPoolPhyAddr);
1409 pDc->pTxHostDescQPool = NULL;
1410 pDc->TxHostDescQPoolSize = 0;
1412 if (pDc->pFrameHdrQPool) {
1413 pci_free_consistent(0, pDc->FrameHdrQPoolSize,
1414 pDc->pFrameHdrQPool,
1415 pDc->FrameHdrQPoolPhyAddr);
1416 pDc->pFrameHdrQPool = NULL;
1417 pDc->FrameHdrQPoolSize = 0;
1419 if (pDc->pTxBufferPool) {
1420 pci_free_consistent(0, pDc->TxBufferPoolSize,
1421 pDc->pTxBufferPool,
1422 pDc->TxBufferPoolPhyAddr);
1423 pDc->pTxBufferPool = NULL;
1424 pDc->TxBufferPoolSize = 0;
1427 pDc->pTxDescQPool = NULL;
1428 pDc->tx_pool_count = 0;
1430 if (pDc->pRxHostDescQPool) {
1431 pci_free_consistent(0, pDc->RxHostDescQPoolSize,
1432 pDc->pRxHostDescQPool,
1433 pDc->RxHostDescQPoolPhyAddr);
1434 pDc->pRxHostDescQPool = NULL;
1435 pDc->RxHostDescQPoolSize = 0;
1437 if (pDc->pRxBufferPool) {
1438 pci_free_consistent(0, pDc->RxBufferPoolSize,
1439 pDc->pRxBufferPool,
1440 pDc->RxBufferPoolPhyAddr);
1441 pDc->pRxBufferPool = NULL;
1442 pDc->RxBufferPoolSize = 0;
1445 pDc->pRxDescQPool = NULL;
1446 pDc->rx_pool_count = 0;
1447 FN_EXIT(0, 0);
1450 /*----------------------------------------------------------------
1451 * acx100_init_memory_pools
1454 * Arguments:
1456 * Returns:
1458 * Side effects:
1460 * Call context:
1462 * STATUS:
1464 * Comment:
1465 * FIXME: This function still needs a cleanup
1466 *----------------------------------------------------------------*/
1468 int acx100_init_memory_pools(wlandevice_t * wlandev, memmap_t * mmt)
1470 #if (WLAN_HOSTIF==WLAN_USB)
1471 UINT TotalMemoryBlocks; // var_40
1472 acx100usb_memmap_t *map;
1473 /* FIXME: is a memmap_t with ConfigWrite3 union type in it.
1474 * This ConfigWrite3 is specially made for this function
1475 * because vali and valj need to be UINT16's. Or am I
1476 * completely wrong
1477 * Actually, I think there needs to be 2 memmaps in this function- one
1478 * for the sizewrite and one for optionswrite
1480 struct {
1481 UINT16 val0x0;
1482 UINT16 val0x2;
1483 UINT16 size; // val0x4
1484 /* UINT16 val0x6;
1485 UINT32 val0x8; It's size only 4 + ACX100RID_BLOCK_SIZE_LEN = 6
1486 UINT32 val0xc; */
1487 } MemoryBlockSize; // var_3c
1489 struct {
1490 UINT16 rid;
1491 UINT16 length;
1492 UINT DMA_config; // val0x4
1493 struct rxhostdescriptor *val0x8;
1494 UINT val0xc; /* rx memory */
1495 UINT val0x10; /* tx memory */
1496 UINT16 TxBlockNum; // val0x14
1497 UINT16 RxBlockNum; // val0x16;
1498 } MemoryConfigOption; // var_2c
1500 FN_ENTER;
1501 map = (acx100usb_memmap_t *)mmt;
1502 #ifdef ACX_DEBUG
1503 acxlog(L_DEBUG,"Dump of Memory Map:\n");
1504 acx100usb_dump_bytes(mmt,44);
1505 #endif
1506 /* Let's see if we can follow this:
1507 first we select our memory block size (which I think is
1508 completely arbitrary) */
1509 MemoryBlockSize.size = wlandev->memblocksize;
1511 /* Then we alert the card to our decision of block size */
1512 if (!acx100_configure(wlandev, &MemoryBlockSize, ACX100_RID_BLOCK_SIZE)) {
1513 acxlog(L_BINSTD, "Ctl: MemoryBlockSizeWrite failed\n");
1514 return 0;
1517 /* We figure out how many total blocks we can create, using
1518 the block size we chose, and the beginning and ending
1519 memory pointers. IE. end-start/size */
1520 TotalMemoryBlocks = (map->PoolEnd-map->PoolStart) / wlandev->memblocksize;
1521 acxlog(L_DEBUG,"TotalMemoryBlocks=%d (%d bytes)\n",TotalMemoryBlocks,TotalMemoryBlocks*wlandev->memblocksize);
1523 /* This one I have no idea on */
1524 /* block-transfer=0x20000
1525 * indirect descriptors=0x10000
1527 MemoryConfigOption.DMA_config = 0x20000; //dma config
1528 /* Declare start of the Rx host pool */
1529 MemoryConfigOption.val0x8 = wlandev->RxHostDescPoolStart;
1531 /* 50% of the allotment of memory blocks go to tx descriptors */
1532 MemoryConfigOption.TxBlockNum = TotalMemoryBlocks / 2;
1533 /* and 50% go to the rx descriptors */
1534 MemoryConfigOption.RxBlockNum = TotalMemoryBlocks - MemoryConfigOption.TxBlockNum;
1536 /* in this block, we save the information we gleaned from the
1537 card into our wlandevice structure; # of tx desc blocks */
1538 wlandev->val0x24fc = MemoryConfigOption.TxBlockNum;
1539 /* # of rx desc blocks */
1540 wlandev->val0x24e4 = MemoryConfigOption.RxBlockNum;
1541 /* size of the tx and rx descriptor queues */
1542 wlandev->val0x2500 = MemoryConfigOption.TxBlockNum * wlandev->memblocksize;
1543 wlandev->val0x24e8 = MemoryConfigOption.RxBlockNum * wlandev->memblocksize;
1545 /* align the tx descriptor queue to an alignment of 0x20 (32 bytes) */
1546 MemoryConfigOption.val0xc = (map->PoolStart + 0x1f) & 0xffffffe0;
1547 /* align the rx descriptor queue to units of 0x20 and offset it
1548 by the tx descriptor queue */
1549 MemoryConfigOption.val0x10 =
1550 (0x1f + map->PoolStart + wlandev->val0x2500) & 0xffffffe0;
1552 /* alert the device to our decision */
1553 if (!acx100_configure(wlandev, &MemoryConfigOption, ACX100_RID_MEMORY_CONFIG_OPTIONS)) {
1554 return 0;
1556 /* and tell the device to kick it into gear */
1557 if (!acx100_issue_cmd(wlandev, ACX100_CMD_INIT_MEMORY, 0, 0, 5000)) {
1558 return 0;
1560 FN_EXIT(0, 0);
1561 return(1);
1562 #else
1563 /* the default PCI code */
1564 UINT TotalMemoryBlocks; // var_40
1565 /* FIXME: is a memmap_t with ConfigWrite3 union type in it.
1566 * This ConfigWrite3 is specially made for this function
1567 * because vali and valj need to be UINT16's. Or am I
1568 * completely wrong
1569 * Actually, I think there needs to be 2 memmaps in this function- one
1570 * for the sizewrite and one for optionswrite
1572 struct {
1573 UINT16 val0x0;
1574 UINT16 val0x2;
1575 UINT16 size; // val0x4
1576 /* UINT16 val0x6;
1577 UINT32 val0x8; It's size only 4 + ACX100RID_BLOCK_SIZE_LEN = 6
1578 UINT32 val0xc; */
1579 } MemoryBlockSize; // var_3c
1581 struct {
1582 UINT16 val0x0;
1583 UINT16 val0x2;
1584 UINT DMA_config; // val0x4
1585 struct rxhostdescriptor *val0x8;
1586 UINT val0xc;
1587 UINT val0x10;
1588 UINT16 TxBlockNum; // val0x14
1589 UINT16 RxBlockNum; // val0x16;
1590 } MemoryConfigOption; // var_2c
1592 FN_ENTER;
1594 /* Let's see if we can follow this:
1595 first we select our memory block size (which I think is
1596 completely arbitrary) */
1597 MemoryBlockSize.size = wlandev->memblocksize;
1599 /* Then we alert the card to our decision of block size */
1600 if (!acx100_configure(wlandev, &MemoryBlockSize, ACX100_RID_BLOCK_SIZE)) {
1601 acxlog(L_BINSTD, "Ctl: MemoryBlockSizeWrite failed\n");
1602 FN_EXIT(1, 0);
1603 return 0;
1606 /* We figure out how many total blocks we can create, using
1607 the block size we chose, and the beginning and ending
1608 memory pointers. IE. end-start/size */
1609 TotalMemoryBlocks = (mmt->m.cw2.val0x28 - mmt->m.cw2.vali) / wlandev->memblocksize;
1611 /* This one I have no idea on */
1612 MemoryConfigOption.DMA_config = 0x30000; //dma config
1613 /* Declare start of the Rx host pool */
1614 MemoryConfigOption.val0x8 = wlandev->RxHostDescPoolStart;
1616 /* 50% of the allotment of memory blocks go to tx descriptors */
1617 MemoryConfigOption.TxBlockNum = TotalMemoryBlocks / 2;
1618 /* and 50% go to the rx descriptors */
1619 MemoryConfigOption.RxBlockNum = TotalMemoryBlocks - MemoryConfigOption.TxBlockNum;
1621 /* in this block, we save the information we gleaned from the
1622 card into our wlandevice structure; # of tx desc blocks */
1623 wlandev->val0x24fc = MemoryConfigOption.TxBlockNum;
1624 /* # of rx desc blocks */
1625 wlandev->val0x24e4 = MemoryConfigOption.RxBlockNum;
1626 /* size of the tx and rx descriptor queues */
1627 wlandev->val0x2500 = MemoryConfigOption.TxBlockNum * wlandev->memblocksize;
1628 wlandev->val0x24e8 = MemoryConfigOption.RxBlockNum * wlandev->memblocksize;
1630 /* align the tx descriptor queue to an alignment of 0x20 (32 bytes) */
1631 MemoryConfigOption.val0xc = (mmt->m.cw2.vali + 0x1f) & 0xffffffe0;
1632 /* align the rx descriptor queue to units of 0x20 and offset it
1633 by the tx descriptor queue */
1634 MemoryConfigOption.val0x10 =
1635 (0x1f + mmt->m.cw2.vali + wlandev->val0x2500) & 0xffffffe0;
1637 /* alert the device to our decision */
1638 if (!acx100_configure(wlandev, &MemoryConfigOption, ACX100_RID_MEMORY_CONFIG_OPTIONS)) {
1639 FN_EXIT(1, 0);
1640 return 0;
1642 /* and tell the device to kick it into gear */
1643 if (!acx100_issue_cmd(wlandev, ACX100_CMD_INIT_MEMORY, 0, 0, 5000)) {
1644 FN_EXIT(1, 0);
1645 return 0;
1648 FN_EXIT(1, 1);
1649 return 1;
1650 #endif
1653 /*----------------------------------------------------------------
1654 * acx100_get_tx_desc
1657 * Arguments:
1659 * Returns:
1661 * Side effects:
1663 * Call context:
1665 * STATUS:
1667 * Comment:
1669 *----------------------------------------------------------------*/
1671 struct txdescriptor *acx100_get_tx_desc(wlandevice_t * wlandev)
1673 struct TIWLAN_DC * pDc = &wlandev->dc;
1674 struct txdescriptor *tx_desc;
1675 unsigned long flags;
1677 FN_ENTER;
1679 spin_lock_irqsave(&tx_lock, flags);
1681 tx_desc = &pDc->pTxDescQPool[pDc->tx_head];
1683 if ((tx_desc->Ctl & DESC_CTL_FREE) == 0) {
1684 /* whoops, descr at current index is not free, so probably
1685 * ring buffer already full */
1686 tx_desc = NULL;
1687 goto error;
1690 wlandev->TxQueueFree--;
1691 acxlog(L_BUF, "got Tx desc %d, %d remain.\n", pDc->tx_head, wlandev->TxQueueFree);
1694 * This comment is probably not entirely correct, needs further discussion
1695 * (restored commented-out code below to fix Tx ring buffer overflow,
1696 * since it's much better to have a slightly less efficiently used ring
1697 * buffer rather than one which easily overflows):
1699 * This doesn't do anything other than limit our maximum number of
1700 * buffers used at a single time (we might as well just declare
1701 * MINFREE_TX less descriptors when we open up.) We should just let it
1702 * slide here, and back off MINFREE_TX in acx100_clean_tx_desc, when given the
1703 * opportunity to let the queue start back up.
1705 if (wlandev->TxQueueFree < MINFREE_TX)
1707 acxlog(L_XFER, "stop queue (avail. Tx desc %d).\n", wlandev->TxQueueFree);
1708 netif_stop_queue(wlandev->netdev);
1711 /* returning current descriptor, so advance to next free one */
1712 pDc->tx_head = (pDc->tx_head + 1) % pDc->tx_pool_count;
1713 error:
1714 spin_unlock_irqrestore(&tx_lock, flags);
1716 FN_EXIT(0, (int)tx_desc);
1717 return tx_desc;
1720 static char type_string[32]; /* I *really* don't care that this is static,
1721 so don't complain, else... ;-) */
1723 /*----------------------------------------------------------------
1724 * acx100_get_packet_type_string
1727 * Arguments:
1729 * Returns:
1731 * Side effects:
1733 * Call context:
1735 * STATUS:
1737 * Comment:
1739 *----------------------------------------------------------------*/
1741 char *acx100_get_packet_type_string(UINT16 fc)
1743 char *ftype = "UNKNOWN", *fstype = "UNKNOWN";
1745 FN_ENTER;
1746 switch (WLAN_GET_FC_FTYPE(fc)) {
1747 case WLAN_FTYPE_MGMT:
1748 ftype = "MGMT";
1749 switch (WLAN_GET_FC_FSTYPE(fc)) {
1750 case WLAN_FSTYPE_ASSOCREQ:
1751 fstype = "AssocReq";
1752 break;
1753 case WLAN_FSTYPE_ASSOCRESP:
1754 fstype = "AssocResp";
1755 break;
1756 case WLAN_FSTYPE_REASSOCREQ:
1757 fstype = "ReassocReq";
1758 break;
1759 case WLAN_FSTYPE_REASSOCRESP:
1760 fstype = "ReassocResp";
1761 break;
1762 case WLAN_FSTYPE_PROBEREQ:
1763 fstype = "ProbeReq";
1764 break;
1765 case WLAN_FSTYPE_PROBERESP:
1766 fstype = "ProbeResp";
1767 break;
1768 case WLAN_FSTYPE_BEACON:
1769 fstype = "Beacon";
1770 break;
1771 case WLAN_FSTYPE_ATIM:
1772 fstype = "ATIM";
1773 break;
1774 case WLAN_FSTYPE_DISASSOC:
1775 fstype = "Disassoc";
1776 break;
1777 case WLAN_FSTYPE_AUTHEN:
1778 fstype = "Authen";
1779 break;
1780 case WLAN_FSTYPE_DEAUTHEN:
1781 fstype = "Deauthen";
1782 break;
1784 break;
1785 case WLAN_FTYPE_CTL:
1786 ftype = "CTL";
1787 switch (WLAN_GET_FC_FSTYPE(fc)) {
1788 case WLAN_FSTYPE_PSPOLL:
1789 fstype = "PSPoll";
1790 break;
1791 case WLAN_FSTYPE_RTS:
1792 fstype = "RTS";
1793 break;
1794 case WLAN_FSTYPE_CTS:
1795 fstype = "CTS";
1796 break;
1797 case WLAN_FSTYPE_ACK:
1798 fstype = "Ack";
1799 break;
1800 case WLAN_FSTYPE_CFEND:
1801 fstype = "CFEnd";
1802 break;
1803 case WLAN_FSTYPE_CFENDCFACK:
1804 fstype = "CFEndCFAck";
1805 break;
1807 break;
1808 case WLAN_FTYPE_DATA:
1809 ftype = "DATA";
1810 switch (WLAN_GET_FC_FSTYPE(fc)) {
1811 case WLAN_FSTYPE_DATAONLY:
1812 fstype = "DataOnly";
1813 break;
1814 case WLAN_FSTYPE_DATA_CFACK:
1815 fstype = "Data CFAck";
1816 break;
1817 case WLAN_FSTYPE_DATA_CFPOLL:
1818 fstype = "Data CFPoll";
1819 break;
1820 case WLAN_FSTYPE_DATA_CFACK_CFPOLL:
1821 fstype = "Data CFAck/CFPoll";
1822 break;
1823 case WLAN_FSTYPE_NULL:
1824 fstype = "Null";
1825 break;
1826 case WLAN_FSTYPE_CFACK:
1827 fstype = "CFAck";
1828 break;
1829 case WLAN_FSTYPE_CFPOLL:
1830 fstype = "CFPoll";
1831 break;
1832 case WLAN_FSTYPE_CFACK_CFPOLL:
1833 fstype = "CFAck/CFPoll";
1834 break;
1836 break;
1838 sprintf(type_string, "%s/%s", ftype, fstype);
1839 FN_EXIT(1, (int)type_string);
1840 return type_string;