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); }
/* * 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; }
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); }
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)); } }
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); } }
/* * 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)); }
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; }
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); }
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
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); }
/* * 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); }