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

Merge branch 'nfp-devlink-capabilities-extensions-and-updates'

Jakub Kicinski says:

====================
nfp: devlink, capabilities extensions and updates

This series starts with an improvement to the usability of the device
memory accessors (CPP transactions).  Next few patches are devoted to
fixing the devlink locking.  After recent patches for mlxsw the locking
scheme of devlink ops has to be reworked.  Following patches improve
NFP code dealing with "representors", and expands the error message
printed when driver has no support for loaded FW.

Second part of the series is focused on vNIC capabilities read from
vNIC control memory (often referred to as "BAR0" for historical reasons).
TLV capability format is established and immediately made use of.  The
next patches rework parsing of features for control vNIC which allows
apps to mask out features they don't want enabled.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
......@@ -22,6 +22,7 @@ nfp-objs := \
nfp_hwmon.o \
nfp_main.o \
nfp_net_common.o \
nfp_net_ctrl.o \
nfp_net_debugdump.o \
nfp_net_ethtool.o \
nfp_net_main.o \
......
......@@ -389,6 +389,8 @@ const struct nfp_app_type app_bpf = {
.id = NFP_APP_BPF_NIC,
.name = "ebpf",
.ctrl_cap_mask = 0,
.init = nfp_bpf_init,
.clean = nfp_bpf_clean,
......
......@@ -99,7 +99,7 @@ nfp_flower_repr_get(struct nfp_app *app, u32 port_id)
if (port >= reprs->num_reprs)
return NULL;
return reprs->reprs[port];
return rcu_dereference(reprs->reprs[port]);
}
static int
......@@ -114,15 +114,19 @@ nfp_flower_reprs_reify(struct nfp_app *app, enum nfp_repr_type type,
if (!reprs)
return 0;
for (i = 0; i < reprs->num_reprs; i++)
if (reprs->reprs[i]) {
struct nfp_repr *repr = netdev_priv(reprs->reprs[i]);
for (i = 0; i < reprs->num_reprs; i++) {
struct net_device *netdev;
netdev = nfp_repr_get_locked(app, reprs, i);
if (netdev) {
struct nfp_repr *repr = netdev_priv(netdev);
err = nfp_flower_cmsg_portreify(repr, exists);
if (err)
return err;
count++;
}
}
return count;
}
......@@ -234,19 +238,21 @@ nfp_flower_spawn_vnic_reprs(struct nfp_app *app,
return -ENOMEM;
for (i = 0; i < cnt; i++) {
struct net_device *repr;
struct nfp_port *port;
u32 port_id;
reprs->reprs[i] = nfp_repr_alloc(app);
if (!reprs->reprs[i]) {
repr = nfp_repr_alloc(app);
if (!repr) {
err = -ENOMEM;
goto err_reprs_clean;
}
RCU_INIT_POINTER(reprs->reprs[i], repr);
/* For now we only support 1 PF */
WARN_ON(repr_type == NFP_REPR_TYPE_PF && i);
port = nfp_port_alloc(app, port_type, reprs->reprs[i]);
port = nfp_port_alloc(app, port_type, repr);
if (repr_type == NFP_REPR_TYPE_PF) {
port->pf_id = i;
port->vnic = priv->nn->dp.ctrl_bar;
......@@ -257,11 +263,11 @@ nfp_flower_spawn_vnic_reprs(struct nfp_app *app,
app->pf->vf_cfg_mem + i * NFP_NET_CFG_BAR_SZ;
}
eth_hw_addr_random(reprs->reprs[i]);
eth_hw_addr_random(repr);
port_id = nfp_flower_cmsg_pcie_port(nfp_pcie, vnic_type,
i, queue);
err = nfp_repr_init(app, reprs->reprs[i],
err = nfp_repr_init(app, repr,
port_id, port, priv->nn->dp.netdev);
if (err) {
nfp_port_free(port);
......@@ -270,7 +276,7 @@ nfp_flower_spawn_vnic_reprs(struct nfp_app *app,
nfp_info(app->cpp, "%s%d Representor(%s) created\n",
repr_type == NFP_REPR_TYPE_PF ? "PF" : "VF", i,
reprs->reprs[i]->name);
repr->name);
}
nfp_app_reprs_set(app, repr_type, reprs);
......@@ -291,7 +297,7 @@ nfp_flower_spawn_vnic_reprs(struct nfp_app *app,
err_reprs_remove:
reprs = nfp_app_reprs_set(app, repr_type, NULL);
err_reprs_clean:
nfp_reprs_clean_and_free(reprs);
nfp_reprs_clean_and_free(app, reprs);
return err;
}
......@@ -329,17 +335,18 @@ nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv)
for (i = 0; i < eth_tbl->count; i++) {
unsigned int phys_port = eth_tbl->ports[i].index;
struct net_device *repr;
struct nfp_port *port;
u32 cmsg_port_id;
reprs->reprs[phys_port] = nfp_repr_alloc(app);
if (!reprs->reprs[phys_port]) {
repr = nfp_repr_alloc(app);
if (!repr) {
err = -ENOMEM;
goto err_reprs_clean;
}
RCU_INIT_POINTER(reprs->reprs[phys_port], repr);
port = nfp_port_alloc(app, NFP_PORT_PHYS_PORT,
reprs->reprs[phys_port]);
port = nfp_port_alloc(app, NFP_PORT_PHYS_PORT, repr);
if (IS_ERR(port)) {
err = PTR_ERR(port);
goto err_reprs_clean;
......@@ -350,11 +357,11 @@ nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv)
goto err_reprs_clean;
}
SET_NETDEV_DEV(reprs->reprs[phys_port], &priv->nn->pdev->dev);
SET_NETDEV_DEV(repr, &priv->nn->pdev->dev);
nfp_net_get_mac_addr(app->pf, port);
cmsg_port_id = nfp_flower_cmsg_phys_port(phys_port);
err = nfp_repr_init(app, reprs->reprs[phys_port],
err = nfp_repr_init(app, repr,
cmsg_port_id, port, priv->nn->dp.netdev);
if (err) {
nfp_port_free(port);
......@@ -367,7 +374,7 @@ nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv)
phys_port);
nfp_info(app->cpp, "Phys Port %d Representor(%s) created\n",
phys_port, reprs->reprs[phys_port]->name);
phys_port, repr->name);
}
nfp_app_reprs_set(app, NFP_REPR_TYPE_PHYS_PORT, reprs);
......@@ -397,7 +404,7 @@ nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv)
err_reprs_remove:
reprs = nfp_app_reprs_set(app, NFP_REPR_TYPE_PHYS_PORT, NULL);
err_reprs_clean:
nfp_reprs_clean_and_free(reprs);
nfp_reprs_clean_and_free(app, reprs);
err_free_ctrl_skb:
kfree_skb(ctrl_skb);
return err;
......@@ -558,6 +565,8 @@ static void nfp_flower_stop(struct nfp_app *app)
const struct nfp_app_type app_flower = {
.id = NFP_APP_FLOWER_NIC,
.name = "flower",
.ctrl_cap_mask = ~0U,
.ctrl_has_meta = true,
.extra_cap = nfp_flower_extra_cap,
......
......@@ -32,6 +32,8 @@
*/
#include <linux/bug.h>
#include <linux/lockdep.h>
#include <linux/rcupdate.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
......@@ -98,14 +100,20 @@ nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size, gfp_t priority)
return skb;
}
struct nfp_reprs *
nfp_reprs_get_locked(struct nfp_app *app, enum nfp_repr_type type)
{
return rcu_dereference_protected(app->reprs[type],
lockdep_is_held(&app->pf->lock));
}
struct nfp_reprs *
nfp_app_reprs_set(struct nfp_app *app, enum nfp_repr_type type,
struct nfp_reprs *reprs)
{
struct nfp_reprs *old;
old = rcu_dereference_protected(app->reprs[type],
lockdep_is_held(&app->pf->lock));
old = nfp_reprs_get_locked(app, type);
rcu_assign_pointer(app->reprs[type], reprs);
return old;
......@@ -116,7 +124,7 @@ struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id)
struct nfp_app *app;
if (id >= ARRAY_SIZE(apps) || !apps[id]) {
nfp_err(pf->cpp, "failed to find app with ID 0x%02hhx\n", id);
nfp_err(pf->cpp, "unknown FW app ID 0x%02hhx, driver too old or support for FW not built in\n", id);
return ERR_PTR(-EINVAL);
}
......
......@@ -66,6 +66,9 @@ extern const struct nfp_app_type app_flower;
* struct nfp_app_type - application definition
* @id: application ID
* @name: application name
* @ctrl_cap_mask: ctrl vNIC capability mask, allows disabling features like
* IRQMOD which are on by default but counter-productive for
* control messages which are often latency-sensitive
* @ctrl_has_meta: control messages have prepend of type:5/port:CTRL
*
* Callbacks
......@@ -100,6 +103,7 @@ struct nfp_app_type {
enum nfp_app_id id;
const char *name;
u32 ctrl_cap_mask;
bool ctrl_has_meta;
int (*init)(struct nfp_app *app);
......@@ -384,6 +388,8 @@ static inline struct net_device *nfp_app_repr_get(struct nfp_app *app, u32 id)
struct nfp_app *nfp_app_from_netdev(struct net_device *netdev);
struct nfp_reprs *
nfp_reprs_get_locked(struct nfp_app *app, enum nfp_repr_type type);
struct nfp_reprs *
nfp_app_reprs_set(struct nfp_app *app, enum nfp_repr_type type,
struct nfp_reprs *reprs);
......
......@@ -152,18 +152,8 @@ nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index)
static int nfp_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
{
struct nfp_pf *pf = devlink_priv(devlink);
int ret;
mutex_lock(&pf->lock);
if (!pf->app) {
ret = -EBUSY;
goto out;
}
ret = nfp_app_eswitch_mode_get(pf->app, mode);
out:
mutex_unlock(&pf->lock);
return ret;
return nfp_app_eswitch_mode_get(pf->app, mode);
}
const struct devlink_ops nfp_devlink_ops = {
......
......@@ -499,13 +499,9 @@ static int nfp_pci_probe(struct pci_dev *pdev,
if (err)
goto err_hwinfo_free;
err = devlink_register(devlink, &pdev->dev);
if (err)
goto err_hwinfo_free;
err = nfp_nsp_init(pdev, pf);
if (err)
goto err_devlink_unreg;
goto err_hwinfo_free;
pf->mip = nfp_mip_open(pf->cpp);
pf->rtbl = __nfp_rtsym_table_read(pf->cpp, pf->mip);
......@@ -549,8 +545,6 @@ static int nfp_pci_probe(struct pci_dev *pdev,
kfree(pf->eth_tbl);
kfree(pf->nspi);
vfree(pf->dumpspec);
err_devlink_unreg:
devlink_unregister(devlink);
err_hwinfo_free:
kfree(pf->hwinfo);
nfp_cpp_free(pf->cpp);
......@@ -571,18 +565,13 @@ static int nfp_pci_probe(struct pci_dev *pdev,
static void nfp_pci_remove(struct pci_dev *pdev)
{
struct nfp_pf *pf = pci_get_drvdata(pdev);
struct devlink *devlink;
nfp_hwmon_unregister(pf);
devlink = priv_to_devlink(pf);
nfp_net_pci_remove(pf);
nfp_pcie_sriov_disable(pdev);
pci_sriov_set_totalvfs(pf->pdev, 0);
devlink_unregister(devlink);
nfp_net_pci_remove(pf);
vfree(pf->dumpspec);
kfree(pf->rtbl);
......@@ -598,7 +587,7 @@ static void nfp_pci_remove(struct pci_dev *pdev)
kfree(pf->eth_tbl);
kfree(pf->nspi);
mutex_destroy(&pf->lock);
devlink_free(devlink);
devlink_free(priv_to_devlink(pf));
pci_release_regions(pdev);
pci_disable_device(pdev);
}
......
......@@ -578,6 +578,7 @@ struct nfp_net_dp {
* @qcp_cfg: Pointer to QCP queue used for configuration notification
* @tx_bar: Pointer to mapped TX queues
* @rx_bar: Pointer to mapped FL/RX queues
* @tlv_caps: Parsed TLV capabilities
* @debugfs_dir: Device directory in debugfs
* @vnic_list: Entry on device vNIC list
* @pdev: Backpointer to PCI device
......@@ -644,6 +645,8 @@ struct nfp_net {
u8 __iomem *tx_bar;
u8 __iomem *rx_bar;
struct nfp_net_tlv_caps tlv_caps;
struct dentry *debugfs_dir;
struct list_head vnic_list;
......
......@@ -293,9 +293,15 @@ int nfp_net_reconfig(struct nfp_net *nn, u32 update)
*/
static int nfp_net_reconfig_mbox(struct nfp_net *nn, u32 mbox_cmd)
{
u32 mbox = nn->tlv_caps.mbox_off;
int ret;
nn_writeq(nn, NFP_NET_CFG_MBOX_CMD, mbox_cmd);
if (!nfp_net_has_mbox(&nn->tlv_caps)) {
nn_err(nn, "no mailbox present, command: %u\n", mbox_cmd);
return -EIO;
}
nn_writeq(nn, mbox + NFP_NET_CFG_MBOX_SIMPLE_CMD, mbox_cmd);
ret = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_MBOX);
if (ret) {
......@@ -303,7 +309,7 @@ static int nfp_net_reconfig_mbox(struct nfp_net *nn, u32 mbox_cmd)
return ret;
}
return -nn_readl(nn, NFP_NET_CFG_MBOX_RET);
return -nn_readl(nn, mbox + NFP_NET_CFG_MBOX_SIMPLE_RET);
}
/* Interrupt configuration and handling
......@@ -2458,7 +2464,7 @@ void nfp_net_coalesce_write_cfg(struct nfp_net *nn)
* ME timestamp ticks. There are 16 ME clock cycles for each timestamp
* count.
*/
factor = nn->me_freq_mhz / 16;
factor = nn->tlv_caps.me_freq_mhz / 16;
/* copy RX interrupt coalesce parameters */
value = (nn->rx_coalesce_max_frames << 16) |
......@@ -3084,8 +3090,9 @@ nfp_net_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
if (!vid)
return 0;
nn_writew(nn, NFP_NET_CFG_VLAN_FILTER_VID, vid);
nn_writew(nn, NFP_NET_CFG_VLAN_FILTER_PROTO, ETH_P_8021Q);
nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_VLAN_FILTER_VID, vid);
nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_VLAN_FILTER_PROTO,
ETH_P_8021Q);
return nfp_net_reconfig_mbox(nn, NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_ADD);
}
......@@ -3101,8 +3108,9 @@ nfp_net_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
if (!vid)
return 0;
nn_writew(nn, NFP_NET_CFG_VLAN_FILTER_VID, vid);
nn_writew(nn, NFP_NET_CFG_VLAN_FILTER_PROTO, ETH_P_8021Q);
nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_VLAN_FILTER_VID, vid);
nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_VLAN_FILTER_PROTO,
ETH_P_8021Q);
return nfp_net_reconfig_mbox(nn, NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_KILL);
}
......@@ -3748,18 +3756,8 @@ static void nfp_net_netdev_init(struct nfp_net *nn)
nfp_net_set_ethtool_ops(netdev);
}
/**
* nfp_net_init() - Initialise/finalise the nfp_net structure
* @nn: NFP Net device structure
*
* Return: 0 on success or negative errno on error.
*/
int nfp_net_init(struct nfp_net *nn)
static int nfp_net_read_caps(struct nfp_net *nn)
{
int err;
nn->dp.rx_dma_dir = DMA_FROM_DEVICE;
/* Get some of the read-only fields from the BAR */
nn->cap = nn_readl(nn, NFP_NET_CFG_CAP);
nn->max_mtu = nn_readl(nn, NFP_NET_CFG_MAX_MTU);
......@@ -3792,6 +3790,29 @@ int nfp_net_init(struct nfp_net *nn)
nn->dp.rx_offset = NFP_NET_RX_OFFSET;
}
/* For control vNICs mask out the capabilities app doesn't want. */
if (!nn->dp.netdev)
nn->cap &= nn->app->type->ctrl_cap_mask;
return 0;
}
/**
* nfp_net_init() - Initialise/finalise the nfp_net structure
* @nn: NFP Net device structure
*
* Return: 0 on success or negative errno on error.
*/
int nfp_net_init(struct nfp_net *nn)
{
int err;
nn->dp.rx_dma_dir = DMA_FROM_DEVICE;
err = nfp_net_read_caps(nn);
if (err)
return err;
/* Set default MTU and Freelist buffer size */
if (nn->max_mtu < NFP_NET_DEFAULT_MTU)
nn->dp.mtu = nn->max_mtu;
......@@ -3815,6 +3836,11 @@ int nfp_net_init(struct nfp_net *nn)
nn->dp.ctrl |= NFP_NET_CFG_CTRL_IRQMOD;
}
err = nfp_net_tlv_caps_parse(&nn->pdev->dev, nn->dp.ctrl_bar,
&nn->tlv_caps);
if (err)
return err;
if (nn->dp.netdev)
nfp_net_netdev_init(nn);
......
/*
* Copyright (C) 2018 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.
*/
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include "nfp_net_ctrl.h"
#include "nfp_net.h"
static void nfp_net_tlv_caps_reset(struct nfp_net_tlv_caps *caps)
{
memset(caps, 0, sizeof(*caps));
caps->me_freq_mhz = 1200;
caps->mbox_off = NFP_NET_CFG_MBOX_BASE;
caps->mbox_len = NFP_NET_CFG_MBOX_VAL_MAX_SZ;
}
int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem,
struct nfp_net_tlv_caps *caps)
{
u8 __iomem *data = ctrl_mem + NFP_NET_CFG_TLV_BASE;
u8 __iomem *end = ctrl_mem + NFP_NET_CFG_BAR_SZ;
u32 hdr;
nfp_net_tlv_caps_reset(caps);
hdr = readl(data);
if (!hdr)
return 0;
while (true) {
unsigned int length, offset;
u32 hdr = readl(data);
length = FIELD_GET(NFP_NET_CFG_TLV_HEADER_LENGTH, hdr);
offset = data - ctrl_mem + NFP_NET_CFG_TLV_BASE;
/* Advance past the header */
data += 4;
if (length % NFP_NET_CFG_TLV_LENGTH_INC) {
dev_err(dev, "TLV size not multiple of %u len:%u\n",
NFP_NET_CFG_TLV_LENGTH_INC, length);
return -EINVAL;
}
if (data + length > end) {
dev_err(dev, "oversized TLV offset:%u len:%u\n",
offset, length);
return -EINVAL;
}
switch (FIELD_GET(NFP_NET_CFG_TLV_HEADER_TYPE, hdr)) {
case NFP_NET_CFG_TLV_TYPE_UNKNOWN:
dev_err(dev, "NULL TLV at offset:%u\n", offset);
return -EINVAL;
case NFP_NET_CFG_TLV_TYPE_RESERVED:
break;
case NFP_NET_CFG_TLV_TYPE_END:
if (!length)
return 0;
dev_err(dev, "END TLV should be empty, has len:%d\n",
length);
return -EINVAL;
case NFP_NET_CFG_TLV_TYPE_ME_FREQ:
if (length != 4) {
dev_err(dev,
"ME FREQ TLV should be 4B, is %dB\n",
length);
return -EINVAL;
}
caps->me_freq_mhz = readl(data);
break;
case NFP_NET_CFG_TLV_TYPE_MBOX:
if (!length) {
caps->mbox_off = 0;
caps->mbox_len = 0;
} else {
caps->mbox_off = data - ctrl_mem;
caps->mbox_len = length;
}
break;
default:
if (!FIELD_GET(NFP_NET_CFG_TLV_HEADER_REQUIRED, hdr))
break;
dev_err(dev, "unknown TLV type:%u offset:%u len:%u\n",
FIELD_GET(NFP_NET_CFG_TLV_HEADER_TYPE, hdr),
offset, length);
return -EINVAL;
}
data += length;
if (data + 4 > end) {
dev_err(dev, "reached end of BAR without END TLV\n");
return -EINVAL;
}
}
/* Not reached */
return -EINVAL;
}
......@@ -43,9 +43,7 @@
#ifndef _NFP_NET_CTRL_H_
#define _NFP_NET_CTRL_H_
/* IMPORTANT: This header file is shared with the FW,
* no OS specific constructs, please!
*/
#include <linux/types.h>
/**
* Configuration BAR size.
......@@ -235,6 +233,12 @@
#define NFP_NET_CFG_RSS_CAP 0x0054
#define NFP_NET_CFG_RSS_CAP_HFUNC 0xff000000
/**
* TLV area start
* %NFP_NET_CFG_TLV_BASE: start anchor of the TLV area
*/
#define NFP_NET_CFG_TLV_BASE 0x0058
/**
* VXLAN/UDP encap configuration
* %NFP_NET_CFG_VXLAN_PORT: Base address of table of tunnels' UDP dst ports
......@@ -409,11 +413,14 @@
* 4B used for update command and 4B return code
* followed by a max of 504B of variable length value
*/
#define NFP_NET_CFG_MBOX_CMD 0x1800
#define NFP_NET_CFG_MBOX_RET 0x1804
#define NFP_NET_CFG_MBOX_VAL 0x1808
#define NFP_NET_CFG_MBOX_BASE 0x1800
#define NFP_NET_CFG_MBOX_VAL_MAX_SZ 0x1F8
#define NFP_NET_CFG_MBOX_SIMPLE_CMD 0x0
#define NFP_NET_CFG_MBOX_SIMPLE_RET 0x4
#define NFP_NET_CFG_MBOX_SIMPLE_VAL 0x8
#define NFP_NET_CFG_MBOX_SIMPLE_LEN 0x12
#define NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_ADD 1
#define NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_KILL 2
......@@ -424,9 +431,87 @@
* %NFP_NET_CFG_VLAN_FILTER_PROTO: VLAN proto to filter
* %NFP_NET_CFG_VXLAN_SZ: Size of the VLAN filter mailbox in bytes
*/
#define NFP_NET_CFG_VLAN_FILTER NFP_NET_CFG_MBOX_VAL
#define NFP_NET_CFG_VLAN_FILTER NFP_NET_CFG_MBOX_SIMPLE_VAL
#define NFP_NET_CFG_VLAN_FILTER_VID NFP_NET_CFG_VLAN_FILTER
#define NFP_NET_CFG_VLAN_FILTER_PROTO (NFP_NET_CFG_VLAN_FILTER + 2)
#define NFP_NET_CFG_VLAN_FILTER_SZ 0x0004
/**
* TLV capabilities
* %NFP_NET_CFG_TLV_TYPE: Offset of type within the TLV
* %NFP_NET_CFG_TLV_TYPE_REQUIRED: Driver must be able to parse the TLV
* %NFP_NET_CFG_TLV_LENGTH: Offset of length within the TLV
* %NFP_NET_CFG_TLV_LENGTH_INC: TLV length increments
* %NFP_NET_CFG_TLV_VALUE: Offset of value with the TLV
*
* List of simple TLV structures, first one starts at %NFP_NET_CFG_TLV_BASE.
* Last structure must be of type %NFP_NET_CFG_TLV_TYPE_END. Presence of TLVs
* is indicated by %NFP_NET_CFG_TLV_BASE being non-zero. TLV structures may
* fill the entire remainder of the BAR or be shorter. FW must make sure TLVs
* don't conflict with other features which allocate space beyond
* %NFP_NET_CFG_TLV_BASE. %NFP_NET_CFG_TLV_TYPE_RESERVED should be used to wrap
* space used by such features.
* Note that the 4 byte TLV header is not counted in %NFP_NET_CFG_TLV_LENGTH.
*/
#define NFP_NET_CFG_TLV_TYPE 0x00
#define NFP_NET_CFG_TLV_TYPE_REQUIRED 0x8000
#define NFP_NET_CFG_TLV_LENGTH 0x02
#define NFP_NET_CFG_TLV_LENGTH_INC 4
#define NFP_NET_CFG_TLV_VALUE 0x04
#define NFP_NET_CFG_TLV_HEADER_REQUIRED 0x80000000
#define NFP_NET_CFG_TLV_HEADER_TYPE 0x7fff0000
#define NFP_NET_CFG_TLV_HEADER_LENGTH 0x0000ffff
/**
* Capability TLV types
*
* %NFP_NET_CFG_TLV_TYPE_UNKNOWN:
* Special TLV type to catch bugs, should never be encountered. Drivers should
* treat encountering this type as error and refuse to probe.
*
* %NFP_NET_CFG_TLV_TYPE_RESERVED:
* Reserved space, may contain legacy fixed-offset fields, or be used for
* padding. The use of this type should be otherwise avoided.
*
* %NFP_NET_CFG_TLV_TYPE_END:
* Empty, end of TLV list. Must be the last TLV. Drivers will stop processing
* further TLVs when encountered.
*
* %NFP_NET_CFG_TLV_TYPE_ME_FREQ:
* Single word, ME frequency in MHz as used in calculation for
* %NFP_NET_CFG_RXR_IRQ_MOD and %NFP_NET_CFG_TXR_IRQ_MOD.
*
* %NFP_NET_CFG_TLV_TYPE_MBOX:
* Variable, mailbox area. Overwrites the default location which is
* %NFP_NET_CFG_MBOX_BASE and length %NFP_NET_CFG_MBOX_VAL_MAX_SZ.
*/
#define NFP_NET_CFG_TLV_TYPE_UNKNOWN 0
#define NFP_NET_CFG_TLV_TYPE_RESERVED 1
#define NFP_NET_CFG_TLV_TYPE_END 2
#define NFP_NET_CFG_TLV_TYPE_ME_FREQ 3
#define NFP_NET_CFG_TLV_TYPE_MBOX 4
struct device;
/**
* struct nfp_net_tlv_caps - parsed control BAR TLV capabilities
* @me_freq_mhz: ME clock_freq (MHz)
* @mbox_off: vNIC mailbox area offset
* @mbox_len: vNIC mailbox area length
*/
struct nfp_net_tlv_caps {
u32 me_freq_mhz;
unsigned int mbox_off;
unsigned int mbox_len;
};
int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem,
struct nfp_net_tlv_caps *caps);
static inline bool nfp_net_has_mbox(struct nfp_net_tlv_caps *caps)
{
return caps->mbox_len >= NFP_NET_CFG_MBOX_SIMPLE_LEN;
}
#endif /* _NFP_NET_CTRL_H_ */
......@@ -518,16 +518,15 @@ nfp_dump_csr_range(struct nfp_pf *pf, struct nfp_dumpspec_csr *spec_csr,
max_rd_addr = cpp_rd_addr + be32_to_cpu(spec_csr->cpp.dump_length);
while (cpp_rd_addr < max_rd_addr) {
if (is_xpb_read(&spec_csr->cpp.cpp_id))
bytes_read = nfp_xpb_readl(pf->cpp, cpp_rd_addr,
(u32 *)dest);
else
if (is_xpb_read(&spec_csr->cpp.cpp_id)) {
err = nfp_xpb_readl(pf->cpp, cpp_rd_addr, (u32 *)dest);
} else {
bytes_read = nfp_cpp_read(pf->cpp, cpp_id, cpp_rd_addr,
dest, reg_sz);
if (bytes_read != reg_sz) {
if (bytes_read >= 0)
bytes_read = -EIO;
dump_header->error = cpu_to_be32(bytes_read);
err = bytes_read == reg_sz ? 0 : -EIO;
}
if (err) {
dump_header->error = cpu_to_be32(err);
dump_header->error_offset = cpu_to_be32(cpp_rd_addr);
break;
}
......@@ -555,8 +554,8 @@ nfp_read_indirect_csr(struct nfp_cpp *cpp,
NFP_IND_ME_REFL_WR_SIG_INIT,
cpp_params.token, cpp_params.island);
result = nfp_cpp_writel(cpp, cpp_id, csr_ctx_ptr_offs, context);
if (result != sizeof(context))
return result < 0 ? result : -EIO;
if (result)
return result;
cpp_id = nfp_get_numeric_cpp_id(&cpp_params);
result = nfp_cpp_read(cpp, cpp_id, csr_ctx_ptr_offs, dest, reg_sz);
......
......@@ -208,12 +208,6 @@ nfp_net_pf_init_vnic(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id)
{
int err;
/* 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_init(nn);
if (err)
return err;
......@@ -373,7 +367,9 @@ nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride)
if (IS_ERR(pf->app))
return PTR_ERR(pf->app);
mutex_lock(&pf->lock);
err = nfp_app_init(pf->app);
mutex_unlock(&pf->lock);
if (err)
goto err_free;
......@@ -401,7 +397,9 @@ nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride)
err_unmap:
nfp_cpp_area_release_free(pf->ctrl_vnic_bar);
err_app_clean:
mutex_lock(&pf->lock);
nfp_app_clean(pf->app);
mutex_unlock(&pf->lock);
err_free:
nfp_app_free(pf->app);
pf->app = NULL;
......@@ -414,7 +412,11 @@ static void nfp_net_pf_app_clean(struct nfp_pf *pf)
nfp_net_pf_free_vnic(pf, pf->ctrl_vnic);
nfp_cpp_area_release_free(pf->ctrl_vnic_bar);
}
mutex_lock(&pf->lock);
nfp_app_clean(pf->app);
mutex_unlock(&pf->lock);
nfp_app_free(pf->app);
pf->app = NULL;
}
......@@ -570,17 +572,6 @@ static int nfp_net_pci_map_mem(struct nfp_pf *pf)
return err;
}
static void nfp_net_pci_remove_finish(struct nfp_pf *pf)
{
nfp_net_pf_app_stop(pf);
/* stop app first, to avoid double free of ctrl vNIC's ddir */
nfp_net_debugfs_dir_clean(&pf->ddir);
nfp_net_pf_free_irqs(pf);
nfp_net_pf_app_clean(pf);
nfp_net_pci_unmap_mem(pf);
}
static int
nfp_net_eth_port_update(struct nfp_cpp *cpp, struct nfp_port *port,
struct nfp_eth_table *eth_table)
......@@ -655,9 +646,6 @@ int nfp_net_refresh_port_table_sync(struct nfp_pf *pf)
nfp_net_pf_free_vnic(pf, nn);
}
if (list_empty(&pf->vnics))
nfp_net_pci_remove_finish(pf);
return 0;
}
......@@ -707,6 +695,7 @@ int nfp_net_refresh_eth_port(struct nfp_port *port)
*/
int nfp_net_pci_probe(struct nfp_pf *pf)
{
struct devlink *devlink = priv_to_devlink(pf);
struct nfp_net_fw_version fw_ver;
u8 __iomem *ctrl_bar, *qc_bar;
int stride;
......@@ -720,16 +709,13 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
return -EINVAL;
}
mutex_lock(&pf->lock);
pf->max_data_vnics = nfp_net_pf_get_num_ports(pf);
if ((int)pf->max_data_vnics < 0) {
err = pf->max_data_vnics;
goto err_unlock;
}
if ((int)pf->max_data_vnics < 0)
return pf->max_data_vnics;
err = nfp_net_pci_map_mem(pf);
if (err)
goto err_unlock;
return err;
ctrl_bar = nfp_cpp_area_iomem(pf->data_vnic_bar);
qc_bar = nfp_cpp_area_iomem(pf->qc_area);
......@@ -768,6 +754,11 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
if (err)
goto err_unmap;
err = devlink_register(devlink, &pf->pdev->dev);
if (err)
goto err_app_clean;
mutex_lock(&pf->lock);
pf->ddir = nfp_net_debugfs_device_add(pf->pdev);
/* Allocate the vnics and do basic init */
......@@ -799,32 +790,39 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
nfp_net_pf_free_vnics(pf);
err_clean_ddir:
nfp_net_debugfs_dir_clean(&pf->ddir);
mutex_unlock(&pf->lock);
cancel_work_sync(&pf->port_refresh_work);
devlink_unregister(devlink);
err_app_clean:
nfp_net_pf_app_clean(pf);
err_unmap:
nfp_net_pci_unmap_mem(pf);
err_unlock:
mutex_unlock(&pf->lock);
cancel_work_sync(&pf->port_refresh_work);
return err;
}
void nfp_net_pci_remove(struct nfp_pf *pf)
{
struct nfp_net *nn;
struct nfp_net *nn, *next;
mutex_lock(&pf->lock);
if (list_empty(&pf->vnics))
goto out;
list_for_each_entry(nn, &pf->vnics, vnic_list)
if (nfp_net_is_data_vnic(nn))
nfp_net_pf_clean_vnic(pf, nn);
list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list) {
if (!nfp_net_is_data_vnic(nn))
continue;
nfp_net_pf_clean_vnic(pf, nn);
nfp_net_pf_free_vnic(pf, nn);
}
nfp_net_pf_free_vnics(pf);
nfp_net_pf_app_stop(pf);
/* stop app first, to avoid double free of ctrl vNIC's ddir */
nfp_net_debugfs_dir_clean(&pf->ddir);
nfp_net_pci_remove_finish(pf);
out:
mutex_unlock(&pf->lock);
devlink_unregister(priv_to_devlink(pf));
nfp_net_pf_free_irqs(pf);
nfp_net_pf_app_clean(pf);
nfp_net_pci_unmap_mem(pf);
cancel_work_sync(&pf->port_refresh_work);
}
......@@ -46,6 +46,13 @@
#include "nfp_net_sriov.h"
#include "nfp_port.h"
struct net_device *
nfp_repr_get_locked(struct nfp_app *app, struct nfp_reprs *set, unsigned int id)
{
return rcu_dereference_protected(set->reprs[id],
lockdep_is_held(&app->pf->lock));
}
static void
nfp_repr_inc_tx_stats(struct net_device *netdev, unsigned int len,
int tx_status)
......@@ -369,21 +376,24 @@ static void nfp_repr_clean_and_free(struct nfp_repr *repr)
nfp_repr_free(repr);
}
void nfp_reprs_clean_and_free(struct nfp_reprs *reprs)
void nfp_reprs_clean_and_free(struct nfp_app *app, struct nfp_reprs *reprs)
{
struct net_device *netdev;
unsigned int i;
for (i = 0; i < reprs->num_reprs; i++)
if (reprs->reprs[i])
nfp_repr_clean_and_free(netdev_priv(reprs->reprs[i]));
for (i = 0; i < reprs->num_reprs; i++) {
netdev = nfp_repr_get_locked(app, reprs, i);
if (netdev)
nfp_repr_clean_and_free(netdev_priv(netdev));
}
kfree(reprs);
}
void
nfp_reprs_clean_and_free_by_type(struct nfp_app *app,
enum nfp_repr_type type)
nfp_reprs_clean_and_free_by_type(struct nfp_app *app, enum nfp_repr_type type)
{
struct net_device *netdev;
struct nfp_reprs *reprs;
int i;
......@@ -395,14 +405,16 @@ nfp_reprs_clean_and_free_by_type(struct nfp_app *app,
/* Preclean must happen before we remove the reprs reference from the
* app below.
*/
for (i = 0; i < reprs->num_reprs; i++)
if (reprs->reprs[i])
nfp_app_repr_preclean(app, reprs->reprs[i]);
for (i = 0; i < reprs->num_reprs; i++) {
netdev = nfp_repr_get_locked(app, reprs, i);
if (netdev)
nfp_app_repr_preclean(app, netdev);
}
reprs = nfp_app_reprs_set(app, type, NULL);
synchronize_rcu();
nfp_reprs_clean_and_free(reprs);
nfp_reprs_clean_and_free(app, reprs);
}
struct nfp_reprs *nfp_reprs_alloc(unsigned int num_reprs)
......@@ -420,48 +432,29 @@ struct nfp_reprs *nfp_reprs_alloc(unsigned int num_reprs)
int nfp_reprs_resync_phys_ports(struct nfp_app *app)
{
struct nfp_reprs *reprs, *old_reprs;
struct net_device *netdev;
struct nfp_reprs *reprs;
struct nfp_repr *repr;
int i;
old_reprs =
rcu_dereference_protected(app->reprs[NFP_REPR_TYPE_PHYS_PORT],
lockdep_is_held(&app->pf->lock));
if (!old_reprs)
return 0;
reprs = nfp_reprs_alloc(old_reprs->num_reprs);
reprs = nfp_reprs_get_locked(app, NFP_REPR_TYPE_PHYS_PORT);
if (!reprs)
return -ENOMEM;
for (i = 0; i < old_reprs->num_reprs; i++) {
if (!old_reprs->reprs[i])
continue;
repr = netdev_priv(old_reprs->reprs[i]);
if (repr->port->type == NFP_PORT_INVALID) {
nfp_app_repr_preclean(app, old_reprs->reprs[i]);
continue;
}
reprs->reprs[i] = old_reprs->reprs[i];
}
old_reprs = nfp_app_reprs_set(app, NFP_REPR_TYPE_PHYS_PORT, reprs);
synchronize_rcu();
return 0;
/* Now we free up removed representors */
for (i = 0; i < old_reprs->num_reprs; i++) {
if (!old_reprs->reprs[i])
for (i = 0; i < reprs->num_reprs; i++) {
netdev = nfp_repr_get_locked(app, reprs, i);
if (!netdev)
continue;
repr = netdev_priv(old_reprs->reprs[i]);
repr = netdev_priv(netdev);
if (repr->port->type != NFP_PORT_INVALID)
continue;
nfp_app_repr_preclean(app, netdev);
rcu_assign_pointer(reprs->reprs[i], NULL);
synchronize_rcu();
nfp_repr_clean(repr);
}
kfree(old_reprs);
return 0;
}
......@@ -35,6 +35,7 @@
#define NFP_NET_REPR_H
struct metadata_dst;
struct nfp_app;
struct nfp_net;
struct nfp_port;
......@@ -47,7 +48,7 @@ struct nfp_port;
*/
struct nfp_reprs {
unsigned int num_reprs;
struct net_device *reprs[0];
struct net_device __rcu *reprs[0];
};
/**
......@@ -114,16 +115,18 @@ static inline int nfp_repr_get_port_id(struct net_device *netdev)
return priv->dst->u.port_info.port_id;
}
struct net_device *
nfp_repr_get_locked(struct nfp_app *app, struct nfp_reprs *set,
unsigned int id);
void nfp_repr_inc_rx_stats(struct net_device *netdev, unsigned int len);
int nfp_repr_init(struct nfp_app *app, struct net_device *netdev,
u32 cmsg_port_id, struct nfp_port *port,
struct net_device *pf_netdev);
struct net_device *nfp_repr_alloc(struct nfp_app *app);
void
nfp_reprs_clean_and_free(struct nfp_reprs *reprs);
void
nfp_reprs_clean_and_free_by_type(struct nfp_app *app,
enum nfp_repr_type type);
void nfp_reprs_clean_and_free(struct nfp_app *app, struct nfp_reprs *reprs);
void nfp_reprs_clean_and_free_by_type(struct nfp_app *app,
enum nfp_repr_type type);
struct nfp_reprs *nfp_reprs_alloc(unsigned int num_reprs);
int nfp_reprs_resync_phys_ports(struct nfp_app *app);
......
......@@ -277,12 +277,6 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
}
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
* to get the value from nfp-hwinfo into ctrl bar
*/
nn->me_freq_mhz = 1200;
err = nfp_net_init(nn);
if (err)
goto err_irqs_disable;
......
......@@ -674,18 +674,20 @@ void __iomem *nfp_cpp_area_iomem(struct nfp_cpp_area *area)
* @offset: Offset into area
* @value: Pointer to read buffer
*
* Return: length of the io, or -ERRNO
* Return: 0 on success, or -ERRNO
*/
int nfp_cpp_area_readl(struct nfp_cpp_area *area,
unsigned long offset, u32 *value)
{
u8 tmp[4];
int err;
int n;
err = nfp_cpp_area_read(area, offset, &tmp, sizeof(tmp));
*value = get_unaligned_le32(tmp);
n = nfp_cpp_area_read(area, offset, &tmp, sizeof(tmp));
if (n != sizeof(tmp))
return n < 0 ? n : -EIO;
return err;
*value = get_unaligned_le32(tmp);
return 0;
}
/**
......@@ -694,16 +696,18 @@ int nfp_cpp_area_readl(struct nfp_cpp_area *area,
* @offset: Offset into area
* @value: Value to write
*
* Return: length of the io, or -ERRNO
* Return: 0 on success, or -ERRNO
*/
int nfp_cpp_area_writel(struct nfp_cpp_area *area,
unsigned long offset, u32 value)
{
u8 tmp[4];
int n;
put_unaligned_le32(value, tmp);
n = nfp_cpp_area_write(area, offset, &tmp, sizeof(tmp));
return nfp_cpp_area_write(area, offset, &tmp, sizeof(tmp));
return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
}
/**
......@@ -712,18 +716,20 @@ int nfp_cpp_area_writel(struct nfp_cpp_area *area,
* @offset: Offset into area
* @value: Pointer to read buffer
*
* Return: length of the io, or -ERRNO
* Return: 0 on success, or -ERRNO
*/
int nfp_cpp_area_readq(struct nfp_cpp_area *area,
unsigned long offset, u64 *value)
{
u8 tmp[8];
int err;
int n;
err = nfp_cpp_area_read(area, offset, &tmp, sizeof(tmp));
*value = get_unaligned_le64(tmp);
n = nfp_cpp_area_read(area, offset, &tmp, sizeof(tmp));
if (n != sizeof(tmp))
return n < 0 ? n : -EIO;
return err;
*value = get_unaligned_le64(tmp);
return 0;
}
/**
......@@ -732,16 +738,18 @@ int nfp_cpp_area_readq(struct nfp_cpp_area *area,
* @offset: Offset into area
* @value: Value to write
*
* Return: length of the io, or -ERRNO
* Return: 0 on success, or -ERRNO
*/
int nfp_cpp_area_writeq(struct nfp_cpp_area *area,
unsigned long offset, u64 value)
{
u8 tmp[8];
int n;
put_unaligned_le64(value, tmp);
n = nfp_cpp_area_write(area, offset, &tmp, sizeof(tmp));
return nfp_cpp_area_write(area, offset, &tmp, sizeof(tmp));
return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
}
/**
......@@ -1080,7 +1088,7 @@ static u32 nfp_xpb_to_cpp(struct nfp_cpp *cpp, u32 *xpb_addr)
* @xpb_addr: Address for operation
* @value: Pointer to read buffer
*
* Return: length of the io, or -ERRNO
* Return: 0 on success, or -ERRNO
*/
int nfp_xpb_readl(struct nfp_cpp *cpp, u32 xpb_addr, u32 *value)
{
......@@ -1095,7 +1103,7 @@ int nfp_xpb_readl(struct nfp_cpp *cpp, u32 xpb_addr, u32 *value)
* @xpb_addr: Address for operation
* @value: Value to write
*
* Return: length of the io, or -ERRNO
* Return: 0 on success, or -ERRNO
*/
int nfp_xpb_writel(struct nfp_cpp *cpp, u32 xpb_addr, u32 value)
{
......@@ -1113,7 +1121,7 @@ int nfp_xpb_writel(struct nfp_cpp *cpp, u32 xpb_addr, u32 value)
*
* KERNEL: This operation is safe to call in interrupt or softirq context.
*
* Return: length of the io, or -ERRNO
* Return: 0 on success, or -ERRNO
*/
int nfp_xpb_writelm(struct nfp_cpp *cpp, u32 xpb_tgt,
u32 mask, u32 value)
......
......@@ -64,18 +64,20 @@
* @address: Address for operation
* @value: Pointer to read buffer
*
* Return: length of the io, or -ERRNO
* Return: 0 on success, or -ERRNO
*/
int nfp_cpp_readl(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u32 *value)
{
u8 tmp[4];
int err;
int n;
err = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
*value = get_unaligned_le32(tmp);
n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
if (n != sizeof(tmp))
return n < 0 ? n : -EIO;
return err;
*value = get_unaligned_le32(tmp);
return 0;
}
/**
......@@ -85,15 +87,18 @@ int nfp_cpp_readl(struct nfp_cpp *cpp, u32 cpp_id,
* @address: Address for operation
* @value: Value to write
*
* Return: length of the io, or -ERRNO
* Return: 0 on success, or -ERRNO
*/
int nfp_cpp_writel(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u32 value)
{
u8 tmp[4];
int n;
put_unaligned_le32(value, tmp);
return nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
}
/**
......@@ -103,18 +108,20 @@ int nfp_cpp_writel(struct nfp_cpp *cpp, u32 cpp_id,
* @address: Address for operation
* @value: Pointer to read buffer
*
* Return: length of the io, or -ERRNO
* Return: 0 on success, or -ERRNO
*/
int nfp_cpp_readq(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u64 *value)
{
u8 tmp[8];
int err;
int n;
err = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
*value = get_unaligned_le64(tmp);
n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
if (n != sizeof(tmp))
return n < 0 ? n : -EIO;
return err;
*value = get_unaligned_le64(tmp);
return 0;
}
/**
......@@ -124,15 +131,18 @@ int nfp_cpp_readq(struct nfp_cpp *cpp, u32 cpp_id,
* @address: Address for operation
* @value: Value to write
*
* Return: length of the io, or -ERRNO
* Return: 0 on success, or -ERRNO
*/
int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u64 value)
{
u8 tmp[8];
int n;
put_unaligned_le64(value, tmp);
return nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
}
/* NOTE: This code should not use nfp_xpb_* functions,
......
......@@ -277,10 +277,6 @@ u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name,
break;
}
if (err == sym->size)
err = 0;
else if (err >= 0)
err = -EIO;
exit:
if (error)
*error = err;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册