Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

eth: fbnic: Add scaffolding for Meta's NIC driver

Create a bare-bones PCI driver for Meta's NIC.
Subsequent changes will flesh it out.

Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/172079935646.1778861.9710282776096050607.stgit@ahduyck-xeon-server.home.arpa
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Alexander Duyck and committed by
Jakub Kicinski
546dd90b c5eaf1b3

+289
+7
MAINTAINERS
··· 14579 14579 F: Documentation/devicetree/bindings/media/amlogic,gx-vdec.yaml 14580 14580 F: drivers/staging/media/meson/vdec/ 14581 14581 14582 + META ETHERNET DRIVERS 14583 + M: Alexander Duyck <alexanderduyck@fb.com> 14584 + M: Jakub Kicinski <kuba@kernel.org> 14585 + R: kernel-team@meta.com 14586 + S: Supported 14587 + F: drivers/net/ethernet/meta/ 14588 + 14582 14589 METHODE UDPU SUPPORT 14583 14590 M: Robert Marko <robert.marko@sartura.hr> 14584 14591 S: Maintained
+1
drivers/net/ethernet/Kconfig
··· 122 122 source "drivers/net/ethernet/marvell/Kconfig" 123 123 source "drivers/net/ethernet/mediatek/Kconfig" 124 124 source "drivers/net/ethernet/mellanox/Kconfig" 125 + source "drivers/net/ethernet/meta/Kconfig" 125 126 source "drivers/net/ethernet/micrel/Kconfig" 126 127 source "drivers/net/ethernet/microchip/Kconfig" 127 128 source "drivers/net/ethernet/mscc/Kconfig"
+1
drivers/net/ethernet/Makefile
··· 59 59 obj-$(CONFIG_NET_VENDOR_MARVELL) += marvell/ 60 60 obj-$(CONFIG_NET_VENDOR_MEDIATEK) += mediatek/ 61 61 obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/ 62 + obj-$(CONFIG_NET_VENDOR_META) += meta/ 62 63 obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/ 63 64 obj-$(CONFIG_NET_VENDOR_MICROCHIP) += microchip/ 64 65 obj-$(CONFIG_NET_VENDOR_MICROSEMI) += mscc/
+30
drivers/net/ethernet/meta/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + # Meta Platforms network device configuration 4 + # 5 + 6 + config NET_VENDOR_META 7 + bool "Meta Platforms devices" 8 + default y 9 + help 10 + If you have a network (Ethernet) card designed by Meta, say Y. 11 + That's Meta as in the parent company of Facebook. 12 + 13 + Note that the answer to this question doesn't directly affect the 14 + kernel: saying N will just cause the configurator to skip all 15 + the questions about Meta cards. If you say Y, you will be asked for 16 + your specific card in the following questions. 17 + 18 + if NET_VENDOR_META 19 + 20 + config FBNIC 21 + tristate "Meta Platforms Host Network Interface" 22 + depends on X86_64 || COMPILE_TEST 23 + depends on PCI_MSI 24 + help 25 + This driver supports Meta Platforms Host Network Interface. 26 + 27 + To compile this driver as a module, choose M here. The module 28 + will be called fbnic. MSI-X interrupt support is required. 29 + 30 + endif # NET_VENDOR_META
+6
drivers/net/ethernet/meta/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Makefile for the Meta Platforms network device drivers. 4 + # 5 + 6 + obj-$(CONFIG_FBNIC) += fbnic/
+10
drivers/net/ethernet/meta/fbnic/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # Copyright (c) Meta Platforms, Inc. and affiliates. 3 + 4 + # 5 + # Makefile for the Meta(R) Host Network Interface 6 + # 7 + 8 + obj-$(CONFIG_FBNIC) += fbnic.o 9 + 10 + fbnic-y := fbnic_pci.o
+19
drivers/net/ethernet/meta/fbnic/fbnic.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 + 4 + #ifndef _FBNIC_H_ 5 + #define _FBNIC_H_ 6 + 7 + #include "fbnic_csr.h" 8 + 9 + extern char fbnic_driver_name[]; 10 + 11 + enum fbnic_boards { 12 + fbnic_board_asic 13 + }; 14 + 15 + struct fbnic_info { 16 + unsigned int bar_mask; 17 + }; 18 + 19 + #endif /* _FBNIC_H_ */
+9
drivers/net/ethernet/meta/fbnic/fbnic_csr.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 + 4 + #ifndef _FBNIC_CSR_H_ 5 + #define _FBNIC_CSR_H_ 6 + 7 + #define PCI_DEVICE_ID_META_FBNIC_ASIC 0x0013 8 + 9 + #endif /* _FBNIC_CSR_H_ */
+5
drivers/net/ethernet/meta/fbnic/fbnic_drvinfo.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 + 4 + #define DRV_NAME "fbnic" 5 + #define DRV_SUMMARY "Meta(R) Host Network Interface Driver"
+201
drivers/net/ethernet/meta/fbnic/fbnic_pci.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include <linux/init.h> 5 + #include <linux/module.h> 6 + #include <linux/pci.h> 7 + #include <linux/types.h> 8 + 9 + #include "fbnic.h" 10 + #include "fbnic_drvinfo.h" 11 + 12 + char fbnic_driver_name[] = DRV_NAME; 13 + 14 + MODULE_DESCRIPTION(DRV_SUMMARY); 15 + MODULE_LICENSE("GPL"); 16 + 17 + static const struct fbnic_info fbnic_asic_info = { 18 + .bar_mask = BIT(0) | BIT(4) 19 + }; 20 + 21 + static const struct fbnic_info *fbnic_info_tbl[] = { 22 + [fbnic_board_asic] = &fbnic_asic_info, 23 + }; 24 + 25 + static const struct pci_device_id fbnic_pci_tbl[] = { 26 + { PCI_DEVICE_DATA(META, FBNIC_ASIC, fbnic_board_asic) }, 27 + /* Required last entry */ 28 + {0, } 29 + }; 30 + MODULE_DEVICE_TABLE(pci, fbnic_pci_tbl); 31 + 32 + /** 33 + * fbnic_probe - Device Initialization Routine 34 + * @pdev: PCI device information struct 35 + * @ent: entry in fbnic_pci_tbl 36 + * 37 + * Initializes a PCI device identified by a pci_dev structure. 38 + * The OS initialization, configuring of the adapter private structure, 39 + * and a hardware reset occur. 40 + * 41 + * Return: 0 on success, negative on failure 42 + **/ 43 + static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 44 + { 45 + const struct fbnic_info *info = fbnic_info_tbl[ent->driver_data]; 46 + int err; 47 + 48 + if (pdev->error_state != pci_channel_io_normal) { 49 + dev_err(&pdev->dev, 50 + "PCI device still in an error state. Unable to load...\n"); 51 + return -EIO; 52 + } 53 + 54 + err = pcim_enable_device(pdev); 55 + if (err) { 56 + dev_err(&pdev->dev, "PCI enable device failed: %d\n", err); 57 + return err; 58 + } 59 + 60 + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(46)); 61 + if (err) 62 + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 63 + if (err) { 64 + dev_err(&pdev->dev, "DMA configuration failed: %d\n", err); 65 + return err; 66 + } 67 + 68 + err = pcim_iomap_regions(pdev, info->bar_mask, fbnic_driver_name); 69 + if (err) { 70 + dev_err(&pdev->dev, 71 + "pci_request_selected_regions failed: %d\n", err); 72 + return err; 73 + } 74 + 75 + pci_set_master(pdev); 76 + pci_save_state(pdev); 77 + 78 + return 0; 79 + } 80 + 81 + /** 82 + * fbnic_remove - Device Removal Routine 83 + * @pdev: PCI device information struct 84 + * 85 + * Called by the PCI subsystem to alert the driver that it should release 86 + * a PCI device. The could be caused by a Hot-Plug event, or because the 87 + * driver is going to be removed from memory. 88 + **/ 89 + static void fbnic_remove(struct pci_dev *pdev) 90 + { 91 + pci_disable_device(pdev); 92 + } 93 + 94 + static int fbnic_pm_suspend(struct device *dev) 95 + { 96 + return 0; 97 + } 98 + 99 + static int __fbnic_pm_resume(struct device *dev) 100 + { 101 + return 0; 102 + } 103 + 104 + static int __maybe_unused fbnic_pm_resume(struct device *dev) 105 + { 106 + int err; 107 + 108 + err = __fbnic_pm_resume(dev); 109 + 110 + return err; 111 + } 112 + 113 + static const struct dev_pm_ops fbnic_pm_ops = { 114 + SET_SYSTEM_SLEEP_PM_OPS(fbnic_pm_suspend, fbnic_pm_resume) 115 + }; 116 + 117 + static void fbnic_shutdown(struct pci_dev *pdev) 118 + { 119 + fbnic_pm_suspend(&pdev->dev); 120 + } 121 + 122 + static pci_ers_result_t fbnic_err_error_detected(struct pci_dev *pdev, 123 + pci_channel_state_t state) 124 + { 125 + /* Disconnect device if failure is not recoverable via reset */ 126 + if (state == pci_channel_io_perm_failure) 127 + return PCI_ERS_RESULT_DISCONNECT; 128 + 129 + fbnic_pm_suspend(&pdev->dev); 130 + 131 + /* Request a slot reset */ 132 + return PCI_ERS_RESULT_NEED_RESET; 133 + } 134 + 135 + static pci_ers_result_t fbnic_err_slot_reset(struct pci_dev *pdev) 136 + { 137 + pci_set_power_state(pdev, PCI_D0); 138 + pci_restore_state(pdev); 139 + pci_save_state(pdev); 140 + 141 + if (pci_enable_device_mem(pdev)) { 142 + dev_err(&pdev->dev, 143 + "Cannot re-enable PCI device after reset.\n"); 144 + return PCI_ERS_RESULT_DISCONNECT; 145 + } 146 + 147 + return PCI_ERS_RESULT_RECOVERED; 148 + } 149 + 150 + static void fbnic_err_resume(struct pci_dev *pdev) 151 + { 152 + } 153 + 154 + static const struct pci_error_handlers fbnic_err_handler = { 155 + .error_detected = fbnic_err_error_detected, 156 + .slot_reset = fbnic_err_slot_reset, 157 + .resume = fbnic_err_resume, 158 + }; 159 + 160 + static struct pci_driver fbnic_driver = { 161 + .name = fbnic_driver_name, 162 + .id_table = fbnic_pci_tbl, 163 + .probe = fbnic_probe, 164 + .remove = fbnic_remove, 165 + .driver.pm = &fbnic_pm_ops, 166 + .shutdown = fbnic_shutdown, 167 + .err_handler = &fbnic_err_handler, 168 + }; 169 + 170 + /** 171 + * fbnic_init_module - Driver Registration Routine 172 + * 173 + * The first routine called when the driver is loaded. All it does is 174 + * register with the PCI subsystem. 175 + * 176 + * Return: 0 on success, negative on failure 177 + **/ 178 + static int __init fbnic_init_module(void) 179 + { 180 + int err; 181 + 182 + err = pci_register_driver(&fbnic_driver); 183 + if (err) 184 + goto out; 185 + 186 + pr_info(DRV_SUMMARY " (%s)", fbnic_driver.name); 187 + out: 188 + return err; 189 + } 190 + module_init(fbnic_init_module); 191 + 192 + /** 193 + * fbnic_exit_module - Driver Exit Cleanup Routine 194 + * 195 + * Called just before the driver is removed from memory. 196 + **/ 197 + static void __exit fbnic_exit_module(void) 198 + { 199 + pci_unregister_driver(&fbnic_driver); 200 + } 201 + module_exit(fbnic_exit_module);