提交 e40d5d78 编写于 作者: D David S. Miller

Merge branch 'netronome-NFP4000-and-NFP6000-PF-driver'

Jakub Kicinski says:

====================
Netronome NFP4000 and NFP6000 PF driver

This is a base PF driver for Netronome NFP4000 and NFP6000 chips.  This
series doesn't add any exciting new features, it provides a foundation
for supporting more advanced firmware applications.

Patch 1 moves a bitfield-related helper from our BPF code to the global
header.

Patch 2 renames the kernel module and adds a new main file.  We were
considering 3-module approach (pf, vf, common netdev library) but
ultimately settled on a single module to keep things simple.

Patch 3 adds support for accessing chip internals.  It provides a way of
configuring access windows to different parts of chip memory and issuing
pretty much any commands on chip's NoC.

Patches 4, 5, 6, 7, 8 provide support for accessing and interpreting
various hardware and firmware information structures.

Patch 9 introduces service processor (NSP) ABI.  This ABI gives us
access to PHY/SFP module configuration and information as well as
methods for unloading and loading application firmware.

Patches 10 and 11 modify the existing netdev code to make it possible
to support multi-port devices (sharing a PCI device).

Patch 12 adds a new driver probe path which will be used for the PF
PCI device IDs.  It utilizes the newly added infrastructure and is able
to load application FW and spawn netdevs for all card's ports.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
......@@ -15,21 +15,21 @@ config NET_VENDOR_NETRONOME
if NET_VENDOR_NETRONOME
config NFP_NETVF
tristate "Netronome(R) NFP4000/NFP6000 VF NIC driver"
config NFP
tristate "Netronome(R) NFP4000/NFP6000 NIC driver"
depends on PCI && PCI_MSI
depends on VXLAN || VXLAN=n
---help---
This driver supports SR-IOV virtual functions of
the Netronome(R) NFP4000/NFP6000 cards working as
a advanced Ethernet NIC.
This driver supports the Netronome(R) NFP4000/NFP6000 based
cards working as a advanced Ethernet NIC. It works with both
SR-IOV physical and virtual functions.
config NFP_NET_DEBUG
bool "Debug support for Netronome(R) NFP3200/NFP6000 NIC drivers"
depends on NFP_NET || NFP_NETVF
config NFP_DEBUG
bool "Debug support for Netronome(R) NFP4000/NFP6000 NIC drivers"
depends on NFP
---help---
Enable extra sanity checks and debugfs support in
Netronome(R) NFP3200/NFP6000 NIC PF and VF drivers.
Netronome(R) NFP4000/NFP6000 NIC drivers.
Note: selecting this option may adversely impact
performance.
......
......@@ -2,4 +2,4 @@
# Makefile for the Netronome network device drivers
#
obj-$(CONFIG_NFP_NETVF) += nfp/
obj-$(CONFIG_NFP) += nfp/
obj-$(CONFIG_NFP_NETVF) += nfp_netvf.o
obj-$(CONFIG_NFP) += nfp.o
nfp_netvf-objs := \
nfp-objs := \
nfpcore/nfp6000_pcie.o \
nfpcore/nfp_cppcore.o \
nfpcore/nfp_cpplib.o \
nfpcore/nfp_hwinfo.o \
nfpcore/nfp_mip.o \
nfpcore/nfp_nffw.o \
nfpcore/nfp_nsp.o \
nfpcore/nfp_nsp_eth.o \
nfpcore/nfp_resource.o \
nfpcore/nfp_rtsym.o \
nfpcore/nfp_target.o \
nfp_main.o \
nfp_net_common.o \
nfp_net_ethtool.o \
nfp_net_offload.o \
nfp_net_main.o \
nfp_netvf_main.o
ifeq ($(CONFIG_BPF_SYSCALL),y)
nfp_netvf-objs += \
nfp-objs += \
nfp_bpf_verifier.o \
nfp_bpf_jit.o
endif
nfp_netvf-$(CONFIG_NFP_NET_DEBUG) += nfp_net_debugfs.o
nfp-$(CONFIG_NFP_DEBUG) += nfp_net_debugfs.o
......@@ -39,8 +39,6 @@
#include <linux/list.h>
#include <linux/types.h>
#define FIELD_FIT(mask, val) (!((((u64)val) << __bf_shf(mask)) & ~(mask)))
/* For branch fixup logic use up-most byte of branch instruction as scratch
* area. Remember to clear this before sending instructions to HW!
*/
......
/*
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* nfp_main.c
* Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
* Alejandro Lucero <alejandro.lucero@netronome.com>
* Jason McMullan <jason.mcmullan@netronome.com>
* Rolf Neugebauer <rolf.neugebauer@netronome.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/vermagic.h>
#include "nfpcore/nfp.h"
#include "nfpcore/nfp_cpp.h"
#include "nfpcore/nfp_nsp_eth.h"
#include "nfpcore/nfp6000_pcie.h"
#include "nfp_main.h"
#include "nfp_net.h"
static const char nfp_driver_name[] = "nfp";
const char nfp_driver_version[] = VERMAGIC_STRING;
static const struct pci_device_id nfp_pci_device_ids[] = {
{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_NFP6000,
PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
PCI_ANY_ID, 0,
},
{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_NFP4000,
PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
PCI_ANY_ID, 0,
},
{ 0, } /* Required last entry. */
};
MODULE_DEVICE_TABLE(pci, nfp_pci_device_ids);
static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs)
{
#ifdef CONFIG_PCI_IOV
struct nfp_pf *pf = pci_get_drvdata(pdev);
int err;
err = pci_enable_sriov(pdev, num_vfs);
if (err) {
dev_warn(&pdev->dev, "Failed to enable PCI sriov: %d\n", err);
return err;
}
pf->num_vfs = num_vfs;
dev_dbg(&pdev->dev, "Created %d VFs.\n", pf->num_vfs);
return num_vfs;
#endif
return 0;
}
static int nfp_pcie_sriov_disable(struct pci_dev *pdev)
{
#ifdef CONFIG_PCI_IOV
struct nfp_pf *pf = pci_get_drvdata(pdev);
/* If the VFs are assigned we cannot shut down SR-IOV without
* causing issues, so just leave the hardware available but
* disabled
*/
if (pci_vfs_assigned(pdev)) {
dev_warn(&pdev->dev, "Disabling while VFs assigned - VFs will not be deallocated\n");
return -EPERM;
}
pf->num_vfs = 0;
pci_disable_sriov(pdev);
dev_dbg(&pdev->dev, "Removed VFs.\n");
#endif
return 0;
}
static int nfp_pcie_sriov_configure(struct pci_dev *pdev, int num_vfs)
{
if (num_vfs == 0)
return nfp_pcie_sriov_disable(pdev);
else
return nfp_pcie_sriov_enable(pdev, num_vfs);
}
/**
* nfp_net_fw_find() - Find the correct firmware image for netdev mode
* @pdev: PCI Device structure
* @pf: NFP PF Device structure
*
* Return: firmware if found and requested successfully.
*/
static const struct firmware *
nfp_net_fw_find(struct pci_dev *pdev, struct nfp_pf *pf)
{
const struct firmware *fw = NULL;
struct nfp_eth_table_port *port;
const char *fw_model;
char fw_name[256];
int spc, err = 0;
int i, j;
if (!pf->eth_tbl) {
dev_err(&pdev->dev, "Error: can't identify media config\n");
return NULL;
}
fw_model = nfp_hwinfo_lookup(pf->cpp, "assembly.partno");
if (!fw_model) {
dev_err(&pdev->dev, "Error: can't read part number\n");
return NULL;
}
spc = ARRAY_SIZE(fw_name);
spc -= snprintf(fw_name, spc, "netronome/nic_%s", fw_model);
for (i = 0; spc > 0 && i < pf->eth_tbl->count; i += j) {
port = &pf->eth_tbl->ports[i];
j = 1;
while (i + j < pf->eth_tbl->count &&
port->speed == port[j].speed)
j++;
spc -= snprintf(&fw_name[ARRAY_SIZE(fw_name) - spc], spc,
"_%dx%d", j, port->speed / 1000);
}
if (spc <= 0)
return NULL;
spc -= snprintf(&fw_name[ARRAY_SIZE(fw_name) - spc], spc, ".nffw");
if (spc <= 0)
return NULL;
err = request_firmware(&fw, fw_name, &pdev->dev);
if (err)
return NULL;
dev_info(&pdev->dev, "Loading FW image: %s\n", fw_name);
return fw;
}
/**
* nfp_net_fw_load() - Load the firmware image
* @pdev: PCI Device structure
* @pf: NFP PF Device structure
* @nsp: NFP SP handle
*
* Return: -ERRNO, 0 for no firmware loaded, 1 for firmware loaded
*/
static int
nfp_fw_load(struct pci_dev *pdev, struct nfp_pf *pf, struct nfp_nsp *nsp)
{
const struct firmware *fw;
u16 interface;
int err;
interface = nfp_cpp_interface(pf->cpp);
if (NFP_CPP_INTERFACE_UNIT_of(interface) != 0) {
/* Only Unit 0 should reset or load firmware */
dev_info(&pdev->dev, "Firmware will be loaded by partner\n");
return 0;
}
fw = nfp_net_fw_find(pdev, pf);
if (!fw)
return 0;
dev_info(&pdev->dev, "Soft-reset, loading FW image\n");
err = nfp_nsp_device_soft_reset(nsp);
if (err < 0) {
dev_err(&pdev->dev, "Failed to soft reset the NFP: %d\n",
err);
goto exit_release_fw;
}
err = nfp_nsp_load_fw(nsp, fw);
if (err < 0) {
dev_err(&pdev->dev, "FW loading failed: %d\n", err);
goto exit_release_fw;
}
dev_info(&pdev->dev, "Finished loading FW image\n");
exit_release_fw:
release_firmware(fw);
return err < 0 ? err : 1;
}
static void nfp_fw_unload(struct nfp_pf *pf)
{
struct nfp_nsp *nsp;
int err;
nsp = nfp_nsp_open(pf->cpp);
if (IS_ERR(nsp)) {
nfp_err(pf->cpp, "Reset failed, can't open NSP\n");
return;
}
err = nfp_nsp_device_soft_reset(nsp);
if (err < 0)
dev_warn(&pf->pdev->dev, "Couldn't unload firmware: %d\n", err);
else
dev_info(&pf->pdev->dev, "Firmware safely unloaded\n");
nfp_nsp_close(nsp);
}
static int nfp_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_id)
{
struct nfp_nsp *nsp;
struct nfp_pf *pf;
int err;
err = pci_enable_device(pdev);
if (err < 0)
return err;
pci_set_master(pdev);
err = dma_set_mask_and_coherent(&pdev->dev,
DMA_BIT_MASK(NFP_NET_MAX_DMA_BITS));
if (err)
goto err_pci_disable;
err = pci_request_regions(pdev, nfp_driver_name);
if (err < 0) {
dev_err(&pdev->dev, "Unable to reserve pci resources.\n");
goto err_pci_disable;
}
pf = kzalloc(sizeof(*pf), GFP_KERNEL);
if (!pf) {
err = -ENOMEM;
goto err_rel_regions;
}
INIT_LIST_HEAD(&pf->ports);
pci_set_drvdata(pdev, pf);
pf->pdev = pdev;
pf->cpp = nfp_cpp_from_nfp6000_pcie(pdev);
if (IS_ERR_OR_NULL(pf->cpp)) {
err = PTR_ERR(pf->cpp);
if (err >= 0)
err = -ENOMEM;
goto err_disable_msix;
}
nsp = nfp_nsp_open(pf->cpp);
if (IS_ERR(nsp)) {
err = PTR_ERR(nsp);
goto err_cpp_free;
}
err = nfp_nsp_wait(nsp);
if (err < 0) {
nfp_nsp_close(nsp);
goto err_cpp_free;
}
pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);
err = nfp_fw_load(pdev, pf, nsp);
nfp_nsp_close(nsp);
if (err < 0) {
dev_err(&pdev->dev, "Failed to load FW\n");
goto err_eth_tbl_free;
}
pf->fw_loaded = !!err;
err = nfp_net_pci_probe(pf);
if (err)
goto err_fw_unload;
return 0;
err_fw_unload:
if (pf->fw_loaded)
nfp_fw_unload(pf);
err_eth_tbl_free:
kfree(pf->eth_tbl);
err_cpp_free:
nfp_cpp_free(pf->cpp);
err_disable_msix:
pci_set_drvdata(pdev, NULL);
kfree(pf);
err_rel_regions:
pci_release_regions(pdev);
err_pci_disable:
pci_disable_device(pdev);
return err;
}
static void nfp_pci_remove(struct pci_dev *pdev)
{
struct nfp_pf *pf = pci_get_drvdata(pdev);
if (!list_empty(&pf->ports))
nfp_net_pci_remove(pf);
nfp_pcie_sriov_disable(pdev);
if (pf->fw_loaded)
nfp_fw_unload(pf);
pci_set_drvdata(pdev, NULL);
nfp_cpp_free(pf->cpp);
kfree(pf->eth_tbl);
kfree(pf);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
static struct pci_driver nfp_pci_driver = {
.name = nfp_driver_name,
.id_table = nfp_pci_device_ids,
.probe = nfp_pci_probe,
.remove = nfp_pci_remove,
.sriov_configure = nfp_pcie_sriov_configure,
};
static int __init nfp_main_init(void)
{
int err;
pr_info("%s: NFP PCIe Driver, Copyright (C) 2014-2017 Netronome Systems\n",
nfp_driver_name);
nfp_net_debugfs_create();
err = pci_register_driver(&nfp_pci_driver);
if (err < 0)
goto err_destroy_debugfs;
err = pci_register_driver(&nfp_netvf_pci_driver);
if (err)
goto err_unreg_pf;
return err;
err_unreg_pf:
pci_unregister_driver(&nfp_pci_driver);
err_destroy_debugfs:
nfp_net_debugfs_destroy();
return err;
}
static void __exit nfp_main_exit(void)
{
pci_unregister_driver(&nfp_netvf_pci_driver);
pci_unregister_driver(&nfp_pci_driver);
nfp_net_debugfs_destroy();
}
module_init(nfp_main_init);
module_exit(nfp_main_exit);
MODULE_FIRMWARE("netronome/nic_AMDA0081-0001_1x40.nffw");
MODULE_FIRMWARE("netronome/nic_AMDA0081-0001_4x10.nffw");
MODULE_FIRMWARE("netronome/nic_AMDA0096-0001_2x10.nffw");
MODULE_FIRMWARE("netronome/nic_AMDA0097-0001_2x40.nffw");
MODULE_FIRMWARE("netronome/nic_AMDA0097-0001_4x10_1x40.nffw");
MODULE_FIRMWARE("netronome/nic_AMDA0097-0001_8x10.nffw");
MODULE_FIRMWARE("netronome/nic_AMDA0099-0001_2x10.nffw");
MODULE_FIRMWARE("netronome/nic_AMDA0099-0001_2x25.nffw");
MODULE_AUTHOR("Netronome Systems <oss-drivers@netronome.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("The Netronome Flow Processor (NFP) driver.");
/*
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* nfp_main.h
* Author: Jason McMullan <jason.mcmullan@netronome.com>
*/
#ifndef NFP_MAIN_H
#define NFP_MAIN_H
#include <linux/list.h>
#include <linux/types.h>
#include <linux/msi.h>
#include <linux/pci.h>
struct dentry;
struct pci_dev;
struct nfp_cpp;
struct nfp_cpp_area;
struct nfp_eth_table;
/**
* struct nfp_pf - NFP PF-specific device structure
* @pdev: Backpointer to PCI device
* @cpp: Pointer to the CPP handle
* @ctrl_area: Pointer to the CPP area for the control BAR
* @tx_area: Pointer to the CPP area for the TX queues
* @rx_area: Pointer to the CPP area for the FL/RX queues
* @irq_entries: Array of MSI-X entries for all ports
* @num_vfs: Number of SR-IOV VFs enabled
* @fw_loaded: Is the firmware loaded?
* @eth_tbl: NSP ETH table
* @ddir: Per-device debugfs directory
* @num_ports: Number of adapter ports
* @ports: Linked list of port structures (struct nfp_net)
*/
struct nfp_pf {
struct pci_dev *pdev;
struct nfp_cpp *cpp;
struct nfp_cpp_area *ctrl_area;
struct nfp_cpp_area *tx_area;
struct nfp_cpp_area *rx_area;
struct msix_entry *irq_entries;
unsigned int num_vfs;
bool fw_loaded;
struct nfp_eth_table *eth_tbl;
struct dentry *ddir;
unsigned int num_ports;
struct list_head ports;
};
extern struct pci_driver nfp_netvf_pci_driver;
int nfp_net_pci_probe(struct nfp_pf *pf);
void nfp_net_pci_remove(struct nfp_pf *pf);
#endif /* NFP_MAIN_H */
/*
* Copyright (C) 2015 Netronome Systems, Inc.
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
......@@ -43,6 +43,7 @@
#define _NFP_NET_H_
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/io-64-nonatomic-hi-lo.h>
......@@ -83,6 +84,7 @@
#define NFP_NET_NON_Q_VECTORS 2
#define NFP_NET_IRQ_LSC_IDX 0
#define NFP_NET_IRQ_EXN_IDX 1
#define NFP_NET_MIN_PORT_IRQS (NFP_NET_NON_Q_VECTORS + 1)
/* Queue/Ring definitions */
#define NFP_NET_MAX_TX_RINGS 64 /* Max. # of Tx rings per device */
......@@ -345,7 +347,7 @@ struct nfp_net_rx_ring {
* @tx_ring: Pointer to TX ring
* @rx_ring: Pointer to RX ring
* @xdp_ring: Pointer to an extra TX ring for XDP
* @irq_idx: Index into MSI-X table
* @irq_entry: MSI-X table entry (use for talking to the device)
* @rx_sync: Seqlock for atomic updates of RX stats
* @rx_pkts: Number of received packets
* @rx_bytes: Number of received bytes
......@@ -362,6 +364,7 @@ struct nfp_net_rx_ring {
* @tx_lso: Counter of LSO packets sent
* @tx_errors: How many TX errors were encountered
* @tx_busy: How often was TX busy (no space)?
* @irq_vector: Interrupt vector number (use for talking to the OS)
* @handler: Interrupt handler for this ring vector
* @name: Name of the interrupt vector
* @affinity_mask: SMP affinity mask for this vector
......@@ -378,7 +381,7 @@ struct nfp_net_r_vector {
struct nfp_net_tx_ring *tx_ring;
struct nfp_net_rx_ring *rx_ring;
int irq_idx;
u16 irq_entry;
struct u64_stats_sync rx_sync;
u64 rx_pkts;
......@@ -400,6 +403,7 @@ struct nfp_net_r_vector {
u64 tx_errors;
u64 tx_busy;
u32 irq_vector;
irq_handler_t handler;
char name[IFNAMSIZ + 8];
cpumask_t affinity_mask;
......@@ -431,20 +435,13 @@ struct nfp_stat_pair {
* struct nfp_net - NFP network device structure
* @pdev: Backpointer to PCI device
* @netdev: Backpointer to net_device structure
* @nfp_fallback: Is the driver used in fallback mode?
* @is_vf: Is the driver attached to a VF?
* @fw_loaded: Is the firmware loaded?
* @bpf_offload_skip_sw: Offloaded BPF program will not be rerun by cls_bpf
* @bpf_offload_xdp: Offloaded BPF program is XDP
* @ctrl: Local copy of the control register/word.
* @fl_bufsz: Currently configured size of the freelist buffers
* @rx_offset: Offset in the RX buffers where packet data starts
* @xdp_prog: Installed XDP program
* @cpp: Pointer to the CPP handle
* @nfp_dev_cpp: Pointer to the NFP Device handle
* @ctrl_area: Pointer to the CPP area for the control BAR
* @tx_area: Pointer to the CPP area for the TX queues
* @rx_area: Pointer to the CPP area for the FL/RX queues
* @fw_ver: Firmware version
* @cap: Capabilities advertised by the Firmware
* @max_mtu: Maximum support MTU advertised by the Firmware
......@@ -494,14 +491,13 @@ struct nfp_stat_pair {
* @tx_bar: Pointer to mapped TX queues
* @rx_bar: Pointer to mapped FL/RX queues
* @debugfs_dir: Device directory in debugfs
* @port_list: Entry on device port list
*/
struct nfp_net {
struct pci_dev *pdev;
struct net_device *netdev;
unsigned nfp_fallback:1;
unsigned is_vf:1;
unsigned fw_loaded:1;
unsigned bpf_offload_skip_sw:1;
unsigned bpf_offload_xdp:1;
......@@ -515,18 +511,6 @@ struct nfp_net {
struct nfp_net_tx_ring *tx_rings;
struct nfp_net_rx_ring *rx_rings;
#ifdef CONFIG_PCI_IOV
unsigned int num_vfs;
struct vf_data_storage *vfinfo;
int vf_rate_link_speed;
#endif
struct nfp_cpp *cpp;
struct platform_device *nfp_dev_cpp;
struct nfp_cpp_area *ctrl_area;
struct nfp_cpp_area *tx_area;
struct nfp_cpp_area *rx_area;
struct nfp_net_fw_version fw_ver;
u32 cap;
u32 max_mtu;
......@@ -589,11 +573,12 @@ struct nfp_net {
u8 __iomem *qcp_cfg;
u8 __iomem *ctrl_bar;
u8 __iomem *q_bar;
u8 __iomem *tx_bar;
u8 __iomem *rx_bar;
struct dentry *debugfs_dir;
struct list_head port_list;
};
struct nfp_net_ring_set {
......@@ -770,8 +755,7 @@ static inline u32 nfp_qcp_wr_ptr_read(u8 __iomem *q)
}
/* Globals */
extern const char nfp_net_driver_name[];
extern const char nfp_net_driver_version[];
extern const char nfp_driver_version[];
/* Prototypes */
void nfp_net_get_fw_version(struct nfp_net_fw_version *fw_ver,
......@@ -789,17 +773,24 @@ int nfp_net_reconfig(struct nfp_net *nn, u32 update);
void nfp_net_rss_write_itbl(struct nfp_net *nn);
void nfp_net_rss_write_key(struct nfp_net *nn);
void nfp_net_coalesce_write_cfg(struct nfp_net *nn);
int nfp_net_irqs_alloc(struct nfp_net *nn);
void nfp_net_irqs_disable(struct nfp_net *nn);
unsigned int
nfp_net_irqs_alloc(struct pci_dev *pdev, struct msix_entry *irq_entries,
unsigned int min_irqs, unsigned int want_irqs);
void nfp_net_irqs_disable(struct pci_dev *pdev);
void
nfp_net_irqs_assign(struct nfp_net *nn, struct msix_entry *irq_entries,
unsigned int n);
int
nfp_net_ring_reconfig(struct nfp_net *nn, struct bpf_prog **xdp_prog,
struct nfp_net_ring_set *rx, struct nfp_net_ring_set *tx);
#ifdef CONFIG_NFP_NET_DEBUG
#ifdef CONFIG_NFP_DEBUG
void nfp_net_debugfs_create(void);
void nfp_net_debugfs_destroy(void);
void nfp_net_debugfs_adapter_add(struct nfp_net *nn);
void nfp_net_debugfs_adapter_del(struct nfp_net *nn);
struct dentry *nfp_net_debugfs_device_add(struct pci_dev *pdev);
void nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id);
void nfp_net_debugfs_dir_clean(struct dentry **dir);
#else
static inline void nfp_net_debugfs_create(void)
{
......@@ -809,14 +800,20 @@ static inline void nfp_net_debugfs_destroy(void)
{
}
static inline void nfp_net_debugfs_adapter_add(struct nfp_net *nn)
static inline struct dentry *nfp_net_debugfs_device_add(struct pci_dev *pdev)
{
return NULL;
}
static inline void
nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id)
{
}
static inline void nfp_net_debugfs_adapter_del(struct nfp_net *nn)
static inline void nfp_net_debugfs_dir_clean(struct dentry **dir)
{
}
#endif /* CONFIG_NFP_NET_DEBUG */
#endif /* CONFIG_NFP_DEBUG */
void nfp_net_filter_stats_timer(unsigned long data);
int nfp_net_bpf_offload(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf);
......
/*
* Copyright (C) 2015 Netronome Systems, Inc.
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
......@@ -281,72 +281,76 @@ static void nfp_net_irq_unmask(struct nfp_net *nn, unsigned int entry_nr)
}
/**
* nfp_net_msix_alloc() - Try to allocate MSI-X irqs
* @nn: NFP Network structure
* @nr_vecs: Number of MSI-X vectors to allocate
*
* For MSI-X we want at least NFP_NET_NON_Q_VECTORS + 1 vectors.
* nfp_net_irqs_alloc() - allocates MSI-X irqs
* @pdev: PCI device structure
* @irq_entries: Array to be initialized and used to hold the irq entries
* @min_irqs: Minimal acceptable number of interrupts
* @wanted_irqs: Target number of interrupts to allocate
*
* Return: Number of MSI-X vectors obtained or 0 on error.
* Return: Number of irqs obtained or 0 on error.
*/
static int nfp_net_msix_alloc(struct nfp_net *nn, int nr_vecs)
unsigned int
nfp_net_irqs_alloc(struct pci_dev *pdev, struct msix_entry *irq_entries,
unsigned int min_irqs, unsigned int wanted_irqs)
{
struct pci_dev *pdev = nn->pdev;
int nvecs;
int i;
unsigned int i;
int got_irqs;
for (i = 0; i < nr_vecs; i++)
nn->irq_entries[i].entry = i;
for (i = 0; i < wanted_irqs; i++)
irq_entries[i].entry = i;
nvecs = pci_enable_msix_range(pdev, nn->irq_entries,
NFP_NET_NON_Q_VECTORS + 1, nr_vecs);
if (nvecs < 0) {
nn_warn(nn, "Failed to enable MSI-X. Wanted %d-%d (err=%d)\n",
NFP_NET_NON_Q_VECTORS + 1, nr_vecs, nvecs);
got_irqs = pci_enable_msix_range(pdev, irq_entries,
min_irqs, wanted_irqs);
if (got_irqs < 0) {
dev_err(&pdev->dev, "Failed to enable %d-%d MSI-X (err=%d)\n",
min_irqs, wanted_irqs, got_irqs);
return 0;
}
return nvecs;
if (got_irqs < wanted_irqs)
dev_warn(&pdev->dev, "Unable to allocate %d IRQs got only %d\n",
wanted_irqs, got_irqs);
return got_irqs;
}
/**
* nfp_net_irqs_alloc() - allocates MSI-X irqs
* @nn: NFP Network structure
* nfp_net_irqs_assign() - Assign interrupts allocated externally to netdev
* @nn: NFP Network structure
* @irq_entries: Table of allocated interrupts
* @n: Size of @irq_entries (number of entries to grab)
*
* Return: Number of irqs obtained or 0 on error.
* After interrupts are allocated with nfp_net_irqs_alloc() this function
* should be called to assign them to a specific netdev (port).
*/
int nfp_net_irqs_alloc(struct nfp_net *nn)
void
nfp_net_irqs_assign(struct nfp_net *nn, struct msix_entry *irq_entries,
unsigned int n)
{
int wanted_irqs;
unsigned int n;
wanted_irqs = nn->num_r_vecs + NFP_NET_NON_Q_VECTORS;
n = nfp_net_msix_alloc(nn, wanted_irqs);
if (n == 0) {
nn_err(nn, "Failed to allocate MSI-X IRQs\n");
return 0;
}
nn->max_r_vecs = n - NFP_NET_NON_Q_VECTORS;
nn->num_r_vecs = nn->max_r_vecs;
if (n < wanted_irqs)
nn_warn(nn, "Unable to allocate %d vectors. Got %d instead\n",
wanted_irqs, n);
memcpy(nn->irq_entries, irq_entries, sizeof(*irq_entries) * n);
return n;
if (nn->num_rx_rings > nn->num_r_vecs ||
nn->num_tx_rings > nn->num_r_vecs)
nn_warn(nn, "More rings (%d,%d) than vectors (%d).\n",
nn->num_rx_rings, nn->num_tx_rings, nn->num_r_vecs);
nn->num_rx_rings = min(nn->num_r_vecs, nn->num_rx_rings);
nn->num_tx_rings = min(nn->num_r_vecs, nn->num_tx_rings);
nn->num_stack_tx_rings = nn->num_tx_rings;
}
/**
* nfp_net_irqs_disable() - Disable interrupts
* @nn: NFP Network structure
* @pdev: PCI device structure
*
* Undoes what @nfp_net_irqs_alloc() does.
*/
void nfp_net_irqs_disable(struct nfp_net *nn)
void nfp_net_irqs_disable(struct pci_dev *pdev)
{
pci_disable_msix(nn->pdev);
pci_disable_msix(pdev);
}
/**
......@@ -410,10 +414,13 @@ static void nfp_net_read_link_status(struct nfp_net *nn)
static irqreturn_t nfp_net_irq_lsc(int irq, void *data)
{
struct nfp_net *nn = data;
struct msix_entry *entry;
entry = &nn->irq_entries[NFP_NET_IRQ_LSC_IDX];
nfp_net_read_link_status(nn);
nfp_net_irq_unmask(nn, NFP_NET_IRQ_LSC_IDX);
nfp_net_irq_unmask(nn, entry->entry);
return IRQ_HANDLED;
}
......@@ -476,32 +483,28 @@ nfp_net_rx_ring_init(struct nfp_net_rx_ring *rx_ring,
}
/**
* nfp_net_irqs_assign() - Assign IRQs and setup rvecs.
* nfp_net_vecs_init() - Assign IRQs and setup rvecs.
* @netdev: netdev structure
*/
static void nfp_net_irqs_assign(struct net_device *netdev)
static void nfp_net_vecs_init(struct net_device *netdev)
{
struct nfp_net *nn = netdev_priv(netdev);
struct nfp_net_r_vector *r_vec;
int r;
if (nn->num_rx_rings > nn->num_r_vecs ||
nn->num_tx_rings > nn->num_r_vecs)
nn_warn(nn, "More rings (%d,%d) than vectors (%d).\n",
nn->num_rx_rings, nn->num_tx_rings, nn->num_r_vecs);
nn->num_rx_rings = min(nn->num_r_vecs, nn->num_rx_rings);
nn->num_tx_rings = min(nn->num_r_vecs, nn->num_tx_rings);
nn->num_stack_tx_rings = nn->num_tx_rings;
nn->lsc_handler = nfp_net_irq_lsc;
nn->exn_handler = nfp_net_irq_exn;
for (r = 0; r < nn->max_r_vecs; r++) {
struct msix_entry *entry;
entry = &nn->irq_entries[NFP_NET_NON_Q_VECTORS + r];
r_vec = &nn->r_vecs[r];
r_vec->nfp_net = nn;
r_vec->handler = nfp_net_irq_rxtx;
r_vec->irq_idx = NFP_NET_NON_Q_VECTORS + r;
r_vec->irq_entry = entry->entry;
r_vec->irq_vector = entry->vector;
cpumask_set_cpu(r, &r_vec->affinity_mask);
}
......@@ -534,7 +537,7 @@ nfp_net_aux_irq_request(struct nfp_net *nn, u32 ctrl_offset,
entry->vector, err);
return err;
}
nn_writeb(nn, ctrl_offset, vector_idx);
nn_writeb(nn, ctrl_offset, entry->entry);
return 0;
}
......@@ -1706,7 +1709,7 @@ static int nfp_net_poll(struct napi_struct *napi, int budget)
if (pkts_polled < budget) {
napi_complete_done(napi, pkts_polled);
nfp_net_irq_unmask(r_vec->nfp_net, r_vec->irq_idx);
nfp_net_irq_unmask(r_vec->nfp_net, r_vec->irq_entry);
}
return pkts_polled;
......@@ -1988,7 +1991,6 @@ static int
nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
int idx)
{
struct msix_entry *entry = &nn->irq_entries[r_vec->irq_idx];
int err;
/* Setup NAPI */
......@@ -1997,17 +1999,19 @@ nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
snprintf(r_vec->name, sizeof(r_vec->name),
"%s-rxtx-%d", nn->netdev->name, idx);
err = request_irq(entry->vector, r_vec->handler, 0, r_vec->name, r_vec);
err = request_irq(r_vec->irq_vector, r_vec->handler, 0, r_vec->name,
r_vec);
if (err) {
netif_napi_del(&r_vec->napi);
nn_err(nn, "Error requesting IRQ %d\n", entry->vector);
nn_err(nn, "Error requesting IRQ %d\n", r_vec->irq_vector);
return err;
}
disable_irq(entry->vector);
disable_irq(r_vec->irq_vector);
irq_set_affinity_hint(entry->vector, &r_vec->affinity_mask);
irq_set_affinity_hint(r_vec->irq_vector, &r_vec->affinity_mask);
nn_dbg(nn, "RV%02d: irq=%03d/%03d\n", idx, entry->vector, entry->entry);
nn_dbg(nn, "RV%02d: irq=%03d/%03d\n", idx, r_vec->irq_vector,
r_vec->irq_entry);
return 0;
}
......@@ -2015,11 +2019,9 @@ nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
static void
nfp_net_cleanup_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec)
{
struct msix_entry *entry = &nn->irq_entries[r_vec->irq_idx];
irq_set_affinity_hint(entry->vector, NULL);
irq_set_affinity_hint(r_vec->irq_vector, NULL);
netif_napi_del(&r_vec->napi);
free_irq(entry->vector, r_vec);
free_irq(r_vec->irq_vector, r_vec);
}
/**
......@@ -2148,7 +2150,7 @@ nfp_net_rx_ring_hw_cfg_write(struct nfp_net *nn,
/* Write the DMA address, size and MSI-X info to the device */
nn_writeq(nn, NFP_NET_CFG_RXR_ADDR(idx), rx_ring->dma);
nn_writeb(nn, NFP_NET_CFG_RXR_SZ(idx), ilog2(rx_ring->cnt));
nn_writeb(nn, NFP_NET_CFG_RXR_VEC(idx), rx_ring->r_vec->irq_idx);
nn_writeb(nn, NFP_NET_CFG_RXR_VEC(idx), rx_ring->r_vec->irq_entry);
}
static void
......@@ -2157,7 +2159,7 @@ nfp_net_tx_ring_hw_cfg_write(struct nfp_net *nn,
{
nn_writeq(nn, NFP_NET_CFG_TXR_ADDR(idx), tx_ring->dma);
nn_writeb(nn, NFP_NET_CFG_TXR_SZ(idx), ilog2(tx_ring->cnt));
nn_writeb(nn, NFP_NET_CFG_TXR_VEC(idx), tx_ring->r_vec->irq_idx);
nn_writeb(nn, NFP_NET_CFG_TXR_VEC(idx), tx_ring->r_vec->irq_entry);
}
static int __nfp_net_set_config_and_enable(struct nfp_net *nn)
......@@ -2251,7 +2253,7 @@ static void nfp_net_open_stack(struct nfp_net *nn)
for (r = 0; r < nn->num_r_vecs; r++) {
napi_enable(&nn->r_vecs[r].napi);
enable_irq(nn->irq_entries[nn->r_vecs[r].irq_idx].vector);
enable_irq(nn->r_vecs[r].irq_vector);
}
netif_tx_wake_all_queues(nn->netdev);
......@@ -2375,7 +2377,7 @@ static void nfp_net_close_stack(struct nfp_net *nn)
nn->link_up = false;
for (r = 0; r < nn->num_r_vecs; r++) {
disable_irq(nn->irq_entries[nn->r_vecs[r].irq_idx].vector);
disable_irq(nn->r_vecs[r].irq_vector);
napi_disable(&nn->r_vecs[r].napi);
}
......@@ -3259,7 +3261,7 @@ int nfp_net_netdev_init(struct net_device *netdev)
netif_carrier_off(netdev);
nfp_net_set_ethtool_ops(netdev);
nfp_net_irqs_assign(netdev);
nfp_net_vecs_init(netdev);
return register_netdev(netdev);
}
......
/*
* Copyright (C) 2015 Netronome Systems, Inc.
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
......@@ -202,16 +202,17 @@ static const struct file_operations nfp_xdp_q_fops = {
.llseek = seq_lseek
};
void nfp_net_debugfs_adapter_add(struct nfp_net *nn)
void nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id)
{
struct dentry *queues, *tx, *rx, *xdp;
char int_name[16];
char name[20];
int i;
if (IS_ERR_OR_NULL(nfp_dir))
return;
nn->debugfs_dir = debugfs_create_dir(pci_name(nn->pdev), nfp_dir);
sprintf(name, "port%d", id);
nn->debugfs_dir = debugfs_create_dir(name, ddir);
if (IS_ERR_OR_NULL(nn->debugfs_dir))
return;
......@@ -227,24 +228,38 @@ void nfp_net_debugfs_adapter_add(struct nfp_net *nn)
return;
for (i = 0; i < min(nn->max_rx_rings, nn->max_r_vecs); i++) {
sprintf(int_name, "%d", i);
debugfs_create_file(int_name, S_IRUSR, rx,
sprintf(name, "%d", i);
debugfs_create_file(name, S_IRUSR, rx,
&nn->r_vecs[i], &nfp_rx_q_fops);
debugfs_create_file(int_name, S_IRUSR, xdp,
debugfs_create_file(name, S_IRUSR, xdp,
&nn->r_vecs[i], &nfp_xdp_q_fops);
}
for (i = 0; i < min(nn->max_tx_rings, nn->max_r_vecs); i++) {
sprintf(int_name, "%d", i);
debugfs_create_file(int_name, S_IRUSR, tx,
sprintf(name, "%d", i);
debugfs_create_file(name, S_IRUSR, tx,
&nn->r_vecs[i], &nfp_tx_q_fops);
}
}
void nfp_net_debugfs_adapter_del(struct nfp_net *nn)
struct dentry *nfp_net_debugfs_device_add(struct pci_dev *pdev)
{
debugfs_remove_recursive(nn->debugfs_dir);
nn->debugfs_dir = NULL;
struct dentry *dev_dir;
if (IS_ERR_OR_NULL(nfp_dir))
return NULL;
dev_dir = debugfs_create_dir(pci_name(pdev), nfp_dir);
if (IS_ERR_OR_NULL(dev_dir))
return NULL;
return dev_dir;
}
void nfp_net_debugfs_dir_clean(struct dentry **dir)
{
debugfs_remove_recursive(*dir);
*dir = NULL;
}
void nfp_net_debugfs_create(void)
......
/*
* Copyright (C) 2015 Netronome Systems, Inc.
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
......@@ -132,9 +132,9 @@ static void nfp_net_get_drvinfo(struct net_device *netdev,
{
struct nfp_net *nn = netdev_priv(netdev);
strlcpy(drvinfo->driver, nfp_net_driver_name, sizeof(drvinfo->driver));
strlcpy(drvinfo->version, nfp_net_driver_version,
sizeof(drvinfo->version));
strlcpy(drvinfo->driver, nn->pdev->driver->name,
sizeof(drvinfo->driver));
strlcpy(drvinfo->version, nfp_driver_version, sizeof(drvinfo->version));
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
"%d.%d.%d.%d",
......
/*
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* nfp_net_main.c
* Netronome network device driver: Main entry point
* Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
* Alejandro Lucero <alejandro.lucero@netronome.com>
* Jason McMullan <jason.mcmullan@netronome.com>
* Rolf Neugebauer <rolf.neugebauer@netronome.com>
*/
#include <linux/etherdevice.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/msi.h>
#include <linux/random.h>
#include "nfpcore/nfp.h"
#include "nfpcore/nfp_cpp.h"
#include "nfpcore/nfp_nffw.h"
#include "nfpcore/nfp_nsp_eth.h"
#include "nfpcore/nfp6000_pcie.h"
#include "nfp_net_ctrl.h"
#include "nfp_net.h"
#include "nfp_main.h"
#define NFP_PF_CSR_SLICE_SIZE (32 * 1024)
static int nfp_is_ready(struct nfp_cpp *cpp)
{
const char *cp;
long state;
int err;
cp = nfp_hwinfo_lookup(cpp, "board.state");
if (!cp)
return 0;
err = kstrtol(cp, 0, &state);
if (err < 0)
return 0;
return state == 15;
}
/**
* nfp_net_map_area() - Help function to map an area
* @cpp: NFP CPP handler
* @name: Name for the area
* @target: CPP target
* @addr: CPP address
* @size: Size of the area
* @area: Area handle (returned).
*
* This function is primarily to simplify the code in the main probe
* function. To undo the effect of this functions call
* @nfp_cpp_area_release_free(*area);
*
* Return: Pointer to memory mapped area or ERR_PTR
*/
static u8 __iomem *nfp_net_map_area(struct nfp_cpp *cpp,
const char *name, int isl, int target,
unsigned long long addr, unsigned long size,
struct nfp_cpp_area **area)
{
u8 __iomem *res;
u32 dest;
int err;
dest = NFP_CPP_ISLAND_ID(target, NFP_CPP_ACTION_RW, 0, isl);
*area = nfp_cpp_area_alloc_with_name(cpp, dest, name, addr, size);
if (!*area) {
err = -EIO;
goto err_area;
}
err = nfp_cpp_area_acquire(*area);
if (err < 0)
goto err_acquire;
res = nfp_cpp_area_iomem(*area);
if (!res) {
err = -EIO;
goto err_map;
}
return res;
err_map:
nfp_cpp_area_release(*area);
err_acquire:
nfp_cpp_area_free(*area);
err_area:
return (u8 __iomem *)ERR_PTR(err);
}
static void
nfp_net_get_mac_addr_hwinfo(struct nfp_net *nn, struct nfp_cpp *cpp,
unsigned int id)
{
u8 mac_addr[ETH_ALEN];
const char *mac_str;
char name[32];
snprintf(name, sizeof(name), "eth%d.mac", id);
mac_str = nfp_hwinfo_lookup(cpp, name);
if (!mac_str) {
dev_warn(&nn->pdev->dev,
"Can't lookup MAC address. Generate\n");
eth_hw_addr_random(nn->netdev);
return;
}
if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
&mac_addr[0], &mac_addr[1], &mac_addr[2],
&mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) {
dev_warn(&nn->pdev->dev,
"Can't parse MAC address (%s). Generate.\n", mac_str);
eth_hw_addr_random(nn->netdev);
return;
}
ether_addr_copy(nn->netdev->dev_addr, mac_addr);
ether_addr_copy(nn->netdev->perm_addr, mac_addr);
}
/**
* nfp_net_get_mac_addr() - Get the MAC address.
* @nn: NFP Network structure
* @pf: NFP PF device structure
* @id: NFP port id
*
* First try to get the MAC address from NSP ETH table. If that
* fails try HWInfo. As a last resort generate a random address.
*/
static void
nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_pf *pf, unsigned int id)
{
int i;
for (i = 0; pf->eth_tbl && i < pf->eth_tbl->count; i++)
if (pf->eth_tbl->ports[i].eth_index == id) {
const u8 *mac_addr = pf->eth_tbl->ports[i].mac_addr;
ether_addr_copy(nn->netdev->dev_addr, mac_addr);
ether_addr_copy(nn->netdev->perm_addr, mac_addr);
return;
}
nfp_net_get_mac_addr_hwinfo(nn, pf->cpp, id);
}
static unsigned int nfp_net_pf_get_num_ports(struct nfp_pf *pf)
{
char name[256];
u16 interface;
int pcie_pf;
int err = 0;
u64 val;
interface = nfp_cpp_interface(pf->cpp);
pcie_pf = NFP_CPP_INTERFACE_UNIT_of(interface);
snprintf(name, sizeof(name), "nfd_cfg_pf%d_num_ports", pcie_pf);
val = nfp_rtsym_read_le(pf->cpp, name, &err);
/* Default to one port */
if (err) {
if (err != -ENOENT)
nfp_err(pf->cpp, "Unable to read adapter port count\n");
val = 1;
}
return val;
}
static unsigned int
nfp_net_pf_total_qcs(struct nfp_pf *pf, void __iomem *ctrl_bar,
unsigned int stride, u32 start_off, u32 num_off)
{
unsigned int i, min_qc, max_qc;
min_qc = readl(ctrl_bar + start_off);
max_qc = min_qc;
for (i = 0; i < pf->num_ports; i++) {
/* To make our lives simpler only accept configuration where
* queues are allocated to PFs in order (queues of PFn all have
* indexes lower than PFn+1).
*/
if (max_qc > readl(ctrl_bar + start_off))
return 0;
max_qc = readl(ctrl_bar + start_off);
max_qc += readl(ctrl_bar + num_off) * stride;
ctrl_bar += NFP_PF_CSR_SLICE_SIZE;
}
return max_qc - min_qc;
}
static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf)
{
const struct nfp_rtsym *ctrl_sym;
u8 __iomem *ctrl_bar;
char pf_symbol[256];
u16 interface;
int pcie_pf;
interface = nfp_cpp_interface(pf->cpp);
pcie_pf = NFP_CPP_INTERFACE_UNIT_of(interface);
snprintf(pf_symbol, sizeof(pf_symbol), "_pf%d_net_bar0", pcie_pf);
ctrl_sym = nfp_rtsym_lookup(pf->cpp, pf_symbol);
if (!ctrl_sym) {
dev_err(&pf->pdev->dev,
"Failed to find PF BAR0 symbol %s\n", pf_symbol);
return NULL;
}
if (ctrl_sym->size < pf->num_ports * NFP_PF_CSR_SLICE_SIZE) {
dev_err(&pf->pdev->dev,
"PF BAR0 too small to contain %d ports\n",
pf->num_ports);
return NULL;
}
ctrl_bar = nfp_net_map_area(pf->cpp, "net.ctrl",
ctrl_sym->domain, ctrl_sym->target,
ctrl_sym->addr, ctrl_sym->size,
&pf->ctrl_area);
if (IS_ERR(ctrl_bar)) {
dev_err(&pf->pdev->dev, "Failed to map PF BAR0: %ld\n",
PTR_ERR(ctrl_bar));
return NULL;
}
return ctrl_bar;
}
static void nfp_net_pf_free_netdevs(struct nfp_pf *pf)
{
struct nfp_net *nn;
while (!list_empty(&pf->ports)) {
nn = list_first_entry(&pf->ports, struct nfp_net, port_list);
list_del(&nn->port_list);
nfp_net_netdev_free(nn);
}
}
static struct nfp_net *
nfp_net_pf_alloc_port_netdev(struct nfp_pf *pf, void __iomem *ctrl_bar,
void __iomem *tx_bar, void __iomem *rx_bar,
int stride, struct nfp_net_fw_version *fw_ver)
{
u32 n_tx_rings, n_rx_rings;
struct nfp_net *nn;
n_tx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_TXRINGS);
n_rx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_RXRINGS);
/* Allocate and initialise the netdev */
nn = nfp_net_netdev_alloc(pf->pdev, n_tx_rings, n_rx_rings);
if (IS_ERR(nn))
return nn;
nn->fw_ver = *fw_ver;
nn->ctrl_bar = ctrl_bar;
nn->tx_bar = tx_bar;
nn->rx_bar = rx_bar;
nn->is_vf = 0;
nn->stride_rx = stride;
nn->stride_tx = stride;
return nn;
}
static int
nfp_net_pf_init_port_netdev(struct nfp_pf *pf, struct nfp_net *nn,
unsigned int id)
{
int err;
/* Get MAC address */
nfp_net_get_mac_addr(nn, pf, id);
/* Get ME clock frequency from ctrl BAR
* XXX for now frequency is hardcoded until we figure out how
* to get the value from nfp-hwinfo into ctrl bar
*/
nn->me_freq_mhz = 1200;
err = nfp_net_netdev_init(nn->netdev);
if (err)
return err;
nfp_net_debugfs_port_add(nn, pf->ddir, id);
nfp_net_info(nn);
return 0;
}
static int
nfp_net_pf_alloc_netdevs(struct nfp_pf *pf, void __iomem *ctrl_bar,
void __iomem *tx_bar, void __iomem *rx_bar,
int stride, struct nfp_net_fw_version *fw_ver)
{
u32 prev_tx_base, prev_rx_base, tgt_tx_base, tgt_rx_base;
struct nfp_net *nn;
unsigned int i;
int err;
prev_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ);
prev_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ);
for (i = 0; i < pf->num_ports; i++) {
tgt_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ);
tgt_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ);
tx_bar += (tgt_tx_base - prev_tx_base) * NFP_QCP_QUEUE_ADDR_SZ;
rx_bar += (tgt_rx_base - prev_rx_base) * NFP_QCP_QUEUE_ADDR_SZ;
prev_tx_base = tgt_tx_base;
prev_rx_base = tgt_rx_base;
nn = nfp_net_pf_alloc_port_netdev(pf, ctrl_bar, tx_bar, rx_bar,
stride, fw_ver);
if (IS_ERR(nn)) {
err = PTR_ERR(nn);
goto err_free_prev;
}
list_add_tail(&nn->port_list, &pf->ports);
ctrl_bar += NFP_PF_CSR_SLICE_SIZE;
}
return 0;
err_free_prev:
nfp_net_pf_free_netdevs(pf);
return err;
}
static int
nfp_net_pf_spawn_netdevs(struct nfp_pf *pf,
void __iomem *ctrl_bar, void __iomem *tx_bar,
void __iomem *rx_bar, int stride,
struct nfp_net_fw_version *fw_ver)
{
unsigned int id, wanted_irqs, num_irqs, ports_left, irqs_left;
struct nfp_net *nn;
int err;
/* Allocate the netdevs and do basic init */
err = nfp_net_pf_alloc_netdevs(pf, ctrl_bar, tx_bar, rx_bar,
stride, fw_ver);
if (err)
return err;
/* Get MSI-X vectors */
wanted_irqs = 0;
list_for_each_entry(nn, &pf->ports, port_list)
wanted_irqs += NFP_NET_NON_Q_VECTORS + nn->num_r_vecs;
pf->irq_entries = kcalloc(wanted_irqs, sizeof(*pf->irq_entries),
GFP_KERNEL);
if (!pf->irq_entries) {
err = -ENOMEM;
goto err_nn_free;
}
num_irqs = nfp_net_irqs_alloc(pf->pdev, pf->irq_entries,
NFP_NET_MIN_PORT_IRQS * pf->num_ports,
wanted_irqs);
if (!num_irqs) {
nn_warn(nn, "Unable to allocate MSI-X Vectors. Exiting\n");
err = -ENOMEM;
goto err_vec_free;
}
/* Distribute IRQs to ports */
irqs_left = num_irqs;
ports_left = pf->num_ports;
list_for_each_entry(nn, &pf->ports, port_list) {
unsigned int n;
n = DIV_ROUND_UP(irqs_left, ports_left);
nfp_net_irqs_assign(nn, &pf->irq_entries[num_irqs - irqs_left],
n);
irqs_left -= n;
ports_left--;
}
/* Finish netdev init and register */
id = 0;
list_for_each_entry(nn, &pf->ports, port_list) {
err = nfp_net_pf_init_port_netdev(pf, nn, id);
if (err)
goto err_prev_deinit;
id++;
}
return 0;
err_prev_deinit:
list_for_each_entry_continue_reverse(nn, &pf->ports, port_list) {
nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
nfp_net_netdev_clean(nn->netdev);
}
nfp_net_irqs_disable(pf->pdev);
err_vec_free:
kfree(pf->irq_entries);
err_nn_free:
nfp_net_pf_free_netdevs(pf);
return err;
}
/*
* PCI device functions
*/
int nfp_net_pci_probe(struct nfp_pf *pf)
{
u8 __iomem *ctrl_bar, *tx_bar, *rx_bar;
u32 total_tx_qcs, total_rx_qcs;
struct nfp_net_fw_version fw_ver;
u32 tx_area_sz, rx_area_sz;
u32 start_q;
int stride;
int err;
/* Verify that the board has completed initialization */
if (!nfp_is_ready(pf->cpp)) {
nfp_err(pf->cpp, "NFP is not ready for NIC operation.\n");
return -EINVAL;
}
pf->num_ports = nfp_net_pf_get_num_ports(pf);
ctrl_bar = nfp_net_pf_map_ctrl_bar(pf);
if (!ctrl_bar)
return pf->fw_loaded ? -EINVAL : -EPROBE_DEFER;
nfp_net_get_fw_version(&fw_ver, ctrl_bar);
if (fw_ver.resv || fw_ver.class != NFP_NET_CFG_VERSION_CLASS_GENERIC) {
nfp_err(pf->cpp, "Unknown Firmware ABI %d.%d.%d.%d\n",
fw_ver.resv, fw_ver.class, fw_ver.major, fw_ver.minor);
err = -EINVAL;
goto err_ctrl_unmap;
}
/* Determine stride */
if (nfp_net_fw_ver_eq(&fw_ver, 0, 0, 0, 1)) {
stride = 2;
nfp_warn(pf->cpp, "OBSOLETE Firmware detected - VF isolation not available\n");
} else {
switch (fw_ver.major) {
case 1 ... 4:
stride = 4;
break;
default:
nfp_err(pf->cpp, "Unsupported Firmware ABI %d.%d.%d.%d\n",
fw_ver.resv, fw_ver.class,
fw_ver.major, fw_ver.minor);
err = -EINVAL;
goto err_ctrl_unmap;
}
}
/* Find how many QC structs need to be mapped */
total_tx_qcs = nfp_net_pf_total_qcs(pf, ctrl_bar, stride,
NFP_NET_CFG_START_TXQ,
NFP_NET_CFG_MAX_TXRINGS);
total_rx_qcs = nfp_net_pf_total_qcs(pf, ctrl_bar, stride,
NFP_NET_CFG_START_RXQ,
NFP_NET_CFG_MAX_RXRINGS);
if (!total_tx_qcs || !total_rx_qcs) {
nfp_err(pf->cpp, "Invalid PF QC configuration [%d,%d]\n",
total_tx_qcs, total_rx_qcs);
err = -EINVAL;
goto err_ctrl_unmap;
}
tx_area_sz = NFP_QCP_QUEUE_ADDR_SZ * total_tx_qcs;
rx_area_sz = NFP_QCP_QUEUE_ADDR_SZ * total_rx_qcs;
/* Map TX queues */
start_q = readl(ctrl_bar + NFP_NET_CFG_START_TXQ);
tx_bar = nfp_net_map_area(pf->cpp, "net.tx", 0, 0,
NFP_PCIE_QUEUE(start_q),
tx_area_sz, &pf->tx_area);
if (IS_ERR(tx_bar)) {
nfp_err(pf->cpp, "Failed to map TX area.\n");
err = PTR_ERR(tx_bar);
goto err_ctrl_unmap;
}
/* Map RX queues */
start_q = readl(ctrl_bar + NFP_NET_CFG_START_RXQ);
rx_bar = nfp_net_map_area(pf->cpp, "net.rx", 0, 0,
NFP_PCIE_QUEUE(start_q),
rx_area_sz, &pf->rx_area);
if (IS_ERR(rx_bar)) {
nfp_err(pf->cpp, "Failed to map RX area.\n");
err = PTR_ERR(rx_bar);
goto err_unmap_tx;
}
pf->ddir = nfp_net_debugfs_device_add(pf->pdev);
err = nfp_net_pf_spawn_netdevs(pf, ctrl_bar, tx_bar, rx_bar,
stride, &fw_ver);
if (err)
goto err_clean_ddir;
return 0;
err_clean_ddir:
nfp_net_debugfs_dir_clean(&pf->ddir);
nfp_cpp_area_release_free(pf->rx_area);
err_unmap_tx:
nfp_cpp_area_release_free(pf->tx_area);
err_ctrl_unmap:
nfp_cpp_area_release_free(pf->ctrl_area);
return err;
}
void nfp_net_pci_remove(struct nfp_pf *pf)
{
struct nfp_net *nn;
list_for_each_entry(nn, &pf->ports, port_list) {
nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
nfp_net_netdev_clean(nn->netdev);
}
nfp_net_pf_free_netdevs(pf);
nfp_net_debugfs_dir_clean(&pf->ddir);
nfp_net_irqs_disable(pf->pdev);
kfree(pf->irq_entries);
nfp_cpp_area_release_free(pf->rx_area);
nfp_cpp_area_release_free(pf->tx_area);
nfp_cpp_area_release_free(pf->ctrl_area);
}
/*
* Copyright (C) 2015 Netronome Systems, Inc.
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
......@@ -45,9 +45,27 @@
#include "nfp_net_ctrl.h"
#include "nfp_net.h"
#include "nfp_main.h"
/**
* struct nfp_net_vf - NFP VF-specific device structure
* @nn: NFP Net structure for this device
* @irq_entries: Pre-allocated array of MSI-X entries
* @q_bar: Pointer to mapped QC memory (NULL if TX/RX mapped directly)
* @ddir: Per-device debugfs directory
*/
struct nfp_net_vf {
struct nfp_net *nn;
struct msix_entry irq_entries[NFP_NET_NON_Q_VECTORS +
NFP_NET_MAX_TX_RINGS];
u8 __iomem *q_bar;
struct dentry *ddir;
};
static const char nfp_net_driver_name[] = "nfp_netvf";
const char nfp_net_driver_name[] = "nfp_netvf";
const char nfp_net_driver_version[] = "0.1";
#define PCI_DEVICE_NFP6000VF 0x6003
static const struct pci_device_id nfp_netvf_pci_device_ids[] = {
{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_NFP6000VF,
......@@ -82,15 +100,22 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
u32 tx_bar_off, rx_bar_off;
u32 tx_bar_sz, rx_bar_sz;
int tx_bar_no, rx_bar_no;
struct nfp_net_vf *vf;
unsigned int num_irqs;
u8 __iomem *ctrl_bar;
struct nfp_net *nn;
u32 startq;
int stride;
int err;
vf = kzalloc(sizeof(*vf), GFP_KERNEL);
if (!vf)
return -ENOMEM;
pci_set_drvdata(pdev, vf);
err = pci_enable_device_mem(pdev);
if (err)
return err;
goto err_free_vf;
err = pci_request_regions(pdev, nfp_net_driver_name);
if (err) {
......@@ -182,6 +207,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
err = PTR_ERR(nn);
goto err_ctrl_unmap;
}
vf->nn = nn;
nn->fw_ver = fw_ver;
nn->ctrl_bar = ctrl_bar;
......@@ -205,17 +231,17 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
bar_sz = (rx_bar_off + rx_bar_sz) - bar_off;
map_addr = pci_resource_start(pdev, tx_bar_no) + bar_off;
nn->q_bar = ioremap_nocache(map_addr, bar_sz);
if (!nn->q_bar) {
vf->q_bar = ioremap_nocache(map_addr, bar_sz);
if (!vf->q_bar) {
nn_err(nn, "Failed to map resource %d\n", tx_bar_no);
err = -EIO;
goto err_netdev_free;
}
/* TX queues */
nn->tx_bar = nn->q_bar + (tx_bar_off - bar_off);
nn->tx_bar = vf->q_bar + (tx_bar_off - bar_off);
/* RX queues */
nn->rx_bar = nn->q_bar + (rx_bar_off - bar_off);
nn->rx_bar = vf->q_bar + (rx_bar_off - bar_off);
} else {
resource_size_t map_addr;
......@@ -240,12 +266,15 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
nfp_netvf_get_mac_addr(nn);
err = nfp_net_irqs_alloc(nn);
if (!err) {
num_irqs = nfp_net_irqs_alloc(pdev, vf->irq_entries,
NFP_NET_MIN_PORT_IRQS,
NFP_NET_NON_Q_VECTORS + nn->num_r_vecs);
if (!num_irqs) {
nn_warn(nn, "Unable to allocate MSI-X Vectors. Exiting\n");
err = -EIO;
goto err_unmap_rx;
}
nfp_net_irqs_assign(nn, vf->irq_entries, num_irqs);
/* Get ME clock frequency from ctrl BAR
* XXX for now frequency is hardcoded until we figure out how
......@@ -257,25 +286,23 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
if (err)
goto err_irqs_disable;
pci_set_drvdata(pdev, nn);
nfp_net_info(nn);
nfp_net_debugfs_adapter_add(nn);
vf->ddir = nfp_net_debugfs_device_add(pdev);
nfp_net_debugfs_port_add(nn, vf->ddir, 0);
return 0;
err_irqs_disable:
nfp_net_irqs_disable(nn);
nfp_net_irqs_disable(pdev);
err_unmap_rx:
if (!nn->q_bar)
if (!vf->q_bar)
iounmap(nn->rx_bar);
err_unmap_tx:
if (!nn->q_bar)
if (!vf->q_bar)
iounmap(nn->tx_bar);
else
iounmap(nn->q_bar);
iounmap(vf->q_bar);
err_netdev_free:
pci_set_drvdata(pdev, NULL);
nfp_net_netdev_free(nn);
err_ctrl_unmap:
iounmap(ctrl_bar);
......@@ -283,71 +310,47 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
pci_release_regions(pdev);
err_pci_disable:
pci_disable_device(pdev);
err_free_vf:
pci_set_drvdata(pdev, NULL);
kfree(vf);
return err;
}
static void nfp_netvf_pci_remove(struct pci_dev *pdev)
{
struct nfp_net *nn = pci_get_drvdata(pdev);
struct nfp_net_vf *vf = pci_get_drvdata(pdev);
struct nfp_net *nn = vf->nn;
/* Note, the order is slightly different from above as we need
* to keep the nn pointer around till we have freed everything.
*/
nfp_net_debugfs_adapter_del(nn);
nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
nfp_net_debugfs_dir_clean(&vf->ddir);
nfp_net_netdev_clean(nn->netdev);
nfp_net_irqs_disable(nn);
nfp_net_irqs_disable(pdev);
if (!nn->q_bar) {
if (!vf->q_bar) {
iounmap(nn->rx_bar);
iounmap(nn->tx_bar);
} else {
iounmap(nn->q_bar);
iounmap(vf->q_bar);
}
iounmap(nn->ctrl_bar);
pci_set_drvdata(pdev, NULL);
nfp_net_netdev_free(nn);
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
kfree(vf);
}
static struct pci_driver nfp_netvf_pci_driver = {
struct pci_driver nfp_netvf_pci_driver = {
.name = nfp_net_driver_name,
.id_table = nfp_netvf_pci_device_ids,
.probe = nfp_netvf_pci_probe,
.remove = nfp_netvf_pci_remove,
};
static int __init nfp_netvf_init(void)
{
int err;
pr_info("%s: NFP VF Network driver, Copyright (C) 2014-2015 Netronome Systems\n",
nfp_net_driver_name);
nfp_net_debugfs_create();
err = pci_register_driver(&nfp_netvf_pci_driver);
if (err) {
nfp_net_debugfs_destroy();
return err;
}
return 0;
}
static void __exit nfp_netvf_exit(void)
{
pci_unregister_driver(&nfp_netvf_pci_driver);
nfp_net_debugfs_destroy();
}
module_init(nfp_netvf_init);
module_exit(nfp_netvf_exit);
MODULE_AUTHOR("Netronome Systems <oss-drivers@netronome.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("NFP VF network device driver");
/*
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef NFP_CRC32_H
#define NFP_CRC32_H
#include <linux/kernel.h>
#include <linux/crc32.h>
/**
* crc32_posix_end() - Finalize POSIX CRC32 working state
* @crc: Current CRC32 working state
* @total_len: Total length of data that was CRC32'd
*
* Return: Final POSIX CRC32 value
*/
static inline u32 crc32_posix_end(u32 crc, size_t total_len)
{
/* Extend with the length of the string. */
while (total_len != 0) {
u8 c = total_len & 0xff;
crc = crc32_be(crc, &c, 1);
total_len >>= 8;
}
return ~crc;
}
static inline u32 crc32_posix(const void *buff, size_t len)
{
return crc32_posix_end(crc32_be(0, buff, len), len);
}
#endif /* NFP_CRC32_H */
/*
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* nfp.h
* Interface for NFP device access and query functions.
*/
#ifndef __NFP_H__
#define __NFP_H__
#include <linux/device.h>
#include "nfp_cpp.h"
/* Implemented in nfp_hwinfo.c */
const char *nfp_hwinfo_lookup(struct nfp_cpp *cpp, const char *lookup);
/* Implemented in nfp_nsp.c */
struct nfp_nsp;
struct firmware;
struct nfp_nsp *nfp_nsp_open(struct nfp_cpp *cpp);
void nfp_nsp_close(struct nfp_nsp *state);
int nfp_nsp_wait(struct nfp_nsp *state);
int nfp_nsp_device_soft_reset(struct nfp_nsp *state);
int nfp_nsp_load_fw(struct nfp_nsp *state, const struct firmware *fw);
int nfp_nsp_read_eth_table(struct nfp_nsp *state, void *buf, unsigned int size);
int nfp_nsp_write_eth_table(struct nfp_nsp *state,
const void *buf, unsigned int size);
/* Implemented in nfp_resource.c */
#define NFP_RESOURCE_TBL_TARGET NFP_CPP_TARGET_MU
#define NFP_RESOURCE_TBL_BASE 0x8100000000ULL
/* NFP Resource Table self-identifier */
#define NFP_RESOURCE_TBL_NAME "nfp.res"
#define NFP_RESOURCE_TBL_KEY 0x00000000 /* Special key for entry 0 */
/* All other keys are CRC32-POSIX of the 8-byte identification string */
/* ARM/PCI vNIC Interfaces 0..3 */
#define NFP_RESOURCE_VNIC_PCI_0 "vnic.p0"
#define NFP_RESOURCE_VNIC_PCI_1 "vnic.p1"
#define NFP_RESOURCE_VNIC_PCI_2 "vnic.p2"
#define NFP_RESOURCE_VNIC_PCI_3 "vnic.p3"
/* NFP Hardware Info Database */
#define NFP_RESOURCE_NFP_HWINFO "nfp.info"
/* Service Processor */
#define NFP_RESOURCE_NSP "nfp.sp"
/* Netronone Flow Firmware Table */
#define NFP_RESOURCE_NFP_NFFW "nfp.nffw"
/* MAC Statistics Accumulator */
#define NFP_RESOURCE_MAC_STATISTICS "mac.stat"
struct nfp_resource *
nfp_resource_acquire(struct nfp_cpp *cpp, const char *name);
void nfp_resource_release(struct nfp_resource *res);
u32 nfp_resource_cpp_id(struct nfp_resource *res);
const char *nfp_resource_name(struct nfp_resource *res);
u64 nfp_resource_address(struct nfp_resource *res);
u64 nfp_resource_size(struct nfp_resource *res);
#endif /* !__NFP_H__ */
/*
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef NFP6000_NFP6000_H
#define NFP6000_NFP6000_H
#include <linux/errno.h>
#include <linux/types.h>
/* CPP Target IDs */
#define NFP_CPP_TARGET_INVALID 0
#define NFP_CPP_TARGET_NBI 1
#define NFP_CPP_TARGET_QDR 2
#define NFP_CPP_TARGET_ILA 6
#define NFP_CPP_TARGET_MU 7
#define NFP_CPP_TARGET_PCIE 9
#define NFP_CPP_TARGET_ARM 10
#define NFP_CPP_TARGET_CRYPTO 12
#define NFP_CPP_TARGET_ISLAND_XPB 14 /* Shared with CAP */
#define NFP_CPP_TARGET_ISLAND_CAP 14 /* Shared with XPB */
#define NFP_CPP_TARGET_CT_XPB 14
#define NFP_CPP_TARGET_LOCAL_SCRATCH 15
#define NFP_CPP_TARGET_CLS NFP_CPP_TARGET_LOCAL_SCRATCH
#define NFP_ISL_EMEM0 24
#define NFP_MU_ADDR_ACCESS_TYPE_MASK 3ULL
#define NFP_MU_ADDR_ACCESS_TYPE_DIRECT 2ULL
#define PUSHPULL(_pull, _push) ((_pull) << 4 | (_push) << 0)
#define PUSH_WIDTH(_pushpull) pushpull_width((_pushpull) >> 0)
#define PULL_WIDTH(_pushpull) pushpull_width((_pushpull) >> 4)
static inline int pushpull_width(int pp)
{
pp &= 0xf;
if (pp == 0)
return -EINVAL;
return 2 << pp;
}
static inline int nfp_cppat_mu_locality_lsb(int mode, bool addr40)
{
switch (mode) {
case 0 ... 3:
return addr40 ? 38 : 30;
default:
return -EINVAL;
}
}
int nfp_target_pushpull(u32 cpp_id, u64 address);
int nfp_target_cpp(u32 cpp_island_id, u64 cpp_island_address,
u32 *cpp_target_id, u64 *cpp_target_address,
const u32 *imb_table);
#endif /* NFP6000_NFP6000_H */
/*
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* nfp_xpb.h
* Author: Jason McMullan <jason.mcmullan@netronome.com>
*/
#ifndef NFP6000_XPB_H
#define NFP6000_XPB_H
/* For use with NFP6000 Databook "XPB Addressing" section
*/
#define NFP_XPB_OVERLAY(island) (((island) & 0x3f) << 24)
#define NFP_XPB_ISLAND(island) (NFP_XPB_OVERLAY(island) + 0x60000)
#define NFP_XPB_ISLAND_of(offset) (((offset) >> 24) & 0x3F)
/* For use with NFP6000 Databook "XPB Island and Device IDs" chapter
*/
#define NFP_XPB_DEVICE(island, slave, device) \
(NFP_XPB_OVERLAY(island) | \
(((slave) & 3) << 22) | \
(((device) & 0x3f) << 16))
#endif /* NFP6000_XPB_H */
/*
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* nfp6000_pcie.h
* Author: Jason McMullan <jason.mcmullan@netronome.com>
*/
#ifndef NFP6000_PCIE_H
#define NFP6000_PCIE_H
#include "nfp_cpp.h"
struct nfp_cpp *nfp_cpp_from_nfp6000_pcie(struct pci_dev *pdev);
#endif /* NFP6000_PCIE_H */
/*
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* nfp_arm.h
* Definitions for ARM-based registers and memory spaces
*/
#ifndef NFP_ARM_H
#define NFP_ARM_H
#define NFP_ARM_QUEUE(_q) (0x100000 + (0x800 * ((_q) & 0xff)))
#define NFP_ARM_IM 0x200000
#define NFP_ARM_EM 0x300000
#define NFP_ARM_GCSR 0x400000
#define NFP_ARM_MPCORE 0x800000
#define NFP_ARM_PL310 0xa00000
/* Register Type: BulkBARConfig */
#define NFP_ARM_GCSR_BULK_BAR(_bar) (0x0 + (0x4 * ((_bar) & 0x7)))
#define NFP_ARM_GCSR_BULK_BAR_TYPE (0x1 << 31)
#define NFP_ARM_GCSR_BULK_BAR_TYPE_BULK (0x0)
#define NFP_ARM_GCSR_BULK_BAR_TYPE_EXPA (0x80000000)
#define NFP_ARM_GCSR_BULK_BAR_TGT(_x) (((_x) & 0xf) << 27)
#define NFP_ARM_GCSR_BULK_BAR_TGT_of(_x) (((_x) >> 27) & 0xf)
#define NFP_ARM_GCSR_BULK_BAR_TOK(_x) (((_x) & 0x3) << 25)
#define NFP_ARM_GCSR_BULK_BAR_TOK_of(_x) (((_x) >> 25) & 0x3)
#define NFP_ARM_GCSR_BULK_BAR_LEN (0x1 << 24)
#define NFP_ARM_GCSR_BULK_BAR_LEN_32BIT (0x0)
#define NFP_ARM_GCSR_BULK_BAR_LEN_64BIT (0x1000000)
#define NFP_ARM_GCSR_BULK_BAR_ADDR(_x) ((_x) & 0x7ff)
#define NFP_ARM_GCSR_BULK_BAR_ADDR_of(_x) ((_x) & 0x7ff)
/* Register Type: ExpansionBARConfig */
#define NFP_ARM_GCSR_EXPA_BAR(_bar) (0x20 + (0x4 * ((_bar) & 0xf)))
#define NFP_ARM_GCSR_EXPA_BAR_TYPE (0x1 << 31)
#define NFP_ARM_GCSR_EXPA_BAR_TYPE_EXPA (0x0)
#define NFP_ARM_GCSR_EXPA_BAR_TYPE_EXPL (0x80000000)
#define NFP_ARM_GCSR_EXPA_BAR_TGT(_x) (((_x) & 0xf) << 27)
#define NFP_ARM_GCSR_EXPA_BAR_TGT_of(_x) (((_x) >> 27) & 0xf)
#define NFP_ARM_GCSR_EXPA_BAR_TOK(_x) (((_x) & 0x3) << 25)
#define NFP_ARM_GCSR_EXPA_BAR_TOK_of(_x) (((_x) >> 25) & 0x3)
#define NFP_ARM_GCSR_EXPA_BAR_LEN (0x1 << 24)
#define NFP_ARM_GCSR_EXPA_BAR_LEN_32BIT (0x0)
#define NFP_ARM_GCSR_EXPA_BAR_LEN_64BIT (0x1000000)
#define NFP_ARM_GCSR_EXPA_BAR_ACT(_x) (((_x) & 0x1f) << 19)
#define NFP_ARM_GCSR_EXPA_BAR_ACT_of(_x) (((_x) >> 19) & 0x1f)
#define NFP_ARM_GCSR_EXPA_BAR_ACT_DERIVED (0)
#define NFP_ARM_GCSR_EXPA_BAR_ADDR(_x) ((_x) & 0x7fff)
#define NFP_ARM_GCSR_EXPA_BAR_ADDR_of(_x) ((_x) & 0x7fff)
/* Register Type: ExplicitBARConfig0_Reg */
#define NFP_ARM_GCSR_EXPL0_BAR(_bar) (0x60 + (0x4 * ((_bar) & 0x7)))
#define NFP_ARM_GCSR_EXPL0_BAR_ADDR(_x) ((_x) & 0x3ffff)
#define NFP_ARM_GCSR_EXPL0_BAR_ADDR_of(_x) ((_x) & 0x3ffff)
/* Register Type: ExplicitBARConfig1_Reg */
#define NFP_ARM_GCSR_EXPL1_BAR(_bar) (0x80 + (0x4 * ((_bar) & 0x7)))
#define NFP_ARM_GCSR_EXPL1_BAR_POSTED (0x1 << 31)
#define NFP_ARM_GCSR_EXPL1_BAR_SIGNAL_REF(_x) (((_x) & 0x7f) << 24)
#define NFP_ARM_GCSR_EXPL1_BAR_SIGNAL_REF_of(_x) (((_x) >> 24) & 0x7f)
#define NFP_ARM_GCSR_EXPL1_BAR_DATA_MASTER(_x) (((_x) & 0xff) << 16)
#define NFP_ARM_GCSR_EXPL1_BAR_DATA_MASTER_of(_x) (((_x) >> 16) & 0xff)
#define NFP_ARM_GCSR_EXPL1_BAR_DATA_REF(_x) ((_x) & 0x3fff)
#define NFP_ARM_GCSR_EXPL1_BAR_DATA_REF_of(_x) ((_x) & 0x3fff)
/* Register Type: ExplicitBARConfig2_Reg */
#define NFP_ARM_GCSR_EXPL2_BAR(_bar) (0xa0 + (0x4 * ((_bar) & 0x7)))
#define NFP_ARM_GCSR_EXPL2_BAR_TGT(_x) (((_x) & 0xf) << 28)
#define NFP_ARM_GCSR_EXPL2_BAR_TGT_of(_x) (((_x) >> 28) & 0xf)
#define NFP_ARM_GCSR_EXPL2_BAR_ACT(_x) (((_x) & 0x1f) << 23)
#define NFP_ARM_GCSR_EXPL2_BAR_ACT_of(_x) (((_x) >> 23) & 0x1f)
#define NFP_ARM_GCSR_EXPL2_BAR_LEN(_x) (((_x) & 0x1f) << 18)
#define NFP_ARM_GCSR_EXPL2_BAR_LEN_of(_x) (((_x) >> 18) & 0x1f)
#define NFP_ARM_GCSR_EXPL2_BAR_BYTE_MASK(_x) (((_x) & 0xff) << 10)
#define NFP_ARM_GCSR_EXPL2_BAR_BYTE_MASK_of(_x) (((_x) >> 10) & 0xff)
#define NFP_ARM_GCSR_EXPL2_BAR_TOK(_x) (((_x) & 0x3) << 8)
#define NFP_ARM_GCSR_EXPL2_BAR_TOK_of(_x) (((_x) >> 8) & 0x3)
#define NFP_ARM_GCSR_EXPL2_BAR_SIGNAL_MASTER(_x) ((_x) & 0xff)
#define NFP_ARM_GCSR_EXPL2_BAR_SIGNAL_MASTER_of(_x) ((_x) & 0xff)
/* Register Type: PostedCommandSignal */
#define NFP_ARM_GCSR_EXPL_POST(_bar) (0xc0 + (0x4 * ((_bar) & 0x7)))
#define NFP_ARM_GCSR_EXPL_POST_SIG_B(_x) (((_x) & 0x7f) << 25)
#define NFP_ARM_GCSR_EXPL_POST_SIG_B_of(_x) (((_x) >> 25) & 0x7f)
#define NFP_ARM_GCSR_EXPL_POST_SIG_B_BUS (0x1 << 24)
#define NFP_ARM_GCSR_EXPL_POST_SIG_B_BUS_PULL (0x0)
#define NFP_ARM_GCSR_EXPL_POST_SIG_B_BUS_PUSH (0x1000000)
#define NFP_ARM_GCSR_EXPL_POST_SIG_A(_x) (((_x) & 0x7f) << 17)
#define NFP_ARM_GCSR_EXPL_POST_SIG_A_of(_x) (((_x) >> 17) & 0x7f)
#define NFP_ARM_GCSR_EXPL_POST_SIG_A_BUS (0x1 << 16)
#define NFP_ARM_GCSR_EXPL_POST_SIG_A_BUS_PULL (0x0)
#define NFP_ARM_GCSR_EXPL_POST_SIG_A_BUS_PUSH (0x10000)
#define NFP_ARM_GCSR_EXPL_POST_SIG_B_RCVD (0x1 << 7)
#define NFP_ARM_GCSR_EXPL_POST_SIG_B_VALID (0x1 << 6)
#define NFP_ARM_GCSR_EXPL_POST_SIG_A_RCVD (0x1 << 5)
#define NFP_ARM_GCSR_EXPL_POST_SIG_A_VALID (0x1 << 4)
#define NFP_ARM_GCSR_EXPL_POST_CMD_COMPLETE (0x1)
/* Register Type: MPCoreBaseAddress */
#define NFP_ARM_GCSR_MPCORE_BASE 0x00e0
#define NFP_ARM_GCSR_MPCORE_BASE_ADDR(_x) (((_x) & 0x7ffff) << 13)
#define NFP_ARM_GCSR_MPCORE_BASE_ADDR_of(_x) (((_x) >> 13) & 0x7ffff)
/* Register Type: PL310BaseAddress */
#define NFP_ARM_GCSR_PL310_BASE 0x00e4
#define NFP_ARM_GCSR_PL310_BASE_ADDR(_x) (((_x) & 0xfffff) << 12)
#define NFP_ARM_GCSR_PL310_BASE_ADDR_of(_x) (((_x) >> 12) & 0xfffff)
/* Register Type: MPCoreConfig */
#define NFP_ARM_GCSR_MP0_CFG 0x00e8
#define NFP_ARM_GCSR_MP0_CFG_SPI_BOOT (0x1 << 14)
#define NFP_ARM_GCSR_MP0_CFG_ENDIAN(_x) (((_x) & 0x3) << 12)
#define NFP_ARM_GCSR_MP0_CFG_ENDIAN_of(_x) (((_x) >> 12) & 0x3)
#define NFP_ARM_GCSR_MP0_CFG_ENDIAN_LITTLE (0)
#define NFP_ARM_GCSR_MP0_CFG_ENDIAN_BIG (1)
#define NFP_ARM_GCSR_MP0_CFG_RESET_VECTOR (0x1 << 8)
#define NFP_ARM_GCSR_MP0_CFG_RESET_VECTOR_LO (0x0)
#define NFP_ARM_GCSR_MP0_CFG_RESET_VECTOR_HI (0x100)
#define NFP_ARM_GCSR_MP0_CFG_OUTCLK_EN(_x) (((_x) & 0xf) << 4)
#define NFP_ARM_GCSR_MP0_CFG_OUTCLK_EN_of(_x) (((_x) >> 4) & 0xf)
#define NFP_ARM_GCSR_MP0_CFG_ARMID(_x) ((_x) & 0xf)
#define NFP_ARM_GCSR_MP0_CFG_ARMID_of(_x) ((_x) & 0xf)
/* Register Type: MPCoreIDCacheDataError */
#define NFP_ARM_GCSR_MP0_CACHE_ERR 0x00ec
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_D7 (0x1 << 15)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_D6 (0x1 << 14)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_D5 (0x1 << 13)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_D4 (0x1 << 12)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_D3 (0x1 << 11)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_D2 (0x1 << 10)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_D1 (0x1 << 9)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_D0 (0x1 << 8)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_I7 (0x1 << 7)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_I6 (0x1 << 6)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_I5 (0x1 << 5)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_I4 (0x1 << 4)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_I3 (0x1 << 3)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_I2 (0x1 << 2)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_I1 (0x1 << 1)
#define NFP_ARM_GCSR_MP0_CACHE_ERR_MP0_I0 (0x1)
/* Register Type: ARMDFT */
#define NFP_ARM_GCSR_DFT 0x0100
#define NFP_ARM_GCSR_DFT_DBG_REQ (0x1 << 20)
#define NFP_ARM_GCSR_DFT_DBG_EN (0x1 << 19)
#define NFP_ARM_GCSR_DFT_WFE_EVT_TRG (0x1 << 18)
#define NFP_ARM_GCSR_DFT_ETM_WFI_RDY (0x1 << 17)
#define NFP_ARM_GCSR_DFT_ETM_PWR_ON (0x1 << 16)
#define NFP_ARM_GCSR_DFT_BIST_FAIL_of(_x) (((_x) >> 8) & 0xf)
#define NFP_ARM_GCSR_DFT_BIST_DONE_of(_x) (((_x) >> 4) & 0xf)
#define NFP_ARM_GCSR_DFT_BIST_RUN(_x) ((_x) & 0x7)
#define NFP_ARM_GCSR_DFT_BIST_RUN_of(_x) ((_x) & 0x7)
/* Gasket CSRs */
/* NOTE: These cannot be remapped, and are always at this location.
*/
#define NFP_ARM_GCSR_START (0xd6000000 + NFP_ARM_GCSR)
#define NFP_ARM_GCSR_SIZE SZ_64K
/* BAR CSRs
*/
#define NFP_ARM_GCSR_BULK_BITS 11
#define NFP_ARM_GCSR_EXPA_BITS 15
#define NFP_ARM_GCSR_EXPL_BITS 18
#define NFP_ARM_GCSR_BULK_SHIFT (40 - 11)
#define NFP_ARM_GCSR_EXPA_SHIFT (40 - 15)
#define NFP_ARM_GCSR_EXPL_SHIFT (40 - 18)
#define NFP_ARM_GCSR_BULK_SIZE (1 << NFP_ARM_GCSR_BULK_SHIFT)
#define NFP_ARM_GCSR_EXPA_SIZE (1 << NFP_ARM_GCSR_EXPA_SHIFT)
#define NFP_ARM_GCSR_EXPL_SIZE (1 << NFP_ARM_GCSR_EXPL_SHIFT)
#define NFP_ARM_GCSR_EXPL2_CSR(target, action, length, \
byte_mask, token, signal_master) \
(NFP_ARM_GCSR_EXPL2_BAR_TGT(target) | \
NFP_ARM_GCSR_EXPL2_BAR_ACT(action) | \
NFP_ARM_GCSR_EXPL2_BAR_LEN(length) | \
NFP_ARM_GCSR_EXPL2_BAR_BYTE_MASK(byte_mask) | \
NFP_ARM_GCSR_EXPL2_BAR_TOK(token) | \
NFP_ARM_GCSR_EXPL2_BAR_SIGNAL_MASTER(signal_master))
#define NFP_ARM_GCSR_EXPL1_CSR(posted, signal_ref, data_master, data_ref) \
(((posted) ? NFP_ARM_GCSR_EXPL1_BAR_POSTED : 0) | \
NFP_ARM_GCSR_EXPL1_BAR_SIGNAL_REF(signal_ref) | \
NFP_ARM_GCSR_EXPL1_BAR_DATA_MASTER(data_master) | \
NFP_ARM_GCSR_EXPL1_BAR_DATA_REF(data_ref))
#define NFP_ARM_GCSR_EXPL0_CSR(address) \
NFP_ARM_GCSR_EXPL0_BAR_ADDR((address) >> NFP_ARM_GCSR_EXPL_SHIFT)
#define NFP_ARM_GCSR_EXPL_POST_EXPECT_A(sig_ref, is_push, is_required) \
(NFP_ARM_GCSR_EXPL_POST_SIG_A(sig_ref) | \
((is_push) ? NFP_ARM_GCSR_EXPL_POST_SIG_A_BUS_PUSH : \
NFP_ARM_GCSR_EXPL_POST_SIG_A_BUS_PULL) | \
((is_required) ? NFP_ARM_GCSR_EXPL_POST_SIG_A_VALID : 0))
#define NFP_ARM_GCSR_EXPL_POST_EXPECT_B(sig_ref, is_push, is_required) \
(NFP_ARM_GCSR_EXPL_POST_SIG_B(sig_ref) | \
((is_push) ? NFP_ARM_GCSR_EXPL_POST_SIG_B_BUS_PUSH : \
NFP_ARM_GCSR_EXPL_POST_SIG_B_BUS_PULL) | \
((is_required) ? NFP_ARM_GCSR_EXPL_POST_SIG_B_VALID : 0))
#define NFP_ARM_GCSR_EXPA_CSR(mode, target, token, is_64, action, address) \
(((mode) ? NFP_ARM_GCSR_EXPA_BAR_TYPE_EXPL : \
NFP_ARM_GCSR_EXPA_BAR_TYPE_EXPA) | \
NFP_ARM_GCSR_EXPA_BAR_TGT(target) | \
NFP_ARM_GCSR_EXPA_BAR_TOK(token) | \
((is_64) ? NFP_ARM_GCSR_EXPA_BAR_LEN_64BIT : \
NFP_ARM_GCSR_EXPA_BAR_LEN_32BIT) | \
NFP_ARM_GCSR_EXPA_BAR_ACT(action) | \
NFP_ARM_GCSR_EXPA_BAR_ADDR((address) >> NFP_ARM_GCSR_EXPA_SHIFT))
#define NFP_ARM_GCSR_BULK_CSR(mode, target, token, is_64, address) \
(((mode) ? NFP_ARM_GCSR_BULK_BAR_TYPE_EXPA : \
NFP_ARM_GCSR_BULK_BAR_TYPE_BULK) | \
NFP_ARM_GCSR_BULK_BAR_TGT(target) | \
NFP_ARM_GCSR_BULK_BAR_TOK(token) | \
((is_64) ? NFP_ARM_GCSR_BULK_BAR_LEN_64BIT : \
NFP_ARM_GCSR_BULK_BAR_LEN_32BIT) | \
NFP_ARM_GCSR_BULK_BAR_ADDR((address) >> NFP_ARM_GCSR_BULK_SHIFT))
/* MP Core CSRs */
#define NFP_ARM_MPCORE_SIZE SZ_128K
/* PL320 CSRs */
#define NFP_ARM_PCSR_SIZE SZ_64K
#endif /* NFP_ARM_H */
/*
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* nfp_cpp.h
* Interface for low-level NFP CPP access.
* Authors: Jason McMullan <jason.mcmullan@netronome.com>
* Rolf Neugebauer <rolf.neugebauer@netronome.com>
*/
#ifndef __NFP_CPP_H__
#define __NFP_CPP_H__
#include <linux/ctype.h>
#include <linux/types.h>
#ifndef NFP_SUBSYS
#define NFP_SUBSYS "nfp"
#endif
#define nfp_err(cpp, fmt, args...) \
dev_err(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
#define nfp_warn(cpp, fmt, args...) \
dev_warn(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
#define nfp_info(cpp, fmt, args...) \
dev_info(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
#define nfp_dbg(cpp, fmt, args...) \
dev_dbg(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
#define PCI_64BIT_BAR_COUNT 3
/* NFP hardware vendor/device ids.
*/
#define PCI_DEVICE_NFP4000 0x4000
#define PCI_DEVICE_NFP6000 0x6000
#define NFP_CPP_NUM_TARGETS 16
struct device;
struct nfp_cpp_area;
struct nfp_cpp;
struct resource;
/* Wildcard indicating a CPP read or write action
*
* The action used will be either read or write depending on whether a
* read or write instruction/call is performed on the NFP_CPP_ID. It
* is recomended that the RW action is used even if all actions to be
* performed on a NFP_CPP_ID are known to be only reads or writes.
* Doing so will in many cases save NFP CPP internal software
* resources.
*/
#define NFP_CPP_ACTION_RW 32
#define NFP_CPP_TARGET_ID_MASK 0x1f
/**
* NFP_CPP_ID() - pack target, token, and action into a CPP ID.
* @target: NFP CPP target id
* @action: NFP CPP action id
* @token: NFP CPP token id
*
* Create a 32-bit CPP identifier representing the access to be made.
* These identifiers are used as parameters to other NFP CPP
* functions. Some CPP devices may allow wildcard identifiers to be
* specified.
*
* Return: NFP CPP ID
*/
#define NFP_CPP_ID(target, action, token) \
((((target) & 0x7f) << 24) | (((token) & 0xff) << 16) | \
(((action) & 0xff) << 8))
/**
* NFP_CPP_ISLAND_ID() - pack target, token, action, and island into a CPP ID.
* @target: NFP CPP target id
* @action: NFP CPP action id
* @token: NFP CPP token id
* @island: NFP CPP island id
*
* Create a 32-bit CPP identifier representing the access to be made.
* These identifiers are used as parameters to other NFP CPP
* functions. Some CPP devices may allow wildcard identifiers to be
* specified.
*
* Return: NFP CPP ID
*/
#define NFP_CPP_ISLAND_ID(target, action, token, island) \
((((target) & 0x7f) << 24) | (((token) & 0xff) << 16) | \
(((action) & 0xff) << 8) | (((island) & 0xff) << 0))
/**
* NFP_CPP_ID_TARGET_of() - Return the NFP CPP target of a NFP CPP ID
* @id: NFP CPP ID
*
* Return: NFP CPP target
*/
static inline u8 NFP_CPP_ID_TARGET_of(u32 id)
{
return (id >> 24) & NFP_CPP_TARGET_ID_MASK;
}
/**
* NFP_CPP_ID_TOKEN_of() - Return the NFP CPP token of a NFP CPP ID
* @id: NFP CPP ID
* Return: NFP CPP token
*/
static inline u8 NFP_CPP_ID_TOKEN_of(u32 id)
{
return (id >> 16) & 0xff;
}
/**
* NFP_CPP_ID_ACTION_of() - Return the NFP CPP action of a NFP CPP ID
* @id: NFP CPP ID
*
* Return: NFP CPP action
*/
static inline u8 NFP_CPP_ID_ACTION_of(u32 id)
{
return (id >> 8) & 0xff;
}
/**
* NFP_CPP_ID_ISLAND_of() - Return the NFP CPP island of a NFP CPP ID
* @id: NFP CPP ID
*
* Return: NFP CPP island
*/
static inline u8 NFP_CPP_ID_ISLAND_of(u32 id)
{
return (id >> 0) & 0xff;
}
/* NFP Interface types - logical interface for this CPP connection
* 4 bits are reserved for interface type.
*/
#define NFP_CPP_INTERFACE_TYPE_INVALID 0x0
#define NFP_CPP_INTERFACE_TYPE_PCI 0x1
#define NFP_CPP_INTERFACE_TYPE_ARM 0x2
#define NFP_CPP_INTERFACE_TYPE_RPC 0x3
#define NFP_CPP_INTERFACE_TYPE_ILA 0x4
/**
* NFP_CPP_INTERFACE() - Construct a 16-bit NFP Interface ID
* @type: NFP Interface Type
* @unit: Unit identifier for the interface type
* @channel: Channel identifier for the interface unit
*
* Interface IDs consists of 4 bits of interface type,
* 4 bits of unit identifier, and 8 bits of channel identifier.
*
* The NFP Interface ID is used in the implementation of
* NFP CPP API mutexes, which use the MU Atomic CompareAndWrite
* operation - hence the limit to 16 bits to be able to
* use the NFP Interface ID as a lock owner.
*
* Return: Interface ID
*/
#define NFP_CPP_INTERFACE(type, unit, channel) \
((((type) & 0xf) << 12) | \
(((unit) & 0xf) << 8) | \
(((channel) & 0xff) << 0))
/**
* NFP_CPP_INTERFACE_TYPE_of() - Get the interface type
* @interface: NFP Interface ID
* Return: NFP Interface ID's type
*/
#define NFP_CPP_INTERFACE_TYPE_of(interface) (((interface) >> 12) & 0xf)
/**
* NFP_CPP_INTERFACE_UNIT_of() - Get the interface unit
* @interface: NFP Interface ID
* Return: NFP Interface ID's unit
*/
#define NFP_CPP_INTERFACE_UNIT_of(interface) (((interface) >> 8) & 0xf)
/**
* NFP_CPP_INTERFACE_CHANNEL_of() - Get the interface channel
* @interface: NFP Interface ID
* Return: NFP Interface ID's channel
*/
#define NFP_CPP_INTERFACE_CHANNEL_of(interface) (((interface) >> 0) & 0xff)
/* Implemented in nfp_cppcore.c */
void nfp_cpp_free(struct nfp_cpp *cpp);
u32 nfp_cpp_model(struct nfp_cpp *cpp);
u16 nfp_cpp_interface(struct nfp_cpp *cpp);
int nfp_cpp_serial(struct nfp_cpp *cpp, const u8 **serial);
void *nfp_hwinfo_cache(struct nfp_cpp *cpp);
void nfp_hwinfo_cache_set(struct nfp_cpp *cpp, void *val);
void *nfp_rtsym_cache(struct nfp_cpp *cpp);
void nfp_rtsym_cache_set(struct nfp_cpp *cpp, void *val);
void nfp_nffw_cache_flush(struct nfp_cpp *cpp);
struct nfp_cpp_area *nfp_cpp_area_alloc_with_name(struct nfp_cpp *cpp,
u32 cpp_id,
const char *name,
unsigned long long address,
unsigned long size);
struct nfp_cpp_area *nfp_cpp_area_alloc(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address,
unsigned long size);
void nfp_cpp_area_free(struct nfp_cpp_area *area);
int nfp_cpp_area_acquire(struct nfp_cpp_area *area);
int nfp_cpp_area_acquire_nonblocking(struct nfp_cpp_area *area);
void nfp_cpp_area_release(struct nfp_cpp_area *area);
void nfp_cpp_area_release_free(struct nfp_cpp_area *area);
int nfp_cpp_area_read(struct nfp_cpp_area *area, unsigned long offset,
void *buffer, size_t length);
int nfp_cpp_area_write(struct nfp_cpp_area *area, unsigned long offset,
const void *buffer, size_t length);
int nfp_cpp_area_check_range(struct nfp_cpp_area *area,
unsigned long long offset, unsigned long size);
const char *nfp_cpp_area_name(struct nfp_cpp_area *cpp_area);
void *nfp_cpp_area_priv(struct nfp_cpp_area *cpp_area);
struct nfp_cpp *nfp_cpp_area_cpp(struct nfp_cpp_area *cpp_area);
struct resource *nfp_cpp_area_resource(struct nfp_cpp_area *area);
phys_addr_t nfp_cpp_area_phys(struct nfp_cpp_area *area);
void __iomem *nfp_cpp_area_iomem(struct nfp_cpp_area *area);
int nfp_cpp_area_readl(struct nfp_cpp_area *area, unsigned long offset,
u32 *value);
int nfp_cpp_area_writel(struct nfp_cpp_area *area, unsigned long offset,
u32 value);
int nfp_cpp_area_readq(struct nfp_cpp_area *area, unsigned long offset,
u64 *value);
int nfp_cpp_area_writeq(struct nfp_cpp_area *area, unsigned long offset,
u64 value);
int nfp_cpp_area_fill(struct nfp_cpp_area *area, unsigned long offset,
u32 value, size_t length);
int nfp_xpb_readl(struct nfp_cpp *cpp, u32 xpb_tgt, u32 *value);
int nfp_xpb_writel(struct nfp_cpp *cpp, u32 xpb_tgt, u32 value);
int nfp_xpb_writelm(struct nfp_cpp *cpp, u32 xpb_tgt, u32 mask, u32 value);
/* Implemented in nfp_cpplib.c */
int nfp_cpp_read(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, void *kernel_vaddr, size_t length);
int nfp_cpp_write(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, const void *kernel_vaddr,
size_t length);
int nfp_cpp_readl(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u32 *value);
int nfp_cpp_writel(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u32 value);
int nfp_cpp_readq(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u64 *value);
int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u64 value);
struct nfp_cpp_mutex;
int nfp_cpp_mutex_init(struct nfp_cpp *cpp, int target,
unsigned long long address, u32 key_id);
struct nfp_cpp_mutex *nfp_cpp_mutex_alloc(struct nfp_cpp *cpp, int target,
unsigned long long address,
u32 key_id);
void nfp_cpp_mutex_free(struct nfp_cpp_mutex *mutex);
int nfp_cpp_mutex_lock(struct nfp_cpp_mutex *mutex);
int nfp_cpp_mutex_unlock(struct nfp_cpp_mutex *mutex);
int nfp_cpp_mutex_trylock(struct nfp_cpp_mutex *mutex);
struct nfp_cpp_explicit;
struct nfp_cpp_explicit_command {
u32 cpp_id;
u16 data_ref;
u8 data_master;
u8 len;
u8 byte_mask;
u8 signal_master;
u8 signal_ref;
u8 posted;
u8 siga;
u8 sigb;
s8 siga_mode;
s8 sigb_mode;
};
#define NFP_SERIAL_LEN 6
/**
* struct nfp_cpp_operations - NFP CPP operations structure
* @area_priv_size: Size of the nfp_cpp_area private data
* @owner: Owner module
* @init: Initialize the NFP CPP bus
* @free: Free the bus
* @read_serial: Read serial number to memory provided
* @get_interface: Return CPP interface
* @area_init: Initialize a new NFP CPP area (not serialized)
* @area_cleanup: Clean up a NFP CPP area (not serialized)
* @area_acquire: Acquire the NFP CPP area (serialized)
* @area_release: Release area (serialized)
* @area_resource: Get resource range of area (not serialized)
* @area_phys: Get physical address of area (not serialized)
* @area_iomem: Get iomem of area (not serialized)
* @area_read: Perform a read from a NFP CPP area (serialized)
* @area_write: Perform a write to a NFP CPP area (serialized)
* @explicit_priv_size: Size of an explicit's private area
* @explicit_acquire: Acquire an explicit area
* @explicit_release: Release an explicit area
* @explicit_put: Write data to send
* @explicit_get: Read data received
* @explicit_do: Perform the transaction
*/
struct nfp_cpp_operations {
size_t area_priv_size;
struct module *owner;
int (*init)(struct nfp_cpp *cpp);
void (*free)(struct nfp_cpp *cpp);
void (*read_serial)(struct device *dev, u8 *serial);
u16 (*get_interface)(struct device *dev);
int (*area_init)(struct nfp_cpp_area *area,
u32 dest, unsigned long long address,
unsigned long size);
void (*area_cleanup)(struct nfp_cpp_area *area);
int (*area_acquire)(struct nfp_cpp_area *area);
void (*area_release)(struct nfp_cpp_area *area);
struct resource *(*area_resource)(struct nfp_cpp_area *area);
phys_addr_t (*area_phys)(struct nfp_cpp_area *area);
void __iomem *(*area_iomem)(struct nfp_cpp_area *area);
int (*area_read)(struct nfp_cpp_area *area, void *kernel_vaddr,
unsigned long offset, unsigned int length);
int (*area_write)(struct nfp_cpp_area *area, const void *kernel_vaddr,
unsigned long offset, unsigned int length);
size_t explicit_priv_size;
int (*explicit_acquire)(struct nfp_cpp_explicit *expl);
void (*explicit_release)(struct nfp_cpp_explicit *expl);
int (*explicit_put)(struct nfp_cpp_explicit *expl,
const void *buff, size_t len);
int (*explicit_get)(struct nfp_cpp_explicit *expl,
void *buff, size_t len);
int (*explicit_do)(struct nfp_cpp_explicit *expl,
const struct nfp_cpp_explicit_command *cmd,
u64 address);
};
struct nfp_cpp *
nfp_cpp_from_operations(const struct nfp_cpp_operations *ops,
struct device *parent, void *priv);
void *nfp_cpp_priv(struct nfp_cpp *priv);
int nfp_cpp_area_cache_add(struct nfp_cpp *cpp, size_t size);
/* The following section contains extensions to the
* NFP CPP API, to be used in a Linux kernel-space context.
*/
/* Use this channel ID for multiple virtual channel interfaces
* (ie ARM and PCIe) when setting up the interface field.
*/
#define NFP_CPP_INTERFACE_CHANNEL_PEROPENER 255
struct device *nfp_cpp_device(struct nfp_cpp *cpp);
/* Return code masks for nfp_cpp_explicit_do()
*/
#define NFP_SIGNAL_MASK_A BIT(0) /* Signal A fired */
#define NFP_SIGNAL_MASK_B BIT(1) /* Signal B fired */
enum nfp_cpp_explicit_signal_mode {
NFP_SIGNAL_NONE = 0,
NFP_SIGNAL_PUSH = 1,
NFP_SIGNAL_PUSH_OPTIONAL = -1,
NFP_SIGNAL_PULL = 2,
NFP_SIGNAL_PULL_OPTIONAL = -2,
};
struct nfp_cpp_explicit *nfp_cpp_explicit_acquire(struct nfp_cpp *cpp);
int nfp_cpp_explicit_set_target(struct nfp_cpp_explicit *expl, u32 cpp_id,
u8 len, u8 mask);
int nfp_cpp_explicit_set_data(struct nfp_cpp_explicit *expl,
u8 data_master, u16 data_ref);
int nfp_cpp_explicit_set_signal(struct nfp_cpp_explicit *expl,
u8 signal_master, u8 signal_ref);
int nfp_cpp_explicit_set_posted(struct nfp_cpp_explicit *expl, int posted,
u8 siga,
enum nfp_cpp_explicit_signal_mode siga_mode,
u8 sigb,
enum nfp_cpp_explicit_signal_mode sigb_mode);
int nfp_cpp_explicit_put(struct nfp_cpp_explicit *expl,
const void *buff, size_t len);
int nfp_cpp_explicit_do(struct nfp_cpp_explicit *expl, u64 address);
int nfp_cpp_explicit_get(struct nfp_cpp_explicit *expl, void *buff, size_t len);
void nfp_cpp_explicit_release(struct nfp_cpp_explicit *expl);
struct nfp_cpp *nfp_cpp_explicit_cpp(struct nfp_cpp_explicit *expl);
void *nfp_cpp_explicit_priv(struct nfp_cpp_explicit *cpp_explicit);
/* Implemented in nfp_cpplib.c */
int nfp_cpp_model_autodetect(struct nfp_cpp *cpp, u32 *model);
int nfp_cpp_explicit_read(struct nfp_cpp *cpp, u32 cpp_id,
u64 addr, void *buff, size_t len,
int width_read);
int nfp_cpp_explicit_write(struct nfp_cpp *cpp, u32 cpp_id,
u64 addr, const void *buff, size_t len,
int width_write);
#endif /* !__NFP_CPP_H__ */
/*
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* nfp_cpplib.c
* Library of functions to access the NFP's CPP bus
* Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
* Jason McMullan <jason.mcmullan@netronome.com>
* Rolf Neugebauer <rolf.neugebauer@netronome.com>
*/
#include <asm/unaligned.h>
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include "nfp_cpp.h"
#include "nfp6000/nfp6000.h"
#include "nfp6000/nfp_xpb.h"
/* NFP6000 PL */
#define NFP_PL_DEVICE_ID 0x00000004
#define NFP_PL_DEVICE_ID_MASK GENMASK(7, 0)
#define NFP6000_ARM_GCSR_SOFTMODEL0 0x00400144
/**
* nfp_cpp_readl() - Read a u32 word from a CPP location
* @cpp: CPP device handle
* @cpp_id: CPP ID for operation
* @address: Address for operation
* @value: Pointer to read buffer
*
* Return: length of the io, or -ERRNO
*/
int nfp_cpp_readl(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u32 *value)
{
u8 tmp[4];
int err;
err = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
*value = get_unaligned_le32(tmp);
return err;
}
/**
* nfp_cpp_writel() - Write a u32 word to a CPP location
* @cpp: CPP device handle
* @cpp_id: CPP ID for operation
* @address: Address for operation
* @value: Value to write
*
* Return: length of the io, or -ERRNO
*/
int nfp_cpp_writel(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u32 value)
{
u8 tmp[4];
put_unaligned_le32(value, tmp);
return nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
}
/**
* nfp_cpp_readq() - Read a u64 word from a CPP location
* @cpp: CPP device handle
* @cpp_id: CPP ID for operation
* @address: Address for operation
* @value: Pointer to read buffer
*
* Return: length of the io, or -ERRNO
*/
int nfp_cpp_readq(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u64 *value)
{
u8 tmp[8];
int err;
err = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
*value = get_unaligned_le64(tmp);
return err;
}
/**
* nfp_cpp_writeq() - Write a u64 word to a CPP location
* @cpp: CPP device handle
* @cpp_id: CPP ID for operation
* @address: Address for operation
* @value: Value to write
*
* Return: length of the io, or -ERRNO
*/
int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u64 value)
{
u8 tmp[8];
put_unaligned_le64(value, tmp);
return nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
}
/* NOTE: This code should not use nfp_xpb_* functions,
* as those are model-specific
*/
int nfp_cpp_model_autodetect(struct nfp_cpp *cpp, u32 *model)
{
const u32 arm_id = NFP_CPP_ID(NFP_CPP_TARGET_ARM, 0, 0);
u32 reg;
int err;
err = nfp_cpp_readl(cpp, arm_id, NFP6000_ARM_GCSR_SOFTMODEL0, model);
if (err < 0)
return err;
/* The PL's PluDeviceID revision code is authoratative */
*model &= ~0xff;
err = nfp_xpb_readl(cpp, NFP_XPB_DEVICE(1, 1, 16) + NFP_PL_DEVICE_ID,
&reg);
if (err < 0)
return err;
*model |= (NFP_PL_DEVICE_ID_MASK & reg) - 0x10;
return 0;
}
static u8 nfp_bytemask(int width, u64 addr)
{
if (width == 8)
return 0xff;
else if (width == 4)
return 0x0f << (addr & 4);
else if (width == 2)
return 0x03 << (addr & 6);
else if (width == 1)
return 0x01 << (addr & 7);
else
return 0;
}
int nfp_cpp_explicit_read(struct nfp_cpp *cpp, u32 cpp_id,
u64 addr, void *buff, size_t len, int width_read)
{
struct nfp_cpp_explicit *expl;
char *tmp = buff;
int err, i, incr;
u8 byte_mask;
if (len & (width_read - 1))
return -EINVAL;
expl = nfp_cpp_explicit_acquire(cpp);
if (!expl)
return -EBUSY;
incr = min_t(int, 16 * width_read, 128);
incr = min_t(int, incr, len);
/* Translate a NFP_CPP_ACTION_RW to action 0 */
if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 0,
NFP_CPP_ID_TOKEN_of(cpp_id));
byte_mask = nfp_bytemask(width_read, addr);
nfp_cpp_explicit_set_target(expl, cpp_id,
incr / width_read - 1, byte_mask);
nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PUSH,
0, NFP_SIGNAL_NONE);
for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
if (i + incr > len) {
incr = len - i;
nfp_cpp_explicit_set_target(expl, cpp_id,
incr / width_read - 1,
0xff);
}
err = nfp_cpp_explicit_do(expl, addr);
if (err < 0)
goto exit_release;
err = nfp_cpp_explicit_get(expl, tmp, incr);
if (err < 0)
goto exit_release;
}
err = len;
exit_release:
nfp_cpp_explicit_release(expl);
return err;
}
int nfp_cpp_explicit_write(struct nfp_cpp *cpp, u32 cpp_id, u64 addr,
const void *buff, size_t len, int width_write)
{
struct nfp_cpp_explicit *expl;
const char *tmp = buff;
int err, i, incr;
u8 byte_mask;
if (len & (width_write - 1))
return -EINVAL;
expl = nfp_cpp_explicit_acquire(cpp);
if (!expl)
return -EBUSY;
incr = min_t(int, 16 * width_write, 128);
incr = min_t(int, incr, len);
/* Translate a NFP_CPP_ACTION_RW to action 1 */
if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 1,
NFP_CPP_ID_TOKEN_of(cpp_id));
byte_mask = nfp_bytemask(width_write, addr);
nfp_cpp_explicit_set_target(expl, cpp_id,
incr / width_write - 1, byte_mask);
nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PULL,
0, NFP_SIGNAL_NONE);
for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
if (i + incr > len) {
incr = len - i;
nfp_cpp_explicit_set_target(expl, cpp_id,
incr / width_write - 1,
0xff);
}
err = nfp_cpp_explicit_put(expl, tmp, incr);
if (err < 0)
goto exit_release;
err = nfp_cpp_explicit_do(expl, addr);
if (err < 0)
goto exit_release;
}
err = len;
exit_release:
nfp_cpp_explicit_release(expl);
return err;
}
/*
* Copyright (C) 2015-2017 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Parse the hwinfo table that the ARM firmware builds in the ARM scratch SRAM
* after chip reset.
*
* Examples of the fields:
* me.count = 40
* me.mask = 0x7f_ffff_ffff
*
* me.count is the total number of MEs on the system.
* me.mask is the bitmask of MEs that are available for application usage.
*
* (ie, in this example, ME 39 has been reserved by boardconfig.)
*/
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <linux/delay.h>
#include <linux/log2.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#define NFP_SUBSYS "nfp_hwinfo"
#include "crc32.h"
#include "nfp.h"
#include "nfp_cpp.h"
#include "nfp6000/nfp6000.h"
#define HWINFO_SIZE_MIN 0x100
#define HWINFO_WAIT 20 /* seconds */
/* The Hardware Info Table defines the properties of the system.
*
* HWInfo v1 Table (fixed size)
*
* 0x0000: u32 version Hardware Info Table version (1.0)
* 0x0004: u32 size Total size of the table, including
* the CRC32 (IEEE 802.3)
* 0x0008: u32 jumptab Offset of key/value table
* 0x000c: u32 keys Total number of keys in the key/value table
* NNNNNN: Key/value jump table and string data
* (size - 4): u32 crc32 CRC32 (same as IEEE 802.3, POSIX csum, etc)
* CRC32("",0) = ~0, CRC32("a",1) = 0x48C279FE
*
* HWInfo v2 Table (variable size)
*
* 0x0000: u32 version Hardware Info Table version (2.0)
* 0x0004: u32 size Current size of the data area, excluding CRC32
* 0x0008: u32 limit Maximum size of the table
* 0x000c: u32 reserved Unused, set to zero
* NNNNNN: Key/value data
* (size - 4): u32 crc32 CRC32 (same as IEEE 802.3, POSIX csum, etc)
* CRC32("",0) = ~0, CRC32("a",1) = 0x48C279FE
*
* If the HWInfo table is in the process of being updated, the low bit
* of version will be set.
*
* HWInfo v1 Key/Value Table
* -------------------------
*
* The key/value table is a set of offsets to ASCIIZ strings which have
* been strcmp(3) sorted (yes, please use bsearch(3) on the table).
*
* All keys are guaranteed to be unique.
*
* N+0: u32 key_1 Offset to the first key
* N+4: u32 val_1 Offset to the first value
* N+8: u32 key_2 Offset to the second key
* N+c: u32 val_2 Offset to the second value
* ...
*
* HWInfo v2 Key/Value Table
* -------------------------
*
* Packed UTF8Z strings, ie 'key1\000value1\000key2\000value2\000'
*
* Unsorted.
*/
#define NFP_HWINFO_VERSION_1 ('H' << 24 | 'I' << 16 | 1 << 8 | 0 << 1 | 0)
#define NFP_HWINFO_VERSION_2 ('H' << 24 | 'I' << 16 | 2 << 8 | 0 << 1 | 0)
#define NFP_HWINFO_VERSION_UPDATING BIT(0)
struct nfp_hwinfo {
u8 start[0];
__le32 version;
__le32 size;
/* v2 specific fields */
__le32 limit;
__le32 resv;
char data[];
};
static bool nfp_hwinfo_is_updating(struct nfp_hwinfo *hwinfo)
{
return le32_to_cpu(hwinfo->version) & NFP_HWINFO_VERSION_UPDATING;
}
static int
hwinfo_db_walk(struct nfp_cpp *cpp, struct nfp_hwinfo *hwinfo, u32 size)
{
const char *key, *val, *end = hwinfo->data + size;
for (key = hwinfo->data; *key && key < end;
key = val + strlen(val) + 1) {
val = key + strlen(key) + 1;
if (val >= end) {
nfp_warn(cpp, "Bad HWINFO - overflowing key\n");
return -EINVAL;
}
if (val + strlen(val) + 1 > end) {
nfp_warn(cpp, "Bad HWINFO - overflowing value\n");
return -EINVAL;
}
}
return 0;
}
static int
hwinfo_db_validate(struct nfp_cpp *cpp, struct nfp_hwinfo *db, u32 len)
{
u32 size, crc;
size = le32_to_cpu(db->size);
if (size > len) {
nfp_err(cpp, "Unsupported hwinfo size %u > %u\n", size, len);
return -EINVAL;
}
size -= sizeof(u32);
crc = crc32_posix(db, size);
if (crc != get_unaligned_le32(db->start + size)) {
nfp_err(cpp, "Corrupt hwinfo table (CRC mismatch), calculated 0x%x, expected 0x%x\n",
crc, get_unaligned_le32(db->start + size));
return -EINVAL;
}
return hwinfo_db_walk(cpp, db, size);
}
static int hwinfo_try_fetch(struct nfp_cpp *cpp, size_t *cpp_size)
{
struct nfp_hwinfo *header;
struct nfp_resource *res;
u64 cpp_addr;
u32 cpp_id;
int err;
u8 *db;
res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_HWINFO);
if (!IS_ERR(res)) {
cpp_id = nfp_resource_cpp_id(res);
cpp_addr = nfp_resource_address(res);
*cpp_size = nfp_resource_size(res);
nfp_resource_release(res);
if (*cpp_size < HWINFO_SIZE_MIN)
return -ENOENT;
} else if (PTR_ERR(res) == -ENOENT) {
/* Try getting the HWInfo table from the 'classic' location */
cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU,
NFP_CPP_ACTION_RW, 0, 1);
cpp_addr = 0x30000;
*cpp_size = 0x0e000;
} else {
return PTR_ERR(res);
}
db = kmalloc(*cpp_size + 1, GFP_KERNEL);
if (!db)
return -ENOMEM;
err = nfp_cpp_read(cpp, cpp_id, cpp_addr, db, *cpp_size);
if (err != *cpp_size) {
kfree(db);
return err < 0 ? err : -EIO;
}
header = (void *)db;
if (nfp_hwinfo_is_updating(header)) {
kfree(db);
return -EBUSY;
}
if (le32_to_cpu(header->version) != NFP_HWINFO_VERSION_2) {
nfp_err(cpp, "Unknown HWInfo version: 0x%08x\n",
le32_to_cpu(header->version));
kfree(db);
return -EINVAL;
}
/* NULL-terminate for safety */
db[*cpp_size] = '\0';
nfp_hwinfo_cache_set(cpp, db);
return 0;
}
static int hwinfo_fetch(struct nfp_cpp *cpp, size_t *hwdb_size)
{
const unsigned long wait_until = jiffies + HWINFO_WAIT * HZ;
int err;
for (;;) {
const unsigned long start_time = jiffies;
err = hwinfo_try_fetch(cpp, hwdb_size);
if (!err)
return 0;
err = msleep_interruptible(100);
if (err || time_after(start_time, wait_until)) {
nfp_err(cpp, "NFP access error\n");
return -EIO;
}
}
}
static int nfp_hwinfo_load(struct nfp_cpp *cpp)
{
struct nfp_hwinfo *db;
size_t hwdb_size = 0;
int err;
err = hwinfo_fetch(cpp, &hwdb_size);
if (err)
return err;
db = nfp_hwinfo_cache(cpp);
err = hwinfo_db_validate(cpp, db, hwdb_size);
if (err) {
kfree(db);
nfp_hwinfo_cache_set(cpp, NULL);
return err;
}
return 0;
}
/**
* nfp_hwinfo_lookup() - Find a value in the HWInfo table by name
* @cpp: NFP CPP handle
* @lookup: HWInfo name to search for
*
* Return: Value of the HWInfo name, or NULL
*/
const char *nfp_hwinfo_lookup(struct nfp_cpp *cpp, const char *lookup)
{
const char *key, *val, *end;
struct nfp_hwinfo *hwinfo;
int err;
hwinfo = nfp_hwinfo_cache(cpp);
if (!hwinfo) {
err = nfp_hwinfo_load(cpp);
if (err)
return NULL;
hwinfo = nfp_hwinfo_cache(cpp);
}
if (!hwinfo || !lookup)
return NULL;
end = hwinfo->data + le32_to_cpu(hwinfo->size) - sizeof(u32);
for (key = hwinfo->data; *key && key < end;
key = val + strlen(val) + 1) {
val = key + strlen(key) + 1;
if (strcmp(key, lookup) == 0)
return val;
}
return NULL;
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -62,6 +62,19 @@
(1ULL << __bf_shf(_mask))); \
})
/**
* FIELD_FIT() - check if value fits in the field
* @_mask: shifted mask defining the field's length and position
* @_val: value to test against the field
*
* Return: true if @_val can fit inside @_mask, false if @_val is too big.
*/
#define FIELD_FIT(_mask, _val) \
({ \
__BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_FIT: "); \
!((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \
})
/**
* FIELD_PREP() - prepare a bitfield element
* @_mask: shifted mask defining the field's length and position
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册