/* * Context: caller holds controller lock */ static void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req) { musb_g_giveback(&musb->endpoints[0].ep_in, req, 0); musb->ep0_state = MUSB_EP0_STAGE_SETUP; }
/* 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); } } }
/* * Context: caller holds controller lock */ static void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req) { musb_g_giveback(&musb->endpoints[0].ep_in, req, 0); }
/* * Context: caller holds controller lock */ static void musb_g_ep0_giveback(struct musb *pThis, struct usb_request *req) { pThis->ep0_state = MGC_END0_STAGE_SETUP; musb_g_giveback(&pThis->aLocalEnd[0].ep_in, req, 0); }