Commit c507565a authored by Chunfeng Yun's avatar Chunfeng Yun Committed by Greg Kroah-Hartman
Browse files

usb: mtu3: give back request when rx error happens



When the Rx enconnter errors, currently, only print error logs, that
may cause class driver's RX halt, shall give back the request with
error status meanwhile.

Signed-off-by: default avatarChunfeng Yun <chunfeng.yun@mediatek.com>
Link: https://lore.kernel.org/r/20230417025203.18097-1-chunfeng.yun@mediatek.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d6f712f5
Loading
Loading
Loading
Loading
+36 −1
Original line number Diff line number Diff line
@@ -466,6 +466,37 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
	mtu3_qmu_resume(mep);
}

/*
 * when rx error happens (except zlperr), QMU will stop, and RQCPR saves
 * the GPD encountered error, Done irq will arise after resuming QMU again.
 */
static void qmu_error_rx(struct mtu3 *mtu, u8 epnum)
{
	struct mtu3_ep *mep = mtu->out_eps + epnum;
	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
	struct qmu_gpd *gpd_current = NULL;
	struct mtu3_request *mreq;
	dma_addr_t cur_gpd_dma;

	cur_gpd_dma = read_rxq_cur_addr(mtu->mac_base, epnum);
	gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);

	mreq = next_request(mep);
	if (!mreq || mreq->gpd != gpd_current) {
		dev_err(mtu->dev, "no correct RX req is found\n");
		return;
	}

	mreq->request.status = -EAGAIN;

	/* by pass the current GDP */
	gpd_current->dw0_info |= cpu_to_le32(GPD_FLAGS_BPS | GPD_FLAGS_HWO);
	mtu3_qmu_resume(mep);

	dev_dbg(mtu->dev, "%s EP%d, current=%p, req=%p\n",
		__func__, epnum, gpd_current, mreq);
}

/*
 * NOTE: request list maybe is already empty as following case:
 * queue_tx --> qmu_interrupt(clear interrupt pending, schedule tasklet)-->
@@ -571,14 +602,18 @@ static void qmu_exception_isr(struct mtu3 *mtu, u32 qmu_status)

	if ((qmu_status & RXQ_CSERR_INT) || (qmu_status & RXQ_LENERR_INT)) {
		errval = mtu3_readl(mbase, U3D_RQERRIR0);
		mtu3_writel(mbase, U3D_RQERRIR0, errval);

		for (i = 1; i < mtu->num_eps; i++) {
			if (errval & QMU_RX_CS_ERR(i))
				dev_err(mtu->dev, "Rx %d CS error!\n", i);

			if (errval & QMU_RX_LEN_ERR(i))
				dev_err(mtu->dev, "RX %d Length error\n", i);

			if (errval & (QMU_RX_CS_ERR(i) | QMU_RX_LEN_ERR(i)))
				qmu_error_rx(mtu, i);
		}
		mtu3_writel(mbase, U3D_RQERRIR0, errval);
	}

	if (qmu_status & RXQ_ZLPERR_INT) {