static int bcm_rpc_tp_tx_agg_release(rpc_tp_info_t * rpcb) { rpc_buf_t *b; int err; /* no aggregation formed */ if (rpcb->tp_tx_agg_p == NULL) return 0; RPC_TP_AGG(("%s: send %d, sframe %d\n", __FUNCTION__, rpcb->tp_tx_agg_bytes, rpcb->tp_tx_agg_sframes)); b = rpcb->tp_tx_agg_p; rpcb->tp_tx_agg_cnt_chain++; rpcb->tp_tx_agg_cnt_sf += rpcb->tp_tx_agg_sframes; rpcb->tp_tx_agg_cnt_bytes += rpcb->tp_tx_agg_bytes; if (rpcb->tp_tx_agg_sframes == 1) rpcb->tp_tx_agg_cnt_noagg++; err = bcm_rpc_tp_buf_send_internal(rpcb, b); bcm_rpc_tp_tx_agg_initstate(rpcb); return err; }
int bcm_rpc_tp_buf_send(rpc_tp_info_t * rpcb, rpc_buf_t *b) { int err; /* Add the TP encapsulation */ bcm_rpc_tp_tx_encap(rpcb, b); /* if aggregation enabled use the agg path, otherwise send immediately */ if (rpcb->tp_tx_aggregation) { err = bcm_rpc_tp_tx_agg(rpcb, b); } else { rpcb->tp_tx_agg_cnt_pass++; err = bcm_rpc_tp_buf_send_internal(rpcb, b); } return err; }
/* This is called by dngl_txstop as txflowcontrol (stopping tx from dongle to host) of bcmwl, * but is called rxflowcontrol in wl driver (pausing rx of wl driver). This is for low driver only. */ void bcm_rpc_tp_txflowctl(rpc_tp_info_t *rpc_th, bool state, int prio) { rpc_buf_t *b; ASSERT(rpc_th); if (rpc_th->tx_flowctl == state) return; RPC_TP_AGG(("tp_txflowctl %d\n", state)); rpc_th->tx_flowctl = state; rpc_th->tx_flowctl_cnt++; rpc_th->tx_flowcontrolled = state; /* when get out of flowcontrol, send all queued packets in a loop * but need to check tx_flowctl every iteration and stop if we got flowcontrolled again */ while (!rpc_th->tx_flowctl && !pktq_empty(rpc_th->tx_flowctlq)) { b = pktdeq(rpc_th->tx_flowctlq); if (b == NULL) break; rpc_th->tx_q_flowctl_segcnt -= pktsegcnt(rpc_th->osh, b); bcm_rpc_tp_buf_send_internal(rpc_th, b, USBDEV_BULK_IN_EP1); } /* bcm_rpc_tp_agg_set(rpc_th, BCM_RPC_TP_DNGL_AGG_FLOWCTL, state); */ /* if lowm is reached, release wldriver * TODO, count more(average 3?) if agg is ON */ if (rpc_th->tx_q_flowctl_segcnt < rpc_th->tx_q_flowctl_lowm) { RPC_TP_AGG(("bcm_rpc_tp_txflowctl, wm hit low!\n")); rpc_th->txflowctl_cb(rpc_th->txflowctl_ctx, OFF); } return; }
static int bcm_rpc_tp_dngl_agg_release(rpc_tp_info_t * rpcb) { int err; rpc_buf_t *b; if (rpcb->tp_dngl_agg_p == NULL) { /* no aggregation formed */ return 0; } RPC_TP_AGG(("%s, send %d, sframe %d\n", __FUNCTION__, rpcb->tp_dngl_agg_bytes, rpcb->tp_dngl_agg_sframes)); b = rpcb->tp_dngl_agg_p; rpcb->tp_dngl_agg_cnt_chain++; rpcb->tp_dngl_agg_cnt_sf += rpcb->tp_dngl_agg_sframes; rpcb->tp_dngl_agg_cnt_bytes += rpcb->tp_dngl_agg_bytes; if (rpcb->tp_dngl_agg_sframes == 1) rpcb->tp_dngl_agg_cnt_noagg++; bcm_rpc_tp_dngl_agg_initstate(rpcb); rpcb->tp_dngl_agg_txpending++; if (rpcb->tx_flowctl) { bcm_rpc_tp_buf_send_enq(rpcb, b); err = 0; } else { err = bcm_rpc_tp_buf_send_internal(rpcb, b, USBDEV_BULK_IN_EP1); } if (err != 0) { RPC_TP_ERR(("bcm_rpc_tp_dngl_agg_release: send err!!!\n")); /* ASSERT(0) */ } return err; }
int bcm_rpc_tp_buf_send(rpc_tp_info_t * rpc_th, rpc_buf_t *b) { int err; /* Add the TP encapsulation */ bcm_rpc_tp_tx_encap(rpc_th, b); /* if agg successful, done; otherwise, send it */ if (rpc_th->tp_dngl_aggregation) { err = bcm_rpc_tp_dngl_agg(rpc_th, b); return err; } rpc_th->tp_dngl_agg_cnt_pass++; if (rpc_th->tx_flowctl) { bcm_rpc_tp_buf_send_enq(rpc_th, b); err = 0; } else { err = bcm_rpc_tp_buf_send_internal(rpc_th, b, USBDEV_BULK_IN_EP1); } return err; }