[ 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