ssusb_qmu.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. #ifdef USE_SSUSB_QMU
  2. #include <linux/spinlock.h>
  3. #include <linux/dma-mapping.h>
  4. #include "musb_core.h"
  5. #include "mu3d_hal_osal.h"
  6. #include "mu3d_hal_qmu_drv.h"
  7. #include "mu3d_hal_hw.h"
  8. #include "ssusb_qmu.h"
  9. /* Sanity CR check in */
  10. /*
  11. 1. Find the last gpd HW has executed and update Tx_gpd_last[]
  12. 2. Set the flag for txstate to know that TX has been completed
  13. ported from proc_qmu_tx() from test driver.
  14. caller:qmu_interrupt after getting QMU done interrupt and TX is raised
  15. */
  16. void qmu_done_tx(struct musb *musb, u8 ep_num, unsigned long flags)
  17. {
  18. TGPD *gpd = Tx_gpd_last[ep_num];
  19. /* QMU GPD address --> CPU DMA address */
  20. TGPD *gpd_current = (TGPD *) (uintptr_t) (os_readl(USB_QMU_TQCPR(ep_num)));
  21. struct musb_ep *musb_ep = &musb->endpoints[ep_num].ep_in;
  22. struct usb_request *request = NULL;
  23. struct musb_request *req = NULL;
  24. /*Transfer PHY addr got from QMU register to VIR addr */
  25. gpd_current = gpd_phys_to_virt((void *)gpd_current, USB_TX, ep_num);
  26. /*
  27. gpd or Last gdp_current
  28. | |
  29. |-> GPD1 --> GPD2 --> GPD3 --> GPD4 --> GPD5 -|
  30. |----------------------------------------------|
  31. */
  32. qmu_printk(K_DEBUG, "[TXD]" "%s EP%d, Last=%p, Current=%p, End=%p\n",
  33. __func__, ep_num, gpd, gpd_current, Tx_gpd_end[ep_num]);
  34. /*gpd_current should at least point to the next GPD to the previous last one. */
  35. if (gpd == gpd_current) {
  36. qmu_printk(K_ERR, "[TXD]" "%s gpd(%p) == gpd_current(%p)\n", __func__, gpd,
  37. gpd_current);
  38. return;
  39. }
  40. if (TGPD_IS_FLAGS_HWO(gpd)) {
  41. qmu_printk(K_DEBUG, "[TXD]" "%s HWO=1, CPR=%x\n", __func__,
  42. os_readl(USB_QMU_TQCPR(ep_num)));
  43. BUG_ON(1);
  44. }
  45. while (gpd != gpd_current && !TGPD_IS_FLAGS_HWO(gpd)) {
  46. qmu_printk(K_DEBUG,
  47. "[TXD]" "gpd=%p ->HWO=%d, BPD=%d, Next_GPD=%lx, DataBuffer=%lx,BufferLen=%d request=%p\n",
  48. gpd, (u32) TGPD_GET_FLAG(gpd),
  49. (u32) TGPD_GET_FORMAT(gpd), (uintptr_t) TGPD_GET_NEXT(gpd),
  50. (uintptr_t) TGPD_GET_DATA(gpd), (u32) TGPD_GET_BUF_LEN(gpd), req);
  51. if (!TGPD_GET_NEXT(gpd)) {
  52. qmu_printk(K_ERR, "[TXD][ERROR]" "Next GPD is null!!\n");
  53. /* BUG_ON(1); */
  54. break;
  55. }
  56. gpd = TGPD_GET_NEXT(gpd);
  57. gpd = gpd_phys_to_virt(gpd, USB_TX, ep_num);
  58. /* trying to give_back the request to gadget driver. */
  59. req = next_request(musb_ep);
  60. if (!req) {
  61. qmu_printk(K_INFO, "[TXD]" "%s Cannot get next request of %d, but QMU has done.\n",
  62. __func__, ep_num);
  63. return;
  64. }
  65. request = &req->request;
  66. Tx_gpd_last[ep_num] = gpd;
  67. musb_g_giveback(musb_ep, request, 0);
  68. req = next_request(musb_ep);
  69. if (req != NULL)
  70. request = &req->request;
  71. }
  72. if (gpd != gpd_current && TGPD_IS_FLAGS_HWO(gpd)) {
  73. qmu_printk(K_ERR, "[TXD][ERROR]" "EP%d TQCSR=%x, TQSAR=%x, TQCPR=%x\n",
  74. ep_num, os_readl(USB_QMU_TQCSR(ep_num)), os_readl(USB_QMU_TQSAR(ep_num)),
  75. os_readl(USB_QMU_TQCPR(ep_num)));
  76. qmu_printk(K_ERR, "[TXD][ERROR]" "QCR0=%x, QCR1=%x, QCR2=%x, QCR3=%x, QGCSR=%x\n",
  77. os_readl(U3D_QCR0), os_readl(U3D_QCR1), os_readl(U3D_QCR2),
  78. os_readl(U3D_QCR3), os_readl(U3D_QGCSR));
  79. qmu_printk(K_ERR, "[TXD][ERROR]" "HWO=%d, BPD=%d, Next_GPD=%lx\n",
  80. (u32) TGPD_GET_FLAG(gpd),
  81. (u32) TGPD_GET_FORMAT(gpd), (uintptr_t) TGPD_GET_NEXT(gpd));
  82. qmu_printk(K_ERR, "[TXD][ERROR]" "DataBuffer=%lx, BufferLen=%d, Endpoint=%d\n",
  83. (uintptr_t) TGPD_GET_DATA(gpd), (u32) TGPD_GET_BUF_LEN(gpd),
  84. (u32) TGPD_GET_EPaddr(gpd));
  85. }
  86. qmu_printk(K_DEBUG, "[TXD]" "%s EP%d, Last=%p, End=%p, complete\n", __func__,
  87. ep_num, Tx_gpd_last[ep_num], Tx_gpd_end[ep_num]);
  88. if (req != NULL) {
  89. if (request->length == 0) {
  90. u32 val = 0;
  91. qmu_printk(K_DEBUG, "[TXD]" "==Send ZLP== %p\n", req);
  92. if (wait_for_value_us
  93. (USB_END_OFFSET(req->epnum, U3D_TX1CSR0), TX_FIFOEMPTY, TX_FIFOEMPTY, 1,
  94. 10) == RET_SUCCESS)
  95. qmu_printk(K_DEBUG, "Tx[%d] 0x%x\n", req->epnum,
  96. USB_ReadCsr32(U3D_TX1CSR0, req->epnum));
  97. else {
  98. qmu_printk(K_CRIT, "Tx[%d] NOT FIFOEMPTY 0x%x\n", req->epnum,
  99. USB_ReadCsr32(U3D_TX1CSR0, req->epnum));
  100. return;
  101. }
  102. /*Disable Tx_DMAREQEN */
  103. val = USB_ReadCsr32(U3D_TX1CSR0, req->epnum) & ~TX_DMAREQEN;
  104. mb();
  105. USB_WriteCsr32(U3D_TX1CSR0, req->epnum, val);
  106. val = USB_ReadCsr32(U3D_TX1CSR0, req->epnum) | TX_TXPKTRDY;
  107. mb();
  108. USB_WriteCsr32(U3D_TX1CSR0, req->epnum, val);
  109. qmu_printk(K_DEBUG,
  110. "[TXD]" "Giveback ZLP of EP%d, actual:%d, length:%d %p\n",
  111. req->epnum, request->actual, request->length, request);
  112. musb_g_giveback(musb_ep, request, 0);
  113. }
  114. }
  115. }
  116. /*
  117. When receiving RXQ done interrupt, qmu_interrupt calls this function.
  118. 1. Traverse GPD/BD data structures to count actual transferred length.
  119. 2. Set the done flag to notify rxstate_qmu() to report status to upper gadget driver.
  120. ported from proc_qmu_rx() from test driver.
  121. caller:qmu_interrupt after getting QMU done interrupt and TX is raised
  122. */
  123. void qmu_done_rx(struct musb *musb, u8 ep_num, unsigned long flags)
  124. {
  125. TGPD *gpd = Rx_gpd_last[ep_num];
  126. /* QMU GPD address --> CPU DMA address */
  127. TGPD *gpd_current = (TGPD *) (uintptr_t) (os_readl(USB_QMU_RQCPR(ep_num)));
  128. struct musb_ep *musb_ep = &musb->endpoints[ep_num].ep_out;
  129. struct usb_request *request = NULL;
  130. struct musb_request *req;
  131. /* trying to give_back the request to gadget driver. */
  132. req = next_request(musb_ep);
  133. if (!req) {
  134. qmu_printk(K_ERR, "[RXD]" "%s Cannot get next request of %d, but QMU has done.\n",
  135. __func__, ep_num);
  136. return;
  137. }
  138. request = &req->request;
  139. /*Transfer PHY addr got from QMU register to VIR addr */
  140. gpd_current = gpd_phys_to_virt(gpd_current, USB_RX, ep_num);
  141. qmu_printk(K_DEBUG, "[RXD]" "%s EP%d, Last=%p, Current=%p, End=%p\n",
  142. __func__, ep_num, gpd, gpd_current, Rx_gpd_end[ep_num]);
  143. /*gpd_current should at least point to the next GPD to the previous last one. */
  144. if (gpd == gpd_current) {
  145. qmu_printk(K_ERR, "[RXD][ERROR]" "%s gpd(%p) == gpd_current(%p)\n", __func__, gpd,
  146. gpd_current);
  147. qmu_printk(K_ERR, "[RXD][ERROR] EP%d RQCSR=%x, RQSAR=%x, RQCPR=%x, RQLDPR=%x\n",
  148. ep_num, os_readl(USB_QMU_RQCSR(ep_num)), os_readl(USB_QMU_RQSAR(ep_num)),
  149. os_readl(USB_QMU_RQCPR(ep_num)), os_readl(USB_QMU_RQLDPR(ep_num)));
  150. qmu_printk(K_ERR, "[RXD][ERROR] QCR0=%x, QCR1=%x, QCR2=%x, QCR3=%x, QGCSR=%x\n",
  151. os_readl(U3D_QCR0), os_readl(U3D_QCR1), os_readl(U3D_QCR2),
  152. os_readl(U3D_QCR3), os_readl(U3D_QGCSR));
  153. qmu_printk(K_INFO, "[RXD][ERROR] HWO=%d, Next_GPD=%lx ,DataBufLen=%d, DataBuf=%lx\n",
  154. (u32) TGPD_GET_FLAG(gpd), (uintptr_t) TGPD_GET_NEXT(gpd),
  155. (u32) TGPD_GET_DataBUF_LEN(gpd), (uintptr_t) TGPD_GET_DATA(gpd));
  156. qmu_printk(K_INFO, "[RXD][ERROR] RecvLen=%d, Endpoint=%d\n",
  157. (u32) TGPD_GET_BUF_LEN(gpd), (u32) TGPD_GET_EPaddr(gpd));
  158. return;
  159. }
  160. if (!gpd || !gpd_current) {
  161. qmu_printk(K_ERR,
  162. "[RXD][ERROR]" "%s EP%d, gpd=%p, gpd_current=%p, ishwo=%d, rx_gpd_last=%p, RQCPR=0x%x\n",
  163. __func__, ep_num, gpd, gpd_current,
  164. ((gpd == NULL) ? 999 : TGPD_IS_FLAGS_HWO(gpd)),
  165. Rx_gpd_last[ep_num],
  166. os_readl(USB_QMU_RQCPR(ep_num)));
  167. return;
  168. }
  169. if (TGPD_IS_FLAGS_HWO(gpd)) {
  170. qmu_printk(K_ERR, "[RXD][ERROR]" "HWO=1!!\n");
  171. BUG_ON(1);
  172. }
  173. while (gpd != gpd_current && !TGPD_IS_FLAGS_HWO(gpd)) {
  174. DEV_UINT32 rcv_len = (DEV_UINT32) TGPD_GET_BUF_LEN(gpd);
  175. DEV_UINT32 buf_len = (DEV_UINT32) TGPD_GET_DataBUF_LEN(gpd);
  176. if (rcv_len > buf_len)
  177. qmu_printk(K_ERR, "[RXD][ERROR]" "%s rcv(%d) > buf(%d) AUK!?\n", __func__,
  178. rcv_len, buf_len);
  179. qmu_printk(K_DEBUG,
  180. "[RXD]" "gpd=%p ->HWO=%d, Next_GPD=%p, RcvLen=%d, BufLen=%d, pBuf=%p\n",
  181. gpd, TGPD_GET_FLAG(gpd), TGPD_GET_NEXT(gpd), rcv_len, buf_len,
  182. TGPD_GET_DATA(gpd));
  183. request->actual += rcv_len;
  184. if (!TGPD_GET_NEXT(gpd) || !TGPD_GET_DATA(gpd)) {
  185. qmu_printk(K_ERR, "[RXD][ERROR]" "%s EP%d ,gpd=%p\n", __func__, ep_num,
  186. gpd);
  187. BUG_ON(1);
  188. }
  189. gpd = TGPD_GET_NEXT(gpd);
  190. gpd = gpd_phys_to_virt(gpd, USB_RX, ep_num);
  191. if (!gpd) {
  192. qmu_printk(K_ERR, "[RXD][ERROR]" "%s EP%d ,gpd=%p\n", __func__, ep_num,
  193. gpd);
  194. BUG_ON(1);
  195. }
  196. Rx_gpd_last[ep_num] = gpd;
  197. musb_g_giveback(musb_ep, request, 0);
  198. req = next_request(musb_ep);
  199. request = &req->request;
  200. }
  201. if (gpd != gpd_current && TGPD_IS_FLAGS_HWO(gpd)) {
  202. qmu_printk(K_ERR, "[RXD][ERROR]" "gpd=%p\n", gpd);
  203. qmu_printk(K_ERR, "[RXD][ERROR]" "EP%d RQCSR=%x, RQSAR=%x, RQCPR=%x, RQLDPR=%x\n",
  204. ep_num, os_readl(USB_QMU_RQCSR(ep_num)), os_readl(USB_QMU_RQSAR(ep_num)),
  205. os_readl(USB_QMU_RQCPR(ep_num)), os_readl(USB_QMU_RQLDPR(ep_num)));
  206. qmu_printk(K_ERR, "[RXD][ERROR]" "QCR0=%x, QCR1=%x, QCR2=%x, QCR3=%x, QGCSR=%x\n",
  207. os_readl(U3D_QCR0), os_readl(U3D_QCR1), os_readl(U3D_QCR2),
  208. os_readl(U3D_QCR3), os_readl(U3D_QGCSR));
  209. qmu_printk(K_INFO, "[RXD][ERROR] HWO=%d, Next_GPD=%lx ,DataBufLen=%d, DataBuf=%lx\n",
  210. (u32) TGPD_GET_FLAG(gpd), (uintptr_t) TGPD_GET_NEXT(gpd),
  211. (u32) TGPD_GET_DataBUF_LEN(gpd), (uintptr_t) TGPD_GET_DATA(gpd));
  212. qmu_printk(K_INFO, "[RXD][ERROR] RecvLen=%d, Endpoint=%d\n",
  213. (u32) TGPD_GET_BUF_LEN(gpd), (u32) TGPD_GET_EPaddr(gpd));
  214. }
  215. qmu_printk(K_DEBUG, "[RXD]" "%s EP%d, Last=%p, End=%p, complete\n", __func__,
  216. ep_num, Rx_gpd_last[ep_num], Rx_gpd_end[ep_num]);
  217. }
  218. void qmu_done_tasklet(unsigned long data)
  219. {
  220. unsigned int qmu_val;
  221. unsigned int i;
  222. unsigned long flags;
  223. struct musb *musb = (struct musb *)data;
  224. spin_lock_irqsave(&musb->lock, flags);
  225. qmu_val = musb->qmu_done_intr;
  226. musb->qmu_done_intr = 0;
  227. for (i = 1; i <= MAX_QMU_EP; i++) {
  228. if (qmu_val & QMU_RX_DONE(i))
  229. qmu_done_rx(musb, i, flags);
  230. if (qmu_val & QMU_TX_DONE(i))
  231. qmu_done_tx(musb, i, flags);
  232. }
  233. spin_unlock_irqrestore(&musb->lock, flags);
  234. }
  235. void qmu_error_recovery(unsigned long data)
  236. {
  237. #ifdef USE_SSUSB_QMU
  238. u8 ep_num;
  239. USB_DIR dir;
  240. unsigned long flags;
  241. struct musb *musb = (struct musb *)data;
  242. struct musb_ep *musb_ep;
  243. struct musb_request *request;
  244. bool is_len_err = false;
  245. int i = 0;
  246. spin_lock_irqsave(&musb->lock, flags);
  247. ep_num = 0;
  248. if ((musb->error_wQmuVal & RXQ_CSERR_INT) || (musb->error_wQmuVal & RXQ_LENERR_INT)) {
  249. dir = USB_RX;
  250. for (i = 1; i <= MAX_QMU_EP; i++) {
  251. if (musb->error_wErrVal & QMU_RX_CS_ERR(i)) {
  252. qmu_printk(K_ERR, "mu3d_hal_resume_qmu Rx %d checksum error!\r\n",
  253. i);
  254. ep_num = i;
  255. break;
  256. }
  257. if (musb->error_wErrVal & QMU_RX_LEN_ERR(i)) {
  258. qmu_printk(K_ERR, "mu3d_hal_resume_qmu RX EP%d Recv Length error\n",
  259. i);
  260. ep_num = i;
  261. is_len_err = true;
  262. break;
  263. }
  264. }
  265. } else if ((musb->error_wQmuVal & TXQ_CSERR_INT) || (musb->error_wQmuVal & TXQ_LENERR_INT)) {
  266. dir = USB_TX;
  267. for (i = 1; i <= MAX_QMU_EP; i++) {
  268. if (musb->error_wErrVal & QMU_TX_CS_ERR(i)) {
  269. qmu_printk(K_ERR, "mu3d_hal_resume_qmu Tx %d checksum error!\r\n",
  270. i);
  271. ep_num = i;
  272. break;
  273. }
  274. if (musb->error_wErrVal & QMU_TX_LEN_ERR(i)) {
  275. qmu_printk(K_ERR, "mu3d_hal_resume_qmu TX EP%d Recv Length error\n",
  276. i);
  277. ep_num = i;
  278. is_len_err = true;
  279. break;
  280. }
  281. }
  282. }
  283. if (ep_num == 0) {
  284. qmu_printk(K_ERR, "Error but ep_num == 0!\r\n");
  285. goto done;
  286. }
  287. _ex_mu3d_hal_flush_qmu(ep_num, dir);
  288. /* mu3d_hal_restart_qmu(ep_num, dir); */
  289. if (dir == USB_TX)
  290. musb_ep = &musb->endpoints[ep_num].ep_in;
  291. else
  292. musb_ep = &musb->endpoints[ep_num].ep_out;
  293. list_for_each_entry(request, &musb_ep->req_list, list) {
  294. qmu_printk(K_ERR, "%s : request 0x%p length(0x%d)\n", __func__, request,
  295. request->request.length);
  296. if (request->request.dma != DMA_ADDR_INVALID) {
  297. if (request->tx) {
  298. qmu_printk(K_ERR, "[TX]" "%s gpd=%p, epnum=%d, len=%d\n", __func__,
  299. Tx_gpd_end[ep_num], ep_num, request->request.length);
  300. request->request.actual = request->request.length;
  301. if (request->request.length > 0) {
  302. u32 txcsr;
  303. if (is_len_err == true) {
  304. _ex_mu3d_hal_insert_transfer_gpd(request->epnum,
  305. USB_TX,
  306. request->
  307. request.dma, 4096,
  308. true, true, false,
  309. ((musb_ep->type ==
  310. USB_ENDPOINT_XFER_ISOC)
  311. ? 0 : 1),
  312. musb_ep->
  313. end_point.maxpacket);
  314. } else {
  315. _ex_mu3d_hal_insert_transfer_gpd(request->epnum,
  316. USB_TX,
  317. request->
  318. request.dma,
  319. request->
  320. request.length,
  321. true, true, false,
  322. ((musb_ep->type ==
  323. USB_ENDPOINT_XFER_ISOC)
  324. ? 0 : 1),
  325. musb_ep->
  326. end_point.maxpacket);
  327. }
  328. /*Enable Tx_DMAREQEN */
  329. txcsr =
  330. USB_ReadCsr32(U3D_TX1CSR0,
  331. request->epnum) | TX_DMAREQEN;
  332. mb();
  333. USB_WriteCsr32(U3D_TX1CSR0, request->epnum, txcsr);
  334. } else if (request->request.length == 0) {
  335. qmu_printk(K_DEBUG, "[TX]" "Send ZLP\n");
  336. }
  337. } else {
  338. qmu_printk(K_ERR, "[RX]" "%s, gpd=%p, epnum=%d, len=%d\n",
  339. __func__, Rx_gpd_end[ep_num], ep_num,
  340. request->request.length);
  341. if (is_len_err == true) {
  342. _ex_mu3d_hal_insert_transfer_gpd(request->epnum, USB_RX,
  343. request->request.dma, 4096,
  344. true, true, false,
  345. (musb_ep->type ==
  346. USB_ENDPOINT_XFER_ISOC ? 0
  347. : 1),
  348. musb_ep->
  349. end_point.maxpacket);
  350. } else {
  351. _ex_mu3d_hal_insert_transfer_gpd(request->epnum, USB_RX,
  352. request->request.dma,
  353. request->request.length,
  354. true, true, false,
  355. (musb_ep->type ==
  356. USB_ENDPOINT_XFER_ISOC ? 0
  357. : 1),
  358. musb_ep->
  359. end_point.maxpacket);
  360. }
  361. }
  362. }
  363. }
  364. mu3d_hal_resume_qmu(ep_num, dir);
  365. done:
  366. spin_unlock_irqrestore(&musb->lock, flags);
  367. #endif
  368. }
  369. void qmu_exception_interrupt(struct musb *musb, DEV_UINT32 wQmuVal)
  370. {
  371. u32 wErrVal;
  372. int i = (int)wQmuVal;
  373. if (wQmuVal & RXQ_CSERR_INT)
  374. qmu_printk(K_ERR, "==Rx %d checksum error==\n", i);
  375. if (wQmuVal & RXQ_LENERR_INT)
  376. qmu_printk(K_ERR, "==Rx %d length error==\n", i);
  377. if (wQmuVal & TXQ_CSERR_INT)
  378. qmu_printk(K_ERR, "==Tx %d checksum error==\n", i);
  379. if (wQmuVal & TXQ_LENERR_INT)
  380. qmu_printk(K_ERR, "==Tx %d length error==\n", i);
  381. if ((wQmuVal & RXQ_CSERR_INT) || (wQmuVal & RXQ_LENERR_INT)) {
  382. wErrVal = os_readl(U3D_RQERRIR0);
  383. qmu_printk(K_DEBUG, "Rx Queue error in QMU mode![0x%x]\r\n", (unsigned int)wErrVal);
  384. for (i = 1; i <= MAX_QMU_EP; i++) {
  385. if (wErrVal & QMU_RX_CS_ERR(i))
  386. qmu_printk(K_ERR, "Rx %d checksum error!\r\n", i);
  387. if (wErrVal & QMU_RX_LEN_ERR(i))
  388. qmu_printk(K_ERR, "RX EP%d Recv Length error\n", i);
  389. }
  390. os_writel(U3D_RQERRIR0, wErrVal);
  391. musb->error_wQmuVal = wQmuVal;
  392. musb->error_wErrVal = wErrVal;
  393. tasklet_schedule(&musb->error_recovery);
  394. }
  395. if (wQmuVal & RXQ_ZLPERR_INT) {
  396. wErrVal = os_readl(U3D_RQERRIR1);
  397. qmu_printk(K_DEBUG, "Rx Queue error in QMU mode![0x%x]\r\n", (unsigned int)wErrVal);
  398. for (i = 1; i <= MAX_QMU_EP; i++) {
  399. if (wErrVal & QMU_RX_ZLP_ERR(i)) {
  400. /*FIXME: should _NOT_ got this error. But now just accept. */
  401. qmu_printk(K_DEBUG, "RX EP%d Recv ZLP\n", i);
  402. }
  403. }
  404. os_writel(U3D_RQERRIR1, wErrVal);
  405. }
  406. if ((wQmuVal & TXQ_CSERR_INT) || (wQmuVal & TXQ_LENERR_INT)) {
  407. wErrVal = os_readl(U3D_TQERRIR0);
  408. qmu_printk(K_DEBUG, "Tx Queue error in QMU mode![0x%x]\r\n", (unsigned int)wErrVal);
  409. for (i = 1; i <= MAX_QMU_EP; i++) {
  410. if (wErrVal & QMU_TX_CS_ERR(i))
  411. qmu_printk(K_ERR, "Tx %d checksum error!\r\n", i);
  412. if (wErrVal & QMU_TX_LEN_ERR(i))
  413. qmu_printk(K_ERR, "Tx %d buffer length error!\r\n", i);
  414. }
  415. os_writel(U3D_TQERRIR0, wErrVal);
  416. musb->error_wQmuVal = wQmuVal;
  417. musb->error_wErrVal = wErrVal;
  418. tasklet_schedule(&musb->error_recovery);
  419. }
  420. if ((wQmuVal & RXQ_EMPTY_INT) || (wQmuVal & TXQ_EMPTY_INT)) {
  421. DEV_UINT32 wEmptyVal = os_readl(U3D_QEMIR);
  422. qmu_printk(K_DEBUG, "%s Empty in QMU mode![0x%x]\r\n",
  423. (wQmuVal & TXQ_EMPTY_INT) ? "TX" : "RX", wEmptyVal);
  424. os_writel(U3D_QEMIR, wEmptyVal);
  425. }
  426. }
  427. #endif