162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* Copyright (c) 2021, Microsoft Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <uapi/linux/bpf.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/inetdevice.h> 762306a36Sopenharmony_ci#include <linux/etherdevice.h> 862306a36Sopenharmony_ci#include <linux/ethtool.h> 962306a36Sopenharmony_ci#include <linux/filter.h> 1062306a36Sopenharmony_ci#include <linux/mm.h> 1162306a36Sopenharmony_ci#include <linux/pci.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <net/checksum.h> 1462306a36Sopenharmony_ci#include <net/ip6_checksum.h> 1562306a36Sopenharmony_ci#include <net/page_pool/helpers.h> 1662306a36Sopenharmony_ci#include <net/xdp.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <net/mana/mana.h> 1962306a36Sopenharmony_ci#include <net/mana/mana_auxiliary.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic DEFINE_IDA(mana_adev_ida); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic int mana_adev_idx_alloc(void) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci return ida_alloc(&mana_adev_ida, GFP_KERNEL); 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void mana_adev_idx_free(int idx) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci ida_free(&mana_adev_ida, idx); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* Microsoft Azure Network Adapter (MANA) functions */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int mana_open(struct net_device *ndev) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct mana_port_context *apc = netdev_priv(ndev); 3862306a36Sopenharmony_ci int err; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci err = mana_alloc_queues(ndev); 4162306a36Sopenharmony_ci if (err) 4262306a36Sopenharmony_ci return err; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci apc->port_is_up = true; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* Ensure port state updated before txq state */ 4762306a36Sopenharmony_ci smp_wmb(); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci netif_carrier_on(ndev); 5062306a36Sopenharmony_ci netif_tx_wake_all_queues(ndev); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci return 0; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic int mana_close(struct net_device *ndev) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct mana_port_context *apc = netdev_priv(ndev); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (!apc->port_is_up) 6062306a36Sopenharmony_ci return 0; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return mana_detach(ndev, true); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic bool mana_can_tx(struct gdma_queue *wq) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci return mana_gd_wq_avail_space(wq) >= MAX_TX_WQE_SIZE; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic unsigned int mana_checksum_info(struct sk_buff *skb) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP)) { 7362306a36Sopenharmony_ci struct iphdr *ip = ip_hdr(skb); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (ip->protocol == IPPROTO_TCP) 7662306a36Sopenharmony_ci return IPPROTO_TCP; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (ip->protocol == IPPROTO_UDP) 7962306a36Sopenharmony_ci return IPPROTO_UDP; 8062306a36Sopenharmony_ci } else if (skb->protocol == htons(ETH_P_IPV6)) { 8162306a36Sopenharmony_ci struct ipv6hdr *ip6 = ipv6_hdr(skb); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (ip6->nexthdr == IPPROTO_TCP) 8462306a36Sopenharmony_ci return IPPROTO_TCP; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (ip6->nexthdr == IPPROTO_UDP) 8762306a36Sopenharmony_ci return IPPROTO_UDP; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* No csum offloading */ 9162306a36Sopenharmony_ci return 0; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic void mana_add_sge(struct mana_tx_package *tp, struct mana_skb_head *ash, 9562306a36Sopenharmony_ci int sg_i, dma_addr_t da, int sge_len, u32 gpa_mkey) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci ash->dma_handle[sg_i] = da; 9862306a36Sopenharmony_ci ash->size[sg_i] = sge_len; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci tp->wqe_req.sgl[sg_i].address = da; 10162306a36Sopenharmony_ci tp->wqe_req.sgl[sg_i].mem_key = gpa_mkey; 10262306a36Sopenharmony_ci tp->wqe_req.sgl[sg_i].size = sge_len; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic int mana_map_skb(struct sk_buff *skb, struct mana_port_context *apc, 10662306a36Sopenharmony_ci struct mana_tx_package *tp, int gso_hs) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct mana_skb_head *ash = (struct mana_skb_head *)skb->head; 10962306a36Sopenharmony_ci int hsg = 1; /* num of SGEs of linear part */ 11062306a36Sopenharmony_ci struct gdma_dev *gd = apc->ac->gdma_dev; 11162306a36Sopenharmony_ci int skb_hlen = skb_headlen(skb); 11262306a36Sopenharmony_ci int sge0_len, sge1_len = 0; 11362306a36Sopenharmony_ci struct gdma_context *gc; 11462306a36Sopenharmony_ci struct device *dev; 11562306a36Sopenharmony_ci skb_frag_t *frag; 11662306a36Sopenharmony_ci dma_addr_t da; 11762306a36Sopenharmony_ci int sg_i; 11862306a36Sopenharmony_ci int i; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci gc = gd->gdma_context; 12162306a36Sopenharmony_ci dev = gc->dev; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (gso_hs && gso_hs < skb_hlen) { 12462306a36Sopenharmony_ci sge0_len = gso_hs; 12562306a36Sopenharmony_ci sge1_len = skb_hlen - gso_hs; 12662306a36Sopenharmony_ci } else { 12762306a36Sopenharmony_ci sge0_len = skb_hlen; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci da = dma_map_single(dev, skb->data, sge0_len, DMA_TO_DEVICE); 13162306a36Sopenharmony_ci if (dma_mapping_error(dev, da)) 13262306a36Sopenharmony_ci return -ENOMEM; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci mana_add_sge(tp, ash, 0, da, sge0_len, gd->gpa_mkey); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (sge1_len) { 13762306a36Sopenharmony_ci sg_i = 1; 13862306a36Sopenharmony_ci da = dma_map_single(dev, skb->data + sge0_len, sge1_len, 13962306a36Sopenharmony_ci DMA_TO_DEVICE); 14062306a36Sopenharmony_ci if (dma_mapping_error(dev, da)) 14162306a36Sopenharmony_ci goto frag_err; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci mana_add_sge(tp, ash, sg_i, da, sge1_len, gd->gpa_mkey); 14462306a36Sopenharmony_ci hsg = 2; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 14862306a36Sopenharmony_ci sg_i = hsg + i; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci frag = &skb_shinfo(skb)->frags[i]; 15162306a36Sopenharmony_ci da = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), 15262306a36Sopenharmony_ci DMA_TO_DEVICE); 15362306a36Sopenharmony_ci if (dma_mapping_error(dev, da)) 15462306a36Sopenharmony_ci goto frag_err; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci mana_add_sge(tp, ash, sg_i, da, skb_frag_size(frag), 15762306a36Sopenharmony_ci gd->gpa_mkey); 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci return 0; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cifrag_err: 16362306a36Sopenharmony_ci for (i = sg_i - 1; i >= hsg; i--) 16462306a36Sopenharmony_ci dma_unmap_page(dev, ash->dma_handle[i], ash->size[i], 16562306a36Sopenharmony_ci DMA_TO_DEVICE); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci for (i = hsg - 1; i >= 0; i--) 16862306a36Sopenharmony_ci dma_unmap_single(dev, ash->dma_handle[i], ash->size[i], 16962306a36Sopenharmony_ci DMA_TO_DEVICE); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return -ENOMEM; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/* Handle the case when GSO SKB linear length is too large. 17562306a36Sopenharmony_ci * MANA NIC requires GSO packets to put only the packet header to SGE0. 17662306a36Sopenharmony_ci * So, we need 2 SGEs for the skb linear part which contains more than the 17762306a36Sopenharmony_ci * header. 17862306a36Sopenharmony_ci * Return a positive value for the number of SGEs, or a negative value 17962306a36Sopenharmony_ci * for an error. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_cistatic int mana_fix_skb_head(struct net_device *ndev, struct sk_buff *skb, 18262306a36Sopenharmony_ci int gso_hs) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci int num_sge = 1 + skb_shinfo(skb)->nr_frags; 18562306a36Sopenharmony_ci int skb_hlen = skb_headlen(skb); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (gso_hs < skb_hlen) { 18862306a36Sopenharmony_ci num_sge++; 18962306a36Sopenharmony_ci } else if (gso_hs > skb_hlen) { 19062306a36Sopenharmony_ci if (net_ratelimit()) 19162306a36Sopenharmony_ci netdev_err(ndev, 19262306a36Sopenharmony_ci "TX nonlinear head: hs:%d, skb_hlen:%d\n", 19362306a36Sopenharmony_ci gso_hs, skb_hlen); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return -EINVAL; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return num_sge; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/* Get the GSO packet's header size */ 20262306a36Sopenharmony_cistatic int mana_get_gso_hs(struct sk_buff *skb) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci int gso_hs; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (skb->encapsulation) { 20762306a36Sopenharmony_ci gso_hs = skb_inner_tcp_all_headers(skb); 20862306a36Sopenharmony_ci } else { 20962306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) { 21062306a36Sopenharmony_ci gso_hs = skb_transport_offset(skb) + 21162306a36Sopenharmony_ci sizeof(struct udphdr); 21262306a36Sopenharmony_ci } else { 21362306a36Sopenharmony_ci gso_hs = skb_tcp_all_headers(skb); 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return gso_hs; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cinetdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci enum mana_tx_pkt_format pkt_fmt = MANA_SHORT_PKT_FMT; 22362306a36Sopenharmony_ci struct mana_port_context *apc = netdev_priv(ndev); 22462306a36Sopenharmony_ci int gso_hs = 0; /* zero for non-GSO pkts */ 22562306a36Sopenharmony_ci u16 txq_idx = skb_get_queue_mapping(skb); 22662306a36Sopenharmony_ci struct gdma_dev *gd = apc->ac->gdma_dev; 22762306a36Sopenharmony_ci bool ipv4 = false, ipv6 = false; 22862306a36Sopenharmony_ci struct mana_tx_package pkg = {}; 22962306a36Sopenharmony_ci struct netdev_queue *net_txq; 23062306a36Sopenharmony_ci struct mana_stats_tx *tx_stats; 23162306a36Sopenharmony_ci struct gdma_queue *gdma_sq; 23262306a36Sopenharmony_ci unsigned int csum_type; 23362306a36Sopenharmony_ci struct mana_txq *txq; 23462306a36Sopenharmony_ci struct mana_cq *cq; 23562306a36Sopenharmony_ci int err, len; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (unlikely(!apc->port_is_up)) 23862306a36Sopenharmony_ci goto tx_drop; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (skb_cow_head(skb, MANA_HEADROOM)) 24162306a36Sopenharmony_ci goto tx_drop_count; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci txq = &apc->tx_qp[txq_idx].txq; 24462306a36Sopenharmony_ci gdma_sq = txq->gdma_sq; 24562306a36Sopenharmony_ci cq = &apc->tx_qp[txq_idx].tx_cq; 24662306a36Sopenharmony_ci tx_stats = &txq->stats; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci pkg.tx_oob.s_oob.vcq_num = cq->gdma_id; 24962306a36Sopenharmony_ci pkg.tx_oob.s_oob.vsq_frame = txq->vsq_frame; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (txq->vp_offset > MANA_SHORT_VPORT_OFFSET_MAX) { 25262306a36Sopenharmony_ci pkg.tx_oob.l_oob.long_vp_offset = txq->vp_offset; 25362306a36Sopenharmony_ci pkt_fmt = MANA_LONG_PKT_FMT; 25462306a36Sopenharmony_ci } else { 25562306a36Sopenharmony_ci pkg.tx_oob.s_oob.short_vp_offset = txq->vp_offset; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 25962306a36Sopenharmony_ci pkt_fmt = MANA_LONG_PKT_FMT; 26062306a36Sopenharmony_ci pkg.tx_oob.l_oob.inject_vlan_pri_tag = 1; 26162306a36Sopenharmony_ci pkg.tx_oob.l_oob.pcp = skb_vlan_tag_get_prio(skb); 26262306a36Sopenharmony_ci pkg.tx_oob.l_oob.dei = skb_vlan_tag_get_cfi(skb); 26362306a36Sopenharmony_ci pkg.tx_oob.l_oob.vlan_id = skb_vlan_tag_get_id(skb); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci pkg.tx_oob.s_oob.pkt_fmt = pkt_fmt; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (pkt_fmt == MANA_SHORT_PKT_FMT) { 26962306a36Sopenharmony_ci pkg.wqe_req.inline_oob_size = sizeof(struct mana_tx_short_oob); 27062306a36Sopenharmony_ci u64_stats_update_begin(&tx_stats->syncp); 27162306a36Sopenharmony_ci tx_stats->short_pkt_fmt++; 27262306a36Sopenharmony_ci u64_stats_update_end(&tx_stats->syncp); 27362306a36Sopenharmony_ci } else { 27462306a36Sopenharmony_ci pkg.wqe_req.inline_oob_size = sizeof(struct mana_tx_oob); 27562306a36Sopenharmony_ci u64_stats_update_begin(&tx_stats->syncp); 27662306a36Sopenharmony_ci tx_stats->long_pkt_fmt++; 27762306a36Sopenharmony_ci u64_stats_update_end(&tx_stats->syncp); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci pkg.wqe_req.inline_oob_data = &pkg.tx_oob; 28162306a36Sopenharmony_ci pkg.wqe_req.flags = 0; 28262306a36Sopenharmony_ci pkg.wqe_req.client_data_unit = 0; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci pkg.wqe_req.num_sge = 1 + skb_shinfo(skb)->nr_frags; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP)) 28762306a36Sopenharmony_ci ipv4 = true; 28862306a36Sopenharmony_ci else if (skb->protocol == htons(ETH_P_IPV6)) 28962306a36Sopenharmony_ci ipv6 = true; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (skb_is_gso(skb)) { 29262306a36Sopenharmony_ci int num_sge; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci gso_hs = mana_get_gso_hs(skb); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci num_sge = mana_fix_skb_head(ndev, skb, gso_hs); 29762306a36Sopenharmony_ci if (num_sge > 0) 29862306a36Sopenharmony_ci pkg.wqe_req.num_sge = num_sge; 29962306a36Sopenharmony_ci else 30062306a36Sopenharmony_ci goto tx_drop_count; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci u64_stats_update_begin(&tx_stats->syncp); 30362306a36Sopenharmony_ci if (skb->encapsulation) { 30462306a36Sopenharmony_ci tx_stats->tso_inner_packets++; 30562306a36Sopenharmony_ci tx_stats->tso_inner_bytes += skb->len - gso_hs; 30662306a36Sopenharmony_ci } else { 30762306a36Sopenharmony_ci tx_stats->tso_packets++; 30862306a36Sopenharmony_ci tx_stats->tso_bytes += skb->len - gso_hs; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci u64_stats_update_end(&tx_stats->syncp); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci pkg.tx_oob.s_oob.is_outer_ipv4 = ipv4; 31362306a36Sopenharmony_ci pkg.tx_oob.s_oob.is_outer_ipv6 = ipv6; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci pkg.tx_oob.s_oob.comp_iphdr_csum = 1; 31662306a36Sopenharmony_ci pkg.tx_oob.s_oob.comp_tcp_csum = 1; 31762306a36Sopenharmony_ci pkg.tx_oob.s_oob.trans_off = skb_transport_offset(skb); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci pkg.wqe_req.client_data_unit = skb_shinfo(skb)->gso_size; 32062306a36Sopenharmony_ci pkg.wqe_req.flags = GDMA_WR_OOB_IN_SGL | GDMA_WR_PAD_BY_SGE0; 32162306a36Sopenharmony_ci if (ipv4) { 32262306a36Sopenharmony_ci ip_hdr(skb)->tot_len = 0; 32362306a36Sopenharmony_ci ip_hdr(skb)->check = 0; 32462306a36Sopenharmony_ci tcp_hdr(skb)->check = 32562306a36Sopenharmony_ci ~csum_tcpudp_magic(ip_hdr(skb)->saddr, 32662306a36Sopenharmony_ci ip_hdr(skb)->daddr, 0, 32762306a36Sopenharmony_ci IPPROTO_TCP, 0); 32862306a36Sopenharmony_ci } else { 32962306a36Sopenharmony_ci ipv6_hdr(skb)->payload_len = 0; 33062306a36Sopenharmony_ci tcp_hdr(skb)->check = 33162306a36Sopenharmony_ci ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, 33262306a36Sopenharmony_ci &ipv6_hdr(skb)->daddr, 0, 33362306a36Sopenharmony_ci IPPROTO_TCP, 0); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci } else if (skb->ip_summed == CHECKSUM_PARTIAL) { 33662306a36Sopenharmony_ci csum_type = mana_checksum_info(skb); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci u64_stats_update_begin(&tx_stats->syncp); 33962306a36Sopenharmony_ci tx_stats->csum_partial++; 34062306a36Sopenharmony_ci u64_stats_update_end(&tx_stats->syncp); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (csum_type == IPPROTO_TCP) { 34362306a36Sopenharmony_ci pkg.tx_oob.s_oob.is_outer_ipv4 = ipv4; 34462306a36Sopenharmony_ci pkg.tx_oob.s_oob.is_outer_ipv6 = ipv6; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci pkg.tx_oob.s_oob.comp_tcp_csum = 1; 34762306a36Sopenharmony_ci pkg.tx_oob.s_oob.trans_off = skb_transport_offset(skb); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci } else if (csum_type == IPPROTO_UDP) { 35062306a36Sopenharmony_ci pkg.tx_oob.s_oob.is_outer_ipv4 = ipv4; 35162306a36Sopenharmony_ci pkg.tx_oob.s_oob.is_outer_ipv6 = ipv6; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci pkg.tx_oob.s_oob.comp_udp_csum = 1; 35462306a36Sopenharmony_ci } else { 35562306a36Sopenharmony_ci /* Can't do offload of this type of checksum */ 35662306a36Sopenharmony_ci if (skb_checksum_help(skb)) 35762306a36Sopenharmony_ci goto tx_drop_count; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci WARN_ON_ONCE(pkg.wqe_req.num_sge > MAX_TX_WQE_SGL_ENTRIES); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (pkg.wqe_req.num_sge <= ARRAY_SIZE(pkg.sgl_array)) { 36462306a36Sopenharmony_ci pkg.wqe_req.sgl = pkg.sgl_array; 36562306a36Sopenharmony_ci } else { 36662306a36Sopenharmony_ci pkg.sgl_ptr = kmalloc_array(pkg.wqe_req.num_sge, 36762306a36Sopenharmony_ci sizeof(struct gdma_sge), 36862306a36Sopenharmony_ci GFP_ATOMIC); 36962306a36Sopenharmony_ci if (!pkg.sgl_ptr) 37062306a36Sopenharmony_ci goto tx_drop_count; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci pkg.wqe_req.sgl = pkg.sgl_ptr; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (mana_map_skb(skb, apc, &pkg, gso_hs)) { 37662306a36Sopenharmony_ci u64_stats_update_begin(&tx_stats->syncp); 37762306a36Sopenharmony_ci tx_stats->mana_map_err++; 37862306a36Sopenharmony_ci u64_stats_update_end(&tx_stats->syncp); 37962306a36Sopenharmony_ci goto free_sgl_ptr; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci skb_queue_tail(&txq->pending_skbs, skb); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci len = skb->len; 38562306a36Sopenharmony_ci net_txq = netdev_get_tx_queue(ndev, txq_idx); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci err = mana_gd_post_work_request(gdma_sq, &pkg.wqe_req, 38862306a36Sopenharmony_ci (struct gdma_posted_wqe_info *)skb->cb); 38962306a36Sopenharmony_ci if (!mana_can_tx(gdma_sq)) { 39062306a36Sopenharmony_ci netif_tx_stop_queue(net_txq); 39162306a36Sopenharmony_ci apc->eth_stats.stop_queue++; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (err) { 39562306a36Sopenharmony_ci (void)skb_dequeue_tail(&txq->pending_skbs); 39662306a36Sopenharmony_ci netdev_warn(ndev, "Failed to post TX OOB: %d\n", err); 39762306a36Sopenharmony_ci err = NETDEV_TX_BUSY; 39862306a36Sopenharmony_ci goto tx_busy; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci err = NETDEV_TX_OK; 40262306a36Sopenharmony_ci atomic_inc(&txq->pending_sends); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci mana_gd_wq_ring_doorbell(gd->gdma_context, gdma_sq); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* skb may be freed after mana_gd_post_work_request. Do not use it. */ 40762306a36Sopenharmony_ci skb = NULL; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci tx_stats = &txq->stats; 41062306a36Sopenharmony_ci u64_stats_update_begin(&tx_stats->syncp); 41162306a36Sopenharmony_ci tx_stats->packets++; 41262306a36Sopenharmony_ci tx_stats->bytes += len; 41362306a36Sopenharmony_ci u64_stats_update_end(&tx_stats->syncp); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_citx_busy: 41662306a36Sopenharmony_ci if (netif_tx_queue_stopped(net_txq) && mana_can_tx(gdma_sq)) { 41762306a36Sopenharmony_ci netif_tx_wake_queue(net_txq); 41862306a36Sopenharmony_ci apc->eth_stats.wake_queue++; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci kfree(pkg.sgl_ptr); 42262306a36Sopenharmony_ci return err; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cifree_sgl_ptr: 42562306a36Sopenharmony_ci kfree(pkg.sgl_ptr); 42662306a36Sopenharmony_citx_drop_count: 42762306a36Sopenharmony_ci ndev->stats.tx_dropped++; 42862306a36Sopenharmony_citx_drop: 42962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 43062306a36Sopenharmony_ci return NETDEV_TX_OK; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void mana_get_stats64(struct net_device *ndev, 43462306a36Sopenharmony_ci struct rtnl_link_stats64 *st) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct mana_port_context *apc = netdev_priv(ndev); 43762306a36Sopenharmony_ci unsigned int num_queues = apc->num_queues; 43862306a36Sopenharmony_ci struct mana_stats_rx *rx_stats; 43962306a36Sopenharmony_ci struct mana_stats_tx *tx_stats; 44062306a36Sopenharmony_ci unsigned int start; 44162306a36Sopenharmony_ci u64 packets, bytes; 44262306a36Sopenharmony_ci int q; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (!apc->port_is_up) 44562306a36Sopenharmony_ci return; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci netdev_stats_to_stats64(st, &ndev->stats); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci for (q = 0; q < num_queues; q++) { 45062306a36Sopenharmony_ci rx_stats = &apc->rxqs[q]->stats; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci do { 45362306a36Sopenharmony_ci start = u64_stats_fetch_begin(&rx_stats->syncp); 45462306a36Sopenharmony_ci packets = rx_stats->packets; 45562306a36Sopenharmony_ci bytes = rx_stats->bytes; 45662306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci st->rx_packets += packets; 45962306a36Sopenharmony_ci st->rx_bytes += bytes; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci for (q = 0; q < num_queues; q++) { 46362306a36Sopenharmony_ci tx_stats = &apc->tx_qp[q].txq.stats; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci do { 46662306a36Sopenharmony_ci start = u64_stats_fetch_begin(&tx_stats->syncp); 46762306a36Sopenharmony_ci packets = tx_stats->packets; 46862306a36Sopenharmony_ci bytes = tx_stats->bytes; 46962306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci st->tx_packets += packets; 47262306a36Sopenharmony_ci st->tx_bytes += bytes; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic int mana_get_tx_queue(struct net_device *ndev, struct sk_buff *skb, 47762306a36Sopenharmony_ci int old_q) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct mana_port_context *apc = netdev_priv(ndev); 48062306a36Sopenharmony_ci u32 hash = skb_get_hash(skb); 48162306a36Sopenharmony_ci struct sock *sk = skb->sk; 48262306a36Sopenharmony_ci int txq; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci txq = apc->indir_table[hash & MANA_INDIRECT_TABLE_MASK]; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (txq != old_q && sk && sk_fullsock(sk) && 48762306a36Sopenharmony_ci rcu_access_pointer(sk->sk_dst_cache)) 48862306a36Sopenharmony_ci sk_tx_queue_set(sk, txq); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci return txq; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic u16 mana_select_queue(struct net_device *ndev, struct sk_buff *skb, 49462306a36Sopenharmony_ci struct net_device *sb_dev) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci int txq; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (ndev->real_num_tx_queues == 1) 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci txq = sk_tx_queue_get(skb->sk); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (txq < 0 || skb->ooo_okay || txq >= ndev->real_num_tx_queues) { 50462306a36Sopenharmony_ci if (skb_rx_queue_recorded(skb)) 50562306a36Sopenharmony_ci txq = skb_get_rx_queue(skb); 50662306a36Sopenharmony_ci else 50762306a36Sopenharmony_ci txq = mana_get_tx_queue(ndev, skb, txq); 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci return txq; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci/* Release pre-allocated RX buffers */ 51462306a36Sopenharmony_cistatic void mana_pre_dealloc_rxbufs(struct mana_port_context *mpc) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct device *dev; 51762306a36Sopenharmony_ci int i; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci dev = mpc->ac->gdma_dev->gdma_context->dev; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (!mpc->rxbufs_pre) 52262306a36Sopenharmony_ci goto out1; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (!mpc->das_pre) 52562306a36Sopenharmony_ci goto out2; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci while (mpc->rxbpre_total) { 52862306a36Sopenharmony_ci i = --mpc->rxbpre_total; 52962306a36Sopenharmony_ci dma_unmap_single(dev, mpc->das_pre[i], mpc->rxbpre_datasize, 53062306a36Sopenharmony_ci DMA_FROM_DEVICE); 53162306a36Sopenharmony_ci put_page(virt_to_head_page(mpc->rxbufs_pre[i])); 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci kfree(mpc->das_pre); 53562306a36Sopenharmony_ci mpc->das_pre = NULL; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ciout2: 53862306a36Sopenharmony_ci kfree(mpc->rxbufs_pre); 53962306a36Sopenharmony_ci mpc->rxbufs_pre = NULL; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ciout1: 54262306a36Sopenharmony_ci mpc->rxbpre_datasize = 0; 54362306a36Sopenharmony_ci mpc->rxbpre_alloc_size = 0; 54462306a36Sopenharmony_ci mpc->rxbpre_headroom = 0; 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci/* Get a buffer from the pre-allocated RX buffers */ 54862306a36Sopenharmony_cistatic void *mana_get_rxbuf_pre(struct mana_rxq *rxq, dma_addr_t *da) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct net_device *ndev = rxq->ndev; 55162306a36Sopenharmony_ci struct mana_port_context *mpc; 55262306a36Sopenharmony_ci void *va; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci mpc = netdev_priv(ndev); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (!mpc->rxbufs_pre || !mpc->das_pre || !mpc->rxbpre_total) { 55762306a36Sopenharmony_ci netdev_err(ndev, "No RX pre-allocated bufs\n"); 55862306a36Sopenharmony_ci return NULL; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* Check sizes to catch unexpected coding error */ 56262306a36Sopenharmony_ci if (mpc->rxbpre_datasize != rxq->datasize) { 56362306a36Sopenharmony_ci netdev_err(ndev, "rxbpre_datasize mismatch: %u: %u\n", 56462306a36Sopenharmony_ci mpc->rxbpre_datasize, rxq->datasize); 56562306a36Sopenharmony_ci return NULL; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (mpc->rxbpre_alloc_size != rxq->alloc_size) { 56962306a36Sopenharmony_ci netdev_err(ndev, "rxbpre_alloc_size mismatch: %u: %u\n", 57062306a36Sopenharmony_ci mpc->rxbpre_alloc_size, rxq->alloc_size); 57162306a36Sopenharmony_ci return NULL; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (mpc->rxbpre_headroom != rxq->headroom) { 57562306a36Sopenharmony_ci netdev_err(ndev, "rxbpre_headroom mismatch: %u: %u\n", 57662306a36Sopenharmony_ci mpc->rxbpre_headroom, rxq->headroom); 57762306a36Sopenharmony_ci return NULL; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci mpc->rxbpre_total--; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci *da = mpc->das_pre[mpc->rxbpre_total]; 58362306a36Sopenharmony_ci va = mpc->rxbufs_pre[mpc->rxbpre_total]; 58462306a36Sopenharmony_ci mpc->rxbufs_pre[mpc->rxbpre_total] = NULL; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* Deallocate the array after all buffers are gone */ 58762306a36Sopenharmony_ci if (!mpc->rxbpre_total) 58862306a36Sopenharmony_ci mana_pre_dealloc_rxbufs(mpc); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return va; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci/* Get RX buffer's data size, alloc size, XDP headroom based on MTU */ 59462306a36Sopenharmony_cistatic void mana_get_rxbuf_cfg(int mtu, u32 *datasize, u32 *alloc_size, 59562306a36Sopenharmony_ci u32 *headroom) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci if (mtu > MANA_XDP_MTU_MAX) 59862306a36Sopenharmony_ci *headroom = 0; /* no support for XDP */ 59962306a36Sopenharmony_ci else 60062306a36Sopenharmony_ci *headroom = XDP_PACKET_HEADROOM; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci *alloc_size = mtu + MANA_RXBUF_PAD + *headroom; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci *datasize = ALIGN(mtu + ETH_HLEN, MANA_RX_DATA_ALIGN); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic int mana_pre_alloc_rxbufs(struct mana_port_context *mpc, int new_mtu) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci struct device *dev; 61062306a36Sopenharmony_ci struct page *page; 61162306a36Sopenharmony_ci dma_addr_t da; 61262306a36Sopenharmony_ci int num_rxb; 61362306a36Sopenharmony_ci void *va; 61462306a36Sopenharmony_ci int i; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci mana_get_rxbuf_cfg(new_mtu, &mpc->rxbpre_datasize, 61762306a36Sopenharmony_ci &mpc->rxbpre_alloc_size, &mpc->rxbpre_headroom); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci dev = mpc->ac->gdma_dev->gdma_context->dev; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci num_rxb = mpc->num_queues * RX_BUFFERS_PER_QUEUE; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci WARN(mpc->rxbufs_pre, "mana rxbufs_pre exists\n"); 62462306a36Sopenharmony_ci mpc->rxbufs_pre = kmalloc_array(num_rxb, sizeof(void *), GFP_KERNEL); 62562306a36Sopenharmony_ci if (!mpc->rxbufs_pre) 62662306a36Sopenharmony_ci goto error; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci mpc->das_pre = kmalloc_array(num_rxb, sizeof(dma_addr_t), GFP_KERNEL); 62962306a36Sopenharmony_ci if (!mpc->das_pre) 63062306a36Sopenharmony_ci goto error; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci mpc->rxbpre_total = 0; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci for (i = 0; i < num_rxb; i++) { 63562306a36Sopenharmony_ci if (mpc->rxbpre_alloc_size > PAGE_SIZE) { 63662306a36Sopenharmony_ci va = netdev_alloc_frag(mpc->rxbpre_alloc_size); 63762306a36Sopenharmony_ci if (!va) 63862306a36Sopenharmony_ci goto error; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci page = virt_to_head_page(va); 64162306a36Sopenharmony_ci /* Check if the frag falls back to single page */ 64262306a36Sopenharmony_ci if (compound_order(page) < 64362306a36Sopenharmony_ci get_order(mpc->rxbpre_alloc_size)) { 64462306a36Sopenharmony_ci put_page(page); 64562306a36Sopenharmony_ci goto error; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci } else { 64862306a36Sopenharmony_ci page = dev_alloc_page(); 64962306a36Sopenharmony_ci if (!page) 65062306a36Sopenharmony_ci goto error; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci va = page_to_virt(page); 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci da = dma_map_single(dev, va + mpc->rxbpre_headroom, 65662306a36Sopenharmony_ci mpc->rxbpre_datasize, DMA_FROM_DEVICE); 65762306a36Sopenharmony_ci if (dma_mapping_error(dev, da)) { 65862306a36Sopenharmony_ci put_page(virt_to_head_page(va)); 65962306a36Sopenharmony_ci goto error; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci mpc->rxbufs_pre[i] = va; 66362306a36Sopenharmony_ci mpc->das_pre[i] = da; 66462306a36Sopenharmony_ci mpc->rxbpre_total = i + 1; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cierror: 67062306a36Sopenharmony_ci mana_pre_dealloc_rxbufs(mpc); 67162306a36Sopenharmony_ci return -ENOMEM; 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic int mana_change_mtu(struct net_device *ndev, int new_mtu) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci struct mana_port_context *mpc = netdev_priv(ndev); 67762306a36Sopenharmony_ci unsigned int old_mtu = ndev->mtu; 67862306a36Sopenharmony_ci int err; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci /* Pre-allocate buffers to prevent failure in mana_attach later */ 68162306a36Sopenharmony_ci err = mana_pre_alloc_rxbufs(mpc, new_mtu); 68262306a36Sopenharmony_ci if (err) { 68362306a36Sopenharmony_ci netdev_err(ndev, "Insufficient memory for new MTU\n"); 68462306a36Sopenharmony_ci return err; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci err = mana_detach(ndev, false); 68862306a36Sopenharmony_ci if (err) { 68962306a36Sopenharmony_ci netdev_err(ndev, "mana_detach failed: %d\n", err); 69062306a36Sopenharmony_ci goto out; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci ndev->mtu = new_mtu; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci err = mana_attach(ndev); 69662306a36Sopenharmony_ci if (err) { 69762306a36Sopenharmony_ci netdev_err(ndev, "mana_attach failed: %d\n", err); 69862306a36Sopenharmony_ci ndev->mtu = old_mtu; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ciout: 70262306a36Sopenharmony_ci mana_pre_dealloc_rxbufs(mpc); 70362306a36Sopenharmony_ci return err; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic const struct net_device_ops mana_devops = { 70762306a36Sopenharmony_ci .ndo_open = mana_open, 70862306a36Sopenharmony_ci .ndo_stop = mana_close, 70962306a36Sopenharmony_ci .ndo_select_queue = mana_select_queue, 71062306a36Sopenharmony_ci .ndo_start_xmit = mana_start_xmit, 71162306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 71262306a36Sopenharmony_ci .ndo_get_stats64 = mana_get_stats64, 71362306a36Sopenharmony_ci .ndo_bpf = mana_bpf, 71462306a36Sopenharmony_ci .ndo_xdp_xmit = mana_xdp_xmit, 71562306a36Sopenharmony_ci .ndo_change_mtu = mana_change_mtu, 71662306a36Sopenharmony_ci}; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistatic void mana_cleanup_port_context(struct mana_port_context *apc) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci kfree(apc->rxqs); 72162306a36Sopenharmony_ci apc->rxqs = NULL; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int mana_init_port_context(struct mana_port_context *apc) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci apc->rxqs = kcalloc(apc->num_queues, sizeof(struct mana_rxq *), 72762306a36Sopenharmony_ci GFP_KERNEL); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci return !apc->rxqs ? -ENOMEM : 0; 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic int mana_send_request(struct mana_context *ac, void *in_buf, 73362306a36Sopenharmony_ci u32 in_len, void *out_buf, u32 out_len) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci struct gdma_context *gc = ac->gdma_dev->gdma_context; 73662306a36Sopenharmony_ci struct gdma_resp_hdr *resp = out_buf; 73762306a36Sopenharmony_ci struct gdma_req_hdr *req = in_buf; 73862306a36Sopenharmony_ci struct device *dev = gc->dev; 73962306a36Sopenharmony_ci static atomic_t activity_id; 74062306a36Sopenharmony_ci int err; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci req->dev_id = gc->mana.dev_id; 74362306a36Sopenharmony_ci req->activity_id = atomic_inc_return(&activity_id); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci err = mana_gd_send_request(gc, in_len, in_buf, out_len, 74662306a36Sopenharmony_ci out_buf); 74762306a36Sopenharmony_ci if (err || resp->status) { 74862306a36Sopenharmony_ci dev_err(dev, "Failed to send mana message: %d, 0x%x\n", 74962306a36Sopenharmony_ci err, resp->status); 75062306a36Sopenharmony_ci return err ? err : -EPROTO; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (req->dev_id.as_uint32 != resp->dev_id.as_uint32 || 75462306a36Sopenharmony_ci req->activity_id != resp->activity_id) { 75562306a36Sopenharmony_ci dev_err(dev, "Unexpected mana message response: %x,%x,%x,%x\n", 75662306a36Sopenharmony_ci req->dev_id.as_uint32, resp->dev_id.as_uint32, 75762306a36Sopenharmony_ci req->activity_id, resp->activity_id); 75862306a36Sopenharmony_ci return -EPROTO; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci return 0; 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic int mana_verify_resp_hdr(const struct gdma_resp_hdr *resp_hdr, 76562306a36Sopenharmony_ci const enum mana_command_code expected_code, 76662306a36Sopenharmony_ci const u32 min_size) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci if (resp_hdr->response.msg_type != expected_code) 76962306a36Sopenharmony_ci return -EPROTO; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (resp_hdr->response.msg_version < GDMA_MESSAGE_V1) 77262306a36Sopenharmony_ci return -EPROTO; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (resp_hdr->response.msg_size < min_size) 77562306a36Sopenharmony_ci return -EPROTO; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return 0; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic int mana_pf_register_hw_vport(struct mana_port_context *apc) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci struct mana_register_hw_vport_resp resp = {}; 78362306a36Sopenharmony_ci struct mana_register_hw_vport_req req = {}; 78462306a36Sopenharmony_ci int err; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, MANA_REGISTER_HW_PORT, 78762306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 78862306a36Sopenharmony_ci req.attached_gfid = 1; 78962306a36Sopenharmony_ci req.is_pf_default_vport = 1; 79062306a36Sopenharmony_ci req.allow_all_ether_types = 1; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 79362306a36Sopenharmony_ci sizeof(resp)); 79462306a36Sopenharmony_ci if (err) { 79562306a36Sopenharmony_ci netdev_err(apc->ndev, "Failed to register hw vPort: %d\n", err); 79662306a36Sopenharmony_ci return err; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci err = mana_verify_resp_hdr(&resp.hdr, MANA_REGISTER_HW_PORT, 80062306a36Sopenharmony_ci sizeof(resp)); 80162306a36Sopenharmony_ci if (err || resp.hdr.status) { 80262306a36Sopenharmony_ci netdev_err(apc->ndev, "Failed to register hw vPort: %d, 0x%x\n", 80362306a36Sopenharmony_ci err, resp.hdr.status); 80462306a36Sopenharmony_ci return err ? err : -EPROTO; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci apc->port_handle = resp.hw_vport_handle; 80862306a36Sopenharmony_ci return 0; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic void mana_pf_deregister_hw_vport(struct mana_port_context *apc) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci struct mana_deregister_hw_vport_resp resp = {}; 81462306a36Sopenharmony_ci struct mana_deregister_hw_vport_req req = {}; 81562306a36Sopenharmony_ci int err; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, MANA_DEREGISTER_HW_PORT, 81862306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 81962306a36Sopenharmony_ci req.hw_vport_handle = apc->port_handle; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 82262306a36Sopenharmony_ci sizeof(resp)); 82362306a36Sopenharmony_ci if (err) { 82462306a36Sopenharmony_ci netdev_err(apc->ndev, "Failed to unregister hw vPort: %d\n", 82562306a36Sopenharmony_ci err); 82662306a36Sopenharmony_ci return; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci err = mana_verify_resp_hdr(&resp.hdr, MANA_DEREGISTER_HW_PORT, 83062306a36Sopenharmony_ci sizeof(resp)); 83162306a36Sopenharmony_ci if (err || resp.hdr.status) 83262306a36Sopenharmony_ci netdev_err(apc->ndev, 83362306a36Sopenharmony_ci "Failed to deregister hw vPort: %d, 0x%x\n", 83462306a36Sopenharmony_ci err, resp.hdr.status); 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic int mana_pf_register_filter(struct mana_port_context *apc) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci struct mana_register_filter_resp resp = {}; 84062306a36Sopenharmony_ci struct mana_register_filter_req req = {}; 84162306a36Sopenharmony_ci int err; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, MANA_REGISTER_FILTER, 84462306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 84562306a36Sopenharmony_ci req.vport = apc->port_handle; 84662306a36Sopenharmony_ci memcpy(req.mac_addr, apc->mac_addr, ETH_ALEN); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 84962306a36Sopenharmony_ci sizeof(resp)); 85062306a36Sopenharmony_ci if (err) { 85162306a36Sopenharmony_ci netdev_err(apc->ndev, "Failed to register filter: %d\n", err); 85262306a36Sopenharmony_ci return err; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci err = mana_verify_resp_hdr(&resp.hdr, MANA_REGISTER_FILTER, 85662306a36Sopenharmony_ci sizeof(resp)); 85762306a36Sopenharmony_ci if (err || resp.hdr.status) { 85862306a36Sopenharmony_ci netdev_err(apc->ndev, "Failed to register filter: %d, 0x%x\n", 85962306a36Sopenharmony_ci err, resp.hdr.status); 86062306a36Sopenharmony_ci return err ? err : -EPROTO; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci apc->pf_filter_handle = resp.filter_handle; 86462306a36Sopenharmony_ci return 0; 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic void mana_pf_deregister_filter(struct mana_port_context *apc) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci struct mana_deregister_filter_resp resp = {}; 87062306a36Sopenharmony_ci struct mana_deregister_filter_req req = {}; 87162306a36Sopenharmony_ci int err; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, MANA_DEREGISTER_FILTER, 87462306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 87562306a36Sopenharmony_ci req.filter_handle = apc->pf_filter_handle; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 87862306a36Sopenharmony_ci sizeof(resp)); 87962306a36Sopenharmony_ci if (err) { 88062306a36Sopenharmony_ci netdev_err(apc->ndev, "Failed to unregister filter: %d\n", 88162306a36Sopenharmony_ci err); 88262306a36Sopenharmony_ci return; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci err = mana_verify_resp_hdr(&resp.hdr, MANA_DEREGISTER_FILTER, 88662306a36Sopenharmony_ci sizeof(resp)); 88762306a36Sopenharmony_ci if (err || resp.hdr.status) 88862306a36Sopenharmony_ci netdev_err(apc->ndev, 88962306a36Sopenharmony_ci "Failed to deregister filter: %d, 0x%x\n", 89062306a36Sopenharmony_ci err, resp.hdr.status); 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_cistatic int mana_query_device_cfg(struct mana_context *ac, u32 proto_major_ver, 89462306a36Sopenharmony_ci u32 proto_minor_ver, u32 proto_micro_ver, 89562306a36Sopenharmony_ci u16 *max_num_vports) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci struct gdma_context *gc = ac->gdma_dev->gdma_context; 89862306a36Sopenharmony_ci struct mana_query_device_cfg_resp resp = {}; 89962306a36Sopenharmony_ci struct mana_query_device_cfg_req req = {}; 90062306a36Sopenharmony_ci struct device *dev = gc->dev; 90162306a36Sopenharmony_ci int err = 0; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_DEV_CONFIG, 90462306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci req.hdr.resp.msg_version = GDMA_MESSAGE_V2; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci req.proto_major_ver = proto_major_ver; 90962306a36Sopenharmony_ci req.proto_minor_ver = proto_minor_ver; 91062306a36Sopenharmony_ci req.proto_micro_ver = proto_micro_ver; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci err = mana_send_request(ac, &req, sizeof(req), &resp, sizeof(resp)); 91362306a36Sopenharmony_ci if (err) { 91462306a36Sopenharmony_ci dev_err(dev, "Failed to query config: %d", err); 91562306a36Sopenharmony_ci return err; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_DEV_CONFIG, 91962306a36Sopenharmony_ci sizeof(resp)); 92062306a36Sopenharmony_ci if (err || resp.hdr.status) { 92162306a36Sopenharmony_ci dev_err(dev, "Invalid query result: %d, 0x%x\n", err, 92262306a36Sopenharmony_ci resp.hdr.status); 92362306a36Sopenharmony_ci if (!err) 92462306a36Sopenharmony_ci err = -EPROTO; 92562306a36Sopenharmony_ci return err; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci *max_num_vports = resp.max_num_vports; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (resp.hdr.response.msg_version == GDMA_MESSAGE_V2) 93162306a36Sopenharmony_ci gc->adapter_mtu = resp.adapter_mtu; 93262306a36Sopenharmony_ci else 93362306a36Sopenharmony_ci gc->adapter_mtu = ETH_FRAME_LEN; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci return 0; 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_cistatic int mana_query_vport_cfg(struct mana_port_context *apc, u32 vport_index, 93962306a36Sopenharmony_ci u32 *max_sq, u32 *max_rq, u32 *num_indir_entry) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci struct mana_query_vport_cfg_resp resp = {}; 94262306a36Sopenharmony_ci struct mana_query_vport_cfg_req req = {}; 94362306a36Sopenharmony_ci int err; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_VPORT_CONFIG, 94662306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci req.vport_index = vport_index; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 95162306a36Sopenharmony_ci sizeof(resp)); 95262306a36Sopenharmony_ci if (err) 95362306a36Sopenharmony_ci return err; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_VPORT_CONFIG, 95662306a36Sopenharmony_ci sizeof(resp)); 95762306a36Sopenharmony_ci if (err) 95862306a36Sopenharmony_ci return err; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (resp.hdr.status) 96162306a36Sopenharmony_ci return -EPROTO; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci *max_sq = resp.max_num_sq; 96462306a36Sopenharmony_ci *max_rq = resp.max_num_rq; 96562306a36Sopenharmony_ci *num_indir_entry = resp.num_indirection_ent; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci apc->port_handle = resp.vport; 96862306a36Sopenharmony_ci ether_addr_copy(apc->mac_addr, resp.mac_addr); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci return 0; 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_civoid mana_uncfg_vport(struct mana_port_context *apc) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci mutex_lock(&apc->vport_mutex); 97662306a36Sopenharmony_ci apc->vport_use_count--; 97762306a36Sopenharmony_ci WARN_ON(apc->vport_use_count < 0); 97862306a36Sopenharmony_ci mutex_unlock(&apc->vport_mutex); 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ciEXPORT_SYMBOL_NS(mana_uncfg_vport, NET_MANA); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ciint mana_cfg_vport(struct mana_port_context *apc, u32 protection_dom_id, 98362306a36Sopenharmony_ci u32 doorbell_pg_id) 98462306a36Sopenharmony_ci{ 98562306a36Sopenharmony_ci struct mana_config_vport_resp resp = {}; 98662306a36Sopenharmony_ci struct mana_config_vport_req req = {}; 98762306a36Sopenharmony_ci int err; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci /* This function is used to program the Ethernet port in the hardware 99062306a36Sopenharmony_ci * table. It can be called from the Ethernet driver or the RDMA driver. 99162306a36Sopenharmony_ci * 99262306a36Sopenharmony_ci * For Ethernet usage, the hardware supports only one active user on a 99362306a36Sopenharmony_ci * physical port. The driver checks on the port usage before programming 99462306a36Sopenharmony_ci * the hardware when creating the RAW QP (RDMA driver) or exposing the 99562306a36Sopenharmony_ci * device to kernel NET layer (Ethernet driver). 99662306a36Sopenharmony_ci * 99762306a36Sopenharmony_ci * Because the RDMA driver doesn't know in advance which QP type the 99862306a36Sopenharmony_ci * user will create, it exposes the device with all its ports. The user 99962306a36Sopenharmony_ci * may not be able to create RAW QP on a port if this port is already 100062306a36Sopenharmony_ci * in used by the Ethernet driver from the kernel. 100162306a36Sopenharmony_ci * 100262306a36Sopenharmony_ci * This physical port limitation only applies to the RAW QP. For RC QP, 100362306a36Sopenharmony_ci * the hardware doesn't have this limitation. The user can create RC 100462306a36Sopenharmony_ci * QPs on a physical port up to the hardware limits independent of the 100562306a36Sopenharmony_ci * Ethernet usage on the same port. 100662306a36Sopenharmony_ci */ 100762306a36Sopenharmony_ci mutex_lock(&apc->vport_mutex); 100862306a36Sopenharmony_ci if (apc->vport_use_count > 0) { 100962306a36Sopenharmony_ci mutex_unlock(&apc->vport_mutex); 101062306a36Sopenharmony_ci return -EBUSY; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci apc->vport_use_count++; 101362306a36Sopenharmony_ci mutex_unlock(&apc->vport_mutex); 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, MANA_CONFIG_VPORT_TX, 101662306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 101762306a36Sopenharmony_ci req.vport = apc->port_handle; 101862306a36Sopenharmony_ci req.pdid = protection_dom_id; 101962306a36Sopenharmony_ci req.doorbell_pageid = doorbell_pg_id; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 102262306a36Sopenharmony_ci sizeof(resp)); 102362306a36Sopenharmony_ci if (err) { 102462306a36Sopenharmony_ci netdev_err(apc->ndev, "Failed to configure vPort: %d\n", err); 102562306a36Sopenharmony_ci goto out; 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci err = mana_verify_resp_hdr(&resp.hdr, MANA_CONFIG_VPORT_TX, 102962306a36Sopenharmony_ci sizeof(resp)); 103062306a36Sopenharmony_ci if (err || resp.hdr.status) { 103162306a36Sopenharmony_ci netdev_err(apc->ndev, "Failed to configure vPort: %d, 0x%x\n", 103262306a36Sopenharmony_ci err, resp.hdr.status); 103362306a36Sopenharmony_ci if (!err) 103462306a36Sopenharmony_ci err = -EPROTO; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci goto out; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci apc->tx_shortform_allowed = resp.short_form_allowed; 104062306a36Sopenharmony_ci apc->tx_vp_offset = resp.tx_vport_offset; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci netdev_info(apc->ndev, "Configured vPort %llu PD %u DB %u\n", 104362306a36Sopenharmony_ci apc->port_handle, protection_dom_id, doorbell_pg_id); 104462306a36Sopenharmony_ciout: 104562306a36Sopenharmony_ci if (err) 104662306a36Sopenharmony_ci mana_uncfg_vport(apc); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci return err; 104962306a36Sopenharmony_ci} 105062306a36Sopenharmony_ciEXPORT_SYMBOL_NS(mana_cfg_vport, NET_MANA); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic int mana_cfg_vport_steering(struct mana_port_context *apc, 105362306a36Sopenharmony_ci enum TRI_STATE rx, 105462306a36Sopenharmony_ci bool update_default_rxobj, bool update_key, 105562306a36Sopenharmony_ci bool update_tab) 105662306a36Sopenharmony_ci{ 105762306a36Sopenharmony_ci u16 num_entries = MANA_INDIRECT_TABLE_SIZE; 105862306a36Sopenharmony_ci struct mana_cfg_rx_steer_req_v2 *req; 105962306a36Sopenharmony_ci struct mana_cfg_rx_steer_resp resp = {}; 106062306a36Sopenharmony_ci struct net_device *ndev = apc->ndev; 106162306a36Sopenharmony_ci mana_handle_t *req_indir_tab; 106262306a36Sopenharmony_ci u32 req_buf_size; 106362306a36Sopenharmony_ci int err; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci req_buf_size = sizeof(*req) + sizeof(mana_handle_t) * num_entries; 106662306a36Sopenharmony_ci req = kzalloc(req_buf_size, GFP_KERNEL); 106762306a36Sopenharmony_ci if (!req) 106862306a36Sopenharmony_ci return -ENOMEM; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci mana_gd_init_req_hdr(&req->hdr, MANA_CONFIG_VPORT_RX, req_buf_size, 107162306a36Sopenharmony_ci sizeof(resp)); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci req->hdr.req.msg_version = GDMA_MESSAGE_V2; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci req->vport = apc->port_handle; 107662306a36Sopenharmony_ci req->num_indir_entries = num_entries; 107762306a36Sopenharmony_ci req->indir_tab_offset = sizeof(*req); 107862306a36Sopenharmony_ci req->rx_enable = rx; 107962306a36Sopenharmony_ci req->rss_enable = apc->rss_state; 108062306a36Sopenharmony_ci req->update_default_rxobj = update_default_rxobj; 108162306a36Sopenharmony_ci req->update_hashkey = update_key; 108262306a36Sopenharmony_ci req->update_indir_tab = update_tab; 108362306a36Sopenharmony_ci req->default_rxobj = apc->default_rxobj; 108462306a36Sopenharmony_ci req->cqe_coalescing_enable = 0; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (update_key) 108762306a36Sopenharmony_ci memcpy(&req->hashkey, apc->hashkey, MANA_HASH_KEY_SIZE); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (update_tab) { 109062306a36Sopenharmony_ci req_indir_tab = (mana_handle_t *)(req + 1); 109162306a36Sopenharmony_ci memcpy(req_indir_tab, apc->rxobj_table, 109262306a36Sopenharmony_ci req->num_indir_entries * sizeof(mana_handle_t)); 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci err = mana_send_request(apc->ac, req, req_buf_size, &resp, 109662306a36Sopenharmony_ci sizeof(resp)); 109762306a36Sopenharmony_ci if (err) { 109862306a36Sopenharmony_ci netdev_err(ndev, "Failed to configure vPort RX: %d\n", err); 109962306a36Sopenharmony_ci goto out; 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci err = mana_verify_resp_hdr(&resp.hdr, MANA_CONFIG_VPORT_RX, 110362306a36Sopenharmony_ci sizeof(resp)); 110462306a36Sopenharmony_ci if (err) { 110562306a36Sopenharmony_ci netdev_err(ndev, "vPort RX configuration failed: %d\n", err); 110662306a36Sopenharmony_ci goto out; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci if (resp.hdr.status) { 111062306a36Sopenharmony_ci netdev_err(ndev, "vPort RX configuration failed: 0x%x\n", 111162306a36Sopenharmony_ci resp.hdr.status); 111262306a36Sopenharmony_ci err = -EPROTO; 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci netdev_info(ndev, "Configured steering vPort %llu entries %u\n", 111662306a36Sopenharmony_ci apc->port_handle, num_entries); 111762306a36Sopenharmony_ciout: 111862306a36Sopenharmony_ci kfree(req); 111962306a36Sopenharmony_ci return err; 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ciint mana_create_wq_obj(struct mana_port_context *apc, 112362306a36Sopenharmony_ci mana_handle_t vport, 112462306a36Sopenharmony_ci u32 wq_type, struct mana_obj_spec *wq_spec, 112562306a36Sopenharmony_ci struct mana_obj_spec *cq_spec, 112662306a36Sopenharmony_ci mana_handle_t *wq_obj) 112762306a36Sopenharmony_ci{ 112862306a36Sopenharmony_ci struct mana_create_wqobj_resp resp = {}; 112962306a36Sopenharmony_ci struct mana_create_wqobj_req req = {}; 113062306a36Sopenharmony_ci struct net_device *ndev = apc->ndev; 113162306a36Sopenharmony_ci int err; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, MANA_CREATE_WQ_OBJ, 113462306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 113562306a36Sopenharmony_ci req.vport = vport; 113662306a36Sopenharmony_ci req.wq_type = wq_type; 113762306a36Sopenharmony_ci req.wq_gdma_region = wq_spec->gdma_region; 113862306a36Sopenharmony_ci req.cq_gdma_region = cq_spec->gdma_region; 113962306a36Sopenharmony_ci req.wq_size = wq_spec->queue_size; 114062306a36Sopenharmony_ci req.cq_size = cq_spec->queue_size; 114162306a36Sopenharmony_ci req.cq_moderation_ctx_id = cq_spec->modr_ctx_id; 114262306a36Sopenharmony_ci req.cq_parent_qid = cq_spec->attached_eq; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 114562306a36Sopenharmony_ci sizeof(resp)); 114662306a36Sopenharmony_ci if (err) { 114762306a36Sopenharmony_ci netdev_err(ndev, "Failed to create WQ object: %d\n", err); 114862306a36Sopenharmony_ci goto out; 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci err = mana_verify_resp_hdr(&resp.hdr, MANA_CREATE_WQ_OBJ, 115262306a36Sopenharmony_ci sizeof(resp)); 115362306a36Sopenharmony_ci if (err || resp.hdr.status) { 115462306a36Sopenharmony_ci netdev_err(ndev, "Failed to create WQ object: %d, 0x%x\n", err, 115562306a36Sopenharmony_ci resp.hdr.status); 115662306a36Sopenharmony_ci if (!err) 115762306a36Sopenharmony_ci err = -EPROTO; 115862306a36Sopenharmony_ci goto out; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci if (resp.wq_obj == INVALID_MANA_HANDLE) { 116262306a36Sopenharmony_ci netdev_err(ndev, "Got an invalid WQ object handle\n"); 116362306a36Sopenharmony_ci err = -EPROTO; 116462306a36Sopenharmony_ci goto out; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci *wq_obj = resp.wq_obj; 116862306a36Sopenharmony_ci wq_spec->queue_index = resp.wq_id; 116962306a36Sopenharmony_ci cq_spec->queue_index = resp.cq_id; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci return 0; 117262306a36Sopenharmony_ciout: 117362306a36Sopenharmony_ci return err; 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ciEXPORT_SYMBOL_NS(mana_create_wq_obj, NET_MANA); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_civoid mana_destroy_wq_obj(struct mana_port_context *apc, u32 wq_type, 117862306a36Sopenharmony_ci mana_handle_t wq_obj) 117962306a36Sopenharmony_ci{ 118062306a36Sopenharmony_ci struct mana_destroy_wqobj_resp resp = {}; 118162306a36Sopenharmony_ci struct mana_destroy_wqobj_req req = {}; 118262306a36Sopenharmony_ci struct net_device *ndev = apc->ndev; 118362306a36Sopenharmony_ci int err; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, MANA_DESTROY_WQ_OBJ, 118662306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 118762306a36Sopenharmony_ci req.wq_type = wq_type; 118862306a36Sopenharmony_ci req.wq_obj_handle = wq_obj; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 119162306a36Sopenharmony_ci sizeof(resp)); 119262306a36Sopenharmony_ci if (err) { 119362306a36Sopenharmony_ci netdev_err(ndev, "Failed to destroy WQ object: %d\n", err); 119462306a36Sopenharmony_ci return; 119562306a36Sopenharmony_ci } 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci err = mana_verify_resp_hdr(&resp.hdr, MANA_DESTROY_WQ_OBJ, 119862306a36Sopenharmony_ci sizeof(resp)); 119962306a36Sopenharmony_ci if (err || resp.hdr.status) 120062306a36Sopenharmony_ci netdev_err(ndev, "Failed to destroy WQ object: %d, 0x%x\n", err, 120162306a36Sopenharmony_ci resp.hdr.status); 120262306a36Sopenharmony_ci} 120362306a36Sopenharmony_ciEXPORT_SYMBOL_NS(mana_destroy_wq_obj, NET_MANA); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_cistatic void mana_destroy_eq(struct mana_context *ac) 120662306a36Sopenharmony_ci{ 120762306a36Sopenharmony_ci struct gdma_context *gc = ac->gdma_dev->gdma_context; 120862306a36Sopenharmony_ci struct gdma_queue *eq; 120962306a36Sopenharmony_ci int i; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci if (!ac->eqs) 121262306a36Sopenharmony_ci return; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci for (i = 0; i < gc->max_num_queues; i++) { 121562306a36Sopenharmony_ci eq = ac->eqs[i].eq; 121662306a36Sopenharmony_ci if (!eq) 121762306a36Sopenharmony_ci continue; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci mana_gd_destroy_queue(gc, eq); 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci kfree(ac->eqs); 122362306a36Sopenharmony_ci ac->eqs = NULL; 122462306a36Sopenharmony_ci} 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_cistatic int mana_create_eq(struct mana_context *ac) 122762306a36Sopenharmony_ci{ 122862306a36Sopenharmony_ci struct gdma_dev *gd = ac->gdma_dev; 122962306a36Sopenharmony_ci struct gdma_context *gc = gd->gdma_context; 123062306a36Sopenharmony_ci struct gdma_queue_spec spec = {}; 123162306a36Sopenharmony_ci int err; 123262306a36Sopenharmony_ci int i; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci ac->eqs = kcalloc(gc->max_num_queues, sizeof(struct mana_eq), 123562306a36Sopenharmony_ci GFP_KERNEL); 123662306a36Sopenharmony_ci if (!ac->eqs) 123762306a36Sopenharmony_ci return -ENOMEM; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci spec.type = GDMA_EQ; 124062306a36Sopenharmony_ci spec.monitor_avl_buf = false; 124162306a36Sopenharmony_ci spec.queue_size = EQ_SIZE; 124262306a36Sopenharmony_ci spec.eq.callback = NULL; 124362306a36Sopenharmony_ci spec.eq.context = ac->eqs; 124462306a36Sopenharmony_ci spec.eq.log2_throttle_limit = LOG2_EQ_THROTTLE; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci for (i = 0; i < gc->max_num_queues; i++) { 124762306a36Sopenharmony_ci err = mana_gd_create_mana_eq(gd, &spec, &ac->eqs[i].eq); 124862306a36Sopenharmony_ci if (err) 124962306a36Sopenharmony_ci goto out; 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci return 0; 125362306a36Sopenharmony_ciout: 125462306a36Sopenharmony_ci mana_destroy_eq(ac); 125562306a36Sopenharmony_ci return err; 125662306a36Sopenharmony_ci} 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_cistatic int mana_fence_rq(struct mana_port_context *apc, struct mana_rxq *rxq) 125962306a36Sopenharmony_ci{ 126062306a36Sopenharmony_ci struct mana_fence_rq_resp resp = {}; 126162306a36Sopenharmony_ci struct mana_fence_rq_req req = {}; 126262306a36Sopenharmony_ci int err; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci init_completion(&rxq->fence_event); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, MANA_FENCE_RQ, 126762306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 126862306a36Sopenharmony_ci req.wq_obj_handle = rxq->rxobj; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 127162306a36Sopenharmony_ci sizeof(resp)); 127262306a36Sopenharmony_ci if (err) { 127362306a36Sopenharmony_ci netdev_err(apc->ndev, "Failed to fence RQ %u: %d\n", 127462306a36Sopenharmony_ci rxq->rxq_idx, err); 127562306a36Sopenharmony_ci return err; 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci err = mana_verify_resp_hdr(&resp.hdr, MANA_FENCE_RQ, sizeof(resp)); 127962306a36Sopenharmony_ci if (err || resp.hdr.status) { 128062306a36Sopenharmony_ci netdev_err(apc->ndev, "Failed to fence RQ %u: %d, 0x%x\n", 128162306a36Sopenharmony_ci rxq->rxq_idx, err, resp.hdr.status); 128262306a36Sopenharmony_ci if (!err) 128362306a36Sopenharmony_ci err = -EPROTO; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci return err; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (wait_for_completion_timeout(&rxq->fence_event, 10 * HZ) == 0) { 128962306a36Sopenharmony_ci netdev_err(apc->ndev, "Failed to fence RQ %u: timed out\n", 129062306a36Sopenharmony_ci rxq->rxq_idx); 129162306a36Sopenharmony_ci return -ETIMEDOUT; 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci return 0; 129562306a36Sopenharmony_ci} 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_cistatic void mana_fence_rqs(struct mana_port_context *apc) 129862306a36Sopenharmony_ci{ 129962306a36Sopenharmony_ci unsigned int rxq_idx; 130062306a36Sopenharmony_ci struct mana_rxq *rxq; 130162306a36Sopenharmony_ci int err; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { 130462306a36Sopenharmony_ci rxq = apc->rxqs[rxq_idx]; 130562306a36Sopenharmony_ci err = mana_fence_rq(apc, rxq); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci /* In case of any error, use sleep instead. */ 130862306a36Sopenharmony_ci if (err) 130962306a36Sopenharmony_ci msleep(100); 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci} 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_cistatic int mana_move_wq_tail(struct gdma_queue *wq, u32 num_units) 131462306a36Sopenharmony_ci{ 131562306a36Sopenharmony_ci u32 used_space_old; 131662306a36Sopenharmony_ci u32 used_space_new; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci used_space_old = wq->head - wq->tail; 131962306a36Sopenharmony_ci used_space_new = wq->head - (wq->tail + num_units); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci if (WARN_ON_ONCE(used_space_new > used_space_old)) 132262306a36Sopenharmony_ci return -ERANGE; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci wq->tail += num_units; 132562306a36Sopenharmony_ci return 0; 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_cistatic void mana_unmap_skb(struct sk_buff *skb, struct mana_port_context *apc) 132962306a36Sopenharmony_ci{ 133062306a36Sopenharmony_ci struct mana_skb_head *ash = (struct mana_skb_head *)skb->head; 133162306a36Sopenharmony_ci struct gdma_context *gc = apc->ac->gdma_dev->gdma_context; 133262306a36Sopenharmony_ci struct device *dev = gc->dev; 133362306a36Sopenharmony_ci int hsg, i; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci /* Number of SGEs of linear part */ 133662306a36Sopenharmony_ci hsg = (skb_is_gso(skb) && skb_headlen(skb) > ash->size[0]) ? 2 : 1; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci for (i = 0; i < hsg; i++) 133962306a36Sopenharmony_ci dma_unmap_single(dev, ash->dma_handle[i], ash->size[i], 134062306a36Sopenharmony_ci DMA_TO_DEVICE); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci for (i = hsg; i < skb_shinfo(skb)->nr_frags + hsg; i++) 134362306a36Sopenharmony_ci dma_unmap_page(dev, ash->dma_handle[i], ash->size[i], 134462306a36Sopenharmony_ci DMA_TO_DEVICE); 134562306a36Sopenharmony_ci} 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cistatic void mana_poll_tx_cq(struct mana_cq *cq) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci struct gdma_comp *completions = cq->gdma_comp_buf; 135062306a36Sopenharmony_ci struct gdma_posted_wqe_info *wqe_info; 135162306a36Sopenharmony_ci unsigned int pkt_transmitted = 0; 135262306a36Sopenharmony_ci unsigned int wqe_unit_cnt = 0; 135362306a36Sopenharmony_ci struct mana_txq *txq = cq->txq; 135462306a36Sopenharmony_ci struct mana_port_context *apc; 135562306a36Sopenharmony_ci struct netdev_queue *net_txq; 135662306a36Sopenharmony_ci struct gdma_queue *gdma_wq; 135762306a36Sopenharmony_ci unsigned int avail_space; 135862306a36Sopenharmony_ci struct net_device *ndev; 135962306a36Sopenharmony_ci struct sk_buff *skb; 136062306a36Sopenharmony_ci bool txq_stopped; 136162306a36Sopenharmony_ci int comp_read; 136262306a36Sopenharmony_ci int i; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci ndev = txq->ndev; 136562306a36Sopenharmony_ci apc = netdev_priv(ndev); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci comp_read = mana_gd_poll_cq(cq->gdma_cq, completions, 136862306a36Sopenharmony_ci CQE_POLLING_BUFFER); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci if (comp_read < 1) 137162306a36Sopenharmony_ci return; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci for (i = 0; i < comp_read; i++) { 137462306a36Sopenharmony_ci struct mana_tx_comp_oob *cqe_oob; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci if (WARN_ON_ONCE(!completions[i].is_sq)) 137762306a36Sopenharmony_ci return; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci cqe_oob = (struct mana_tx_comp_oob *)completions[i].cqe_data; 138062306a36Sopenharmony_ci if (WARN_ON_ONCE(cqe_oob->cqe_hdr.client_type != 138162306a36Sopenharmony_ci MANA_CQE_COMPLETION)) 138262306a36Sopenharmony_ci return; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci switch (cqe_oob->cqe_hdr.cqe_type) { 138562306a36Sopenharmony_ci case CQE_TX_OKAY: 138662306a36Sopenharmony_ci break; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci case CQE_TX_SA_DROP: 138962306a36Sopenharmony_ci case CQE_TX_MTU_DROP: 139062306a36Sopenharmony_ci case CQE_TX_INVALID_OOB: 139162306a36Sopenharmony_ci case CQE_TX_INVALID_ETH_TYPE: 139262306a36Sopenharmony_ci case CQE_TX_HDR_PROCESSING_ERROR: 139362306a36Sopenharmony_ci case CQE_TX_VF_DISABLED: 139462306a36Sopenharmony_ci case CQE_TX_VPORT_IDX_OUT_OF_RANGE: 139562306a36Sopenharmony_ci case CQE_TX_VPORT_DISABLED: 139662306a36Sopenharmony_ci case CQE_TX_VLAN_TAGGING_VIOLATION: 139762306a36Sopenharmony_ci if (net_ratelimit()) 139862306a36Sopenharmony_ci netdev_err(ndev, "TX: CQE error %d\n", 139962306a36Sopenharmony_ci cqe_oob->cqe_hdr.cqe_type); 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci apc->eth_stats.tx_cqe_err++; 140262306a36Sopenharmony_ci break; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci default: 140562306a36Sopenharmony_ci /* If the CQE type is unknown, log an error, 140662306a36Sopenharmony_ci * and still free the SKB, update tail, etc. 140762306a36Sopenharmony_ci */ 140862306a36Sopenharmony_ci if (net_ratelimit()) 140962306a36Sopenharmony_ci netdev_err(ndev, "TX: unknown CQE type %d\n", 141062306a36Sopenharmony_ci cqe_oob->cqe_hdr.cqe_type); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci apc->eth_stats.tx_cqe_unknown_type++; 141362306a36Sopenharmony_ci break; 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci if (WARN_ON_ONCE(txq->gdma_txq_id != completions[i].wq_num)) 141762306a36Sopenharmony_ci return; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci skb = skb_dequeue(&txq->pending_skbs); 142062306a36Sopenharmony_ci if (WARN_ON_ONCE(!skb)) 142162306a36Sopenharmony_ci return; 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci wqe_info = (struct gdma_posted_wqe_info *)skb->cb; 142462306a36Sopenharmony_ci wqe_unit_cnt += wqe_info->wqe_size_in_bu; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci mana_unmap_skb(skb, apc); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci napi_consume_skb(skb, cq->budget); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci pkt_transmitted++; 143162306a36Sopenharmony_ci } 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (WARN_ON_ONCE(wqe_unit_cnt == 0)) 143462306a36Sopenharmony_ci return; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci mana_move_wq_tail(txq->gdma_sq, wqe_unit_cnt); 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci gdma_wq = txq->gdma_sq; 143962306a36Sopenharmony_ci avail_space = mana_gd_wq_avail_space(gdma_wq); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci /* Ensure tail updated before checking q stop */ 144262306a36Sopenharmony_ci smp_mb(); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci net_txq = txq->net_txq; 144562306a36Sopenharmony_ci txq_stopped = netif_tx_queue_stopped(net_txq); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci /* Ensure checking txq_stopped before apc->port_is_up. */ 144862306a36Sopenharmony_ci smp_rmb(); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci if (txq_stopped && apc->port_is_up && avail_space >= MAX_TX_WQE_SIZE) { 145162306a36Sopenharmony_ci netif_tx_wake_queue(net_txq); 145262306a36Sopenharmony_ci apc->eth_stats.wake_queue++; 145362306a36Sopenharmony_ci } 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci if (atomic_sub_return(pkt_transmitted, &txq->pending_sends) < 0) 145662306a36Sopenharmony_ci WARN_ON_ONCE(1); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci cq->work_done = pkt_transmitted; 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_cistatic void mana_post_pkt_rxq(struct mana_rxq *rxq) 146262306a36Sopenharmony_ci{ 146362306a36Sopenharmony_ci struct mana_recv_buf_oob *recv_buf_oob; 146462306a36Sopenharmony_ci u32 curr_index; 146562306a36Sopenharmony_ci int err; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci curr_index = rxq->buf_index++; 146862306a36Sopenharmony_ci if (rxq->buf_index == rxq->num_rx_buf) 146962306a36Sopenharmony_ci rxq->buf_index = 0; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci recv_buf_oob = &rxq->rx_oobs[curr_index]; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci err = mana_gd_post_work_request(rxq->gdma_rq, &recv_buf_oob->wqe_req, 147462306a36Sopenharmony_ci &recv_buf_oob->wqe_inf); 147562306a36Sopenharmony_ci if (WARN_ON_ONCE(err)) 147662306a36Sopenharmony_ci return; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci WARN_ON_ONCE(recv_buf_oob->wqe_inf.wqe_size_in_bu != 1); 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_cistatic struct sk_buff *mana_build_skb(struct mana_rxq *rxq, void *buf_va, 148262306a36Sopenharmony_ci uint pkt_len, struct xdp_buff *xdp) 148362306a36Sopenharmony_ci{ 148462306a36Sopenharmony_ci struct sk_buff *skb = napi_build_skb(buf_va, rxq->alloc_size); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci if (!skb) 148762306a36Sopenharmony_ci return NULL; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci if (xdp->data_hard_start) { 149062306a36Sopenharmony_ci skb_reserve(skb, xdp->data - xdp->data_hard_start); 149162306a36Sopenharmony_ci skb_put(skb, xdp->data_end - xdp->data); 149262306a36Sopenharmony_ci return skb; 149362306a36Sopenharmony_ci } 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci skb_reserve(skb, rxq->headroom); 149662306a36Sopenharmony_ci skb_put(skb, pkt_len); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci return skb; 149962306a36Sopenharmony_ci} 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_cistatic void mana_rx_skb(void *buf_va, bool from_pool, 150262306a36Sopenharmony_ci struct mana_rxcomp_oob *cqe, struct mana_rxq *rxq) 150362306a36Sopenharmony_ci{ 150462306a36Sopenharmony_ci struct mana_stats_rx *rx_stats = &rxq->stats; 150562306a36Sopenharmony_ci struct net_device *ndev = rxq->ndev; 150662306a36Sopenharmony_ci uint pkt_len = cqe->ppi[0].pkt_len; 150762306a36Sopenharmony_ci u16 rxq_idx = rxq->rxq_idx; 150862306a36Sopenharmony_ci struct napi_struct *napi; 150962306a36Sopenharmony_ci struct xdp_buff xdp = {}; 151062306a36Sopenharmony_ci struct sk_buff *skb; 151162306a36Sopenharmony_ci u32 hash_value; 151262306a36Sopenharmony_ci u32 act; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci rxq->rx_cq.work_done++; 151562306a36Sopenharmony_ci napi = &rxq->rx_cq.napi; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci if (!buf_va) { 151862306a36Sopenharmony_ci ++ndev->stats.rx_dropped; 151962306a36Sopenharmony_ci return; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci act = mana_run_xdp(ndev, rxq, &xdp, buf_va, pkt_len); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci if (act == XDP_REDIRECT && !rxq->xdp_rc) 152562306a36Sopenharmony_ci return; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci if (act != XDP_PASS && act != XDP_TX) 152862306a36Sopenharmony_ci goto drop_xdp; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci skb = mana_build_skb(rxq, buf_va, pkt_len, &xdp); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci if (!skb) 153362306a36Sopenharmony_ci goto drop; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci if (from_pool) 153662306a36Sopenharmony_ci skb_mark_for_recycle(skb); 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci skb->dev = napi->dev; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, ndev); 154162306a36Sopenharmony_ci skb_checksum_none_assert(skb); 154262306a36Sopenharmony_ci skb_record_rx_queue(skb, rxq_idx); 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci if ((ndev->features & NETIF_F_RXCSUM) && cqe->rx_iphdr_csum_succeed) { 154562306a36Sopenharmony_ci if (cqe->rx_tcp_csum_succeed || cqe->rx_udp_csum_succeed) 154662306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 154762306a36Sopenharmony_ci } 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci if (cqe->rx_hashtype != 0 && (ndev->features & NETIF_F_RXHASH)) { 155062306a36Sopenharmony_ci hash_value = cqe->ppi[0].pkt_hash; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci if (cqe->rx_hashtype & MANA_HASH_L4) 155362306a36Sopenharmony_ci skb_set_hash(skb, hash_value, PKT_HASH_TYPE_L4); 155462306a36Sopenharmony_ci else 155562306a36Sopenharmony_ci skb_set_hash(skb, hash_value, PKT_HASH_TYPE_L3); 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci if (cqe->rx_vlantag_present) { 155962306a36Sopenharmony_ci u16 vlan_tci = cqe->rx_vlan_id; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci); 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci u64_stats_update_begin(&rx_stats->syncp); 156562306a36Sopenharmony_ci rx_stats->packets++; 156662306a36Sopenharmony_ci rx_stats->bytes += pkt_len; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci if (act == XDP_TX) 156962306a36Sopenharmony_ci rx_stats->xdp_tx++; 157062306a36Sopenharmony_ci u64_stats_update_end(&rx_stats->syncp); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci if (act == XDP_TX) { 157362306a36Sopenharmony_ci skb_set_queue_mapping(skb, rxq_idx); 157462306a36Sopenharmony_ci mana_xdp_tx(skb, ndev); 157562306a36Sopenharmony_ci return; 157662306a36Sopenharmony_ci } 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci napi_gro_receive(napi, skb); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci return; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_cidrop_xdp: 158362306a36Sopenharmony_ci u64_stats_update_begin(&rx_stats->syncp); 158462306a36Sopenharmony_ci rx_stats->xdp_drop++; 158562306a36Sopenharmony_ci u64_stats_update_end(&rx_stats->syncp); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_cidrop: 158862306a36Sopenharmony_ci if (from_pool) { 158962306a36Sopenharmony_ci page_pool_recycle_direct(rxq->page_pool, 159062306a36Sopenharmony_ci virt_to_head_page(buf_va)); 159162306a36Sopenharmony_ci } else { 159262306a36Sopenharmony_ci WARN_ON_ONCE(rxq->xdp_save_va); 159362306a36Sopenharmony_ci /* Save for reuse */ 159462306a36Sopenharmony_ci rxq->xdp_save_va = buf_va; 159562306a36Sopenharmony_ci } 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci ++ndev->stats.rx_dropped; 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci return; 160062306a36Sopenharmony_ci} 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_cistatic void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev, 160362306a36Sopenharmony_ci dma_addr_t *da, bool *from_pool, bool is_napi) 160462306a36Sopenharmony_ci{ 160562306a36Sopenharmony_ci struct page *page; 160662306a36Sopenharmony_ci void *va; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci *from_pool = false; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci /* Reuse XDP dropped page if available */ 161162306a36Sopenharmony_ci if (rxq->xdp_save_va) { 161262306a36Sopenharmony_ci va = rxq->xdp_save_va; 161362306a36Sopenharmony_ci rxq->xdp_save_va = NULL; 161462306a36Sopenharmony_ci } else if (rxq->alloc_size > PAGE_SIZE) { 161562306a36Sopenharmony_ci if (is_napi) 161662306a36Sopenharmony_ci va = napi_alloc_frag(rxq->alloc_size); 161762306a36Sopenharmony_ci else 161862306a36Sopenharmony_ci va = netdev_alloc_frag(rxq->alloc_size); 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci if (!va) 162162306a36Sopenharmony_ci return NULL; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci page = virt_to_head_page(va); 162462306a36Sopenharmony_ci /* Check if the frag falls back to single page */ 162562306a36Sopenharmony_ci if (compound_order(page) < get_order(rxq->alloc_size)) { 162662306a36Sopenharmony_ci put_page(page); 162762306a36Sopenharmony_ci return NULL; 162862306a36Sopenharmony_ci } 162962306a36Sopenharmony_ci } else { 163062306a36Sopenharmony_ci page = page_pool_dev_alloc_pages(rxq->page_pool); 163162306a36Sopenharmony_ci if (!page) 163262306a36Sopenharmony_ci return NULL; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci *from_pool = true; 163562306a36Sopenharmony_ci va = page_to_virt(page); 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci *da = dma_map_single(dev, va + rxq->headroom, rxq->datasize, 163962306a36Sopenharmony_ci DMA_FROM_DEVICE); 164062306a36Sopenharmony_ci if (dma_mapping_error(dev, *da)) { 164162306a36Sopenharmony_ci if (*from_pool) 164262306a36Sopenharmony_ci page_pool_put_full_page(rxq->page_pool, page, false); 164362306a36Sopenharmony_ci else 164462306a36Sopenharmony_ci put_page(virt_to_head_page(va)); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci return NULL; 164762306a36Sopenharmony_ci } 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci return va; 165062306a36Sopenharmony_ci} 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci/* Allocate frag for rx buffer, and save the old buf */ 165362306a36Sopenharmony_cistatic void mana_refill_rx_oob(struct device *dev, struct mana_rxq *rxq, 165462306a36Sopenharmony_ci struct mana_recv_buf_oob *rxoob, void **old_buf, 165562306a36Sopenharmony_ci bool *old_fp) 165662306a36Sopenharmony_ci{ 165762306a36Sopenharmony_ci bool from_pool; 165862306a36Sopenharmony_ci dma_addr_t da; 165962306a36Sopenharmony_ci void *va; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci va = mana_get_rxfrag(rxq, dev, &da, &from_pool, true); 166262306a36Sopenharmony_ci if (!va) 166362306a36Sopenharmony_ci return; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci dma_unmap_single(dev, rxoob->sgl[0].address, rxq->datasize, 166662306a36Sopenharmony_ci DMA_FROM_DEVICE); 166762306a36Sopenharmony_ci *old_buf = rxoob->buf_va; 166862306a36Sopenharmony_ci *old_fp = rxoob->from_pool; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci rxoob->buf_va = va; 167162306a36Sopenharmony_ci rxoob->sgl[0].address = da; 167262306a36Sopenharmony_ci rxoob->from_pool = from_pool; 167362306a36Sopenharmony_ci} 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_cistatic void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq, 167662306a36Sopenharmony_ci struct gdma_comp *cqe) 167762306a36Sopenharmony_ci{ 167862306a36Sopenharmony_ci struct mana_rxcomp_oob *oob = (struct mana_rxcomp_oob *)cqe->cqe_data; 167962306a36Sopenharmony_ci struct gdma_context *gc = rxq->gdma_rq->gdma_dev->gdma_context; 168062306a36Sopenharmony_ci struct net_device *ndev = rxq->ndev; 168162306a36Sopenharmony_ci struct mana_recv_buf_oob *rxbuf_oob; 168262306a36Sopenharmony_ci struct mana_port_context *apc; 168362306a36Sopenharmony_ci struct device *dev = gc->dev; 168462306a36Sopenharmony_ci void *old_buf = NULL; 168562306a36Sopenharmony_ci u32 curr, pktlen; 168662306a36Sopenharmony_ci bool old_fp; 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci apc = netdev_priv(ndev); 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci switch (oob->cqe_hdr.cqe_type) { 169162306a36Sopenharmony_ci case CQE_RX_OKAY: 169262306a36Sopenharmony_ci break; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci case CQE_RX_TRUNCATED: 169562306a36Sopenharmony_ci ++ndev->stats.rx_dropped; 169662306a36Sopenharmony_ci rxbuf_oob = &rxq->rx_oobs[rxq->buf_index]; 169762306a36Sopenharmony_ci netdev_warn_once(ndev, "Dropped a truncated packet\n"); 169862306a36Sopenharmony_ci goto drop; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci case CQE_RX_COALESCED_4: 170162306a36Sopenharmony_ci netdev_err(ndev, "RX coalescing is unsupported\n"); 170262306a36Sopenharmony_ci apc->eth_stats.rx_coalesced_err++; 170362306a36Sopenharmony_ci return; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci case CQE_RX_OBJECT_FENCE: 170662306a36Sopenharmony_ci complete(&rxq->fence_event); 170762306a36Sopenharmony_ci return; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci default: 171062306a36Sopenharmony_ci netdev_err(ndev, "Unknown RX CQE type = %d\n", 171162306a36Sopenharmony_ci oob->cqe_hdr.cqe_type); 171262306a36Sopenharmony_ci apc->eth_stats.rx_cqe_unknown_type++; 171362306a36Sopenharmony_ci return; 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci pktlen = oob->ppi[0].pkt_len; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci if (pktlen == 0) { 171962306a36Sopenharmony_ci /* data packets should never have packetlength of zero */ 172062306a36Sopenharmony_ci netdev_err(ndev, "RX pkt len=0, rq=%u, cq=%u, rxobj=0x%llx\n", 172162306a36Sopenharmony_ci rxq->gdma_id, cq->gdma_id, rxq->rxobj); 172262306a36Sopenharmony_ci return; 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci curr = rxq->buf_index; 172662306a36Sopenharmony_ci rxbuf_oob = &rxq->rx_oobs[curr]; 172762306a36Sopenharmony_ci WARN_ON_ONCE(rxbuf_oob->wqe_inf.wqe_size_in_bu != 1); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci mana_refill_rx_oob(dev, rxq, rxbuf_oob, &old_buf, &old_fp); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci /* Unsuccessful refill will have old_buf == NULL. 173262306a36Sopenharmony_ci * In this case, mana_rx_skb() will drop the packet. 173362306a36Sopenharmony_ci */ 173462306a36Sopenharmony_ci mana_rx_skb(old_buf, old_fp, oob, rxq); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_cidrop: 173762306a36Sopenharmony_ci mana_move_wq_tail(rxq->gdma_rq, rxbuf_oob->wqe_inf.wqe_size_in_bu); 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci mana_post_pkt_rxq(rxq); 174062306a36Sopenharmony_ci} 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_cistatic void mana_poll_rx_cq(struct mana_cq *cq) 174362306a36Sopenharmony_ci{ 174462306a36Sopenharmony_ci struct gdma_comp *comp = cq->gdma_comp_buf; 174562306a36Sopenharmony_ci struct mana_rxq *rxq = cq->rxq; 174662306a36Sopenharmony_ci int comp_read, i; 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci comp_read = mana_gd_poll_cq(cq->gdma_cq, comp, CQE_POLLING_BUFFER); 174962306a36Sopenharmony_ci WARN_ON_ONCE(comp_read > CQE_POLLING_BUFFER); 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci rxq->xdp_flush = false; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci for (i = 0; i < comp_read; i++) { 175462306a36Sopenharmony_ci if (WARN_ON_ONCE(comp[i].is_sq)) 175562306a36Sopenharmony_ci return; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci /* verify recv cqe references the right rxq */ 175862306a36Sopenharmony_ci if (WARN_ON_ONCE(comp[i].wq_num != cq->rxq->gdma_id)) 175962306a36Sopenharmony_ci return; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci mana_process_rx_cqe(rxq, cq, &comp[i]); 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci if (comp_read > 0) { 176562306a36Sopenharmony_ci struct gdma_context *gc = rxq->gdma_rq->gdma_dev->gdma_context; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci mana_gd_wq_ring_doorbell(gc, rxq->gdma_rq); 176862306a36Sopenharmony_ci } 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci if (rxq->xdp_flush) 177162306a36Sopenharmony_ci xdp_do_flush(); 177262306a36Sopenharmony_ci} 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_cistatic int mana_cq_handler(void *context, struct gdma_queue *gdma_queue) 177562306a36Sopenharmony_ci{ 177662306a36Sopenharmony_ci struct mana_cq *cq = context; 177762306a36Sopenharmony_ci u8 arm_bit; 177862306a36Sopenharmony_ci int w; 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci WARN_ON_ONCE(cq->gdma_cq != gdma_queue); 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci if (cq->type == MANA_CQ_TYPE_RX) 178362306a36Sopenharmony_ci mana_poll_rx_cq(cq); 178462306a36Sopenharmony_ci else 178562306a36Sopenharmony_ci mana_poll_tx_cq(cq); 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci w = cq->work_done; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci if (w < cq->budget && 179062306a36Sopenharmony_ci napi_complete_done(&cq->napi, w)) { 179162306a36Sopenharmony_ci arm_bit = SET_ARM_BIT; 179262306a36Sopenharmony_ci } else { 179362306a36Sopenharmony_ci arm_bit = 0; 179462306a36Sopenharmony_ci } 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci mana_gd_ring_cq(gdma_queue, arm_bit); 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci return w; 179962306a36Sopenharmony_ci} 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_cistatic int mana_poll(struct napi_struct *napi, int budget) 180262306a36Sopenharmony_ci{ 180362306a36Sopenharmony_ci struct mana_cq *cq = container_of(napi, struct mana_cq, napi); 180462306a36Sopenharmony_ci int w; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci cq->work_done = 0; 180762306a36Sopenharmony_ci cq->budget = budget; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci w = mana_cq_handler(cq, cq->gdma_cq); 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci return min(w, budget); 181262306a36Sopenharmony_ci} 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_cistatic void mana_schedule_napi(void *context, struct gdma_queue *gdma_queue) 181562306a36Sopenharmony_ci{ 181662306a36Sopenharmony_ci struct mana_cq *cq = context; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci napi_schedule_irqoff(&cq->napi); 181962306a36Sopenharmony_ci} 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_cistatic void mana_deinit_cq(struct mana_port_context *apc, struct mana_cq *cq) 182262306a36Sopenharmony_ci{ 182362306a36Sopenharmony_ci struct gdma_dev *gd = apc->ac->gdma_dev; 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci if (!cq->gdma_cq) 182662306a36Sopenharmony_ci return; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci mana_gd_destroy_queue(gd->gdma_context, cq->gdma_cq); 182962306a36Sopenharmony_ci} 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_cistatic void mana_deinit_txq(struct mana_port_context *apc, struct mana_txq *txq) 183262306a36Sopenharmony_ci{ 183362306a36Sopenharmony_ci struct gdma_dev *gd = apc->ac->gdma_dev; 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci if (!txq->gdma_sq) 183662306a36Sopenharmony_ci return; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci mana_gd_destroy_queue(gd->gdma_context, txq->gdma_sq); 183962306a36Sopenharmony_ci} 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_cistatic void mana_destroy_txq(struct mana_port_context *apc) 184262306a36Sopenharmony_ci{ 184362306a36Sopenharmony_ci struct napi_struct *napi; 184462306a36Sopenharmony_ci int i; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci if (!apc->tx_qp) 184762306a36Sopenharmony_ci return; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci for (i = 0; i < apc->num_queues; i++) { 185062306a36Sopenharmony_ci napi = &apc->tx_qp[i].tx_cq.napi; 185162306a36Sopenharmony_ci napi_synchronize(napi); 185262306a36Sopenharmony_ci napi_disable(napi); 185362306a36Sopenharmony_ci netif_napi_del(napi); 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i].tx_object); 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci mana_deinit_cq(apc, &apc->tx_qp[i].tx_cq); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci mana_deinit_txq(apc, &apc->tx_qp[i].txq); 186062306a36Sopenharmony_ci } 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci kfree(apc->tx_qp); 186362306a36Sopenharmony_ci apc->tx_qp = NULL; 186462306a36Sopenharmony_ci} 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_cistatic int mana_create_txq(struct mana_port_context *apc, 186762306a36Sopenharmony_ci struct net_device *net) 186862306a36Sopenharmony_ci{ 186962306a36Sopenharmony_ci struct mana_context *ac = apc->ac; 187062306a36Sopenharmony_ci struct gdma_dev *gd = ac->gdma_dev; 187162306a36Sopenharmony_ci struct mana_obj_spec wq_spec; 187262306a36Sopenharmony_ci struct mana_obj_spec cq_spec; 187362306a36Sopenharmony_ci struct gdma_queue_spec spec; 187462306a36Sopenharmony_ci struct gdma_context *gc; 187562306a36Sopenharmony_ci struct mana_txq *txq; 187662306a36Sopenharmony_ci struct mana_cq *cq; 187762306a36Sopenharmony_ci u32 txq_size; 187862306a36Sopenharmony_ci u32 cq_size; 187962306a36Sopenharmony_ci int err; 188062306a36Sopenharmony_ci int i; 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci apc->tx_qp = kcalloc(apc->num_queues, sizeof(struct mana_tx_qp), 188362306a36Sopenharmony_ci GFP_KERNEL); 188462306a36Sopenharmony_ci if (!apc->tx_qp) 188562306a36Sopenharmony_ci return -ENOMEM; 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci /* The minimum size of the WQE is 32 bytes, hence 188862306a36Sopenharmony_ci * MAX_SEND_BUFFERS_PER_QUEUE represents the maximum number of WQEs 188962306a36Sopenharmony_ci * the SQ can store. This value is then used to size other queues 189062306a36Sopenharmony_ci * to prevent overflow. 189162306a36Sopenharmony_ci */ 189262306a36Sopenharmony_ci txq_size = MAX_SEND_BUFFERS_PER_QUEUE * 32; 189362306a36Sopenharmony_ci BUILD_BUG_ON(!PAGE_ALIGNED(txq_size)); 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci cq_size = MAX_SEND_BUFFERS_PER_QUEUE * COMP_ENTRY_SIZE; 189662306a36Sopenharmony_ci cq_size = PAGE_ALIGN(cq_size); 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci gc = gd->gdma_context; 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci for (i = 0; i < apc->num_queues; i++) { 190162306a36Sopenharmony_ci apc->tx_qp[i].tx_object = INVALID_MANA_HANDLE; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci /* Create SQ */ 190462306a36Sopenharmony_ci txq = &apc->tx_qp[i].txq; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci u64_stats_init(&txq->stats.syncp); 190762306a36Sopenharmony_ci txq->ndev = net; 190862306a36Sopenharmony_ci txq->net_txq = netdev_get_tx_queue(net, i); 190962306a36Sopenharmony_ci txq->vp_offset = apc->tx_vp_offset; 191062306a36Sopenharmony_ci skb_queue_head_init(&txq->pending_skbs); 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci memset(&spec, 0, sizeof(spec)); 191362306a36Sopenharmony_ci spec.type = GDMA_SQ; 191462306a36Sopenharmony_ci spec.monitor_avl_buf = true; 191562306a36Sopenharmony_ci spec.queue_size = txq_size; 191662306a36Sopenharmony_ci err = mana_gd_create_mana_wq_cq(gd, &spec, &txq->gdma_sq); 191762306a36Sopenharmony_ci if (err) 191862306a36Sopenharmony_ci goto out; 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci /* Create SQ's CQ */ 192162306a36Sopenharmony_ci cq = &apc->tx_qp[i].tx_cq; 192262306a36Sopenharmony_ci cq->type = MANA_CQ_TYPE_TX; 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci cq->txq = txq; 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci memset(&spec, 0, sizeof(spec)); 192762306a36Sopenharmony_ci spec.type = GDMA_CQ; 192862306a36Sopenharmony_ci spec.monitor_avl_buf = false; 192962306a36Sopenharmony_ci spec.queue_size = cq_size; 193062306a36Sopenharmony_ci spec.cq.callback = mana_schedule_napi; 193162306a36Sopenharmony_ci spec.cq.parent_eq = ac->eqs[i].eq; 193262306a36Sopenharmony_ci spec.cq.context = cq; 193362306a36Sopenharmony_ci err = mana_gd_create_mana_wq_cq(gd, &spec, &cq->gdma_cq); 193462306a36Sopenharmony_ci if (err) 193562306a36Sopenharmony_ci goto out; 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci memset(&wq_spec, 0, sizeof(wq_spec)); 193862306a36Sopenharmony_ci memset(&cq_spec, 0, sizeof(cq_spec)); 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci wq_spec.gdma_region = txq->gdma_sq->mem_info.dma_region_handle; 194162306a36Sopenharmony_ci wq_spec.queue_size = txq->gdma_sq->queue_size; 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci cq_spec.gdma_region = cq->gdma_cq->mem_info.dma_region_handle; 194462306a36Sopenharmony_ci cq_spec.queue_size = cq->gdma_cq->queue_size; 194562306a36Sopenharmony_ci cq_spec.modr_ctx_id = 0; 194662306a36Sopenharmony_ci cq_spec.attached_eq = cq->gdma_cq->cq.parent->id; 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci err = mana_create_wq_obj(apc, apc->port_handle, GDMA_SQ, 194962306a36Sopenharmony_ci &wq_spec, &cq_spec, 195062306a36Sopenharmony_ci &apc->tx_qp[i].tx_object); 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci if (err) 195362306a36Sopenharmony_ci goto out; 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci txq->gdma_sq->id = wq_spec.queue_index; 195662306a36Sopenharmony_ci cq->gdma_cq->id = cq_spec.queue_index; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci txq->gdma_sq->mem_info.dma_region_handle = 195962306a36Sopenharmony_ci GDMA_INVALID_DMA_REGION; 196062306a36Sopenharmony_ci cq->gdma_cq->mem_info.dma_region_handle = 196162306a36Sopenharmony_ci GDMA_INVALID_DMA_REGION; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci txq->gdma_txq_id = txq->gdma_sq->id; 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci cq->gdma_id = cq->gdma_cq->id; 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci if (WARN_ON(cq->gdma_id >= gc->max_num_cqs)) { 196862306a36Sopenharmony_ci err = -EINVAL; 196962306a36Sopenharmony_ci goto out; 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci gc->cq_table[cq->gdma_id] = cq->gdma_cq; 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci netif_napi_add_tx(net, &cq->napi, mana_poll); 197562306a36Sopenharmony_ci napi_enable(&cq->napi); 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT); 197862306a36Sopenharmony_ci } 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci return 0; 198162306a36Sopenharmony_ciout: 198262306a36Sopenharmony_ci mana_destroy_txq(apc); 198362306a36Sopenharmony_ci return err; 198462306a36Sopenharmony_ci} 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_cistatic void mana_destroy_rxq(struct mana_port_context *apc, 198762306a36Sopenharmony_ci struct mana_rxq *rxq, bool validate_state) 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci{ 199062306a36Sopenharmony_ci struct gdma_context *gc = apc->ac->gdma_dev->gdma_context; 199162306a36Sopenharmony_ci struct mana_recv_buf_oob *rx_oob; 199262306a36Sopenharmony_ci struct device *dev = gc->dev; 199362306a36Sopenharmony_ci struct napi_struct *napi; 199462306a36Sopenharmony_ci struct page *page; 199562306a36Sopenharmony_ci int i; 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci if (!rxq) 199862306a36Sopenharmony_ci return; 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci napi = &rxq->rx_cq.napi; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci if (validate_state) 200362306a36Sopenharmony_ci napi_synchronize(napi); 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci napi_disable(napi); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci xdp_rxq_info_unreg(&rxq->xdp_rxq); 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci netif_napi_del(napi); 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci mana_destroy_wq_obj(apc, GDMA_RQ, rxq->rxobj); 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci mana_deinit_cq(apc, &rxq->rx_cq); 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci if (rxq->xdp_save_va) 201662306a36Sopenharmony_ci put_page(virt_to_head_page(rxq->xdp_save_va)); 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci for (i = 0; i < rxq->num_rx_buf; i++) { 201962306a36Sopenharmony_ci rx_oob = &rxq->rx_oobs[i]; 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci if (!rx_oob->buf_va) 202262306a36Sopenharmony_ci continue; 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci dma_unmap_single(dev, rx_oob->sgl[0].address, 202562306a36Sopenharmony_ci rx_oob->sgl[0].size, DMA_FROM_DEVICE); 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci page = virt_to_head_page(rx_oob->buf_va); 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci if (rx_oob->from_pool) 203062306a36Sopenharmony_ci page_pool_put_full_page(rxq->page_pool, page, false); 203162306a36Sopenharmony_ci else 203262306a36Sopenharmony_ci put_page(page); 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci rx_oob->buf_va = NULL; 203562306a36Sopenharmony_ci } 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci page_pool_destroy(rxq->page_pool); 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci if (rxq->gdma_rq) 204062306a36Sopenharmony_ci mana_gd_destroy_queue(gc, rxq->gdma_rq); 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci kfree(rxq); 204362306a36Sopenharmony_ci} 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_cistatic int mana_fill_rx_oob(struct mana_recv_buf_oob *rx_oob, u32 mem_key, 204662306a36Sopenharmony_ci struct mana_rxq *rxq, struct device *dev) 204762306a36Sopenharmony_ci{ 204862306a36Sopenharmony_ci struct mana_port_context *mpc = netdev_priv(rxq->ndev); 204962306a36Sopenharmony_ci bool from_pool = false; 205062306a36Sopenharmony_ci dma_addr_t da; 205162306a36Sopenharmony_ci void *va; 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci if (mpc->rxbufs_pre) 205462306a36Sopenharmony_ci va = mana_get_rxbuf_pre(rxq, &da); 205562306a36Sopenharmony_ci else 205662306a36Sopenharmony_ci va = mana_get_rxfrag(rxq, dev, &da, &from_pool, false); 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci if (!va) 205962306a36Sopenharmony_ci return -ENOMEM; 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci rx_oob->buf_va = va; 206262306a36Sopenharmony_ci rx_oob->from_pool = from_pool; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci rx_oob->sgl[0].address = da; 206562306a36Sopenharmony_ci rx_oob->sgl[0].size = rxq->datasize; 206662306a36Sopenharmony_ci rx_oob->sgl[0].mem_key = mem_key; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci return 0; 206962306a36Sopenharmony_ci} 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci#define MANA_WQE_HEADER_SIZE 16 207262306a36Sopenharmony_ci#define MANA_WQE_SGE_SIZE 16 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_cistatic int mana_alloc_rx_wqe(struct mana_port_context *apc, 207562306a36Sopenharmony_ci struct mana_rxq *rxq, u32 *rxq_size, u32 *cq_size) 207662306a36Sopenharmony_ci{ 207762306a36Sopenharmony_ci struct gdma_context *gc = apc->ac->gdma_dev->gdma_context; 207862306a36Sopenharmony_ci struct mana_recv_buf_oob *rx_oob; 207962306a36Sopenharmony_ci struct device *dev = gc->dev; 208062306a36Sopenharmony_ci u32 buf_idx; 208162306a36Sopenharmony_ci int ret; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci WARN_ON(rxq->datasize == 0); 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci *rxq_size = 0; 208662306a36Sopenharmony_ci *cq_size = 0; 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci for (buf_idx = 0; buf_idx < rxq->num_rx_buf; buf_idx++) { 208962306a36Sopenharmony_ci rx_oob = &rxq->rx_oobs[buf_idx]; 209062306a36Sopenharmony_ci memset(rx_oob, 0, sizeof(*rx_oob)); 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci rx_oob->num_sge = 1; 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci ret = mana_fill_rx_oob(rx_oob, apc->ac->gdma_dev->gpa_mkey, rxq, 209562306a36Sopenharmony_ci dev); 209662306a36Sopenharmony_ci if (ret) 209762306a36Sopenharmony_ci return ret; 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci rx_oob->wqe_req.sgl = rx_oob->sgl; 210062306a36Sopenharmony_ci rx_oob->wqe_req.num_sge = rx_oob->num_sge; 210162306a36Sopenharmony_ci rx_oob->wqe_req.inline_oob_size = 0; 210262306a36Sopenharmony_ci rx_oob->wqe_req.inline_oob_data = NULL; 210362306a36Sopenharmony_ci rx_oob->wqe_req.flags = 0; 210462306a36Sopenharmony_ci rx_oob->wqe_req.client_data_unit = 0; 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci *rxq_size += ALIGN(MANA_WQE_HEADER_SIZE + 210762306a36Sopenharmony_ci MANA_WQE_SGE_SIZE * rx_oob->num_sge, 32); 210862306a36Sopenharmony_ci *cq_size += COMP_ENTRY_SIZE; 210962306a36Sopenharmony_ci } 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci return 0; 211262306a36Sopenharmony_ci} 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_cistatic int mana_push_wqe(struct mana_rxq *rxq) 211562306a36Sopenharmony_ci{ 211662306a36Sopenharmony_ci struct mana_recv_buf_oob *rx_oob; 211762306a36Sopenharmony_ci u32 buf_idx; 211862306a36Sopenharmony_ci int err; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci for (buf_idx = 0; buf_idx < rxq->num_rx_buf; buf_idx++) { 212162306a36Sopenharmony_ci rx_oob = &rxq->rx_oobs[buf_idx]; 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci err = mana_gd_post_and_ring(rxq->gdma_rq, &rx_oob->wqe_req, 212462306a36Sopenharmony_ci &rx_oob->wqe_inf); 212562306a36Sopenharmony_ci if (err) 212662306a36Sopenharmony_ci return -ENOSPC; 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci return 0; 213062306a36Sopenharmony_ci} 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_cistatic int mana_create_page_pool(struct mana_rxq *rxq, struct gdma_context *gc) 213362306a36Sopenharmony_ci{ 213462306a36Sopenharmony_ci struct page_pool_params pprm = {}; 213562306a36Sopenharmony_ci int ret; 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci pprm.pool_size = RX_BUFFERS_PER_QUEUE; 213862306a36Sopenharmony_ci pprm.nid = gc->numa_node; 213962306a36Sopenharmony_ci pprm.napi = &rxq->rx_cq.napi; 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci rxq->page_pool = page_pool_create(&pprm); 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci if (IS_ERR(rxq->page_pool)) { 214462306a36Sopenharmony_ci ret = PTR_ERR(rxq->page_pool); 214562306a36Sopenharmony_ci rxq->page_pool = NULL; 214662306a36Sopenharmony_ci return ret; 214762306a36Sopenharmony_ci } 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci return 0; 215062306a36Sopenharmony_ci} 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_cistatic struct mana_rxq *mana_create_rxq(struct mana_port_context *apc, 215362306a36Sopenharmony_ci u32 rxq_idx, struct mana_eq *eq, 215462306a36Sopenharmony_ci struct net_device *ndev) 215562306a36Sopenharmony_ci{ 215662306a36Sopenharmony_ci struct gdma_dev *gd = apc->ac->gdma_dev; 215762306a36Sopenharmony_ci struct mana_obj_spec wq_spec; 215862306a36Sopenharmony_ci struct mana_obj_spec cq_spec; 215962306a36Sopenharmony_ci struct gdma_queue_spec spec; 216062306a36Sopenharmony_ci struct mana_cq *cq = NULL; 216162306a36Sopenharmony_ci struct gdma_context *gc; 216262306a36Sopenharmony_ci u32 cq_size, rq_size; 216362306a36Sopenharmony_ci struct mana_rxq *rxq; 216462306a36Sopenharmony_ci int err; 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci gc = gd->gdma_context; 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci rxq = kzalloc(struct_size(rxq, rx_oobs, RX_BUFFERS_PER_QUEUE), 216962306a36Sopenharmony_ci GFP_KERNEL); 217062306a36Sopenharmony_ci if (!rxq) 217162306a36Sopenharmony_ci return NULL; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci rxq->ndev = ndev; 217462306a36Sopenharmony_ci rxq->num_rx_buf = RX_BUFFERS_PER_QUEUE; 217562306a36Sopenharmony_ci rxq->rxq_idx = rxq_idx; 217662306a36Sopenharmony_ci rxq->rxobj = INVALID_MANA_HANDLE; 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci mana_get_rxbuf_cfg(ndev->mtu, &rxq->datasize, &rxq->alloc_size, 217962306a36Sopenharmony_ci &rxq->headroom); 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci /* Create page pool for RX queue */ 218262306a36Sopenharmony_ci err = mana_create_page_pool(rxq, gc); 218362306a36Sopenharmony_ci if (err) { 218462306a36Sopenharmony_ci netdev_err(ndev, "Create page pool err:%d\n", err); 218562306a36Sopenharmony_ci goto out; 218662306a36Sopenharmony_ci } 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci err = mana_alloc_rx_wqe(apc, rxq, &rq_size, &cq_size); 218962306a36Sopenharmony_ci if (err) 219062306a36Sopenharmony_ci goto out; 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci rq_size = PAGE_ALIGN(rq_size); 219362306a36Sopenharmony_ci cq_size = PAGE_ALIGN(cq_size); 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci /* Create RQ */ 219662306a36Sopenharmony_ci memset(&spec, 0, sizeof(spec)); 219762306a36Sopenharmony_ci spec.type = GDMA_RQ; 219862306a36Sopenharmony_ci spec.monitor_avl_buf = true; 219962306a36Sopenharmony_ci spec.queue_size = rq_size; 220062306a36Sopenharmony_ci err = mana_gd_create_mana_wq_cq(gd, &spec, &rxq->gdma_rq); 220162306a36Sopenharmony_ci if (err) 220262306a36Sopenharmony_ci goto out; 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci /* Create RQ's CQ */ 220562306a36Sopenharmony_ci cq = &rxq->rx_cq; 220662306a36Sopenharmony_ci cq->type = MANA_CQ_TYPE_RX; 220762306a36Sopenharmony_ci cq->rxq = rxq; 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci memset(&spec, 0, sizeof(spec)); 221062306a36Sopenharmony_ci spec.type = GDMA_CQ; 221162306a36Sopenharmony_ci spec.monitor_avl_buf = false; 221262306a36Sopenharmony_ci spec.queue_size = cq_size; 221362306a36Sopenharmony_ci spec.cq.callback = mana_schedule_napi; 221462306a36Sopenharmony_ci spec.cq.parent_eq = eq->eq; 221562306a36Sopenharmony_ci spec.cq.context = cq; 221662306a36Sopenharmony_ci err = mana_gd_create_mana_wq_cq(gd, &spec, &cq->gdma_cq); 221762306a36Sopenharmony_ci if (err) 221862306a36Sopenharmony_ci goto out; 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci memset(&wq_spec, 0, sizeof(wq_spec)); 222162306a36Sopenharmony_ci memset(&cq_spec, 0, sizeof(cq_spec)); 222262306a36Sopenharmony_ci wq_spec.gdma_region = rxq->gdma_rq->mem_info.dma_region_handle; 222362306a36Sopenharmony_ci wq_spec.queue_size = rxq->gdma_rq->queue_size; 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci cq_spec.gdma_region = cq->gdma_cq->mem_info.dma_region_handle; 222662306a36Sopenharmony_ci cq_spec.queue_size = cq->gdma_cq->queue_size; 222762306a36Sopenharmony_ci cq_spec.modr_ctx_id = 0; 222862306a36Sopenharmony_ci cq_spec.attached_eq = cq->gdma_cq->cq.parent->id; 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci err = mana_create_wq_obj(apc, apc->port_handle, GDMA_RQ, 223162306a36Sopenharmony_ci &wq_spec, &cq_spec, &rxq->rxobj); 223262306a36Sopenharmony_ci if (err) 223362306a36Sopenharmony_ci goto out; 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci rxq->gdma_rq->id = wq_spec.queue_index; 223662306a36Sopenharmony_ci cq->gdma_cq->id = cq_spec.queue_index; 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci rxq->gdma_rq->mem_info.dma_region_handle = GDMA_INVALID_DMA_REGION; 223962306a36Sopenharmony_ci cq->gdma_cq->mem_info.dma_region_handle = GDMA_INVALID_DMA_REGION; 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci rxq->gdma_id = rxq->gdma_rq->id; 224262306a36Sopenharmony_ci cq->gdma_id = cq->gdma_cq->id; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci err = mana_push_wqe(rxq); 224562306a36Sopenharmony_ci if (err) 224662306a36Sopenharmony_ci goto out; 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ci if (WARN_ON(cq->gdma_id >= gc->max_num_cqs)) { 224962306a36Sopenharmony_ci err = -EINVAL; 225062306a36Sopenharmony_ci goto out; 225162306a36Sopenharmony_ci } 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci gc->cq_table[cq->gdma_id] = cq->gdma_cq; 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_ci netif_napi_add_weight(ndev, &cq->napi, mana_poll, 1); 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci WARN_ON(xdp_rxq_info_reg(&rxq->xdp_rxq, ndev, rxq_idx, 225862306a36Sopenharmony_ci cq->napi.napi_id)); 225962306a36Sopenharmony_ci WARN_ON(xdp_rxq_info_reg_mem_model(&rxq->xdp_rxq, MEM_TYPE_PAGE_POOL, 226062306a36Sopenharmony_ci rxq->page_pool)); 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci napi_enable(&cq->napi); 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT); 226562306a36Sopenharmony_ciout: 226662306a36Sopenharmony_ci if (!err) 226762306a36Sopenharmony_ci return rxq; 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci netdev_err(ndev, "Failed to create RXQ: err = %d\n", err); 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci mana_destroy_rxq(apc, rxq, false); 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci if (cq) 227462306a36Sopenharmony_ci mana_deinit_cq(apc, cq); 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci return NULL; 227762306a36Sopenharmony_ci} 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_cistatic int mana_add_rx_queues(struct mana_port_context *apc, 228062306a36Sopenharmony_ci struct net_device *ndev) 228162306a36Sopenharmony_ci{ 228262306a36Sopenharmony_ci struct mana_context *ac = apc->ac; 228362306a36Sopenharmony_ci struct mana_rxq *rxq; 228462306a36Sopenharmony_ci int err = 0; 228562306a36Sopenharmony_ci int i; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci for (i = 0; i < apc->num_queues; i++) { 228862306a36Sopenharmony_ci rxq = mana_create_rxq(apc, i, &ac->eqs[i], ndev); 228962306a36Sopenharmony_ci if (!rxq) { 229062306a36Sopenharmony_ci err = -ENOMEM; 229162306a36Sopenharmony_ci goto out; 229262306a36Sopenharmony_ci } 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci u64_stats_init(&rxq->stats.syncp); 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci apc->rxqs[i] = rxq; 229762306a36Sopenharmony_ci } 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci apc->default_rxobj = apc->rxqs[0]->rxobj; 230062306a36Sopenharmony_ciout: 230162306a36Sopenharmony_ci return err; 230262306a36Sopenharmony_ci} 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_cistatic void mana_destroy_vport(struct mana_port_context *apc) 230562306a36Sopenharmony_ci{ 230662306a36Sopenharmony_ci struct gdma_dev *gd = apc->ac->gdma_dev; 230762306a36Sopenharmony_ci struct mana_rxq *rxq; 230862306a36Sopenharmony_ci u32 rxq_idx; 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { 231162306a36Sopenharmony_ci rxq = apc->rxqs[rxq_idx]; 231262306a36Sopenharmony_ci if (!rxq) 231362306a36Sopenharmony_ci continue; 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci mana_destroy_rxq(apc, rxq, true); 231662306a36Sopenharmony_ci apc->rxqs[rxq_idx] = NULL; 231762306a36Sopenharmony_ci } 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci mana_destroy_txq(apc); 232062306a36Sopenharmony_ci mana_uncfg_vport(apc); 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci if (gd->gdma_context->is_pf) 232362306a36Sopenharmony_ci mana_pf_deregister_hw_vport(apc); 232462306a36Sopenharmony_ci} 232562306a36Sopenharmony_ci 232662306a36Sopenharmony_cistatic int mana_create_vport(struct mana_port_context *apc, 232762306a36Sopenharmony_ci struct net_device *net) 232862306a36Sopenharmony_ci{ 232962306a36Sopenharmony_ci struct gdma_dev *gd = apc->ac->gdma_dev; 233062306a36Sopenharmony_ci int err; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci apc->default_rxobj = INVALID_MANA_HANDLE; 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci if (gd->gdma_context->is_pf) { 233562306a36Sopenharmony_ci err = mana_pf_register_hw_vport(apc); 233662306a36Sopenharmony_ci if (err) 233762306a36Sopenharmony_ci return err; 233862306a36Sopenharmony_ci } 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_ci err = mana_cfg_vport(apc, gd->pdid, gd->doorbell); 234162306a36Sopenharmony_ci if (err) 234262306a36Sopenharmony_ci return err; 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci return mana_create_txq(apc, net); 234562306a36Sopenharmony_ci} 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_cistatic void mana_rss_table_init(struct mana_port_context *apc) 234862306a36Sopenharmony_ci{ 234962306a36Sopenharmony_ci int i; 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) 235262306a36Sopenharmony_ci apc->indir_table[i] = 235362306a36Sopenharmony_ci ethtool_rxfh_indir_default(i, apc->num_queues); 235462306a36Sopenharmony_ci} 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ciint mana_config_rss(struct mana_port_context *apc, enum TRI_STATE rx, 235762306a36Sopenharmony_ci bool update_hash, bool update_tab) 235862306a36Sopenharmony_ci{ 235962306a36Sopenharmony_ci u32 queue_idx; 236062306a36Sopenharmony_ci int err; 236162306a36Sopenharmony_ci int i; 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci if (update_tab) { 236462306a36Sopenharmony_ci for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) { 236562306a36Sopenharmony_ci queue_idx = apc->indir_table[i]; 236662306a36Sopenharmony_ci apc->rxobj_table[i] = apc->rxqs[queue_idx]->rxobj; 236762306a36Sopenharmony_ci } 236862306a36Sopenharmony_ci } 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci err = mana_cfg_vport_steering(apc, rx, true, update_hash, update_tab); 237162306a36Sopenharmony_ci if (err) 237262306a36Sopenharmony_ci return err; 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci mana_fence_rqs(apc); 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci return 0; 237762306a36Sopenharmony_ci} 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_civoid mana_query_gf_stats(struct mana_port_context *apc) 238062306a36Sopenharmony_ci{ 238162306a36Sopenharmony_ci struct mana_query_gf_stat_resp resp = {}; 238262306a36Sopenharmony_ci struct mana_query_gf_stat_req req = {}; 238362306a36Sopenharmony_ci struct net_device *ndev = apc->ndev; 238462306a36Sopenharmony_ci int err; 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_GF_STAT, 238762306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 238862306a36Sopenharmony_ci req.req_stats = STATISTICS_FLAGS_HC_TX_BYTES | 238962306a36Sopenharmony_ci STATISTICS_FLAGS_HC_TX_UCAST_PACKETS | 239062306a36Sopenharmony_ci STATISTICS_FLAGS_HC_TX_UCAST_BYTES | 239162306a36Sopenharmony_ci STATISTICS_FLAGS_HC_TX_MCAST_PACKETS | 239262306a36Sopenharmony_ci STATISTICS_FLAGS_HC_TX_MCAST_BYTES | 239362306a36Sopenharmony_ci STATISTICS_FLAGS_HC_TX_BCAST_PACKETS | 239462306a36Sopenharmony_ci STATISTICS_FLAGS_HC_TX_BCAST_BYTES; 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 239762306a36Sopenharmony_ci sizeof(resp)); 239862306a36Sopenharmony_ci if (err) { 239962306a36Sopenharmony_ci netdev_err(ndev, "Failed to query GF stats: %d\n", err); 240062306a36Sopenharmony_ci return; 240162306a36Sopenharmony_ci } 240262306a36Sopenharmony_ci err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_GF_STAT, 240362306a36Sopenharmony_ci sizeof(resp)); 240462306a36Sopenharmony_ci if (err || resp.hdr.status) { 240562306a36Sopenharmony_ci netdev_err(ndev, "Failed to query GF stats: %d, 0x%x\n", err, 240662306a36Sopenharmony_ci resp.hdr.status); 240762306a36Sopenharmony_ci return; 240862306a36Sopenharmony_ci } 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci apc->eth_stats.hc_tx_bytes = resp.hc_tx_bytes; 241162306a36Sopenharmony_ci apc->eth_stats.hc_tx_ucast_pkts = resp.hc_tx_ucast_pkts; 241262306a36Sopenharmony_ci apc->eth_stats.hc_tx_ucast_bytes = resp.hc_tx_ucast_bytes; 241362306a36Sopenharmony_ci apc->eth_stats.hc_tx_bcast_pkts = resp.hc_tx_bcast_pkts; 241462306a36Sopenharmony_ci apc->eth_stats.hc_tx_bcast_bytes = resp.hc_tx_bcast_bytes; 241562306a36Sopenharmony_ci apc->eth_stats.hc_tx_mcast_pkts = resp.hc_tx_mcast_pkts; 241662306a36Sopenharmony_ci apc->eth_stats.hc_tx_mcast_bytes = resp.hc_tx_mcast_bytes; 241762306a36Sopenharmony_ci} 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_cistatic int mana_init_port(struct net_device *ndev) 242062306a36Sopenharmony_ci{ 242162306a36Sopenharmony_ci struct mana_port_context *apc = netdev_priv(ndev); 242262306a36Sopenharmony_ci u32 max_txq, max_rxq, max_queues; 242362306a36Sopenharmony_ci int port_idx = apc->port_idx; 242462306a36Sopenharmony_ci u32 num_indirect_entries; 242562306a36Sopenharmony_ci int err; 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci err = mana_init_port_context(apc); 242862306a36Sopenharmony_ci if (err) 242962306a36Sopenharmony_ci return err; 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci err = mana_query_vport_cfg(apc, port_idx, &max_txq, &max_rxq, 243262306a36Sopenharmony_ci &num_indirect_entries); 243362306a36Sopenharmony_ci if (err) { 243462306a36Sopenharmony_ci netdev_err(ndev, "Failed to query info for vPort %d\n", 243562306a36Sopenharmony_ci port_idx); 243662306a36Sopenharmony_ci goto reset_apc; 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci max_queues = min_t(u32, max_txq, max_rxq); 244062306a36Sopenharmony_ci if (apc->max_queues > max_queues) 244162306a36Sopenharmony_ci apc->max_queues = max_queues; 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci if (apc->num_queues > apc->max_queues) 244462306a36Sopenharmony_ci apc->num_queues = apc->max_queues; 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci eth_hw_addr_set(ndev, apc->mac_addr); 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci return 0; 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_cireset_apc: 245162306a36Sopenharmony_ci kfree(apc->rxqs); 245262306a36Sopenharmony_ci apc->rxqs = NULL; 245362306a36Sopenharmony_ci return err; 245462306a36Sopenharmony_ci} 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ciint mana_alloc_queues(struct net_device *ndev) 245762306a36Sopenharmony_ci{ 245862306a36Sopenharmony_ci struct mana_port_context *apc = netdev_priv(ndev); 245962306a36Sopenharmony_ci struct gdma_dev *gd = apc->ac->gdma_dev; 246062306a36Sopenharmony_ci int err; 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci err = mana_create_vport(apc, ndev); 246362306a36Sopenharmony_ci if (err) 246462306a36Sopenharmony_ci return err; 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci err = netif_set_real_num_tx_queues(ndev, apc->num_queues); 246762306a36Sopenharmony_ci if (err) 246862306a36Sopenharmony_ci goto destroy_vport; 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci err = mana_add_rx_queues(apc, ndev); 247162306a36Sopenharmony_ci if (err) 247262306a36Sopenharmony_ci goto destroy_vport; 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci apc->rss_state = apc->num_queues > 1 ? TRI_STATE_TRUE : TRI_STATE_FALSE; 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci err = netif_set_real_num_rx_queues(ndev, apc->num_queues); 247762306a36Sopenharmony_ci if (err) 247862306a36Sopenharmony_ci goto destroy_vport; 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci mana_rss_table_init(apc); 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci err = mana_config_rss(apc, TRI_STATE_TRUE, true, true); 248362306a36Sopenharmony_ci if (err) 248462306a36Sopenharmony_ci goto destroy_vport; 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci if (gd->gdma_context->is_pf) { 248762306a36Sopenharmony_ci err = mana_pf_register_filter(apc); 248862306a36Sopenharmony_ci if (err) 248962306a36Sopenharmony_ci goto destroy_vport; 249062306a36Sopenharmony_ci } 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci mana_chn_setxdp(apc, mana_xdp_get(apc)); 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci return 0; 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_cidestroy_vport: 249762306a36Sopenharmony_ci mana_destroy_vport(apc); 249862306a36Sopenharmony_ci return err; 249962306a36Sopenharmony_ci} 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ciint mana_attach(struct net_device *ndev) 250262306a36Sopenharmony_ci{ 250362306a36Sopenharmony_ci struct mana_port_context *apc = netdev_priv(ndev); 250462306a36Sopenharmony_ci int err; 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci ASSERT_RTNL(); 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci err = mana_init_port(ndev); 250962306a36Sopenharmony_ci if (err) 251062306a36Sopenharmony_ci return err; 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci if (apc->port_st_save) { 251362306a36Sopenharmony_ci err = mana_alloc_queues(ndev); 251462306a36Sopenharmony_ci if (err) { 251562306a36Sopenharmony_ci mana_cleanup_port_context(apc); 251662306a36Sopenharmony_ci return err; 251762306a36Sopenharmony_ci } 251862306a36Sopenharmony_ci } 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci apc->port_is_up = apc->port_st_save; 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci /* Ensure port state updated before txq state */ 252362306a36Sopenharmony_ci smp_wmb(); 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ci if (apc->port_is_up) 252662306a36Sopenharmony_ci netif_carrier_on(ndev); 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci netif_device_attach(ndev); 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci return 0; 253162306a36Sopenharmony_ci} 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_cistatic int mana_dealloc_queues(struct net_device *ndev) 253462306a36Sopenharmony_ci{ 253562306a36Sopenharmony_ci struct mana_port_context *apc = netdev_priv(ndev); 253662306a36Sopenharmony_ci unsigned long timeout = jiffies + 120 * HZ; 253762306a36Sopenharmony_ci struct gdma_dev *gd = apc->ac->gdma_dev; 253862306a36Sopenharmony_ci struct mana_txq *txq; 253962306a36Sopenharmony_ci struct sk_buff *skb; 254062306a36Sopenharmony_ci int i, err; 254162306a36Sopenharmony_ci u32 tsleep; 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci if (apc->port_is_up) 254462306a36Sopenharmony_ci return -EINVAL; 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci mana_chn_setxdp(apc, NULL); 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci if (gd->gdma_context->is_pf) 254962306a36Sopenharmony_ci mana_pf_deregister_filter(apc); 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci /* No packet can be transmitted now since apc->port_is_up is false. 255262306a36Sopenharmony_ci * There is still a tiny chance that mana_poll_tx_cq() can re-enable 255362306a36Sopenharmony_ci * a txq because it may not timely see apc->port_is_up being cleared 255462306a36Sopenharmony_ci * to false, but it doesn't matter since mana_start_xmit() drops any 255562306a36Sopenharmony_ci * new packets due to apc->port_is_up being false. 255662306a36Sopenharmony_ci * 255762306a36Sopenharmony_ci * Drain all the in-flight TX packets. 255862306a36Sopenharmony_ci * A timeout of 120 seconds for all the queues is used. 255962306a36Sopenharmony_ci * This will break the while loop when h/w is not responding. 256062306a36Sopenharmony_ci * This value of 120 has been decided here considering max 256162306a36Sopenharmony_ci * number of queues. 256262306a36Sopenharmony_ci */ 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci for (i = 0; i < apc->num_queues; i++) { 256562306a36Sopenharmony_ci txq = &apc->tx_qp[i].txq; 256662306a36Sopenharmony_ci tsleep = 1000; 256762306a36Sopenharmony_ci while (atomic_read(&txq->pending_sends) > 0 && 256862306a36Sopenharmony_ci time_before(jiffies, timeout)) { 256962306a36Sopenharmony_ci usleep_range(tsleep, tsleep + 1000); 257062306a36Sopenharmony_ci tsleep <<= 1; 257162306a36Sopenharmony_ci } 257262306a36Sopenharmony_ci if (atomic_read(&txq->pending_sends)) { 257362306a36Sopenharmony_ci err = pcie_flr(to_pci_dev(gd->gdma_context->dev)); 257462306a36Sopenharmony_ci if (err) { 257562306a36Sopenharmony_ci netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n", 257662306a36Sopenharmony_ci err, atomic_read(&txq->pending_sends), 257762306a36Sopenharmony_ci txq->gdma_txq_id); 257862306a36Sopenharmony_ci } 257962306a36Sopenharmony_ci break; 258062306a36Sopenharmony_ci } 258162306a36Sopenharmony_ci } 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci for (i = 0; i < apc->num_queues; i++) { 258462306a36Sopenharmony_ci txq = &apc->tx_qp[i].txq; 258562306a36Sopenharmony_ci while ((skb = skb_dequeue(&txq->pending_skbs))) { 258662306a36Sopenharmony_ci mana_unmap_skb(skb, apc); 258762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 258862306a36Sopenharmony_ci } 258962306a36Sopenharmony_ci atomic_set(&txq->pending_sends, 0); 259062306a36Sopenharmony_ci } 259162306a36Sopenharmony_ci /* We're 100% sure the queues can no longer be woken up, because 259262306a36Sopenharmony_ci * we're sure now mana_poll_tx_cq() can't be running. 259362306a36Sopenharmony_ci */ 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci apc->rss_state = TRI_STATE_FALSE; 259662306a36Sopenharmony_ci err = mana_config_rss(apc, TRI_STATE_FALSE, false, false); 259762306a36Sopenharmony_ci if (err) { 259862306a36Sopenharmony_ci netdev_err(ndev, "Failed to disable vPort: %d\n", err); 259962306a36Sopenharmony_ci return err; 260062306a36Sopenharmony_ci } 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci mana_destroy_vport(apc); 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ci return 0; 260562306a36Sopenharmony_ci} 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ciint mana_detach(struct net_device *ndev, bool from_close) 260862306a36Sopenharmony_ci{ 260962306a36Sopenharmony_ci struct mana_port_context *apc = netdev_priv(ndev); 261062306a36Sopenharmony_ci int err; 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_ci ASSERT_RTNL(); 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_ci apc->port_st_save = apc->port_is_up; 261562306a36Sopenharmony_ci apc->port_is_up = false; 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci /* Ensure port state updated before txq state */ 261862306a36Sopenharmony_ci smp_wmb(); 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_ci netif_tx_disable(ndev); 262162306a36Sopenharmony_ci netif_carrier_off(ndev); 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_ci if (apc->port_st_save) { 262462306a36Sopenharmony_ci err = mana_dealloc_queues(ndev); 262562306a36Sopenharmony_ci if (err) 262662306a36Sopenharmony_ci return err; 262762306a36Sopenharmony_ci } 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci if (!from_close) { 263062306a36Sopenharmony_ci netif_device_detach(ndev); 263162306a36Sopenharmony_ci mana_cleanup_port_context(apc); 263262306a36Sopenharmony_ci } 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci return 0; 263562306a36Sopenharmony_ci} 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_cistatic int mana_probe_port(struct mana_context *ac, int port_idx, 263862306a36Sopenharmony_ci struct net_device **ndev_storage) 263962306a36Sopenharmony_ci{ 264062306a36Sopenharmony_ci struct gdma_context *gc = ac->gdma_dev->gdma_context; 264162306a36Sopenharmony_ci struct mana_port_context *apc; 264262306a36Sopenharmony_ci struct net_device *ndev; 264362306a36Sopenharmony_ci int err; 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci ndev = alloc_etherdev_mq(sizeof(struct mana_port_context), 264662306a36Sopenharmony_ci gc->max_num_queues); 264762306a36Sopenharmony_ci if (!ndev) 264862306a36Sopenharmony_ci return -ENOMEM; 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci *ndev_storage = ndev; 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_ci apc = netdev_priv(ndev); 265362306a36Sopenharmony_ci apc->ac = ac; 265462306a36Sopenharmony_ci apc->ndev = ndev; 265562306a36Sopenharmony_ci apc->max_queues = gc->max_num_queues; 265662306a36Sopenharmony_ci apc->num_queues = gc->max_num_queues; 265762306a36Sopenharmony_ci apc->port_handle = INVALID_MANA_HANDLE; 265862306a36Sopenharmony_ci apc->pf_filter_handle = INVALID_MANA_HANDLE; 265962306a36Sopenharmony_ci apc->port_idx = port_idx; 266062306a36Sopenharmony_ci 266162306a36Sopenharmony_ci mutex_init(&apc->vport_mutex); 266262306a36Sopenharmony_ci apc->vport_use_count = 0; 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_ci ndev->netdev_ops = &mana_devops; 266562306a36Sopenharmony_ci ndev->ethtool_ops = &mana_ethtool_ops; 266662306a36Sopenharmony_ci ndev->mtu = ETH_DATA_LEN; 266762306a36Sopenharmony_ci ndev->max_mtu = gc->adapter_mtu - ETH_HLEN; 266862306a36Sopenharmony_ci ndev->min_mtu = ETH_MIN_MTU; 266962306a36Sopenharmony_ci ndev->needed_headroom = MANA_HEADROOM; 267062306a36Sopenharmony_ci ndev->dev_port = port_idx; 267162306a36Sopenharmony_ci SET_NETDEV_DEV(ndev, gc->dev); 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci netif_carrier_off(ndev); 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci netdev_rss_key_fill(apc->hashkey, MANA_HASH_KEY_SIZE); 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci err = mana_init_port(ndev); 267862306a36Sopenharmony_ci if (err) 267962306a36Sopenharmony_ci goto free_net; 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci netdev_lockdep_set_classes(ndev); 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_ci ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; 268462306a36Sopenharmony_ci ndev->hw_features |= NETIF_F_RXCSUM; 268562306a36Sopenharmony_ci ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; 268662306a36Sopenharmony_ci ndev->hw_features |= NETIF_F_RXHASH; 268762306a36Sopenharmony_ci ndev->features = ndev->hw_features | NETIF_F_HW_VLAN_CTAG_TX | 268862306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX; 268962306a36Sopenharmony_ci ndev->vlan_features = ndev->features; 269062306a36Sopenharmony_ci ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | 269162306a36Sopenharmony_ci NETDEV_XDP_ACT_NDO_XMIT; 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ci err = register_netdev(ndev); 269462306a36Sopenharmony_ci if (err) { 269562306a36Sopenharmony_ci netdev_err(ndev, "Unable to register netdev.\n"); 269662306a36Sopenharmony_ci goto reset_apc; 269762306a36Sopenharmony_ci } 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci return 0; 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_cireset_apc: 270262306a36Sopenharmony_ci kfree(apc->rxqs); 270362306a36Sopenharmony_ci apc->rxqs = NULL; 270462306a36Sopenharmony_cifree_net: 270562306a36Sopenharmony_ci *ndev_storage = NULL; 270662306a36Sopenharmony_ci netdev_err(ndev, "Failed to probe vPort %d: %d\n", port_idx, err); 270762306a36Sopenharmony_ci free_netdev(ndev); 270862306a36Sopenharmony_ci return err; 270962306a36Sopenharmony_ci} 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_cistatic void adev_release(struct device *dev) 271262306a36Sopenharmony_ci{ 271362306a36Sopenharmony_ci struct mana_adev *madev = container_of(dev, struct mana_adev, adev.dev); 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci kfree(madev); 271662306a36Sopenharmony_ci} 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_cistatic void remove_adev(struct gdma_dev *gd) 271962306a36Sopenharmony_ci{ 272062306a36Sopenharmony_ci struct auxiliary_device *adev = gd->adev; 272162306a36Sopenharmony_ci int id = adev->id; 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_ci auxiliary_device_delete(adev); 272462306a36Sopenharmony_ci auxiliary_device_uninit(adev); 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci mana_adev_idx_free(id); 272762306a36Sopenharmony_ci gd->adev = NULL; 272862306a36Sopenharmony_ci} 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_cistatic int add_adev(struct gdma_dev *gd) 273162306a36Sopenharmony_ci{ 273262306a36Sopenharmony_ci struct auxiliary_device *adev; 273362306a36Sopenharmony_ci struct mana_adev *madev; 273462306a36Sopenharmony_ci int ret; 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci madev = kzalloc(sizeof(*madev), GFP_KERNEL); 273762306a36Sopenharmony_ci if (!madev) 273862306a36Sopenharmony_ci return -ENOMEM; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci adev = &madev->adev; 274162306a36Sopenharmony_ci ret = mana_adev_idx_alloc(); 274262306a36Sopenharmony_ci if (ret < 0) 274362306a36Sopenharmony_ci goto idx_fail; 274462306a36Sopenharmony_ci adev->id = ret; 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_ci adev->name = "rdma"; 274762306a36Sopenharmony_ci adev->dev.parent = gd->gdma_context->dev; 274862306a36Sopenharmony_ci adev->dev.release = adev_release; 274962306a36Sopenharmony_ci madev->mdev = gd; 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci ret = auxiliary_device_init(adev); 275262306a36Sopenharmony_ci if (ret) 275362306a36Sopenharmony_ci goto init_fail; 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ci ret = auxiliary_device_add(adev); 275662306a36Sopenharmony_ci if (ret) 275762306a36Sopenharmony_ci goto add_fail; 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci gd->adev = adev; 276062306a36Sopenharmony_ci return 0; 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_ciadd_fail: 276362306a36Sopenharmony_ci auxiliary_device_uninit(adev); 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ciinit_fail: 276662306a36Sopenharmony_ci mana_adev_idx_free(adev->id); 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ciidx_fail: 276962306a36Sopenharmony_ci kfree(madev); 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_ci return ret; 277262306a36Sopenharmony_ci} 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ciint mana_probe(struct gdma_dev *gd, bool resuming) 277562306a36Sopenharmony_ci{ 277662306a36Sopenharmony_ci struct gdma_context *gc = gd->gdma_context; 277762306a36Sopenharmony_ci struct mana_context *ac = gd->driver_data; 277862306a36Sopenharmony_ci struct device *dev = gc->dev; 277962306a36Sopenharmony_ci u16 num_ports = 0; 278062306a36Sopenharmony_ci int err; 278162306a36Sopenharmony_ci int i; 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci dev_info(dev, 278462306a36Sopenharmony_ci "Microsoft Azure Network Adapter protocol version: %d.%d.%d\n", 278562306a36Sopenharmony_ci MANA_MAJOR_VERSION, MANA_MINOR_VERSION, MANA_MICRO_VERSION); 278662306a36Sopenharmony_ci 278762306a36Sopenharmony_ci err = mana_gd_register_device(gd); 278862306a36Sopenharmony_ci if (err) 278962306a36Sopenharmony_ci return err; 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci if (!resuming) { 279262306a36Sopenharmony_ci ac = kzalloc(sizeof(*ac), GFP_KERNEL); 279362306a36Sopenharmony_ci if (!ac) 279462306a36Sopenharmony_ci return -ENOMEM; 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_ci ac->gdma_dev = gd; 279762306a36Sopenharmony_ci gd->driver_data = ac; 279862306a36Sopenharmony_ci } 279962306a36Sopenharmony_ci 280062306a36Sopenharmony_ci err = mana_create_eq(ac); 280162306a36Sopenharmony_ci if (err) 280262306a36Sopenharmony_ci goto out; 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci err = mana_query_device_cfg(ac, MANA_MAJOR_VERSION, MANA_MINOR_VERSION, 280562306a36Sopenharmony_ci MANA_MICRO_VERSION, &num_ports); 280662306a36Sopenharmony_ci if (err) 280762306a36Sopenharmony_ci goto out; 280862306a36Sopenharmony_ci 280962306a36Sopenharmony_ci if (!resuming) { 281062306a36Sopenharmony_ci ac->num_ports = num_ports; 281162306a36Sopenharmony_ci } else { 281262306a36Sopenharmony_ci if (ac->num_ports != num_ports) { 281362306a36Sopenharmony_ci dev_err(dev, "The number of vPorts changed: %d->%d\n", 281462306a36Sopenharmony_ci ac->num_ports, num_ports); 281562306a36Sopenharmony_ci err = -EPROTO; 281662306a36Sopenharmony_ci goto out; 281762306a36Sopenharmony_ci } 281862306a36Sopenharmony_ci } 281962306a36Sopenharmony_ci 282062306a36Sopenharmony_ci if (ac->num_ports == 0) 282162306a36Sopenharmony_ci dev_err(dev, "Failed to detect any vPort\n"); 282262306a36Sopenharmony_ci 282362306a36Sopenharmony_ci if (ac->num_ports > MAX_PORTS_IN_MANA_DEV) 282462306a36Sopenharmony_ci ac->num_ports = MAX_PORTS_IN_MANA_DEV; 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci if (!resuming) { 282762306a36Sopenharmony_ci for (i = 0; i < ac->num_ports; i++) { 282862306a36Sopenharmony_ci err = mana_probe_port(ac, i, &ac->ports[i]); 282962306a36Sopenharmony_ci if (err) 283062306a36Sopenharmony_ci break; 283162306a36Sopenharmony_ci } 283262306a36Sopenharmony_ci } else { 283362306a36Sopenharmony_ci for (i = 0; i < ac->num_ports; i++) { 283462306a36Sopenharmony_ci rtnl_lock(); 283562306a36Sopenharmony_ci err = mana_attach(ac->ports[i]); 283662306a36Sopenharmony_ci rtnl_unlock(); 283762306a36Sopenharmony_ci if (err) 283862306a36Sopenharmony_ci break; 283962306a36Sopenharmony_ci } 284062306a36Sopenharmony_ci } 284162306a36Sopenharmony_ci 284262306a36Sopenharmony_ci err = add_adev(gd); 284362306a36Sopenharmony_ciout: 284462306a36Sopenharmony_ci if (err) 284562306a36Sopenharmony_ci mana_remove(gd, false); 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci return err; 284862306a36Sopenharmony_ci} 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_civoid mana_remove(struct gdma_dev *gd, bool suspending) 285162306a36Sopenharmony_ci{ 285262306a36Sopenharmony_ci struct gdma_context *gc = gd->gdma_context; 285362306a36Sopenharmony_ci struct mana_context *ac = gd->driver_data; 285462306a36Sopenharmony_ci struct device *dev = gc->dev; 285562306a36Sopenharmony_ci struct net_device *ndev; 285662306a36Sopenharmony_ci int err; 285762306a36Sopenharmony_ci int i; 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci /* adev currently doesn't support suspending, always remove it */ 286062306a36Sopenharmony_ci if (gd->adev) 286162306a36Sopenharmony_ci remove_adev(gd); 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci for (i = 0; i < ac->num_ports; i++) { 286462306a36Sopenharmony_ci ndev = ac->ports[i]; 286562306a36Sopenharmony_ci if (!ndev) { 286662306a36Sopenharmony_ci if (i == 0) 286762306a36Sopenharmony_ci dev_err(dev, "No net device to remove\n"); 286862306a36Sopenharmony_ci goto out; 286962306a36Sopenharmony_ci } 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci /* All cleanup actions should stay after rtnl_lock(), otherwise 287262306a36Sopenharmony_ci * other functions may access partially cleaned up data. 287362306a36Sopenharmony_ci */ 287462306a36Sopenharmony_ci rtnl_lock(); 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci err = mana_detach(ndev, false); 287762306a36Sopenharmony_ci if (err) 287862306a36Sopenharmony_ci netdev_err(ndev, "Failed to detach vPort %d: %d\n", 287962306a36Sopenharmony_ci i, err); 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci if (suspending) { 288262306a36Sopenharmony_ci /* No need to unregister the ndev. */ 288362306a36Sopenharmony_ci rtnl_unlock(); 288462306a36Sopenharmony_ci continue; 288562306a36Sopenharmony_ci } 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci unregister_netdevice(ndev); 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_ci rtnl_unlock(); 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci free_netdev(ndev); 289262306a36Sopenharmony_ci } 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci mana_destroy_eq(ac); 289562306a36Sopenharmony_ciout: 289662306a36Sopenharmony_ci mana_gd_deregister_device(gd); 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci if (suspending) 289962306a36Sopenharmony_ci return; 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_ci gd->driver_data = NULL; 290262306a36Sopenharmony_ci gd->gdma_context = NULL; 290362306a36Sopenharmony_ci kfree(ac); 290462306a36Sopenharmony_ci} 2905