Skip to content

Commit 1a9d488

Browse files
ahduyckkuba-moo
authored andcommitted
eth: fbnic: Allocate core device specific structures and devlink interface
At the core of the fbnic device will be the devlink interface. This interface will eventually provide basic functionality in the event that there are any issues with the network interface. Add support for allocating the MSI-X vectors and setting up the BAR mapping. With this we can start enabling various subsystems and start brining up additional interfaces such the AXI fabric and the firmware mailbox. Signed-off-by: Alexander Duyck <[email protected]> Link: https://patch.msgid.link/172079936012.1778861.4670986685222676467.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 546dd90 commit 1a9d488

File tree

5 files changed

+222
-2
lines changed

5 files changed

+222
-2
lines changed

drivers/net/ethernet/meta/fbnic/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@
77

88
obj-$(CONFIG_FBNIC) += fbnic.o
99

10-
fbnic-y := fbnic_pci.o
10+
fbnic-y := fbnic_devlink.o \
11+
fbnic_irq.o \
12+
fbnic_pci.o

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,35 @@
66

77
#include "fbnic_csr.h"
88

9+
struct fbnic_dev {
10+
struct device *dev;
11+
12+
u32 __iomem *uc_addr0;
13+
u32 __iomem *uc_addr4;
14+
unsigned short num_irqs;
15+
16+
u64 dsn;
17+
};
18+
19+
/* Reserve entry 0 in the MSI-X "others" array until we have filled all
20+
* 32 of the possible interrupt slots. By doing this we can avoid any
21+
* potential conflicts should we need to enable one of the debug interrupt
22+
* causes later.
23+
*/
24+
enum {
25+
FBNIC_NON_NAPI_VECTORS
26+
};
27+
928
extern char fbnic_driver_name[];
1029

30+
void fbnic_devlink_free(struct fbnic_dev *fbd);
31+
struct fbnic_dev *fbnic_devlink_alloc(struct pci_dev *pdev);
32+
void fbnic_devlink_register(struct fbnic_dev *fbd);
33+
void fbnic_devlink_unregister(struct fbnic_dev *fbd);
34+
35+
void fbnic_free_irqs(struct fbnic_dev *fbd);
36+
int fbnic_alloc_irqs(struct fbnic_dev *fbd);
37+
1138
enum fbnic_boards {
1239
fbnic_board_asic
1340
};
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
3+
4+
#include <asm/unaligned.h>
5+
#include <linux/pci.h>
6+
#include <linux/types.h>
7+
#include <net/devlink.h>
8+
9+
#include "fbnic.h"
10+
11+
#define FBNIC_SN_STR_LEN 24
12+
13+
static int fbnic_devlink_info_get(struct devlink *devlink,
14+
struct devlink_info_req *req,
15+
struct netlink_ext_ack *extack)
16+
{
17+
struct fbnic_dev *fbd = devlink_priv(devlink);
18+
int err;
19+
20+
if (fbd->dsn) {
21+
unsigned char serial[FBNIC_SN_STR_LEN];
22+
u8 dsn[8];
23+
24+
put_unaligned_be64(fbd->dsn, dsn);
25+
err = snprintf(serial, FBNIC_SN_STR_LEN, "%8phD", dsn);
26+
if (err < 0)
27+
return err;
28+
29+
err = devlink_info_serial_number_put(req, serial);
30+
if (err)
31+
return err;
32+
}
33+
34+
return 0;
35+
}
36+
37+
static const struct devlink_ops fbnic_devlink_ops = {
38+
.info_get = fbnic_devlink_info_get,
39+
};
40+
41+
void fbnic_devlink_free(struct fbnic_dev *fbd)
42+
{
43+
struct devlink *devlink = priv_to_devlink(fbd);
44+
45+
devlink_free(devlink);
46+
}
47+
48+
struct fbnic_dev *fbnic_devlink_alloc(struct pci_dev *pdev)
49+
{
50+
void __iomem * const *iomap_table;
51+
struct devlink *devlink;
52+
struct fbnic_dev *fbd;
53+
54+
devlink = devlink_alloc(&fbnic_devlink_ops, sizeof(struct fbnic_dev),
55+
&pdev->dev);
56+
if (!devlink)
57+
return NULL;
58+
59+
fbd = devlink_priv(devlink);
60+
pci_set_drvdata(pdev, fbd);
61+
fbd->dev = &pdev->dev;
62+
63+
iomap_table = pcim_iomap_table(pdev);
64+
fbd->uc_addr0 = iomap_table[0];
65+
fbd->uc_addr4 = iomap_table[4];
66+
67+
fbd->dsn = pci_get_dsn(pdev);
68+
69+
return fbd;
70+
}
71+
72+
void fbnic_devlink_register(struct fbnic_dev *fbd)
73+
{
74+
struct devlink *devlink = priv_to_devlink(fbd);
75+
76+
devlink_register(devlink);
77+
}
78+
79+
void fbnic_devlink_unregister(struct fbnic_dev *fbd)
80+
{
81+
struct devlink *devlink = priv_to_devlink(fbd);
82+
83+
devlink_unregister(devlink);
84+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
3+
4+
#include <linux/pci.h>
5+
#include <linux/types.h>
6+
7+
#include "fbnic.h"
8+
9+
void fbnic_free_irqs(struct fbnic_dev *fbd)
10+
{
11+
struct pci_dev *pdev = to_pci_dev(fbd->dev);
12+
13+
fbd->num_irqs = 0;
14+
15+
pci_free_irq_vectors(pdev);
16+
}
17+
18+
int fbnic_alloc_irqs(struct fbnic_dev *fbd)
19+
{
20+
unsigned int wanted_irqs = FBNIC_NON_NAPI_VECTORS;
21+
struct pci_dev *pdev = to_pci_dev(fbd->dev);
22+
int num_irqs;
23+
24+
wanted_irqs += 1;
25+
num_irqs = pci_alloc_irq_vectors(pdev, FBNIC_NON_NAPI_VECTORS + 1,
26+
wanted_irqs, PCI_IRQ_MSIX);
27+
if (num_irqs < 0) {
28+
dev_err(fbd->dev, "Failed to allocate MSI-X entries\n");
29+
return num_irqs;
30+
}
31+
32+
if (num_irqs < wanted_irqs)
33+
dev_warn(fbd->dev, "Allocated %d IRQs, expected %d\n",
34+
num_irqs, wanted_irqs);
35+
36+
fbd->num_irqs = num_irqs;
37+
38+
return 0;
39+
}

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

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ MODULE_DEVICE_TABLE(pci, fbnic_pci_tbl);
4343
static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
4444
{
4545
const struct fbnic_info *info = fbnic_info_tbl[ent->driver_data];
46+
struct fbnic_dev *fbd;
4647
int err;
4748

4849
if (pdev->error_state != pci_channel_io_normal) {
@@ -72,10 +73,39 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
7273
return err;
7374
}
7475

76+
fbd = fbnic_devlink_alloc(pdev);
77+
if (!fbd) {
78+
dev_err(&pdev->dev, "Devlink allocation failed\n");
79+
return -ENOMEM;
80+
}
81+
7582
pci_set_master(pdev);
7683
pci_save_state(pdev);
7784

85+
err = fbnic_alloc_irqs(fbd);
86+
if (err)
87+
goto free_fbd;
88+
89+
fbnic_devlink_register(fbd);
90+
91+
if (!fbd->dsn) {
92+
dev_warn(&pdev->dev, "Reading serial number failed\n");
93+
goto init_failure_mode;
94+
}
95+
7896
return 0;
97+
98+
init_failure_mode:
99+
dev_warn(&pdev->dev, "Probe error encountered, entering init failure mode. Normal networking functionality will not be available.\n");
100+
/* Always return 0 even on error so devlink is registered to allow
101+
* firmware updates for fixes.
102+
*/
103+
return 0;
104+
free_fbd:
105+
pci_disable_device(pdev);
106+
fbnic_devlink_free(fbd);
107+
108+
return err;
79109
}
80110

81111
/**
@@ -88,17 +118,50 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
88118
**/
89119
static void fbnic_remove(struct pci_dev *pdev)
90120
{
121+
struct fbnic_dev *fbd = pci_get_drvdata(pdev);
122+
123+
fbnic_devlink_unregister(fbd);
124+
fbnic_free_irqs(fbd);
125+
91126
pci_disable_device(pdev);
127+
fbnic_devlink_free(fbd);
92128
}
93129

94130
static int fbnic_pm_suspend(struct device *dev)
95131
{
132+
struct fbnic_dev *fbd = dev_get_drvdata(dev);
133+
134+
/* Free the IRQs so they aren't trying to occupy sleeping CPUs */
135+
fbnic_free_irqs(fbd);
136+
137+
/* Hardware is about to go away, so switch off MMIO access internally */
138+
WRITE_ONCE(fbd->uc_addr0, NULL);
139+
WRITE_ONCE(fbd->uc_addr4, NULL);
140+
96141
return 0;
97142
}
98143

99144
static int __fbnic_pm_resume(struct device *dev)
100145
{
146+
struct fbnic_dev *fbd = dev_get_drvdata(dev);
147+
void __iomem * const *iomap_table;
148+
int err;
149+
150+
/* Restore MMIO access */
151+
iomap_table = pcim_iomap_table(to_pci_dev(dev));
152+
fbd->uc_addr0 = iomap_table[0];
153+
fbd->uc_addr4 = iomap_table[4];
154+
155+
/* Rerequest the IRQs */
156+
err = fbnic_alloc_irqs(fbd);
157+
if (err)
158+
goto err_invalidate_uc_addr;
159+
101160
return 0;
161+
err_invalidate_uc_addr:
162+
WRITE_ONCE(fbd->uc_addr0, NULL);
163+
WRITE_ONCE(fbd->uc_addr4, NULL);
164+
return err;
102165
}
103166

104167
static int __maybe_unused fbnic_pm_resume(struct device *dev)
@@ -134,6 +197,8 @@ static pci_ers_result_t fbnic_err_error_detected(struct pci_dev *pdev,
134197

135198
static pci_ers_result_t fbnic_err_slot_reset(struct pci_dev *pdev)
136199
{
200+
int err;
201+
137202
pci_set_power_state(pdev, PCI_D0);
138203
pci_restore_state(pdev);
139204
pci_save_state(pdev);
@@ -144,7 +209,10 @@ static pci_ers_result_t fbnic_err_slot_reset(struct pci_dev *pdev)
144209
return PCI_ERS_RESULT_DISCONNECT;
145210
}
146211

147-
return PCI_ERS_RESULT_RECOVERED;
212+
/* Restore device to previous state */
213+
err = __fbnic_pm_resume(&pdev->dev);
214+
215+
return err ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
148216
}
149217

150218
static void fbnic_err_resume(struct pci_dev *pdev)

0 commit comments

Comments
 (0)