This patch assign devices to different interrupters based on their slot_id. However, it's not mandatory that a device should use the same interrupter. A device can assign its control transfer to one interrupter and bulk/intr/ isoc transfer to another. The interrupter usage policy is flexible. This policy in this patch may be replaced by better approach in the future. Signed-off-by: Andiry Xu <andiry.xu@xxxxxxx> --- drivers/usb/host/xhci-mem.c | 3 +++ drivers/usb/host/xhci-ring.c | 22 ++++++++++++++-------- drivers/usb/host/xhci.h | 2 ++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 3468b8e..ccbb375 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -780,6 +780,9 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, INIT_LIST_HEAD(&dev->cmd_list); dev->udev = udev; + /* Decide the interrupter target */ + dev->intr_target = slot_id % xhci->intr_num; + /* Point to output device context in dcbaa. */ xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma; xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 7d4ee35..3f40c42 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2510,6 +2510,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, bool first_trb; u64 addr; bool more_trbs_coming; + int intr; struct xhci_generic_trb *start_trb; int start_cycle; @@ -2530,6 +2531,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, urb_priv = urb->hcpriv; td = urb_priv->td[0]; + intr = xhci->devs[slot_id]->intr_target; /* * Don't give the first TRB to the hardware (by toggling the cycle bit) * until we've finished creating all the other TRBs. The ring's cycle @@ -2600,7 +2602,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, running_total) ; length_field = TRB_LEN(trb_buff_len) | remainder | - TRB_INTR_TARGET(0); + TRB_INTR_TARGET(intr); if (num_trbs > 1) more_trbs_coming = true; else @@ -2660,9 +2662,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, bool more_trbs_coming; int start_cycle; u32 field, length_field; - int running_total, trb_buff_len, ret; u64 addr; + int intr; if (urb->num_sgs) return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index); @@ -2706,6 +2708,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, urb_priv = urb->hcpriv; td = urb_priv->td[0]; + intr = xhci->devs[slot_id]->intr_target; /* * Don't give the first TRB to the hardware (by toggling the cycle bit) * until we've finished creating all the other TRBs. The ring's cycle @@ -2751,7 +2754,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, running_total); length_field = TRB_LEN(trb_buff_len) | remainder | - TRB_INTR_TARGET(0); + TRB_INTR_TARGET(intr); if (num_trbs > 1) more_trbs_coming = true; else @@ -2795,6 +2798,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, u32 field, length_field; struct urb_priv *urb_priv; struct xhci_td *td; + int intr; ep_ring = xhci_urb_to_transfer_ring(xhci, urb); if (!ep_ring) @@ -2828,6 +2832,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, urb_priv = urb->hcpriv; td = urb_priv->td[0]; + intr = xhci->devs[slot_id]->intr_target; /* * Don't give the first TRB to the hardware (by toggling the cycle bit) * until we've finished creating all the other TRBs. The ring's cycle @@ -2847,7 +2852,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* FIXME endianness is probably going to bite my ass here. */ setup->bRequestType | setup->bRequest << 8 | setup->wValue << 16, setup->wIndex | setup->wLength << 16, - TRB_LEN(8) | TRB_INTR_TARGET(0), + TRB_LEN(8) | TRB_INTR_TARGET(intr), /* Immediate data in pointer */ field); @@ -2855,7 +2860,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field = 0; length_field = TRB_LEN(urb->transfer_buffer_length) | xhci_td_remainder(urb->transfer_buffer_length) | - TRB_INTR_TARGET(0); + TRB_INTR_TARGET(intr); if (urb->transfer_buffer_length > 0) { if (setup->bRequestType & USB_DIR_IN) field |= TRB_DIR_IN; @@ -2879,7 +2884,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, queue_trb(xhci, ep_ring, false, false, 0, 0, - TRB_INTR_TARGET(0), + TRB_INTR_TARGET(intr), /* Event on completion */ field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state); @@ -2924,7 +2929,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, u32 field, length_field; int running_total, trb_buff_len, td_len, td_remain_len, ret; u64 start_addr, addr; - int i, j; + int i, j, intr; bool more_trbs_coming; ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; @@ -2948,6 +2953,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, start_trb = &ep_ring->enqueue->generic; start_cycle = ep_ring->cycle_state; + intr = xhci->devs[slot_id]->intr_target; /* Queue the first TRB, even if it's zero-length */ for (i = 0; i < num_tds; i++) { first_trb = true; @@ -3010,7 +3016,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, remainder = xhci_td_remainder(td_len - running_total); length_field = TRB_LEN(trb_buff_len) | remainder | - TRB_INTR_TARGET(0); + TRB_INTR_TARGET(intr); queue_trb(xhci, ep_ring, false, more_trbs_coming, lower_32_bits(addr), upper_32_bits(addr), diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index a31f833..1df5cdf 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -774,6 +774,8 @@ struct xhci_virt_device { int num_rings_cached; /* Store xHC assigned device address */ int address; + /* Store the interrupter target */ + int intr_target; #define XHCI_MAX_RINGS_CACHED 31 struct xhci_virt_ep eps[31]; struct completion cmd_completion; -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html