Skip to content

Commit

Permalink
nfp: allocate irqs in lower driver
Browse files Browse the repository at this point in the history
PF services multiple ports using single PCI device therefore
IRQs can no longer be allocated in the netdev code.  Lower
portion of the driver has to allocate the IRQs and hand them
out to ports.

Signed-off-by: Jakub Kicinski <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Jakub Kicinski authored and davem330 committed Feb 10, 2017
1 parent 6f1cd5c commit fdace6c
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 99 deletions.
17 changes: 13 additions & 4 deletions drivers/net/ethernet/netronome/nfp/nfp_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,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 */
Expand Down Expand Up @@ -345,7 +346,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
Expand All @@ -362,6 +363,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
Expand All @@ -378,7 +380,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;
Expand All @@ -400,6 +402,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;
Expand Down Expand Up @@ -788,8 +791,14 @@ 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);
Expand Down
144 changes: 73 additions & 71 deletions drivers/net/ethernet/netronome/nfp/nfp_net_common.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* 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
Expand Down Expand Up @@ -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);
}

/**
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand All @@ -1997,29 +1999,29 @@ 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;
}

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

/**
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
}
Expand Down
Loading

0 comments on commit fdace6c

Please sign in to comment.