Skip to content

Commit

Permalink
Merge branch 'nfp-dma-adjust_head-fixes'
Browse files Browse the repository at this point in the history
Jakub Kicinski says:

====================
nfp: DMA flags, adjust head and fixes

This series takes advantage of Alex's DMA_ATTR_SKIP_CPU_SYNC to make
XDP packet modifications "correct" from DMA API point of view.  It
also allows us to parse the metadata before we run XDP at no additional
DMA sync cost.  That way we can get rid of the metadata memcpy, and
remove the last upstream user of bpf_prog->xdp_adjust_head.

David's patch adds a way to read capabilities from the management
firmware.

There are also two net-next fixes.  Patch 4 which fixes what seems to
be a result of a botched rebase on my part.  Patch 5 corrects locking
when state of ethernet ports is being refreshed.

v3: move the sync from alloc func to the actual give to hw func
v2: sync rx buffers before giving them to the card (Alex)
====================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Apr 24, 2017
2 parents 0d688a0 + 90fdc56 commit 09d3607
Show file tree
Hide file tree
Showing 10 changed files with 265 additions and 78 deletions.
1 change: 1 addition & 0 deletions drivers/net/ethernet/netronome/nfp/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ nfp-objs := \
nfpcore/nfp_mutex.o \
nfpcore/nfp_nffw.o \
nfpcore/nfp_nsp.o \
nfpcore/nfp_nsp_cmds.o \
nfpcore/nfp_nsp_eth.o \
nfpcore/nfp_resource.o \
nfpcore/nfp_rtsym.o \
Expand Down
7 changes: 7 additions & 0 deletions drivers/net/ethernet/netronome/nfp/nfp_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ nfp_fw_load(struct pci_dev *pdev, struct nfp_pf *pf, struct nfp_nsp *nsp)

static int nfp_nsp_init(struct pci_dev *pdev, struct nfp_pf *pf)
{
struct nfp_nsp_identify *nspi;
struct nfp_nsp *nsp;
int err;

Expand All @@ -269,6 +270,12 @@ static int nfp_nsp_init(struct pci_dev *pdev, struct nfp_pf *pf)

pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp);

nspi = __nfp_nsp_identify(nsp);
if (nspi) {
dev_info(&pdev->dev, "BSP: %s\n", nspi->version);
kfree(nspi);
}

err = nfp_fw_load(pdev, pf, nsp);
if (err < 0) {
kfree(pf->eth_tbl);
Expand Down
9 changes: 8 additions & 1 deletion drivers/net/ethernet/netronome/nfp/nfp_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,12 @@ struct nfp_net_rx_desc {

#define NFP_NET_META_FIELD_MASK GENMASK(NFP_NET_META_FIELD_SIZE - 1, 0)

struct nfp_meta_parsed {
u32 hash_type;
u32 hash;
u32 mark;
};

struct nfp_net_rx_hash {
__be32 hash_type;
__be32 hash;
Expand Down Expand Up @@ -813,7 +819,8 @@ struct nfp_net_dp *nfp_net_clone_dp(struct nfp_net *nn);
int nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_dp *new);

bool nfp_net_link_changed_read_clear(struct nfp_net *nn);
void nfp_net_refresh_port_config(struct nfp_net *nn);
int nfp_net_refresh_eth_port(struct nfp_net *nn);
void nfp_net_refresh_port_table(struct nfp_net *nn);

#ifdef CONFIG_NFP_DEBUG
void nfp_net_debugfs_create(void);
Expand Down
125 changes: 72 additions & 53 deletions drivers/net/ethernet/netronome/nfp/nfp_net_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,31 @@ void nfp_net_get_fw_version(struct nfp_net_fw_version *fw_ver,

static dma_addr_t nfp_net_dma_map_rx(struct nfp_net_dp *dp, void *frag)
{
return dma_map_single(dp->dev, frag + NFP_NET_RX_BUF_HEADROOM,
dp->fl_bufsz - NFP_NET_RX_BUF_NON_DATA,
dp->rx_dma_dir);
return dma_map_single_attrs(dp->dev, frag + NFP_NET_RX_BUF_HEADROOM,
dp->fl_bufsz - NFP_NET_RX_BUF_NON_DATA,
dp->rx_dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
}

static void
nfp_net_dma_sync_dev_rx(const struct nfp_net_dp *dp, dma_addr_t dma_addr)
{
dma_sync_single_for_device(dp->dev, dma_addr,
dp->fl_bufsz - NFP_NET_RX_BUF_NON_DATA,
dp->rx_dma_dir);
}

static void nfp_net_dma_unmap_rx(struct nfp_net_dp *dp, dma_addr_t dma_addr)
{
dma_unmap_single(dp->dev, dma_addr,
dp->fl_bufsz - NFP_NET_RX_BUF_NON_DATA,
dp->rx_dma_dir);
dma_unmap_single_attrs(dp->dev, dma_addr,
dp->fl_bufsz - NFP_NET_RX_BUF_NON_DATA,
dp->rx_dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
}

static void nfp_net_dma_sync_cpu_rx(struct nfp_net_dp *dp, dma_addr_t dma_addr,
unsigned int len)
{
dma_sync_single_for_cpu(dp->dev, dma_addr - NFP_NET_RX_BUF_HEADROOM,
len, dp->rx_dma_dir);
}

/* Firmware reconfig
Expand Down Expand Up @@ -1208,6 +1223,8 @@ static void nfp_net_rx_give_one(const struct nfp_net_dp *dp,

wr_idx = rx_ring->wr_p & (rx_ring->cnt - 1);

nfp_net_dma_sync_dev_rx(dp, dma_addr);

/* Stash SKB and DMA address away */
rx_ring->rxbufs[wr_idx].frag = frag;
rx_ring->rxbufs[wr_idx].dma_addr = dma_addr;
Expand Down Expand Up @@ -1385,8 +1402,9 @@ static void nfp_net_rx_csum(struct nfp_net_dp *dp,
}
}

static void nfp_net_set_hash(struct net_device *netdev, struct sk_buff *skb,
unsigned int type, __be32 *hash)
static void
nfp_net_set_hash(struct net_device *netdev, struct nfp_meta_parsed *meta,
unsigned int type, __be32 *hash)
{
if (!(netdev->features & NETIF_F_RXHASH))
return;
Expand All @@ -1395,29 +1413,31 @@ static void nfp_net_set_hash(struct net_device *netdev, struct sk_buff *skb,
case NFP_NET_RSS_IPV4:
case NFP_NET_RSS_IPV6:
case NFP_NET_RSS_IPV6_EX:
skb_set_hash(skb, get_unaligned_be32(hash), PKT_HASH_TYPE_L3);
meta->hash_type = PKT_HASH_TYPE_L3;
break;
default:
skb_set_hash(skb, get_unaligned_be32(hash), PKT_HASH_TYPE_L4);
meta->hash_type = PKT_HASH_TYPE_L4;
break;
}

meta->hash = get_unaligned_be32(hash);
}

static void
nfp_net_set_hash_desc(struct net_device *netdev, struct sk_buff *skb,
nfp_net_set_hash_desc(struct net_device *netdev, struct nfp_meta_parsed *meta,
void *data, struct nfp_net_rx_desc *rxd)
{
struct nfp_net_rx_hash *rx_hash = data;

if (!(rxd->rxd.flags & PCIE_DESC_RX_RSS))
return;

nfp_net_set_hash(netdev, skb, get_unaligned_be32(&rx_hash->hash_type),
nfp_net_set_hash(netdev, meta, get_unaligned_be32(&rx_hash->hash_type),
&rx_hash->hash);
}

static void *
nfp_net_parse_meta(struct net_device *netdev, struct sk_buff *skb,
nfp_net_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
void *data, int meta_len)
{
u32 meta_info;
Expand All @@ -1429,13 +1449,13 @@ nfp_net_parse_meta(struct net_device *netdev, struct sk_buff *skb,
switch (meta_info & NFP_NET_META_FIELD_MASK) {
case NFP_NET_META_HASH:
meta_info >>= NFP_NET_META_FIELD_SIZE;
nfp_net_set_hash(netdev, skb,
nfp_net_set_hash(netdev, meta,
meta_info & NFP_NET_META_FIELD_MASK,
(__be32 *)data);
data += 4;
break;
case NFP_NET_META_MARK:
skb->mark = get_unaligned_be32(data);
meta->mark = get_unaligned_be32(data);
data += 4;
break;
default:
Expand Down Expand Up @@ -1569,13 +1589,12 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
tx_ring = r_vec->xdp_ring;

while (pkts_polled < budget) {
unsigned int meta_len, data_len, data_off, pkt_len;
u8 meta_prepend[NFP_NET_MAX_PREPEND];
unsigned int meta_len, data_len, meta_off, pkt_len, pkt_off;
struct nfp_net_rx_buf *rxbuf;
struct nfp_net_rx_desc *rxd;
struct nfp_meta_parsed meta;
dma_addr_t new_dma_addr;
void *new_frag;
u8 *meta;

idx = rx_ring->rd_p & (rx_ring->cnt - 1);

Expand All @@ -1588,6 +1607,8 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
*/
dma_rmb();

memset(&meta, 0, sizeof(meta));

rx_ring->rd_p++;
pkts_polled++;

Expand All @@ -1608,21 +1629,19 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
data_len = le16_to_cpu(rxd->rxd.data_len);
pkt_len = data_len - meta_len;

pkt_off = NFP_NET_RX_BUF_HEADROOM + dp->rx_dma_off;
if (dp->rx_offset == NFP_NET_CFG_RX_OFFSET_DYNAMIC)
data_off = NFP_NET_RX_BUF_HEADROOM + meta_len;
pkt_off += meta_len;
else
data_off = NFP_NET_RX_BUF_HEADROOM + dp->rx_offset;
data_off += dp->rx_dma_off;
pkt_off += dp->rx_offset;
meta_off = pkt_off - meta_len;

/* Stats update */
u64_stats_update_begin(&r_vec->rx_sync);
r_vec->rx_pkts++;
r_vec->rx_bytes += pkt_len;
u64_stats_update_end(&r_vec->rx_sync);

/* Pointer to start of metadata */
meta = rxbuf->frag + data_off - meta_len;

if (unlikely(meta_len > NFP_NET_MAX_PREPEND ||
(dp->rx_offset && meta_len > dp->rx_offset))) {
nn_dp_warn(dp, "oversized RX packet metadata %u\n",
Expand All @@ -1631,31 +1650,41 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
continue;
}

nfp_net_dma_sync_cpu_rx(dp, rxbuf->dma_addr + meta_off,
data_len);

if (!dp->chained_metadata_format) {
nfp_net_set_hash_desc(dp->netdev, &meta,
rxbuf->frag + meta_off, rxd);
} else if (meta_len) {
void *end;

end = nfp_net_parse_meta(dp->netdev, &meta,
rxbuf->frag + meta_off,
meta_len);
if (unlikely(end != rxbuf->frag + pkt_off)) {
nn_dp_warn(dp, "invalid RX packet metadata\n");
nfp_net_rx_drop(dp, r_vec, rx_ring, rxbuf,
NULL);
continue;
}
}

if (xdp_prog && !(rxd->rxd.flags & PCIE_DESC_RX_BPF &&
dp->bpf_offload_xdp)) {
unsigned int dma_off;
void *hard_start;
int act;

hard_start = rxbuf->frag + NFP_NET_RX_BUF_HEADROOM;
dma_off = data_off - NFP_NET_RX_BUF_HEADROOM;
dma_sync_single_for_cpu(dp->dev, rxbuf->dma_addr,
dma_off + pkt_len,
DMA_BIDIRECTIONAL);

/* Move prepend out of the way */
if (xdp_prog->xdp_adjust_head) {
memcpy(meta_prepend, meta, meta_len);
meta = meta_prepend;
}

act = nfp_net_run_xdp(xdp_prog, rxbuf->frag, hard_start,
&data_off, &pkt_len);
&pkt_off, &pkt_len);
switch (act) {
case XDP_PASS:
break;
case XDP_TX:
dma_off = data_off - NFP_NET_RX_BUF_HEADROOM;
dma_off = pkt_off - NFP_NET_RX_BUF_HEADROOM;
if (unlikely(!nfp_net_tx_xdp_buf(dp, rx_ring,
tx_ring, rxbuf,
dma_off,
Expand Down Expand Up @@ -1689,22 +1718,11 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)

nfp_net_rx_give_one(dp, rx_ring, new_frag, new_dma_addr);

skb_reserve(skb, data_off);
skb_reserve(skb, pkt_off);
skb_put(skb, pkt_len);

if (!dp->chained_metadata_format) {
nfp_net_set_hash_desc(dp->netdev, skb, meta, rxd);
} else if (meta_len) {
void *end;

end = nfp_net_parse_meta(dp->netdev, skb, meta,
meta_len);
if (unlikely(end != meta + meta_len)) {
nn_dp_warn(dp, "invalid RX packet metadata\n");
nfp_net_rx_drop(dp, r_vec, rx_ring, NULL, skb);
continue;
}
}
skb->mark = meta.mark;
skb_set_hash(skb, meta.hash, meta.hash_type);

skb_record_rx_queue(skb, rx_ring->idx);
skb->protocol = eth_type_trans(skb, dp->netdev);
Expand Down Expand Up @@ -2147,7 +2165,7 @@ nfp_net_tx_ring_hw_cfg_write(struct nfp_net *nn,
*/
static int nfp_net_set_config_and_enable(struct nfp_net *nn)
{
u32 new_ctrl, update = 0;
u32 bufsz, new_ctrl, update = 0;
unsigned int r;
int err;

Expand Down Expand Up @@ -2181,8 +2199,9 @@ static int nfp_net_set_config_and_enable(struct nfp_net *nn)
nfp_net_write_mac_addr(nn);

nn_writel(nn, NFP_NET_CFG_MTU, nn->dp.netdev->mtu);
nn_writel(nn, NFP_NET_CFG_FLBUFSZ,
nn->dp.fl_bufsz - NFP_NET_RX_BUF_NON_DATA);

bufsz = nn->dp.fl_bufsz - nn->dp.rx_dma_off - NFP_NET_RX_BUF_NON_DATA;
nn_writel(nn, NFP_NET_CFG_FLBUFSZ, bufsz);

/* Enable device */
new_ctrl |= NFP_NET_CFG_CTRL_ENABLE;
Expand Down
13 changes: 9 additions & 4 deletions drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,15 @@ nfp_net_get_link_ksettings(struct net_device *netdev,
return 0;

/* Use link speed from ETH table if available, otherwise try the BAR */
if (nn->eth_port && nfp_net_link_changed_read_clear(nn))
nfp_net_refresh_port_config(nn);
/* Separate if - on FW error the port could've disappeared from table */
if (nn->eth_port) {
int err;

if (nfp_net_link_changed_read_clear(nn)) {
err = nfp_net_refresh_eth_port(nn);
if (err)
return err;
}

cmd->base.port = nn->eth_port->port_type;
cmd->base.speed = nn->eth_port->speed;
cmd->base.duplex = DUPLEX_FULL;
Expand Down Expand Up @@ -273,7 +278,7 @@ nfp_net_set_link_ksettings(struct net_device *netdev,
if (err > 0)
return 0; /* no change */

nfp_net_refresh_port_config(nn);
nfp_net_refresh_port_table(nn);

return err;

Expand Down
Loading

0 comments on commit 09d3607

Please sign in to comment.