Пример #1
0
static int
bcm_rpc_tp_tx_agg(rpc_tp_info_t *rpcb, rpc_buf_t *b)
{
	uint totlen;
	uint pktlen;
	int err = 0;

	ASSERT(rpcb->tp_tx_aggregation);

	pktlen = pkttotlen(rpcb->osh, b);
	totlen = pktlen + rpcb->tp_tx_agg_bytes;

	if ((totlen > rpcb->tp_tx_agg_bytes_max) ||
		(rpcb->tp_tx_agg_sframes + 1 > rpcb->tp_tx_agg_sframes_limit)) {

		RPC_TP_AGG(("%s: terminte TP agg for txbyte %d or txframe %d\n", __FUNCTION__,
			rpcb->tp_tx_agg_bytes_max, rpcb->tp_tx_agg_sframes_limit));

		/* release current agg, continue with new agg */
		err = bcm_rpc_tp_tx_agg_release(rpcb);
	}

	bcm_rpc_tp_tx_agg_append(rpcb, b);

	/* if the new frag is also already over the agg limit, release it */
	if (pktlen >= rpcb->tp_tx_agg_bytes_max) {
		int new_err;
		new_err = bcm_rpc_tp_tx_agg_release(rpcb);
		if (!err)
			err = new_err;
	}

	return err;
}
Пример #2
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));
}
Пример #3
0
static void
bcm_rpc_tp_tx_encap(rpc_tp_info_t * rpcb, rpc_buf_t *b)
{
	uint32 *tp_lenp;
	uint32 rpc_len;

	rpc_len = pkttotlen(rpcb->osh, b);
	tp_lenp = (uint32*)bcm_rpc_buf_push(rpcb, b, BCM_RPC_TP_ENCAP_LEN);
	*tp_lenp = htol32(rpc_len);
}
Пример #4
0
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);
}
Пример #5
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);
}