[ Date Index ] [ Thread Index ] [ <= Previous by date / thread ] [ Next by date / thread => ]
Yes its perfectly feasable, its all gpl and on sourceforge in a cvs tree.
So I
can either post sections of offending code or you can have a browse of the tree directly. What is simplest?Offending code is probably easiest. I didn't get to bed last night and I'm not firing on all cylinders...
Ok here goes its quite a bit of code but it is the important bits. rt2x00_interrupt_rxdone is called from a master interupt handler that reads a bit mask on the device to determine what interrupt routine to fire, that (master handler) is protected with a spin_lock_irq_save() and spin_lock_irq_restore(). void rt2x00_interrupt_rxdone(struct _rt2x00_adapter *adapter) { struct _rxd rxd; u8 *dma = NULL; struct ieee802_11_hdr *header802_11 = NULL; struct sk_buff *skb = NULL; struct _skb_cb *skb_cb = NULL; spin_lock(&adapter->rx_lock); while(adapter->dma->rx_ring_done_index != adapter->dma->rx_ring_index){ dma = (u8*) adapter->dma->rx_ring[adapter->dma->rx_ring_index].data_addr; device_to_cpu(&rxd, adapter->dma->rx_ring[adapter->dma->rx_ring_index].desc_addr, sizeof(struct _rxd)); header802_11 = (struct ieee802_11_hdr*)dma; if(rxd.owner == DESC_OWNED_BY_NIC) break; /* If it is the first frame of multiple fragments allocate the maximum frame_size. */ if(header802_11->frame_ctl & IEEE802_11_FCTL_MOREFRAGS && !(header802_11->seq_ctl & IEEE802_11_SCTL_FRAG)) skb = dev_alloc_skb(MAX_PACKET_SIZE); else skb = dev_alloc_skb(rxd.data_byte_count + 2); if(!skb){ adapter->stats.rx_dropped++; /* Hand dma back to the adapter. */ rxd.owner = DESC_OWNED_BY_NIC; cpu_to_device(adapter->dma->rx_ring[adapter->dma->rx_ring_index].desc_addr, &rxd, sizeof(struct _rxd)); break; } skb_reserve(skb, 2); /* 16 byte align the IP header */ // code below seems to be illegal before skb_put // skb_cb = (struct _skb_cb*)skb->cb; // memset(skb_cb, 0x00, sizeof(struct _skb_cb)); // memcpy(&skb_cb->rxd, &rxd, sizeof(struct _rxd)); // skb_cb->header_length = IEEE802_11_HLEN; /* Copy entire frame to buffer. */ device_to_cpu(skb_put(skb, rxd.data_byte_count), dma, rxd.data_byte_count); /* Enqueue packet for processing. */ skb_queue_tail(&adapter->rx_packet_queue, skb); /* Hand dma back to the adapter. */ rxd.owner = DESC_OWNED_BY_NIC; cpu_to_device(adapter->dma->rx_ring[adapter->dma->rx_ring_index].desc_addr, &rxd, sizeof(struct _rxd)); /* Move to next packet in dma-> */ INCREASE_RING(adapter->dma->rx_ring_index, RX_RING_SIZE); } /* * Update the done index. * Make sure the rx done index is 1 lower then main index. * Also make sure to check for end of buffer. */ if(adapter->dma->rx_ring_index == 0) adapter->dma->rx_ring_done_index = RX_RING_SIZE; else adapter->dma->rx_ring_done_index = adapter->dma->rx_ring_index - 1; /* Schedule rx packet processing. */ if(!skb_queue_empty(&adapter->rx_packet_queue)) tasklet_schedule(&adapter->rx_tasklet); spin_unlock(&adapter->rx_lock); } That is the interupt handler, it *basicly* works although i believe the stuff with skn->cb to be illegal before a skb_put, so i am not running that at the moment (commented out as above). device_to_cpu and cpu_to_device are basicly a big/little end convertor for multiple ARCHS, for the moment it translates directly (in my cvs tree anyway) to a memcpy(); If i replace the tasklet_schedule with a *direct* call to the tasklet handler then all that code works. But left as is here the tasklets don't fire and a big crash is encountered at some point later. during the device init there is the following tasklet_init(&adapter->rx_tasklet, rt2x00_delayed_handle_rx, (unsigned long)adapter); and during net device up there is a tasklet_enable(&adapter->rx_tasklet); duing net device down/stop there is a tasklet_kill(&adapter->rx_tasklet); tasklet_disable(&adapter->rx_tasklet); The tasklet handler is void rt2x00_delayed_handle_rx(unsigned long data) { struct _rt2x00_adapter *adapter = (struct _rt2x00_adapter*) data; struct sk_buff *skb = NULL; spin_lock_bh(&adapter->rx_lock); while(!skb_queue_empty(&adapter->rx_packet_queue)){ if(!TEST_FLAG(adapter, ADAPTER_ENABLED)) break; /* We are not ready, abort sending packets. */ skb = skb_dequeue(&adapter->rx_packet_queue); skb->dev = adapter->net_dev; /* Packet comes from our device. */ skb->protocol = eth_type_trans(skb, adapter->net_dev); /* Update protocol. */ adapter->stats.rx_packets++; adapter->stats.rx_bytes += skb->len; if(((struct _skb_cb*)skb)->multicast) adapter->stats.multicast++; if(rt2x00_receive_packet(adapter, skb)){ /* Packet received succesfull. */ netif_rx(skb); /* Send packet to upper layer. */ adapter->net_dev->last_rx = jiffies; /* Update RX time. */ } else { /* Packet failed. */ adapter->stats.rx_errors++; /* Update error count. */ dev_kfree_skb_irq(skb); /* Release skb packet. */ } } spin_unlock_bh(&adapter->rx_lock); if(LINK_TYPE(adapter, IW_MODE_REPEAT) && !skb_queue_empty(&adapter->tx_packet_queue)) tasklet_schedule(&adapter->tx_tasklet); } -- Robin Cornelius --------------------------------------------------- robin@xxxxxxxxxxxxxxxxxxxxx http://www.cornelius.demon.co.uk http://sourceforge.net/projects/rt2400 GPG Key ID: 0x729A79A23B7EE764 http://www.biglumber.com/x/web?qs=0x729A79A23B7EE764
Attachment:
pgp00015.pgp
Description: PGP signature