Skip to content

Commit bc61077

Browse files
ahduyckkuba-moo
authored andcommitted
eth: fbnic: Allocate a netdevice and napi vectors with queues
Allocate a netdev and figure out basics like how many queues we need, MAC address, MTU bounds. Kick off a service task to do various periodic things like health checking. The service task only runs when device is open. We have four levels of objects here: - ring - A HW ring with head / tail pointers, - triad - Two submission and one completion ring, - NAPI - NAPI, with one IRQ and any number of Rx and Tx triads, - Netdev - The ultimate container of the rings and napi vectors. The "triad" is the only less-than-usual construct. On Rx we have two "free buffer" submission rings, one for packet headers and one for packet data. On Tx we have separate rings for XDP Tx and normal Tx. So we ended up with ring triplets in both directions. We keep NAPIs on a local list, even though core already maintains a list. Later on having a separate list will matter for live reconfig. We introduce the list already, the churn would not be worth it. Signed-off-by: Alexander Duyck <[email protected]> Link: https://patch.msgid.link/172079938358.1778861.11681469974633489463.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Jakub Kicinski <[email protected]>
1 parent da3cde0 commit bc61077

File tree

9 files changed

+775
-2
lines changed

9 files changed

+775
-2
lines changed

drivers/net/ethernet/meta/fbnic/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@ fbnic-y := fbnic_devlink.o \
1111
fbnic_fw.o \
1212
fbnic_irq.o \
1313
fbnic_mac.o \
14+
fbnic_netdev.o \
1415
fbnic_pci.o \
15-
fbnic_tlv.o
16+
fbnic_tlv.o \
17+
fbnic_txrx.o

drivers/net/ethernet/meta/fbnic/fbnic.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,37 @@
44
#ifndef _FBNIC_H_
55
#define _FBNIC_H_
66

7+
#include <linux/interrupt.h>
78
#include <linux/io.h>
9+
#include <linux/types.h>
10+
#include <linux/workqueue.h>
811

912
#include "fbnic_csr.h"
1013
#include "fbnic_fw.h"
1114
#include "fbnic_mac.h"
1215

1316
struct fbnic_dev {
1417
struct device *dev;
18+
struct net_device *netdev;
1519

1620
u32 __iomem *uc_addr0;
1721
u32 __iomem *uc_addr4;
1822
const struct fbnic_mac *mac;
1923
unsigned int fw_msix_vector;
2024
unsigned short num_irqs;
2125

26+
struct delayed_work service_task;
27+
2228
struct fbnic_fw_mbx mbx[FBNIC_IPC_MBX_INDICES];
2329
/* Lock protecting Tx Mailbox queue to prevent possible races */
2430
spinlock_t fw_tx_lock;
2531

2632
u64 dsn;
2733
u32 mps;
2834
u32 readrq;
35+
36+
/* Number of TCQs/RCQs available on hardware */
37+
u16 max_num_queues;
2938
};
3039

3140
/* Reserve entry 0 in the MSI-X "others" array until we have filled all
@@ -81,6 +90,11 @@ void fbnic_fw_wr32(struct fbnic_dev *fbd, u32 reg, u32 val);
8190
#define fw_wr32(_f, _r, _v) fbnic_fw_wr32(_f, _r, _v)
8291
#define fw_wrfl(_f) fbnic_fw_rd32(_f, FBNIC_FW_ZERO_REG)
8392

93+
static inline bool fbnic_init_failure(struct fbnic_dev *fbd)
94+
{
95+
return !fbd->netdev;
96+
}
97+
8498
extern char fbnic_driver_name[];
8599

86100
void fbnic_devlink_free(struct fbnic_dev *fbd);
@@ -91,6 +105,9 @@ void fbnic_devlink_unregister(struct fbnic_dev *fbd);
91105
int fbnic_fw_enable_mbx(struct fbnic_dev *fbd);
92106
void fbnic_fw_disable_mbx(struct fbnic_dev *fbd);
93107

108+
int fbnic_request_irq(struct fbnic_dev *dev, int nr, irq_handler_t handler,
109+
unsigned long flags, const char *name, void *data);
110+
void fbnic_free_irq(struct fbnic_dev *dev, int nr, void *data);
94111
void fbnic_free_irqs(struct fbnic_dev *fbd);
95112
int fbnic_alloc_irqs(struct fbnic_dev *fbd);
96113

@@ -99,6 +116,7 @@ enum fbnic_boards {
99116
};
100117

101118
struct fbnic_info {
119+
unsigned int max_num_queues;
102120
unsigned int bar_mask;
103121
};
104122

drivers/net/ethernet/meta/fbnic/fbnic_csr.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,47 @@ enum {
366366
#define FBNIC_PUL_OB_TLP_HDR_AR_CFG_BME CSR_BIT(18)
367367
#define FBNIC_CSR_END_PUL_USER 0x31080 /* CSR section delimiter */
368368

369+
/* Queue Registers
370+
*
371+
* The queue register offsets are specific for a given queue grouping. So to
372+
* find the actual register offset it is necessary to combine FBNIC_QUEUE(n)
373+
* with the register to get the actual register offset like so:
374+
* FBNIC_QUEUE_TWQ0_CTL(n) == FBNIC_QUEUE(n) + FBNIC_QUEUE_TWQ0_CTL
375+
*/
376+
#define FBNIC_CSR_START_QUEUE 0x40000 /* CSR section delimiter */
377+
#define FBNIC_QUEUE_STRIDE 0x400 /* 0x1000 */
378+
#define FBNIC_QUEUE(n)\
379+
(0x40000 + FBNIC_QUEUE_STRIDE * (n)) /* 0x100000 + 4096*n */
380+
381+
#define FBNIC_QUEUE_TWQ0_CTL 0x000 /* 0x000 */
382+
#define FBNIC_QUEUE_TWQ1_CTL 0x001 /* 0x004 */
383+
#define FBNIC_QUEUE_TWQ_CTL_RESET CSR_BIT(0)
384+
#define FBNIC_QUEUE_TWQ_CTL_ENABLE CSR_BIT(1)
385+
#define FBNIC_QUEUE_TWQ_CTL_PREFETCH_DISABLE CSR_BIT(2)
386+
#define FBNIC_QUEUE_TWQ_CTL_TXB_FIFO_SEL_MASK CSR_GENMASK(30, 29)
387+
enum {
388+
FBNIC_QUEUE_TWQ_CTL_TXB_SHARED = 0,
389+
FBNIC_QUEUE_TWQ_CTL_TXB_EI_DATA = 1,
390+
FBNIC_QUEUE_TWQ_CTL_TXB_EI_CTL = 2,
391+
};
392+
393+
#define FBNIC_QUEUE_TWQ_CTL_AGGR_MODE CSR_BIT(31)
394+
395+
#define FBNIC_QUEUE_TWQ0_TAIL 0x002 /* 0x008 */
396+
#define FBNIC_QUEUE_TWQ1_TAIL 0x003 /* 0x00c */
397+
398+
/* Tx Completion Queue Registers */
399+
#define FBNIC_QUEUE_TCQ_HEAD 0x081 /* 0x204 */
400+
401+
/* Rx Completion Queue Registers */
402+
#define FBNIC_QUEUE_RCQ_HEAD 0x201 /* 0x804 */
403+
404+
/* Rx Buffer Descriptor Queue Registers */
405+
#define FBNIC_QUEUE_BDQ_HPQ_TAIL 0x241 /* 0x904 */
406+
#define FBNIC_QUEUE_BDQ_PPQ_TAIL 0x242 /* 0x908 */
407+
369408
#define FBNIC_MAX_QUEUES 128
409+
#define FBNIC_CSR_END_QUEUE (0x40000 + 0x400 * FBNIC_MAX_QUEUES - 1)
370410

371411
/* BAR 4 CSRs */
372412

drivers/net/ethernet/meta/fbnic/fbnic_irq.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <linux/types.h>
66

77
#include "fbnic.h"
8+
#include "fbnic_txrx.h"
89

910
static irqreturn_t fbnic_fw_msix_intr(int __always_unused irq, void *data)
1011
{
@@ -80,6 +81,29 @@ void fbnic_fw_disable_mbx(struct fbnic_dev *fbd)
8081
fbnic_mbx_clean(fbd);
8182
}
8283

84+
int fbnic_request_irq(struct fbnic_dev *fbd, int nr, irq_handler_t handler,
85+
unsigned long flags, const char *name, void *data)
86+
{
87+
struct pci_dev *pdev = to_pci_dev(fbd->dev);
88+
int irq = pci_irq_vector(pdev, nr);
89+
90+
if (irq < 0)
91+
return irq;
92+
93+
return request_irq(irq, handler, flags, name, data);
94+
}
95+
96+
void fbnic_free_irq(struct fbnic_dev *fbd, int nr, void *data)
97+
{
98+
struct pci_dev *pdev = to_pci_dev(fbd->dev);
99+
int irq = pci_irq_vector(pdev, nr);
100+
101+
if (irq < 0)
102+
return;
103+
104+
free_irq(irq, data);
105+
}
106+
83107
void fbnic_free_irqs(struct fbnic_dev *fbd)
84108
{
85109
struct pci_dev *pdev = to_pci_dev(fbd->dev);
@@ -97,7 +121,7 @@ int fbnic_alloc_irqs(struct fbnic_dev *fbd)
97121
struct pci_dev *pdev = to_pci_dev(fbd->dev);
98122
int num_irqs;
99123

100-
wanted_irqs += 1;
124+
wanted_irqs += min_t(unsigned int, num_online_cpus(), FBNIC_MAX_RXQS);
101125
num_irqs = pci_alloc_irq_vectors(pdev, FBNIC_NON_NAPI_VECTORS + 1,
102126
wanted_irqs, PCI_IRQ_MSIX);
103127
if (num_irqs < 0) {
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
3+
4+
#include <linux/etherdevice.h>
5+
#include <linux/ipv6.h>
6+
#include <linux/types.h>
7+
8+
#include "fbnic.h"
9+
#include "fbnic_netdev.h"
10+
#include "fbnic_txrx.h"
11+
12+
int __fbnic_open(struct fbnic_net *fbn)
13+
{
14+
int err;
15+
16+
err = fbnic_alloc_napi_vectors(fbn);
17+
if (err)
18+
return err;
19+
20+
err = netif_set_real_num_tx_queues(fbn->netdev,
21+
fbn->num_tx_queues);
22+
if (err)
23+
goto free_resources;
24+
25+
err = netif_set_real_num_rx_queues(fbn->netdev,
26+
fbn->num_rx_queues);
27+
if (err)
28+
goto free_resources;
29+
30+
return 0;
31+
free_resources:
32+
fbnic_free_napi_vectors(fbn);
33+
return err;
34+
}
35+
36+
static int fbnic_open(struct net_device *netdev)
37+
{
38+
struct fbnic_net *fbn = netdev_priv(netdev);
39+
int err;
40+
41+
err = __fbnic_open(fbn);
42+
if (!err)
43+
fbnic_up(fbn);
44+
45+
return err;
46+
}
47+
48+
static int fbnic_stop(struct net_device *netdev)
49+
{
50+
struct fbnic_net *fbn = netdev_priv(netdev);
51+
52+
fbnic_down(fbn);
53+
54+
fbnic_free_napi_vectors(fbn);
55+
56+
return 0;
57+
}
58+
59+
static const struct net_device_ops fbnic_netdev_ops = {
60+
.ndo_open = fbnic_open,
61+
.ndo_stop = fbnic_stop,
62+
.ndo_validate_addr = eth_validate_addr,
63+
.ndo_start_xmit = fbnic_xmit_frame,
64+
};
65+
66+
void fbnic_reset_queues(struct fbnic_net *fbn,
67+
unsigned int tx, unsigned int rx)
68+
{
69+
struct fbnic_dev *fbd = fbn->fbd;
70+
unsigned int max_napis;
71+
72+
max_napis = fbd->num_irqs - FBNIC_NON_NAPI_VECTORS;
73+
74+
tx = min(tx, max_napis);
75+
fbn->num_tx_queues = tx;
76+
77+
rx = min(rx, max_napis);
78+
fbn->num_rx_queues = rx;
79+
80+
fbn->num_napi = max(tx, rx);
81+
}
82+
83+
/**
84+
* fbnic_netdev_free - Free the netdev associate with fbnic
85+
* @fbd: Driver specific structure to free netdev from
86+
*
87+
* Allocate and initialize the netdev and netdev private structure. Bind
88+
* together the hardware, netdev, and pci data structures.
89+
**/
90+
void fbnic_netdev_free(struct fbnic_dev *fbd)
91+
{
92+
free_netdev(fbd->netdev);
93+
fbd->netdev = NULL;
94+
}
95+
96+
/**
97+
* fbnic_netdev_alloc - Allocate a netdev and associate with fbnic
98+
* @fbd: Driver specific structure to associate netdev with
99+
*
100+
* Allocate and initialize the netdev and netdev private structure. Bind
101+
* together the hardware, netdev, and pci data structures.
102+
*
103+
* Return: 0 on success, negative on failure
104+
**/
105+
struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd)
106+
{
107+
struct net_device *netdev;
108+
struct fbnic_net *fbn;
109+
int default_queues;
110+
111+
netdev = alloc_etherdev_mq(sizeof(*fbn), FBNIC_MAX_RXQS);
112+
if (!netdev)
113+
return NULL;
114+
115+
SET_NETDEV_DEV(netdev, fbd->dev);
116+
fbd->netdev = netdev;
117+
118+
netdev->netdev_ops = &fbnic_netdev_ops;
119+
120+
fbn = netdev_priv(netdev);
121+
122+
fbn->netdev = netdev;
123+
fbn->fbd = fbd;
124+
INIT_LIST_HEAD(&fbn->napis);
125+
126+
default_queues = netif_get_num_default_rss_queues();
127+
if (default_queues > fbd->max_num_queues)
128+
default_queues = fbd->max_num_queues;
129+
130+
fbnic_reset_queues(fbn, default_queues, default_queues);
131+
132+
netdev->min_mtu = IPV6_MIN_MTU;
133+
netdev->max_mtu = FBNIC_MAX_JUMBO_FRAME_SIZE - ETH_HLEN;
134+
135+
netif_carrier_off(netdev);
136+
137+
netif_tx_stop_all_queues(netdev);
138+
139+
return netdev;
140+
}
141+
142+
static int fbnic_dsn_to_mac_addr(u64 dsn, char *addr)
143+
{
144+
addr[0] = (dsn >> 56) & 0xFF;
145+
addr[1] = (dsn >> 48) & 0xFF;
146+
addr[2] = (dsn >> 40) & 0xFF;
147+
addr[3] = (dsn >> 16) & 0xFF;
148+
addr[4] = (dsn >> 8) & 0xFF;
149+
addr[5] = dsn & 0xFF;
150+
151+
return is_valid_ether_addr(addr) ? 0 : -EINVAL;
152+
}
153+
154+
/**
155+
* fbnic_netdev_register - Initialize general software structures
156+
* @netdev: Netdev containing structure to initialize and register
157+
*
158+
* Initialize the MAC address for the netdev and register it.
159+
*
160+
* Return: 0 on success, negative on failure
161+
**/
162+
int fbnic_netdev_register(struct net_device *netdev)
163+
{
164+
struct fbnic_net *fbn = netdev_priv(netdev);
165+
struct fbnic_dev *fbd = fbn->fbd;
166+
u64 dsn = fbd->dsn;
167+
u8 addr[ETH_ALEN];
168+
int err;
169+
170+
err = fbnic_dsn_to_mac_addr(dsn, addr);
171+
if (!err) {
172+
ether_addr_copy(netdev->perm_addr, addr);
173+
eth_hw_addr_set(netdev, addr);
174+
} else {
175+
/* A randomly assigned MAC address will cause provisioning
176+
* issues so instead just fail to spawn the netdev and
177+
* avoid any confusion.
178+
*/
179+
dev_err(fbd->dev, "MAC addr %pM invalid\n", addr);
180+
return err;
181+
}
182+
183+
return register_netdev(netdev);
184+
}
185+
186+
void fbnic_netdev_unregister(struct net_device *netdev)
187+
{
188+
unregister_netdev(netdev);
189+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
3+
4+
#ifndef _FBNIC_NETDEV_H_
5+
#define _FBNIC_NETDEV_H_
6+
7+
#include <linux/types.h>
8+
9+
#include "fbnic_txrx.h"
10+
11+
struct fbnic_net {
12+
struct fbnic_ring *tx[FBNIC_MAX_TXQS];
13+
struct fbnic_ring *rx[FBNIC_MAX_RXQS];
14+
15+
struct net_device *netdev;
16+
struct fbnic_dev *fbd;
17+
18+
u16 num_napi;
19+
20+
u16 num_tx_queues;
21+
u16 num_rx_queues;
22+
23+
struct list_head napis;
24+
};
25+
26+
int __fbnic_open(struct fbnic_net *fbn);
27+
void fbnic_up(struct fbnic_net *fbn);
28+
void fbnic_down(struct fbnic_net *fbn);
29+
30+
struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd);
31+
void fbnic_netdev_free(struct fbnic_dev *fbd);
32+
int fbnic_netdev_register(struct net_device *netdev);
33+
void fbnic_netdev_unregister(struct net_device *netdev);
34+
void fbnic_reset_queues(struct fbnic_net *fbn,
35+
unsigned int tx, unsigned int rx);
36+
37+
#endif /* _FBNIC_NETDEV_H_ */

0 commit comments

Comments
 (0)