nfp: add support for tx/rx with metadata portid
authorSimon Horman <simon.horman@netronome.com>
Fri, 23 Jun 2017 20:12:06 +0000 (22:12 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sun, 25 Jun 2017 15:42:01 +0000 (11:42 -0400)
Allow tx/rx with metadata port id. This will be used for tx/rx of
representor netdevs acting as upper-devices while a pf netdev acts
as a lower-device.

Signed-off-by: Simon Horman <simon.horman@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/nfp_net.h
drivers/net/ethernet/netronome/nfp/nfp_net_common.c

index b744679..b1fa77b 100644 (file)
@@ -318,6 +318,7 @@ struct nfp_meta_parsed {
        u8 csum_type;
        u32 hash;
        u32 mark;
+       u32 portid;
        __wsum csum;
 };
 
index 2134493..2e72854 100644 (file)
@@ -755,6 +755,26 @@ static void nfp_net_tx_xmit_more_flush(struct nfp_net_tx_ring *tx_ring)
        tx_ring->wr_ptr_add = 0;
 }
 
+static int nfp_net_prep_port_id(struct sk_buff *skb)
+{
+       struct metadata_dst *md_dst = skb_metadata_dst(skb);
+       unsigned char *data;
+
+       if (likely(!md_dst))
+               return 0;
+       if (unlikely(md_dst->type != METADATA_HW_PORT_MUX))
+               return 0;
+
+       if (unlikely(skb_cow_head(skb, 8)))
+               return -ENOMEM;
+
+       data = skb_push(skb, 8);
+       put_unaligned_be32(NFP_NET_META_PORTID, data);
+       put_unaligned_be32(md_dst->u.port_info.port_id, data + 4);
+
+       return 8;
+}
+
 /**
  * nfp_net_tx() - Main transmit entry point
  * @skb:    SKB to transmit
@@ -767,6 +787,7 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev)
        struct nfp_net *nn = netdev_priv(netdev);
        const struct skb_frag_struct *frag;
        struct nfp_net_tx_desc *txd, txdg;
+       int f, nr_frags, wr_idx, md_bytes;
        struct nfp_net_tx_ring *tx_ring;
        struct nfp_net_r_vector *r_vec;
        struct nfp_net_tx_buf *txbuf;
@@ -774,8 +795,6 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev)
        struct nfp_net_dp *dp;
        dma_addr_t dma_addr;
        unsigned int fsize;
-       int f, nr_frags;
-       int wr_idx;
        u16 qidx;
 
        dp = &nn->dp;
@@ -797,6 +816,13 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev)
                return NETDEV_TX_BUSY;
        }
 
+       md_bytes = nfp_net_prep_port_id(skb);
+       if (unlikely(md_bytes < 0)) {
+               nfp_net_tx_xmit_more_flush(tx_ring);
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
+       }
+
        /* Start with the head skbuf */
        dma_addr = dma_map_single(dp->dev, skb->data, skb_headlen(skb),
                                  DMA_TO_DEVICE);
@@ -815,7 +841,7 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev)
 
        /* Build TX descriptor */
        txd = &tx_ring->txds[wr_idx];
-       txd->offset_eop = (nr_frags == 0) ? PCIE_DESC_TX_EOP : 0;
+       txd->offset_eop = (nr_frags ? 0 : PCIE_DESC_TX_EOP) | md_bytes;
        txd->dma_len = cpu_to_le16(skb_headlen(skb));
        nfp_desc_set_dma_addr(txd, dma_addr);
        txd->data_len = cpu_to_le16(skb->len);
@@ -855,7 +881,7 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev)
                        *txd = txdg;
                        txd->dma_len = cpu_to_le16(fsize);
                        nfp_desc_set_dma_addr(txd, dma_addr);
-                       txd->offset_eop =
+                       txd->offset_eop |=
                                (f == nr_frags - 1) ? PCIE_DESC_TX_EOP : 0;
                }
 
@@ -1450,6 +1476,10 @@ nfp_net_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
                        meta->mark = get_unaligned_be32(data);
                        data += 4;
                        break;
+               case NFP_NET_META_PORTID:
+                       meta->portid = get_unaligned_be32(data);
+                       data += 4;
+                       break;
                case NFP_NET_META_CSUM:
                        meta->csum_type = CHECKSUM_COMPLETE;
                        meta->csum =
@@ -1594,6 +1624,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
                struct nfp_net_rx_buf *rxbuf;
                struct nfp_net_rx_desc *rxd;
                struct nfp_meta_parsed meta;
+               struct net_device *netdev;
                dma_addr_t new_dma_addr;
                void *new_frag;
 
@@ -1672,7 +1703,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
                }
 
                if (xdp_prog && !(rxd->rxd.flags & PCIE_DESC_RX_BPF &&
-                                 dp->bpf_offload_xdp)) {
+                                 dp->bpf_offload_xdp) && !meta.portid) {
                        unsigned int dma_off;
                        void *hard_start;
                        int act;
@@ -1718,6 +1749,20 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
                        continue;
                }
 
+               if (likely(!meta.portid)) {
+                       netdev = dp->netdev;
+               } else {
+                       struct nfp_net *nn;
+
+                       nn = netdev_priv(dp->netdev);
+                       netdev = nfp_app_repr_get(nn->app, meta.portid);
+                       if (unlikely(!netdev)) {
+                               nfp_net_rx_drop(dp, r_vec, rx_ring, rxbuf, skb);
+                               continue;
+                       }
+                       nfp_repr_inc_rx_stats(netdev, pkt_len);
+               }
+
                nfp_net_dma_unmap_rx(dp, rxbuf->dma_addr);
 
                nfp_net_rx_give_one(dp, rx_ring, new_frag, new_dma_addr);
@@ -1729,7 +1774,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
                skb_set_hash(skb, meta.hash, meta.hash_type);
 
                skb_record_rx_queue(skb, rx_ring->idx);
-               skb->protocol = eth_type_trans(skb, dp->netdev);
+               skb->protocol = eth_type_trans(skb, netdev);
 
                nfp_net_rx_csum(dp, r_vec, rxd, &meta, skb);