usb: grab urb sizes from driver

Instead of hardcoding the values, ask the driver for the supported sizes and
allocate the skb allocators accordingly.
This commit is contained in:
Alexander Boettcher 2013-03-19 11:50:59 +01:00 committed by Norman Feske
parent 9abf88c195
commit c95a6c54ea
1 changed files with 50 additions and 35 deletions

View File

@ -47,38 +47,46 @@ struct sk_buff *_alloc_skb(unsigned int size, bool tx = true);
/** /**
* Skb-bitmap allocator * Skb-bitmap allocator
*/ */
template <unsigned ENTRIES, unsigned BUFFER>
class Skb class Skb
{ {
private: private:
enum { unsigned const _entries;
IDX = ENTRIES / 32,
};
sk_buff _buf[ENTRIES]; sk_buff *_buf;
unsigned _free[ENTRIES / sizeof(unsigned)]; unsigned *_free;
unsigned _idx; unsigned _idx;
bool _wait_free; bool _wait_free;
enum { ENTRY_ELEMENT_SIZE = sizeof(_free[0]) * 8 };
public: public:
Skb() : _idx(0) Skb(unsigned const entries, unsigned const buffer_size)
:
_entries(entries), _idx(0)
{ {
Genode::memset(_free, 0xff, sizeof(_free)); unsigned const size = _entries / sizeof(_free[0]);
for (unsigned i = 0; i < ENTRIES; i++) _buf = new (Genode::env()->heap()) sk_buff[_entries];
_buf[i].start = (unsigned char *)kmalloc(BUFFER, GFP_NOIO); _free = new (Genode::env()->heap()) unsigned[size];
Genode::memset(_free, 0xff, size * sizeof(_free[0]));
for (unsigned i = 0; i < _entries; i++)
_buf[i].start = (unsigned char *)kmalloc(buffer_size, GFP_NOIO);
} }
sk_buff *alloc() sk_buff *alloc()
{ {
for (register int i = 0; i < IDX; i++) { unsigned const IDX = _entries / ENTRY_ELEMENT_SIZE;
for (register unsigned i = 0; i < IDX; i++) {
if (_free[_idx] != 0) { if (_free[_idx] != 0) {
unsigned msb = Genode::log2(_free[_idx]); unsigned msb = Genode::log2(_free[_idx]);
_free[_idx] ^= (1 << msb); _free[_idx] ^= (1 << msb);
sk_buff *r = &_buf[(_idx * 32) + msb]; sk_buff *r = &_buf[(_idx * ENTRY_ELEMENT_SIZE) + msb];
r->data = r->start; r->data = r->start;
r->phys = 0; r->phys = 0;
r->cloned = 0; r->cloned = 0;
@ -90,8 +98,9 @@ class Skb
} }
/* wait until some SKBs are fred */ /* wait until some SKBs are freed */
_wait_free = false; _wait_free = false;
PDBG("wait for free skbs ...");
_wait_event(_wait_free); _wait_event(_wait_free);
return alloc(); return alloc();
@ -100,36 +109,28 @@ class Skb
void free(sk_buff *buf) void free(sk_buff *buf)
{ {
unsigned entry = buf - &_buf[0]; unsigned entry = buf - &_buf[0];
if (&_buf[0] > buf || entry > ENTRIES) if (&_buf[0] > buf || entry > _entries)
return; return;
/* unblock waiting skb allocs */ /* unblock waiting skb allocs */
_wait_free = true; _wait_free = true;
_idx = entry / 32; _idx = entry / ENTRY_ELEMENT_SIZE;
_free[_idx] |= (1 << (entry % 32)); _free[_idx] |= (1 << (entry % ENTRY_ELEMENT_SIZE));
} }
}; };
/* smsc95xx.c */
enum { DEFAULT_HS_BURST_CAP_SIZE = 18944 };
/* send/receive skb type */
typedef Skb<50,DEFAULT_HS_BURST_CAP_SIZE> Tx_skb;
typedef Skb<32, DEFAULT_HS_BURST_CAP_SIZE> Rx_skb;
/* send/receive skb allocators */ /* send/receive skb allocators */
static Tx_skb *skb_tx() static Skb *skb_tx(unsigned const elements = 0, unsigned const buffer_size = 0)
{ {
static Tx_skb _skb; static Skb _skb(elements, buffer_size);
return &_skb; return &_skb;
} }
static Rx_skb *skb_rx() static Skb *skb_rx(unsigned const elements = 0, unsigned const buffer_size = 0)
{ {
static Rx_skb _skb; static Skb _skb(elements, buffer_size);
return &_skb; return &_skb;
} }
@ -149,18 +150,31 @@ class Nic_device : public Nic::Device
{ {
public: public:
struct net_device *_ndev; /* Linux-net device */ struct net_device *_ndev; /* Linux-net device */
fixup_t _tx_fixup; fixup_t _tx_fixup;
bool const _burst;
public: public:
Nic_device(struct net_device *ndev) : _ndev(ndev) Nic_device(struct net_device *ndev)
:
_ndev(ndev),
/* XXX should be configurable instead of guessing burst mode */
_burst(((usbnet *)netdev_priv(ndev))->rx_urb_size > 2048)
{ {
struct usbnet *dev = (usbnet *)netdev_priv(_ndev);
/* initialize skb allocators */
skb_rx(64, dev->rx_urb_size);
skb_tx(32, dev->rx_urb_size);
if (!burst()) return;
/* /*
* Retrieve 'tx_fixup' funcion from driver and set it to zero, so it * Retrieve 'tx_fixup' function from driver and set it to zero,
* cannot be called by the actual driver. * so it cannot be called by the actual driver. Required for
* burst mode.
*/ */
struct usbnet *dev = (usbnet *)netdev_priv(ndev);
_tx_fixup = dev->driver_info->tx_fixup; _tx_fixup = dev->driver_info->tx_fixup;
dev->driver_info->tx_fixup = 0; dev->driver_info->tx_fixup = 0;
} }
@ -194,7 +208,8 @@ class Nic_device : public Nic::Device
*/ */
sk_buff *alloc_skb() sk_buff *alloc_skb()
{ {
sk_buff *skb = _alloc_skb(18944); struct usbnet *dev = (usbnet *)netdev_priv(_ndev);
sk_buff *skb = _alloc_skb(dev->rx_urb_size);
skb->len = 0; skb->len = 0;
return skb; return skb;
} }
@ -259,7 +274,7 @@ class Nic_device : public Nic::Device
return m; return m;
} }
bool burst() { return true; } bool burst() { return _burst; }
}; };