Example #1
0
/* copy a pkt buffer chain into a buffer */
uint
pktcopy(void *drv, void *p, uint offset, int len, uchar *buf)
{
	uint n, ret = 0;

	if (len < 0)
		len = 4096;	/* "infinite" */

	/* skip 'offset' bytes */
	for (; p && offset; p = PKTNEXT(drv, p)) {
		if (offset < (uint)PKTLEN(drv, p))
			break;
		offset -= PKTLEN(drv, p);
	}

	if (!p)
		return 0;

	/* copy the data */
	for (; p && len; p = PKTNEXT(drv, p)) {
		n = MIN((uint)PKTLEN(drv, p) - offset, (uint)len);
		bcopy(PKTDATA(drv, p) + offset, buf, n);
		buf += n;
		len -= n;
		ret += n;
		offset = 0;
	}

	return ret;
}
/* copy a buffer into a pkt buffer chain */
uint
pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
{
	uint n, ret = 0;

	/* skip 'offset' bytes */
	for (; p && offset; p = PKTNEXT(osh, p)) {
		if (offset < (uint)PKTLEN(osh, p))
			break;
		offset -= PKTLEN(osh, p);
	}

	if (!p)
		return 0;

	/* copy the data */
	for (; p && len; p = PKTNEXT(osh, p)) {
		n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
		bcopy(buf, PKTDATA(osh, p) + offset, n);
		buf += n;
		len -= n;
		ret += n;
		offset = 0;
	}

	return ret;
}
Example #3
0
/*
 * tp_tx_agg_p points to the header lbuf, tp_tx_agg_ptail points to the tail lbuf
 *
 * The TP agg format typically will be below
 *   | TP header(len) | subframe1 rpc_header | subframe1 data |
 *     | TP header(len) | subframe2 rpc_header | subframe2 data |
 *          ...
 *           | TP header(len) | subframeN rpc_header | subframeN data |
 * no padding
*/
static void
bcm_rpc_tp_tx_agg_append(rpc_tp_info_t * rpcb, rpc_buf_t *b)
{
	uint tp_len;

	tp_len = pkttotlen(rpcb->osh, b);

	if (rpcb->tp_tx_agg_p == NULL) {
		/* toc, set tail to last fragment */
		if (PKTNEXT(rpcb->osh, b)) {
			rpcb->tp_tx_agg_p = b;
			rpcb->tp_tx_agg_ptail = pktlast(rpcb->osh, b);
		} else
			rpcb->tp_tx_agg_p =  rpcb->tp_tx_agg_ptail = b;
	} else {
		/* chain the pkts at the end of current one */
		ASSERT(rpcb->tp_tx_agg_ptail != NULL);
		PKTSETNEXT(rpcb->osh, rpcb->tp_tx_agg_ptail, b);
		/* toc, set tail to last fragment */
		if (PKTNEXT(rpcb->osh, b)) {
			rpcb->tp_tx_agg_ptail = pktlast(rpcb->osh, b);
		} else
			rpcb->tp_tx_agg_ptail = b;

	}

	rpcb->tp_tx_agg_sframes++;
	rpcb->tp_tx_agg_bytes += tp_len;

	RPC_TP_AGG(("%s: tp_len %d tot %d, sframe %d\n", __FUNCTION__, tp_len,
	                rpcb->tp_tx_agg_bytes, rpcb->tp_tx_agg_sframes));
}
/* return the last buffer of chained pkt */
void *
pktlast(osl_t *osh, void *p)
{
	for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
		;

	return (p);
}
Example #5
0
/* return the last buffer of chained pkt */
void *
BCMROMFN(pktlast)(osl_t *osh, void *p)
{
	for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
		;

	return (p);
}
Example #6
0
int
bcm_rpc_buf_totlen_get(rpc_tp_info_t * rpc_th, rpc_buf_t* b)
{
	int totlen = 0;
	for (; b; b = (rpc_buf_t *) PKTNEXT(rpc_th->osh, b)) {
		totlen += PKTLEN(rpc_th->osh, b);
	}
	return totlen;
}
Example #7
0
/* return total length of buffer chain */
uint pkttotlen(void *drv, void *p)
{
	uint total;

	total = 0;
	for (; p; p = PKTNEXT(drv, p))
		total += PKTLEN(drv, p);
	return (total);
}
/* return total length of buffer chain */
uint
pkttotlen(osl_t *osh, void *p)
{
	uint total;

	total = 0;
	for (; p; p = PKTNEXT(osh, p))
		total += PKTLEN(osh, p);
	return (total);
}
/* count segments of a chained packet */
uint
pktsegcnt(osl_t *osh, void *p)
{
	uint cnt;

	for (cnt = 0; p; p = PKTNEXT(osh, p))
		cnt++;

	return cnt;
}
Example #10
0
/* copy data from one pkt buffer (chain) to another */
uint
pkt2pktcopy(osl_t *osh, void *p1, uint offs1, void *p2, uint offs2, int maxlen)
{
	uint8 *dp1, *dp2;
	uint len1, len2, copylen, totallen;

	for (; p1 && offs; p1 = PKTNEXT(osh, p1)) {
		if (offs1 < (uint)PKTLEN(osh, p1))
			break;
		offs1 -= PKTLEN(osh, p1);
	}
	for (; p2 && offs; p2 = PKTNEXT(osh, p2)) {
		if (offs2 < (uint)PKTLEN(osh, p2))
			break;
		offs2 -= PKTLEN(osh, p2);
	}

	/* Heck w/it, only need the above for now */
}
Example #11
0
/* count segments of a chained packet */
uint
BCMROMFN(pktsegcnt)(osl_t *osh, void *p)
{
	uint cnt;

	for (cnt = 0; p; p = PKTNEXT(osh, p))
		cnt++;

	return cnt;
}
Example #12
0
/* pretty hex print a pkt buffer chain */
void prpkt(char *msg, void *drv, void *p0)
{
	void *p;

	if (msg && (msg[0] != '\0'))
		printf("%s: ", msg);

	for (p = p0; p; p = PKTNEXT(drv, p))
		prhex(NULL, PKTDATA(drv, p), PKTLEN(drv, p));
}
Example #13
0
File: etc.c Project: cilynx/dd-wrt
uint
etc_totlen(etc_info_t *etc, void *p)
{
	uint total;

	total = 0;
	for (; p; p = PKTNEXT(etc->et, p))
		total += PKTLEN(etc->et, p);
	return (total);
}
Example #14
0
uint BCMFASTPATH
osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, hnddma_seg_map_t *dmah)
{
	int dir;

	ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
	dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;

#if defined(__ARM_ARCH_7A__) && defined(BCMDMASGLISTOSL)
	if (dmah != NULL) {
		int32 nsegs, i, totsegs = 0, totlen = 0;
		struct scatterlist *sg, _sg[16];
		struct sk_buff *skb;
		for (skb = (struct sk_buff *)p; skb != NULL; skb = PKTNEXT(osh, skb)) {
			sg = &_sg[totsegs];
			if (skb_is_nonlinear(skb)) {
				nsegs = skb_to_sgvec(skb, sg, 0, PKTLEN(osh, skb));
				ASSERT((nsegs > 0) && (nsegs <= 16));
				pci_map_sg(osh->pdev, sg, nsegs, dir);
			} else {
				nsegs = 1;
				sg->page_link = 0;
				sg_set_buf(sg, PKTDATA(osh, skb), PKTLEN(osh, skb));

				pci_map_single(osh->pdev, PKTDATA(osh, skb),
				    PKTISCTF(osh, skb) ? CTFMAPSZ : PKTLEN(osh, skb), dir);
			}
			totsegs += nsegs;
			totlen += PKTLEN(osh, skb);
		}
		dmah->nsegs = totsegs;
		dmah->origsize = totlen;
		for (i = 0, sg = _sg; i < totsegs; i++, sg++) {
			dmah->segs[i].addr = sg_phys(sg);
			dmah->segs[i].length = sg->length;
		}
		return dmah->segs[0].addr;
	}
#endif

	return (pci_map_single(osh->pdev, va, size, dir));
}
Example #15
0
void
bcm_rpc_tp_rx_from_dnglbus(rpc_tp_info_t *rpc_th, struct lbuf *lb)
{
	void *orig_p, *p;
	void *rpc_p, *rpc_prev;
	uint pktlen, tp_len, iter = 0;
	osl_t *osh;
	bool dbg_agg;
	uint dbg_data[16], i;	/* must fit host agg limit BCM_RPC_TP_HOST_AGG_MAX_SFRAME+1 */

	dbg_agg = FALSE;

	rpc_th->rx_cnt++;

	if (rpc_th->rx_pkt == NULL) {
		RPC_TP_ERR(("%s: no rpc rx fn, dropping\n", __FUNCTION__));
		rpc_th->rxdrop_cnt++;
		lb_free(lb);
		return;
	}
	orig_p = PKTFRMNATIVE(rpc_th->osh, lb);


	osh = rpc_th->osh;

	/* take ownership of the dnglbus packet chain
	 * since it will be freed by bcm_rpc_tp_buf_free()
	 */
	rpc_th->buf_cnt_inuse += pktsegcnt(rpc_th->osh, orig_p);

	dbg_data[0] = pktsegcnt(rpc_th->osh, orig_p);

	pktlen = PKTLEN(osh, orig_p);

	p = orig_p;

	/* while we have more data in the TP frame's packet chain,
	 *   create a packet chain(could be cloned) for the next RPC frame
	 *   then give it away to high layer for process(buffer not freed)
	 */
	while (p != NULL) {
		iter++;

		/* read TP_HDR(len of rpc frame) and pull the data pointer past the length word */
		if (pktlen >= BCM_RPC_TP_ENCAP_LEN) {
			ASSERT(((uint)PKTDATA(osh, p) & 0x3) == 0); /* ensure aligned word read */
			tp_len = ltoh32(*(uint32*)PKTDATA(osh, p));
			PKTPULL(osh, p, BCM_RPC_TP_ENCAP_LEN);
			pktlen -= BCM_RPC_TP_ENCAP_LEN;
		} else {
			/* error case: less data than the encapsulation size
			 * treat as an empty tp buffer, at end of current buffer
			 */
			tp_len = 0;
			pktlen = 0;

			rpc_th->tp_dngl_deagg_cnt_badsflen++;	/* bad sf len */
		}

		/* if TP header finished a buffer(rpc header in next chained buffer), open next */
		if (pktlen == 0) {
			void *next_p = PKTNEXT(osh, p);
			PKTSETNEXT(osh, p, NULL);
			rpc_th->buf_cnt_inuse--;
			PKTFREE(osh, p, FALSE);
			p = next_p;
			if (p)
				pktlen = PKTLEN(osh, p);
		}

		dbg_data[iter] = tp_len;

		if (tp_len < pktlen || dbg_agg) {
			dbg_agg = TRUE;
			RPC_TP_DEAGG(("DEAGG: [%d] p %p data %p pktlen %d tp_len %d\n",
				iter, p, PKTDATA(osh, p), pktlen, tp_len));
			rpc_th->tp_dngl_deagg_cnt_sf++;
			rpc_th->tp_dngl_deagg_cnt_bytes += tp_len;
		}

		/* empty TP buffer (special case: use tp_len to pad for some USB pktsize bugs) */
		if (tp_len == 0) {
			rpc_th->tp_dngl_deagg_cnt_pass++;
			continue;
		} else if (tp_len > 10000 ) {	/* something is wrong */
			/* print out msgs according to value of p  -- in case it is NULL */
			if (p != NULL) {
				RPC_TP_ERR(("DEAGG: iter %d, p(%p data %p pktlen %d)\n",
					iter, p, PKTDATA(osh, p), PKTLEN(osh, p)));
			} else {
				RPC_TP_ERR(("DEAGG: iter %d, p is NULL", iter));
			}
		}

		/* ========= For this TP subframe, find the end, build a chain, sendup ========= */

		/* RPC frame packet chain starts with this packet */
		rpc_prev = NULL;
		rpc_p = p;
		ASSERT(p != NULL);

		/* find the last frag in this rpc chain */
		while ((tp_len >= pktlen) && p) {
			if (dbg_agg)
				RPC_TP_DEAGG(("DEAGG: tp_len %d consumes p(%p pktlen %d)\n", tp_len,
					p, pktlen));
			rpc_prev = p;
			p = PKTNEXT(osh, p);
			tp_len -= pktlen;

			if (p != NULL) {
				pktlen = PKTLEN(osh, p);
			} else {
				if (tp_len != 0) {
					uint totlen, seg;
					totlen = pkttotlen(osh, rpc_p);
					seg = pktsegcnt(rpc_th->osh, rpc_p);

					RPC_TP_ERR(("DEAGG, toss[%d], orig_p %p segcnt %d",
					       iter, orig_p, dbg_data[0]));
					RPC_TP_ERR(("DEAGG,rpc_p %p totlen %d pktl %d tp_len %d\n",
					       rpc_p, totlen, pktlen, tp_len));
					for (i = 1; i <= iter; i++)
						RPC_TP_ERR(("tplen[%d] = %d  ", i, dbg_data[i]));
					RPC_TP_ERR(("\n"));
					p = rpc_p;
					while (p != NULL) {
						RPC_TP_ERR(("this seg len %d\n", PKTLEN(osh, p)));
						p = PKTNEXT(osh, p);
					}

					rpc_th->buf_cnt_inuse -= seg;
					PKTFREE(osh, rpc_p, FALSE);
					rpc_th->tp_dngl_deagg_cnt_badfmt++;

					/* big hammer to recover USB
					 * extern void dngl_reboot(void); dngl_reboot();
					 */
					goto end;
				}
				pktlen = 0;
				break;
			}
		}

		/* fix up the last frag */
		if (tp_len == 0) {
			/* if the whole RPC buffer chain ended at the end of the prev TP buffer,
			 *    end the RPC buffer chain. we are done
			 */
			if (dbg_agg)
				RPC_TP_DEAGG(("DEAGG: END rpc chain p %p len %d\n\n", rpc_prev,
					pktlen));

			PKTSETNEXT(osh, rpc_prev, NULL);
			if (iter > 1) {
				rpc_th->tp_dngl_deagg_cnt_chain++;
				RPC_TP_DEAGG(("this frag %d totlen %d\n", pktlen,
					pkttotlen(osh, orig_p)));
			}

		} else {
			/* if pktlen has more bytes than tp_len, another tp frame must follow
			 *   create a clone of the sub-range of the current TP buffer covered
			 *   by the RPC buffer, attach to the end of the RPC buffer chain
			 *   (cut off the original chain link)
			 *   continue chain looping(p != NULL)
			 */
			void *new_p;
			ASSERT(p != NULL);

			RPC_TP_DEAGG(("DEAGG: cloning %d bytes out of p(%p data %p) len %d\n",
				tp_len, p, PKTDATA(osh, p), pktlen));

			new_p = osl_pktclone(osh, p, 0, tp_len);
			rpc_th->buf_cnt_inuse++;
			rpc_th->tp_dngl_deagg_cnt_clone++;

			RPC_TP_DEAGG(("DEAGG: after clone, newp(%p data %p pktlen %d)\n",
				new_p, PKTDATA(osh, new_p), PKTLEN(osh, new_p)));

			if (rpc_prev) {
				RPC_TP_DEAGG(("DEAGG: chaining: %p->%p(clone)\n", rpc_prev,
					new_p));
				PKTSETNEXT(osh, rpc_prev, new_p);
			} else {
				RPC_TP_DEAGG(("DEAGG: clone %p is a complete rpc pkt\n", new_p));
				rpc_p = new_p;
			}

			PKTPULL(osh, p, tp_len);
			pktlen -= tp_len;
			RPC_TP_DEAGG(("DEAGG: remainder packet p %p data %p pktlen %d\n",
				p, PKTDATA(osh, p), PKTLEN(osh, p)));
		}

		/* !! send up */
		(rpc_th->rx_pkt)(rpc_th->rx_context, rpc_p);
	}

end:
	ASSERT(p == NULL);
}
Example #16
0
File: hnddma.c Project: ariavie/bcm
/*
 * Just like above except go through the extra effort of splitting
 * buffers that cross 4Kbyte boundaries into multiple tx descriptors.
 */
int
dma_tx(dma_info_t *di, void *p0, uint32 coreflags)
{
	void *p, *next;
	uchar *data;
	uint plen, len;
	uchar *page, *start, *end;
	uint txout;
	uint32 ctrl;
	uint32 pa;

	DMA_TRACE(("%s: dma_tx\n", di->name));

	txout = di->txout;
	ctrl = 0;

	/*
	 * Walk the chain of packet buffers
	 * splitting those that cross 4 Kbyte boundaries
	 * allocating and initializing transmit descriptor entries.
	 */
	for (p = p0; p; p = next) {
		data = PKTDATA(di->drv, p);
		plen = PKTLEN(di->drv, p);
		next = PKTNEXT(di->drv, p);

		/* PR988 - skip zero length buffers */
		if (plen == 0)
			continue;

		for (page = (uchar*)PAGEBASE(data);
			page <= (uchar*)PAGEBASE(data + plen - 1);
			page += PAGESZ) {

			/* return nonzero if out of tx descriptors */
			if (NEXTTXD(txout) == di->txin)
				goto outoftxd;

			start = (page == (uchar*)PAGEBASE(data))?  data: page;
			end = (page == (uchar*)PAGEBASE(data + plen))?
				(data + plen): (page + PAGESZ);
			len = end - start;

			/* build the descriptor control value */
			ctrl = len & CTRL_BC_MASK;

			/* PR3697: Descriptor flags are not ignored for descriptors where SOF is clear */
			ctrl |= coreflags;

			if ((p == p0) && (start == data))
				ctrl |= CTRL_SOF;
			if ((next == NULL) && (end == (data + plen)))
				ctrl |= (CTRL_IOC | CTRL_EOF);
			if (txout == (di->ntxd - 1))
				ctrl |= CTRL_EOT;

			/* get physical address of buffer start */
			pa = (uint32) DMA_MAP(di->dev, start, len, DMA_TX, p);

			/* init the tx descriptor */
			W_SM(&di->txd[txout].ctrl, BUS_SWAP32(ctrl));
			W_SM(&di->txd[txout].addr, BUS_SWAP32(pa + di->dataoffset));

			ASSERT(di->txp[txout] == NULL);

			txout = NEXTTXD(txout);
		}
	}

	/* if last txd eof not set, fix it */
	if (!(ctrl & CTRL_EOF))
		W_SM(&di->txd[PREVTXD(txout)].ctrl, BUS_SWAP32(ctrl | CTRL_IOC | CTRL_EOF));

	/* save the packet */
	di->txp[di->txout] = p0;

	/* bump the tx descriptor index */
	di->txout = txout;

	/* kick the chip */
	W_REG(&di->regs->xmtptr, I2B(txout));

	/* tx flow control */
	di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;

	return (0);

outoftxd:
	DMA_ERROR(("%s: dma_tx: out of txds\n", di->name));
	PKTFREE(di->drv, p0, TRUE);
	di->txavail = 0;
	di->hnddma.txnobuf++;
	return (-1);
}