octeontx2-pf: Add Marvell OcteonTX2 NIC driver

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>
This commit is contained in:
Sunil Goutham 2020-01-27 18:35:15 +05:30 committed by David S. Miller
parent 9e0703a265
commit 165475779b
6 changed files with 362 additions and 0 deletions

View 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.

View 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/

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -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 */