eth: fbnic: Add scaffolding for Meta's NIC driver
authorAlexander Duyck <alexanderduyck@fb.com>
Fri, 12 Jul 2024 15:49:16 +0000 (08:49 -0700)
committerJakub Kicinski <kuba@kernel.org>
Mon, 15 Jul 2024 19:50:42 +0000 (12:50 -0700)
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>
MAINTAINERS
drivers/net/ethernet/Kconfig
drivers/net/ethernet/Makefile
drivers/net/ethernet/meta/Kconfig [new file with mode: 0644]
drivers/net/ethernet/meta/Makefile [new file with mode: 0644]
drivers/net/ethernet/meta/fbnic/Makefile [new file with mode: 0644]
drivers/net/ethernet/meta/fbnic/fbnic.h [new file with mode: 0644]
drivers/net/ethernet/meta/fbnic/fbnic_csr.h [new file with mode: 0644]
drivers/net/ethernet/meta/fbnic/fbnic_drvinfo.h [new file with mode: 0644]
drivers/net/ethernet/meta/fbnic/fbnic_pci.c [new file with mode: 0644]

index 0b73a6e2d78c716e92c6ffad9aa10a7455c71356..dd4297ea41f960a6db3c7b1e3ede7b130bc955c3 100644 (file)
@@ -14579,6 +14579,13 @@ T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/amlogic,gx-vdec.yaml
 F:     drivers/staging/media/meson/vdec/
 
+META ETHERNET DRIVERS
+M:     Alexander Duyck <alexanderduyck@fb.com>
+M:     Jakub Kicinski <kuba@kernel.org>
+R:     kernel-team@meta.com
+S:     Supported
+F:     drivers/net/ethernet/meta/
+
 METHODE UDPU SUPPORT
 M:     Robert Marko <robert.marko@sartura.hr>
 S:     Maintained
index 6a19b5393ed1132de02426db7e8f3f3750be1beb..0baac25db4f84355dc9381be274729d438dd531d 100644 (file)
@@ -122,6 +122,7 @@ source "drivers/net/ethernet/litex/Kconfig"
 source "drivers/net/ethernet/marvell/Kconfig"
 source "drivers/net/ethernet/mediatek/Kconfig"
 source "drivers/net/ethernet/mellanox/Kconfig"
+source "drivers/net/ethernet/meta/Kconfig"
 source "drivers/net/ethernet/micrel/Kconfig"
 source "drivers/net/ethernet/microchip/Kconfig"
 source "drivers/net/ethernet/mscc/Kconfig"
index 0d872d4efcd10b1d29752e7fcd6aede2ec657902..c03203439c0ed3b1c7c4d645edb013a650e87f32 100644 (file)
@@ -59,6 +59,7 @@ obj-$(CONFIG_NET_VENDOR_LITEX) += litex/
 obj-$(CONFIG_NET_VENDOR_MARVELL) += marvell/
 obj-$(CONFIG_NET_VENDOR_MEDIATEK) += mediatek/
 obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/
+obj-$(CONFIG_NET_VENDOR_META) += meta/
 obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/
 obj-$(CONFIG_NET_VENDOR_MICROCHIP) += microchip/
 obj-$(CONFIG_NET_VENDOR_MICROSEMI) += mscc/
diff --git a/drivers/net/ethernet/meta/Kconfig b/drivers/net/ethernet/meta/Kconfig
new file mode 100644 (file)
index 0000000..fbbc38e
--- /dev/null
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Meta Platforms network device configuration
+#
+
+config NET_VENDOR_META
+       bool "Meta Platforms devices"
+       default y
+       help
+         If you have a network (Ethernet) card designed by Meta, say Y.
+         That's Meta as in the parent company of Facebook.
+
+         Note that the answer to this question doesn't directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         the questions about Meta cards. If you say Y, you will be asked for
+         your specific card in the following questions.
+
+if NET_VENDOR_META
+
+config FBNIC
+       tristate "Meta Platforms Host Network Interface"
+       depends on X86_64 || COMPILE_TEST
+       depends on PCI_MSI
+       help
+         This driver supports Meta Platforms Host Network Interface.
+
+         To compile this driver as a module, choose M here. The module
+         will be called fbnic.  MSI-X interrupt support is required.
+
+endif # NET_VENDOR_META
diff --git a/drivers/net/ethernet/meta/Makefile b/drivers/net/ethernet/meta/Makefile
new file mode 100644 (file)
index 0000000..88804f3
--- /dev/null
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the Meta Platforms network device drivers.
+#
+
+obj-$(CONFIG_FBNIC) += fbnic/
diff --git a/drivers/net/ethernet/meta/fbnic/Makefile b/drivers/net/ethernet/meta/fbnic/Makefile
new file mode 100644 (file)
index 0000000..ce277fe
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+
+#
+# Makefile for the Meta(R) Host Network Interface
+#
+
+obj-$(CONFIG_FBNIC) += fbnic.o
+
+fbnic-y := fbnic_pci.o
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h
new file mode 100644 (file)
index 0000000..25702da
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) Meta Platforms, Inc. and affiliates. */
+
+#ifndef _FBNIC_H_
+#define _FBNIC_H_
+
+#include "fbnic_csr.h"
+
+extern char fbnic_driver_name[];
+
+enum fbnic_boards {
+       fbnic_board_asic
+};
+
+struct fbnic_info {
+       unsigned int bar_mask;
+};
+
+#endif /* _FBNIC_H_ */
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
new file mode 100644 (file)
index 0000000..72e89c0
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) Meta Platforms, Inc. and affiliates. */
+
+#ifndef _FBNIC_CSR_H_
+#define _FBNIC_CSR_H_
+
+#define PCI_DEVICE_ID_META_FBNIC_ASIC          0x0013
+
+#endif /* _FBNIC_CSR_H_ */
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_drvinfo.h b/drivers/net/ethernet/meta/fbnic/fbnic_drvinfo.h
new file mode 100644 (file)
index 0000000..809ba67
--- /dev/null
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) Meta Platforms, Inc. and affiliates. */
+
+#define DRV_NAME "fbnic"
+#define DRV_SUMMARY "Meta(R) Host Network Interface Driver"
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c
new file mode 100644 (file)
index 0000000..aff031e
--- /dev/null
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) Meta Platforms, Inc. and affiliates. */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include "fbnic.h"
+#include "fbnic_drvinfo.h"
+
+char fbnic_driver_name[] = DRV_NAME;
+
+MODULE_DESCRIPTION(DRV_SUMMARY);
+MODULE_LICENSE("GPL");
+
+static const struct fbnic_info fbnic_asic_info = {
+       .bar_mask = BIT(0) | BIT(4)
+};
+
+static const struct fbnic_info *fbnic_info_tbl[] = {
+       [fbnic_board_asic] = &fbnic_asic_info,
+};
+
+static const struct pci_device_id fbnic_pci_tbl[] = {
+       { PCI_DEVICE_DATA(META, FBNIC_ASIC, fbnic_board_asic) },
+       /* Required last entry */
+       {0, }
+};
+MODULE_DEVICE_TABLE(pci, fbnic_pci_tbl);
+
+/**
+ * fbnic_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in fbnic_pci_tbl
+ *
+ * Initializes a PCI device identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ *
+ * Return: 0 on success, negative on failure
+ **/
+static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       const struct fbnic_info *info = fbnic_info_tbl[ent->driver_data];
+       int err;
+
+       if (pdev->error_state != pci_channel_io_normal) {
+               dev_err(&pdev->dev,
+                       "PCI device still in an error state. Unable to load...\n");
+               return -EIO;
+       }
+
+       err = pcim_enable_device(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "PCI enable device failed: %d\n", err);
+               return err;
+       }
+
+       err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(46));
+       if (err)
+               err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+       if (err) {
+               dev_err(&pdev->dev, "DMA configuration failed: %d\n", err);
+               return err;
+       }
+
+       err = pcim_iomap_regions(pdev, info->bar_mask, fbnic_driver_name);
+       if (err) {
+               dev_err(&pdev->dev,
+                       "pci_request_selected_regions failed: %d\n", err);
+               return err;
+       }
+
+       pci_set_master(pdev);
+       pci_save_state(pdev);
+
+       return 0;
+}
+
+/**
+ * fbnic_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * Called by the PCI subsystem to alert the driver that it should release
+ * a PCI device.  The could be caused by a Hot-Plug event, or because the
+ * driver is going to be removed from memory.
+ **/
+static void fbnic_remove(struct pci_dev *pdev)
+{
+       pci_disable_device(pdev);
+}
+
+static int fbnic_pm_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int __fbnic_pm_resume(struct device *dev)
+{
+       return 0;
+}
+
+static int __maybe_unused fbnic_pm_resume(struct device *dev)
+{
+       int err;
+
+       err = __fbnic_pm_resume(dev);
+
+       return err;
+}
+
+static const struct dev_pm_ops fbnic_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(fbnic_pm_suspend, fbnic_pm_resume)
+};
+
+static void fbnic_shutdown(struct pci_dev *pdev)
+{
+       fbnic_pm_suspend(&pdev->dev);
+}
+
+static pci_ers_result_t fbnic_err_error_detected(struct pci_dev *pdev,
+                                                pci_channel_state_t state)
+{
+       /* Disconnect device if failure is not recoverable via reset */
+       if (state == pci_channel_io_perm_failure)
+               return PCI_ERS_RESULT_DISCONNECT;
+
+       fbnic_pm_suspend(&pdev->dev);
+
+       /* Request a slot reset */
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t fbnic_err_slot_reset(struct pci_dev *pdev)
+{
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       pci_save_state(pdev);
+
+       if (pci_enable_device_mem(pdev)) {
+               dev_err(&pdev->dev,
+                       "Cannot re-enable PCI device after reset.\n");
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void fbnic_err_resume(struct pci_dev *pdev)
+{
+}
+
+static const struct pci_error_handlers fbnic_err_handler = {
+       .error_detected = fbnic_err_error_detected,
+       .slot_reset     = fbnic_err_slot_reset,
+       .resume         = fbnic_err_resume,
+};
+
+static struct pci_driver fbnic_driver = {
+       .name           = fbnic_driver_name,
+       .id_table       = fbnic_pci_tbl,
+       .probe          = fbnic_probe,
+       .remove         = fbnic_remove,
+       .driver.pm      = &fbnic_pm_ops,
+       .shutdown       = fbnic_shutdown,
+       .err_handler    = &fbnic_err_handler,
+};
+
+/**
+ * fbnic_init_module - Driver Registration Routine
+ *
+ * The first routine called when the driver is loaded.  All it does is
+ * register with the PCI subsystem.
+ *
+ * Return: 0 on success, negative on failure
+ **/
+static int __init fbnic_init_module(void)
+{
+       int err;
+
+       err = pci_register_driver(&fbnic_driver);
+       if (err)
+               goto out;
+
+       pr_info(DRV_SUMMARY " (%s)", fbnic_driver.name);
+out:
+       return err;
+}
+module_init(fbnic_init_module);
+
+/**
+ * fbnic_exit_module - Driver Exit Cleanup Routine
+ *
+ * Called just before the driver is removed from memory.
+ **/
+static void __exit fbnic_exit_module(void)
+{
+       pci_unregister_driver(&fbnic_driver);
+}
+module_exit(fbnic_exit_module);