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>
This commit is contained in:
parent
029fd8ea1f
commit
8a5f0665da
|
@ -1605,6 +1605,29 @@ static int ehci_submit_int_msg(struct udevice *dev, struct usb_device *udev,
|
|||
return _ehci_submit_int_msg(udev, pipe, buffer, length, interval);
|
||||
}
|
||||
|
||||
static struct int_queue *ehci_create_int_queue(struct udevice *dev,
|
||||
struct usb_device *udev, unsigned long pipe, int queuesize,
|
||||
int elementsize, void *buffer, int interval)
|
||||
{
|
||||
debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
|
||||
return _ehci_create_int_queue(udev, pipe, queuesize, elementsize,
|
||||
buffer, interval);
|
||||
}
|
||||
|
||||
static void *ehci_poll_int_queue(struct udevice *dev, struct usb_device *udev,
|
||||
struct int_queue *queue)
|
||||
{
|
||||
debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
|
||||
return _ehci_poll_int_queue(udev, queue);
|
||||
}
|
||||
|
||||
static int ehci_destroy_int_queue(struct udevice *dev, struct usb_device *udev,
|
||||
struct int_queue *queue)
|
||||
{
|
||||
debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
|
||||
return _ehci_destroy_int_queue(udev, queue);
|
||||
}
|
||||
|
||||
int ehci_register(struct udevice *dev, struct ehci_hccr *hccr,
|
||||
struct ehci_hcor *hcor, const struct ehci_ops *ops,
|
||||
uint tweaks, enum usb_init_type init)
|
||||
|
@ -1653,6 +1676,9 @@ struct dm_usb_ops ehci_usb_ops = {
|
|||
.control = ehci_submit_control_msg,
|
||||
.bulk = ehci_submit_bulk_msg,
|
||||
.interrupt = ehci_submit_int_msg,
|
||||
.create_int_queue = ehci_create_int_queue,
|
||||
.poll_int_queue = ehci_poll_int_queue,
|
||||
.destroy_int_queue = ehci_destroy_int_queue,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -65,6 +65,42 @@ int submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
|
|||
return ops->bulk(bus, udev, pipe, buffer, length);
|
||||
}
|
||||
|
||||
struct int_queue *create_int_queue(struct usb_device *udev,
|
||||
unsigned long pipe, int queuesize, int elementsize,
|
||||
void *buffer, int interval)
|
||||
{
|
||||
struct udevice *bus = udev->controller_dev;
|
||||
struct dm_usb_ops *ops = usb_get_ops(bus);
|
||||
|
||||
if (!ops->create_int_queue)
|
||||
return NULL;
|
||||
|
||||
return ops->create_int_queue(bus, udev, pipe, queuesize, elementsize,
|
||||
buffer, interval);
|
||||
}
|
||||
|
||||
void *poll_int_queue(struct usb_device *udev, struct int_queue *queue)
|
||||
{
|
||||
struct udevice *bus = udev->controller_dev;
|
||||
struct dm_usb_ops *ops = usb_get_ops(bus);
|
||||
|
||||
if (!ops->poll_int_queue)
|
||||
return NULL;
|
||||
|
||||
return ops->poll_int_queue(bus, udev, queue);
|
||||
}
|
||||
|
||||
int destroy_int_queue(struct usb_device *udev, struct int_queue *queue)
|
||||
{
|
||||
struct udevice *bus = udev->controller_dev;
|
||||
struct dm_usb_ops *ops = usb_get_ops(bus);
|
||||
|
||||
if (!ops->destroy_int_queue)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->destroy_int_queue(bus, udev, queue);
|
||||
}
|
||||
|
||||
int usb_alloc_device(struct usb_device *udev)
|
||||
{
|
||||
struct udevice *bus = udev->controller_dev;
|
||||
|
|
|
@ -198,7 +198,7 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|||
int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int transfer_len, int interval);
|
||||
|
||||
#if defined CONFIG_USB_EHCI || defined CONFIG_MUSB_HOST
|
||||
#if defined CONFIG_USB_EHCI || defined CONFIG_MUSB_HOST || defined(CONFIG_DM_USB)
|
||||
struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
|
||||
int queuesize, int elementsize, void *buffer, int interval);
|
||||
int destroy_int_queue(struct usb_device *dev, struct int_queue *queue);
|
||||
|
@ -660,6 +660,52 @@ struct dm_usb_ops {
|
|||
int (*interrupt)(struct udevice *bus, struct usb_device *udev,
|
||||
unsigned long pipe, void *buffer, int length,
|
||||
int interval);
|
||||
|
||||
/**
|
||||
* create_int_queue() - Create and queue interrupt packets
|
||||
*
|
||||
* Create and queue @queuesize number of interrupt usb packets of
|
||||
* @elementsize bytes each. @buffer must be atleast @queuesize *
|
||||
* @elementsize bytes.
|
||||
*
|
||||
* Note some controllers only support a queuesize of 1.
|
||||
*
|
||||
* @interval: Interrupt interval
|
||||
*
|
||||
* @return A pointer to the created interrupt queue or NULL on error
|
||||
*/
|
||||
struct int_queue * (*create_int_queue)(struct udevice *bus,
|
||||
struct usb_device *udev, unsigned long pipe,
|
||||
int queuesize, int elementsize, void *buffer,
|
||||
int interval);
|
||||
|
||||
/**
|
||||
* poll_int_queue() - Poll an interrupt queue for completed packets
|
||||
*
|
||||
* Poll an interrupt queue for completed packets. The return value
|
||||
* points to the part of the buffer passed to create_int_queue()
|
||||
* corresponding to the completed packet.
|
||||
*
|
||||
* @queue: queue to poll
|
||||
*
|
||||
* @return Pointer to the data of the first completed packet, or
|
||||
* NULL if no packets are ready
|
||||
*/
|
||||
void * (*poll_int_queue)(struct udevice *bus, struct usb_device *udev,
|
||||
struct int_queue *queue);
|
||||
|
||||
/**
|
||||
* destroy_int_queue() - Destroy an interrupt queue
|
||||
*
|
||||
* Destroy an interrupt queue created by create_int_queue().
|
||||
*
|
||||
* @queue: queue to poll
|
||||
*
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int (*destroy_int_queue)(struct udevice *bus, struct usb_device *udev,
|
||||
struct int_queue *queue);
|
||||
|
||||
/**
|
||||
* alloc_device() - Allocate a new device context (XHCI)
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue