aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSunil Goutham <sgoutham@cavium.com>2017-05-02 09:06:54 -0400
committerDavid S. Miller <davem@davemloft.net>2017-05-02 15:41:21 -0400
commit05c773f52b96ef3fbc7d9bfa21caadc6247ef7a8 (patch)
tree9d20a83f0b3f08bd3fcd3d0c00920abaa19dfb8c
parent927987f39f116db477fcd74ced2a2aea940e585c (diff)
net: thunderx: Add basic XDP support
Adds basic XDP support i.e attaching a BPF program to an interface. Also takes care of allocating separate Tx queues for XDP path and for network stack packet transmission. This patch doesn't support handling of any of the XDP actions, all are treated as XDP_PASS i.e packets will be handed over to the network stack. Changes also involve allocating one receive buffer per page in XDP mode and multiple in normal mode i.e when no BPF program is attached. Signed-off-by: Sunil Goutham <sgoutham@cavium.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic.h6
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c26
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_main.c162
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_queues.c15
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_queues.h9
5 files changed, 199 insertions, 19 deletions
diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h
index dca6aed49094..4a02e618e318 100644
--- a/drivers/net/ethernet/cavium/thunder/nic.h
+++ b/drivers/net/ethernet/cavium/thunder/nic.h
@@ -268,9 +268,9 @@ struct nicvf {
268 struct net_device *netdev; 268 struct net_device *netdev;
269 struct pci_dev *pdev; 269 struct pci_dev *pdev;
270 void __iomem *reg_base; 270 void __iomem *reg_base;
271 struct bpf_prog *xdp_prog;
271#define MAX_QUEUES_PER_QSET 8 272#define MAX_QUEUES_PER_QSET 8
272 struct queue_set *qs; 273 struct queue_set *qs;
273 struct nicvf_cq_poll *napi[8];
274 void *iommu_domain; 274 void *iommu_domain;
275 u8 vf_id; 275 u8 vf_id;
276 u8 sqs_id; 276 u8 sqs_id;
@@ -296,6 +296,7 @@ struct nicvf {
296 /* Queue count */ 296 /* Queue count */
297 u8 rx_queues; 297 u8 rx_queues;
298 u8 tx_queues; 298 u8 tx_queues;
299 u8 xdp_tx_queues;
299 u8 max_queues; 300 u8 max_queues;
300 301
301 u8 node; 302 u8 node;
@@ -320,6 +321,9 @@ struct nicvf {
320 struct nicvf_drv_stats __percpu *drv_stats; 321 struct nicvf_drv_stats __percpu *drv_stats;
321 struct bgx_stats bgx_stats; 322 struct bgx_stats bgx_stats;
322 323
324 /* Napi */
325 struct nicvf_cq_poll *napi[8];
326
323 /* MSI-X */ 327 /* MSI-X */
324 u8 num_vec; 328 u8 num_vec;
325 char irq_name[NIC_VF_MSIX_VECTORS][IFNAMSIZ + 15]; 329 char irq_name[NIC_VF_MSIX_VECTORS][IFNAMSIZ + 15];
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
index a89db5f3e26e..b9ece9cbf98b 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
@@ -721,7 +721,7 @@ static int nicvf_set_channels(struct net_device *dev,
721 struct nicvf *nic = netdev_priv(dev); 721 struct nicvf *nic = netdev_priv(dev);
722 int err = 0; 722 int err = 0;
723 bool if_up = netif_running(dev); 723 bool if_up = netif_running(dev);
724 int cqcount; 724 u8 cqcount, txq_count;
725 725
726 if (!channel->rx_count || !channel->tx_count) 726 if (!channel->rx_count || !channel->tx_count)
727 return -EINVAL; 727 return -EINVAL;
@@ -730,10 +730,26 @@ static int nicvf_set_channels(struct net_device *dev,
730 if (channel->tx_count > nic->max_queues) 730 if (channel->tx_count > nic->max_queues)
731 return -EINVAL; 731 return -EINVAL;
732 732
733 if (nic->xdp_prog &&
734 ((channel->tx_count + channel->rx_count) > nic->max_queues)) {
735 netdev_err(nic->netdev,
736 "XDP mode, RXQs + TXQs > Max %d\n",
737 nic->max_queues);
738 return -EINVAL;
739 }
740
733 if (if_up) 741 if (if_up)
734 nicvf_stop(dev); 742 nicvf_stop(dev);
735 743
736 cqcount = max(channel->rx_count, channel->tx_count); 744 nic->rx_queues = channel->rx_count;
745 nic->tx_queues = channel->tx_count;
746 if (!nic->xdp_prog)
747 nic->xdp_tx_queues = 0;
748 else
749 nic->xdp_tx_queues = channel->rx_count;
750
751 txq_count = nic->xdp_tx_queues + nic->tx_queues;
752 cqcount = max(nic->rx_queues, txq_count);
737 753
738 if (cqcount > MAX_CMP_QUEUES_PER_QS) { 754 if (cqcount > MAX_CMP_QUEUES_PER_QS) {
739 nic->sqs_count = roundup(cqcount, MAX_CMP_QUEUES_PER_QS); 755 nic->sqs_count = roundup(cqcount, MAX_CMP_QUEUES_PER_QS);
@@ -742,12 +758,10 @@ static int nicvf_set_channels(struct net_device *dev,
742 nic->sqs_count = 0; 758 nic->sqs_count = 0;
743 } 759 }
744 760
745 nic->qs->rq_cnt = min_t(u32, channel->rx_count, MAX_RCV_QUEUES_PER_QS); 761 nic->qs->rq_cnt = min_t(u8, nic->rx_queues, MAX_RCV_QUEUES_PER_QS);
746 nic->qs->sq_cnt = min_t(u32, channel->tx_count, MAX_SND_QUEUES_PER_QS); 762 nic->qs->sq_cnt = min_t(u8, txq_count, MAX_SND_QUEUES_PER_QS);
747 nic->qs->cq_cnt = max(nic->qs->rq_cnt, nic->qs->sq_cnt); 763 nic->qs->cq_cnt = max(nic->qs->rq_cnt, nic->qs->sq_cnt);
748 764
749 nic->rx_queues = channel->rx_count;
750 nic->tx_queues = channel->tx_count;
751 err = nicvf_set_real_num_queues(dev, nic->tx_queues, nic->rx_queues); 765 err = nicvf_set_real_num_queues(dev, nic->tx_queues, nic->rx_queues);
752 if (err) 766 if (err)
753 return err; 767 return err;
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
index 0d79894400ab..9c48873350f8 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
@@ -17,6 +17,8 @@
17#include <linux/prefetch.h> 17#include <linux/prefetch.h>
18#include <linux/irq.h> 18#include <linux/irq.h>
19#include <linux/iommu.h> 19#include <linux/iommu.h>
20#include <linux/bpf.h>
21#include <linux/filter.h>
20 22
21#include "nic_reg.h" 23#include "nic_reg.h"
22#include "nic.h" 24#include "nic.h"
@@ -397,8 +399,10 @@ static void nicvf_request_sqs(struct nicvf *nic)
397 399
398 if (nic->rx_queues > MAX_RCV_QUEUES_PER_QS) 400 if (nic->rx_queues > MAX_RCV_QUEUES_PER_QS)
399 rx_queues = nic->rx_queues - MAX_RCV_QUEUES_PER_QS; 401 rx_queues = nic->rx_queues - MAX_RCV_QUEUES_PER_QS;
400 if (nic->tx_queues > MAX_SND_QUEUES_PER_QS) 402
401 tx_queues = nic->tx_queues - MAX_SND_QUEUES_PER_QS; 403 tx_queues = nic->tx_queues + nic->xdp_tx_queues;
404 if (tx_queues > MAX_SND_QUEUES_PER_QS)
405 tx_queues = tx_queues - MAX_SND_QUEUES_PER_QS;
402 406
403 /* Set no of Rx/Tx queues in each of the SQsets */ 407 /* Set no of Rx/Tx queues in each of the SQsets */
404 for (sqs = 0; sqs < nic->sqs_count; sqs++) { 408 for (sqs = 0; sqs < nic->sqs_count; sqs++) {
@@ -496,6 +500,43 @@ static int nicvf_init_resources(struct nicvf *nic)
496 return 0; 500 return 0;
497} 501}
498 502
503static inline bool nicvf_xdp_rx(struct nicvf *nic,
504 struct bpf_prog *prog,
505 struct cqe_rx_t *cqe_rx)
506{
507 struct xdp_buff xdp;
508 u32 action;
509 u16 len;
510 u64 dma_addr, cpu_addr;
511
512 /* Retrieve packet buffer's DMA address and length */
513 len = *((u16 *)((void *)cqe_rx + (3 * sizeof(u64))));
514 dma_addr = *((u64 *)((void *)cqe_rx + (7 * sizeof(u64))));
515
516 cpu_addr = nicvf_iova_to_phys(nic, dma_addr);
517 if (!cpu_addr)
518 return false;
519
520 xdp.data = phys_to_virt(cpu_addr);
521 xdp.data_end = xdp.data + len;
522
523 rcu_read_lock();
524 action = bpf_prog_run_xdp(prog, &xdp);
525 rcu_read_unlock();
526
527 switch (action) {
528 case XDP_PASS:
529 case XDP_TX:
530 case XDP_ABORTED:
531 case XDP_DROP:
532 /* Pass on all packets to network stack */
533 return false;
534 default:
535 bpf_warn_invalid_xdp_action(action);
536 }
537 return false;
538}
539
499static void nicvf_snd_pkt_handler(struct net_device *netdev, 540static void nicvf_snd_pkt_handler(struct net_device *netdev,
500 struct cqe_send_t *cqe_tx, 541 struct cqe_send_t *cqe_tx,
501 int budget, int *subdesc_cnt, 542 int budget, int *subdesc_cnt,
@@ -599,6 +640,11 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,
599 return; 640 return;
600 } 641