Commit 1e2d0824 authored by Haiyang Zhang's avatar Haiyang Zhang Committed by David S. Miller

net: mana: Add support for EQ sharing

The existing code uses (1 + #vPorts * #Queues) MSIXs, which may exceed
the device limit.

Support EQ sharing, so that multiple vPorts (NICs) can share the same
set of MSIXs.

And, report the EQ-sharing capability bit to the host, which means the
host can potentially offer more vPorts and queues to the VM.

Also update the resource limit checking and error handling for better
robustness.

Now, we support up to 256 virtual ports per VF (it was 16/VF), and
support up to 64 queues per vPort (it was 16).
Signed-off-by: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e1b5683f
...@@ -312,9 +312,6 @@ struct gdma_queue_spec { ...@@ -312,9 +312,6 @@ struct gdma_queue_spec {
void *context; void *context;
unsigned long log2_throttle_limit; unsigned long log2_throttle_limit;
/* Only used by the MANA device. */
struct net_device *ndev;
} eq; } eq;
struct { struct {
...@@ -489,16 +486,28 @@ enum { ...@@ -489,16 +486,28 @@ enum {
GDMA_PROTOCOL_LAST = GDMA_PROTOCOL_V1, GDMA_PROTOCOL_LAST = GDMA_PROTOCOL_V1,
}; };
#define GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT BIT(0)
#define GDMA_DRV_CAP_FLAGS1 GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT
#define GDMA_DRV_CAP_FLAGS2 0
#define GDMA_DRV_CAP_FLAGS3 0
#define GDMA_DRV_CAP_FLAGS4 0
struct gdma_verify_ver_req { struct gdma_verify_ver_req {
struct gdma_req_hdr hdr; struct gdma_req_hdr hdr;
/* Mandatory fields required for protocol establishment */ /* Mandatory fields required for protocol establishment */
u64 protocol_ver_min; u64 protocol_ver_min;
u64 protocol_ver_max; u64 protocol_ver_max;
u64 drv_cap_flags1;
u64 drv_cap_flags2; /* Gdma Driver Capability Flags */
u64 drv_cap_flags3; u64 gd_drv_cap_flags1;
u64 drv_cap_flags4; u64 gd_drv_cap_flags2;
u64 gd_drv_cap_flags3;
u64 gd_drv_cap_flags4;
/* Advisory fields */ /* Advisory fields */
u64 drv_ver; u64 drv_ver;
......
...@@ -67,6 +67,10 @@ static int mana_gd_query_max_resources(struct pci_dev *pdev) ...@@ -67,6 +67,10 @@ static int mana_gd_query_max_resources(struct pci_dev *pdev)
if (gc->max_num_queues > resp.max_rq) if (gc->max_num_queues > resp.max_rq)
gc->max_num_queues = resp.max_rq; gc->max_num_queues = resp.max_rq;
/* The Hardware Channel (HWC) used 1 MSI-X */
if (gc->max_num_queues > gc->num_msix_usable - 1)
gc->max_num_queues = gc->num_msix_usable - 1;
return 0; return 0;
} }
...@@ -384,28 +388,31 @@ static int mana_gd_register_irq(struct gdma_queue *queue, ...@@ -384,28 +388,31 @@ static int mana_gd_register_irq(struct gdma_queue *queue,
struct gdma_resource *r; struct gdma_resource *r;
unsigned int msi_index; unsigned int msi_index;
unsigned long flags; unsigned long flags;
int err; struct device *dev;
int err = 0;
gc = gd->gdma_context; gc = gd->gdma_context;
r = &gc->msix_resource; r = &gc->msix_resource;
dev = gc->dev;
spin_lock_irqsave(&r->lock, flags); spin_lock_irqsave(&r->lock, flags);
msi_index = find_first_zero_bit(r->map, r->size); msi_index = find_first_zero_bit(r->map, r->size);
if (msi_index >= r->size) { if (msi_index >= r->size || msi_index >= gc->num_msix_usable) {
err = -ENOSPC; err = -ENOSPC;
} else { } else {
bitmap_set(r->map, msi_index, 1); bitmap_set(r->map, msi_index, 1);
queue->eq.msix_index = msi_index; queue->eq.msix_index = msi_index;
err = 0;
} }
spin_unlock_irqrestore(&r->lock, flags); spin_unlock_irqrestore(&r->lock, flags);
if (err) if (err) {
return err; dev_err(dev, "Register IRQ err:%d, msi:%u rsize:%u, nMSI:%u",
err, msi_index, r->size, gc->num_msix_usable);
WARN_ON(msi_index >= gc->num_msix_usable); return err;
}
gic = &gc->irq_contexts[msi_index]; gic = &gc->irq_contexts[msi_index];
...@@ -836,6 +843,11 @@ int mana_gd_verify_vf_version(struct pci_dev *pdev) ...@@ -836,6 +843,11 @@ int mana_gd_verify_vf_version(struct pci_dev *pdev)
req.protocol_ver_min = GDMA_PROTOCOL_FIRST; req.protocol_ver_min = GDMA_PROTOCOL_FIRST;
req.protocol_ver_max = GDMA_PROTOCOL_LAST; req.protocol_ver_max = GDMA_PROTOCOL_LAST;
req.gd_drv_cap_flags1 = GDMA_DRV_CAP_FLAGS1;
req.gd_drv_cap_flags2 = GDMA_DRV_CAP_FLAGS2;
req.gd_drv_cap_flags3 = GDMA_DRV_CAP_FLAGS3;
req.gd_drv_cap_flags4 = GDMA_DRV_CAP_FLAGS4;
err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp); err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp);
if (err || resp.hdr.status) { if (err || resp.hdr.status) {
dev_err(gc->dev, "VfVerifyVersionOutput: %d, status=0x%x\n", dev_err(gc->dev, "VfVerifyVersionOutput: %d, status=0x%x\n",
...@@ -1154,10 +1166,8 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) ...@@ -1154,10 +1166,8 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
if (max_queues_per_port > MANA_MAX_NUM_QUEUES) if (max_queues_per_port > MANA_MAX_NUM_QUEUES)
max_queues_per_port = MANA_MAX_NUM_QUEUES; max_queues_per_port = MANA_MAX_NUM_QUEUES;
max_irqs = max_queues_per_port * MAX_PORTS_IN_MANA_DEV;
/* Need 1 interrupt for the Hardware communication Channel (HWC) */ /* Need 1 interrupt for the Hardware communication Channel (HWC) */
max_irqs++; max_irqs = max_queues_per_port + 1;
nvec = pci_alloc_irq_vectors(pdev, 2, max_irqs, PCI_IRQ_MSIX); nvec = pci_alloc_irq_vectors(pdev, 2, max_irqs, PCI_IRQ_MSIX);
if (nvec < 0) if (nvec < 0)
...@@ -1244,6 +1254,9 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1244,6 +1254,9 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
int bar = 0; int bar = 0;
int err; int err;
/* Each port has 2 CQs, each CQ has at most 1 EQE at a time */
BUILD_BUG_ON(2 * MAX_PORTS_IN_MANA_DEV * GDMA_EQE_SIZE > EQ_SIZE);
err = pci_enable_device(pdev); err = pci_enable_device(pdev);
if (err) if (err)
return -ENXIO; return -ENXIO;
......
...@@ -46,7 +46,7 @@ enum TRI_STATE { ...@@ -46,7 +46,7 @@ enum TRI_STATE {
#define EQ_SIZE (8 * PAGE_SIZE) #define EQ_SIZE (8 * PAGE_SIZE)
#define LOG2_EQ_THROTTLE 3 #define LOG2_EQ_THROTTLE 3
#define MAX_PORTS_IN_MANA_DEV 16 #define MAX_PORTS_IN_MANA_DEV 256
struct mana_stats { struct mana_stats {
u64 packets; u64 packets;
...@@ -322,6 +322,8 @@ struct mana_context { ...@@ -322,6 +322,8 @@ struct mana_context {
u16 num_ports; u16 num_ports;
struct mana_eq *eqs;
struct net_device *ports[MAX_PORTS_IN_MANA_DEV]; struct net_device *ports[MAX_PORTS_IN_MANA_DEV];
}; };
...@@ -331,8 +333,6 @@ struct mana_port_context { ...@@ -331,8 +333,6 @@ struct mana_port_context {
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
struct mana_eq *eqs;
enum TRI_STATE rss_state; enum TRI_STATE rss_state;
mana_handle_t default_rxobj; mana_handle_t default_rxobj;
...@@ -402,11 +402,11 @@ enum mana_command_code { ...@@ -402,11 +402,11 @@ enum mana_command_code {
struct mana_query_device_cfg_req { struct mana_query_device_cfg_req {
struct gdma_req_hdr hdr; struct gdma_req_hdr hdr;
/* Driver Capability flags */ /* MANA Nic Driver Capability flags */
u64 drv_cap_flags1; u64 mn_drv_cap_flags1;
u64 drv_cap_flags2; u64 mn_drv_cap_flags2;
u64 drv_cap_flags3; u64 mn_drv_cap_flags3;
u64 drv_cap_flags4; u64 mn_drv_cap_flags4;
u32 proto_major_ver; u32 proto_major_ver;
u32 proto_minor_ver; u32 proto_minor_ver;
...@@ -523,7 +523,7 @@ struct mana_cfg_rx_steer_resp { ...@@ -523,7 +523,7 @@ struct mana_cfg_rx_steer_resp {
struct gdma_resp_hdr hdr; struct gdma_resp_hdr hdr;
}; /* HW DATA */ }; /* HW DATA */
#define MANA_MAX_NUM_QUEUES 16 #define MANA_MAX_NUM_QUEUES 64
#define MANA_SHORT_VPORT_OFFSET_MAX ((1U << 8) - 1) #define MANA_SHORT_VPORT_OFFSET_MAX ((1U << 8) - 1)
......
...@@ -696,56 +696,56 @@ static void mana_destroy_wq_obj(struct mana_port_context *apc, u32 wq_type, ...@@ -696,56 +696,56 @@ static void mana_destroy_wq_obj(struct mana_port_context *apc, u32 wq_type,
resp.hdr.status); resp.hdr.status);
} }
static void mana_destroy_eq(struct gdma_context *gc, static void mana_destroy_eq(struct mana_context *ac)
struct mana_port_context *apc)
{ {
struct gdma_context *gc = ac->gdma_dev->gdma_context;
struct gdma_queue *eq; struct gdma_queue *eq;
int i; int i;
if (!apc->eqs) if (!ac->eqs)
return; return;
for (i = 0; i < apc->num_queues; i++) { for (i = 0; i < gc->max_num_queues; i++) {
eq = apc->eqs[i].eq; eq = ac->eqs[i].eq;
if (!eq) if (!eq)
continue; continue;
mana_gd_destroy_queue(gc, eq); mana_gd_destroy_queue(gc, eq);
} }
kfree(apc->eqs); kfree(ac->eqs);
apc->eqs = NULL; ac->eqs = NULL;
} }
static int mana_create_eq(struct mana_port_context *apc) static int mana_create_eq(struct mana_context *ac)
{ {
struct gdma_dev *gd = apc->ac->gdma_dev; struct gdma_dev *gd = ac->gdma_dev;
struct gdma_context *gc = gd->gdma_context;
struct gdma_queue_spec spec = {}; struct gdma_queue_spec spec = {};
int err; int err;
int i; int i;
apc->eqs = kcalloc(apc->num_queues, sizeof(struct mana_eq), ac->eqs = kcalloc(gc->max_num_queues, sizeof(struct mana_eq),
GFP_KERNEL); GFP_KERNEL);
if (!apc->eqs) if (!ac->eqs)
return -ENOMEM; return -ENOMEM;
spec.type = GDMA_EQ; spec.type = GDMA_EQ;
spec.monitor_avl_buf = false; spec.monitor_avl_buf = false;
spec.queue_size = EQ_SIZE; spec.queue_size = EQ_SIZE;
spec.eq.callback = NULL; spec.eq.callback = NULL;
spec.eq.context = apc->eqs; spec.eq.context = ac->eqs;
spec.eq.log2_throttle_limit = LOG2_EQ_THROTTLE; spec.eq.log2_throttle_limit = LOG2_EQ_THROTTLE;
spec.eq.ndev = apc->ndev;
for (i = 0; i < apc->num_queues; i++) { for (i = 0; i < gc->max_num_queues; i++) {
err = mana_gd_create_mana_eq(gd, &spec, &apc->eqs[i].eq); err = mana_gd_create_mana_eq(gd, &spec, &ac->eqs[i].eq);
if (err) if (err)
goto out; goto out;
} }
return 0; return 0;
out: out:
mana_destroy_eq(gd->gdma_context, apc); mana_destroy_eq(ac);
return err; return err;
} }
...@@ -1157,7 +1157,8 @@ static void mana_destroy_txq(struct mana_port_context *apc) ...@@ -1157,7 +1157,8 @@ static void mana_destroy_txq(struct mana_port_context *apc)
static int mana_create_txq(struct mana_port_context *apc, static int mana_create_txq(struct mana_port_context *apc,
struct net_device *net) struct net_device *net)
{ {
struct gdma_dev *gd = apc->ac->gdma_dev; struct mana_context *ac = apc->ac;
struct gdma_dev *gd = ac->gdma_dev;
struct mana_obj_spec wq_spec; struct mana_obj_spec wq_spec;
struct mana_obj_spec cq_spec; struct mana_obj_spec cq_spec;
struct gdma_queue_spec spec; struct gdma_queue_spec spec;
...@@ -1218,7 +1219,7 @@ static int mana_create_txq(struct mana_port_context *apc, ...@@ -1218,7 +1219,7 @@ static int mana_create_txq(struct mana_port_context *apc,
spec.monitor_avl_buf = false; spec.monitor_avl_buf = false;
spec.queue_size = cq_size; spec.queue_size = cq_size;
spec.cq.callback = mana_schedule_napi; spec.cq.callback = mana_schedule_napi;
spec.cq.parent_eq = apc->eqs[i].eq; spec.cq.parent_eq = ac->eqs[i].eq;
spec.cq.context = cq; spec.cq.context = cq;
err = mana_gd_create_mana_wq_cq(gd, &spec, &cq->gdma_cq); err = mana_gd_create_mana_wq_cq(gd, &spec, &cq->gdma_cq);
if (err) if (err)
...@@ -1502,12 +1503,13 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc, ...@@ -1502,12 +1503,13 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
static int mana_add_rx_queues(struct mana_port_context *apc, static int mana_add_rx_queues(struct mana_port_context *apc,
struct net_device *ndev) struct net_device *ndev)
{ {
struct mana_context *ac = apc->ac;
struct mana_rxq *rxq; struct mana_rxq *rxq;
int err = 0; int err = 0;
int i; int i;
for (i = 0; i < apc->num_queues; i++) { for (i = 0; i < apc->num_queues; i++) {
rxq = mana_create_rxq(apc, i, &apc->eqs[i], ndev); rxq = mana_create_rxq(apc, i, &ac->eqs[i], ndev);
if (!rxq) { if (!rxq) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
...@@ -1619,16 +1621,11 @@ static int mana_init_port(struct net_device *ndev) ...@@ -1619,16 +1621,11 @@ static int mana_init_port(struct net_device *ndev)
int mana_alloc_queues(struct net_device *ndev) int mana_alloc_queues(struct net_device *ndev)
{ {
struct mana_port_context *apc = netdev_priv(ndev); struct mana_port_context *apc = netdev_priv(ndev);
struct gdma_dev *gd = apc->ac->gdma_dev;
int err; int err;
err = mana_create_eq(apc);
if (err)
return err;
err = mana_create_vport(apc, ndev); err = mana_create_vport(apc, ndev);
if (err) if (err)
goto destroy_eq; return err;
err = netif_set_real_num_tx_queues(ndev, apc->num_queues); err = netif_set_real_num_tx_queues(ndev, apc->num_queues);
if (err) if (err)
...@@ -1654,8 +1651,6 @@ int mana_alloc_queues(struct net_device *ndev) ...@@ -1654,8 +1651,6 @@ int mana_alloc_queues(struct net_device *ndev)
destroy_vport: destroy_vport:
mana_destroy_vport(apc); mana_destroy_vport(apc);
destroy_eq:
mana_destroy_eq(gd->gdma_context, apc);
return err; return err;
} }
...@@ -1732,8 +1727,6 @@ static int mana_dealloc_queues(struct net_device *ndev) ...@@ -1732,8 +1727,6 @@ static int mana_dealloc_queues(struct net_device *ndev)
mana_destroy_vport(apc); mana_destroy_vport(apc);
mana_destroy_eq(apc->ac->gdma_dev->gdma_context, apc);
return 0; return 0;
} }
...@@ -1786,7 +1779,7 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, ...@@ -1786,7 +1779,7 @@ static int mana_probe_port(struct mana_context *ac, int port_idx,
apc->ac = ac; apc->ac = ac;
apc->ndev = ndev; apc->ndev = ndev;
apc->max_queues = gc->max_num_queues; apc->max_queues = gc->max_num_queues;
apc->num_queues = min_t(uint, gc->max_num_queues, MANA_MAX_NUM_QUEUES); apc->num_queues = gc->max_num_queues;
apc->port_handle = INVALID_MANA_HANDLE; apc->port_handle = INVALID_MANA_HANDLE;
apc->port_idx = port_idx; apc->port_idx = port_idx;
...@@ -1857,6 +1850,10 @@ int mana_probe(struct gdma_dev *gd) ...@@ -1857,6 +1850,10 @@ int mana_probe(struct gdma_dev *gd)
ac->num_ports = 1; ac->num_ports = 1;
gd->driver_data = ac; gd->driver_data = ac;
err = mana_create_eq(ac);
if (err)
goto out;
err = mana_query_device_cfg(ac, MANA_MAJOR_VERSION, MANA_MINOR_VERSION, err = mana_query_device_cfg(ac, MANA_MAJOR_VERSION, MANA_MINOR_VERSION,
MANA_MICRO_VERSION, &ac->num_ports); MANA_MICRO_VERSION, &ac->num_ports);
if (err) if (err)
...@@ -1906,6 +1903,9 @@ void mana_remove(struct gdma_dev *gd) ...@@ -1906,6 +1903,9 @@ void mana_remove(struct gdma_dev *gd)
free_netdev(ndev); free_netdev(ndev);
} }
mana_destroy_eq(ac);
out: out:
mana_gd_deregister_device(gd); mana_gd_deregister_device(gd);
gd->driver_data = NULL; gd->driver_data = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment