From f1820eb4f44dfbfc16f06fbaff9ce3d9dde268f5 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 4 Apr 2024 08:25:49 +0200 Subject: usb: xhci: refactor xhci_set_configuration In the next step endpoints for multiple interfaces are set up. Move most of the per endpoint initialization to separate function to avoid another identation level. Reviewed-by: Marek Vasut Reviewed-by: Neal Gompa Signed-off-by: Janne Grunau --- drivers/usb/host/xhci.c | 119 +++++++++++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index d13cbff9b37..534c4b973fb 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -475,67 +475,34 @@ static int xhci_configure_endpoints(struct usb_device *udev, bool ctx_change) } /** - * Configure the endpoint, programming the device contexts. + * Fill endpoint contexts for interface descriptor ifdesc. * - * @param udev pointer to the USB device structure - * Return: returns the status of the xhci_configure_endpoints + * @param udev pointer to the USB device structure + * @param ctrl pointer to the xhci pravte device structure + * @param virt_dev pointer to the xhci virtual device structure + * @param ifdesc pointer to the USB interface config descriptor + * Return: returns the status of xhci_init_ep_contexts_if */ -static int xhci_set_configuration(struct usb_device *udev) +static int xhci_init_ep_contexts_if(struct usb_device *udev, + struct xhci_ctrl *ctrl, + struct xhci_virt_device *virt_dev, + struct usb_interface *ifdesc + ) { - struct xhci_container_ctx *in_ctx; - struct xhci_container_ctx *out_ctx; - struct xhci_input_control_ctx *ctrl_ctx; - struct xhci_slot_ctx *slot_ctx; struct xhci_ep_ctx *ep_ctx[MAX_EP_CTX_NUM]; int cur_ep; - int max_ep_flag = 0; int ep_index; unsigned int dir; unsigned int ep_type; - struct xhci_ctrl *ctrl = xhci_get_ctrl(udev); - int num_of_ep; - int ep_flag = 0; u64 trb_64 = 0; - int slot_id = udev->slot_id; - struct xhci_virt_device *virt_dev = ctrl->devs[slot_id]; - struct usb_interface *ifdesc; u32 max_esit_payload; unsigned int interval; unsigned int mult; unsigned int max_burst; unsigned int avg_trb_len; unsigned int err_count = 0; + int num_of_ep = ifdesc->no_of_ep; - out_ctx = virt_dev->out_ctx; - in_ctx = virt_dev->in_ctx; - - num_of_ep = udev->config.if_desc[0].no_of_ep; - ifdesc = &udev->config.if_desc[0]; - - ctrl_ctx = xhci_get_input_control_ctx(in_ctx); - /* Initialize the input context control */ - ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG); - ctrl_ctx->drop_flags = 0; - - /* EP_FLAG gives values 1 & 4 for EP1OUT and EP2IN */ - for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) { - ep_flag = xhci_get_ep_index(&ifdesc->ep_desc[cur_ep]); - ctrl_ctx->add_flags |= cpu_to_le32(1 << (ep_flag + 1)); - if (max_ep_flag < ep_flag) - max_ep_flag = ep_flag; - } - - xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size); - - /* slot context */ - xhci_slot_copy(ctrl, in_ctx, out_ctx); - slot_ctx = xhci_get_slot_ctx(ctrl, in_ctx); - slot_ctx->dev_info &= ~(cpu_to_le32(LAST_CTX_MASK)); - slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(max_ep_flag + 1) | 0); - - xhci_endpoint_copy(ctrl, in_ctx, out_ctx, 0); - - /* filling up ep contexts */ for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) { struct usb_endpoint_descriptor *endpt_desc = NULL; struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc = NULL; @@ -561,7 +528,8 @@ static int xhci_set_configuration(struct usb_device *udev) avg_trb_len = max_esit_payload; ep_index = xhci_get_ep_index(endpt_desc); - ep_ctx[ep_index] = xhci_get_ep_ctx(ctrl, in_ctx, ep_index); + ep_ctx[ep_index] = xhci_get_ep_ctx(ctrl, virt_dev->in_ctx, + ep_index); /* Allocate the ep rings */ virt_dev->eps[ep_index].ring = xhci_ring_alloc(ctrl, 1, true); @@ -614,6 +582,65 @@ static int xhci_set_configuration(struct usb_device *udev) } } + return 0; +} + +/** + * Configure the endpoint, programming the device contexts. + * + * @param udev pointer to the USB device structure + * Return: returns the status of the xhci_configure_endpoints + */ +static int xhci_set_configuration(struct usb_device *udev) +{ + struct xhci_container_ctx *out_ctx; + struct xhci_container_ctx *in_ctx; + struct xhci_input_control_ctx *ctrl_ctx; + struct xhci_slot_ctx *slot_ctx; + int err; + int cur_ep; + int max_ep_flag = 0; + struct xhci_ctrl *ctrl = xhci_get_ctrl(udev); + int num_of_ep; + int ep_flag = 0; + int slot_id = udev->slot_id; + struct xhci_virt_device *virt_dev = ctrl->devs[slot_id]; + struct usb_interface *ifdesc; + + out_ctx = virt_dev->out_ctx; + in_ctx = virt_dev->in_ctx; + + num_of_ep = udev->config.if_desc[0].no_of_ep; + ifdesc = &udev->config.if_desc[0]; + + ctrl_ctx = xhci_get_input_control_ctx(in_ctx); + /* Initialize the input context control */ + ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG); + ctrl_ctx->drop_flags = 0; + + /* EP_FLAG gives values 1 & 4 for EP1OUT and EP2IN */ + for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) { + ep_flag = xhci_get_ep_index(&ifdesc->ep_desc[cur_ep]); + ctrl_ctx->add_flags |= cpu_to_le32(1 << (ep_flag + 1)); + if (max_ep_flag < ep_flag) + max_ep_flag = ep_flag; + } + + xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size); + + /* slot context */ + xhci_slot_copy(ctrl, in_ctx, out_ctx); + slot_ctx = xhci_get_slot_ctx(ctrl, in_ctx); + slot_ctx->dev_info &= ~(cpu_to_le32(LAST_CTX_MASK)); + slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(max_ep_flag + 1) | 0); + + xhci_endpoint_copy(ctrl, in_ctx, out_ctx, 0); + + /* filling up ep contexts */ + err = xhci_init_ep_contexts_if(udev, ctrl, virt_dev, ifdesc); + if (err < 0) + return err; + return xhci_configure_endpoints(udev, false); } -- cgit v1.3.1 From 086e461d9e2cc0b98a187883774fa4b8be68a0ab Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 4 Apr 2024 08:25:50 +0200 Subject: usb: xhci: Set up endpoints for the first 2 interfaces The xhci driver currently only does the necessary initialization for endpoints found in the first interface descriptor. Apple USB keyboards (released 2021) use the second interface descriptor for the HID keyboard boot protocol. To allow USB drivers to use endpoints from other interface descriptors the xhci driver needs to ensure these endpoints are initialized as well. Use USB_MAX_ACTIVE_INTERFACES to control how many interface descriptors are considered during endpoint initialisation. For now define it to 2 as that is sufficient for supporting the Apple keyboards. Reviewed-by: Marek Vasut Reviewed-by: Neal Gompa Signed-off-by: Janne Grunau --- drivers/usb/host/xhci.c | 31 +++++++++++++++++++------------ include/usb.h | 6 ++++++ 2 files changed, 25 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 534c4b973fb..741e186ee05 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -606,24 +606,28 @@ static int xhci_set_configuration(struct usb_device *udev) int slot_id = udev->slot_id; struct xhci_virt_device *virt_dev = ctrl->devs[slot_id]; struct usb_interface *ifdesc; + unsigned int ifnum; + unsigned int max_ifnum = min((unsigned int)USB_MAX_ACTIVE_INTERFACES, + (unsigned int)udev->config.no_of_if); out_ctx = virt_dev->out_ctx; in_ctx = virt_dev->in_ctx; - num_of_ep = udev->config.if_desc[0].no_of_ep; - ifdesc = &udev->config.if_desc[0]; - ctrl_ctx = xhci_get_input_control_ctx(in_ctx); /* Initialize the input context control */ ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG); ctrl_ctx->drop_flags = 0; - /* EP_FLAG gives values 1 & 4 for EP1OUT and EP2IN */ - for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) { - ep_flag = xhci_get_ep_index(&ifdesc->ep_desc[cur_ep]); - ctrl_ctx->add_flags |= cpu_to_le32(1 << (ep_flag + 1)); - if (max_ep_flag < ep_flag) - max_ep_flag = ep_flag; + for (ifnum = 0; ifnum < max_ifnum; ifnum++) { + ifdesc = &udev->config.if_desc[ifnum]; + num_of_ep = ifdesc->no_of_ep; + /* EP_FLAG gives values 1 & 4 for EP1OUT and EP2IN */ + for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) { + ep_flag = xhci_get_ep_index(&ifdesc->ep_desc[cur_ep]); + ctrl_ctx->add_flags |= cpu_to_le32(1 << (ep_flag + 1)); + if (max_ep_flag < ep_flag) + max_ep_flag = ep_flag; + } } xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size); @@ -637,9 +641,12 @@ static int xhci_set_configuration(struct usb_device *udev) xhci_endpoint_copy(ctrl, in_ctx, out_ctx, 0); /* filling up ep contexts */ - err = xhci_init_ep_contexts_if(udev, ctrl, virt_dev, ifdesc); - if (err < 0) - return err; + for (ifnum = 0; ifnum < max_ifnum; ifnum++) { + ifdesc = &udev->config.if_desc[ifnum]; + err = xhci_init_ep_contexts_if(udev, ctrl, virt_dev, ifdesc); + if (err < 0) + return err; + } return xhci_configure_endpoints(udev, false); } diff --git a/include/usb.h b/include/usb.h index 09e3f0cb309..3aafdc8bfd1 100644 --- a/include/usb.h +++ b/include/usb.h @@ -49,6 +49,12 @@ extern bool usb_started; /* flag for the started/stopped USB status */ */ #define USB_TIMEOUT_MS(pipe) (usb_pipebulk(pipe) ? 5000 : 1000) +/* + * The xhcd hcd driver prepares only a limited number interfaces / endpoints. + * Define this limit so that drivers do not exceed it. + */ +#define USB_MAX_ACTIVE_INTERFACES 2 + /* device request (setup) */ struct devrequest { __u8 requesttype; -- cgit v1.3.1 From 0b6775c40283dd645a28b30cafa9d8cc19dc34aa Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 4 Apr 2024 08:25:51 +0200 Subject: usb: xhci: Abort transfers with unallocated rings Discovered while trying to use the second interface in the USB keyboard driver necessary on Apple USB keyboards. Reviewed-by: Marek Vasut Reviewed-by: Neal Gompa Signed-off-by: Janne Grunau --- drivers/usb/host/xhci-ring.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index b60661fe05e..910c5f3352b 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -685,6 +685,9 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, reset_ep(udev, ep_index); ring = virt_dev->eps[ep_index].ring; + if (!ring) + return -EINVAL; + /* * How much data is (potentially) left before the 64KB boundary? * XHCI Spec puts restriction( TABLE 49 and 6.4.1 section of XHCI Spec) @@ -871,6 +874,8 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, ep_index = usb_pipe_ep_index(pipe); ep_ring = virt_dev->eps[ep_index].ring; + if (!ep_ring) + return -EINVAL; /* * Check to see if the max packet size for the default control -- cgit v1.3.1