Issueing commands to xHC

To issue commands to the USB device or the xHC, the xhci driver uses two basic structures, the Command TRBs and the Command Ring. In effect, the Command Ring is a circular buffer in host memory where the Command TRBs to be passed to the xHC are stored. The xHC reads the Command TRBs placed on the Command Ring by the xhci driver using DMA read transfers.

In order for the above scheme to work, two elementary things are needed:
1) to indicate to the xHC that there is an unhandled Command TRB on the Command Ring waiting for execution
2) and to communicate to the xHC the DMA address of the Command Ring

These are performed with the use of two memory-mapped registers:
1) the first by writing to the Host Controller Doorbell Register.
2) and the second via the Command Ring Control Register.
More specifically, xHC has an internal register, called Command Ring Dequeue Pointer, the value of which is initialized with the value written to the memory-mapped Command Ring Control Register and is updated by the xHC when it finishes the processing of each stored command. When the command is completed, xHC writes the value of this internal register to the Command Completion Event TRB that posts in the Event Ring.

The xhci driver is informed about the completion status of the commands passed to xHC via different circular buffers called Event Rings. The Event Rings, that also rest in host memory, are populated by the xHC with the so-called Event TRBs using DMA write transfers.

So, when the xhci driver wants to issue a command to the xHC needs to build the appropriate Command TRB, to enqueue it in the Command Ring and to ring the xHC doorbell via writing to the Host Controller Doorbell register.

The Command Ring is allocated in xhci_mem_init():

xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags);

And its DMA address is written in the Command Ring Control Register:

val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
       		(xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) |
		xhci->cmd_ring->cycle_state;
xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);

The function for ringing the xHC doorbell is the xhci_ring_cmd_db(), in which the doorbell register is written:

xhci_writel(xhci, DB_VALUE_HOST, &xhci->dba->doorbell[0]);

The xhci driver stores all information related to a command into the structure xhci_command, that is defined as follows:

struct xhci_command {
	struct xhci_container_ctx	*in_ctx;
	u32				status;
	struct completion		*completion;
	union xhci_trb			*command_trb;
	struct list_head		cmd_list;
};

The ‘completion’ field is used when xhci driver waits for the completion of the command, otherwise ‘completion’ is set to NULL. The completion structure is initialized using init_completion(cmd->completion).
The xhci driver calls wait_for_completion_interruptible_timeout(cmd->completion, time_interval) to wait for the command’s completion for a predefined time interval. The completion is triggered using complete(cmd->completion). In order for a command to be allocated with its ‘completion’ field allocated and initialized, you need to call xhci_alloc_command() with the third argument ‘allocate_completion’ set to true. If wait_for_completion_interruptible_timeout() returns 0 the time interval has passed and complete() has not be called, if it returns a negative code a signal interrupted the thread waiting on this completion and if it returns 1 complete() was called before the time interval expires.

The ‘status’ field is the command completion status reported by the Command Completion Event TRB and it is written into this field before the command completes.

The ‘cmd_list’ field is used to form a node on a device ‘s list command list. Each device is associated with a list of commands issued to it and that have a completion thread associated with them. New commands to the device are allocated and added at the end of the device ‘s command list.
When a command completes, actually when xhci_complete_cmd_in_cmd_wait_list() is called, the command is deleted from the device ‘s command list.

The fields ‘command_trb’ and ‘in_ctx’ are pointers to the data structures that hold the command and its parameters. Briefly, the Command TRB is a 64 bytes structure reporting the type of the command, the slot and the endpoint IDs to which the command is issued and the DMA address of the Input Context, in case the command wants to configure the slot or endpoint contexts.

After the allocation and initialization of the xhci_command structure, the command is entered in the Command Ring using xhci_queue_<command_type>() functions, that set appropriately, depending on the command type, the fields of the Command TRB and update the Command Ring with the new Command TRB. To inform xHC that a new command has been enqueued, we ring the doorbell using xhci_ring_cmd_db(). Furthermore, the xhci_command is inserted to the device command list.

After the command execution, xHC generates a Command Completion Event TRB, posts it to the xhci driver via the Event Ring and generates a interrupt. The xhci has more than one Event Rings, each one associated with an interrupt line (more about the xhci interrupters’ interface will be said in a follow-on post). The Command Completion Event TRB informs xhci driver about the command’s completion status. The xHC interrupts are handled by the xhci_irq() routine, which basically acknowledges the interrupt and calls xhci_handle_event() to handle the event accordingly to its type (apart from the Command Completion Events, there are also other types of events passed to the Event Ring such as Transfer Events). Hence, the Command Completion Events are actually handled by handle_cmd_completion(). Different type of commands are handled differently upon completion. xHC will post a Command Completion Event on every command issued to the Command Ring.

Under some situations, xhci driver needs to wait on the completion of a command before comtinue its tasks. For example, the driver have to wait for the completion of a Configure Endpoint command before issueing further commands to the host controller. That ‘s why the driver calls wait_for_completion_interruptible_timeout() after queueing a Configure Endpoint command and the command completion handler has to call complete() for that command. The same stands for the Address Device, Evaluate Context and Enable Slot commands. If you are interested in waiting on the completion of other commands, you need to ensure that complete() will be called in the code path, otherwise the timer will expires although the Command Completion Event was generated by xHC.

Also, another thing you should care about, when issuing a command, is to not forget to free the xhci_command struct and delete it from the device command list.

Detailed documentation on the available commands and their functionality can be found in the xHCI Specification.

To be updated (probably)…

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s