octeontx2-pf: Add Marvell OcteonTX2 NIC driver
authorSunil Goutham <sgoutham@marvell.com>
Mon, 27 Jan 2020 13:05:15 +0000 (18:35 +0530)
committerDavid S. Miller <davem@davemloft.net>
Mon, 27 Jan 2020 13:33:39 +0000 (14:33 +0100)
This patch adds template for the Marvell's OcteonTX2 network
controller's physical function driver. Just the probe, PCI
specific initialization and netdev registration.

Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/marvell/octeontx2/Kconfig
drivers/net/ethernet/marvell/octeontx2/Makefile
drivers/net/ethernet/marvell/octeontx2/nic/Makefile [new file with mode: 0644]
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h [new file with mode: 0644]
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c [new file with mode: 0644]
drivers/net/ethernet/marvell/octeontx2/nic/otx2_reg.h [new file with mode: 0644]

index fb34fbd62088f92f2474c0c15950237943a078fd..ced514c05c97f43f6e56e98cc3e7641fbf8814ad 100644 (file)
@@ -25,3 +25,11 @@ config NDC_DIS_DYNAMIC_CACHING
          This config option disables caching of dynamic entries such as NIX SQEs
          , NPA stack pages etc in NDC. Also locks down NIX SQ/CQ/RQ/RSS and
          NPA Aura/Pool contexts.
+
+config OCTEONTX2_PF
+       tristate "Marvell OcteonTX2 NIC Physical Function driver"
+       select OCTEONTX2_MBOX
+       depends on (64BIT && COMPILE_TEST) || ARM64
+       depends on PCI
+       help
+         This driver supports Marvell's OcteonTX2 NIC physical function.
index e579dcd54c97213429ff93c3fa926d936d10405f..0064a69e0f72fa0c2f4aecccb9b0cfbe241a6393 100644 (file)
@@ -3,4 +3,6 @@
 # Makefile for Marvell OcteonTX2 device drivers.
 #
 
+obj-$(CONFIG_OCTEONTX2_MBOX) += af/
 obj-$(CONFIG_OCTEONTX2_AF) += af/
+obj-$(CONFIG_OCTEONTX2_PF) += nic/
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile b/drivers/net/ethernet/marvell/octeontx2/nic/Makefile
new file mode 100644 (file)
index 0000000..622b803
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for Marvell's OcteonTX2 ethernet device drivers
+#
+
+obj-$(CONFIG_OCTEONTX2_PF) += octeontx2_nicpf.o
+
+octeontx2_nicpf-y := otx2_pf.o
+
+ccflags-y += -I$(srctree)/drivers/net/ethernet/marvell/octeontx2/af
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
new file mode 100644 (file)
index 0000000..9d52ab3
--- /dev/null
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Marvell OcteonTx2 RVU Ethernet driver
+ *
+ * Copyright (C) 2020 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef OTX2_COMMON_H
+#define OTX2_COMMON_H
+
+#include <linux/pci.h>
+
+#include "otx2_reg.h"
+
+/* PCI device IDs */
+#define PCI_DEVID_OCTEONTX2_RVU_PF              0xA063
+
+/* PCI BAR nos */
+#define PCI_CFG_REG_BAR_NUM                     2
+
+struct otx2_hw {
+       struct pci_dev          *pdev;
+       u16                     rx_queues;
+       u16                     tx_queues;
+       u16                     max_queues;
+};
+
+struct otx2_nic {
+       void __iomem            *reg_base;
+       struct net_device       *netdev;
+
+       struct otx2_hw          hw;
+       struct pci_dev          *pdev;
+       struct device           *dev;
+};
+
+/* Register read/write APIs */
+static inline void __iomem *otx2_get_regaddr(struct otx2_nic *nic, u64 offset)
+{
+       u64 blkaddr;
+
+       switch ((offset >> RVU_FUNC_BLKADDR_SHIFT) & RVU_FUNC_BLKADDR_MASK) {
+       case BLKTYPE_NIX:
+               blkaddr = BLKADDR_NIX0;
+               break;
+       case BLKTYPE_NPA:
+               blkaddr = BLKADDR_NPA;
+               break;
+       default:
+               blkaddr = BLKADDR_RVUM;
+               break;
+       };
+
+       offset &= ~(RVU_FUNC_BLKADDR_MASK << RVU_FUNC_BLKADDR_SHIFT);
+       offset |= (blkaddr << RVU_FUNC_BLKADDR_SHIFT);
+
+       return nic->reg_base + offset;
+}
+
+static inline void otx2_write64(struct otx2_nic *nic, u64 offset, u64 val)
+{
+       void __iomem *addr = otx2_get_regaddr(nic, offset);
+
+       writeq(val, addr);
+}
+
+static inline u64 otx2_read64(struct otx2_nic *nic, u64 offset)
+{
+       void __iomem *addr = otx2_get_regaddr(nic, offset);
+
+       return readq(addr);
+}
+
+#endif /* OTX2_COMMON_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
new file mode 100644 (file)
index 0000000..d3af200
--- /dev/null
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell OcteonTx2 RVU Physcial Function ethernet driver
+ *
+ * Copyright (C) 2020 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+#include <linux/of.h>
+#include <linux/if_vlan.h>
+#include <linux/iommu.h>
+#include <net/ip.h>
+
+#include "otx2_common.h"
+
+#define DRV_NAME       "octeontx2-nicpf"
+#define DRV_STRING     "Marvell OcteonTX2 NIC Physical Function Driver"
+#define DRV_VERSION    "1.0"
+
+/* Supported devices */
+static const struct pci_device_id otx2_pf_id_table[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_RVU_PF) },
+       { 0, }  /* end of table */
+};
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION(DRV_STRING);
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, otx2_pf_id_table);
+
+static int otx2_set_real_num_queues(struct net_device *netdev,
+                                   int tx_queues, int rx_queues)
+{
+       int err;
+
+       err = netif_set_real_num_tx_queues(netdev, tx_queues);
+       if (err) {
+               netdev_err(netdev,
+                          "Failed to set no of Tx queues: %d\n", tx_queues);
+               return err;
+       }
+
+       err = netif_set_real_num_rx_queues(netdev, rx_queues);
+       if (err)
+               netdev_err(netdev,
+                          "Failed to set no of Rx queues: %d\n", rx_queues);
+       return err;
+}
+
+static int otx2_open(struct net_device *netdev)
+{
+       netif_carrier_off(netdev);
+
+       return 0;
+}
+
+static int otx2_stop(struct net_device *netdev)
+{
+       return 0;
+}
+
+static const struct net_device_ops otx2_netdev_ops = {
+       .ndo_open               = otx2_open,
+       .ndo_stop               = otx2_stop,
+};
+
+static int otx2_check_pf_usable(struct otx2_nic *nic)
+{
+       u64 rev;
+
+       rev = otx2_read64(nic, RVU_PF_BLOCK_ADDRX_DISC(BLKADDR_RVUM));
+       rev = (rev >> 12) & 0xFF;
+       /* Check if AF has setup revision for RVUM block,
+        * otherwise this driver probe should be deferred
+        * until AF driver comes up.
+        */
+       if (!rev) {
+               dev_warn(nic->dev,
+                        "AF is not initialized, deferring probe\n");
+               return -EPROBE_DEFER;
+       }
+       return 0;
+}
+
+static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct device *dev = &pdev->dev;
+       struct net_device *netdev;
+       struct otx2_nic *pf;
+       struct otx2_hw *hw;
+       int err, qcount;
+
+       err = pcim_enable_device(pdev);
+       if (err) {
+               dev_err(dev, "Failed to enable PCI device\n");
+               return err;
+       }
+
+       err = pci_request_regions(pdev, DRV_NAME);
+       if (err) {
+               dev_err(dev, "PCI request regions failed 0x%x\n", err);
+               return err;
+       }
+
+       err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
+       if (err) {
+               dev_err(dev, "DMA mask config failed, abort\n");
+               goto err_release_regions;
+       }
+
+       pci_set_master(pdev);
+
+       /* Set number of queues */
+       qcount = min_t(int, num_online_cpus(), num_online_cpus());
+
+       netdev = alloc_etherdev_mqs(sizeof(*pf), qcount, qcount);
+       if (!netdev) {
+               err = -ENOMEM;
+               goto err_release_regions;
+       }
+
+       pci_set_drvdata(pdev, netdev);
+       SET_NETDEV_DEV(netdev, &pdev->dev);
+       pf = netdev_priv(netdev);
+       pf->netdev = netdev;
+       pf->pdev = pdev;
+       pf->dev = dev;
+
+       hw = &pf->hw;
+       hw->pdev = pdev;
+       hw->rx_queues = qcount;
+       hw->tx_queues = qcount;
+       hw->max_queues = qcount;
+
+       /* Map CSRs */
+       pf->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0);
+       if (!pf->reg_base) {
+               dev_err(dev, "Unable to map physical function CSRs, aborting\n");
+               err = -ENOMEM;
+               goto err_free_netdev;
+       }
+
+       err = otx2_check_pf_usable(pf);
+       if (err)
+               goto err_free_netdev;
+
+       err = otx2_set_real_num_queues(netdev, hw->tx_queues, hw->rx_queues);
+       if (err)
+               goto err_free_netdev;
+
+       netdev->netdev_ops = &otx2_netdev_ops;
+
+       err = register_netdev(netdev);
+       if (err) {
+               dev_err(dev, "Failed to register netdevice\n");
+               goto err_free_netdev;
+       }
+
+       return 0;
+
+err_free_netdev:
+       pci_set_drvdata(pdev, NULL);
+       free_netdev(netdev);
+err_release_regions:
+       pci_release_regions(pdev);
+       return err;
+}
+
+static void otx2_remove(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct otx2_nic *pf;
+
+       if (!netdev)
+               return;
+
+       pf = netdev_priv(netdev);
+
+       unregister_netdev(netdev);
+       pci_free_irq_vectors(pf->pdev);
+       pci_set_drvdata(pdev, NULL);
+       free_netdev(netdev);
+       pci_release_regions(pdev);
+}
+
+static struct pci_driver otx2_pf_driver = {
+       .name = DRV_NAME,
+       .id_table = otx2_pf_id_table,
+       .probe = otx2_probe,
+       .shutdown = otx2_remove,
+       .remove = otx2_remove,
+};
+
+static int __init otx2_rvupf_init_module(void)
+{
+       pr_info("%s: %s\n", DRV_NAME, DRV_STRING);
+
+       return pci_register_driver(&otx2_pf_driver);
+}
+
+static void __exit otx2_rvupf_cleanup_module(void)
+{
+       pci_unregister_driver(&otx2_pf_driver);
+}
+
+module_init(otx2_rvupf_init_module);
+module_exit(otx2_rvupf_cleanup_module);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_reg.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_reg.h
new file mode 100644 (file)
index 0000000..d0bd64a
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Marvell OcteonTx2 RVU Ethernet driver
+ *
+ * Copyright (C) 2020 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef OTX2_REG_H
+#define OTX2_REG_H
+
+#include <rvu_struct.h>
+
+/* RVU PF registers */
+#define        RVU_PF_VFX_PFVF_MBOX0               (0x00000)
+#define        RVU_PF_VFX_PFVF_MBOX1               (0x00008)
+#define RVU_PF_VFX_PFVF_MBOXX(a, b)         (0x0 | (a) << 12 | (b) << 3)
+#define RVU_PF_VF_BAR4_ADDR                 (0x10)
+#define RVU_PF_BLOCK_ADDRX_DISC(a)          (0x200 | (a) << 3)
+#define RVU_PF_VFME_STATUSX(a)              (0x800 | (a) << 3)
+#define RVU_PF_VFTRPENDX(a)                 (0x820 | (a) << 3)
+#define RVU_PF_VFTRPEND_W1SX(a)             (0x840 | (a) << 3)
+#define RVU_PF_VFPF_MBOX_INTX(a)            (0x880 | (a) << 3)
+#define RVU_PF_VFPF_MBOX_INT_W1SX(a)        (0x8A0 | (a) << 3)
+#define RVU_PF_VFPF_MBOX_INT_ENA_W1SX(a)    (0x8C0 | (a) << 3)
+#define RVU_PF_VFPF_MBOX_INT_ENA_W1CX(a)    (0x8E0 | (a) << 3)
+#define RVU_PF_VFFLR_INTX(a)                (0x900 | (a) << 3)
+#define RVU_PF_VFFLR_INT_W1SX(a)            (0x920 | (a) << 3)
+#define RVU_PF_VFFLR_INT_ENA_W1SX(a)        (0x940 | (a) << 3)
+#define RVU_PF_VFFLR_INT_ENA_W1CX(a)        (0x960 | (a) << 3)
+#define RVU_PF_VFME_INTX(a)                 (0x980 | (a) << 3)
+#define RVU_PF_VFME_INT_W1SX(a)             (0x9A0 | (a) << 3)
+#define RVU_PF_VFME_INT_ENA_W1SX(a)         (0x9C0 | (a) << 3)
+#define RVU_PF_VFME_INT_ENA_W1CX(a)         (0x9E0 | (a) << 3)
+#define RVU_PF_PFAF_MBOX0                   (0xC00)
+#define RVU_PF_PFAF_MBOX1                   (0xC08)
+#define RVU_PF_PFAF_MBOXX(a)                (0xC00 | (a) << 3)
+#define RVU_PF_INT                          (0xc20)
+#define RVU_PF_INT_W1S                      (0xc28)
+#define RVU_PF_INT_ENA_W1S                  (0xc30)
+#define RVU_PF_INT_ENA_W1C                  (0xc38)
+#define RVU_PF_MSIX_VECX_ADDR(a)            (0x000 | (a) << 4)
+#define RVU_PF_MSIX_VECX_CTL(a)             (0x008 | (a) << 4)
+#define RVU_PF_MSIX_PBAX(a)                 (0xF0000 | (a) << 3)
+
+#define RVU_FUNC_BLKADDR_SHIFT         20
+#define RVU_FUNC_BLKADDR_MASK          0x1FULL
+
+#endif /* OTX2_REG_H */