void epping_destroy_adapter(epping_adapter_t *pAdapter) { struct net_device *dev = NULL; epping_context_t *pEpping_ctx; if (!pAdapter || !pAdapter->pEpping_ctx) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: pAdapter = NULL\n", __func__); return; } dev = pAdapter->dev; pEpping_ctx = pAdapter->pEpping_ctx; epping_unregister_adapter(pAdapter); cdf_spinlock_destroy(&pAdapter->data_lock); cdf_softirq_timer_free(&pAdapter->epping_timer); pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; while (cdf_nbuf_queue_len(&pAdapter->nodrop_queue)) { cdf_nbuf_t tmp_nbuf = NULL; tmp_nbuf = cdf_nbuf_queue_remove(&pAdapter->nodrop_queue); if (tmp_nbuf) cdf_nbuf_free(tmp_nbuf); } free_netdev(dev); if (!pEpping_ctx) EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: pEpping_ctx = NULL\n", __func__); else pEpping_ctx->epping_adapter = NULL; }
void epping_tx_queue_timeout(struct net_device *dev) { epping_adapter_t *pAdapter; pAdapter = netdev_priv(dev); if (NULL == pAdapter) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: EPPING adapter context is Null", __func__); goto end; } EPPING_LOG(CDF_TRACE_LEVEL_ERROR, "%s: Transmission timeout occurred, pAdapter->started= %d", __func__, pAdapter->started); /* Getting here implies we disabled the TX queues * for too long. Since this is epping * (not because of disassociation or low resource scenarios), * try to restart the queue */ if (pAdapter->started) netif_wake_queue(dev); end: return; }
void epping_driver_exit(v_CONTEXT_t pVosContext) { epping_context_t *pEpping_ctx; pr_info("%s: unloading driver\n", __func__); pEpping_ctx = vos_get_context(VOS_MODULE_ID_HDD, pVosContext); if(!pEpping_ctx) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: module exit called before probe",__func__); } else { vos_set_unload_in_progress(TRUE); vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, TRUE); } hif_unregister_driver(); vos_mem_free(pEpping_ctx); vos_preClose( &pVosContext ); #ifdef MEMORY_DEBUG adf_net_buf_debug_exit(); vos_mem_exit(); #endif #ifdef TIMER_MANAGER vos_timer_exit(); #endif pr_info("%s: driver unloaded\n", __func__); }
int epping_cookie_init(epping_context_t*pEpping_ctx) { A_UINT32 i, j; pEpping_ctx->cookie_list = NULL; pEpping_ctx->cookie_count = 0; for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) { pEpping_ctx->s_cookie_mem[i] = vos_mem_malloc(sizeof(struct epping_cookie)*MAX_COOKIE_SLOT_SIZE); if (pEpping_ctx->s_cookie_mem[i] == NULL) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: no mem for cookie (idx = %d)", __func__, i); goto error; } vos_mem_zero(pEpping_ctx->s_cookie_mem[i], sizeof(struct epping_cookie)*MAX_COOKIE_SLOT_SIZE); } adf_os_spinlock_init(&pEpping_ctx->cookie_lock); for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) { struct epping_cookie *cookie_mem = pEpping_ctx->s_cookie_mem[i]; for (j = 0; j < MAX_COOKIE_SLOT_SIZE; j++) { epping_free_cookie(pEpping_ctx, &cookie_mem[j]); } } return 0; error: for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) { if (pEpping_ctx->s_cookie_mem[i]) { vos_mem_free(pEpping_ctx->s_cookie_mem[i]); pEpping_ctx->s_cookie_mem[i] = NULL; } } return -ENOMEM; }
epping_adapter_t *epping_add_adapter(epping_context_t *pEpping_ctx, tSirMacAddr macAddr, tCDF_CON_MODE device_mode) { struct net_device *dev; epping_adapter_t *pAdapter; dev = alloc_netdev(sizeof(epping_adapter_t), "wifi%d", #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) NET_NAME_UNKNOWN, #endif ether_setup); if (dev == NULL) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: Cannot allocate epping_adapter_t\n", __func__); return NULL; } pAdapter = netdev_priv(dev); cdf_mem_zero(pAdapter, sizeof(*pAdapter)); pAdapter->dev = dev; pAdapter->pEpping_ctx = pEpping_ctx; pAdapter->device_mode = device_mode; /* station, SAP, etc */ cdf_mem_copy(dev->dev_addr, (void *)macAddr, sizeof(tSirMacAddr)); cdf_mem_copy(pAdapter->macAddressCurrent.bytes, macAddr, sizeof(tSirMacAddr)); cdf_spinlock_init(&pAdapter->data_lock); cdf_nbuf_queue_init(&pAdapter->nodrop_queue); pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; cdf_softirq_timer_init(epping_get_cdf_ctx(), &pAdapter->epping_timer, epping_timer_expire, dev, CDF_TIMER_TYPE_SW); dev->type = ARPHRD_IEEE80211; dev->netdev_ops = &epping_drv_ops; dev->watchdog_timeo = 5 * HZ; /* XXX */ dev->tx_queue_len = EPPING_TXBUF - 1; /* 1 for mgmt frame */ if (epping_register_adapter(pAdapter) == 0) { EPPING_LOG(LOG1, FL("Disabling queues")); netif_tx_disable(dev); netif_carrier_off(dev); return pAdapter; } else { epping_destroy_adapter(pAdapter); return NULL; } }
void epping_tx_timer_expire(epping_adapter_t *pAdapter) { adf_nbuf_t nodrop_skb; EPPING_LOG(VOS_TRACE_LEVEL_INFO, "%s: queue len: %d\n", __func__, adf_nbuf_queue_len(&pAdapter->nodrop_queue)); if (!adf_nbuf_queue_len(&pAdapter->nodrop_queue)) { /* nodrop queue is empty so no need to arm timer */ pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; return; } /* try to flush nodrop queue */ while ((nodrop_skb = adf_nbuf_queue_remove(&pAdapter->nodrop_queue))) { HTCSetNodropPkt(pAdapter->pEpping_ctx->HTCHandle, TRUE); if (epping_tx_send_int(nodrop_skb, pAdapter)) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: nodrop: %p xmit fail in timer\n", __func__, nodrop_skb); /* fail to xmit so put the nodrop packet to the nodrop queue */ adf_nbuf_queue_insert_head(&pAdapter->nodrop_queue, nodrop_skb); break; } else { HTCSetNodropPkt(pAdapter->pEpping_ctx->HTCHandle, FALSE); EPPING_LOG(VOS_TRACE_LEVEL_INFO, "%s: nodrop: %p xmit ok in timer\n", __func__, nodrop_skb); } } /* if nodrop queue is not empty, continue to arm timer */ if (nodrop_skb) { adf_os_spin_lock_bh(&pAdapter->data_lock); /* if nodrop queue is not empty, continue to arm timer */ if (pAdapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) { pAdapter->epping_timer_state = EPPING_TX_TIMER_RUNNING; adf_os_timer_mod(&pAdapter->epping_timer, TX_RETRY_TIMEOUT_IN_MS); } adf_os_spin_unlock_bh(&pAdapter->data_lock); } else { pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; } }
static void epping_timer_expire(void *data) { struct net_device *dev = (struct net_device *)data; epping_adapter_t *pAdapter; if (dev == NULL) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: netdev = NULL", __func__); return; } pAdapter = netdev_priv(dev); if (pAdapter == NULL) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: adapter = NULL", __func__); return; } pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; epping_tx_timer_expire(pAdapter); }
void epping_tx_dup_pkt(epping_adapter_t *pAdapter, HTC_ENDPOINT_ID eid, adf_nbuf_t skb) { struct epping_cookie * cookie = NULL; int skb_len, ret; adf_nbuf_t new_skb; cookie = epping_alloc_cookie(pAdapter->pEpping_ctx); if (cookie == NULL) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: epping_alloc_cookie returns no resource\n", __func__); return; } new_skb = adf_nbuf_copy(skb); if (!new_skb) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: adf_nbuf_copy returns no resource\n", __func__); epping_free_cookie(pAdapter->pEpping_ctx, cookie); return; } SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt, cookie, adf_nbuf_data(skb), adf_nbuf_len(new_skb), eid, 0); SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, new_skb); skb_len = (int)adf_nbuf_len(new_skb); /* send the packet */ ret = HTCSendPkt(pAdapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt); if (ret != A_OK) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: HTCSendPkt failed, ret = %d\n", __func__, ret); epping_free_cookie(pAdapter->pEpping_ctx, cookie); adf_nbuf_free(new_skb); return; } pAdapter->stats.tx_bytes += skb_len; ++pAdapter->stats.tx_packets; if (((pAdapter->stats.tx_packets + pAdapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 && (pAdapter->stats.tx_packets || pAdapter->stats.tx_dropped)) { epping_log_stats(pAdapter, __func__); } }
static void epping_stop_adapter(epping_adapter_t *pAdapter) { if (pAdapter && pAdapter->started) { EPPING_LOG(LOG1, FL("Disabling queues")); netif_tx_disable(pAdapter->dev); netif_carrier_off(pAdapter->dev); pAdapter->started = false; #if defined(MSM_PLATFORM) && defined(HIF_PCI) && defined(CONFIG_CNSS) cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_LOW); #endif } }
struct net_device_stats *epping_get_stats(struct net_device *dev) { epping_adapter_t *pAdapter = netdev_priv(dev); if (NULL == pAdapter) { EPPING_LOG(CDF_TRACE_LEVEL_ERROR, "%s: pAdapter = NULL", __func__); return NULL; } return &pAdapter->stats; }
int epping_ndev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { epping_adapter_t *pAdapter; int ret = 0; pAdapter = netdev_priv(dev); if (NULL == pAdapter) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: EPPING adapter context is Null", __func__); ret = -ENODEV; goto end; } if (dev != pAdapter->dev) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: HDD adapter/dev inconsistency", __func__); ret = -ENODEV; goto end; } if ((!ifr) || (!ifr->ifr_data)) { ret = -EINVAL; goto end; } switch (cmd) { case (SIOCDEVPRIVATE + 1): EPPING_LOG(CDF_TRACE_LEVEL_ERROR, "%s: do not support ioctl %d (SIOCDEVPRIVATE + 1)", __func__, cmd); break; default: EPPING_LOG(CDF_TRACE_LEVEL_ERROR, "%s: unknown ioctl %d", __func__, cmd); ret = -EINVAL; break; } end: return ret; }
static int epping_register_adapter(epping_adapter_t *pAdapter) { int ret = 0; if ((ret = register_netdev(pAdapter->dev)) != 0) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: unable to register device\n", pAdapter->dev->name); } else { pAdapter->registered = true; } return ret; }
static int epping_start_adapter(epping_adapter_t *pAdapter) { if (!pAdapter) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: pAdapter= NULL\n", __func__); return -1; } if (!pAdapter->started) { #if defined(MSM_PLATFORM) && defined(HIF_PCI) && defined(CONFIG_CNSS) cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_HIGH); #endif netif_carrier_on(pAdapter->dev); EPPING_LOG(LOG1, FL("Enabling queues")); netif_tx_start_all_queues(pAdapter->dev); pAdapter->started = true; } else { EPPING_LOG(CDF_TRACE_LEVEL_WARN, "%s: pAdapter %p already started\n", __func__, pAdapter); } return 0; }
void epping_exit(v_CONTEXT_t pVosContext) { epping_context_t *pEpping_ctx; VosContextType *gpVosContext; pEpping_ctx = vos_get_context(VOS_MODULE_ID_HDD, pVosContext); if (pEpping_ctx == NULL) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: error: pEpping_ctx = NULL", __func__); return; } gpVosContext = pEpping_ctx->pVosContext; if (pVosContext == NULL) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: error: pVosContext = NULL", __func__); return; } if (pEpping_ctx->epping_adapter) { epping_destroy_adapter(pEpping_ctx->epping_adapter); pEpping_ctx->epping_adapter = NULL; } hif_disable_isr(gpVosContext->pHIFContext); hif_reset_soc(gpVosContext->pHIFContext); HTCStop(gpVosContext->htc_ctx); HTCDestroy(gpVosContext->htc_ctx); gpVosContext->htc_ctx = NULL; #ifdef HIF_PCI { int i; for (i = 0; i < EPPING_MAX_NUM_EPIDS; i++) { epping_unregister_tx_copier(i, pEpping_ctx); } } #endif /* HIF_PCI */ epping_cookie_cleanup(pEpping_ctx); }
static void epping_ndev_uninit(struct net_device *dev) { epping_adapter_t *pAdapter; pAdapter = netdev_priv(dev); if (NULL == pAdapter) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: EPPING adapter context is Null", __func__); goto end; } epping_stop_adapter(pAdapter); end: return; }
void epping_log_stats(epping_adapter_t *pAdapter, const char *str) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: txCount = %lu, txDrop = %lu, tx_bytes = %lu, " "rxCount = %lu, rxDrop = %lu, rx_bytes = %lu, tx_acks = %u\n", str, pAdapter->stats.tx_packets, pAdapter->stats.tx_dropped, pAdapter->stats.tx_bytes, pAdapter->stats.rx_packets, pAdapter->stats.rx_dropped, pAdapter->stats.rx_bytes, pAdapter->pEpping_ctx->total_tx_acks); }
void epping_unregister_tx_copier(HTC_ENDPOINT_ID eid, epping_context_t *pEpping_ctx) { epping_poll_t *epping_poll; if (eid < 0 || eid >= EPPING_MAX_NUM_EPIDS ) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: invalid eid = %d", __func__, eid); return; } epping_poll = &pEpping_ctx->epping_poll[eid]; epping_poll->done = true; if (epping_poll->inited) { epping_tx_copier_schedule(pEpping_ctx, eid, NULL); msleep(EPPING_KTID_KILL_WAIT_TIME_MS); } if (epping_poll->skb) adf_nbuf_free(epping_poll->skb); OS_MEMZERO(epping_poll, sizeof(epping_poll_t)); EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: eid = %d", __func__, eid); }
static void epping_unregister_adapter(epping_adapter_t *pAdapter) { if (pAdapter) { epping_stop_adapter(pAdapter); if (pAdapter->registered) { unregister_netdev(pAdapter->dev); pAdapter->registered = false; } } else { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: pAdapter = NULL, unable to unregister device\n", __func__); } }
void epping_register_tx_copier(HTC_ENDPOINT_ID eid, epping_context_t *pEpping_ctx) { epping_poll_t *epping_poll = &pEpping_ctx->epping_poll[eid]; epping_poll->eid = eid; epping_poll->arg = pEpping_ctx->epping_adapter; epping_poll->done = false; EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: eid = %d, arg = %p", __func__, eid, pEpping_ctx->epping_adapter); sema_init(&epping_poll->sem, 0); adf_os_atomic_init(&epping_poll->atm); epping_poll->inited = true; epping_poll->pid = kthread_create(epping_tx_thread_fn, epping_poll, EPPING_TX_THREAD); wake_up_process(epping_poll->pid); }
static void epping_target_suspend_acknowledge(void *context) { void *vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL); epping_context_t *pEpping_ctx = vos_get_context(VOS_MODULE_ID_HDD, vos_context); int wow_nack = *((int *)context); if (NULL == pEpping_ctx) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: epping_ctx is NULL", __func__); return; } /* EPPING_TODO: do we need wow_nack? */ pEpping_ctx->wow_nack = wow_nack; }
int epping_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { epping_adapter_t *pAdapter; int ret = 0; pAdapter = netdev_priv(dev); if (NULL == pAdapter) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: EPPING adapter context is Null", __func__); ret = -ENODEV; goto end; } ret = epping_tx_send(skb, pAdapter); end: return ret; }
static int epping_ndev_stop(struct net_device *dev) { epping_adapter_t *pAdapter; int ret = 0; pAdapter = netdev_priv(dev); if (NULL == pAdapter) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "%s: EPPING adapter context is Null", __func__); ret = -ENODEV; goto end; } epping_stop_adapter(pAdapter); end: return ret; }
void epping_log_packet(epping_adapter_t *pAdapter, EPPING_HEADER *eppingHdr, int ret, const char *str) { if (eppingHdr->Cmd_h & EPPING_LOG_MASK) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: cmd = %d, seqNo = %u, flag = 0x%x, ret = %d, " "txCount = %lu, txDrop = %lu, txBytes = %lu," "rxCount = %lu, rxDrop = %lu, rxBytes = %lu\n", str, eppingHdr->Cmd_h, eppingHdr->SeqNo, eppingHdr->CmdFlags_h, ret, pAdapter->stats.tx_packets, pAdapter->stats.tx_dropped, pAdapter->stats.tx_bytes, pAdapter->stats.rx_packets, pAdapter->stats.rx_dropped, pAdapter->stats.rx_bytes); } }
static int epping_tx_thread_fn(void *data) { int i; epping_poll_t *epping_poll = data; EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: arg = %p", __func__, data); while (!epping_poll->done) { down(&epping_poll->sem); adf_os_atomic_dec(&epping_poll->atm); if (epping_poll->skb && !epping_poll->done) { for (i = 0; i < MAX_TX_PKT_DUP_NUM; i++) { epping_tx_dup_pkt((epping_adapter_t *)epping_poll->arg, epping_poll->eid, epping_poll->skb); udelay(WLAN_EPPING_DELAY_TIMEOUT_US); } } } return 0; }
/* * Call netif_stop_queue frequently will impact the mboxping tx t-put. * Return HTC_SEND_FULL_KEEP directly in epping_tx_queue_full to avoid. */ return HTC_SEND_FULL_KEEP; } #endif /* HIF_SDIO */ void epping_tx_complete_multiple(void *ctx, HTC_PACKET_QUEUE *pPacketQueue) { epping_context_t *pEpping_ctx = (epping_context_t *)ctx; epping_adapter_t *pAdapter = pEpping_ctx->epping_adapter; struct net_device* dev = pAdapter->dev; A_STATUS status; HTC_ENDPOINT_ID eid; adf_nbuf_t pktSkb; struct epping_cookie *cookie; A_BOOL flushing = FALSE; adf_nbuf_queue_t skb_queue; HTC_PACKET *htc_pkt; adf_nbuf_queue_init(&skb_queue); adf_os_spin_lock_bh(&pAdapter->data_lock); while (!HTC_QUEUE_EMPTY(pPacketQueue)) { htc_pkt = HTC_PACKET_DEQUEUE(pPacketQueue); if (htc_pkt == NULL) break; status=htc_pkt->Status; eid=htc_pkt->Endpoint; pktSkb=GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt); cookie = htc_pkt->pPktContext; if (!pktSkb) { EPPING_LOG(VOS_TRACE_LEVEL_ERROR, "%s: pktSkb is NULL", __func__); ASSERT(0); } else { if (htc_pkt->pBuffer != adf_nbuf_data(pktSkb)) { EPPING_LOG(VOS_TRACE_LEVEL_ERROR, "%s: htc_pkt buffer not equal to skb->data", __func__); ASSERT(0); } /* add this to the list, use faster non-lock API */ adf_nbuf_queue_add(&skb_queue,pktSkb); if (A_SUCCESS(status)) if (htc_pkt->ActualLength != adf_nbuf_len(pktSkb)) { EPPING_LOG(VOS_TRACE_LEVEL_ERROR, "%s: htc_pkt length not equal to skb->len", __func__); ASSERT(0); } } EPPING_LOG(VOS_TRACE_LEVEL_INFO, "%s skb=%p data=%p len=0x%x eid=%d ", __func__, pktSkb, htc_pkt->pBuffer, htc_pkt->ActualLength, eid); if (A_FAILED(status)) { if (status == A_ECANCELED) { /* a packet was flushed */ flushing = TRUE; } if (status != A_NO_RESOURCE) { printk("%s() -TX ERROR, status: 0x%x\n", __func__, status); } } else { EPPING_LOG(VOS_TRACE_LEVEL_INFO, "%s: OK\n", __func__); flushing = FALSE; } epping_free_cookie(pAdapter->pEpping_ctx, cookie); } adf_os_spin_unlock_bh(&pAdapter->data_lock); /* free all skbs in our local list */ while (adf_nbuf_queue_len(&skb_queue)) { /* use non-lock version */ pktSkb = adf_nbuf_queue_remove(&skb_queue); if (pktSkb == NULL) break; adf_nbuf_tx_free(pktSkb, ADF_NBUF_PKT_ERROR); pEpping_ctx->total_tx_acks++; } if (!flushing) { netif_wake_queue(dev); } }
int epping_tx_send(adf_nbuf_t skb, epping_adapter_t *pAdapter) { adf_nbuf_t nodrop_skb; EPPING_HEADER *eppingHdr; A_UINT8 ac = 0; eppingHdr = (EPPING_HEADER *)adf_nbuf_data(skb); if (!IS_EPPING_PACKET(eppingHdr)) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: Recived non endpoint ping packets\n", __func__); /* no packet to send, cleanup */ adf_nbuf_free(skb); return -ENOMEM; } /* the stream ID is mapped to an access class */ ac = eppingHdr->StreamNo_h; /* hard coded two ep ids */ if (ac != 0 && ac != 1) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: ac %d is not mapped to mboxping service\n", __func__, ac); adf_nbuf_free(skb); return -ENOMEM; } /* * some EPPING packets cannot be dropped no matter what access class * it was sent on. A special care has been taken: * 1. when there is no TX resource, queue the control packets to * a special queue * 2. when there is TX resource, send the queued control packets first * and then other packets * 3. a timer launches to check if there is queued control packets and * flush them */ /* check the nodrop queue first */ while ((nodrop_skb = adf_nbuf_queue_remove(&pAdapter->nodrop_queue))) { HTCSetNodropPkt(pAdapter->pEpping_ctx->HTCHandle, TRUE); if (epping_tx_send_int(nodrop_skb, pAdapter)) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: nodrop: %p xmit fail\n", __func__, nodrop_skb); /* fail to xmit so put the nodrop packet to the nodrop queue */ adf_nbuf_queue_insert_head(&pAdapter->nodrop_queue, nodrop_skb); /* no cookie so free the current skb */ goto tx_fail; } else { HTCSetNodropPkt(pAdapter->pEpping_ctx->HTCHandle, FALSE); EPPING_LOG(VOS_TRACE_LEVEL_INFO, "%s: nodrop: %p xmit ok\n", __func__, nodrop_skb); } } /* send the original packet */ if (epping_tx_send_int(skb, pAdapter)) goto tx_fail; return 0; tx_fail: if (!IS_EPING_PACKET_NO_DROP(eppingHdr)) { /* allow to drop the skb so drop it */ adf_nbuf_free(skb); ++pAdapter->stats.tx_dropped; EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: Tx skb %p dropped, stats.tx_dropped = %ld\n", __func__, skb, pAdapter->stats.tx_dropped); return -ENOMEM; } else { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: nodrop: %p queued\n", __func__, skb); adf_nbuf_queue_add(&pAdapter->nodrop_queue, skb); adf_os_spin_lock_bh(&pAdapter->data_lock); if (pAdapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) { pAdapter->epping_timer_state = EPPING_TX_TIMER_RUNNING; adf_os_timer_mod(&pAdapter->epping_timer, TX_RETRY_TIMEOUT_IN_MS); } adf_os_spin_unlock_bh(&pAdapter->data_lock); } return 0; }
static int epping_tx_send_int(adf_nbuf_t skb, epping_adapter_t *pAdapter) { EPPING_HEADER *eppingHdr = (EPPING_HEADER *)adf_nbuf_data(skb); HTC_ENDPOINT_ID eid = ENDPOINT_UNUSED; struct epping_cookie * cookie = NULL; A_UINT8 ac = 0; A_STATUS ret = A_OK; int skb_len; EPPING_HEADER tmpHdr = *eppingHdr; /* allocate resource for this packet */ cookie = epping_alloc_cookie(pAdapter->pEpping_ctx); /* no resource */ if (cookie == NULL) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: epping_alloc_cookie returns no resource\n", __func__); return -1; } if (enb_tx_dump) epping_hex_dump((void *)eppingHdr, skb->len, __func__); /* * a quirk of linux, the payload of the frame is 32-bit aligned and thus * the addition of the HTC header will mis-align the start of the HTC * frame, so we add some padding which will be stripped off in the target */ if (EPPING_ALIGNMENT_PAD > 0) { A_NETBUF_PUSH(skb, EPPING_ALIGNMENT_PAD); } /* prepare ep/HTC information */ ac = eppingHdr->StreamNo_h; eid = pAdapter->pEpping_ctx->EppingEndpoint[ac]; if (eid < 0 || eid >= EPPING_MAX_NUM_EPIDS) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: invalid eid = %d, ac = %d\n", __func__, eid, ac); return -1; } if (tmpHdr.Cmd_h == EPPING_CMD_RESET_RECV_CNT || tmpHdr.Cmd_h == EPPING_CMD_CONT_RX_START) { epping_set_kperf_flag(pAdapter, eid, tmpHdr.CmdBuffer_t[0]); } if (pAdapter->pEpping_ctx->kperf[eid]) { switch (tmpHdr.Cmd_h) { case EPPING_CMD_NO_ECHO: #ifdef HIF_PCI epping_tx_copier_schedule(pAdapter->pEpping_ctx, eid, skb); #endif /* HIF_PCI */ break; default: break; } } if (pAdapter->pEpping_ctx->kperf[eid] && tmpHdr.Cmd_h == EPPING_CMD_NO_ECHO) { epping_tx_dup_pkt(pAdapter, eid, skb); } SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt, cookie, adf_nbuf_data(skb), adf_nbuf_len(skb), eid, 0); SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, skb); skb_len = skb->len; /* send the packet */ ret = HTCSendPkt(pAdapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt); epping_log_packet(pAdapter, &tmpHdr, ret, __func__); if (ret != A_OK) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: HTCSendPkt failed, status = %d\n", __func__, ret); epping_free_cookie(pAdapter->pEpping_ctx, cookie); return -1; } pAdapter->stats.tx_bytes += skb_len; ++pAdapter->stats.tx_packets; if (((pAdapter->stats.tx_packets + pAdapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 && (pAdapter->stats.tx_packets || pAdapter->stats.tx_dropped)) { epping_log_stats(pAdapter, __func__); } return 0; }
int epping_wlan_startup(struct device *parent_dev, v_VOID_t *hif_sc) { int ret = 0; epping_context_t *pEpping_ctx = NULL; VosContextType *pVosContext = NULL; HTC_INIT_INFO htcInfo; struct ol_softc *scn; tSirMacAddr adapter_macAddr; adf_os_device_t adf_ctx; EPPING_LOG(VOS_TRACE_LEVEL_INFO_HIGH, "%s: Enter", __func__); pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); if(pVosContext == NULL) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: Failed vos_get_global_context", __func__); ret = -1; return ret; } pEpping_ctx = vos_get_context(VOS_MODULE_ID_HDD, pVosContext); if(pEpping_ctx == NULL) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: Failed to get pEpping_ctx", __func__); ret = -1; return ret; } pEpping_ctx->parent_dev = (void *)parent_dev; epping_get_dummy_mac_addr(adapter_macAddr); ((VosContextType*)pVosContext)->pHIFContext = hif_sc; /* store target type and target version info in hdd ctx */ pEpping_ctx->target_type = ((struct ol_softc *)hif_sc)->target_type; /* Initialize the timer module */ vos_timer_module_init(); scn = vos_get_context(VOS_MODULE_ID_HIF, pVosContext); if (!scn) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, "%s: scn is null!", __func__); return -1; } scn->enableuartprint = 0; scn->enablefwlog = 0; /* Initialize BMI and Download firmware */ if (bmi_download_firmware(scn)) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, "%s: BMI failed to download target", __func__); BMICleanup(scn); return -1; } EPPING_LOG(VOS_TRACE_LEVEL_INFO_HIGH, "%s: bmi_download_firmware done", __func__); htcInfo.pContext = pVosContext->pHIFContext; htcInfo.TargetFailure = ol_target_failure; htcInfo.TargetSendSuspendComplete = epping_target_suspend_acknowledge; adf_ctx = vos_get_context(VOS_MODULE_ID_ADF, pVosContext); /* Create HTC */ pVosContext->htc_ctx = HTCCreate(htcInfo.pContext, &htcInfo, adf_ctx); if (!pVosContext->htc_ctx) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, "%s: Failed to Create HTC", __func__); BMICleanup(scn); return -1; } pEpping_ctx->HTCHandle = vos_get_context(VOS_MODULE_ID_HTC, pVosContext); if (pEpping_ctx->HTCHandle == NULL) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: HTCHandle is NULL", __func__); return -1; } scn->htc_handle = pEpping_ctx->HTCHandle; HIFClaimDevice(scn->hif_hdl, scn); if (bmi_done(scn)) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: Failed to complete BMI phase", __func__); goto error_end; } /* start HIF */ if (HTCWaitTarget(scn->htc_handle) != A_OK) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: HTCWaitTarget error", __func__); goto error_end; } EPPING_LOG(VOS_TRACE_LEVEL_INFO_HIGH, "%s: HTC ready", __func__); ret = epping_connect_service(pEpping_ctx); if (ret != 0) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: HTCWaitTargetdone", __func__); goto error_end; } if (HTCStart(pEpping_ctx->HTCHandle) != A_OK) { goto error_end; } EPPING_LOG(VOS_TRACE_LEVEL_INFO_HIGH, "%s: HTC started", __func__); /* init the tx cookie resource */ ret = epping_cookie_init(pEpping_ctx); if (ret == 0) { pEpping_ctx->epping_adapter = epping_add_adapter(pEpping_ctx, adapter_macAddr, WLAN_HDD_INFRA_STATION); } if (ret < 0 || pEpping_ctx->epping_adapter == NULL) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: epping_add_adaptererror error", __func__); HTCStop(pEpping_ctx->HTCHandle); epping_cookie_cleanup(pEpping_ctx); goto error_end; } #ifdef HIF_PCI { int i; for (i = 0; i < EPPING_MAX_NUM_EPIDS; i++) { epping_register_tx_copier(i, pEpping_ctx); } } #endif /* HIF_PCI */ EPPING_LOG(VOS_TRACE_LEVEL_INFO_HIGH, "%s: Exit", __func__); complete(&pEpping_ctx->wlan_start_comp); return ret; error_end: HTCDestroy(pVosContext->htc_ctx); pVosContext->htc_ctx = NULL; BMICleanup(scn); return -1; }
int epping_connect_service(epping_context_t *pEpping_ctx) { int status, i; HTC_SERVICE_CONNECT_REQ connect; HTC_SERVICE_CONNECT_RESP response; cdf_mem_zero(&connect, sizeof(connect)); cdf_mem_zero(&response, sizeof(response)); /* these fields are the same for all service endpoints */ connect.EpCallbacks.pContext = pEpping_ctx; connect.EpCallbacks.EpTxCompleteMultiple = epping_tx_complete_multiple; connect.EpCallbacks.EpRecv = epping_rx; /* epping_tx_complete use Multiple version */ connect.EpCallbacks.EpTxComplete = NULL; connect.MaxSendQueueDepth = 64; #ifdef HIF_SDIO connect.EpCallbacks.EpRecvRefill = epping_refill; connect.EpCallbacks.EpSendFull = epping_tx_queue_full /* ar6000_tx_queue_full */; #elif defined(HIF_USB) || defined(HIF_PCI) connect.EpCallbacks.EpRecvRefill = NULL /* provided by HIF */; connect.EpCallbacks.EpSendFull = NULL /* provided by HIF */; /* disable flow control for hw flow control */ connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; #endif /* connect to service */ connect.ServiceID = WMI_DATA_BE_SVC; status = htc_connect_service(pEpping_ctx->HTCHandle, &connect, &response); if (status != EOK) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "Failed to connect to Endpoint Ping BE service status:%d \n", status); return -1;; } else { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "eppingtest BE endpoint:%d\n", response.Endpoint); } pEpping_ctx->EppingEndpoint[0] = response.Endpoint; #if defined(HIF_PCI) || defined(HIF_USB) connect.ServiceID = WMI_DATA_BK_SVC; status = htc_connect_service(pEpping_ctx->HTCHandle, &connect, &response); if (status != EOK) { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "Failed to connect to Endpoint Ping BK service status:%d \n", status); return -1;; } else { EPPING_LOG(CDF_TRACE_LEVEL_FATAL, "eppingtest BK endpoint:%d\n", response.Endpoint); } pEpping_ctx->EppingEndpoint[1] = response.Endpoint; /* Since we do not create other two SVC use BK endpoint * for rest ACs (2, 3) */ for (i = 2; i < EPPING_MAX_NUM_EPIDS; i++) { pEpping_ctx->EppingEndpoint[i] = response.Endpoint; } #else /* we only use one endpoint for high latenance bus. * Map all AC's EPIDs to the same endpoint ID returned by HTC */ for (i = 0; i < EPPING_MAX_NUM_EPIDS; i++) { pEpping_ctx->EppingEndpoint[i] = response.Endpoint; } #endif return 0; }
/**--------------------------------------------------------------------------- \brief epping_driver_init() - End point ping driver Init Function This is the driver entry point - called in different timeline depending on whether the driver is statically or dynamically linked \param - con_mode connection mode \return - 0 for success, negative for failure ----------------------------------------------------------------------------*/ int epping_driver_init(int con_mode, vos_wake_lock_t *g_wake_lock, char *pwlan_module_name) { int ret = 0; unsigned long rc; epping_context_t *pEpping_ctx = NULL; VOS_STATUS status = VOS_STATUS_SUCCESS; EPPING_LOG(VOS_TRACE_LEVEL_INFO_HIGH, "%s: Enter", __func__); #ifdef TIMER_MANAGER vos_timer_manager_init(); #endif #ifdef MEMORY_DEBUG vos_mem_init(); adf_net_buf_debug_init(); #endif pEpping_ctx = vos_mem_malloc(sizeof(epping_context_t)); if (pEpping_ctx == NULL) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: No memory", __func__); ret = -ENOMEM; goto error1; } vos_mem_zero(pEpping_ctx, sizeof(epping_context_t)); pEpping_ctx->g_wake_lock = g_wake_lock; pEpping_ctx->con_mode = con_mode; pEpping_ctx->pwlan_module_name = pwlan_module_name; status = vos_preOpen(&pEpping_ctx->pVosContext); if (!VOS_IS_STATUS_SUCCESS(status)) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: Failed to preOpen VOSS", __func__); ret = -1; goto error1; } /* save epping_context in VOSS */ ((VosContextType *)(pEpping_ctx->pVosContext))->pHDDContext = (v_VOID_t*)pEpping_ctx; #ifdef HIF_SDIO #define WLAN_WAIT_TIME_WLANSTART 10000 #else #define WLAN_WAIT_TIME_WLANSTART 2000 #endif init_completion(&pEpping_ctx->wlan_start_comp); ret = hif_register_driver(); if (!ret) { rc = wait_for_completion_timeout( &pEpping_ctx->wlan_start_comp, msecs_to_jiffies(WLAN_WAIT_TIME_WLANSTART)); if (!rc) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: timed-out waiting for hif_register_driver", __func__); ret = -1; } else ret = 0; } if (ret) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: %s driver Initialization failed", __func__, pEpping_ctx->pwlan_module_name); hif_unregister_driver(); vos_preClose(&pEpping_ctx->pVosContext); ret = -ENODEV; vos_mem_free(pEpping_ctx); #ifdef MEMORY_DEBUG adf_net_buf_debug_exit(); vos_mem_exit(); #endif #ifdef TIMER_MANAGER vos_timer_exit(); #endif return ret; } else { pr_info("%s: %s driver loaded\n", __func__, pEpping_ctx->pwlan_module_name); return 0; } error1: if (pEpping_ctx) { vos_mem_free(pEpping_ctx); pEpping_ctx = NULL; } #ifdef MEMORY_DEBUG adf_net_buf_debug_exit(); vos_mem_exit(); #endif #ifdef TIMER_MANAGER vos_timer_exit(); #endif return ret; }