Skip to content

Commit 05c773f

Browse files
Sunil Gouthamdavem330
Sunil Goutham
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 927987f commit 05c773f

File tree

5 files changed

+199
-19
lines changed

5 files changed

+199
-19
lines changed

drivers/net/ethernet/cavium/thunder/nic.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,9 @@ struct nicvf {
268268
struct net_device *netdev;
269269
struct pci_dev *pdev;
270270
void __iomem *reg_base;
271+
struct bpf_prog *xdp_prog;
271272
#define MAX_QUEUES_PER_QSET 8
272273
struct queue_set *qs;
273-
struct nicvf_cq_poll *napi[8];
274274
void *iommu_domain;
275275
u8 vf_id;
276276
u8 sqs_id;
@@ -296,6 +296,7 @@ struct nicvf {
296296
/* Queue count */
297297
u8 rx_queues;
298298
u8 tx_queues;
299+
u8 xdp_tx_queues;
299300
u8 max_queues;
300301

301302
u8 node;
@@ -320,6 +321,9 @@ struct nicvf {
320321
struct nicvf_drv_stats __percpu *drv_stats;
321322
struct bgx_stats bgx_stats;
322323

324+
/* Napi */
325+
struct nicvf_cq_poll *napi[8];
326+
323327
/* MSI-X */
324328
u8 num_vec;
325329
char irq_name[NIC_VF_MSIX_VECTORS][IFNAMSIZ + 15];

drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c

+20-6
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ static int nicvf_set_channels(struct net_device *dev,
721721
struct nicvf *nic = netdev_priv(dev);
722722
int err = 0;
723723
bool if_up = netif_running(dev);
724-
int cqcount;
724+
u8 cqcount, txq_count;
725725

726726
if (!channel->rx_count || !channel->tx_count)
727727
return -EINVAL;
@@ -730,10 +730,26 @@ static int nicvf_set_channels(struct net_device *dev,
730730
if (channel->tx_count > nic->max_queues)
731731
return -EINVAL;
732732

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+
733741
if (if_up)
734742
nicvf_stop(dev);
735743

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);
737753

738754
if (cqcount > MAX_CMP_QUEUES_PER_QS) {
739755
nic->sqs_count = roundup(cqcount, MAX_CMP_QUEUES_PER_QS);
@@ -742,12 +758,10 @@ static int nicvf_set_channels(struct net_device *dev,
742758
nic->sqs_count = 0;
743759
}
744760

745-
nic->qs->rq_cnt = min_t(u32, channel->rx_count, MAX_RCV_QUEUES_PER_QS);
746-
nic->qs->sq_cnt = min_t(u32, channel->tx_count, MAX_SND_QUEUES_PER_QS);
761+
nic->qs->rq_cnt = min_t(u8, nic->rx_queues, MAX_RCV_QUEUES_PER_QS);
762+
nic->qs->sq_cnt = min_t(u8, txq_count, MAX_SND_QUEUES_PER_QS);
747763
nic->qs->cq_cnt = max(nic->qs->rq_cnt, nic->qs->sq_cnt);
748764

749-
nic->rx_queues = channel->rx_count;
750-
nic->tx_queues = channel->tx_count;
751765
err = nicvf_set_real_num_queues(dev, nic->tx_queues, nic->rx_queues);
752766
if (err)
753767
return err;

drivers/net/ethernet/cavium/thunder/nicvf_main.c

+160-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <linux/prefetch.h>
1818
#include <linux/irq.h>
1919
#include <linux/iommu.h>
20+
#include <linux/bpf.h>
21+
#include <linux/filter.h>
2022

2123
#include "nic_reg.h"
2224
#include "nic.h"
@@ -397,8 +399,10 @@ static void nicvf_request_sqs(struct nicvf *nic)
397399

398400
if (nic->rx_queues > MAX_RCV_QUEUES_PER_QS)
399401
rx_queues = nic->rx_queues - MAX_RCV_QUEUES_PER_QS;
400-
if (nic->tx_queues > MAX_SND_QUEUES_PER_QS)
401-
tx_queues = nic->tx_queues - MAX_SND_QUEUES_PER_QS;
402+
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;
402406

403407
/* Set no of Rx/Tx queues in each of the SQsets */
404408
for (sqs = 0; sqs < nic->sqs_count; sqs++) {
@@ -496,6 +500,43 @@ static int nicvf_init_resources(struct nicvf *nic)
496500
return 0;
497501
}
498502

503+
static 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+
499540
static void nicvf_snd_pkt_handler(struct net_device *netdev,
500541
struct cqe_send_t *cqe_tx,
501542
int budget, int *subdesc_cnt,
@@ -599,6 +640,11 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,
599640
return;
600641
}
601642

643+
/* For XDP, ignore pkts spanning multiple pages */
644+
if (nic->xdp_prog && (cqe_rx->rb_cnt == 1))
645+
if (nicvf_xdp_rx(snic, nic->xdp_prog, cqe_rx))
646+
return;
647+
602648
skb = nicvf_get_rcv_skb(snic, cqe_rx);
603649
if (!skb) {
604650
netdev_dbg(nic->netdev, "Packet not received\n");
@@ -1529,6 +1575,117 @@ static int nicvf_set_features(struct net_device *netdev,
15291575
return 0;
15301576
}
15311577

1578+
static void nicvf_set_xdp_queues(struct nicvf *nic, bool bpf_attached)
1579+
{
1580+
u8 cq_count, txq_count;
1581+
1582+
/* Set XDP Tx queue count same as Rx queue count */
1583+
if (!bpf_attached)
1584+
nic->xdp_tx_queues = 0;
1585+
else
1586+
nic->xdp_tx_queues = nic->rx_queues;
1587+
1588+
/* If queue count > MAX_CMP_QUEUES_PER_QS, then additional qsets
1589+
* needs to be allocated, check how many.
1590+
*/
1591+
txq_count = nic->xdp_tx_queues + nic->tx_queues;
1592+
cq_count = max(nic->rx_queues, txq_count);
1593+
if (cq_count > MAX_CMP_QUEUES_PER_QS) {
1594+
nic->sqs_count = roundup(cq_count, MAX_CMP_QUEUES_PER_QS);
1595+
nic->sqs_count = (nic->sqs_count / MAX_CMP_QUEUES_PER_QS) - 1;
1596+
} else {
1597+
nic->sqs_count = 0;
1598+
}
1599+
1600+
/* Set primary Qset's resources */
1601+
nic->qs->rq_cnt = min_t(u8, nic->rx_queues, MAX_RCV_QUEUES_PER_QS);
1602+
nic->qs->sq_cnt = min_t(u8, txq_count, MAX_SND_QUEUES_PER_QS);
1603+
nic->qs->cq_cnt = max_t(u8, nic->qs->rq_cnt, nic->qs->sq_cnt);
1604+
1605+
/* Update stack */
1606+
nicvf_set_real_num_queues(nic->netdev, nic->tx_queues, nic->rx_queues);
1607+
}
1608+
1609+
static int nicvf_xdp_setup(struct nicvf *nic, struct bpf_prog *prog)
1610+
{
1611+
struct net_device *dev = nic->netdev;
1612+
bool if_up = netif_running(nic->netdev);
1613+
struct bpf_prog *old_prog;
1614+
bool bpf_attached = false;
1615+
1616+
/* For now just support only the usual MTU sized frames */
1617+
if (prog && (dev->mtu > 1500)) {
1618+
netdev_warn(dev, "Jumbo frames not yet supported with XDP, current MTU %d.\n",
1619+
dev->mtu);
1620+
return -EOPNOTSUPP;
1621+
}
1622+
1623+
if (prog && prog->xdp_adjust_head)
1624+
return -EOPNOTSUPP;
1625+
1626+
/* ALL SQs attached to CQs i.e same as RQs, are treated as
1627+
* XDP Tx queues and more Tx queues are allocated for
1628+
* network stack to send pkts out.
1629+
*
1630+
* No of Tx queues are either same as Rx queues or whatever
1631+
* is left in max no of queues possible.
1632+
*/
1633+
if ((nic->rx_queues + nic->tx_queues) > nic->max_queues) {
1634+
netdev_warn(dev,
1635+
"Failed to attach BPF prog, RXQs + TXQs > Max %d\n",
1636+
nic->max_queues);
1637+
return -ENOMEM;
1638+
}
1639+
1640+
if (if_up)
1641+
nicvf_stop(nic->netdev);
1642+
1643+
old_prog = xchg(&nic->xdp_prog, prog);
1644+
/* Detach old prog, if any */
1645+
if (old_prog)
1646+
bpf_prog_put(old_prog);
1647+
1648+
if (nic->xdp_prog) {
1649+
/* Attach BPF program */
1650+
nic->xdp_prog = bpf_prog_add(nic->xdp_prog, nic->rx_queues - 1);
1651+
if (!IS_ERR(nic->xdp_prog))
1652+
bpf_attached = true;
1653+
}
1654+
1655+
/* Calculate Tx queues needed for XDP and network stack */
1656+
nicvf_set_xdp_queues(nic, bpf_attached);
1657+
1658+
if (if_up) {
1659+
/* Reinitialize interface, clean slate */
1660+
nicvf_open(nic->netdev);
1661+
netif_trans_update(nic->netdev);
1662+
}
1663+
1664+
return 0;
1665+
}
1666+
1667+
static int nicvf_xdp(struct net_device *netdev, struct netdev_xdp *xdp)
1668+
{
1669+
struct nicvf *nic = netdev_priv(netdev);
1670+
1671+
/* To avoid checks while retrieving buffer address from CQE_RX,
1672+
* do not support XDP for T88 pass1.x silicons which are anyway
1673+
* not in use widely.
1674+
*/
1675+
if (pass1_silicon(nic->pdev))
1676+
return -EOPNOTSUPP;
1677+
1678+
switch (xdp->command) {
1679+
case XDP_SETUP_PROG:
1680+
return nicvf_xdp_setup(nic, xdp->prog);
1681+
case XDP_QUERY_PROG:
1682+
xdp->prog_attached = !!nic->xdp_prog;
1683+
return 0;
1684+
default:
1685+
return -EINVAL;
1686+
}
1687+
}
1688+
15321689
static const struct net_device_ops nicvf_netdev_ops = {
15331690
.ndo_open = nicvf_open,
15341691
.ndo_stop = nicvf_stop,
@@ -1539,6 +1696,7 @@ static const struct net_device_ops nicvf_netdev_ops = {
15391696
.ndo_tx_timeout = nicvf_tx_timeout,
15401697
.ndo_fix_features = nicvf_fix_features,
15411698
.ndo_set_features = nicvf_set_features,
1699+
.ndo_xdp = nicvf_xdp,
15421700
};
15431701

15441702
static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)

drivers/net/ethernet/cavium/thunder/nicvf_queues.c

+5-10
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,6 @@
1919
#include "q_struct.h"
2020
#include "nicvf_queues.h"
2121

22-
static inline u64 nicvf_iova_to_phys(struct nicvf *nic, dma_addr_t dma_addr)
23-
{
24-
/* Translation is installed only when IOMMU is present */
25-
if (nic->iommu_domain)
26-
return iommu_iova_to_phys(nic->iommu_domain, dma_addr);
27-
return dma_addr;
28-
}
29-
3022
static void nicvf_get_page(struct nicvf *nic)
3123
{
3224
if (!nic->rb_pageref || !nic->rb_page)
@@ -149,8 +141,10 @@ static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, struct rbdr *rbdr,
149141
{
150142
struct pgcache *pgcache = NULL;
151143

152-
/* Check if request can be accomodated in previous allocated page */
153-
if (nic->rb_page &&
144+
/* Check if request can be accomodated in previous allocated page.
145+
* But in XDP mode only one buffer per page is permitted.
146+
*/
147+
if (!nic->pnicvf->xdp_prog && nic->rb_page &&
154148
((nic->rb_page_offset + buf_len) <= PAGE_SIZE)) {
155149
nic->rb_pageref++;
156150
goto ret;
@@ -961,6 +955,7 @@ int nicvf_set_qset_resources(struct nicvf *nic)
961955

962956
nic->rx_queues = qs->rq_cnt;
963957
nic->tx_queues = qs->sq_cnt;
958+
nic->xdp_tx_queues = 0;
964959

965960
return 0;
966961
}

drivers/net/ethernet/cavium/thunder/nicvf_queues.h

+9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define NICVF_QUEUES_H
1111

1212
#include <linux/netdevice.h>
13+
#include <linux/iommu.h>
1314
#include "q_struct.h"
1415

1516
#define MAX_QUEUE_SET 128
@@ -312,6 +313,14 @@ struct queue_set {
312313

313314
#define CQ_ERR_MASK (CQ_WR_FULL | CQ_WR_DISABLE | CQ_WR_FAULT)
314315

316+
static inline u64 nicvf_iova_to_phys(struct nicvf *nic, dma_addr_t dma_addr)
317+
{
318+
/* Translation is installed only when IOMMU is present */
319+
if (nic->iommu_domain)
320+
return iommu_iova_to_phys(nic->iommu_domain, dma_addr);
321+
return dma_addr;
322+
}
323+
315324
void nicvf_unmap_sndq_buffers(struct nicvf *nic, struct snd_queue *sq,
316325
int hdr_sqe, u8 subdesc_cnt);
317326
void nicvf_config_vlan_stripping(struct nicvf *nic,

0 commit comments

Comments
 (0)