USB: Performance improvements

Added SKB bitmap allocator, use Nic::Packet_allocator in packet stream, use slab
allocators on top of back-end AVL allocator, split allocators in cached/uncached
for general purpose/DMA allocation, added patch to original code to distinguish
cached or uncached memory requests, take advantage of and implement TX bursts
(or SKB batching), call interrupt handlers until they return unhandled.
This commit is contained in:
Sebastian Sumpf 2012-08-03 18:32:51 +02:00 committed by Norman Feske
parent 8734eab6ac
commit 3207b4eed0
18 changed files with 1788 additions and 272 deletions

View File

@ -0,0 +1,664 @@
diff -r a83abb859b41 drivers/net/usb/smsc95xx.c
--- a/drivers/net/usb/smsc95xx.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/net/usb/smsc95xx.c Tue Aug 07 17:18:51 2012 +0200
@@ -65,7 +65,7 @@
static int smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data)
{
- u32 *buf = kmalloc(4, GFP_KERNEL);
+ u32 *buf = kmalloc(4, GFP_NOIO);
int ret;
BUG_ON(!dev);
@@ -90,7 +90,7 @@
static int smsc95xx_write_reg(struct usbnet *dev, u32 index, u32 data)
{
- u32 *buf = kmalloc(4, GFP_KERNEL);
+ u32 *buf = kmalloc(4, GFP_NOIO);
int ret;
BUG_ON(!dev);
@@ -328,7 +328,7 @@
return -ENOMEM;
}
- usb_context = kmalloc(sizeof(struct usb_context), GFP_ATOMIC);
+ usb_context = kmalloc(sizeof(struct usb_context), GFP_NOIO);
if (usb_context == NULL) {
netdev_warn(dev->net, "Error allocating control msg\n");
usb_free_urb(urb);
@@ -990,7 +990,7 @@
}
dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc95xx_priv),
- GFP_KERNEL);
+ GFP_NOIO);
pdata = (struct smsc95xx_priv *)(dev->data[0]);
if (!pdata) {
diff -r a83abb859b41 drivers/net/usb/usbnet.c
--- a/drivers/net/usb/usbnet.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/net/usb/usbnet.c Tue Aug 07 17:18:51 2012 +0200
@@ -201,7 +201,7 @@
period = max ((int) dev->status->desc.bInterval,
(dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3);
- buf = kmalloc (maxp, GFP_KERNEL);
+ buf = kmalloc (maxp, GFP_NOIO);
if (buf) {
dev->interrupt = usb_alloc_urb (0, GFP_KERNEL);
if (!dev->interrupt) {
@@ -1512,7 +1512,7 @@
if (!--dev->suspend_count) {
/* resume interrupt URBs */
if (dev->interrupt && test_bit(EVENT_DEV_OPEN, &dev->flags))
- usb_submit_urb(dev->interrupt, GFP_NOIO);
+ usb_submit_urb(dev->interrupt, GFP_KERNEL);
spin_lock_irq(&dev->txq.lock);
while ((res = usb_get_from_anchor(&dev->deferred))) {
diff -r a83abb859b41 drivers/usb/core/config.c
--- a/drivers/usb/core/config.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/core/config.c Tue Aug 07 17:18:51 2012 +0200
@@ -689,7 +689,7 @@
if (!dev->rawdescriptors)
goto err2;
- desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
+ desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_NOIO);
if (!desc)
goto err2;
@@ -716,7 +716,7 @@
USB_DT_CONFIG_SIZE);
/* Now that we know the length, get the whole thing */
- bigbuffer = kmalloc(length, GFP_KERNEL);
+ bigbuffer = kmalloc(length, GFP_NOIO);
if (!bigbuffer) {
result = -ENOMEM;
goto err;
diff -r a83abb859b41 drivers/usb/core/devices.c
--- a/drivers/usb/core/devices.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/core/devices.c Tue Aug 07 17:18:51 2012 +0200
@@ -505,7 +505,7 @@
return 0;
/* allocate 2^1 pages = 8K (on i386);
* should be more than enough for one device */
- pages_start = (char *)__get_free_pages(GFP_NOIO, 1);
+ pages_start = (char *)__get_free_pages(GFP_KERNEL, 1);
if (!pages_start)
return -ENOMEM;
diff -r a83abb859b41 drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/core/hub.c Tue Aug 07 17:18:51 2012 +0200
@@ -740,7 +740,7 @@
hcd = bus_to_hcd(hdev->bus);
if (hcd->driver->update_hub_device) {
ret = hcd->driver->update_hub_device(hcd, hdev,
- &hub->tt, GFP_NOIO);
+ &hub->tt, GFP_KERNEL);
if (ret < 0) {
dev_err(hub->intfdev, "Host not "
"accepting hub info "
@@ -879,7 +879,7 @@
init3:
hub->quiescing = 0;
- status = usb_submit_urb(hub->urb, GFP_NOIO);
+ status = usb_submit_urb(hub->urb, GFP_KERNEL);
if (status < 0)
dev_err(hub->intfdev, "activate --> %d\n", status);
if (hub->has_indicators && blinkenlights)
@@ -968,20 +968,21 @@
int maxp, ret;
char *message = "out of memory";
- hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);
+ hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_NOIO);
if (!hub->buffer) {
ret = -ENOMEM;
goto fail;
}
- hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
+ hub->status = kmalloc(sizeof(*hub->status), GFP_NOIO);
if (!hub->status) {
ret = -ENOMEM;
goto fail;
}
mutex_init(&hub->status_mutex);
- hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
+ hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_NOIO);
+ printk("Alloc hub desc: %p\n", hub->descriptor);
if (!hub->descriptor) {
ret = -ENOMEM;
goto fail;
@@ -3790,7 +3791,7 @@
len = max(len, old_length);
}
- buf = kmalloc(len, GFP_NOIO);
+ buf = kmalloc(len, GFP_KERNEL);
if (buf == NULL) {
dev_err(&udev->dev, "no mem to re-read configs after reset\n");
/* assume the worst */
diff -r a83abb859b41 drivers/usb/core/message.c
--- a/drivers/usb/core/message.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/core/message.c Tue Aug 07 17:18:51 2012 +0200
@@ -50,7 +50,7 @@
init_completion(&ctx.done);
urb->context = &ctx;
urb->actual_length = 0;
- retval = usb_submit_urb(urb, GFP_NOIO);
+ retval = usb_submit_urb(urb, GFP_KERNEL);
if (unlikely(retval))
goto out;
@@ -87,7 +87,7 @@
int retv;
int length;
- urb = usb_alloc_urb(0, GFP_NOIO);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
@@ -866,11 +866,11 @@
if (index <= 0)
return NULL;
- buf = kmalloc(MAX_USB_STRING_SIZE, GFP_NOIO);
+ buf = kmalloc(MAX_USB_STRING_SIZE, GFP_KERNEL);
if (buf) {
len = usb_string(udev, index, buf, MAX_USB_STRING_SIZE);
if (len > 0) {
- smallbuf = kmalloc(++len, GFP_NOIO);
+ smallbuf = kmalloc(++len, GFP_KERNEL);
if (!smallbuf)
return buf;
memcpy(smallbuf, buf, len);
@@ -941,7 +941,7 @@
int usb_get_status(struct usb_device *dev, int type, int target, void *data)
{
int ret;
- u16 *status = kmalloc(sizeof(*status), GFP_KERNEL);
+ u16 *status = kmalloc(sizeof(*status), GFP_NOIO);
if (!status)
return -ENOMEM;
@@ -1713,7 +1713,7 @@
if (cp) {
nintf = cp->desc.bNumInterfaces;
new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),
- GFP_NOIO);
+ GFP_KERNEL);
if (!new_interfaces) {
dev_err(&dev->dev, "Out of memory\n");
return -ENOMEM;
@@ -1722,7 +1722,7 @@
for (; n < nintf; ++n) {
new_interfaces[n] = kzalloc(
sizeof(struct usb_interface),
- GFP_NOIO);
+ GFP_KERNEL);
if (!new_interfaces[n]) {
dev_err(&dev->dev, "Out of memory\n");
ret = -ENOMEM;
diff -r a83abb859b41 drivers/usb/core/urb.c
--- a/drivers/usb/core/urb.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/core/urb.c Tue Aug 07 17:18:51 2012 +0200
@@ -266,7 +266,7 @@
*
* The general rules for how to decide which mem_flags to use
* are the same as for kmalloc. There are four
- * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and
+ * different possible values; GFP_KERNEL, GFP_NOFS, GFP_KERNEL and
* GFP_ATOMIC.
*
* GFP_NOFS is not ever used, as it has not been implemented yet.
@@ -279,7 +279,7 @@
* (c) current->state != TASK_RUNNING, this is the case only after
* you've changed it.
*
- * GFP_NOIO is used in the block io path and error handling of storage
+ * GFP_KERNEL is used in the block io path and error handling of storage
* devices.
*
* All other situations use GFP_KERNEL.
@@ -290,12 +290,12 @@
* (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also
* called with a spinlock held);
* (3) If you use a kernel thread with a network driver you must use
- * GFP_NOIO, unless (b) or (c) apply;
+ * GFP_KERNEL, unless (b) or (c) apply;
* (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c)
* apply or your are in a storage driver's block io path;
* (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and
* (6) changing firmware on a running storage or net device uses
- * GFP_NOIO, unless b) or c) apply
+ * GFP_KERNEL, unless b) or c) apply
*
*/
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
diff -r a83abb859b41 drivers/usb/storage/alauda.c
--- a/drivers/usb/storage/alauda.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/storage/alauda.c Tue Aug 07 17:18:51 2012 +0200
@@ -448,8 +448,8 @@
num_zones = MEDIA_INFO(us).capacity >> (MEDIA_INFO(us).zoneshift
+ MEDIA_INFO(us).blockshift + MEDIA_INFO(us).pageshift);
- MEDIA_INFO(us).pba_to_lba = kcalloc(num_zones, sizeof(u16*), GFP_NOIO);
- MEDIA_INFO(us).lba_to_pba = kcalloc(num_zones, sizeof(u16*), GFP_NOIO);
+ MEDIA_INFO(us).pba_to_lba = kcalloc(num_zones, sizeof(u16*), GFP_KERNEL);
+ MEDIA_INFO(us).lba_to_pba = kcalloc(num_zones, sizeof(u16*), GFP_KERNEL);
if (alauda_reset_media(us) != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -577,8 +577,8 @@
unsigned int lba_offset, lba_real, blocknum;
unsigned int zone_base_lba = zone * uzonesize;
unsigned int zone_base_pba = zone * zonesize;
- u16 *lba_to_pba = kcalloc(zonesize, sizeof(u16), GFP_NOIO);
- u16 *pba_to_lba = kcalloc(zonesize, sizeof(u16), GFP_NOIO);
+ u16 *lba_to_pba = kcalloc(zonesize, sizeof(u16), GFP_KERNEL);
+ u16 *pba_to_lba = kcalloc(zonesize, sizeof(u16), GFP_KERNEL);
if (lba_to_pba == NULL || pba_to_lba == NULL) {
result = USB_STOR_TRANSPORT_ERROR;
goto error;
@@ -940,7 +940,7 @@
*/
len = min(sectors, blocksize) * (pagesize + 64);
- buffer = kmalloc(len, GFP_NOIO);
+ buffer = kmalloc(len, GFP_KERNEL);
if (buffer == NULL) {
printk(KERN_WARNING "alauda_read_data: Out of memory\n");
return USB_STOR_TRANSPORT_ERROR;
@@ -1033,7 +1033,7 @@
*/
len = min(sectors, blocksize) * pagesize;
- buffer = kmalloc(len, GFP_NOIO);
+ buffer = kmalloc(len, GFP_KERNEL);
if (buffer == NULL) {
printk(KERN_WARNING "alauda_write_data: Out of memory\n");
return USB_STOR_TRANSPORT_ERROR;
@@ -1043,7 +1043,7 @@
* We also need a temporary block buffer, where we read in the old data,
* overwrite parts with the new data, and manipulate the redundancy data
*/
- blockbuffer = kmalloc((pagesize + 64) * blocksize, GFP_NOIO);
+ blockbuffer = kmalloc((pagesize + 64) * blocksize, GFP_KERNEL);
if (blockbuffer == NULL) {
printk(KERN_WARNING "alauda_write_data: Out of memory\n");
kfree(buffer);
@@ -1121,7 +1121,7 @@
struct usb_host_interface *altsetting = us->pusb_intf->cur_altsetting;
nand_init_ecc();
- us->extra = kzalloc(sizeof(struct alauda_info), GFP_NOIO);
+ us->extra = kzalloc(sizeof(struct alauda_info), GFP_KERNEL);
if (!us->extra) {
US_DEBUGP("init_alauda: Gah! Can't allocate storage for"
"alauda info struct!\n");
diff -r a83abb859b41 drivers/usb/storage/datafab.c
--- a/drivers/usb/storage/datafab.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/storage/datafab.c Tue Aug 07 17:18:51 2012 +0200
@@ -174,7 +174,7 @@
// bounce buffer and the actual transfer buffer.
alloclen = min(totallen, 65536u);
- buffer = kmalloc(alloclen, GFP_NOIO);
+ buffer = kmalloc(alloclen, GFP_KERNEL);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR;
@@ -258,7 +258,7 @@
// bounce buffer and the actual transfer buffer.
alloclen = min(totallen, 65536u);
- buffer = kmalloc(alloclen, GFP_NOIO);
+ buffer = kmalloc(alloclen, GFP_KERNEL);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR;
@@ -338,7 +338,7 @@
return USB_STOR_TRANSPORT_ERROR;
memcpy(command, scommand, 8);
- buf = kmalloc(512, GFP_NOIO);
+ buf = kmalloc(512, GFP_KERNEL);
if (!buf)
return USB_STOR_TRANSPORT_ERROR;
@@ -409,7 +409,7 @@
}
memcpy(command, scommand, 8);
- reply = kmalloc(512, GFP_NOIO);
+ reply = kmalloc(512, GFP_KERNEL);
if (!reply)
return USB_STOR_TRANSPORT_ERROR;
@@ -565,7 +565,7 @@
};
if (!us->extra) {
- us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO);
+ us->extra = kzalloc(sizeof(struct datafab_info), GFP_KERNEL);
if (!us->extra) {
US_DEBUGP("datafab_transport: Gah! "
"Can't allocate storage for Datafab info struct!\n");
diff -r a83abb859b41 drivers/usb/storage/jumpshot.c
--- a/drivers/usb/storage/jumpshot.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/storage/jumpshot.c Tue Aug 07 17:18:51 2012 +0200
@@ -188,7 +188,7 @@
// bounce buffer and the actual transfer buffer.
alloclen = min(totallen, 65536u);
- buffer = kmalloc(alloclen, GFP_NOIO);
+ buffer = kmalloc(alloclen, GFP_KERNEL);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR;
@@ -265,7 +265,7 @@
// bounce buffer and the actual transfer buffer.
alloclen = min(totallen, 65536u);
- buffer = kmalloc(alloclen, GFP_NOIO);
+ buffer = kmalloc(alloclen, GFP_KERNEL);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR;
@@ -340,7 +340,7 @@
command[0] = 0xE0;
command[1] = 0xEC;
- reply = kmalloc(512, GFP_NOIO);
+ reply = kmalloc(512, GFP_KERNEL);
if (!reply)
return USB_STOR_TRANSPORT_ERROR;
@@ -493,7 +493,7 @@
};
if (!us->extra) {
- us->extra = kzalloc(sizeof(struct jumpshot_info), GFP_NOIO);
+ us->extra = kzalloc(sizeof(struct jumpshot_info), GFP_KERNEL);
if (!us->extra) {
US_DEBUGP("jumpshot_transport: Gah! Can't allocate storage for jumpshot info struct!\n");
return USB_STOR_TRANSPORT_ERROR;
diff -r a83abb859b41 drivers/usb/storage/karma.c
--- a/drivers/usb/storage/karma.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/storage/karma.c Tue Aug 07 17:18:51 2012 +0200
@@ -182,11 +182,11 @@
static int rio_karma_init(struct us_data *us)
{
int ret = 0;
- struct karma_data *data = kzalloc(sizeof(struct karma_data), GFP_NOIO);
+ struct karma_data *data = kzalloc(sizeof(struct karma_data), GFP_KERNEL);
if (!data)
goto out;
- data->recv = kmalloc(RIO_RECV_LEN, GFP_NOIO);
+ data->recv = kmalloc(RIO_RECV_LEN, GFP_KERNEL);
if (!data->recv) {
kfree(data);
goto out;
diff -r a83abb859b41 drivers/usb/storage/onetouch.c
--- a/drivers/usb/storage/onetouch.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/storage/onetouch.c Tue Aug 07 17:18:51 2012 +0200
@@ -163,7 +163,7 @@
usb_kill_urb(onetouch->irq);
break;
case US_RESUME:
- if (usb_submit_urb(onetouch->irq, GFP_NOIO) != 0)
+ if (usb_submit_urb(onetouch->irq, GFP_KERNEL) != 0)
dev_err(&onetouch->irq->dev->dev,
"usb_submit_urb failed\n");
break;
diff -r a83abb859b41 drivers/usb/storage/realtek_cr.c
--- a/drivers/usb/storage/realtek_cr.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/storage/realtek_cr.c Tue Aug 07 17:18:51 2012 +0200
@@ -367,7 +367,7 @@
u8 cmnd[12] = { 0 };
u8 *buf;
- buf = kmalloc(len, GFP_NOIO);
+ buf = kmalloc(len, GFP_KERNEL);
if (buf == NULL)
return USB_STOR_TRANSPORT_ERROR;
@@ -398,7 +398,7 @@
u8 cmnd[12] = { 0 };
u8 *buf;
- buf = kmalloc(len, GFP_NOIO);
+ buf = kmalloc(len, GFP_KERNEL);
if (buf == NULL)
return USB_STOR_TRANSPORT_ERROR;
memcpy(buf, data, len);
@@ -428,7 +428,7 @@
u8 cmnd[12] = { 0 };
u8 *buf;
- buf = kmalloc(len, GFP_NOIO);
+ buf = kmalloc(len, GFP_KERNEL);
if (buf == NULL)
return USB_STOR_TRANSPORT_ERROR;
diff -r a83abb859b41 drivers/usb/storage/sddr09.c
--- a/drivers/usb/storage/sddr09.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/storage/sddr09.c Tue Aug 07 17:18:51 2012 +0200
@@ -692,7 +692,7 @@
return result;
}
- buf = kmalloc(bulklen, GFP_NOIO);
+ buf = kmalloc(bulklen, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -768,7 +768,7 @@
// bounce buffer and the actual transfer buffer.
len = min(sectors, (unsigned int) info->blocksize) * info->pagesize;
- buffer = kmalloc(len, GFP_NOIO);
+ buffer = kmalloc(len, GFP_KERNEL);
if (buffer == NULL) {
printk(KERN_WARNING "sddr09_read_data: Out of memory\n");
return -ENOMEM;
@@ -1000,7 +1000,7 @@
pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT);
blocklen = (pagelen << info->blockshift);
- blockbuffer = kmalloc(blocklen, GFP_NOIO);
+ blockbuffer = kmalloc(blocklen, GFP_KERNEL);
if (!blockbuffer) {
printk(KERN_WARNING "sddr09_write_data: Out of memory\n");
return -ENOMEM;
@@ -1011,7 +1011,7 @@
// at a time between the bounce buffer and the actual transfer buffer.
len = min(sectors, (unsigned int) info->blocksize) * info->pagesize;
- buffer = kmalloc(len, GFP_NOIO);
+ buffer = kmalloc(len, GFP_KERNEL);
if (buffer == NULL) {
printk(KERN_WARNING "sddr09_write_data: Out of memory\n");
kfree(blockbuffer);
@@ -1230,7 +1230,7 @@
alloc_blocks = min(numblocks, SDDR09_READ_MAP_BUFSZ >> CONTROL_SHIFT);
alloc_len = (alloc_blocks << CONTROL_SHIFT);
- buffer = kmalloc(alloc_len, GFP_NOIO);
+ buffer = kmalloc(alloc_len, GFP_KERNEL);
if (buffer == NULL) {
printk(KERN_WARNING "sddr09_read_map: out of memory\n");
result = -1;
@@ -1242,8 +1242,8 @@
kfree(info->lba_to_pba);
kfree(info->pba_to_lba);
- info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
- info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
+ info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
+ info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
printk(KERN_WARNING "sddr09_read_map: out of memory\n");
@@ -1438,7 +1438,7 @@
return -EINVAL;
}
- us->extra = kzalloc(sizeof(struct sddr09_card_info), GFP_NOIO);
+ us->extra = kzalloc(sizeof(struct sddr09_card_info), GFP_KERNEL);
if (!us->extra)
return -ENOMEM;
us->extra_destructor = sddr09_card_info_destructor;
diff -r a83abb859b41 drivers/usb/storage/sddr55.c
--- a/drivers/usb/storage/sddr55.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/storage/sddr55.c Tue Aug 07 17:18:51 2012 +0200
@@ -216,7 +216,7 @@
len = min((unsigned int) sectors, (unsigned int) info->blocksize >>
info->smallpageshift) * PAGESIZE;
- buffer = kmalloc(len, GFP_NOIO);
+ buffer = kmalloc(len, GFP_KERNEL);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR; /* out of memory */
offset = 0;
@@ -344,7 +344,7 @@
len = min((unsigned int) sectors, (unsigned int) info->blocksize >>
info->smallpageshift) * PAGESIZE;
- buffer = kmalloc(len, GFP_NOIO);
+ buffer = kmalloc(len, GFP_KERNEL);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR;
offset = 0;
@@ -661,7 +661,7 @@
numblocks = info->capacity >> (info->blockshift + info->pageshift);
- buffer = kmalloc( numblocks * 2, GFP_NOIO );
+ buffer = kmalloc( numblocks * 2, GFP_KERNEL );
if (!buffer)
return -1;
@@ -694,8 +694,8 @@
kfree(info->lba_to_pba);
kfree(info->pba_to_lba);
- info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
- info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
+ info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
+ info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
kfree(info->lba_to_pba);
@@ -799,7 +799,7 @@
if (!us->extra) {
us->extra = kzalloc(
- sizeof(struct sddr55_card_info), GFP_NOIO);
+ sizeof(struct sddr55_card_info), GFP_KERNEL);
if (!us->extra)
return USB_STOR_TRANSPORT_ERROR;
us->extra_destructor = sddr55_card_info_destructor;
diff -r a83abb859b41 drivers/usb/storage/shuttle_usbat.c
--- a/drivers/usb/storage/shuttle_usbat.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/storage/shuttle_usbat.c Tue Aug 07 17:18:51 2012 +0200
@@ -1068,7 +1068,7 @@
if (!us || !info)
return USB_STOR_TRANSPORT_ERROR;
- reply = kmalloc(512, GFP_NOIO);
+ reply = kmalloc(512, GFP_KERNEL);
if (!reply)
return USB_STOR_TRANSPORT_ERROR;
@@ -1153,7 +1153,7 @@
*/
alloclen = min(totallen, 65536u);
- buffer = kmalloc(alloclen, GFP_NOIO);
+ buffer = kmalloc(alloclen, GFP_KERNEL);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR;
@@ -1244,7 +1244,7 @@
*/
alloclen = min(totallen, 65536u);
- buffer = kmalloc(alloclen, GFP_NOIO);
+ buffer = kmalloc(alloclen, GFP_KERNEL);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR;
@@ -1348,7 +1348,7 @@
len = (65535/srb->transfersize) * srb->transfersize;
US_DEBUGP("Max read is %d bytes\n", len);
len = min(len, scsi_bufflen(srb));
- buffer = kmalloc(len, GFP_NOIO);
+ buffer = kmalloc(len, GFP_KERNEL);
if (buffer == NULL) /* bloody hell! */
return USB_STOR_TRANSPORT_FAILED;
sector = short_pack(data[7+3], data[7+2]);
@@ -1459,7 +1459,7 @@
unsigned char subcountL = USBAT_ATA_LBA_ME;
unsigned char *status = us->iobuf;
- us->extra = kzalloc(sizeof(struct usbat_info), GFP_NOIO);
+ us->extra = kzalloc(sizeof(struct usbat_info), GFP_KERNEL);
if (!us->extra) {
US_DEBUGP("init_usbat: Gah! Can't allocate storage for usbat info struct!\n");
return 1;
diff -r a83abb859b41 drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/storage/transport.c Tue Aug 07 17:18:51 2012 +0200
@@ -151,7 +151,7 @@
us->current_urb->transfer_dma = us->iobuf_dma;
/* submit the URB */
- status = usb_submit_urb(us->current_urb, GFP_NOIO);
+ status = usb_submit_urb(us->current_urb, GFP_KERNEL);
if (status) {
/* something went wrong */
return status;
@@ -429,7 +429,7 @@
US_DEBUGP("%s: xfer %u bytes, %d entries\n", __func__,
length, num_sg);
result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0,
- sg, num_sg, length, GFP_NOIO);
+ sg, num_sg, length, GFP_KERNEL);
if (result) {
US_DEBUGP("usb_sg_init returned %d\n", result);
return USB_STOR_XFER_ERROR;
diff -r a83abb859b41 drivers/usb/storage/uas.c
--- a/drivers/usb/storage/uas.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/storage/uas.c Tue Aug 07 17:18:51 2012 +0200
@@ -142,7 +142,7 @@
struct scsi_pointer *scp = (void *)cmdinfo;
struct scsi_cmnd *cmnd = container_of(scp,
struct scsi_cmnd, SCp);
- uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
+ uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_KERNEL);
}
}
diff -r a83abb859b41 drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c Tue Aug 07 17:17:03 2012 +0200
+++ b/drivers/usb/storage/usb.c Tue Aug 07 17:18:51 2012 +0200
@@ -409,7 +409,7 @@
usb_set_intfdata(intf, us);
/* Allocate the control/setup and DMA-mapped buffers */
- us->cr = kmalloc(sizeof(*us->cr), GFP_KERNEL);
+ us->cr = kmalloc(sizeof(*us->cr), GFP_NOIO);
if (!us->cr) {
US_DEBUGP("usb_ctrlrequest allocation failed\n");
return -ENOMEM;

View File

@ -0,0 +1,121 @@
assert_spec foc
assert_spec platform_panda
#
# Build
#
build {
core
init
drivers/timer
drivers/framebuffer
drivers/sd_card
drivers/usb
server/nic_bridge
server/part_blk
l4linux
}
create_boot_directory
#
# Config
#
set config {
<config prio_levels="2">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="fb_drv">
<binary name="omap4_fb_drv"/>
<resource name="RAM" quantum="4M"/>
<provides><service name="Framebuffer"/></provides>
</start>
<start name="sd_card_drv" priority="-1">
<resource name="RAM" quantum="4M"/>
<provides><service name="Block"/></provides>
</start>
<start name="usb_drv">
<resource name="RAM" quantum="6M"/>
<provides>
<service name="Input"/>
<service name="Nic"/>
</provides>
<config>
<hid/>
<nic mac="2e:60:90:0c:4e:01" />
</config>
</start>
<start name="part_blk" priority="-1">
<resource name="RAM" quantum="2M"/>
<provides><service name="Block"/></provides>
<config>
<policy label="vmlinux.1 -> sda" partition="1" />
<policy label="vmlinux.2 -> sda" partition="2" />
<policy label="test-libc_ffat" partition="3" />
</config>
<route>
<service name="Block"> <child name="sd_card_drv"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="vmlinux.1">
<binary name="l4linux"/>
<resource name="RAM" quantum="96M"/>
<config args="mem=54M l4x_rd=initrd.gz">
<block label="sda" />
</config>
<route>
<service name="Input"> <child name="usb_drv"/> </service>
<service name="Framebuffer"> <child name="fb_drv"/> </service>
<service name="Block"> <child name="part_blk"/> </service>
<service name="Nic"> <child name="usb_drv"/> </service>
<service name="Timer"> <child name="timer"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
</config>}
install_config $config
#
# Boot modules
#
set boot_modules {
core
init
timer
part_blk
l4linux
initrd.gz
omap4_fb_drv
sd_card_drv
usb_drv
}
set uri "https://github.com/downloads/skalk/genode/busybox-initrd-arm-20120710.gz"
if {![file exists bin/initrd.gz]} {
puts "Download initramfs ..."
exec >& /dev/null wget -c -O bin/initrd.gz $uri
}
build_boot_image [join $boot_modules " "]

View File

@ -45,7 +45,7 @@ append config {
<provides><service name="Timer"/></provides>
</start>
<start name="usb_drv">
<resource name="RAM" quantum="3M"/>
<resource name="RAM" quantum="6M"/>
<provides><service name="Input"/></provides>
<config>
<hid/>

View File

@ -45,7 +45,7 @@ set config {
<provides> <service name="Timer"/> </provides>
</start>
<start name="usb_drv">
<resource name="RAM" quantum="3M"/>
<resource name="RAM" quantum="6M"/>
<provides> <service name="Block"/> </provides>
<config><storage /></config>
</start>

View File

@ -68,49 +68,7 @@ struct ehci_hcd_omap_platform_data
};
struct regulator;
/*********************************************
** arch/arm/plat-omap/include/plat/board.h **
*********************************************/
struct omap_usb_config;
/************************************************
** arch/arm/plat-omap/include/plat/omap34xx.h **
************************************************/
#define OMAP34XX_UHH_CONFIG_BASE 0
#define OMAP34XX_EHCI_BASE 0
#define OMAP34XX_USBTLL_BASE 0
#define INT_34XX_EHCI_IRQ 0
#define OMAP34XX_OHCI_BASE 0
#define INT_34XX_OHCI_IRQ 0
#define OMAP3430_REV_ES2_1 0
static inline int cpu_is_omap34xx(void) { return 0; }
static inline int cpu_is_omap3430(void) { return 0; }
/***************************************************
** platform definition os for OMAP44xx all under **
** 'arch/arm/plat-omap/include **
***************************************************/
enum {
OMAP44XX_IRQ_GIC_START = 32,
OMAP44XX_IRQ_EHCI = 77 + OMAP44XX_IRQ_GIC_START,
OMAP44XX_IRQ_OHCI =76 + OMAP44XX_IRQ_GIC_START,
};
enum {
L4_44XX_BASE = 0x4a000000,
OMAP44XX_USBTLL_BASE = L4_44XX_BASE + 0x62000,
OMAP44XX_UHH_CONFIG_BASE = L4_44XX_BASE + 0x64000,
OMAP44XX_HSUSB_OHCI_BASE = L4_44XX_BASE + 0x64800,
OMAP44XX_HSUSB_EHCI_BASE = L4_44XX_BASE + 0x64C00,
};
static inline int cpu_is_omap44xx(void) { return 1; }
/*****************************
** linux/platform_device.h **
@ -132,6 +90,7 @@ int platform_get_irq_byname(struct platform_device *, const char *);
int platform_driver_register(struct platform_driver *);
int platform_device_register(struct platform_device *);
/**********************
** asm/generic/io.h **
**********************/

View File

@ -61,8 +61,6 @@ static struct ehci_hcd_omap_platform_data _ehci_data
};
/**
* Enables USB clocks
*/
@ -89,11 +87,8 @@ struct Clocks : Genode::Mmio
void dump()
{
Usb_host_clk::access_t a1 = read<Usb_host_clk>();
PDBG("Host clock %x", a1);
Usb_tll_clk::access_t a3 = read<Usb_tll_clk>();
PDBG("TLL: %x", a3);
Usb_phy_clk::access_t a4 = read<Usb_phy_clk>();
PDBG("Phy: %x", a4);
}
};

View File

@ -1,93 +0,0 @@
/*
* \brief DMA memory pool
* \author Sebastian Sumpf
* \date 2012-06-18
*/
/*
* Copyright (C) 2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _DMA_H_
#define _DMA_H_
#include <base/allocator_avl.h>
#include <dataspace/client.h>
#include <lx_emul.h>
/*********************
** linux/dmapool.h **
*********************/
namespace Genode {
/**
* Dma-pool manager
*/
class Dma
{
private:
enum { SIZE = 1024 * 1024 };
addr_t _base; /* virt base of pool */
addr_t _base_phys; /* phys base of pool */
Allocator_avl _range; /* range allocator for pool */
Dma() : _range(env()->heap())
{
Ram_dataspace_capability cap = env()->ram_session()->alloc(SIZE, false);
_base_phys = Dataspace_client(cap).phys_addr();
_base = (addr_t)env()->rm_session()->attach(cap);
dde_kit_log(DEBUG_DMA, "New DMA range [%lx-%lx)", _base, _base + SIZE);
_range.add_range(_base, SIZE);
}
public:
static Dma* pool()
{
static Dma _p;
return &_p;
}
addr_t base() const { return _base; };
addr_t end() const { return _base + SIZE - 1; }
/**
* Alloc 'size' bytes of DMA memory
*/
void *alloc(size_t size, int align = 12)
{
void *addr;
if (!_range.alloc_aligned(size, &addr, align)) {
PERR("DMA of %zu bytes allocation failed", size);
return 0;
}
return addr;
}
/**
* Free DMA memory
*/
void free(void *addr) { _range.free(addr); }
/**
* Get phys for virt address
*/
addr_t phys_addr(void *addr)
{
addr_t a = (addr_t)addr;
if (a < _base || a >= _base + SIZE) {
PERR("No DMA phys addr for %lx", a);
return 0;
}
return (a - _base) + _base_phys;
}
};
}
#endif /* _DMA_H_ */

View File

@ -812,8 +812,6 @@ void skb_queue_purge(struct sk_buff_head *list) { TRACE; }
void skb_tx_timestamp(struct sk_buff *skb) { TRACE; }
bool skb_defer_rx_timestamp(struct sk_buff *skb) { TRACE; return 0; }
void dev_kfree_skb_any(struct sk_buff *skb) { TRACE; }
/*********************
** linux/ethtool.h **

View File

@ -20,7 +20,7 @@
#include <util/string.h>
/* Local includes */
#include "dma.h"
#include "mem.h"
#include "routine.h"
#include "signal.h"
#include "lx_emul.h"
@ -44,6 +44,208 @@ extern "C" {
#define UNSUPPORTED
#endif
namespace Genode {
class Slab_alloc : public Slab
{
private:
Mem::Zone_alloc *_allocator;
size_t _calculate_block_size(size_t object_size)
{
size_t block_size = 8 * (object_size + sizeof(Slab_entry)) + sizeof(Slab_block);
return align_addr(block_size, 12);
}
public:
Slab_alloc(size_t object_size, Mem::Zone_alloc *allocator)
: Slab(object_size, _calculate_block_size(object_size), 0, allocator),
_allocator(allocator) { }
inline void *alloc()
{
void *result;
return (Slab::alloc(slab_size(), &result) ? result : 0);
}
bool match(void const *addr) { return _allocator->match(addr); }
addr_t phys_addr(void const *addr) { return _allocator->phys_addr(addr); }
};
}
class Malloc
{
private:
Genode::Mem *_pool;
enum {
SLAB_START_LOG2 = 3, /* 8 B */
SLAB_STOP_LOG2 = 16, /* 64 KB */
NUM_SLABS = (SLAB_STOP_LOG2 - SLAB_START_LOG2) + 1
};
/* slab allocator using Mem as back-end */
Genode::Slab_alloc *_allocator[NUM_SLABS];
void _init_slabs()
{
using namespace Genode;
_pool->init_zones(NUM_SLABS);
for (unsigned i = SLAB_START_LOG2; i <= SLAB_STOP_LOG2; i++) {
Mem::Zone_alloc *allocator = _pool->new_zone_allocator();
_allocator[i - SLAB_START_LOG2] = new (env()->heap()) Slab_alloc(1U << i, allocator);
}
}
/**
* Return slab for 'struct dma_pool' of size
*/
int _dma_pool_slab(Genode::size_t size)
{
int msb = Genode::log2(size);
if (size > (1U << msb))
msb++;
/* take next chunk */
return msb++;
}
public:
Malloc(Genode::Mem *pool) : _pool(pool) { _init_slabs(); }
/**
* General purpose allcator
*/
static Malloc *mem()
{
static Malloc _m(Genode::Mem::pool());
return &_m;
}
/**
* DMA allocator
*/
static Malloc *dma()
{
static Malloc _m(Genode::Mem::dma());
return &_m;
}
/**
* Alloc with alignment (uses back-end when alingment is > 2)
*/
void *alloc(Genode::size_t size, int align)
{
if (align <= 2)
return alloc(size);
return _pool->alloc(size, -1, align);
}
/**
* Alloc in slabs
*/
void *alloc(Genode::size_t size)
{
int msb = Genode::log2(size);
if (size > (1U << msb))
msb++;
if (size < (1U << SLAB_START_LOG2))
msb = SLAB_STOP_LOG2;
if (msb > SLAB_STOP_LOG2) {
PINF("Slab too large %u", 1U << msb);
return _pool->alloc(size);
}
return _allocator[msb - SLAB_START_LOG2]->alloc();
}
/**
* Free from slabs
*/
void free(void const *addr)
{
for (register unsigned i = SLAB_START_LOG2; i <= SLAB_STOP_LOG2; i++) {
Genode::Slab_alloc *slab = _allocator[i - SLAB_START_LOG2];
if (!slab->match(addr))
continue;
slab->free((void *)addr);
return;
}
_pool->free((void *)addr);
}
/**
* Get phys addr
*/
Genode::addr_t phys_addr(void *addr)
{
for (register unsigned i = SLAB_START_LOG2; i <= SLAB_STOP_LOG2; i++) {
Genode::Slab_alloc *slab = _allocator[i - SLAB_START_LOG2];
if (!slab->match(addr))
continue;
return slab->phys_addr(addr);
}
/* not found in slabs, try in back-end */
return _pool->phys_addr(addr);
}
/**
* Allocate aligned memory in slabs
*/
void *dma_pool_alloc(size_t size, int align, Genode::addr_t *dma)
{
using namespace Genode;
int msb = _dma_pool_slab(size);
addr_t base = (addr_t)_allocator[msb - SLAB_START_LOG2]->alloc();
unsigned align_val = (1U << align);
unsigned align_mask = align_val - 1;
/* make room for pointer */
addr_t addr = base + sizeof(Genode::addr_t);
/* align */
addr = (addr + align_val - 1) & ~align_mask;
addr_t *ptr = (addr_t *)addr - 1;
*ptr = base;
*dma = phys_addr((void *)addr);
return (void *)addr;
}
/**
* Free memory allocted with 'dma_pool_alloc'
*/
void dma_pool_free(size_t size, void *addr)
{
using namespace Genode;
int msb = _dma_pool_slab(size);
addr_t base = *((addr_t *)addr - 1);
_allocator[msb - SLAB_START_LOG2]->free((void *)base);
}
};
/***********************
** Atomic operations **
***********************/
@ -77,8 +279,7 @@ void mutex_unlock(struct mutex *m) { if (m->lock) dde_kit_lock_unlock( m->lock);
void *kmalloc(size_t size, gfp_t flags)
{
/* align at least four byte alignment */
void *addr = Genode::Dma::pool()->alloc(size, 2);
void *addr = flags & GFP_NOIO ? Malloc::dma()->alloc(size) : Malloc::mem()->alloc(size);
return addr;
}
@ -88,6 +289,7 @@ void *kzalloc(size_t size, gfp_t flags)
void *addr = kmalloc(size, flags);
if (addr)
Genode::memset(addr, 0, size);
return addr;
}
@ -102,8 +304,8 @@ void *kcalloc(size_t n, size_t size, gfp_t flags)
void kfree(const void *p)
{
//dde_kit_large_free((void *)p);
Genode::Dma::pool()->free((void *)p);
Malloc::mem()->free(p);
Malloc::dma()->free(p);
}
@ -161,7 +363,7 @@ int kref_put(struct kref *kref, void (*release) (struct kref *kref))
size_t copy_to_user(void *dst, void const *src, size_t len)
{
if (dst && src && len)
Genode::memcpy(dst, src, len);
memcpy(dst, src, len);
return 0;
}
@ -169,7 +371,7 @@ size_t copy_to_user(void *dst, void const *src, size_t len)
size_t copy_from_user(void *dst, void const *src, size_t len)
{
if (dst && src && len)
Genode::memcpy(dst, src, len);
memcpy(dst, src, len);
return 0;
}
@ -181,12 +383,16 @@ bool access_ok(int access, void *addr, size_t size) { return 1; }
** linux/string.h **
********************/
void *memcpy(void *dest, const void *src, size_t n) {
return Genode::memcpy(dest, src, n); }
void *_memcpy(void *d, const void *s, size_t n)
{
return Genode::memcpy(d, s, n);
}
void *memset(void *s, int c, size_t n) {
return Genode::memset(s, c, n); }
inline void *memset(void *s, int c, size_t n)
{
return Genode::memset(s, c, n);
}
int snprintf(char *buf, size_t size, const char *fmt, ...)
@ -570,9 +776,6 @@ unsigned long msecs_to_jiffies(const unsigned int m) { return m / JIFFIES_TICK_M
long time_after_eq(long a, long b) { return (a - b) >= 0; }
long time_after(long a, long b) { return (b - a) < 0; }
struct dma_pool
{
size_t size;
@ -602,43 +805,37 @@ void dma_pool_destroy(struct dma_pool *d)
}
static void* _alloc(size_t size, int align, dma_addr_t *dma)
{
void *addr = Genode::Dma::pool()->alloc(size, align < 2 ? 2 : align);
if (!addr)
return 0;
*dma = (dma_addr_t)Genode::Dma::pool()->phys_addr(addr);
dde_kit_log(DEBUG_DMA, "DMA pool alloc addr: %p size %zx align: %d, phys: %lx", addr, size, align, *dma);
memset(addr, 0, size);
return addr;
}
void *dma_pool_alloc(struct dma_pool *d, gfp_t f, dma_addr_t *dma)
{
return _alloc(d->size, d->align, dma);
return Malloc::dma()->dma_pool_alloc(d->size, d->align, (Genode::addr_t*)dma);
}
void dma_pool_free(struct dma_pool *d, void *vaddr, dma_addr_t a)
{
dde_kit_log(DEBUG_DMA, "free: addr %p, size: %zx", vaddr, d->size);
Genode::Dma::pool()->free(vaddr);
Malloc::dma()->dma_pool_free(d->size, vaddr);
}
void *dma_alloc_coherent(struct device *, size_t size, dma_addr_t *dma, gfp_t)
{
return _alloc(size, PAGE_SHIFT, dma);
void *addr = Malloc::dma()->alloc(size, PAGE_SHIFT);
if (!addr)
return 0;
*dma = (dma_addr_t)Malloc::dma()->phys_addr(addr);
dde_kit_log(DEBUG_DMA, "DMA pool alloc addr: %p size %zx align: %d, phys: %lx",
addr, size, PAGE_SHIFT, *dma);
return addr;
}
void dma_free_coherent(struct device *, size_t size, void *vaddr, dma_addr_t)
{
dde_kit_log(DEBUG_DMA, "free: addr %p, size: %zx", vaddr, size);
Genode::Dma::pool()->free(vaddr);
Malloc::dma()->free(vaddr);
}
@ -654,7 +851,8 @@ dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
enum dma_data_direction dir,
struct dma_attrs *attrs)
{
dma_addr_t phys = (dma_addr_t)Genode::Dma::pool()->phys_addr(ptr);
dma_addr_t phys = (dma_addr_t)Malloc::dma()->phys_addr(ptr);
dde_kit_log(DEBUG_DMA, "virt: %p phys: %lx", ptr, phys);
return phys;
}
@ -753,7 +951,7 @@ resource_size_t resource_size(const struct resource *res)
struct net_device *alloc_etherdev(int sizeof_priv)
{
net_device *dev = (net_device *)kzalloc(sizeof(net_device), 0);
net_device *dev = new (Genode::env()->heap()) net_device();
dev->mtu = 1500;
dev->hard_header_len = 0;
@ -783,7 +981,6 @@ int is_valid_ether_addr(const u8 *addr)
** linux/mii.h **
*****************/
/**
* Restart NWay (autonegotiation) for this interface
*/
@ -834,21 +1031,3 @@ u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv)
}
/***********************
** linux/netdevice.h **
***********************/
void *netdev_priv(const struct net_device *dev)
{
return dev->priv;
}
/**********************
** linux/inerrupt.h **
**********************/
void tasklet_schedule(struct tasklet_struct *t)
{
t->func(t->data);
}

View File

@ -33,13 +33,13 @@ extern "C" {
#include <linux/usb/storage.h>
#define VERBOSE_LX_EMUL 0
#define VERBOSE_LX_EMUL 0
#if VERBOSE_LX_EMUL
#define DEBUG_COMPLETION 0
#define DEBUG_DMA 0
#define DEBUG_DRIVER 1
#define DEBUG_DRIVER 0
#define DEBUG_IRQ 0
#define DEBUG_KREF 0
#define DEBUG_PCI 0
@ -627,11 +627,9 @@ int fls(int x);
/********************
** linux/string.h **
********************/
#undef memcpy
#ifndef __cplusplus
void *memcpy(void *dest, const void *src, size_t n);
#endif
void *memcpy(void *d, const void *s, size_t n);
void *memset(void *s, int c, size_t n);
int memcmp(const void *, const void *, size_t);
void *memscan(void *addr, int c, size_t size);
@ -2664,7 +2662,10 @@ struct sk_buff
unsigned char *end;
unsigned char *data;
unsigned char *tail;
unsigned char *phys;
unsigned int truesize;
void *packet;
unsigned char *clone;
};
struct sk_buff_head
@ -2682,7 +2683,6 @@ struct sk_buff_head
skb = tmp, tmp = skb->next)
struct skb_shared_info *skb_shinfo(struct sk_buff *);
struct sk_buff *alloc_skb(unsigned int, gfp_t);
unsigned char *skb_push(struct sk_buff *, unsigned int);
unsigned char *skb_pull(struct sk_buff *, unsigned int);
@ -2901,7 +2901,8 @@ struct netdev_hw_addr
u32 netif_msg_init(int, int);
void *netdev_priv(const struct net_device *);
static inline void *netdev_priv(const struct net_device *dev) { return dev->priv; }
int netif_running(const struct net_device *);
int netif_device_present(struct net_device *);
void netif_device_detach(struct net_device *);
@ -2978,7 +2979,7 @@ struct tasklet_struct
unsigned long data;
};
void tasklet_schedule(struct tasklet_struct *);
static inline void tasklet_schedule(struct tasklet_struct *t) { t->func(t->data); }
void tasklet_kill(struct tasklet_struct *);
/*************************

View File

@ -0,0 +1,237 @@
/*
* \brief Memory pool
* \author Sebastian Sumpf
* \date 2012-06-18
*/
/*
* Copyright (C) 2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _MEM_H_
#define _MEM_H_
#include <base/allocator_avl.h>
#include <dataspace/client.h>
#include <lx_emul.h>
/*********************
** linux/dmapool.h **
*********************/
namespace Genode {
/**
* Memory back-end
*/
class Mem
{
/* configurable sizes of memory pools */
enum
{
MEM_POOL = 2 * 1024 * 1024,
DMA_POOL = 3 * 1024 * 1024,
};
private:
addr_t _base; /* virt base of pool */
addr_t _base_phys; /* phys base of pool */
size_t _size; /* size of backng store */
Allocator_avl _range; /* range allocator for pool */
addr_t *_zones; /* bases of zones */
int _zone_count; /* number of zones */
int _zone_alloc; /* currently allocated zones */
Ram_dataspace_capability _ds_cap; /* backing store */
/**
* Private constructor
*/
Mem(size_t size, bool cached = true)
: _size(size), _range(env()->heap()),_zone_count(0), _zone_alloc(0)
{
_ds_cap = env()->ram_session()->alloc(_size, cached);
_base_phys = Dataspace_client(_ds_cap).phys_addr();
_base = (addr_t)env()->rm_session()->attach(_ds_cap);
dde_kit_log(DEBUG_DMA, "New DMA range [%lx-%lx)", _base, _base + _size);
_range.add_range(_base, _size);
}
/**
* Convert 'Mem' addres to zone address
*/
void *_to_zone(void const *addr, int i)
{
if (i < 0)
return (void *)addr;
addr_t zone_base = _zones[i];
addr_t offset = (addr_t)addr - _base;
return (void *)(zone_base + offset);
}
/**
* Convert zone addres to 'Mem' address
*/
void *_from_zone(void const *addr, int i)
{
if (i < 0)
return (void *)addr;
addr_t zone_base = _zones[i];
addr_t offset = (addr_t)addr - zone_base;
return (void *)(_base + offset);
}
public:
/**
* Memory zone within Mem allocator
*/
class Zone_alloc : public Allocator
{
private:
Mem *_pool; /* pool of zone */
int _zone; /* zone number */
addr_t _base; /* base address of zone */
size_t _size; /* size of zone */
public:
Zone_alloc(Mem *pool, int zone, addr_t base, size_t size)
: _pool(pool), _zone(zone), _base(base), _size(size) { }
/*************************
** Alocator interface **
*************************/
bool alloc(size_t size, void **out_addr)
{
*out_addr = _pool->alloc(size, _zone);
if (!*out_addr) {
PERR("Zone of %zu bytes allocation failed", size);
return false;
}
return true;
}
void free(void *addr, size_t /* size */) { _pool->free(addr, _zone); }
size_t overhead(size_t size) { return 0; }
/**
* Check if address matches zone
*/
bool match(void const *addr)
{
addr_t a = (addr_t)addr;
bool ret = ((a >= _base) && (a < (_base + _size)));
return ret;
}
/**
* Retrieve virt to phys mapping
*/
addr_t phys_addr(void const *addr) { return _pool->phys_addr(addr, _zone); }
};
/**
* Gernal purpose memory pool
*/
static Mem* pool()
{
static Mem _p(MEM_POOL);
return &_p;
}
/**
* DMA memory pool
*/
static Mem* dma()
{
static Mem _p(DMA_POOL, false);
return &_p;
}
/**
* Allocator interface
*/
void *alloc(size_t size, int zone = -1, int align = 2)
{
void *addr;
if (!_range.alloc_aligned(size, &addr, align)) {
PERR("Memory allocation of %zu bytes failed", size);
return 0;
}
return _to_zone(addr, zone);
}
/**
* Free addr in zone
*/
void free(void *addr, int zone = -1) { _range.free(_from_zone(addr, zone)); }
/**
* Get phys for virt address
*/
addr_t phys_addr(void const *addr, int zone = - 1)
{
addr_t a = (addr_t)_from_zone(addr, zone);
if (a < _base || a >= _base + _size) {
PERR("No DMA phys addr for %lx zone: %d", a, zone);
return 0;
}
return (a - _base) + _base_phys;
}
/**
* Iinit allocator with count zones
*/
void init_zones(int count)
{
if (_zone_count)
return;
_zones = (addr_t *)env()->heap()->alloc(count * sizeof(addr_t));
_zone_count = count;
for (int i = 0; i < _zone_count; i++) {
_zones[i] = (addr_t)env()->rm_session()->attach(_ds_cap);
dde_kit_log(DEBUG_DMA, "Zone %d: base: %lx end %lx", i, _zones[i], _zones[i] + _size);
}
PINF("Registered %d zone allocators", count);
}
/**
* Create new zone allocator
*
* 'init_zones' must have been called beforehand
*/
Zone_alloc *new_zone_allocator()
{
if(_zone_alloc >= _zone_count) {
PERR("Zone allocators exhausted");
return 0;
}
Zone_alloc *zone = new(env()->heap()) Zone_alloc(this,
_zone_alloc,
_zones[_zone_alloc],
_size);
_zone_alloc++;
return zone;
}
};
}
#endif /* _MEM_H_ */

View File

@ -15,17 +15,55 @@
#define _NIC__COMPONENT_H_
#include <root/component.h>
#include <nic/packet_allocator.h>
#include <nic_session/rpc_object.h>
#include <timer_session/connection.h>
#include <signal/dispatch.h>
#define BENCH 0
namespace Nic {
using namespace Genode;
class Session_component;
#if BENCH
struct Counter : public Genode::Thread<8192>
{
char const *prefix;
int cnt;
int burst;
size_t size;
void entry()
{
Timer::Connection _timer;
int interval = 5;
while(1) {
_timer.msleep(interval * 1000);
PDBG("%s: Packets %d/s (in %d burst packets) bytes/s: %d",
prefix, cnt / interval, burst / interval, size / interval);
cnt = 0;
size = 0;
burst = 0;
}
}
void inc(size_t s) { cnt++; size += s; }
void inc_burst() { burst++; }
Counter(char const *prefix) : prefix(prefix), cnt(0), burst(0), size(0) { start(); }
};
#else
struct Counter
{
Counter(char const *) { };
void inc(size_t) { }
void inc_burst() { }
};
#endif
struct Device : ::Device
{
Session_component *_session;
@ -44,9 +82,43 @@ namespace Nic {
* Set session belonging to this driver
*/
void session(Session_component *s) { _session = s; }
/**
* Check for session
*/
bool session() { return _session != 0; }
/**
* Alloc an SKB
*/
virtual sk_buff *alloc_skb() = 0;
/**
* Submit SKB to device
*/
virtual void tx_skb(sk_buff *skb) = 0;
/**
* Setup SKB with 'data' of 'size', return 'false' if SKB is longer than
* 'end'.
*/
virtual bool skb_fill(struct sk_buff *skb, unsigned char *data, Genode::size_t size, unsigned char *end) = 0;
/**
* Call driver fixup function on SKB
*/
virtual void tx_fixup(struct sk_buff *skb) = 0;
/**
* Return true if device supports burst operations
*/
virtual bool burst() = 0;
Device() : _session(0) { }
};
class Session_component : public Genode::Allocator_avl,
class Session_component : public Nic::Packet_allocator,
public Packet_session_component<Session_rpc_object>
{
private:
@ -58,29 +130,85 @@ namespace Nic {
void _process_packets()
{
static sk_buff work_skb; /* dummy skb for fixup calls */
static Counter counter("TX");
int tx_cnt = 0;
unsigned size = 0;
sk_buff *skb = 0;
unsigned char *ptr = 0;
/* submit received packets to lower layer */
while (_tx_sink->packet_avail())
{
Packet_descriptor packet = _tx_sink->get_packet();
addr_t virt = (addr_t)_tx_sink->packet_content(packet);
/* send to driver */
_device->tx(virt, packet.size());
if (!_tx_sink->ready_to_ack())
PWRN("Wait for TX packet ack");
if (_device->burst()) {
if (!ptr || !_device->skb_fill(&work_skb, ptr, packet.size(), skb->end)) {
/* submit batch to device */
if (ptr) {
_device->tx_skb(skb);
tx_cnt++;
counter.inc_burst();
}
/* alloc new SKB */
skb = _device->alloc_skb();
ptr = skb->data;
work_skb.data = 0;
_device->skb_fill(&work_skb, ptr, packet.size(), skb->end);
}
/* copy packet to current data pos */
Genode::memcpy(work_skb.data, (void *)virt, packet.size());
/* call fixup on dummy SKB */
_device->tx_fixup(&work_skb);
/* advance to next slot */
ptr = work_skb.end;
skb->len += work_skb.truesize;
} else {
/* send to driver */
_device->tx(virt, packet.size());
}
counter.inc(packet.size());
if (!_tx_sink->ready_to_ack()) {
_wait_event(_tx_sink->ready_to_ack());
}
/* acknowledge to client */
_tx_sink->acknowledge_packet(packet);
/* check if we received any signals (don't block) */
if ((tx_cnt % 20) == 0)
Service_handler::s()->check_signal(false);
}
/* sumbit last skb */
if (skb) {
_device->tx_skb(skb);
counter.inc_burst();
}
/* for large TCP/s check RX immediately */
Irq::check_irq();
/* release acknowledged packets */
while (_rx.source()->ack_avail())
_rx_ack(false);
}
void _rx_ack(bool block = true)
{
while (_rx.source()->ack_avail() || block)
{
Packet_descriptor packet = _rx.source()->get_acked_packet();
/* free packet buffer */
_rx.source()->release_packet(packet);
block = false;
}
}
@ -95,10 +223,11 @@ namespace Nic {
Signal_receiver *sig_rec,
::Device *device)
:
Genode::Allocator_avl(Genode::env()->heap()),
Nic::Packet_allocator(Genode::env()->heap()),
Packet_session_component(tx_ds, rx_ds, this, ep, sig_rec),
_device(static_cast<Device *>(device)),
_tx_sink(Session_rpc_object::_tx.sink()) { _device->session(this); }
_tx_sink(Session_rpc_object::_tx.sink())
{ _device->session(this); }
Mac_address mac_address() { return _device->mac_address(); }
@ -107,9 +236,23 @@ namespace Nic {
*/
void rx(addr_t virt, size_t size)
{
Packet_descriptor p =_rx.source()->alloc_packet(size);
memcpy(_rx.source()->packet_content(p), (void*)virt, size);
_rx.source()->submit_packet(p);
static Counter counter("RX");
while (true) {
try {
Packet_descriptor p =_rx.source()->alloc_packet(size);
Genode::memcpy(_rx.source()->packet_content(p), (void*)virt, size);
_rx.source()->submit_packet(p);
counter.inc(size);
} catch (...) {
/* ack or block */
_rx_ack();
continue;
}
break;
}
_rx_ack(false);
}
};

View File

@ -19,28 +19,151 @@
#include <util/xml_node.h>
#include <lx_emul.h>
#include <dma.h>
#include <mem.h>
#include <nic/component.h>
#include "signal.h"
extern "C" {
#include <linux/usb.h>
#include <linux/usb/usbnet.h>
}
static Signal_helper *_signal = 0;
enum {
START = 0x1, /* device flag */
HEAD_ROOM = 32, /* head room in skb in bytes */
MAC_LEN = 17, /* 12 number and 6 colons */
HEAD_ROOM = 8, /* head room in skb in bytes */
MAC_LEN = 17, /* 12 number and 6 colons */
};
class Nic_device : public Nic::Device
/**
* Internal alloc function
*/
struct sk_buff *_alloc_skb(unsigned int size, bool tx = true);
/**
* Skb-bitmap allocator
*/
template <unsigned ENTRIES, unsigned BUFFER>
class Skb
{
private:
struct net_device *_ndev; /* Linux-net device */
enum {
IDX = ENTRIES / 32,
};
sk_buff _buf[ENTRIES];
unsigned _free[ENTRIES / sizeof(unsigned)];
unsigned _idx;
bool _wait_free;
public:
Nic_device(struct net_device *ndev) : _ndev(ndev) { }
Skb() : _idx(0)
{
Genode::memset(_free, 0xff, sizeof(_free));
for (unsigned i = 0; i < ENTRIES; i++)
_buf[i].start = (unsigned char *)Genode::Mem::dma()->alloc(BUFFER);;
}
sk_buff *alloc()
{
for (register int i = 0; i < IDX; i++) {
if (_free[_idx] != 0) {
unsigned msb = Genode::log2(_free[_idx]);
_free[_idx] ^= (1 << msb);
sk_buff *r = &_buf[(_idx * 32) + msb];
r->data = r->start;
r->phys = 0;
r->cloned = 0;
r->clone = 0;
r->len = 0;
return r;
}
_idx = (_idx + 1) % IDX;
}
/* wait until some SKBs are fred */
_wait_free = false;
_wait_event(_wait_free);
return alloc();
}
void free(sk_buff *buf)
{
unsigned entry = buf - &_buf[0];
if (&_buf[0] > buf || entry > ENTRIES)
return;
/* unblock waiting skb allocs */
_wait_free = true;
_idx = entry / 32;
_free[_idx] |= (1 << (entry % 32));
}
};
/* 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 */
static Tx_skb *skb_tx()
{
static Tx_skb _skb;
return &_skb;
}
static Rx_skb *skb_rx()
{
static Rx_skb _skb;
return &_skb;
}
/**
* Prototype of fixup function
*/
extern "C" {
typedef struct sk_buff* (*fixup_t)(struct usbnet *, struct sk_buff *, gfp_t);
}
/**
* Net_device to session glue code
*/
class Nic_device : public Nic::Device
{
public:
struct net_device *_ndev; /* Linux-net device */
fixup_t _tx_fixup;
public:
Nic_device(struct net_device *ndev) : _ndev(ndev)
{
/*
* Retrieve 'tx_fixup' funcion from driver and set it to zero, so it
* cannot be called by the actual driver.
*/
struct usbnet *dev = (usbnet *)netdev_priv(ndev);
_tx_fixup = dev->driver_info->tx_fixup;
dev->driver_info->tx_fixup = 0;
}
/**
* Add device
@ -58,20 +181,73 @@ class Nic_device : public Nic::Device
*/
void tx(Genode::addr_t virt, Genode::size_t size)
{
sk_buff *skb = alloc_skb(size + HEAD_ROOM, 0);
sk_buff *skb = _alloc_skb(size + HEAD_ROOM);
skb->len = size;
skb->data += HEAD_ROOM;
Genode::memcpy(skb->data, (void *)virt, skb->len);
_ndev->netdev_ops->ndo_start_xmit(skb, _ndev);
tx_skb(skb);
}
/**
* Alloc an SKB
*/
sk_buff *alloc_skb()
{
sk_buff *skb = _alloc_skb(18944);
skb->len = 0;
return skb;
}
/**
* Submit SKB to the driver
*/
void tx_skb(sk_buff *skb)
{
struct usbnet *dev = (usbnet *)netdev_priv(_ndev);
unsigned long dropped = dev->net->stats.tx_dropped;
_ndev->netdev_ops->ndo_start_xmit(skb, _ndev);
if (dropped < dev->net->stats.tx_dropped)
PWRN("Dropped SKB");
}
/**
* Call tx_fixup function of driver
*/
void tx_fixup(struct sk_buff *skb)
{
struct usbnet *dev = (usbnet *)netdev_priv(_ndev);
if(!_tx_fixup || !_tx_fixup(dev, skb, 0))
PERR("Tx fixup error");
}
/**
* Fill an SKB with 'data' if 'size', return false if SKB is greater than
* 'end'
*/
bool skb_fill(struct sk_buff *skb, unsigned char *data, Genode::size_t size, unsigned char *end)
{
Genode::addr_t align = ((Genode::addr_t)(data + 3) & ~3);
skb->truesize = skb->data == 0 ? 0 : (unsigned char*)align - data;
data = skb->data == 0 ? data : (unsigned char*)align;
skb->start = data;
data += HEAD_ROOM;
skb->len = size;
skb->data = data;
skb->end = skb->tail = data + size;
skb->truesize += (skb->end - skb->start);
return skb->end >= end ? false : true;
}
/**
* Submit packet for session
*/
void rx(sk_buff *skb) { _session->rx((Genode::addr_t)skb->data, skb->len); }
inline void rx(sk_buff *skb) { _session->rx((Genode::addr_t)skb->data, skb->len); }
/**
* Return mac address
@ -82,11 +258,15 @@ class Nic_device : public Nic::Device
Genode::memcpy(&m, _ndev->_dev_addr, ETH_ALEN);
return m;
}
bool burst() { return true; }
};
/* XXX support multiple devices */
static Nic_device *_nic = 0;
void Nic::init(Genode::Signal_receiver *recv) {
_signal = new (Genode::env()->heap()) Signal_helper(recv); }
@ -128,8 +308,10 @@ int netif_device_present(struct net_device *dev) { return 1; }
int netif_rx(struct sk_buff *skb)
{
if (_nic)
if (_nic && _nic->session()) {
_nic->rx(skb);
}
dev_kfree_skb(skb);
return NET_RX_SUCCESS;
}
@ -139,18 +321,25 @@ int netif_rx(struct sk_buff *skb)
** linux/skbuff.h **
********************/
struct sk_buff *alloc_skb(unsigned int size, gfp_t priority)
struct sk_buff *_alloc_skb(unsigned int size, bool tx)
{
sk_buff *skb = new (Genode::env()->heap()) sk_buff;
Genode::memset(skb, 0, sizeof(sk_buff));
sk_buff *skb = tx ? skb_tx()->alloc() : skb_rx()->alloc();
size = (size + 3) & ~(0x3);
skb->start = skb->data = size ? (unsigned char*)kzalloc(size, 0) : 0;
skb->tail = skb->end = skb->start + size;
skb->tail = skb->end = skb->start + size;
skb->truesize = size;
dde_kit_log(DEBUG_SKB, "alloc sbk: %p start: %p size: %u", skb, skb->start, size);
return skb;
}
struct sk_buff *alloc_skb(unsigned int size, gfp_t priority)
{
/*
* Note: This is only called for RX skb's by the driver
*/
struct sk_buff *skb = _alloc_skb(size, false);
return skb;
}
@ -160,13 +349,21 @@ void dev_kfree_skb(struct sk_buff *skb)
dde_kit_log(DEBUG_SKB, "free skb: %p start: %p cloned: %d",
skb, skb->start, skb->cloned);
if (!skb->cloned)
kfree(skb->start);
if (skb->cloned) {
skb->start = skb->clone;
skb->cloned = false;
skb_rx()->free(skb);
return;
}
destroy(Genode::env()->heap(), skb);
skb_tx()->free(skb);
skb_rx()->free(skb);
}
void dev_kfree_skb_any(struct sk_buff *skb) { dev_kfree_skb(skb); }
/**
* Reserve 'len'
*/
@ -223,7 +420,7 @@ unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
/**
* Return current head room
*/
unsigned int skb_headroom(const struct sk_buff *skb)
unsigned int skb_headroom(const struct sk_buff *skb)
{
return skb->data - skb->start;
}
@ -251,8 +448,8 @@ unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)
void skb_trim(struct sk_buff *skb, unsigned int len)
{
if (skb->len <= len) {
PERR("Error trimming skb: %p data: %p start: %p len %u ret: %p",
skb, skb->data, skb->start, len, __builtin_return_address((0)));
PERR("Error trimming to %u bytes skb: %p data: %p start: %p len %u ret: %p",
len, skb, skb->data, skb->start, skb->len, __builtin_return_address((0)));
return;
}
@ -269,8 +466,12 @@ void skb_trim(struct sk_buff *skb, unsigned int len)
struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
{
sk_buff *c = alloc_skb(0, 0);
Genode::memcpy(c, skb, sizeof(sk_buff));
unsigned char *start = c->start;
*c = *skb;
/* save old start pointer */
c->cloned = 1;
c->clone = start;
return c;
}
@ -392,7 +593,7 @@ namespace Genode {
mac_str[i] = (digit(s[hi], HEX) << 4) | digit(s[lo], HEX);
}
memcpy(mac->addr, mac_str, ETH_ALEN);
Genode::memcpy(mac->addr, mac_str, ETH_ALEN);
return MAC_LEN;
}
@ -425,7 +626,7 @@ void random_ether_addr(u8 *addr)
Xml_node::Attribute mac_node = nic_config.attribute("mac");
mac_node.value(&mac);
} catch (...) {
/* use fallback mac */
/* use fallback mac */
snprint_mac(str, fallback);
PWRN("No mac address or wrong format attribute in <nic> - using fallback (%s)",
str);
@ -439,3 +640,4 @@ void random_ether_addr(u8 *addr)
snprint_mac(str, mac.addr);
PINF("Using configured mac: %s", str);
}

View File

@ -68,13 +68,20 @@ class Service_handler
return;
}
do {
check_signal();
}
void check_signal(bool block = true)
{
while (_receiver->pending() || block) {
Genode::Signal s = _receiver->wait_for_signal();
/* handle signal IRQ, timer, or event signals */
Driver_context *ctx = static_cast<Driver_context *>(s.context());
ctx->handle();
} while (_receiver->pending());
block = false;
}
}
};
@ -108,6 +115,7 @@ namespace Timer
namespace Irq
{
void init(Genode::Signal_receiver *recv);
void check_irq();
}
namespace Event

View File

@ -13,15 +13,15 @@
#include <signal.h>
#include <lx_emul.h>
#include <dma.h>
extern "C" {
#include <dde_kit/interrupt.h>
}
/* our local incarnation of sender and receiver */
static Signal_helper *_signal = 0;
static Genode::Lock _irq_ack_lock(Genode::Lock::LOCKED);
static Genode::Lock _irq_sync(Genode::Lock::LOCKED);
static Genode::Lock _irq_wait(Genode::Lock::LOCKED);
/**
@ -37,6 +37,7 @@ struct Irq_handler : Genode::List<Irq_handler>::Element
};
/**
* Signal context for IRQs
*/
@ -70,13 +71,60 @@ class Irq_context : public Driver_context,
/* called by the DDE kit upon IRQ */
static void _dde_handler(void *irq)
{
/* unlock if main thread is waiting */
_irq_wait.unlock();
Irq_context *ctx = static_cast<Irq_context *>(irq);
/* set context & submit signal */
_signal->sender()->context(ctx->_ctx_cap);
_signal->sender()->submit();
_irq_ack_lock.lock();
/* wait for interrupt to get acked at device side */
_irq_sync.lock();
}
/**
* Call one IRQ handler
*/
inline bool _handle_one(Irq_handler *h)
{
bool handled = false;
/*
* It might be that the next interrupt triggers right after the device has
* acknowledged the IRQ
*/
do {
if (h->handler(_irq, h->dev) != IRQ_HANDLED)
return handled;
if (!handled)
Routine::schedule_all();
handled = true;
} while (true);
}
/**
* Call all handlers registered for this context
*/
bool _handle()
{
bool handled = false;
/* report IRQ to all clients */
for (Irq_handler *h = _handler_list.first(); h; h = h->next()) {
handled = _handle_one(h);
dde_kit_log(DEBUG_IRQ, "IRQ: %u ret: %u %p", _irq, handled, h->handler);
if (handled)
break;
}
/* interrupt should be acked at device now */
_irq_sync.unlock();
return handled;
}
public:
@ -94,23 +142,10 @@ class Irq_context : public Driver_context,
_list()->insert(this);
}
void handle()
{
/* report IRQ to all clients */
for (Irq_handler *h = _handler_list.first(); h; h = h->next()) {
irqreturn_t rc;
rc = h->handler(_irq, h->dev);
dde_kit_log(DEBUG_IRQ, "IRQ: %u ret: %u %p", _irq, rc, h->handler);
if (rc == IRQ_HANDLED) {
Routine::schedule_all();
break;
}
}
_irq_ack_lock.unlock();
}
inline void handle() { _handle(); }
const char *debug() { return "Irq_context"; }
/**
* Request an IRQ
*/
@ -126,6 +161,21 @@ class Irq_context : public Driver_context,
/* register Linux handler */
ctx->_handler_list.insert(h);
}
static bool check_irq()
{
bool handled = false;
for (Irq_context *i = _list()->first(); i; i = i->next())
handled |= i->_handle();
return handled;
}
static void wait()
{
_irq_wait.lock();
check_irq();
}
};
@ -133,6 +183,13 @@ void Irq::init(Genode::Signal_receiver *recv) {
_signal = new (Genode::env()->heap()) Signal_helper(recv); }
void Irq::check_irq()
{
if (!Irq_context::check_irq())
Irq_context::wait();
}
/***********************
** linux/interrupt.h **
***********************/
@ -140,7 +197,8 @@ void Irq::init(Genode::Signal_receiver *recv) {
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)
{
dde_kit_log(DEBUG_IRQ, "Request irq %u", irq);
dde_kit_log(DEBUG_IRQ, "Request irq %u handler %p", irq, handler);
Irq_context::request_irq(irq, handler, dev);
return 0;
}

View File

@ -91,7 +91,7 @@ void scsi_alloc_buffer(size_t size, struct scsi_cmnd *cmnd)
scsi_setup_buffer(cmnd, size, 0, 0);
struct scatterlist *sgl = cmnd->sdb.table.sgl;
struct page *page = _page(cmnd);
page->virt = kmalloc(size, 0);
page->virt = kmalloc(size, GFP_NOIO);
page->phys = dma_map_single_attrs(0, page->virt, 0, 0, 0);
sgl->dma_address = page->phys;
}

View File

@ -128,11 +128,11 @@ class Storage_device : public Genode::List<Storage_device>::Element,
cmnd->session = (void *)session;
Genode::uint32_t be_block_nr = bswap<Genode::uint32_t>(block_nr);
Genode::memcpy(&cmnd->cmnd[2], &be_block_nr, 4);
memcpy(&cmnd->cmnd[2], &be_block_nr, 4);
/* transfer one block */
Genode::uint16_t be_block_count = bswap(block_count);
Genode::memcpy(&cmnd->cmnd[7], &be_block_count, 2);
memcpy(&cmnd->cmnd[7], &be_block_count, 2);
/* setup command */
scsi_setup_buffer(cmnd, block_count * _block_size, (void *)virt, phys);

View File

@ -0,0 +1,44 @@
/*
* \brief Test functions
* \author Sebastian Sumpf
* \date 2012-08-02
*/
/*
* Copyright (C) 2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#if 0
void tx_test() {
char *data = (char *)skb->data;
if (data[0x2a] == (char)0xaa && data[0x2b] == (char)0xbb) {
PDBG("Got server signal");
static char data[1066];
static char header[] = {
0x00, 0x1c, 0x25, 0x9e, 0x92, 0x4a, 0x2e, 0x60, 0x90, 0x0c, 0x4e, 0x01, 0x08, 0x00, 0x45, 0x00,
0x04, 0x1c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11, 0x22, 0x88, 0x0a, 0x00, 0x00, 0x3b, 0x0a, 0x00,
0x00, 0x0f, 0x89, 0xc5, 0x04, 0xd2, 0x04, 0x08, 0x54, 0xfd};
Genode::memset(data, 0, 1065);
memcpy(data, header, sizeof(header));
while (1) {
sk_buff *skb = alloc_skb(1066 + HEAD_ROOM, 0);
if (!skb) {
Service_handler::s()->check_signal(true);
continue;
}
skb->len = 1066;
skb->data += HEAD_ROOM;
memcpy(skb->data, data, 1066);
_nic->_ndev->netdev_ops->ndo_start_xmit(skb, _nic->_ndev);
dev_kfree_skb(skb);
}
}
}
#endif