diff --git a/dde_linux/patches/mem_optimization.patch b/dde_linux/patches/mem_optimization.patch new file mode 100644 index 0000000000..9c4ab6cb2c --- /dev/null +++ b/dde_linux/patches/mem_optimization.patch @@ -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; diff --git a/dde_linux/run/linux_nic_panda.run b/dde_linux/run/linux_nic_panda.run new file mode 100644 index 0000000000..867987c354 --- /dev/null +++ b/dde_linux/run/linux_nic_panda.run @@ -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 { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +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 " "] + diff --git a/dde_linux/run/usb_hid.run b/dde_linux/run/usb_hid.run index 30099e436c..756970b006 100644 --- a/dde_linux/run/usb_hid.run +++ b/dde_linux/run/usb_hid.run @@ -45,7 +45,7 @@ append config { - + diff --git a/dde_linux/run/usb_storage.run b/dde_linux/run/usb_storage.run index 33896a4fa5..6e386c4545 100644 --- a/dde_linux/run/usb_storage.run +++ b/dde_linux/run/usb_storage.run @@ -45,7 +45,7 @@ set config { - + diff --git a/dde_linux/src/drivers/usb/arm/platform/lx_emul.h b/dde_linux/src/drivers/usb/arm/platform/lx_emul.h index b814780c31..8a7a6ee43f 100644 --- a/dde_linux/src/drivers/usb/arm/platform/lx_emul.h +++ b/dde_linux/src/drivers/usb/arm/platform/lx_emul.h @@ -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 ** **********************/ diff --git a/dde_linux/src/drivers/usb/arm/platform/platform.cc b/dde_linux/src/drivers/usb/arm/platform/platform.cc index aa361fdfc9..23baed3b39 100644 --- a/dde_linux/src/drivers/usb/arm/platform/platform.cc +++ b/dde_linux/src/drivers/usb/arm/platform/platform.cc @@ -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(); - PDBG("Host clock %x", a1); Usb_tll_clk::access_t a3 = read(); - PDBG("TLL: %x", a3); Usb_phy_clk::access_t a4 = read(); - PDBG("Phy: %x", a4); } }; diff --git a/dde_linux/src/drivers/usb/dma.h b/dde_linux/src/drivers/usb/dma.h deleted file mode 100644 index 70f3c7996f..0000000000 --- a/dde_linux/src/drivers/usb/dma.h +++ /dev/null @@ -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 -#include -#include - -/********************* - ** 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_ */ diff --git a/dde_linux/src/drivers/usb/dummies.c b/dde_linux/src/drivers/usb/dummies.c index f08e5f3c7f..17de6b418e 100644 --- a/dde_linux/src/drivers/usb/dummies.c +++ b/dde_linux/src/drivers/usb/dummies.c @@ -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 ** diff --git a/dde_linux/src/drivers/usb/lx_emul.cc b/dde_linux/src/drivers/usb/lx_emul.cc index f86a307a4c..d3ba8977fe 100644 --- a/dde_linux/src/drivers/usb/lx_emul.cc +++ b/dde_linux/src/drivers/usb/lx_emul.cc @@ -20,7 +20,7 @@ #include /* 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); -} diff --git a/dde_linux/src/drivers/usb/lx_emul.h b/dde_linux/src/drivers/usb/lx_emul.h index 7dc5a20713..b4a0f808c2 100644 --- a/dde_linux/src/drivers/usb/lx_emul.h +++ b/dde_linux/src/drivers/usb/lx_emul.h @@ -33,13 +33,13 @@ extern "C" { #include -#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 *); /************************* diff --git a/dde_linux/src/drivers/usb/mem.h b/dde_linux/src/drivers/usb/mem.h new file mode 100644 index 0000000000..22979e61fb --- /dev/null +++ b/dde_linux/src/drivers/usb/mem.h @@ -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 +#include +#include + +/********************* + ** 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_ */ diff --git a/dde_linux/src/drivers/usb/nic/component.h b/dde_linux/src/drivers/usb/nic/component.h index 1ac5bb9a0e..601ed50d84 100644 --- a/dde_linux/src/drivers/usb/nic/component.h +++ b/dde_linux/src/drivers/usb/nic/component.h @@ -15,17 +15,55 @@ #define _NIC__COMPONENT_H_ #include +#include #include - +#include #include +#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 { 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)), - _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); } }; diff --git a/dde_linux/src/drivers/usb/nic/nic.cc b/dde_linux/src/drivers/usb/nic/nic.cc index 9597fcdf39..58ad54b35e 100644 --- a/dde_linux/src/drivers/usb/nic/nic.cc +++ b/dde_linux/src/drivers/usb/nic/nic.cc @@ -19,28 +19,151 @@ #include #include -#include +#include #include #include "signal.h" +extern "C" { +#include +#include +} + 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 +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 - 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); } + diff --git a/dde_linux/src/drivers/usb/signal.h b/dde_linux/src/drivers/usb/signal.h index 34d46efda3..099e186b10 100644 --- a/dde_linux/src/drivers/usb/signal.h +++ b/dde_linux/src/drivers/usb/signal.h @@ -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(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 diff --git a/dde_linux/src/drivers/usb/signal/irq.cc b/dde_linux/src/drivers/usb/signal/irq.cc index 374dc9ce26..46ff85397a 100644 --- a/dde_linux/src/drivers/usb/signal/irq.cc +++ b/dde_linux/src/drivers/usb/signal/irq.cc @@ -13,15 +13,15 @@ #include #include -#include + extern "C" { #include } - /* 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::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); /* 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; } + diff --git a/dde_linux/src/drivers/usb/storage/scsi.c b/dde_linux/src/drivers/usb/storage/scsi.c index 6d6c4ed426..2c66bcb56b 100644 --- a/dde_linux/src/drivers/usb/storage/scsi.c +++ b/dde_linux/src/drivers/usb/storage/scsi.c @@ -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; } diff --git a/dde_linux/src/drivers/usb/storage/storage.cc b/dde_linux/src/drivers/usb/storage/storage.cc index 9c3de0d4a2..f013b55e8b 100644 --- a/dde_linux/src/drivers/usb/storage/storage.cc +++ b/dde_linux/src/drivers/usb/storage/storage.cc @@ -128,11 +128,11 @@ class Storage_device : public Genode::List::Element, cmnd->session = (void *)session; Genode::uint32_t be_block_nr = bswap(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); diff --git a/dde_linux/src/drivers/usb/test.cc b/dde_linux/src/drivers/usb/test.cc new file mode 100644 index 0000000000..0e98907a7f --- /dev/null +++ b/dde_linux/src/drivers/usb/test.cc @@ -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