Very low performance (~ 0.4 MB / s) with Linux kernel kernel loading and hardware loop

I am writing a Linux kernel driver for a USB user device that will use mass endpoints, everything works fine, however I get very slow data transfer speeds. In particular, it takes ~ 25 seconds to write and read data at 10 MB. I tried this on an embedded system and a Linux VM running on a smart PC with similar results.

I am using Cypress's EZ-USB FX2 development kit as the target board. He launches the firmware for the bulk cabinet, which sets two and two end points. Each endpoint has a double buffer and supports 512 bytes. The firmware checks the endpoints through a closed (1) loop in main (), not sleeping mode and copies data from the outside to the endpoints when this data is available using auto-identifiers. I was told that this could correctly transfer data to Windows using their specific application, but they did not have the opportunity to verify this.

My code (corresponding parts below) calls the mass_io function in the device probe procedure. This function creates a number (URB_SETS) out urbs that try to write 512 bytes to the device. Changing this number between 1 and 32 does not change performance. All of them are copied from the same buffer. The callback handler for each write operation to the output endpoint is used to create a read urb on the corresponding endpoint. Reading the callback creates another urb record until I hit the total number of write / read requests that I want to run at a time (20,000). I am currently working to activate most of the operations in the callback functions in the lower halves if they block other interrupts. I am also thinking of rewriting mass cycle firmware for Cypress FX2,to use interrupts instead of polling. Is there anything here that looks unusual to make performance so low? Thanks in advance. Please let me know if you want to see more code, this is just a driver for checking I / O in Cypress FX2.

:

static void bulk_io_out_callback0(struct urb *t_urb) {
    // will need to make this work with bottom half
    struct usb_dev_stat *uds = t_urb->context;
    struct urb *urb0 = usb_alloc_urb(0,GFP_KERNEL);
    if (urb0 == NULL) {
            printk("bulk_io_out_callback0: out of memory!");
    }
    usb_fill_bulk_urb(urb0, interface_to_usbdev(uds->intf), usb_rcvbulkpipe(uds->udev,uds->ep_in[0]), uds->buf_in, uds->max_packet, bulk_io_in_callback0, uds);
    usb_submit_urb(urb0,GFP_KERNEL);
    usb_free_urb(urb0);
}

:

static void bulk_io_in_callback0(struct urb *t_urb) {
    struct usb_dev_stat *uds = t_urb->context;

    struct urb *urb0 = usb_alloc_urb(0,GFP_KERNEL);
    if (urb0 == NULL) {
            printk("bulk_io_out_callback0: out of memory!");
    }

    if (uds->seq--) {
            usb_fill_bulk_urb(urb0, interface_to_usbdev(uds->intf), usb_sndbulkpipe(uds->udev,uds->ep_out[0]), uds->buf_out, uds->max_packet, bulk_io_out_callback0, uds);
            usb_submit_urb(urb0,GFP_KERNEL);
    }
    else {
            uds->t1 = get_seconds();
            uds->buf_in[9] = 0; // to ensure we only print the first 8 chars below
            printk("bulk_io_in_callback0: completed, time=%lds, bytes=%d, data=%s\n", (uds->t1-uds->t0), uds->max_packet*SEQ, uds->buf_in);
    }
    usb_free_urb(urb0);
}

urbs:

static int bulk_io (struct usb_interface *interface, struct usb_dev_stat *uds) {
    struct urb *urb0;
    int i;

    uds->t0 = get_seconds();

    memcpy(uds->buf_out,"abcd1234",8);

    uds->seq = SEQ; // how many times we will run this

    printk("bulk_io: starting up the stream, seq=%ld\n", uds->seq);

    for (i = 0; i < URB_SETS; i++) {
            urb0 = usb_alloc_urb(0,GFP_KERNEL);
            if (urb0 == NULL) {
                    printk("bulk_io: out of memory!\n");
                    return(-1);
            }

            usb_fill_bulk_urb(urb0, interface_to_usbdev(uds->intf), usb_sndbulkpipe(uds->udev,uds->ep_out[0]), uds->buf_out, uds->max_packet, bulk_io_out_callback0, uds);
                            printk("bulk_io: submitted urb, status=%d\n", usb_submit_urb(urb0,GFP_KERNEL));
            usb_free_urb(urb0); // we don't need this anymore
    }


    return(0);
}

1 , udev- > speed == 3, USB_SPEED_HIGH, , , Linux , ....

2 , urb (kmalloc, submit) , .

+5
1

.

EZ-USB FX2 Cypress . , . 512 .

, 512 .

4096 , (, ). , 1/4 , , .

, . - , , .

, , " " 512 , , - .

, - , , , 512 . ​​ .

+1

All Articles