Exemplo n.º 1
0
static int
write_smt_entry(struct adapter *sc, int idx)
{
	struct port_info *pi = &sc->port[idx];
	struct cpl_smt_write_req *req;
	struct mbuf *m;

	m = M_GETHDR_OFLD(0, CPL_PRIORITY_CONTROL, req);
	if (m == NULL) {
		log(LOG_ERR, "%s: no mbuf, can't write SMT entry for %d\n",
		    __func__, idx);
		return (ENOMEM);
	}

	req->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
	req->mtu_idx = NMTUS - 1;  /* should be 0 but there's a T3 bug */
	req->iff = idx;
	memset(req->src_mac1, 0, sizeof(req->src_mac1));
	memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN);

	t3_offload_tx(sc, m);

	return (0);
}
Exemplo n.º 2
0
/*
 * Set up an L2T entry and send any packets waiting in the arp queue.  The
 * supplied skb is used for the CPL_L2T_WRITE_REQ.  Must be called with the
 * entry locked.
 */
static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb,
				  struct l2t_entry *e)
{
	struct cpl_l2t_write_req *req;

	if (!skb) {
		skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
		if (!skb)
			return -ENOMEM;
	}

	req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx));
	req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) |
			    V_L2T_W_VLAN(e->vlan & VLAN_VID_MASK) |
			    V_L2T_W_PRIO(vlan_prio(e)));
	memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac));
	memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac));
	skb->priority = CPL_PRIORITY_CONTROL;
	cxgb3_ofld_send(dev, skb);
	while (e->arpq_head) {
		skb = e->arpq_head;
		e->arpq_head = skb->next;
		skb->next = NULL;
		cxgb3_ofld_send(dev, skb);
	}
	e->arpq_tail = NULL;
	e->state = L2T_STATE_VALID;

	return 0;
}
Exemplo n.º 3
0
static inline void
write_tx_wr(void *dst, struct toepcb *toep, unsigned int immdlen,
    unsigned int plen, uint8_t credits, int more_to_come)
{
	struct fw_ofld_tx_data_wr *txwr = dst;
	int shove = !more_to_come;
	int compl = 1;

	/*
	 * We always request completion notifications from the firmware.  The
	 * only exception is when we know we'll get more data to send shortly
	 * and that we'll have some tx credits remaining to transmit that data.
	 */
	if (more_to_come && toep->tx_credits - credits >= MIN_OFLD_TX_CREDITS)
		compl = 0;

	txwr->op_to_immdlen = htobe32(V_WR_OP(FW_OFLD_TX_DATA_WR) |
	    V_FW_WR_COMPL(compl) | V_FW_WR_IMMDLEN(immdlen));
	txwr->flowid_len16 = htobe32(V_FW_WR_FLOWID(toep->tid) |
	    V_FW_WR_LEN16(credits));
	txwr->tunnel_to_proxy =
	    htobe32(V_FW_OFLD_TX_DATA_WR_ULPMODE(toep->ulp_mode) |
		V_FW_OFLD_TX_DATA_WR_URGENT(0) |	/* XXX */
		V_FW_OFLD_TX_DATA_WR_SHOVE(shove));
	txwr->plen = htobe32(plen);
}
Exemplo n.º 4
0
static inline void
write_tx_wr(void *dst, struct toepcb *toep, unsigned int immdlen,
    unsigned int plen, uint8_t credits, int shove, int ulp_submode, int txalign)
{
	struct fw_ofld_tx_data_wr *txwr = dst;

	txwr->op_to_immdlen = htobe32(V_WR_OP(FW_OFLD_TX_DATA_WR) |
	    V_FW_WR_IMMDLEN(immdlen));
	txwr->flowid_len16 = htobe32(V_FW_WR_FLOWID(toep->tid) |
	    V_FW_WR_LEN16(credits));
	txwr->lsodisable_to_flags = htobe32(V_TX_ULP_MODE(toep->ulp_mode) |
	    V_TX_ULP_SUBMODE(ulp_submode) | V_TX_URG(0) | V_TX_SHOVE(shove));
	txwr->plen = htobe32(plen);

	if (txalign > 0) {
		struct tcpcb *tp = intotcpcb(toep->inp);

		if (plen < 2 * tp->t_maxseg || is_10G_port(toep->vi->pi))
			txwr->lsodisable_to_flags |=
			    htobe32(F_FW_OFLD_TX_DATA_WR_LSODISABLE);
		else
			txwr->lsodisable_to_flags |=
			    htobe32(F_FW_OFLD_TX_DATA_WR_ALIGNPLD |
				(tp->t_flags & TF_NODELAY ? 0 :
				F_FW_OFLD_TX_DATA_WR_ALIGNPLDSHOVE));
	}
}
Exemplo n.º 5
0
static int
do_abort_req_rss(struct t3cdev *dev, struct mbuf *m)
{
	union opcode_tid *p = cplhdr(m);
	unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
	struct toe_tid_entry *toe_tid;

	toe_tid = lookup_tid(&(T3C_DATA (dev))->tid_maps, hwtid);
	if (toe_tid->ctx && toe_tid->client->handlers &&
		toe_tid->client->handlers[p->opcode]) {
		return toe_tid->client->handlers[p->opcode]
						(dev, m, toe_tid->ctx);
	} else {
		struct cpl_abort_req_rss *req = cplhdr(m);
		struct cpl_abort_rpl *rpl;
		
		struct mbuf *m = m_get(M_NOWAIT, MT_DATA);
		if (!m) {
			log(LOG_NOTICE, "do_abort_req_rss: couldn't get mbuf!\n");
			goto out;
		}

		m_set_priority(m, CPL_PRIORITY_DATA);
		rpl = cplhdr(m);
		rpl->wr.wr_hi = 
			htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));
		rpl->wr.wr_lo = htonl(V_WR_TID(GET_TID(req)));
		OPCODE_TID(rpl) =
			htonl(MK_OPCODE_TID(CPL_ABORT_RPL, GET_TID(req)));
		rpl->cmd = req->status;
		cxgb_ofld_send(dev, m);
 out:
		return (CPL_RET_BUF_DONE);
	}
}
Exemplo n.º 6
0
/*
 * Populate a TID_RELEASE WR.  The mbuf must be already propely sized.
 */
static inline void
mk_tid_release(struct mbuf *m, unsigned int tid)
{
	struct cpl_tid_release *req;

	m_set_priority(m, CPL_PRIORITY_SETUP);
	req = mtod(m, struct cpl_tid_release *);
	m->m_pkthdr.len = m->m_len = sizeof(*req);
	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid));
}
Exemplo n.º 7
0
static void release_tid(struct t3cdev *tdev, u32 hwtid, struct sk_buff *skb)
{
	struct cpl_tid_release *req;

	skb = get_skb(skb, sizeof *req, GFP_KERNEL);
	if (!skb)
		return;
	req = (struct cpl_tid_release *) skb_put(skb, sizeof(*req));
	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, hwtid));
	skb->priority = CPL_PRIORITY_SETUP;
	iwch_cxgb3_ofld_send(tdev, skb);
	return;
}
Exemplo n.º 8
0
static inline void
write_tx_wr(void *dst, struct toepcb *toep, unsigned int immdlen,
    unsigned int plen, uint8_t credits, int shove)
{
	struct fw_ofld_tx_data_wr *txwr = dst;

	txwr->op_to_immdlen = htobe32(V_WR_OP(FW_OFLD_TX_DATA_WR) |
	    V_FW_WR_IMMDLEN(immdlen));
	txwr->flowid_len16 = htobe32(V_FW_WR_FLOWID(toep->tid) |
	    V_FW_WR_LEN16(credits));
	txwr->lsodisable_to_proxy =
	    htobe32(V_FW_OFLD_TX_DATA_WR_ULPMODE(toep->ulp_mode) |
		V_FW_OFLD_TX_DATA_WR_URGENT(0) |	/* XXX */
		V_FW_OFLD_TX_DATA_WR_SHOVE(shove));
	txwr->plen = htobe32(plen);
}
Exemplo n.º 9
0
static inline void
write_tx_wr(void *dst, struct toepcb *toep, unsigned int immdlen,
    unsigned int plen, uint8_t credits, int shove, int ulp_mode, int txalign)
{
	struct fw_ofld_tx_data_wr *txwr = dst;
	unsigned int wr_ulp_mode;

	txwr->op_to_immdlen = htobe32(V_WR_OP(FW_OFLD_TX_DATA_WR) |
	    V_FW_WR_IMMDLEN(immdlen));
	txwr->flowid_len16 = htobe32(V_FW_WR_FLOWID(toep->tid) |
	    V_FW_WR_LEN16(credits));

	/* for iscsi, the mode & submode setting is per-packet */
	if (toep->ulp_mode == ULP_MODE_ISCSI)
		wr_ulp_mode = V_FW_OFLD_TX_DATA_WR_ULPMODE(ulp_mode >> 4) |
			V_FW_OFLD_TX_DATA_WR_ULPSUBMODE(ulp_mode & 3);
	else
Exemplo n.º 10
0
int iwch_resume_tid(struct iwch_ep *ep)
{
	struct cpl_set_tcb_field *req;
	struct sk_buff *skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);

	if (!skb)
		return -ENOMEM;
	req = (struct cpl_set_tcb_field *) skb_put(skb, sizeof(*req));
	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
	req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid));
	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, ep->hwtid));
	req->reply = 0;
	req->cpu_idx = 0;
	req->word = htons(W_TCB_RX_QUIESCE);
	req->mask = cpu_to_be64(1ULL << S_TCB_RX_QUIESCE);
	req->val = 0;

	skb->priority = CPL_PRIORITY_DATA;
	return iwch_cxgb3_ofld_send(ep->com.tdev, skb);
}
Exemplo n.º 11
0
/*
 * Set up an L2T entry and send any packets waiting in the arp queue.  Must be
 * called with the entry locked.
 */
static int
setup_l2e_send_pending(struct adapter *sc, struct l2t_entry *e)
{
	struct mbuf *m;
	struct cpl_l2t_write_req *req;
	struct port_info *pi = &sc->port[e->smt_idx];	/* smt_idx is port_id */

	mtx_assert(&e->lock, MA_OWNED);

	m = M_GETHDR_OFLD(pi->first_qset, CPL_PRIORITY_CONTROL, req);
	if (m == NULL) {
		log(LOG_ERR, "%s: no mbuf, can't setup L2 entry at index %d\n",
		    __func__, e->idx);
		return (ENOMEM);
	}

	req->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx));
	req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) |
	    V_L2T_W_VLAN(e->vlan & EVL_VLID_MASK) |
	    V_L2T_W_PRIO(EVL_PRIOFTAG(e->vlan)));
	memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac));

	t3_offload_tx(sc, m);

	/*
	 * XXX: We used pi->first_qset to send the L2T_WRITE_REQ.  If any mbuf
	 * on the arpq is going out via another queue set associated with the
	 * port then it has a bad race with the L2T_WRITE_REQ.  Ideally we
	 * should wait till the reply to the write before draining the arpq.
	 */
	while (e->arpq_head) {
		m = e->arpq_head;
		e->arpq_head = m->m_next;
		m->m_next = NULL;
		t3_offload_tx(sc, m);
	}
	e->arpq_tail = NULL;

	return (0);
}