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