Commit 8a5f0665da6701f06443ae989e9c0962807a1249
Committed by
Simon Glass
1 parent
029fd8ea1f
Exists in
v2017.01-smarct4x
and in
34 other branches
dm: usb: Add support for interrupt queues to the dm usb code
Interrupt endpoints typically are polled for a long time by the usb controller before they return anything, so calls to submit_int_msg() can take a long time to complete this. To avoid this the u-boot code has the an interrupt queue mechanism / API, add support for this to the driver-model usb code and implement it for the dm ehci code. See the added doc comments for more details. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Simon Glass <sjg@chromium.org>
Showing 3 changed files with 109 additions and 1 deletions Side-by-side Diff
drivers/usb/host/ehci-hcd.c
... | ... | @@ -1605,6 +1605,29 @@ |
1605 | 1605 | return _ehci_submit_int_msg(udev, pipe, buffer, length, interval); |
1606 | 1606 | } |
1607 | 1607 | |
1608 | +static struct int_queue *ehci_create_int_queue(struct udevice *dev, | |
1609 | + struct usb_device *udev, unsigned long pipe, int queuesize, | |
1610 | + int elementsize, void *buffer, int interval) | |
1611 | +{ | |
1612 | + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); | |
1613 | + return _ehci_create_int_queue(udev, pipe, queuesize, elementsize, | |
1614 | + buffer, interval); | |
1615 | +} | |
1616 | + | |
1617 | +static void *ehci_poll_int_queue(struct udevice *dev, struct usb_device *udev, | |
1618 | + struct int_queue *queue) | |
1619 | +{ | |
1620 | + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); | |
1621 | + return _ehci_poll_int_queue(udev, queue); | |
1622 | +} | |
1623 | + | |
1624 | +static int ehci_destroy_int_queue(struct udevice *dev, struct usb_device *udev, | |
1625 | + struct int_queue *queue) | |
1626 | +{ | |
1627 | + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); | |
1628 | + return _ehci_destroy_int_queue(udev, queue); | |
1629 | +} | |
1630 | + | |
1608 | 1631 | int ehci_register(struct udevice *dev, struct ehci_hccr *hccr, |
1609 | 1632 | struct ehci_hcor *hcor, const struct ehci_ops *ops, |
1610 | 1633 | uint tweaks, enum usb_init_type init) |
... | ... | @@ -1653,6 +1676,9 @@ |
1653 | 1676 | .control = ehci_submit_control_msg, |
1654 | 1677 | .bulk = ehci_submit_bulk_msg, |
1655 | 1678 | .interrupt = ehci_submit_int_msg, |
1679 | + .create_int_queue = ehci_create_int_queue, | |
1680 | + .poll_int_queue = ehci_poll_int_queue, | |
1681 | + .destroy_int_queue = ehci_destroy_int_queue, | |
1656 | 1682 | }; |
1657 | 1683 | |
1658 | 1684 | #endif |
drivers/usb/host/usb-uclass.c
... | ... | @@ -65,6 +65,42 @@ |
65 | 65 | return ops->bulk(bus, udev, pipe, buffer, length); |
66 | 66 | } |
67 | 67 | |
68 | +struct int_queue *create_int_queue(struct usb_device *udev, | |
69 | + unsigned long pipe, int queuesize, int elementsize, | |
70 | + void *buffer, int interval) | |
71 | +{ | |
72 | + struct udevice *bus = udev->controller_dev; | |
73 | + struct dm_usb_ops *ops = usb_get_ops(bus); | |
74 | + | |
75 | + if (!ops->create_int_queue) | |
76 | + return NULL; | |
77 | + | |
78 | + return ops->create_int_queue(bus, udev, pipe, queuesize, elementsize, | |
79 | + buffer, interval); | |
80 | +} | |
81 | + | |
82 | +void *poll_int_queue(struct usb_device *udev, struct int_queue *queue) | |
83 | +{ | |
84 | + struct udevice *bus = udev->controller_dev; | |
85 | + struct dm_usb_ops *ops = usb_get_ops(bus); | |
86 | + | |
87 | + if (!ops->poll_int_queue) | |
88 | + return NULL; | |
89 | + | |
90 | + return ops->poll_int_queue(bus, udev, queue); | |
91 | +} | |
92 | + | |
93 | +int destroy_int_queue(struct usb_device *udev, struct int_queue *queue) | |
94 | +{ | |
95 | + struct udevice *bus = udev->controller_dev; | |
96 | + struct dm_usb_ops *ops = usb_get_ops(bus); | |
97 | + | |
98 | + if (!ops->destroy_int_queue) | |
99 | + return -ENOSYS; | |
100 | + | |
101 | + return ops->destroy_int_queue(bus, udev, queue); | |
102 | +} | |
103 | + | |
68 | 104 | int usb_alloc_device(struct usb_device *udev) |
69 | 105 | { |
70 | 106 | struct udevice *bus = udev->controller_dev; |
include/usb.h
... | ... | @@ -198,7 +198,7 @@ |
198 | 198 | int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, |
199 | 199 | int transfer_len, int interval); |
200 | 200 | |
201 | -#if defined CONFIG_USB_EHCI || defined CONFIG_MUSB_HOST | |
201 | +#if defined CONFIG_USB_EHCI || defined CONFIG_MUSB_HOST || defined(CONFIG_DM_USB) | |
202 | 202 | struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe, |
203 | 203 | int queuesize, int elementsize, void *buffer, int interval); |
204 | 204 | int destroy_int_queue(struct usb_device *dev, struct int_queue *queue); |
... | ... | @@ -660,6 +660,52 @@ |
660 | 660 | int (*interrupt)(struct udevice *bus, struct usb_device *udev, |
661 | 661 | unsigned long pipe, void *buffer, int length, |
662 | 662 | int interval); |
663 | + | |
664 | + /** | |
665 | + * create_int_queue() - Create and queue interrupt packets | |
666 | + * | |
667 | + * Create and queue @queuesize number of interrupt usb packets of | |
668 | + * @elementsize bytes each. @buffer must be atleast @queuesize * | |
669 | + * @elementsize bytes. | |
670 | + * | |
671 | + * Note some controllers only support a queuesize of 1. | |
672 | + * | |
673 | + * @interval: Interrupt interval | |
674 | + * | |
675 | + * @return A pointer to the created interrupt queue or NULL on error | |
676 | + */ | |
677 | + struct int_queue * (*create_int_queue)(struct udevice *bus, | |
678 | + struct usb_device *udev, unsigned long pipe, | |
679 | + int queuesize, int elementsize, void *buffer, | |
680 | + int interval); | |
681 | + | |
682 | + /** | |
683 | + * poll_int_queue() - Poll an interrupt queue for completed packets | |
684 | + * | |
685 | + * Poll an interrupt queue for completed packets. The return value | |
686 | + * points to the part of the buffer passed to create_int_queue() | |
687 | + * corresponding to the completed packet. | |
688 | + * | |
689 | + * @queue: queue to poll | |
690 | + * | |
691 | + * @return Pointer to the data of the first completed packet, or | |
692 | + * NULL if no packets are ready | |
693 | + */ | |
694 | + void * (*poll_int_queue)(struct udevice *bus, struct usb_device *udev, | |
695 | + struct int_queue *queue); | |
696 | + | |
697 | + /** | |
698 | + * destroy_int_queue() - Destroy an interrupt queue | |
699 | + * | |
700 | + * Destroy an interrupt queue created by create_int_queue(). | |
701 | + * | |
702 | + * @queue: queue to poll | |
703 | + * | |
704 | + * @return 0 if OK, -ve on error | |
705 | + */ | |
706 | + int (*destroy_int_queue)(struct udevice *bus, struct usb_device *udev, | |
707 | + struct int_queue *queue); | |
708 | + | |
663 | 709 | /** |
664 | 710 | * alloc_device() - Allocate a new device context (XHCI) |
665 | 711 | * |