Commit d0e96f5a authored by Sarah Sharp's avatar Sarah Sharp Committed by Greg Kroah-Hartman

USB: xhci: Control transfer support.

Allow device drivers to enqueue URBs to control endpoints on devices under
an xHCI host controller.  Each control transfer is represented by a
series of Transfer Descriptors (TDs) written to an endpoint ring.  There
is one TD for the Setup phase, (optionally) one TD for the Data phase, and
one TD for the Status phase.

Enqueue these TDs onto the endpoint ring that represents the control
endpoint.  The host controller hardware will return an event on the event
ring that points to the (DMA) address of one of the TDs on the endpoint
ring.  If the transfer was successful, the transfer event TRB will have a
completion code of success, and it will point to the Status phase TD.
Anything else is considered an error.

This should work for control endpoints besides the default endpoint, but
that hasn't been tested.
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 6d65b78a
...@@ -509,6 +509,99 @@ void xhci_shutdown(struct usb_hcd *hcd) ...@@ -509,6 +509,99 @@ void xhci_shutdown(struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/**
* xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and
* HCDs. Find the index for an endpoint given its descriptor. Use the return
* value to right shift 1 for the bitmask.
*
* Index = (epnum * 2) + direction - 1,
* where direction = 0 for OUT, 1 for IN.
* For control endpoints, the IN index is used (OUT index is unused), so
* index = (epnum * 2) + direction - 1 = (epnum * 2) + 1 - 1 = (epnum * 2)
*/
unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc)
{
unsigned int index;
if (usb_endpoint_xfer_control(desc))
index = (unsigned int) (usb_endpoint_num(desc)*2);
else
index = (unsigned int) (usb_endpoint_num(desc)*2) +
(usb_endpoint_dir_in(desc) ? 1 : 0) - 1;
return index;
}
/* Returns 1 if the arguments are OK;
* returns 0 this is a root hub; returns -EINVAL for NULL pointers.
*/
int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint *ep, int check_ep, const char *func) {
if (!hcd || (check_ep && !ep) || !udev) {
printk(KERN_DEBUG "xHCI %s called with invalid args\n",
func);
return -EINVAL;
}
if (!udev->parent) {
printk(KERN_DEBUG "xHCI %s called for root hub\n",
func);
return 0;
}
if (!udev->slot_id) {
printk(KERN_DEBUG "xHCI %s called with unaddressed device\n",
func);
return -EINVAL;
}
return 1;
}
/*
* non-error returns are a promise to giveback() the urb later
* we drop ownership so next owner (or urb unlink) can get it
*/
int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
unsigned long flags;
int ret = 0;
unsigned int slot_id, ep_index;
if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0)
return -EINVAL;
slot_id = urb->dev->slot_id;
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
/* Only support ep 0 control transfers for now */
if (ep_index != 0) {
xhci_dbg(xhci, "WARN: urb submitted to unsupported ep %x\n",
urb->ep->desc.bEndpointAddress);
return -ENOSYS;
}
spin_lock_irqsave(&xhci->lock, flags);
if (!xhci->devs || !xhci->devs[slot_id]) {
if (!in_interrupt())
dev_warn(&urb->dev->dev, "WARN: urb submitted for dev with no Slot ID\n");
return -EINVAL;
}
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
if (!in_interrupt())
xhci_dbg(xhci, "urb submitted during PCI suspend\n");
ret = -ESHUTDOWN;
goto exit;
}
ret = queue_ctrl_tx(xhci, mem_flags, urb, slot_id, ep_index);
exit:
spin_unlock_irqrestore(&xhci->lock, flags);
return ret;
}
/* Remove from hardware lists
* completions normally happen asynchronously
*/
int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
return -ENOSYS;
}
/* /*
* At this point, the struct usb_device is about to go away, the device has * At this point, the struct usb_device is about to go away, the device has
* disconnected, and all traffic has been stopped and the endpoints have been * disconnected, and all traffic has been stopped and the endpoints have been
......
...@@ -141,6 +141,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, ...@@ -141,6 +141,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
if (!ring) if (!ring)
return 0; return 0;
INIT_LIST_HEAD(&ring->td_list);
if (num_segs == 0) if (num_segs == 0)
return ring; return ring;
...@@ -188,6 +189,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, ...@@ -188,6 +189,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
return 0; return 0;
} }
/* All the xhci_tds in the ring's TD list should be freed at this point */
void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
{ {
struct xhci_virt_device *dev; struct xhci_virt_device *dev;
......
...@@ -111,6 +111,8 @@ static const struct hc_driver xhci_pci_hc_driver = { ...@@ -111,6 +111,8 @@ static const struct hc_driver xhci_pci_hc_driver = {
/* /*
* managing i/o requests and associated device resources * managing i/o requests and associated device resources
*/ */
.urb_enqueue = xhci_urb_enqueue,
.urb_dequeue = xhci_urb_dequeue,
.alloc_dev = xhci_alloc_dev, .alloc_dev = xhci_alloc_dev,
.free_dev = xhci_free_dev, .free_dev = xhci_free_dev,
.address_device = xhci_address_device, .address_device = xhci_address_device,
......
This diff is collapsed.
...@@ -448,6 +448,9 @@ struct xhci_doorbell_array { ...@@ -448,6 +448,9 @@ struct xhci_doorbell_array {
#define DB_STREAM_ID_HOST 0x0 #define DB_STREAM_ID_HOST 0x0
#define DB_MASK (0xff << 8) #define DB_MASK (0xff << 8)
/* Endpoint Target - bits 0:7 */
#define EPI_TO_DB(p) (((p) + 1) & 0xff)
/** /**
* struct xhci_slot_ctx * struct xhci_slot_ctx
...@@ -552,13 +555,18 @@ struct xhci_ep_ctx { ...@@ -552,13 +555,18 @@ struct xhci_ep_ctx {
* 4 - TRB error * 4 - TRB error
* 5-7 - reserved * 5-7 - reserved
*/ */
#define EP_STATE (0xf) #define EP_STATE_MASK (0xf)
#define EP_STATE_DISABLED 0
#define EP_STATE_RUNNING 1
#define EP_STATE_HALTED 2
#define EP_STATE_STOPPED 3
#define EP_STATE_ERROR 4
/* Mult - Max number of burtst within an interval, in EP companion desc. */ /* Mult - Max number of burtst within an interval, in EP companion desc. */
#define EP_MULT(p) ((p & 0x3) << 8) #define EP_MULT(p) ((p & 0x3) << 8)
/* bits 10:14 are Max Primary Streams */ /* bits 10:14 are Max Primary Streams */
/* bit 15 is Linear Stream Array */ /* bit 15 is Linear Stream Array */
/* Interval - period between requests to an endpoint - 125u increments. */ /* Interval - period between requests to an endpoint - 125u increments. */
#define EP_INTERVAL (0xff << 16) #define EP_INTERVAL (0xff << 16)
/* ep_info2 bitmasks */ /* ep_info2 bitmasks */
/* /*
...@@ -618,7 +626,6 @@ struct xhci_virt_device { ...@@ -618,7 +626,6 @@ struct xhci_virt_device {
dma_addr_t in_ctx_dma; dma_addr_t in_ctx_dma;
/* FIXME when stream support is added */ /* FIXME when stream support is added */
struct xhci_ring *ep_rings[31]; struct xhci_ring *ep_rings[31];
dma_addr_t ep_dma[31];
/* Status of the last command issued for this device */ /* Status of the last command issued for this device */
u32 cmd_status; u32 cmd_status;
}; };
...@@ -657,6 +664,9 @@ struct xhci_transfer_event { ...@@ -657,6 +664,9 @@ struct xhci_transfer_event {
u32 flags; u32 flags;
} __attribute__ ((packed)); } __attribute__ ((packed));
/** Transfer Event bit fields **/
#define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f)
/* Completion Code - only applicable for some types of TRBs */ /* Completion Code - only applicable for some types of TRBs */
#define COMP_CODE_MASK (0xff << 24) #define COMP_CODE_MASK (0xff << 24)
#define GET_COMP_CODE(p) (((p) & COMP_CODE_MASK) >> 24) #define GET_COMP_CODE(p) (((p) & COMP_CODE_MASK) >> 24)
...@@ -877,6 +887,12 @@ union xhci_trb { ...@@ -877,6 +887,12 @@ union xhci_trb {
#define TRBS_PER_SEGMENT 64 #define TRBS_PER_SEGMENT 64
#define SEGMENT_SIZE (TRBS_PER_SEGMENT*16) #define SEGMENT_SIZE (TRBS_PER_SEGMENT*16)
struct xhci_td {
struct list_head td_list;
struct urb *urb;
union xhci_trb *last_trb;
};
struct xhci_segment { struct xhci_segment {
union xhci_trb *trbs; union xhci_trb *trbs;
/* private to HCD */ /* private to HCD */
...@@ -892,6 +908,7 @@ struct xhci_ring { ...@@ -892,6 +908,7 @@ struct xhci_ring {
union xhci_trb *dequeue; union xhci_trb *dequeue;
struct xhci_segment *deq_seg; struct xhci_segment *deq_seg;
unsigned int deq_updates; unsigned int deq_updates;
struct list_head td_list;
/* /*
* Write the cycle state into the TRB cycle field to give ownership of * Write the cycle state into the TRB cycle field to give ownership of
* the TRB to the host controller (if we are the producer), or to check * the TRB to the host controller (if we are the producer), or to check
...@@ -1042,6 +1059,8 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, struct intr_reg *ir_set, int set_n ...@@ -1042,6 +1059,8 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, struct intr_reg *ir_set, int set_n
void xhci_print_registers(struct xhci_hcd *xhci); void xhci_print_registers(struct xhci_hcd *xhci);
void xhci_dbg_regs(struct xhci_hcd *xhci); void xhci_dbg_regs(struct xhci_hcd *xhci);
void xhci_print_run_regs(struct xhci_hcd *xhci); void xhci_print_run_regs(struct xhci_hcd *xhci);
void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb);
void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb);
void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg); void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg);
void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring); void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring);
void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst); void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst);
...@@ -1055,6 +1074,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags); ...@@ -1055,6 +1074,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags);
void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id); void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id);
int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags); int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags);
int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev); int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev);
unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc);
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
/* xHCI PCI glue */ /* xHCI PCI glue */
...@@ -1074,6 +1094,8 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd); ...@@ -1074,6 +1094,8 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd);
int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev);
void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev); void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev);
int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev); int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev);
int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
/* xHCI ring, segment, TRB, and TD functions */ /* xHCI ring, segment, TRB, and TD functions */
dma_addr_t trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); dma_addr_t trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
...@@ -1083,6 +1105,7 @@ void handle_event(struct xhci_hcd *xhci); ...@@ -1083,6 +1105,7 @@ void handle_event(struct xhci_hcd *xhci);
void set_hc_event_deq(struct xhci_hcd *xhci); void set_hc_event_deq(struct xhci_hcd *xhci);
int queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id); int queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id);
int queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, u32 slot_id); int queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, u32 slot_id);
int queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index);
/* xHCI roothub code */ /* xHCI roothub code */
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment