Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ecb7bc41 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: xhci: Fix Command Ring Stopped Event handling"

parents 8a70d14d b099ce3b
Loading
Loading
Loading
Loading
+33 −52
Original line number Diff line number Diff line
@@ -1367,47 +1367,11 @@ static int xhci_search_cmd_trb_in_cd_list(struct xhci_hcd *xhci,
	return 0;
}

/*
 * If the cmd_trb_comp_code is COMP_CMD_ABORT, we just check whether the
 * trb pointed by the command ring dequeue pointer is the trb we want to
 * cancel or not. And if the cmd_trb_comp_code is COMP_CMD_STOP, we will
 * traverse the cancel_cmd_list to trun the all of the commands according
 * to command descriptor to NO-OP trb.
 */
static int handle_stopped_cmd_ring(struct xhci_hcd *xhci,
		int cmd_trb_comp_code)
{
	int cur_trb_is_good = 0;

	/* Searching the cmd trb pointed by the command ring dequeue
	 * pointer in command descriptor list. If it is found, free it.
	 */
	cur_trb_is_good = xhci_search_cmd_trb_in_cd_list(xhci,
			xhci->cmd_ring->dequeue);

	if (cmd_trb_comp_code == COMP_CMD_ABORT)
		xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
	else if (cmd_trb_comp_code == COMP_CMD_STOP) {
		/* traversing the cancel_cmd_list and canceling
		 * the command according to command descriptor
		 */
		xhci_cancel_cmd_in_cd_list(xhci);

		xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
		/*
		 * ring command ring doorbell again to restart the
		 * command ring
		 */
		if (xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue)
			xhci_ring_cmd_db(xhci);
	}
	return cur_trb_is_good;
}

static void handle_cmd_completion(struct xhci_hcd *xhci,
		struct xhci_event_cmd *event)
{
	int slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
	int comp_code = GET_COMP_CODE(le32_to_cpu(event->status));
	u64 cmd_dma;
	dma_addr_t cmd_dequeue_dma;
	struct xhci_input_control_ctx *ctrl_ctx;
@@ -1430,16 +1394,34 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
		return;
	}

	if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) ||
		(GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) {
		/* If the return value is 0, we think the trb pointed by
		 * command ring dequeue pointer is a good trb. The good
		 * trb means we don't want to cancel the trb, but it have
		 * been stopped by host. So we should handle it normally.
		 * Otherwise, driver should invoke inc_deq() and return.
		 */
		if (handle_stopped_cmd_ring(xhci,
				GET_COMP_CODE(le32_to_cpu(event->status)))) {
	/*
	 * Command Ring Stopped events point at the xHC's *current* dequeue
	 * pointer, i.e. the next command that will be executed. That TRB may
	 * or may not have been issued yet. Just overwrite all canceled commands
	 * with NOOPs and restart the ring, leaving our internal dequeue pointer
	 * as it is (we will get another event for that position later, when
	 * it has actually been executed).
	 */
	if (comp_code == COMP_CMD_STOP) {
		xhci_cancel_cmd_in_cd_list(xhci);
		xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
		if (xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue)
			xhci_ring_cmd_db(xhci);
		return;
	}

	/*
	 * If we aborted a command, we check if it is one of the commands we
	 * meant to cancel. In that case, it will be freed and we just finish
	 * up right here. If we aborted something else instead, we run it
	 * through the normal handlers below. At any rate, the command ring is
	 * stopped now, but the xHC will issue a Command Ring Stopped event
	 * after this that will cause us to restart it.
	 */
	if (comp_code == COMP_CMD_ABORT) {
		xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
		if (xhci_search_cmd_trb_in_cd_list(xhci,
			xhci->cmd_ring->dequeue)) {
			inc_deq(xhci, xhci->cmd_ring);
			return;
		}
@@ -1454,7 +1436,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
	switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])
		& TRB_TYPE_BITMASK) {
	case TRB_TYPE(TRB_ENABLE_SLOT):
		if (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_SUCCESS)
		if (comp_code == COMP_SUCCESS)
			xhci->slot_id = slot_id;
		else
			xhci->slot_id = 0;
@@ -1510,19 +1492,18 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
		}
bandwidth_change:
		xhci_dbg(xhci, "Completed config ep cmd\n");
		xhci->devs[slot_id]->cmd_status =
			GET_COMP_CODE(le32_to_cpu(event->status));
		xhci->devs[slot_id]->cmd_status = comp_code;
		complete(&xhci->devs[slot_id]->cmd_completion);
		break;
	case TRB_TYPE(TRB_EVAL_CONTEXT):
		virt_dev = xhci->devs[slot_id];
		if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event))
			break;
		xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(le32_to_cpu(event->status));
		xhci->devs[slot_id]->cmd_status = comp_code;
		complete(&xhci->devs[slot_id]->cmd_completion);
		break;
	case TRB_TYPE(TRB_ADDR_DEV):
		xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(le32_to_cpu(event->status));
		xhci->devs[slot_id]->cmd_status = comp_code;
		complete(&xhci->addr_dev);
		break;
	case TRB_TYPE(TRB_STOP_RING):