Example #1
0
/*
   When receiving RXQ done interrupt, qmu_interrupt calls this function.

   1. Traverse GPD/BD data structures to count actual transferred length.
   2. Set the done flag to notify rxstate_qmu() to report status to upper gadget driver.

    ported from proc_qmu_rx() from test driver.

    caller:qmu_interrupt after getting QMU done interrupt and TX is raised

*/
void qmu_done_rx(struct musb *musb, u8 ep_num, unsigned long flags)
{
	TGPD *gpd = Rx_gpd_last[ep_num];
	TGPD *gpd_current = (TGPD *) (os_readl(USB_QMU_RQCPR(ep_num)));
	struct musb_ep *musb_ep = &musb->endpoints[ep_num].ep_out;
	struct usb_request *request = NULL;
	struct musb_request *req;

	/* trying to give_back the request to gadget driver. */
	req = next_request(musb_ep);
	if (!req) {
		qmu_printk(K_ERR, "[RXD]" "%s Cannot get next request of %d, "
			   "but QMU has done.\n", __func__, ep_num);
		return;
	} else {
		request = &req->request;
	}

	/*Transfer PHY addr got from QMU register to VIR addr */
	gpd_current = phys_to_virt((unsigned long)gpd_current);

	qmu_printk(K_DEBUG, "[RXD]" "%s EP%d, Last=%p, Current=%p, End=%p\n",
		   __func__, ep_num, gpd, gpd_current, Rx_gpd_end[ep_num]);

	/*gpd_current should at least point to the next GPD to the previous last one. */
	if (gpd == gpd_current) {
		qmu_printk(K_ERR, "[RXD][ERROR]" "%s gpd(%p) == gpd_current(%p)\n", __func__, gpd,
			   gpd_current);

		qmu_printk(K_ERR, "[RXD][ERROR]" "EP%d RQCSR=%x, RQSAR=%x, RQCPR=%x, RQLDPR=%x\n",
			   ep_num, os_readl(USB_QMU_RQCSR(ep_num)), os_readl(USB_QMU_RQSAR(ep_num)),
			   os_readl(USB_QMU_RQCPR(ep_num)), os_readl(USB_QMU_RQLDPR(ep_num)));

		qmu_printk(K_ERR, "[RXD][ERROR]" "QCR0=%x, QCR1=%x, QCR2=%x, QCR3=%x, "
			   "QGCSR=%x\n", os_readl(U3D_QCR0), os_readl(U3D_QCR1), os_readl(U3D_QCR2),
			   os_readl(U3D_QCR3), os_readl(U3D_QGCSR));

		qmu_printk(K_INFO, "[RXD][ERROR]" "HWO=%d, Next_GPD=%x ,DataBufLen=%d, "
			   "DataBuf=%x, RecvLen=%d, Endpoint=%d\n",
			   (DEV_UINT32) TGPD_GET_FLAG(gpd), (DEV_UINT32) TGPD_GET_NEXT(gpd),
			   (DEV_UINT32) TGPD_GET_DataBUF_LEN(gpd), (DEV_UINT32) TGPD_GET_DATA(gpd),
			   (DEV_UINT32) TGPD_GET_BUF_LEN(gpd), (DEV_UINT32) TGPD_GET_EPaddr(gpd));

		return;
	}

	spin_unlock_irqrestore(&musb->lock, flags);

	/* invalidate GPD data in CPU */
	dma_sync_single_for_cpu(musb->controller, virt_to_phys(gpd), sizeof(TGPD), DMA_FROM_DEVICE);

	spin_lock_irqsave(&musb->lock, flags);

	if (!gpd || !gpd_current) {
		qmu_printk(K_ERR, "[RXD][ERROR]" "%s EP%d, gpd=%p, gpd_current=%p, ishwo=%d, \
			rx_gpd_last=%p, RQCPR=0x%x\n", __func__, ep_num, gpd, gpd_current, ((gpd == NULL) ? 999 : TGPD_IS_FLAGS_HWO(gpd)), Rx_gpd_last[ep_num], os_readl(USB_QMU_RQCPR(ep_num)));
		return;
	}
/*
   When receiving RXQ done interrupt, qmu_interrupt calls this function.

   1. Traverse GPD/BD data structures to count actual transferred length.
   2. Set the done flag to notify rxstate_qmu() to report status to upper gadget driver.

    ported from proc_qmu_rx() from test driver.

    caller:qmu_interrupt after getting QMU done interrupt and TX is raised

*/
void qmu_done_rx(struct musb *musb, u8 ep_num, unsigned long flags)
{
	TGPD* gpd = Rx_gpd_last[ep_num];
	TGPD* gpd_current = (TGPD*)(uintptr_t)(os_readl(USB_QMU_RQCPR(ep_num))); //QMU GPD address --> CPU DMA address
	struct musb_ep		*musb_ep = &musb->endpoints[ep_num].ep_out;
	struct usb_request	*request = NULL;
	struct musb_request	*req;

	//trying to give_back the request to gadget driver.
	req = next_request(musb_ep);
	if (!req) {
		qmu_printk(K_ERR, "[RXD]""%s Cannot get next request of %d, "
			"but QMU has done.\n", __func__, ep_num);
		return;
	} else {
		request = &req->request;
	}

	/*Transfer PHY addr got from QMU register to VIR addr*/
	gpd_current = gpd_phys_to_virt(gpd_current, USB_RX, ep_num);

	qmu_printk(K_DEBUG, "[RXD]""%s EP%d, Last=%p, Current=%p, End=%p\n",
		__func__, ep_num, gpd, gpd_current, Rx_gpd_end[ep_num]);

	/*gpd_current should at least point to the next GPD to the previous last one.*/
	if (gpd == gpd_current) {
		qmu_printk(K_ERR, "[RXD][ERROR]""%s gpd(%p) == gpd_current(%p)\n", __func__, gpd, \
			gpd_current);

		qmu_printk(K_ERR, "[RXD][ERROR]""EP%d RQCSR=%x, RQSAR=%x, RQCPR=%x, RQLDPR=%x\n",
				ep_num, os_readl(USB_QMU_RQCSR(ep_num)), os_readl(USB_QMU_RQSAR(ep_num)),
				os_readl(USB_QMU_RQCPR(ep_num)), os_readl(USB_QMU_RQLDPR(ep_num)));

		qmu_printk(K_ERR, "[RXD][ERROR]""QCR0=%x, QCR1=%x, QCR2=%x, QCR3=%x, "
			"QGCSR=%x\n", os_readl(U3D_QCR0), os_readl(U3D_QCR1), os_readl(U3D_QCR2), \
			os_readl(U3D_QCR3), os_readl(U3D_QGCSR));

		qmu_printk(K_INFO,"[RXD][ERROR]""HWO=%d, Next_GPD=%lx ,DataBufLen=%d, "
			"DataBuf=%lx, RecvLen=%d, Endpoint=%d\n",
			(u32)TGPD_GET_FLAG(gpd), (uintptr_t)TGPD_GET_NEXT(gpd),
			(u32)TGPD_GET_DataBUF_LEN(gpd), (uintptr_t)TGPD_GET_DATA(gpd),
			(u32)TGPD_GET_BUF_LEN(gpd), (u32)TGPD_GET_EPaddr(gpd));

		return;
	}

	if(!gpd || !gpd_current) {
		qmu_printk(K_ERR, "[RXD][ERROR]""%s EP%d, gpd=%p, gpd_current=%p, ishwo=%d, \
			rx_gpd_last=%p, RQCPR=0x%x\n", __func__,
			ep_num, gpd, gpd_current, ((gpd==NULL) ? 999 : TGPD_IS_FLAGS_HWO(gpd)),
			Rx_gpd_last[ep_num], os_readl(USB_QMU_RQCPR(ep_num)));
		return;
	}
Example #3
0
/*
    1. Find the last gpd HW has executed and update Tx_gpd_last[]
    2. Set the flag for txstate to know that TX has been completed

    ported from proc_qmu_tx() from test driver.

    caller:qmu_interrupt after getting QMU done interrupt and TX is raised

*/
void qmu_done_tx(struct musb *musb, u8 ep_num, unsigned long flags)
{
	TGPD *gpd = Tx_gpd_last[ep_num];
	TGPD *gpd_current = (TGPD *) (os_readl(USB_QMU_TQCPR(ep_num)));
	struct musb_ep *musb_ep = &musb->endpoints[ep_num].ep_in;
	struct usb_request *request = NULL;
	struct musb_request *req;

	/* trying to give_back the request to gadget driver. */
	req = next_request(musb_ep);
	if (!req) {
		qmu_printk(K_INFO, "[TXD]" "%s Cannot get next request of %d, "
			   "but QMU has done.\n", __func__, ep_num);
		return;
	} else {
		request = &req->request;
	}

	/*Transfer PHY addr got from QMU register to VIR addr */
	gpd_current = phys_to_virt((unsigned long)gpd_current);

	/*
	   gpd or Last       gdp_current
	   |                  |
	   |->  GPD1 --> GPD2 --> GPD3 --> GPD4 --> GPD5 -|
	   |----------------------------------------------|
	 */

	qmu_printk(K_DEBUG, "[TXD]" "%s EP%d, Last=%p, Current=%p, End=%p\n",
		   __func__, ep_num, gpd, gpd_current, Tx_gpd_end[ep_num]);

	/*gpd_current should at least point to the next GPD to the previous last one. */
	if (gpd == gpd_current) {
		qmu_printk(K_ERR, "[TXD][ERROR]" "%s gpd(%p) == gpd_current(%p)\n", __func__, gpd,
			   gpd_current);
		return;
	}

	spin_unlock_irqrestore(&musb->lock, flags);

	/* flush data from device to CPU */
	dma_sync_single_for_cpu(musb->controller, virt_to_phys(gpd), sizeof(TGPD), DMA_FROM_DEVICE);

	spin_lock_irqsave(&musb->lock, flags);

	if (TGPD_IS_FLAGS_HWO(gpd)) {
		qmu_printk(K_DEBUG, "[TXD]" "%s HWO=1, CPR=%x\n", __func__,
			   os_readl(USB_QMU_TQCPR(ep_num)));
		BUG_ON(1);
	}

	while (gpd != gpd_current && !TGPD_IS_FLAGS_HWO(gpd)) {

		qmu_printk(K_DEBUG, "[TXD]" "gpd=%p ->HWO=%d, BPD=%d, Next_GPD=%x, DataBuffer=%x, "
			   "BufferLen=%d request=%p\n", gpd, (u32) TGPD_GET_FLAG(gpd),
			   (u32) TGPD_GET_FORMAT(gpd), (u32) TGPD_GET_NEXT(gpd),
			   (u32) TGPD_GET_DATA(gpd), (u32) TGPD_GET_BUF_LEN(gpd), req);

		if (!TGPD_GET_NEXT(gpd)) {
			qmu_printk(K_ERR, "[TXD][ERROR]" "Next GPD is null!!\n");
			/* BUG_ON(1); */
			break;
		}

		gpd = TGPD_GET_NEXT(gpd);

		spin_unlock_irqrestore(&musb->lock, flags);

		/*flush data from device to CPU */
		dma_sync_single_for_cpu(musb->controller,
					(dma_addr_t) gpd, sizeof(TGPD), DMA_FROM_DEVICE);

		spin_lock_irqsave(&musb->lock, flags);

		gpd = phys_to_virt((unsigned long)gpd);

		Tx_gpd_last[ep_num] = gpd;
		musb_g_giveback(musb_ep, request, 0);
		req = next_request(musb_ep);
		request = &req->request;
	}

	if (gpd != gpd_current && TGPD_IS_FLAGS_HWO(gpd)) {
		qmu_printk(K_ERR, "[TXD][ERROR]" "EP%d TQCSR=%x, TQSAR=%x, TQCPR=%x\n",
			   ep_num, os_readl(USB_QMU_TQCSR(ep_num)), os_readl(USB_QMU_TQSAR(ep_num)),
			   os_readl(USB_QMU_TQCPR(ep_num)));

		qmu_printk(K_ERR, "[TXD][ERROR]" "QCR0=%x, QCR1=%x, QCR2=%x, QCR3=%x, "
			   "QGCSR=%x\n", os_readl(U3D_QCR0), os_readl(U3D_QCR1), os_readl(U3D_QCR2),
			   os_readl(U3D_QCR3), os_readl(U3D_QGCSR));

		qmu_printk(K_ERR, "[TXD][ERROR]" "HWO=%d, BPD=%d, Next_GPD=%x, DataBuffer=%x, "
			   "BufferLen=%d, Endpoint=%d\n", (DEV_UINT32) TGPD_GET_FLAG(gpd),
			   (DEV_UINT32) TGPD_GET_FORMAT(gpd), (DEV_UINT32) TGPD_GET_NEXT(gpd),
			   (DEV_UINT32) TGPD_GET_DATA(gpd), (DEV_UINT32) TGPD_GET_BUF_LEN(gpd),
			   (DEV_UINT32) TGPD_GET_EPaddr(gpd));
	}

	qmu_printk(K_DEBUG, "[TXD]" "%s EP%d, Last=%p, End=%p, complete\n", __func__,
		   ep_num, Tx_gpd_last[ep_num], Tx_gpd_end[ep_num]);

	if (req != NULL) {
		if (request->length == 0) {
			qmu_printk(K_DEBUG, "[TXD]" "==Send ZLP== %p\n", req);

			while (!(USB_ReadCsr32(U3D_TX1CSR0, req->epnum) & TX_FIFOFULL)) {
				USB_WriteCsr32(U3D_TX1CSR0, req->epnum,
					       USB_ReadCsr32(U3D_TX1CSR0,
							     req->epnum) | TX_TXPKTRDY);
				break;
			}

			qmu_printk(K_DEBUG,
				   "[TXD]" "Giveback ZLP of EP%d, actual:%d, length:%d %p\n",
				   req->epnum, request->actual, request->length, request);

			musb_g_giveback(musb_ep, request, 0);
		}
	}
}
/*
    1. Find the last gpd HW has executed and update Tx_gpd_last[]
    2. Set the flag for txstate to know that TX has been completed

    ported from proc_qmu_tx() from test driver.

    caller:qmu_interrupt after getting QMU done interrupt and TX is raised

*/
void qmu_done_tx(struct musb *musb, u8 ep_num, unsigned long flags)
{
	TGPD* gpd = Tx_gpd_last[ep_num];
	TGPD* gpd_current = (TGPD*)(uintptr_t)(os_readl(USB_QMU_TQCPR(ep_num))); //QMU GPD address --> CPU DMA address
	struct musb_ep		*musb_ep = &musb->endpoints[ep_num].ep_in;
	struct usb_request	*request = NULL;
	struct musb_request	*req = NULL;

	/*Transfer PHY addr got from QMU register to VIR addr*/
	gpd_current = gpd_phys_to_virt((void *)gpd_current, USB_TX, ep_num);

	/*
                      gpd or Last       gdp_current
                           |                  |
            |->  GPD1 --> GPD2 --> GPD3 --> GPD4 --> GPD5 -|
            |----------------------------------------------|
	*/

	qmu_printk(K_DEBUG, "[TXD]""%s EP%d, Last=%p, Current=%p, End=%p\n",
		__func__, ep_num, gpd, gpd_current, Tx_gpd_end[ep_num]);

	/*gpd_current should at least point to the next GPD to the previous last one.*/
	if (gpd == gpd_current) {
		qmu_printk(K_ERR, "[TXD]""%s gpd(%p) == gpd_current(%p)\n", __func__, gpd, \
			gpd_current);
		return;
	}

	if(TGPD_IS_FLAGS_HWO(gpd)) {
		qmu_printk(K_DEBUG, "[TXD]""%s HWO=1, CPR=%x\n", __func__, os_readl(USB_QMU_TQCPR(ep_num)));
		BUG_ON(1);
	}

	while (gpd!=gpd_current && !TGPD_IS_FLAGS_HWO(gpd)) {

		qmu_printk(K_DEBUG, "[TXD]""gpd=%p ->HWO=%d, BPD=%d, Next_GPD=%lx, DataBuffer=%lx, "
			"BufferLen=%d request=%p\n", gpd, (u32)TGPD_GET_FLAG(gpd), (u32)TGPD_GET_FORMAT(gpd), \
			(uintptr_t)TGPD_GET_NEXT(gpd), (uintptr_t)TGPD_GET_DATA(gpd), (u32)TGPD_GET_BUF_LEN(gpd), req);

		if(!TGPD_GET_NEXT(gpd)) {
			qmu_printk(K_ERR, "[TXD][ERROR]""Next GPD is null!!\n");
			//BUG_ON(1);
			break;
		}

		gpd = TGPD_GET_NEXT(gpd);

		gpd = gpd_phys_to_virt(gpd, USB_TX, ep_num);

		/* trying to give_back the request to gadget driver. */
		req = next_request(musb_ep);
		if (!req) {
			qmu_printk(K_INFO, "[TXD]""%s Cannot get next request of %d, "
				"but QMU has done.\n", __func__, ep_num);
			return;
		} else {
			request = &req->request;
		}

		Tx_gpd_last[ep_num] = gpd;
		musb_g_giveback(musb_ep, request, 0);
		req = next_request(musb_ep);
		if (req != NULL) {
			request = &req->request;
		}
	}

	if(gpd!=gpd_current && TGPD_IS_FLAGS_HWO(gpd)) {
		qmu_printk(K_ERR, "[TXD][ERROR]""EP%d TQCSR=%x, TQSAR=%x, TQCPR=%x\n",
			ep_num, os_readl(USB_QMU_TQCSR(ep_num)), os_readl(USB_QMU_TQSAR(ep_num)),
				os_readl(USB_QMU_TQCPR(ep_num)));

		qmu_printk(K_ERR, "[TXD][ERROR]""QCR0=%x, QCR1=%x, QCR2=%x, QCR3=%x, "
			"QGCSR=%x\n", os_readl(U3D_QCR0), os_readl(U3D_QCR1), os_readl(U3D_QCR2), \
			os_readl(U3D_QCR3), os_readl(U3D_QGCSR));

		qmu_printk(K_ERR, "[TXD][ERROR]""HWO=%d, BPD=%d, Next_GPD=%lx, DataBuffer=%lx, "
			"BufferLen=%d, Endpoint=%d\n", (u32)TGPD_GET_FLAG(gpd), \
			(u32)TGPD_GET_FORMAT(gpd), (uintptr_t)TGPD_GET_NEXT(gpd), \
			(uintptr_t)TGPD_GET_DATA(gpd), (u32)TGPD_GET_BUF_LEN(gpd), \
			(u32)TGPD_GET_EPaddr(gpd));
	}

	qmu_printk(K_DEBUG, "[TXD]""%s EP%d, Last=%p, End=%p, complete\n", __func__,
		ep_num, Tx_gpd_last[ep_num], Tx_gpd_end[ep_num]);

	if (req != NULL) {
		if (request->length == 0) {
			u32 val = 0;

			qmu_printk(K_DEBUG, "[TXD]""==Send ZLP== %p\n", req);

			if (wait_for_value_us(USB_END_OFFSET(req->epnum, U3D_TX1CSR0), TX_FIFOEMPTY, TX_FIFOEMPTY, 1, 10) == RET_SUCCESS)
				qmu_printk(K_DEBUG, "Tx[%d] 0x%x\n", req->epnum, USB_ReadCsr32(U3D_TX1CSR0, req->epnum));
			else {
				qmu_printk(K_CRIT, "Tx[%d] NOT FIFOEMPTY 0x%x\n", req->epnum, USB_ReadCsr32(U3D_TX1CSR0, req->epnum));
				return;
			}

			/*Disable Tx_DMAREQEN*/
			val = USB_ReadCsr32(U3D_TX1CSR0, req->epnum) & ~TX_DMAREQEN;

			mb();

			USB_WriteCsr32(U3D_TX1CSR0, req->epnum, val);

			val = USB_ReadCsr32(U3D_TX1CSR0, req->epnum) | TX_TXPKTRDY;

			mb();

			USB_WriteCsr32(U3D_TX1CSR0, req->epnum, val);

			qmu_printk(K_DEBUG, "[TXD]""Giveback ZLP of EP%d, actual:%d, length:%d %p\n",
				req->epnum, request->actual, request->length, request);

			musb_g_giveback(musb_ep, request, 0);
		}
	}
}