/* * The TX lock protects user tasks from the ISR. If TX DMA interrupt occurs * while the user task is processing the TX DMA descriptors the ISR will * ignore interrupt the request by not processing the DMA table since that * is done by the user task anyway. In SMP, when a user task enters the TX DMA * processing while the ISR (on another CPU) is also processing the user task * will loop waiting for the ISR to complete. */ static int grtm_request_txlock(struct grtm_priv *pDev, int block) { SPIN_IRQFLAGS(irqflags); int got_lock = 0; do { SPIN_LOCK_IRQ(&pDev->devlock, irqflags); if (pDev->handling_transmission == 0) { pDev->handling_transmission = 1; got_lock = 1; } SPIN_UNLOCK_IRQ(&pDev->devlock, irqflags); } while (!got_lock && block); return got_lock; }
u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) { _irqL irqL; unsigned int pipe; int status; u32 ret = _FAIL, bwritezero = _FALSE; PURB purb = NULL; _adapter *padapter = (_adapter *)pintfhdl->padapter; struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobj); struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem; struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; struct usb_device *pusbd = pdvobj->pusbdev; struct pkt_attrib *pattrib = &pxmitframe->attrib; RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("+usb_write_port\n")); if (RTW_CANNOT_TX(padapter)) { #ifdef DBG_TX DBG_871X(" DBG_TX %s:%d bDriverStopped%d, bSurpriseRemoved:%d\n",__FUNCTION__, __LINE__ ,padapter->bDriverStopped, padapter->bSurpriseRemoved); #endif RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved )!!!\n")); rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY); goto exit; } SPIN_LOCK_IRQ(pxmitpriv->lock, &irqL); switch(addr) { case VO_QUEUE_INX: pxmitpriv->voq_cnt++; pxmitbuf->flags = VO_QUEUE_INX; break; case VI_QUEUE_INX: pxmitpriv->viq_cnt++; pxmitbuf->flags = VI_QUEUE_INX; break; case BE_QUEUE_INX: pxmitpriv->beq_cnt++; pxmitbuf->flags = BE_QUEUE_INX; break; case BK_QUEUE_INX: pxmitpriv->bkq_cnt++; pxmitbuf->flags = BK_QUEUE_INX; break; case HIGH_QUEUE_INX: pxmitbuf->flags = HIGH_QUEUE_INX; break; default: pxmitbuf->flags = MGT_QUEUE_INX; break; } SPIN_UNLOCK_IRQ(pxmitpriv->lock, &irqL); purb = pxmitbuf->pxmit_urb[0]; //translate DMA FIFO addr to pipehandle pipe = ffaddr2pipehdl(pdvobj, addr); #ifdef CONFIG_REDUCE_USB_TX_INT if ( (pxmitpriv->free_xmitbuf_cnt%NR_XMITBUFF == 0) || (pxmitbuf->buf_tag > XMITBUF_DATA) ) { purb->transfer_flags &= (~URB_NO_INTERRUPT); } else { purb->transfer_flags |= URB_NO_INTERRUPT; //DBG_8192C("URB_NO_INTERRUPT "); } #endif usb_fill_bulk_urb(purb, pusbd, pipe, pxmitframe->buf_addr, //= pxmitbuf->pbuf cnt, usb_write_port_complete, pxmitbuf);//context is pxmitbuf #ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX purb->transfer_dma = pxmitbuf->dma_transfer_addr; purb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; purb->transfer_flags |= URB_ZERO_PACKET; #endif // CONFIG_USE_USB_BUFFER_ALLOC_TX #ifdef USB_PACKET_OFFSET_SZ #if (USB_PACKET_OFFSET_SZ == 0) purb->transfer_flags |= URB_ZERO_PACKET; #endif #endif status = usb_submit_urb(purb, GFP_ATOMIC); if (!status) { #ifdef DBG_CONFIG_ERROR_DETECT { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); pHalData->srestpriv.last_tx_time = rtw_get_current_time(); } #endif } else { rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR); DBG_871X("usb_write_port, status=%d\n", status); RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port(): usb_submit_urb, status=%x\n", status)); switch (status) { case -ENODEV: padapter->bDriverStopped=_TRUE; break; default: break; } goto exit; } ret= _SUCCESS; RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("-usb_write_port\n")); exit: if (ret != _SUCCESS) rtw_free_xmitbuf(pxmitpriv, pxmitbuf); return ret; }
static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs) { _irqL irqL; int i; struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; _adapter *padapter = pxmitbuf->padapter; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; switch(pxmitbuf->flags) { case VO_QUEUE_INX: pxmitpriv->voq_cnt--; break; case VI_QUEUE_INX: pxmitpriv->viq_cnt--; break; case BE_QUEUE_INX: pxmitpriv->beq_cnt--; break; case BK_QUEUE_INX: pxmitpriv->bkq_cnt--; break; default: break; } if (RTW_CANNOT_TX(padapter)) { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); DBG_8192C("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) pxmitbuf->buf_tag(%x) \n", __FUNCTION__,padapter->bDriverStopped, padapter->bSurpriseRemoved,pxmitbuf->buf_tag); goto check_completion; } if (purb->status==0) { } else { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete : purb->status(%d) != 0 \n", purb->status)); DBG_871X("###=> urb_write_port_complete status(%d)\n",purb->status); if((purb->status==-EPIPE)||(purb->status==-EPROTO)) { sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL); } else if (purb->status == -EINPROGRESS) { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: EINPROGESS\n")); goto check_completion; } else if (purb->status == -ENOENT) { DBG_871X("%s: -ENOENT\n", __func__); goto check_completion; } else if (purb->status == -ECONNRESET) { DBG_871X("%s: -ECONNRESET\n", __func__); goto check_completion; } else if (purb->status == -ESHUTDOWN) { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: ESHUTDOWN\n")); padapter->bDriverStopped=_TRUE; RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bDriverStopped=TRUE\n")); goto check_completion; } else { padapter->bSurpriseRemoved=_TRUE; DBG_8192C("bSurpriseRemoved=TRUE\n"); RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bSurpriseRemoved=TRUE\n")); goto check_completion; } } #ifdef DBG_CONFIG_ERROR_DETECT { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); pHalData->srestpriv.last_tx_complete_time = rtw_get_current_time(); } #endif check_completion: SPIN_LOCK_IRQ(pxmitpriv->lock_sctx, &irqL); rtw_sctx_done_err(&pxmitbuf->sctx, purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS); SPIN_UNLOCK_IRQ(pxmitpriv->lock_sctx, &irqL); rtw_free_xmitbuf(pxmitpriv, pxmitbuf); tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); }