int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal) { void *p; int err = 0; int len, psize, maxlen; ASSERT(pktp->plen != 0); maxlen = pktp->maxlen; psize = minimal ? (maxlen >> 2) : maxlen; for (len = (int)pktp->len; len < psize; len++) { p = PKTGET(osh, pktp->len, TRUE); if (p == NULL) { err = BCME_NOMEM; break; } if (pktpool_add(pktp, p) != BCME_OK) { PKTFREE(osh, p, FALSE); err = BCME_ERROR; break; } } return err; }
rpc_buf_t * bcm_rpc_tp_buf_alloc(rpc_tp_info_t * rpc_th, int len) { rpc_buf_t * b; size_t tp_len = len + BCM_RPC_TP_ENCAP_LEN; size_t padlen; #ifdef BCMUSBDEV padlen = MAX(BCM_RPC_TP_DNGL_TOTLEN_BAD_PAD, BCM_RPC_TP_DNGL_ZLP_PAD); padlen = ROUNDUP(padlen, sizeof(int)); #else padlen = 0; #endif /* BCMUSBDEV */ /* get larger packet with padding which might be required due to USB ZLP */ b = (rpc_buf_t*)PKTGET(rpc_th->osh, tp_len + padlen, FALSE); if (b != NULL) { rpc_th->bufalloc++; rpc_th->buf_cnt_inuse++; /* set the len back to tp_len */ bcm_rpc_buf_len_set(rpc_th, b, tp_len); PKTPULL(rpc_th->osh, b, BCM_RPC_TP_ENCAP_LEN); } return b; }
/* totally bogus -- d11 hdr only + tx hdrs */ static void * wlc_olpc_get_pkt(wlc_info_t *wlc, uint ac, uint* fifo) { int buflen = (TXOFF + WL_OLPC_PKT_LEN); void* p = NULL; osl_t *osh = wlc->osh; const char* macaddr = NULL; struct dot11_header *hdr = NULL; if ((p = PKTGET(osh, buflen, TRUE)) == NULL) { WL_ERROR(("wl%d: %s: pktget error for len %d \n", wlc->pub->unit, __FUNCTION__, buflen)); goto fatal; } macaddr = WLC_MACADDR(wlc); WL_NONE(("pkt manip\n")); /* reserve TXOFF bytes of headroom */ PKTPULL(osh, p, TXOFF); PKTSETLEN(osh, p, WL_OLPC_PKT_LEN); WL_NONE(("d11_hdr\n")); hdr = (struct dot11_header*)PKTDATA(osh, p); bzero((char*)hdr, WL_OLPC_PKT_LEN); hdr->fc = htol16(FC_DATA); hdr->durid = 0; bcopy((const char*)macaddr, (char*)&(hdr->a1.octet), ETHER_ADDR_LEN); bcopy((const char*)macaddr, (char*)&(hdr->a2.octet), ETHER_ADDR_LEN); bcopy((const char*)macaddr, (char*)&(hdr->a3.octet), ETHER_ADDR_LEN); hdr->seq = 0; WL_NONE(("prep raw 80211\n")); wlc->olpc_info->tx_cal_pkts = TRUE; /* frameid returned here -- ignore for now -- may speed up using this */ (void)wlc_prep80211_raw(wlc, NULL, ac, TRUE, p, fifo); wlc->olpc_info->tx_cal_pkts = FALSE; return p; fatal: return (NULL); }
void* osl_pktdup(void *drv, void *p) { END_OBJ *end; M_BLK_ID m; int len = pkttotlen(drv, p); /* drv is a pointer to an END_OBJ in disguise */ end = (END_OBJ*)drv; /* dont use a real dup until PR14233 is fixed m = netMblkChainDup(end->pNetPool, (M_BLK_ID)p, 0, M_COPYALL, M_DONTWAIT); */ /* alloc a new mbuf */ if ((m = PKTGET(drv, len, TRUE)) == NULL) return (NULL); /* copy data into mbuf */ pktcopy(drv, p, 0, len, (uchar*)PKTDATA(drv, m)); ASSERT(len == PKTLEN(drv, m)); return (m); }
/* * pktpool_init: * User provides a pktpool_t sturcture and specifies the number of packets to * be pre-filled into the pool (pplen). The size of all packets in a pool must * be the same and is specified by plen. * pktpool_init first attempts to register the pool and fetch a unique poolid. * If registration fails, it is considered an BCME_ERR, caused by either the * registry was not pre-created (pktpool_attach) or the registry is full. * If registration succeeds, then the requested number of packets will be filled * into the pool as part of initialization. In the event that there is no * available memory to service the request, then BCME_NOMEM will be returned * along with the count of how many packets were successfully allocated. * In dongle builds, prior to memory reclaimation, one should limit the number * of packets to be allocated during pktpool_init and fill the pool up after * reclaim stage. */ int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pplen, int plen, bool istx, uint8 type) { int i, err = BCME_OK; int pktplen; uint8 pktp_id; ASSERT(pktp != NULL); ASSERT(osh != NULL); ASSERT(pplen != NULL); pktplen = *pplen; bzero(pktp, sizeof(pktpool_t)); /* assign a unique pktpool id */ if ((pktp_id = (uint8) pktpool_register(pktp)) == PKTPOOL_INVALID_ID) { return BCME_ERROR; } POOLSETID(pktp, pktp_id); pktp->inited = TRUE; pktp->istx = istx ? TRUE : FALSE; pktp->plen = (uint16)plen; pktp->type = type; pktp->maxlen = PKTPOOL_LEN_MAX; pktplen = LIMIT_TO_MAX(pktplen, pktp->maxlen); for (i = 0; i < pktplen; i++) { void *p; p = PKTGET(osh, plen, TRUE); if (p == NULL) { /* Not able to allocate all requested pkts * so just return what was actually allocated * We can add to the pool later */ if (pktp->freelist == NULL) /* pktpool free list is empty */ err = BCME_NOMEM; goto exit; } PKTSETPOOL(osh, p, TRUE, pktp); /* Tag packet with pool ID */ PKTSETFREELIST(p, pktp->freelist); /* insert p at head of free list */ pktp->freelist = p; pktp->avail++; #ifdef BCMDBG_POOL pktp->dbg_q[pktp->dbg_qlen++].p = p; #endif } exit: pktp->len = pktp->avail; *pplen = pktp->len; return err; }
/* internal pkt allocation, no BCM_RPC_TP_ENCAP_LEN */ static rpc_buf_t * bcm_rpc_tp_pktget(rpc_tp_info_t * rpcb, int len, bool send) { rpc_buf_t* b; #if defined(NDIS) struct lbuf *lb; if (len > LBDATASZ) return (NULL); if (send) lb = shared_lb_get(rpcb->sh, &rpcb->sh->txfree); else lb = shared_lb_get(rpcb->sh, &rpcb->sh->rxfree); if (lb != NULL) lb->len = len; b = (rpc_buf_t*)lb; #else struct sk_buff *skb; #if defined(CTFPOOL) skb = PKTGET(rpcb->osh, len, FALSE); #else if ((skb = dev_alloc_skb(len))) { skb_put(skb, len); skb->priority = 0; } #endif /* defined(CTFPOOL) */ b = (rpc_buf_t*)skb; if (b != NULL) { #ifdef CTFMAP /* Clear the ctf buf flag to allow full dma map */ PKTCLRCTF(rpcb->osh, skb); CTFMAPPTR(rpcb->osh, skb) = NULL; #endif /* CTFMAP */ RPC_TP_LOCK(rpcb); rpcb->bufalloc++; if (!rpcb->rxflowctrl && (rpcb->buf_cnt_inuse >= RPCRX_WM_HI)) { rpcb->rxflowctrl = TRUE; RPC_TP_ERR(("%s, rxflowctrl change to %d\n", __FUNCTION__, rpcb->rxflowctrl)); dbus_flowctrl_rx(rpcb->bus, TRUE); } rpcb->buf_cnt_inuse++; if (rpcb->buf_cnt_inuse > (int)rpcb->buf_cnt_max) rpcb->buf_cnt_max = rpcb->buf_cnt_inuse; RPC_TP_UNLOCK(rpcb); } else { printf("%s: buf alloc failed buf_cnt_inuse %d rxflowctrl:%d\n", __FUNCTION__, rpcb->buf_cnt_inuse, rpcb->rxflowctrl); ASSERT(0); } #endif /* NDIS */ return b; }
static void BCMFASTPATH rpc_dbus_recv_buf(void *handle, uint8 *buf, int len) { rpc_tp_info_t *rpcb = handle; void *pkt; uint32 rpc_len; uint frag; uint agglen; if ((rpcb == NULL) || (buf == NULL)) return; frag = rpcb->tp_host_deagg_cnt_sf; agglen = len; /* TP pkt should have more than encapsulation header */ if (len <= BCM_RPC_TP_ENCAP_LEN) { RPC_TP_ERR(("%s: wrong len %d\n", __FUNCTION__, len)); goto error; } while (len > BCM_RPC_TP_ENCAP_LEN) { rpc_len = ltoh32_ua(buf); if (rpc_len > (uint32)(len - BCM_RPC_TP_ENCAP_LEN)) { rpcb->tp_host_deagg_cnt_badsflen++; return; } /* RPC_BUFFER_RX: allocate */ #if defined(BCM_RPC_ROC) if ((pkt = PKTGET(rpcb->osh, rpc_len, FALSE)) == NULL) { #else if ((pkt = bcm_rpc_tp_pktget(rpcb, rpc_len, FALSE)) == NULL) { #endif printf("%s: bcm_rpc_tp_pktget failed (len %d)\n", __FUNCTION__, len); goto error; } /* RPC_BUFFER_RX: BYTE_COPY from dbus buffer */ bcopy(buf + BCM_RPC_TP_ENCAP_LEN, bcm_rpc_buf_data(rpcb, pkt), rpc_len); /* !! send up */ bcm_rpc_tp_rx(rpcb, pkt); len -= (BCM_RPC_TP_ENCAP_LEN + rpc_len); buf += (BCM_RPC_TP_ENCAP_LEN + rpc_len); if (len > BCM_RPC_TP_ENCAP_LEN) { /* more frag */ rpcb->tp_host_deagg_cnt_sf++; RPC_TP_DEAGG(("%s: deagg %d(remaining %d) bytes\n", __FUNCTION__, rpc_len, len)); } else { if (len != 0) { printf("%s: deagg, remaining len %d is not 0\n", __FUNCTION__, len); } rpcb->tp_host_deagg_cnt_pass++; } } if (frag < rpcb->tp_host_deagg_cnt_sf) { /* aggregated frames */ rpcb->tp_host_deagg_cnt_sf++; /* last one was not counted */ rpcb->tp_host_deagg_cnt_chain++; rpcb->tp_host_deagg_cnt_bytes += agglen; } error: return; } int BCMFASTPATH bcm_rpc_tp_recv_rtn(rpc_tp_info_t *rpcb) { void *pkt; int status = 0; if (!rpcb) return BCME_BADARG; if ((pkt = bcm_rpc_tp_pktget(rpcb, PKTBUFSZ, FALSE)) == NULL) { return BCME_NORESOURCE; } RPC_TP_LOCK(rpcb); if (rpcb->rx_rtn_pkt != NULL) { RPC_TP_UNLOCK(rpcb); if (pkt != NULL) bcm_rpc_tp_pktfree(rpcb, pkt, FALSE); return BCME_BUSY; } rpcb->rx_rtn_pkt = pkt; RPC_TP_UNLOCK(rpcb); #ifndef BCMUSBDEV_EP_FOR_RPCRETURN status = dbus_recv_ctl(rpcb->bus, bcm_rpc_buf_data(rpcb, rpcb->rx_rtn_pkt), PKTBUFSZ); #else if (rpcb->has_2nd_bulk_in_ep) { status = dbus_recv_bulk(rpcb->bus, USBDEV_BULK_IN_EP2); } else { status = dbus_recv_ctl(rpcb->bus, bcm_rpc_buf_data(rpcb, rpcb->rx_rtn_pkt), PKTBUFSZ); } #endif /* BCMUSBDEV_EP_FOR_RPCRETURN */ if (status) { /* May have been cleared by complete routine */ RPC_TP_LOCK(rpcb); pkt = rpcb->rx_rtn_pkt; rpcb->rx_rtn_pkt = NULL; RPC_TP_UNLOCK(rpcb); if (pkt != NULL) bcm_rpc_tp_pktfree(rpcb, pkt, FALSE); if (status == DBUS_ERR_RXFAIL) status = BCME_RXFAIL; else if (status == DBUS_ERR_NODEVICE) status = BCME_NODEVICE; else status = BCME_ERROR; } return status; }
/* post receive buffers */ void dma_rxfill(dma_info_t *di) { void *p; uint rxin, rxout; uint ctrl; uint n; uint i; uint32 pa; uint rxbufsize; /* * Determine how many receive buffers we're lacking * from the full complement, allocate, initialize, * and post them, then update the chip rx lastdscr. */ rxin = di->rxin; rxout = di->rxout; rxbufsize = di->rxbufsize; n = di->nrxpost - NRXDACTIVE(rxin, rxout); DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n)); for (i = 0; i < n; i++) { if ((p = PKTGET(di->drv, rxbufsize, FALSE)) == NULL) { DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", di->name)); di->hnddma.rxnobuf++; break; } /* PR3263 & PR3387 & PR4642 war: rxh.len=0 means dma writes not complete */ *(uint32*)(OSL_UNCACHED(PKTDATA(di->drv, p))) = 0; pa = (uint32) DMA_MAP(di->dev, PKTDATA(di->drv, p), rxbufsize, DMA_RX, p); ASSERT(ISALIGNED(pa, 4)); /* save the free packet pointer */ #if 0 ASSERT(di->rxp[rxout] == NULL); #endif di->rxp[rxout] = p; /* paranoia */ ASSERT(R_SM(&di->rxd[rxout].addr) == 0); /* prep the descriptor control value */ ctrl = rxbufsize; if (rxout == (di->nrxd - 1)) ctrl |= CTRL_EOT; /* init the rx descriptor */ W_SM(&di->rxd[rxout].ctrl, BUS_SWAP32(ctrl)); W_SM(&di->rxd[rxout].addr, BUS_SWAP32(pa + di->dataoffset)); DMA_TRACE(("%s: dma_rxfill: ctrl %08x dataoffset: %08x\n", di->name, BUS_SWAP32(ctrl), BUS_SWAP32(pa + di->dataoffset))); rxout = NEXTRXD(rxout); } di->rxout = rxout; /* update the chip lastdscr pointer */ W_REG(&di->regs->rcvptr, I2B(rxout)); }