162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright(c) 2020 Intel Corporation. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/* 862306a36Sopenharmony_ci * This file contains HFI1 support for IPOIB SDMA functionality 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/log2.h> 1262306a36Sopenharmony_ci#include <linux/circ_buf.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "sdma.h" 1562306a36Sopenharmony_ci#include "verbs.h" 1662306a36Sopenharmony_ci#include "trace_ibhdrs.h" 1762306a36Sopenharmony_ci#include "ipoib.h" 1862306a36Sopenharmony_ci#include "trace_tx.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* Add a convenience helper */ 2162306a36Sopenharmony_ci#define CIRC_ADD(val, add, size) (((val) + (add)) & ((size) - 1)) 2262306a36Sopenharmony_ci#define CIRC_NEXT(val, size) CIRC_ADD(val, 1, size) 2362306a36Sopenharmony_ci#define CIRC_PREV(val, size) CIRC_ADD(val, -1, size) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct ipoib_txparms { 2662306a36Sopenharmony_ci struct hfi1_devdata *dd; 2762306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr; 2862306a36Sopenharmony_ci struct hfi1_ibport *ibp; 2962306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq; 3062306a36Sopenharmony_ci union hfi1_ipoib_flow flow; 3162306a36Sopenharmony_ci u32 dqpn; 3262306a36Sopenharmony_ci u8 hdr_dwords; 3362306a36Sopenharmony_ci u8 entropy; 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic struct ipoib_txreq * 3762306a36Sopenharmony_cihfi1_txreq_from_idx(struct hfi1_ipoib_circ_buf *r, u32 idx) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci return (struct ipoib_txreq *)(r->items + (idx << r->shift)); 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic u32 hfi1_ipoib_txreqs(const u64 sent, const u64 completed) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci return sent - completed; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic u64 hfi1_ipoib_used(struct hfi1_ipoib_txq *txq) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci return hfi1_ipoib_txreqs(txq->tx_ring.sent_txreqs, 5062306a36Sopenharmony_ci txq->tx_ring.complete_txreqs); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic void hfi1_ipoib_stop_txq(struct hfi1_ipoib_txq *txq) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci trace_hfi1_txq_stop(txq); 5662306a36Sopenharmony_ci if (atomic_inc_return(&txq->tx_ring.stops) == 1) 5762306a36Sopenharmony_ci netif_stop_subqueue(txq->priv->netdev, txq->q_idx); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic void hfi1_ipoib_wake_txq(struct hfi1_ipoib_txq *txq) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci trace_hfi1_txq_wake(txq); 6362306a36Sopenharmony_ci if (atomic_dec_and_test(&txq->tx_ring.stops)) 6462306a36Sopenharmony_ci netif_wake_subqueue(txq->priv->netdev, txq->q_idx); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic uint hfi1_ipoib_ring_hwat(struct hfi1_ipoib_txq *txq) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci return min_t(uint, txq->priv->netdev->tx_queue_len, 7062306a36Sopenharmony_ci txq->tx_ring.max_items - 1); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic uint hfi1_ipoib_ring_lwat(struct hfi1_ipoib_txq *txq) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci return min_t(uint, txq->priv->netdev->tx_queue_len, 7662306a36Sopenharmony_ci txq->tx_ring.max_items) >> 1; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void hfi1_ipoib_check_queue_depth(struct hfi1_ipoib_txq *txq) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci ++txq->tx_ring.sent_txreqs; 8262306a36Sopenharmony_ci if (hfi1_ipoib_used(txq) >= hfi1_ipoib_ring_hwat(txq) && 8362306a36Sopenharmony_ci !atomic_xchg(&txq->tx_ring.ring_full, 1)) { 8462306a36Sopenharmony_ci trace_hfi1_txq_full(txq); 8562306a36Sopenharmony_ci hfi1_ipoib_stop_txq(txq); 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void hfi1_ipoib_check_queue_stopped(struct hfi1_ipoib_txq *txq) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct net_device *dev = txq->priv->netdev; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* If shutting down just return as queue state is irrelevant */ 9462306a36Sopenharmony_ci if (unlikely(dev->reg_state != NETREG_REGISTERED)) 9562306a36Sopenharmony_ci return; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* 9862306a36Sopenharmony_ci * When the queue has been drained to less than half full it will be 9962306a36Sopenharmony_ci * restarted. 10062306a36Sopenharmony_ci * The size of the txreq ring is fixed at initialization. 10162306a36Sopenharmony_ci * The tx queue len can be adjusted upward while the interface is 10262306a36Sopenharmony_ci * running. 10362306a36Sopenharmony_ci * The tx queue len can be large enough to overflow the txreq_ring. 10462306a36Sopenharmony_ci * Use the minimum of the current tx_queue_len or the rings max txreqs 10562306a36Sopenharmony_ci * to protect against ring overflow. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ci if (hfi1_ipoib_used(txq) < hfi1_ipoib_ring_lwat(txq) && 10862306a36Sopenharmony_ci atomic_xchg(&txq->tx_ring.ring_full, 0)) { 10962306a36Sopenharmony_ci trace_hfi1_txq_xmit_unstopped(txq); 11062306a36Sopenharmony_ci hfi1_ipoib_wake_txq(txq); 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic void hfi1_ipoib_free_tx(struct ipoib_txreq *tx, int budget) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = tx->txq->priv; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (likely(!tx->sdma_status)) { 11962306a36Sopenharmony_ci dev_sw_netstats_tx_add(priv->netdev, 1, tx->skb->len); 12062306a36Sopenharmony_ci } else { 12162306a36Sopenharmony_ci ++priv->netdev->stats.tx_errors; 12262306a36Sopenharmony_ci dd_dev_warn(priv->dd, 12362306a36Sopenharmony_ci "%s: Status = 0x%x pbc 0x%llx txq = %d sde = %d\n", 12462306a36Sopenharmony_ci __func__, tx->sdma_status, 12562306a36Sopenharmony_ci le64_to_cpu(tx->sdma_hdr->pbc), tx->txq->q_idx, 12662306a36Sopenharmony_ci tx->txq->sde->this_idx); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci napi_consume_skb(tx->skb, budget); 13062306a36Sopenharmony_ci tx->skb = NULL; 13162306a36Sopenharmony_ci sdma_txclean(priv->dd, &tx->txreq); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic void hfi1_ipoib_drain_tx_ring(struct hfi1_ipoib_txq *txq) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct hfi1_ipoib_circ_buf *tx_ring = &txq->tx_ring; 13762306a36Sopenharmony_ci int i; 13862306a36Sopenharmony_ci struct ipoib_txreq *tx; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci for (i = 0; i < tx_ring->max_items; i++) { 14162306a36Sopenharmony_ci tx = hfi1_txreq_from_idx(tx_ring, i); 14262306a36Sopenharmony_ci tx->complete = 0; 14362306a36Sopenharmony_ci dev_kfree_skb_any(tx->skb); 14462306a36Sopenharmony_ci tx->skb = NULL; 14562306a36Sopenharmony_ci sdma_txclean(txq->priv->dd, &tx->txreq); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci tx_ring->head = 0; 14862306a36Sopenharmony_ci tx_ring->tail = 0; 14962306a36Sopenharmony_ci tx_ring->complete_txreqs = 0; 15062306a36Sopenharmony_ci tx_ring->sent_txreqs = 0; 15162306a36Sopenharmony_ci tx_ring->avail = hfi1_ipoib_ring_hwat(txq); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic int hfi1_ipoib_poll_tx_ring(struct napi_struct *napi, int budget) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq = 15762306a36Sopenharmony_ci container_of(napi, struct hfi1_ipoib_txq, napi); 15862306a36Sopenharmony_ci struct hfi1_ipoib_circ_buf *tx_ring = &txq->tx_ring; 15962306a36Sopenharmony_ci u32 head = tx_ring->head; 16062306a36Sopenharmony_ci u32 max_tx = tx_ring->max_items; 16162306a36Sopenharmony_ci int work_done; 16262306a36Sopenharmony_ci struct ipoib_txreq *tx = hfi1_txreq_from_idx(tx_ring, head); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci trace_hfi1_txq_poll(txq); 16562306a36Sopenharmony_ci for (work_done = 0; work_done < budget; work_done++) { 16662306a36Sopenharmony_ci /* See hfi1_ipoib_sdma_complete() */ 16762306a36Sopenharmony_ci if (!smp_load_acquire(&tx->complete)) 16862306a36Sopenharmony_ci break; 16962306a36Sopenharmony_ci tx->complete = 0; 17062306a36Sopenharmony_ci trace_hfi1_tx_produce(tx, head); 17162306a36Sopenharmony_ci hfi1_ipoib_free_tx(tx, budget); 17262306a36Sopenharmony_ci head = CIRC_NEXT(head, max_tx); 17362306a36Sopenharmony_ci tx = hfi1_txreq_from_idx(tx_ring, head); 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci tx_ring->complete_txreqs += work_done; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* Finished freeing tx items so store the head value. */ 17862306a36Sopenharmony_ci smp_store_release(&tx_ring->head, head); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci hfi1_ipoib_check_queue_stopped(txq); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (work_done < budget) 18362306a36Sopenharmony_ci napi_complete_done(napi, work_done); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return work_done; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic void hfi1_ipoib_sdma_complete(struct sdma_txreq *txreq, int status) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct ipoib_txreq *tx = container_of(txreq, struct ipoib_txreq, txreq); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci trace_hfi1_txq_complete(tx->txq); 19362306a36Sopenharmony_ci tx->sdma_status = status; 19462306a36Sopenharmony_ci /* see hfi1_ipoib_poll_tx_ring */ 19562306a36Sopenharmony_ci smp_store_release(&tx->complete, 1); 19662306a36Sopenharmony_ci napi_schedule_irqoff(&tx->txq->napi); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic int hfi1_ipoib_build_ulp_payload(struct ipoib_txreq *tx, 20062306a36Sopenharmony_ci struct ipoib_txparms *txp) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct hfi1_devdata *dd = txp->dd; 20362306a36Sopenharmony_ci struct sdma_txreq *txreq = &tx->txreq; 20462306a36Sopenharmony_ci struct sk_buff *skb = tx->skb; 20562306a36Sopenharmony_ci int ret = 0; 20662306a36Sopenharmony_ci int i; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (skb_headlen(skb)) { 20962306a36Sopenharmony_ci ret = sdma_txadd_kvaddr(dd, txreq, skb->data, skb_headlen(skb)); 21062306a36Sopenharmony_ci if (unlikely(ret)) 21162306a36Sopenharmony_ci return ret; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 21562306a36Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ret = sdma_txadd_page(dd, 21862306a36Sopenharmony_ci txreq, 21962306a36Sopenharmony_ci skb_frag_page(frag), 22062306a36Sopenharmony_ci frag->bv_offset, 22162306a36Sopenharmony_ci skb_frag_size(frag), 22262306a36Sopenharmony_ci NULL, NULL, NULL); 22362306a36Sopenharmony_ci if (unlikely(ret)) 22462306a36Sopenharmony_ci break; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return ret; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic int hfi1_ipoib_build_tx_desc(struct ipoib_txreq *tx, 23162306a36Sopenharmony_ci struct ipoib_txparms *txp) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct hfi1_devdata *dd = txp->dd; 23462306a36Sopenharmony_ci struct sdma_txreq *txreq = &tx->txreq; 23562306a36Sopenharmony_ci struct hfi1_sdma_header *sdma_hdr = tx->sdma_hdr; 23662306a36Sopenharmony_ci u16 pkt_bytes = 23762306a36Sopenharmony_ci sizeof(sdma_hdr->pbc) + (txp->hdr_dwords << 2) + tx->skb->len; 23862306a36Sopenharmony_ci int ret; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci ret = sdma_txinit(txreq, 0, pkt_bytes, hfi1_ipoib_sdma_complete); 24162306a36Sopenharmony_ci if (unlikely(ret)) 24262306a36Sopenharmony_ci return ret; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* add pbc + headers */ 24562306a36Sopenharmony_ci ret = sdma_txadd_kvaddr(dd, 24662306a36Sopenharmony_ci txreq, 24762306a36Sopenharmony_ci sdma_hdr, 24862306a36Sopenharmony_ci sizeof(sdma_hdr->pbc) + (txp->hdr_dwords << 2)); 24962306a36Sopenharmony_ci if (unlikely(ret)) 25062306a36Sopenharmony_ci return ret; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* add the ulp payload */ 25362306a36Sopenharmony_ci return hfi1_ipoib_build_ulp_payload(tx, txp); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic void hfi1_ipoib_build_ib_tx_headers(struct ipoib_txreq *tx, 25762306a36Sopenharmony_ci struct ipoib_txparms *txp) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = tx->txq->priv; 26062306a36Sopenharmony_ci struct hfi1_sdma_header *sdma_hdr = tx->sdma_hdr; 26162306a36Sopenharmony_ci struct sk_buff *skb = tx->skb; 26262306a36Sopenharmony_ci struct hfi1_pportdata *ppd = ppd_from_ibp(txp->ibp); 26362306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr = txp->ah_attr; 26462306a36Sopenharmony_ci struct ib_other_headers *ohdr; 26562306a36Sopenharmony_ci struct ib_grh *grh; 26662306a36Sopenharmony_ci u16 dwords; 26762306a36Sopenharmony_ci u16 slid; 26862306a36Sopenharmony_ci u16 dlid; 26962306a36Sopenharmony_ci u16 lrh0; 27062306a36Sopenharmony_ci u32 bth0; 27162306a36Sopenharmony_ci u32 sqpn = (u32)(priv->netdev->dev_addr[1] << 16 | 27262306a36Sopenharmony_ci priv->netdev->dev_addr[2] << 8 | 27362306a36Sopenharmony_ci priv->netdev->dev_addr[3]); 27462306a36Sopenharmony_ci u16 payload_dwords; 27562306a36Sopenharmony_ci u8 pad_cnt; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci pad_cnt = -skb->len & 3; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* Includes ICRC */ 28062306a36Sopenharmony_ci payload_dwords = ((skb->len + pad_cnt) >> 2) + SIZE_OF_CRC; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* header size in dwords LRH+BTH+DETH = (8+12+8)/4. */ 28362306a36Sopenharmony_ci txp->hdr_dwords = 7; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH) { 28662306a36Sopenharmony_ci grh = &sdma_hdr->hdr.ibh.u.l.grh; 28762306a36Sopenharmony_ci txp->hdr_dwords += 28862306a36Sopenharmony_ci hfi1_make_grh(txp->ibp, 28962306a36Sopenharmony_ci grh, 29062306a36Sopenharmony_ci rdma_ah_read_grh(ah_attr), 29162306a36Sopenharmony_ci txp->hdr_dwords - LRH_9B_DWORDS, 29262306a36Sopenharmony_ci payload_dwords); 29362306a36Sopenharmony_ci lrh0 = HFI1_LRH_GRH; 29462306a36Sopenharmony_ci ohdr = &sdma_hdr->hdr.ibh.u.l.oth; 29562306a36Sopenharmony_ci } else { 29662306a36Sopenharmony_ci lrh0 = HFI1_LRH_BTH; 29762306a36Sopenharmony_ci ohdr = &sdma_hdr->hdr.ibh.u.oth; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci lrh0 |= (rdma_ah_get_sl(ah_attr) & 0xf) << 4; 30162306a36Sopenharmony_ci lrh0 |= (txp->flow.sc5 & 0xf) << 12; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci dlid = opa_get_lid(rdma_ah_get_dlid(ah_attr), 9B); 30462306a36Sopenharmony_ci if (dlid == be16_to_cpu(IB_LID_PERMISSIVE)) { 30562306a36Sopenharmony_ci slid = be16_to_cpu(IB_LID_PERMISSIVE); 30662306a36Sopenharmony_ci } else { 30762306a36Sopenharmony_ci u16 lid = (u16)ppd->lid; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (lid) { 31062306a36Sopenharmony_ci lid |= rdma_ah_get_path_bits(ah_attr) & 31162306a36Sopenharmony_ci ((1 << ppd->lmc) - 1); 31262306a36Sopenharmony_ci slid = lid; 31362306a36Sopenharmony_ci } else { 31462306a36Sopenharmony_ci slid = be16_to_cpu(IB_LID_PERMISSIVE); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* Includes ICRC */ 31962306a36Sopenharmony_ci dwords = txp->hdr_dwords + payload_dwords; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* Build the lrh */ 32262306a36Sopenharmony_ci sdma_hdr->hdr.hdr_type = HFI1_PKT_TYPE_9B; 32362306a36Sopenharmony_ci hfi1_make_ib_hdr(&sdma_hdr->hdr.ibh, lrh0, dwords, dlid, slid); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* Build the bth */ 32662306a36Sopenharmony_ci bth0 = (IB_OPCODE_UD_SEND_ONLY << 24) | (pad_cnt << 20) | priv->pkey; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci ohdr->bth[0] = cpu_to_be32(bth0); 32962306a36Sopenharmony_ci ohdr->bth[1] = cpu_to_be32(txp->dqpn); 33062306a36Sopenharmony_ci ohdr->bth[2] = cpu_to_be32(mask_psn((u32)txp->txq->tx_ring.sent_txreqs)); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Build the deth */ 33362306a36Sopenharmony_ci ohdr->u.ud.deth[0] = cpu_to_be32(priv->qkey); 33462306a36Sopenharmony_ci ohdr->u.ud.deth[1] = cpu_to_be32((txp->entropy << 33562306a36Sopenharmony_ci HFI1_IPOIB_ENTROPY_SHIFT) | sqpn); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* Construct the pbc. */ 33862306a36Sopenharmony_ci sdma_hdr->pbc = 33962306a36Sopenharmony_ci cpu_to_le64(create_pbc(ppd, 34062306a36Sopenharmony_ci ib_is_sc5(txp->flow.sc5) << 34162306a36Sopenharmony_ci PBC_DC_INFO_SHIFT, 34262306a36Sopenharmony_ci 0, 34362306a36Sopenharmony_ci sc_to_vlt(priv->dd, txp->flow.sc5), 34462306a36Sopenharmony_ci dwords - SIZE_OF_CRC + 34562306a36Sopenharmony_ci (sizeof(sdma_hdr->pbc) >> 2))); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic struct ipoib_txreq *hfi1_ipoib_send_dma_common(struct net_device *dev, 34962306a36Sopenharmony_ci struct sk_buff *skb, 35062306a36Sopenharmony_ci struct ipoib_txparms *txp) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 35362306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq = txp->txq; 35462306a36Sopenharmony_ci struct ipoib_txreq *tx; 35562306a36Sopenharmony_ci struct hfi1_ipoib_circ_buf *tx_ring = &txq->tx_ring; 35662306a36Sopenharmony_ci u32 tail = tx_ring->tail; 35762306a36Sopenharmony_ci int ret; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (unlikely(!tx_ring->avail)) { 36062306a36Sopenharmony_ci u32 head; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (hfi1_ipoib_used(txq) >= hfi1_ipoib_ring_hwat(txq)) 36362306a36Sopenharmony_ci /* This shouldn't happen with a stopped queue */ 36462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 36562306a36Sopenharmony_ci /* See hfi1_ipoib_poll_tx_ring() */ 36662306a36Sopenharmony_ci head = smp_load_acquire(&tx_ring->head); 36762306a36Sopenharmony_ci tx_ring->avail = 36862306a36Sopenharmony_ci min_t(u32, hfi1_ipoib_ring_hwat(txq), 36962306a36Sopenharmony_ci CIRC_CNT(head, tail, tx_ring->max_items)); 37062306a36Sopenharmony_ci } else { 37162306a36Sopenharmony_ci tx_ring->avail--; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci tx = hfi1_txreq_from_idx(tx_ring, tail); 37462306a36Sopenharmony_ci trace_hfi1_txq_alloc_tx(txq); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* so that we can test if the sdma descriptors are there */ 37762306a36Sopenharmony_ci tx->txreq.num_desc = 0; 37862306a36Sopenharmony_ci tx->txq = txq; 37962306a36Sopenharmony_ci tx->skb = skb; 38062306a36Sopenharmony_ci INIT_LIST_HEAD(&tx->txreq.list); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci hfi1_ipoib_build_ib_tx_headers(tx, txp); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci ret = hfi1_ipoib_build_tx_desc(tx, txp); 38562306a36Sopenharmony_ci if (likely(!ret)) { 38662306a36Sopenharmony_ci if (txq->flow.as_int != txp->flow.as_int) { 38762306a36Sopenharmony_ci txq->flow.tx_queue = txp->flow.tx_queue; 38862306a36Sopenharmony_ci txq->flow.sc5 = txp->flow.sc5; 38962306a36Sopenharmony_ci txq->sde = 39062306a36Sopenharmony_ci sdma_select_engine_sc(priv->dd, 39162306a36Sopenharmony_ci txp->flow.tx_queue, 39262306a36Sopenharmony_ci txp->flow.sc5); 39362306a36Sopenharmony_ci trace_hfi1_flow_switch(txq); 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci return tx; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci sdma_txclean(priv->dd, &tx->txreq); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return ERR_PTR(ret); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic int hfi1_ipoib_submit_tx_list(struct net_device *dev, 40562306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci int ret; 40862306a36Sopenharmony_ci u16 count_out; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci ret = sdma_send_txlist(txq->sde, 41162306a36Sopenharmony_ci iowait_get_ib_work(&txq->wait), 41262306a36Sopenharmony_ci &txq->tx_list, 41362306a36Sopenharmony_ci &count_out); 41462306a36Sopenharmony_ci if (likely(!ret) || ret == -EBUSY || ret == -ECOMM) 41562306a36Sopenharmony_ci return ret; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci dd_dev_warn(txq->priv->dd, "cannot send skb tx list, err %d.\n", ret); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return ret; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic int hfi1_ipoib_flush_tx_list(struct net_device *dev, 42362306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci int ret = 0; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (!list_empty(&txq->tx_list)) { 42862306a36Sopenharmony_ci /* Flush the current list */ 42962306a36Sopenharmony_ci ret = hfi1_ipoib_submit_tx_list(dev, txq); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (unlikely(ret)) 43262306a36Sopenharmony_ci if (ret != -EBUSY) 43362306a36Sopenharmony_ci ++dev->stats.tx_carrier_errors; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return ret; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int hfi1_ipoib_submit_tx(struct hfi1_ipoib_txq *txq, 44062306a36Sopenharmony_ci struct ipoib_txreq *tx) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci int ret; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci ret = sdma_send_txreq(txq->sde, 44562306a36Sopenharmony_ci iowait_get_ib_work(&txq->wait), 44662306a36Sopenharmony_ci &tx->txreq, 44762306a36Sopenharmony_ci txq->pkts_sent); 44862306a36Sopenharmony_ci if (likely(!ret)) { 44962306a36Sopenharmony_ci txq->pkts_sent = true; 45062306a36Sopenharmony_ci iowait_starve_clear(txq->pkts_sent, &txq->wait); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return ret; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic int hfi1_ipoib_send_dma_single(struct net_device *dev, 45762306a36Sopenharmony_ci struct sk_buff *skb, 45862306a36Sopenharmony_ci struct ipoib_txparms *txp) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq = txp->txq; 46162306a36Sopenharmony_ci struct hfi1_ipoib_circ_buf *tx_ring; 46262306a36Sopenharmony_ci struct ipoib_txreq *tx; 46362306a36Sopenharmony_ci int ret; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci tx = hfi1_ipoib_send_dma_common(dev, skb, txp); 46662306a36Sopenharmony_ci if (IS_ERR(tx)) { 46762306a36Sopenharmony_ci int ret = PTR_ERR(tx); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (ret == -ENOMEM) 47262306a36Sopenharmony_ci ++dev->stats.tx_errors; 47362306a36Sopenharmony_ci else 47462306a36Sopenharmony_ci ++dev->stats.tx_carrier_errors; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return NETDEV_TX_OK; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci tx_ring = &txq->tx_ring; 48062306a36Sopenharmony_ci trace_hfi1_tx_consume(tx, tx_ring->tail); 48162306a36Sopenharmony_ci /* consume tx */ 48262306a36Sopenharmony_ci smp_store_release(&tx_ring->tail, CIRC_NEXT(tx_ring->tail, tx_ring->max_items)); 48362306a36Sopenharmony_ci ret = hfi1_ipoib_submit_tx(txq, tx); 48462306a36Sopenharmony_ci if (likely(!ret)) { 48562306a36Sopenharmony_citx_ok: 48662306a36Sopenharmony_ci trace_sdma_output_ibhdr(txq->priv->dd, 48762306a36Sopenharmony_ci &tx->sdma_hdr->hdr, 48862306a36Sopenharmony_ci ib_is_sc5(txp->flow.sc5)); 48962306a36Sopenharmony_ci hfi1_ipoib_check_queue_depth(txq); 49062306a36Sopenharmony_ci return NETDEV_TX_OK; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci txq->pkts_sent = false; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (ret == -EBUSY || ret == -ECOMM) 49662306a36Sopenharmony_ci goto tx_ok; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* mark complete and kick napi tx */ 49962306a36Sopenharmony_ci smp_store_release(&tx->complete, 1); 50062306a36Sopenharmony_ci napi_schedule(&tx->txq->napi); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci ++dev->stats.tx_carrier_errors; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci return NETDEV_TX_OK; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic int hfi1_ipoib_send_dma_list(struct net_device *dev, 50862306a36Sopenharmony_ci struct sk_buff *skb, 50962306a36Sopenharmony_ci struct ipoib_txparms *txp) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq = txp->txq; 51262306a36Sopenharmony_ci struct hfi1_ipoib_circ_buf *tx_ring; 51362306a36Sopenharmony_ci struct ipoib_txreq *tx; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* Has the flow change ? */ 51662306a36Sopenharmony_ci if (txq->flow.as_int != txp->flow.as_int) { 51762306a36Sopenharmony_ci int ret; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci trace_hfi1_flow_flush(txq); 52062306a36Sopenharmony_ci ret = hfi1_ipoib_flush_tx_list(dev, txq); 52162306a36Sopenharmony_ci if (unlikely(ret)) { 52262306a36Sopenharmony_ci if (ret == -EBUSY) 52362306a36Sopenharmony_ci ++dev->stats.tx_dropped; 52462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 52562306a36Sopenharmony_ci return NETDEV_TX_OK; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci tx = hfi1_ipoib_send_dma_common(dev, skb, txp); 52962306a36Sopenharmony_ci if (IS_ERR(tx)) { 53062306a36Sopenharmony_ci int ret = PTR_ERR(tx); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (ret == -ENOMEM) 53562306a36Sopenharmony_ci ++dev->stats.tx_errors; 53662306a36Sopenharmony_ci else 53762306a36Sopenharmony_ci ++dev->stats.tx_carrier_errors; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci return NETDEV_TX_OK; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci tx_ring = &txq->tx_ring; 54362306a36Sopenharmony_ci trace_hfi1_tx_consume(tx, tx_ring->tail); 54462306a36Sopenharmony_ci /* consume tx */ 54562306a36Sopenharmony_ci smp_store_release(&tx_ring->tail, CIRC_NEXT(tx_ring->tail, tx_ring->max_items)); 54662306a36Sopenharmony_ci list_add_tail(&tx->txreq.list, &txq->tx_list); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci hfi1_ipoib_check_queue_depth(txq); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci trace_sdma_output_ibhdr(txq->priv->dd, 55162306a36Sopenharmony_ci &tx->sdma_hdr->hdr, 55262306a36Sopenharmony_ci ib_is_sc5(txp->flow.sc5)); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (!netdev_xmit_more()) 55562306a36Sopenharmony_ci (void)hfi1_ipoib_flush_tx_list(dev, txq); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci return NETDEV_TX_OK; 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic u8 hfi1_ipoib_calc_entropy(struct sk_buff *skb) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci if (skb_transport_header_was_set(skb)) { 56362306a36Sopenharmony_ci u8 *hdr = (u8 *)skb_transport_header(skb); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci return (hdr[0] ^ hdr[1] ^ hdr[2] ^ hdr[3]); 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return (u8)skb_get_queue_mapping(skb); 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ciint hfi1_ipoib_send(struct net_device *dev, 57262306a36Sopenharmony_ci struct sk_buff *skb, 57362306a36Sopenharmony_ci struct ib_ah *address, 57462306a36Sopenharmony_ci u32 dqpn) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 57762306a36Sopenharmony_ci struct ipoib_txparms txp; 57862306a36Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (unlikely(skb->len > rn->mtu + HFI1_IPOIB_ENCAP_LEN)) { 58162306a36Sopenharmony_ci dd_dev_warn(priv->dd, "packet len %d (> %d) too long to send, dropping\n", 58262306a36Sopenharmony_ci skb->len, 58362306a36Sopenharmony_ci rn->mtu + HFI1_IPOIB_ENCAP_LEN); 58462306a36Sopenharmony_ci ++dev->stats.tx_dropped; 58562306a36Sopenharmony_ci ++dev->stats.tx_errors; 58662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 58762306a36Sopenharmony_ci return NETDEV_TX_OK; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci txp.dd = priv->dd; 59162306a36Sopenharmony_ci txp.ah_attr = &ibah_to_rvtah(address)->attr; 59262306a36Sopenharmony_ci txp.ibp = to_iport(priv->device, priv->port_num); 59362306a36Sopenharmony_ci txp.txq = &priv->txqs[skb_get_queue_mapping(skb)]; 59462306a36Sopenharmony_ci txp.dqpn = dqpn; 59562306a36Sopenharmony_ci txp.flow.sc5 = txp.ibp->sl_to_sc[rdma_ah_get_sl(txp.ah_attr)]; 59662306a36Sopenharmony_ci txp.flow.tx_queue = (u8)skb_get_queue_mapping(skb); 59762306a36Sopenharmony_ci txp.entropy = hfi1_ipoib_calc_entropy(skb); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (netdev_xmit_more() || !list_empty(&txp.txq->tx_list)) 60062306a36Sopenharmony_ci return hfi1_ipoib_send_dma_list(dev, skb, &txp); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci return hfi1_ipoib_send_dma_single(dev, skb, &txp); 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci/* 60662306a36Sopenharmony_ci * hfi1_ipoib_sdma_sleep - ipoib sdma sleep function 60762306a36Sopenharmony_ci * 60862306a36Sopenharmony_ci * This function gets called from sdma_send_txreq() when there are not enough 60962306a36Sopenharmony_ci * sdma descriptors available to send the packet. It adds Tx queue's wait 61062306a36Sopenharmony_ci * structure to sdma engine's dmawait list to be woken up when descriptors 61162306a36Sopenharmony_ci * become available. 61262306a36Sopenharmony_ci */ 61362306a36Sopenharmony_cistatic int hfi1_ipoib_sdma_sleep(struct sdma_engine *sde, 61462306a36Sopenharmony_ci struct iowait_work *wait, 61562306a36Sopenharmony_ci struct sdma_txreq *txreq, 61662306a36Sopenharmony_ci uint seq, 61762306a36Sopenharmony_ci bool pkts_sent) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq = 62062306a36Sopenharmony_ci container_of(wait->iow, struct hfi1_ipoib_txq, wait); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci write_seqlock(&sde->waitlock); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci if (likely(txq->priv->netdev->reg_state == NETREG_REGISTERED)) { 62562306a36Sopenharmony_ci if (sdma_progress(sde, seq, txreq)) { 62662306a36Sopenharmony_ci write_sequnlock(&sde->waitlock); 62762306a36Sopenharmony_ci return -EAGAIN; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (list_empty(&txreq->list)) 63162306a36Sopenharmony_ci /* came from non-list submit */ 63262306a36Sopenharmony_ci list_add_tail(&txreq->list, &txq->tx_list); 63362306a36Sopenharmony_ci if (list_empty(&txq->wait.list)) { 63462306a36Sopenharmony_ci struct hfi1_ibport *ibp = &sde->ppd->ibport_data; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (!atomic_xchg(&txq->tx_ring.no_desc, 1)) { 63762306a36Sopenharmony_ci trace_hfi1_txq_queued(txq); 63862306a36Sopenharmony_ci hfi1_ipoib_stop_txq(txq); 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci ibp->rvp.n_dmawait++; 64162306a36Sopenharmony_ci iowait_queue(pkts_sent, wait->iow, &sde->dmawait); 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci write_sequnlock(&sde->waitlock); 64562306a36Sopenharmony_ci return -EBUSY; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci write_sequnlock(&sde->waitlock); 64962306a36Sopenharmony_ci return -EINVAL; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci/* 65362306a36Sopenharmony_ci * hfi1_ipoib_sdma_wakeup - ipoib sdma wakeup function 65462306a36Sopenharmony_ci * 65562306a36Sopenharmony_ci * This function gets called when SDMA descriptors becomes available and Tx 65662306a36Sopenharmony_ci * queue's wait structure was previously added to sdma engine's dmawait list. 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_cistatic void hfi1_ipoib_sdma_wakeup(struct iowait *wait, int reason) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq = 66162306a36Sopenharmony_ci container_of(wait, struct hfi1_ipoib_txq, wait); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci trace_hfi1_txq_wakeup(txq); 66462306a36Sopenharmony_ci if (likely(txq->priv->netdev->reg_state == NETREG_REGISTERED)) 66562306a36Sopenharmony_ci iowait_schedule(wait, system_highpri_wq, WORK_CPU_UNBOUND); 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic void hfi1_ipoib_flush_txq(struct work_struct *work) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci struct iowait_work *ioww = 67162306a36Sopenharmony_ci container_of(work, struct iowait_work, iowork); 67262306a36Sopenharmony_ci struct iowait *wait = iowait_ioww_to_iow(ioww); 67362306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq = 67462306a36Sopenharmony_ci container_of(wait, struct hfi1_ipoib_txq, wait); 67562306a36Sopenharmony_ci struct net_device *dev = txq->priv->netdev; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (likely(dev->reg_state == NETREG_REGISTERED) && 67862306a36Sopenharmony_ci likely(!hfi1_ipoib_flush_tx_list(dev, txq))) 67962306a36Sopenharmony_ci if (atomic_xchg(&txq->tx_ring.no_desc, 0)) 68062306a36Sopenharmony_ci hfi1_ipoib_wake_txq(txq); 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ciint hfi1_ipoib_txreq_init(struct hfi1_ipoib_dev_priv *priv) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct net_device *dev = priv->netdev; 68662306a36Sopenharmony_ci u32 tx_ring_size, tx_item_size; 68762306a36Sopenharmony_ci struct hfi1_ipoib_circ_buf *tx_ring; 68862306a36Sopenharmony_ci int i, j; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* 69162306a36Sopenharmony_ci * Ring holds 1 less than tx_ring_size 69262306a36Sopenharmony_ci * Round up to next power of 2 in order to hold at least tx_queue_len 69362306a36Sopenharmony_ci */ 69462306a36Sopenharmony_ci tx_ring_size = roundup_pow_of_two(dev->tx_queue_len + 1); 69562306a36Sopenharmony_ci tx_item_size = roundup_pow_of_two(sizeof(struct ipoib_txreq)); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci priv->txqs = kcalloc_node(dev->num_tx_queues, 69862306a36Sopenharmony_ci sizeof(struct hfi1_ipoib_txq), 69962306a36Sopenharmony_ci GFP_KERNEL, 70062306a36Sopenharmony_ci priv->dd->node); 70162306a36Sopenharmony_ci if (!priv->txqs) 70262306a36Sopenharmony_ci return -ENOMEM; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci for (i = 0; i < dev->num_tx_queues; i++) { 70562306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq = &priv->txqs[i]; 70662306a36Sopenharmony_ci struct ipoib_txreq *tx; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci tx_ring = &txq->tx_ring; 70962306a36Sopenharmony_ci iowait_init(&txq->wait, 71062306a36Sopenharmony_ci 0, 71162306a36Sopenharmony_ci hfi1_ipoib_flush_txq, 71262306a36Sopenharmony_ci NULL, 71362306a36Sopenharmony_ci hfi1_ipoib_sdma_sleep, 71462306a36Sopenharmony_ci hfi1_ipoib_sdma_wakeup, 71562306a36Sopenharmony_ci NULL, 71662306a36Sopenharmony_ci NULL); 71762306a36Sopenharmony_ci txq->priv = priv; 71862306a36Sopenharmony_ci txq->sde = NULL; 71962306a36Sopenharmony_ci INIT_LIST_HEAD(&txq->tx_list); 72062306a36Sopenharmony_ci atomic_set(&txq->tx_ring.stops, 0); 72162306a36Sopenharmony_ci atomic_set(&txq->tx_ring.ring_full, 0); 72262306a36Sopenharmony_ci atomic_set(&txq->tx_ring.no_desc, 0); 72362306a36Sopenharmony_ci txq->q_idx = i; 72462306a36Sopenharmony_ci txq->flow.tx_queue = 0xff; 72562306a36Sopenharmony_ci txq->flow.sc5 = 0xff; 72662306a36Sopenharmony_ci txq->pkts_sent = false; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci netdev_queue_numa_node_write(netdev_get_tx_queue(dev, i), 72962306a36Sopenharmony_ci priv->dd->node); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci txq->tx_ring.items = 73262306a36Sopenharmony_ci kvzalloc_node(array_size(tx_ring_size, tx_item_size), 73362306a36Sopenharmony_ci GFP_KERNEL, priv->dd->node); 73462306a36Sopenharmony_ci if (!txq->tx_ring.items) 73562306a36Sopenharmony_ci goto free_txqs; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci txq->tx_ring.max_items = tx_ring_size; 73862306a36Sopenharmony_ci txq->tx_ring.shift = ilog2(tx_item_size); 73962306a36Sopenharmony_ci txq->tx_ring.avail = hfi1_ipoib_ring_hwat(txq); 74062306a36Sopenharmony_ci tx_ring = &txq->tx_ring; 74162306a36Sopenharmony_ci for (j = 0; j < tx_ring_size; j++) { 74262306a36Sopenharmony_ci hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr = 74362306a36Sopenharmony_ci kzalloc_node(sizeof(*tx->sdma_hdr), 74462306a36Sopenharmony_ci GFP_KERNEL, priv->dd->node); 74562306a36Sopenharmony_ci if (!hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr) 74662306a36Sopenharmony_ci goto free_txqs; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci netif_napi_add_tx(dev, &txq->napi, hfi1_ipoib_poll_tx_ring); 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci return 0; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cifree_txqs: 75562306a36Sopenharmony_ci for (i--; i >= 0; i--) { 75662306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq = &priv->txqs[i]; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci netif_napi_del(&txq->napi); 75962306a36Sopenharmony_ci tx_ring = &txq->tx_ring; 76062306a36Sopenharmony_ci for (j = 0; j < tx_ring_size; j++) 76162306a36Sopenharmony_ci kfree(hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr); 76262306a36Sopenharmony_ci kvfree(tx_ring->items); 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci kfree(priv->txqs); 76662306a36Sopenharmony_ci priv->txqs = NULL; 76762306a36Sopenharmony_ci return -ENOMEM; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic void hfi1_ipoib_drain_tx_list(struct hfi1_ipoib_txq *txq) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct sdma_txreq *txreq; 77362306a36Sopenharmony_ci struct sdma_txreq *txreq_tmp; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci list_for_each_entry_safe(txreq, txreq_tmp, &txq->tx_list, list) { 77662306a36Sopenharmony_ci struct ipoib_txreq *tx = 77762306a36Sopenharmony_ci container_of(txreq, struct ipoib_txreq, txreq); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci list_del(&txreq->list); 78062306a36Sopenharmony_ci sdma_txclean(txq->priv->dd, &tx->txreq); 78162306a36Sopenharmony_ci dev_kfree_skb_any(tx->skb); 78262306a36Sopenharmony_ci tx->skb = NULL; 78362306a36Sopenharmony_ci txq->tx_ring.complete_txreqs++; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci if (hfi1_ipoib_used(txq)) 78762306a36Sopenharmony_ci dd_dev_warn(txq->priv->dd, 78862306a36Sopenharmony_ci "txq %d not empty found %u requests\n", 78962306a36Sopenharmony_ci txq->q_idx, 79062306a36Sopenharmony_ci hfi1_ipoib_txreqs(txq->tx_ring.sent_txreqs, 79162306a36Sopenharmony_ci txq->tx_ring.complete_txreqs)); 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_civoid hfi1_ipoib_txreq_deinit(struct hfi1_ipoib_dev_priv *priv) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci int i, j; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci for (i = 0; i < priv->netdev->num_tx_queues; i++) { 79962306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq = &priv->txqs[i]; 80062306a36Sopenharmony_ci struct hfi1_ipoib_circ_buf *tx_ring = &txq->tx_ring; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci iowait_cancel_work(&txq->wait); 80362306a36Sopenharmony_ci iowait_sdma_drain(&txq->wait); 80462306a36Sopenharmony_ci hfi1_ipoib_drain_tx_list(txq); 80562306a36Sopenharmony_ci netif_napi_del(&txq->napi); 80662306a36Sopenharmony_ci hfi1_ipoib_drain_tx_ring(txq); 80762306a36Sopenharmony_ci for (j = 0; j < tx_ring->max_items; j++) 80862306a36Sopenharmony_ci kfree(hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr); 80962306a36Sopenharmony_ci kvfree(tx_ring->items); 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci kfree(priv->txqs); 81362306a36Sopenharmony_ci priv->txqs = NULL; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_civoid hfi1_ipoib_napi_tx_enable(struct net_device *dev) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 81962306a36Sopenharmony_ci int i; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci for (i = 0; i < dev->num_tx_queues; i++) { 82262306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq = &priv->txqs[i]; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci napi_enable(&txq->napi); 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_civoid hfi1_ipoib_napi_tx_disable(struct net_device *dev) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 83162306a36Sopenharmony_ci int i; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci for (i = 0; i < dev->num_tx_queues; i++) { 83462306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq = &priv->txqs[i]; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci napi_disable(&txq->napi); 83762306a36Sopenharmony_ci hfi1_ipoib_drain_tx_ring(txq); 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_civoid hfi1_ipoib_tx_timeout(struct net_device *dev, unsigned int q) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 84462306a36Sopenharmony_ci struct hfi1_ipoib_txq *txq = &priv->txqs[q]; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci dd_dev_info(priv->dd, "timeout txq %p q %u stopped %u stops %d no_desc %d ring_full %d\n", 84762306a36Sopenharmony_ci txq, q, 84862306a36Sopenharmony_ci __netif_subqueue_stopped(dev, txq->q_idx), 84962306a36Sopenharmony_ci atomic_read(&txq->tx_ring.stops), 85062306a36Sopenharmony_ci atomic_read(&txq->tx_ring.no_desc), 85162306a36Sopenharmony_ci atomic_read(&txq->tx_ring.ring_full)); 85262306a36Sopenharmony_ci dd_dev_info(priv->dd, "sde %p engine %u\n", 85362306a36Sopenharmony_ci txq->sde, 85462306a36Sopenharmony_ci txq->sde ? txq->sde->this_idx : 0); 85562306a36Sopenharmony_ci dd_dev_info(priv->dd, "flow %x\n", txq->flow.as_int); 85662306a36Sopenharmony_ci dd_dev_info(priv->dd, "sent %llu completed %llu used %llu\n", 85762306a36Sopenharmony_ci txq->tx_ring.sent_txreqs, txq->tx_ring.complete_txreqs, 85862306a36Sopenharmony_ci hfi1_ipoib_used(txq)); 85962306a36Sopenharmony_ci dd_dev_info(priv->dd, "tx_queue_len %u max_items %u\n", 86062306a36Sopenharmony_ci dev->tx_queue_len, txq->tx_ring.max_items); 86162306a36Sopenharmony_ci dd_dev_info(priv->dd, "head %u tail %u\n", 86262306a36Sopenharmony_ci txq->tx_ring.head, txq->tx_ring.tail); 86362306a36Sopenharmony_ci dd_dev_info(priv->dd, "wait queued %u\n", 86462306a36Sopenharmony_ci !list_empty(&txq->wait.list)); 86562306a36Sopenharmony_ci dd_dev_info(priv->dd, "tx_list empty %u\n", 86662306a36Sopenharmony_ci list_empty(&txq->tx_list)); 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 869