/** * \fn context_DriverTask * \brief The driver task * * This function is the driver's main task that always runs in the driver's * single context, scheduled through the OS (the driver's workqueue in Linux). * Only one instantiation of this task may run at a time! * * \note * \param hContext - The module handle * \return void * \sa context_RequestSchedule */ void context_DriverTask (TI_HANDLE hContext) { TContext *pContext = (TContext *)hContext; TContextCbFunc fCbFunc; TI_HANDLE hCbHndl; TI_UINT32 i; CL_TRACE_START_L1(); TRACE0(pContext->hReport, REPORT_SEVERITY_INFORMATION , "context_DriverTask():\n"); /* For all registered clients do: */ for (i = 0; i < pContext->uNumClients; i++) { /* If client is pending and enabled */ if (pContext->aClientPending[i] && pContext->aClientEnabled[i]) { #ifdef TI_DBG pContext->aInvokeCount[i]++; TRACE1(pContext->hReport, REPORT_SEVERITY_INFORMATION , "Invoking - Client=, ID=%d\n", i); #endif /* TI_DBG */ /* Clear client's pending flag */ pContext->aClientPending[i] = TI_FALSE; /* Call client's callback function */ fCbFunc = pContext->aClientCbFunc[i]; hCbHndl = pContext->aClientCbHndl[i]; fCbFunc(hCbHndl); } } CL_TRACE_END_L1("tiwlan_drv.ko", "CONTEXT", "TASK", ""); }
TI_BOOL os_receivePacket(TI_HANDLE OsContext, void *pRxDesc ,void *pPacket, TI_UINT16 Length) { TWlanDrvIfObj *drv = (TWlanDrvIfObj *)OsContext; unsigned char *pdata = (unsigned char *)((TI_UINT32)pPacket & ~(TI_UINT32)0x3); rx_head_t *rx_head = (rx_head_t *)(pdata - WSPI_PAD_BYTES - RX_HEAD_LEN_ALIGNED); struct sk_buff *skb = rx_head->skb; #ifdef TI_DBG if ((TI_UINT32)pPacket & 0x3) { if ((TI_UINT32)pPacket - (TI_UINT32)skb->data != 2) { printk("os_receivePacket() address error skb=0x%x skb->data=0x%x pPacket=0x%x !!!\n",(int)skb, (int)skb->data, (int)pPacket); } } else { if ((TI_UINT32)skb->data != (TI_UINT32)pPacket) { printk("os_receivePacket() address error skb=0x%x skb->data=0x%x pPacket=0x%x !!!\n",(int)skb, (int)skb->data, (int)pPacket); } } if (Length != RX_ETH_PKT_LEN(pPacket)) { printk("os_receivePacket() Length=%d != RX_ETH_PKT_LEN(pPacket)=%d!!!\n",(int)Length, RX_ETH_PKT_LEN(pPacket)); } #endif /* printk("-->> os_receivePacket() pPacket=0x%x Length=%d skb=0x%x skb->data=0x%x skb->head=0x%x skb->len=%d\n", (int)pPacket, (int)Length, (int)skb, (int)skb->data, (int)skb->head, (int)skb->len); */ /* Use skb_reserve, it updates both skb->data and skb->tail. */ skb->data = RX_ETH_PKT_DATA(pPacket); skb->tail = skb->data; skb_put(skb, RX_ETH_PKT_LEN(pPacket)); /* printk("-->> os_receivePacket() skb=0x%x skb->data=0x%x skb->head=0x%x skb->len=%d\n", (int)skb, (int)skb->data, (int)skb->head, (int)skb->len); */ ti_nodprintf(TIWLAN_LOG_INFO, "os_receivePacket - Received EAPOL len-%d\n", WBUF_LEN(pWbuf)); skb->dev = drv->netdev; skb->protocol = eth_type_trans(skb, drv->netdev); skb->ip_summed = CHECKSUM_NONE; drv->stats.rx_packets++; drv->stats.rx_bytes += skb->len; /* Send the skb to the TCP stack. * it responsibly of the Linux kernel to free the skb */ { CL_TRACE_START_L1(); os_wake_lock_timeout_enable(drv); netif_rx_ni(skb); /* Note: Don't change this trace (needed to exclude OS processing from Rx CPU utilization) */ CL_TRACE_END_L1("tiwlan_drv.ko", "OS", "RX", ""); } return TI_TRUE; }
/* * \brief FW interrupt handler, just switch to WLAN context for handling * * \param hFwEvent - FwEvent Driver handle * \return void * * \par Description * Called by the FW-Interrupt ISR (external context!). * Requests the context engine to schedule the driver task for handling the FW-Events. * * \sa */ void fwEvent_InterruptRequest (TI_HANDLE hFwEvent) { TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; CL_TRACE_START_L1(); TRACE0(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_InterruptRequest()\n"); /* Request switch to driver context for handling the FW-Interrupt event */ context_RequestSchedule (pFwEvent->hContext, pFwEvent->uContextId); CL_TRACE_END_L1("tiwlan_drv.ko", "IRQ", "FwEvent", ""); }
/** * \fn wlanDrvIf_Xmit * \brief Packets transmission * * The network stack calls this function in order to transmit a packet * through the WLAN interface. * The packet is inserted to the drver Tx queues and its handling is continued * after switching to the driver context. * * \note * \param skb - The Linux packet buffer structure * \param dev - The driver network-interface handle * \return 0 (= OK) * \sa */ static int wlanDrvIf_Xmit (struct sk_buff *skb, struct net_device *dev) { TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev); TTxCtrlBlk * pPktCtrlBlk; int status; CL_TRACE_START_L1(); os_profile (drv, 0, 0); drv->stats.tx_packets++; drv->stats.tx_bytes += skb->len; /* Allocate a TxCtrlBlk for the Tx packet and save timestamp, length and packet handle */ pPktCtrlBlk = TWD_txCtrlBlk_Alloc (drv->tCommon.hTWD); pPktCtrlBlk->tTxDescriptor.startTime = os_timeStampMs(drv); /* remove use of skb->tstamp.off_usec */ pPktCtrlBlk->tTxDescriptor.length = skb->len; pPktCtrlBlk->tTxPktParams.pInputPkt = skb; /* Point the first BDL buffer to the Ethernet header, and the second buffer to the rest of the packet */ pPktCtrlBlk->tTxnStruct.aBuf[0] = skb->data; pPktCtrlBlk->tTxnStruct.aLen[0] = ETHERNET_HDR_LEN; pPktCtrlBlk->tTxnStruct.aBuf[1] = skb->data + ETHERNET_HDR_LEN; pPktCtrlBlk->tTxnStruct.aLen[1] = (TI_UINT16)skb->len - ETHERNET_HDR_LEN; pPktCtrlBlk->tTxnStruct.aLen[2] = 0; /* Send the packet to the driver for transmission. */ status = txDataQ_InsertPacket (drv->tCommon.hTxDataQ, pPktCtrlBlk,(TI_UINT8)skb->priority); /* If failed (queue full or driver not running), drop the packet. */ if (status != TI_OK) { drv->stats.tx_errors++; } os_profile (drv, 1, 0); CL_TRACE_END_L1("tiwlan_drv.ko", "OS", "TX", ""); return 0; }
/** * \fn busDrv_TxnDoneCb * \brief Continue async transaction processing (CB) * * Called back by the lower (BSP) bus-driver upon Async transaction completion (TxnDone ISR). * Call busDrv_SendTxnParts to continue sending the remained transaction parts. * * \note * \param hBusDrv - The module's object * \param status - The last transaction result - 0 = OK, else Error * \return void * \sa busDrv_SendTxnParts */ static void busDrv_TxnDoneCb (TI_HANDLE hBusDrv, int iStatus) { TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv; CL_TRACE_START_L1(); /* If last transaction part failed, set error in Txn struct, call TxnDone CB and exit. */ if (iStatus != 0) { TRACE1(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "busDrv_TxnDoneCb: Status = 0x%x\n", iStatus); TXN_PARAM_SET_STATUS(pBusDrv->pCurrTxn, TXN_PARAM_STATUS_ERROR); pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pBusDrv->pCurrTxn); CL_TRACE_END_L1("tiwlan_drv.ko", "TXN_DONE", "BusDrvCB", ""); return; } TRACE0(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_TxnDoneCb()\n"); /* Continue sending the remained transaction parts. */ busDrv_SendTxnParts (pBusDrv); CL_TRACE_END_L1("tiwlan_drv.ko", "TXN_DONE", "BusDrvCB", ""); }
static int xmit_Bridge (struct sk_buff *skb, struct net_device *dev, TIntraBssBridge *pBssBridgeParam) { TWlanDrvIfObj *drv = (TWlanDrvIfObj *)NETDEV_GET_PRIVATE(dev); TTxCtrlBlk * pPktCtrlBlk; TEthernetHeader *pEthHead = (TEthernetHeader *)(skb->data); int status; CL_TRACE_START_L1(); os_profile (drv, 0, 0); drv->stats.tx_packets++; drv->stats.tx_bytes += skb->len; /* Allocate a TxCtrlBlk for the Tx packet and save timestamp, length and packet handle */ pPktCtrlBlk = TWD_txCtrlBlk_Alloc (drv->tCommon.hTWD); if (pPktCtrlBlk == NULL) { drv->stats.tx_errors++; os_profile (drv, 1, 0); CL_TRACE_END_L1("tiwlan_drv.ko", "OS", "TX", ""); return 0; } /* Set interface type according to net device interface number */ if (drv->tCommon.eIfRole == IF_ROLE_TYPE_AP) SET_PKT_TYPE_IF_ROLE_AP(pPktCtrlBlk); else SET_PKT_TYPE_IF_ROLE_STA(pPktCtrlBlk); pPktCtrlBlk->tTxDescriptor.startTime = os_timeStampMs(drv); /* remove use of skb->tstamp.off_usec */ pPktCtrlBlk->tTxDescriptor.length = skb->len; pPktCtrlBlk->tTxPktParams.pInputPkt = skb; /* Check MGMT packet from hostapd, forward it to the Mgmt-Queue and exit without ethernet header */ if (HTOWLANS(pEthHead->type) == AP_MGMT_ETH_TYPE) { /* Copy WLAN header into aPktHdr - format for MGMT packets */ memcpy (pPktCtrlBlk->aPktHdr, skb->data + ETHERNET_HDR_LEN , WLAN_HDR_LEN ); /* Skip ethernet header, send as management frame */ pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_MGMT; pPktCtrlBlk->tTxnStruct.aBuf[0] = (TI_UINT8 *)pPktCtrlBlk->aPktHdr; pPktCtrlBlk->tTxnStruct.aLen[0] = WLAN_HDR_LEN; pPktCtrlBlk->tTxnStruct.aBuf[1] = skb->data + ETHERNET_HDR_LEN + WLAN_HDR_LEN; pPktCtrlBlk->tTxnStruct.aLen[1] = (TI_UINT16)skb->len - ETHERNET_HDR_LEN - WLAN_HDR_LEN; pPktCtrlBlk->tTxnStruct.aLen[2] = 0; pPktCtrlBlk->tTxPktParams.uInputPktLen = skb->len; pPktCtrlBlk->tTxDescriptor.length = (TI_UINT16)((pPktCtrlBlk->tTxnStruct.aLen[0]) + (pPktCtrlBlk->tTxnStruct.aLen[1])); status = txMgmtQ_Xmit (drv->tCommon.hTxMgmtQ, pPktCtrlBlk, TI_TRUE); } else { /* Point the first BDL buffer to the Ethernet header, and the second buffer to the rest of the packet */ pPktCtrlBlk->tTxnStruct.aBuf[0] = skb->data; pPktCtrlBlk->tTxnStruct.aLen[0] = ETHERNET_HDR_LEN; pPktCtrlBlk->tTxnStruct.aBuf[1] = skb->data + ETHERNET_HDR_LEN; pPktCtrlBlk->tTxnStruct.aLen[1] = (TI_UINT16)skb->len - ETHERNET_HDR_LEN; pPktCtrlBlk->tTxnStruct.aLen[2] = 0; /* Send the packet to the driver for transmission. */ status = txDataQ_InsertPacket (drv->tCommon.hTxDataQ, pPktCtrlBlk,(TI_UINT8)skb->priority, pBssBridgeParam); } /* If failed (queue full or driver not running), drop the packet. */ if (status != TI_OK) { drv->stats.tx_errors++; } os_profile (drv, 1, 0); CL_TRACE_END_L1("tiwlan_drv.ko", "OS", "TX", ""); return 0; }
/** * \fn wlanDrvIf_receivePacket * \brief Receive packet from from lower level * */ TI_BOOL wlanDrvIf_receivePacket(TI_HANDLE OsContext, void *pRxDesc ,void *pPacket, TI_UINT16 Length, TIntraBssBridge *pBridgeDecision) { TWlanDrvIfObj *drv = (TWlanDrvIfObj *)OsContext; unsigned char *pdata = (unsigned char *)((TI_UINT32)pRxDesc & ~(TI_UINT32)0x3); rx_head_t *rx_head = (rx_head_t *)(pdata - WSPI_PAD_BYTES - RX_HEAD_LEN_ALIGNED); struct sk_buff *skb = rx_head->skb; struct sk_buff *new_skb; EIntraBssBridgeDecision eBridge = INTRA_BSS_BRIDGE_NO_BRIDGE; skb->data = pPacket; skb_put(skb, Length); skb->dev = drv->netdev; drv->stats.rx_packets++; drv->stats.rx_bytes += skb->len; /* Intra BSS bridge section */ if(pBridgeDecision != NULL) { eBridge = pBridgeDecision->eDecision; } if(INTRA_BSS_BRIDGE_NO_BRIDGE == eBridge) { /* Forward packet to network stack*/ CL_TRACE_START_L1(); skb->protocol = eth_type_trans(skb, drv->netdev); skb->ip_summed = CHECKSUM_NONE; netif_rx_ni(skb); /* Note: Don't change this trace (needed to exclude OS processing from Rx CPU utilization) */ CL_TRACE_END_L1("tiwlan_drv.ko", "OS", "RX", ""); } else if( INTRA_BSS_BRIDGE_UNICAST == eBridge) { /* Send packet to Tx */ TRACE2(drv->tCommon.hReport, REPORT_SEVERITY_WARNING, " wlanDrvIf_receivePacket() Unicast Bridge data=0x%x len=%d \n", RX_ETH_PKT_DATA(pPacket), RX_ETH_PKT_LEN(pPacket)); xmit_Bridge (skb, pDrvStaticHandle->netdev, pBridgeDecision); } else /* Broadcast/Multicast packet*/ { /* Duplicate packet*/ new_skb = skb_clone(skb, GFP_ATOMIC); skb->protocol = eth_type_trans(skb, drv->netdev); skb->ip_summed = CHECKSUM_NONE; netif_rx_ni(skb); if(new_skb) { xmit_Bridge (new_skb, pDrvStaticHandle->netdev, pBridgeDecision); } else { printk (KERN_ERR "%s: skb_clone failed\n", __FUNCTION__); return TI_FALSE; } } return TI_TRUE; }