IB/hfi1: Rework AIP and VNIC dummy netdev usage
All other users of the dummy netdevice embed the netdev in other
structures:
init_dummy_netdev(&mal->dummy_dev);
init_dummy_netdev(ð->dummy_dev);
init_dummy_netdev(&ar->napi_dev);
init_dummy_netdev(&irq_grp->napi_ndev);
init_dummy_netdev(&wil->napi_ndev);
init_dummy_netdev(&trans_pcie->napi_dev);
init_dummy_netdev(&dev->napi_dev);
init_dummy_netdev(&bus->mux_dev);
The AIP and VNIC implementation turns that model inside out and used a
kfree() to free what appears to be a netdev struct when in reality, it is
a struct that enbodies the rx state as well as the dummy netdev used to
support napi_poll across disparate receive contexts. The relationship is
infered by the odd allocation:
const int netdev_size = sizeof(*dd->dummy_netdev) +
sizeof(struct hfi1_netdev_priv);
<snip>
dd->dummy_netdev = kcalloc_node(1, netdev_size, GFP_KERNEL, dd->node);
Correct the issue by:
- Correctly naming the alloc and free functions
- Renaming hfi1_netdev_priv to hfi1_netdev_rx
- Replacing dd dummy_netdev with a netdev_rx pointer
- Embedding the net_device in hfi1_netdev_rx
- Moving the init_dummy_netdev to the alloc routine
- Adjusting wrappers to fit the new model
Fixes: 6991abcb99 ("IB/hfi1: Add functions to receive accelerated ipoib packets")
Link: https://lore.kernel.org/r/1617026056-50483-11-git-send-email-dennis.dalessandro@cornelisnetworks.com
Reviewed-by: Kaike Wan <kaike.wan@intel.com>
Signed-off-by: Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
Signed-off-by: Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
This commit is contained in:
committed by
Jason Gunthorpe
parent
9c8823e0d3
commit
780278c2c8
@@ -15243,8 +15243,8 @@ int hfi1_init_dd(struct hfi1_devdata *dd)
|
|||||||
(dd->revision >> CCE_REVISION_SW_SHIFT)
|
(dd->revision >> CCE_REVISION_SW_SHIFT)
|
||||||
& CCE_REVISION_SW_MASK);
|
& CCE_REVISION_SW_MASK);
|
||||||
|
|
||||||
/* alloc netdev data */
|
/* alloc VNIC/AIP rx data */
|
||||||
ret = hfi1_netdev_alloc(dd);
|
ret = hfi1_alloc_rx(dd);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto bail_cleanup;
|
goto bail_cleanup;
|
||||||
|
|
||||||
@@ -15348,7 +15348,7 @@ bail_clear_intr:
|
|||||||
hfi1_comp_vectors_clean_up(dd);
|
hfi1_comp_vectors_clean_up(dd);
|
||||||
msix_clean_up_interrupts(dd);
|
msix_clean_up_interrupts(dd);
|
||||||
bail_cleanup:
|
bail_cleanup:
|
||||||
hfi1_netdev_free(dd);
|
hfi1_free_rx(dd);
|
||||||
hfi1_pcie_ddcleanup(dd);
|
hfi1_pcie_ddcleanup(dd);
|
||||||
bail_free:
|
bail_free:
|
||||||
hfi1_free_devdata(dd);
|
hfi1_free_devdata(dd);
|
||||||
|
|||||||
@@ -69,7 +69,6 @@
|
|||||||
#include <rdma/ib_hdrs.h>
|
#include <rdma/ib_hdrs.h>
|
||||||
#include <rdma/opa_addr.h>
|
#include <rdma/opa_addr.h>
|
||||||
#include <linux/rhashtable.h>
|
#include <linux/rhashtable.h>
|
||||||
#include <linux/netdevice.h>
|
|
||||||
#include <rdma/rdma_vt.h>
|
#include <rdma/rdma_vt.h>
|
||||||
|
|
||||||
#include "chip_registers.h"
|
#include "chip_registers.h"
|
||||||
@@ -1060,6 +1059,7 @@ struct sdma_vl_map;
|
|||||||
#define SERIAL_MAX 16 /* length of the serial number */
|
#define SERIAL_MAX 16 /* length of the serial number */
|
||||||
|
|
||||||
typedef int (*send_routine)(struct rvt_qp *, struct hfi1_pkt_state *, u64);
|
typedef int (*send_routine)(struct rvt_qp *, struct hfi1_pkt_state *, u64);
|
||||||
|
struct hfi1_netdev_rx;
|
||||||
struct hfi1_devdata {
|
struct hfi1_devdata {
|
||||||
struct hfi1_ibdev verbs_dev; /* must be first */
|
struct hfi1_ibdev verbs_dev; /* must be first */
|
||||||
/* pointers to related structs for this device */
|
/* pointers to related structs for this device */
|
||||||
@@ -1402,7 +1402,7 @@ struct hfi1_devdata {
|
|||||||
/* Lock to protect IRQ SRC register access */
|
/* Lock to protect IRQ SRC register access */
|
||||||
spinlock_t irq_src_lock;
|
spinlock_t irq_src_lock;
|
||||||
int vnic_num_vports;
|
int vnic_num_vports;
|
||||||
struct net_device *dummy_netdev;
|
struct hfi1_netdev_rx *netdev_rx;
|
||||||
|
|
||||||
/* Keeps track of IPoIB RSM rule users */
|
/* Keeps track of IPoIB RSM rule users */
|
||||||
atomic_t ipoib_rsm_usr_num;
|
atomic_t ipoib_rsm_usr_num;
|
||||||
|
|||||||
@@ -1767,7 +1767,7 @@ static void remove_one(struct pci_dev *pdev)
|
|||||||
hfi1_unregister_ib_device(dd);
|
hfi1_unregister_ib_device(dd);
|
||||||
|
|
||||||
/* free netdev data */
|
/* free netdev data */
|
||||||
hfi1_netdev_free(dd);
|
hfi1_free_rx(dd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable the IB link, disable interrupts on the device,
|
* Disable the IB link, disable interrupts on the device,
|
||||||
|
|||||||
@@ -14,15 +14,14 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* struct hfi1_netdev_rxq - Receive Queue for HFI
|
* struct hfi1_netdev_rxq - Receive Queue for HFI
|
||||||
* dummy netdev. Both IPoIB and VNIC netdevices will be working on
|
* Both IPoIB and VNIC netdevices will be working on the rx abstraction.
|
||||||
* top of this device.
|
|
||||||
* @napi: napi object
|
* @napi: napi object
|
||||||
* @priv: ptr to netdev_priv
|
* @rx: ptr to netdev_rx
|
||||||
* @rcd: ptr to receive context data
|
* @rcd: ptr to receive context data
|
||||||
*/
|
*/
|
||||||
struct hfi1_netdev_rxq {
|
struct hfi1_netdev_rxq {
|
||||||
struct napi_struct napi;
|
struct napi_struct napi;
|
||||||
struct hfi1_netdev_priv *priv;
|
struct hfi1_netdev_rx *rx;
|
||||||
struct hfi1_ctxtdata *rcd;
|
struct hfi1_ctxtdata *rcd;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -36,7 +35,8 @@ struct hfi1_netdev_rxq {
|
|||||||
#define NUM_NETDEV_MAP_ENTRIES HFI1_MAX_NETDEV_CTXTS
|
#define NUM_NETDEV_MAP_ENTRIES HFI1_MAX_NETDEV_CTXTS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct hfi1_netdev_priv: data required to setup and run HFI netdev.
|
* struct hfi1_netdev_rx: data required to setup and run HFI netdev.
|
||||||
|
* @rx_napi: the dummy netdevice to support "polling" the receive contexts
|
||||||
* @dd: hfi1_devdata
|
* @dd: hfi1_devdata
|
||||||
* @rxq: pointer to dummy netdev receive queues.
|
* @rxq: pointer to dummy netdev receive queues.
|
||||||
* @num_rx_q: number of receive queues
|
* @num_rx_q: number of receive queues
|
||||||
@@ -48,7 +48,8 @@ struct hfi1_netdev_rxq {
|
|||||||
* @netdevs: atomic counter of netdevs using dummy netdev.
|
* @netdevs: atomic counter of netdevs using dummy netdev.
|
||||||
* When 0 receive queues will be freed.
|
* When 0 receive queues will be freed.
|
||||||
*/
|
*/
|
||||||
struct hfi1_netdev_priv {
|
struct hfi1_netdev_rx {
|
||||||
|
struct net_device rx_napi;
|
||||||
struct hfi1_devdata *dd;
|
struct hfi1_devdata *dd;
|
||||||
struct hfi1_netdev_rxq *rxq;
|
struct hfi1_netdev_rxq *rxq;
|
||||||
int num_rx_q;
|
int num_rx_q;
|
||||||
@@ -60,42 +61,28 @@ struct hfi1_netdev_priv {
|
|||||||
atomic_t netdevs;
|
atomic_t netdevs;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline
|
|
||||||
struct hfi1_netdev_priv *hfi1_netdev_priv(struct net_device *dev)
|
|
||||||
{
|
|
||||||
return (struct hfi1_netdev_priv *)&dev[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
int hfi1_netdev_ctxt_count(struct hfi1_devdata *dd)
|
int hfi1_netdev_ctxt_count(struct hfi1_devdata *dd)
|
||||||
{
|
{
|
||||||
struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
|
return dd->netdev_rx->num_rx_q;
|
||||||
|
|
||||||
return priv->num_rx_q;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
struct hfi1_ctxtdata *hfi1_netdev_get_ctxt(struct hfi1_devdata *dd, int ctxt)
|
struct hfi1_ctxtdata *hfi1_netdev_get_ctxt(struct hfi1_devdata *dd, int ctxt)
|
||||||
{
|
{
|
||||||
struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
|
return dd->netdev_rx->rxq[ctxt].rcd;
|
||||||
|
|
||||||
return priv->rxq[ctxt].rcd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
int hfi1_netdev_get_free_rmt_idx(struct hfi1_devdata *dd)
|
int hfi1_netdev_get_free_rmt_idx(struct hfi1_devdata *dd)
|
||||||
{
|
{
|
||||||
struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
|
return dd->netdev_rx->rmt_start;
|
||||||
|
|
||||||
return priv->rmt_start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void hfi1_netdev_set_free_rmt_idx(struct hfi1_devdata *dd, int rmt_idx)
|
void hfi1_netdev_set_free_rmt_idx(struct hfi1_devdata *dd, int rmt_idx)
|
||||||
{
|
{
|
||||||
struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
|
dd->netdev_rx->rmt_start = rmt_idx;
|
||||||
|
|
||||||
priv->rmt_start = rmt_idx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 hfi1_num_netdev_contexts(struct hfi1_devdata *dd, u32 available_contexts,
|
u32 hfi1_num_netdev_contexts(struct hfi1_devdata *dd, u32 available_contexts,
|
||||||
@@ -105,8 +92,8 @@ void hfi1_netdev_enable_queues(struct hfi1_devdata *dd);
|
|||||||
void hfi1_netdev_disable_queues(struct hfi1_devdata *dd);
|
void hfi1_netdev_disable_queues(struct hfi1_devdata *dd);
|
||||||
int hfi1_netdev_rx_init(struct hfi1_devdata *dd);
|
int hfi1_netdev_rx_init(struct hfi1_devdata *dd);
|
||||||
int hfi1_netdev_rx_destroy(struct hfi1_devdata *dd);
|
int hfi1_netdev_rx_destroy(struct hfi1_devdata *dd);
|
||||||
int hfi1_netdev_alloc(struct hfi1_devdata *dd);
|
int hfi1_alloc_rx(struct hfi1_devdata *dd);
|
||||||
void hfi1_netdev_free(struct hfi1_devdata *dd);
|
void hfi1_free_rx(struct hfi1_devdata *dd);
|
||||||
int hfi1_netdev_add_data(struct hfi1_devdata *dd, int id, void *data);
|
int hfi1_netdev_add_data(struct hfi1_devdata *dd, int id, void *data);
|
||||||
void *hfi1_netdev_remove_data(struct hfi1_devdata *dd, int id);
|
void *hfi1_netdev_remove_data(struct hfi1_devdata *dd, int id);
|
||||||
void *hfi1_netdev_get_data(struct hfi1_devdata *dd, int id);
|
void *hfi1_netdev_get_data(struct hfi1_devdata *dd, int id);
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
#include <rdma/ib_verbs.h>
|
#include <rdma/ib_verbs.h>
|
||||||
|
|
||||||
static int hfi1_netdev_setup_ctxt(struct hfi1_netdev_priv *priv,
|
static int hfi1_netdev_setup_ctxt(struct hfi1_netdev_rx *rx,
|
||||||
struct hfi1_ctxtdata *uctxt)
|
struct hfi1_ctxtdata *uctxt)
|
||||||
{
|
{
|
||||||
unsigned int rcvctrl_ops;
|
unsigned int rcvctrl_ops;
|
||||||
struct hfi1_devdata *dd = priv->dd;
|
struct hfi1_devdata *dd = rx->dd;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
uctxt->rhf_rcv_function_map = netdev_rhf_rcv_functions;
|
uctxt->rhf_rcv_function_map = netdev_rhf_rcv_functions;
|
||||||
@@ -118,11 +118,11 @@ static void hfi1_netdev_deallocate_ctxt(struct hfi1_devdata *dd,
|
|||||||
hfi1_free_ctxt(uctxt);
|
hfi1_free_ctxt(uctxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hfi1_netdev_allot_ctxt(struct hfi1_netdev_priv *priv,
|
static int hfi1_netdev_allot_ctxt(struct hfi1_netdev_rx *rx,
|
||||||
struct hfi1_ctxtdata **ctxt)
|
struct hfi1_ctxtdata **ctxt)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct hfi1_devdata *dd = priv->dd;
|
struct hfi1_devdata *dd = rx->dd;
|
||||||
|
|
||||||
rc = hfi1_netdev_allocate_ctxt(dd, ctxt);
|
rc = hfi1_netdev_allocate_ctxt(dd, ctxt);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
@@ -130,7 +130,7 @@ static int hfi1_netdev_allot_ctxt(struct hfi1_netdev_priv *priv,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = hfi1_netdev_setup_ctxt(priv, *ctxt);
|
rc = hfi1_netdev_setup_ctxt(rx, *ctxt);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
dd_dev_err(dd, "netdev ctxt setup failed %d\n", rc);
|
dd_dev_err(dd, "netdev ctxt setup failed %d\n", rc);
|
||||||
hfi1_netdev_deallocate_ctxt(dd, *ctxt);
|
hfi1_netdev_deallocate_ctxt(dd, *ctxt);
|
||||||
@@ -184,31 +184,31 @@ u32 hfi1_num_netdev_contexts(struct hfi1_devdata *dd, u32 available_contexts,
|
|||||||
(u32)HFI1_MAX_NETDEV_CTXTS);
|
(u32)HFI1_MAX_NETDEV_CTXTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hfi1_netdev_rxq_init(struct net_device *dev)
|
static int hfi1_netdev_rxq_init(struct hfi1_netdev_rx *rx)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int rc;
|
int rc;
|
||||||
struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dev);
|
struct hfi1_devdata *dd = rx->dd;
|
||||||
struct hfi1_devdata *dd = priv->dd;
|
struct net_device *dev = &rx->rx_napi;
|
||||||
|
|
||||||
priv->num_rx_q = dd->num_netdev_contexts;
|
rx->num_rx_q = dd->num_netdev_contexts;
|
||||||
priv->rxq = kcalloc_node(priv->num_rx_q, sizeof(struct hfi1_netdev_rxq),
|
rx->rxq = kcalloc_node(rx->num_rx_q, sizeof(*rx->rxq),
|
||||||
GFP_KERNEL, dd->node);
|
GFP_KERNEL, dd->node);
|
||||||
|
|
||||||
if (!priv->rxq) {
|
if (!rx->rxq) {
|
||||||
dd_dev_err(dd, "Unable to allocate netdev queue data\n");
|
dd_dev_err(dd, "Unable to allocate netdev queue data\n");
|
||||||
return (-ENOMEM);
|
return (-ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < priv->num_rx_q; i++) {
|
for (i = 0; i < rx->num_rx_q; i++) {
|
||||||
struct hfi1_netdev_rxq *rxq = &priv->rxq[i];
|
struct hfi1_netdev_rxq *rxq = &rx->rxq[i];
|
||||||
|
|
||||||
rc = hfi1_netdev_allot_ctxt(priv, &rxq->rcd);
|
rc = hfi1_netdev_allot_ctxt(rx, &rxq->rcd);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto bail_context_irq_failure;
|
goto bail_context_irq_failure;
|
||||||
|
|
||||||
hfi1_rcd_get(rxq->rcd);
|
hfi1_rcd_get(rxq->rcd);
|
||||||
rxq->priv = priv;
|
rxq->rx = rx;
|
||||||
rxq->rcd->napi = &rxq->napi;
|
rxq->rcd->napi = &rxq->napi;
|
||||||
dd_dev_info(dd, "Setting rcv queue %d napi to context %d\n",
|
dd_dev_info(dd, "Setting rcv queue %d napi to context %d\n",
|
||||||
i, rxq->rcd->ctxt);
|
i, rxq->rcd->ctxt);
|
||||||
@@ -228,7 +228,7 @@ static int hfi1_netdev_rxq_init(struct net_device *dev)
|
|||||||
bail_context_irq_failure:
|
bail_context_irq_failure:
|
||||||
dd_dev_err(dd, "Unable to allot receive context\n");
|
dd_dev_err(dd, "Unable to allot receive context\n");
|
||||||
for (; i >= 0; i--) {
|
for (; i >= 0; i--) {
|
||||||
struct hfi1_netdev_rxq *rxq = &priv->rxq[i];
|
struct hfi1_netdev_rxq *rxq = &rx->rxq[i];
|
||||||
|
|
||||||
if (rxq->rcd) {
|
if (rxq->rcd) {
|
||||||
hfi1_netdev_deallocate_ctxt(dd, rxq->rcd);
|
hfi1_netdev_deallocate_ctxt(dd, rxq->rcd);
|
||||||
@@ -236,20 +236,19 @@ bail_context_irq_failure:
|
|||||||
rxq->rcd = NULL;
|
rxq->rcd = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kfree(priv->rxq);
|
kfree(rx->rxq);
|
||||||
priv->rxq = NULL;
|
rx->rxq = NULL;
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hfi1_netdev_rxq_deinit(struct net_device *dev)
|
static void hfi1_netdev_rxq_deinit(struct hfi1_netdev_rx *rx)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dev);
|
struct hfi1_devdata *dd = rx->dd;
|
||||||
struct hfi1_devdata *dd = priv->dd;
|
|
||||||
|
|
||||||
for (i = 0; i < priv->num_rx_q; i++) {
|
for (i = 0; i < rx->num_rx_q; i++) {
|
||||||
struct hfi1_netdev_rxq *rxq = &priv->rxq[i];
|
struct hfi1_netdev_rxq *rxq = &rx->rxq[i];
|
||||||
|
|
||||||
netif_napi_del(&rxq->napi);
|
netif_napi_del(&rxq->napi);
|
||||||
hfi1_netdev_deallocate_ctxt(dd, rxq->rcd);
|
hfi1_netdev_deallocate_ctxt(dd, rxq->rcd);
|
||||||
@@ -257,41 +256,41 @@ static void hfi1_netdev_rxq_deinit(struct net_device *dev)
|
|||||||
rxq->rcd = NULL;
|
rxq->rcd = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(priv->rxq);
|
kfree(rx->rxq);
|
||||||
priv->rxq = NULL;
|
rx->rxq = NULL;
|
||||||
priv->num_rx_q = 0;
|
rx->num_rx_q = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enable_queues(struct hfi1_netdev_priv *priv)
|
static void enable_queues(struct hfi1_netdev_rx *rx)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < priv->num_rx_q; i++) {
|
for (i = 0; i < rx->num_rx_q; i++) {
|
||||||
struct hfi1_netdev_rxq *rxq = &priv->rxq[i];
|
struct hfi1_netdev_rxq *rxq = &rx->rxq[i];
|
||||||
|
|
||||||
dd_dev_info(priv->dd, "enabling queue %d on context %d\n", i,
|
dd_dev_info(rx->dd, "enabling queue %d on context %d\n", i,
|
||||||
rxq->rcd->ctxt);
|
rxq->rcd->ctxt);
|
||||||
napi_enable(&rxq->napi);
|
napi_enable(&rxq->napi);
|
||||||
hfi1_rcvctrl(priv->dd,
|
hfi1_rcvctrl(rx->dd,
|
||||||
HFI1_RCVCTRL_CTXT_ENB | HFI1_RCVCTRL_INTRAVAIL_ENB,
|
HFI1_RCVCTRL_CTXT_ENB | HFI1_RCVCTRL_INTRAVAIL_ENB,
|
||||||
rxq->rcd);
|
rxq->rcd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disable_queues(struct hfi1_netdev_priv *priv)
|
static void disable_queues(struct hfi1_netdev_rx *rx)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
msix_netdev_synchronize_irq(priv->dd);
|
msix_netdev_synchronize_irq(rx->dd);
|
||||||
|
|
||||||
for (i = 0; i < priv->num_rx_q; i++) {
|
for (i = 0; i < rx->num_rx_q; i++) {
|
||||||
struct hfi1_netdev_rxq *rxq = &priv->rxq[i];
|
struct hfi1_netdev_rxq *rxq = &rx->rxq[i];
|
||||||
|
|
||||||
dd_dev_info(priv->dd, "disabling queue %d on context %d\n", i,
|
dd_dev_info(rx->dd, "disabling queue %d on context %d\n", i,
|
||||||
rxq->rcd->ctxt);
|
rxq->rcd->ctxt);
|
||||||
|
|
||||||
/* wait for napi if it was scheduled */
|
/* wait for napi if it was scheduled */
|
||||||
hfi1_rcvctrl(priv->dd,
|
hfi1_rcvctrl(rx->dd,
|
||||||
HFI1_RCVCTRL_CTXT_DIS | HFI1_RCVCTRL_INTRAVAIL_DIS,
|
HFI1_RCVCTRL_CTXT_DIS | HFI1_RCVCTRL_INTRAVAIL_DIS,
|
||||||
rxq->rcd);
|
rxq->rcd);
|
||||||
napi_synchronize(&rxq->napi);
|
napi_synchronize(&rxq->napi);
|
||||||
@@ -308,15 +307,14 @@ static void disable_queues(struct hfi1_netdev_priv *priv)
|
|||||||
*/
|
*/
|
||||||
int hfi1_netdev_rx_init(struct hfi1_devdata *dd)
|
int hfi1_netdev_rx_init(struct hfi1_devdata *dd)
|
||||||
{
|
{
|
||||||
struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
|
struct hfi1_netdev_rx *rx = dd->netdev_rx;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (atomic_fetch_inc(&priv->netdevs))
|
if (atomic_fetch_inc(&rx->netdevs))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mutex_lock(&hfi1_mutex);
|
mutex_lock(&hfi1_mutex);
|
||||||
init_dummy_netdev(dd->dummy_netdev);
|
res = hfi1_netdev_rxq_init(rx);
|
||||||
res = hfi1_netdev_rxq_init(dd->dummy_netdev);
|
|
||||||
mutex_unlock(&hfi1_mutex);
|
mutex_unlock(&hfi1_mutex);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -329,12 +327,12 @@ int hfi1_netdev_rx_init(struct hfi1_devdata *dd)
|
|||||||
*/
|
*/
|
||||||
int hfi1_netdev_rx_destroy(struct hfi1_devdata *dd)
|
int hfi1_netdev_rx_destroy(struct hfi1_devdata *dd)
|
||||||
{
|
{
|
||||||
struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
|
struct hfi1_netdev_rx *rx = dd->netdev_rx;
|
||||||
|
|
||||||
/* destroy the RX queues only if it is the last netdev going away */
|
/* destroy the RX queues only if it is the last netdev going away */
|
||||||
if (atomic_fetch_add_unless(&priv->netdevs, -1, 0) == 1) {
|
if (atomic_fetch_add_unless(&rx->netdevs, -1, 0) == 1) {
|
||||||
mutex_lock(&hfi1_mutex);
|
mutex_lock(&hfi1_mutex);
|
||||||
hfi1_netdev_rxq_deinit(dd->dummy_netdev);
|
hfi1_netdev_rxq_deinit(rx);
|
||||||
mutex_unlock(&hfi1_mutex);
|
mutex_unlock(&hfi1_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,39 +340,43 @@ int hfi1_netdev_rx_destroy(struct hfi1_devdata *dd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hfi1_netdev_alloc - Allocates netdev and private data. It is required
|
* hfi1_alloc_rx - Allocates the rx support structure
|
||||||
* because RMT index and MSI-X interrupt can be set only
|
|
||||||
* during driver initialization.
|
|
||||||
*
|
|
||||||
* @dd: hfi1 dev data
|
* @dd: hfi1 dev data
|
||||||
|
*
|
||||||
|
* Allocate the rx structure to support gathering the receive
|
||||||
|
* resources and the dummy netdev.
|
||||||
|
*
|
||||||
|
* Updates dd struct pointer upon success.
|
||||||
|
*
|
||||||
|
* Return: 0 (success) -error on failure
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
int hfi1_netdev_alloc(struct hfi1_devdata *dd)
|
int hfi1_alloc_rx(struct hfi1_devdata *dd)
|
||||||
{
|
{
|
||||||
struct hfi1_netdev_priv *priv;
|
struct hfi1_netdev_rx *rx;
|
||||||
const int netdev_size = sizeof(*dd->dummy_netdev) +
|
|
||||||
sizeof(struct hfi1_netdev_priv);
|
|
||||||
|
|
||||||
dd_dev_info(dd, "allocating netdev size %d\n", netdev_size);
|
dd_dev_info(dd, "allocating rx size %ld\n", sizeof(*rx));
|
||||||
dd->dummy_netdev = kcalloc_node(1, netdev_size, GFP_KERNEL, dd->node);
|
rx = kzalloc_node(sizeof(*rx), GFP_KERNEL, dd->node);
|
||||||
|
|
||||||
if (!dd->dummy_netdev)
|
if (!rx)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
rx->dd = dd;
|
||||||
|
init_dummy_netdev(&rx->rx_napi);
|
||||||
|
|
||||||
priv = hfi1_netdev_priv(dd->dummy_netdev);
|
xa_init(&rx->dev_tbl);
|
||||||
priv->dd = dd;
|
atomic_set(&rx->enabled, 0);
|
||||||
xa_init(&priv->dev_tbl);
|
atomic_set(&rx->netdevs, 0);
|
||||||
atomic_set(&priv->enabled, 0);
|
dd->netdev_rx = rx;
|
||||||
atomic_set(&priv->netdevs, 0);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hfi1_netdev_free(struct hfi1_devdata *dd)
|
void hfi1_free_rx(struct hfi1_devdata *dd)
|
||||||
{
|
{
|
||||||
if (dd->dummy_netdev) {
|
if (dd->netdev_rx) {
|
||||||
dd_dev_info(dd, "hfi1 netdev freed\n");
|
dd_dev_info(dd, "hfi1 rx freed\n");
|
||||||
kfree(dd->dummy_netdev);
|
kfree(dd->netdev_rx);
|
||||||
dd->dummy_netdev = NULL;
|
dd->netdev_rx = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,33 +391,33 @@ void hfi1_netdev_free(struct hfi1_devdata *dd)
|
|||||||
*/
|
*/
|
||||||
void hfi1_netdev_enable_queues(struct hfi1_devdata *dd)
|
void hfi1_netdev_enable_queues(struct hfi1_devdata *dd)
|
||||||
{
|
{
|
||||||
struct hfi1_netdev_priv *priv;
|
struct hfi1_netdev_rx *rx;
|
||||||
|
|
||||||
if (!dd->dummy_netdev)
|
if (!dd->netdev_rx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
priv = hfi1_netdev_priv(dd->dummy_netdev);
|
rx = dd->netdev_rx;
|
||||||
if (atomic_fetch_inc(&priv->enabled))
|
if (atomic_fetch_inc(&rx->enabled))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_lock(&hfi1_mutex);
|
mutex_lock(&hfi1_mutex);
|
||||||
enable_queues(priv);
|
enable_queues(rx);
|
||||||
mutex_unlock(&hfi1_mutex);
|
mutex_unlock(&hfi1_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hfi1_netdev_disable_queues(struct hfi1_devdata *dd)
|
void hfi1_netdev_disable_queues(struct hfi1_devdata *dd)
|
||||||
{
|
{
|
||||||
struct hfi1_netdev_priv *priv;
|
struct hfi1_netdev_rx *rx;
|
||||||
|
|
||||||
if (!dd->dummy_netdev)
|
if (!dd->netdev_rx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
priv = hfi1_netdev_priv(dd->dummy_netdev);
|
rx = dd->netdev_rx;
|
||||||
if (atomic_dec_if_positive(&priv->enabled))
|
if (atomic_dec_if_positive(&rx->enabled))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_lock(&hfi1_mutex);
|
mutex_lock(&hfi1_mutex);
|
||||||
disable_queues(priv);
|
disable_queues(rx);
|
||||||
mutex_unlock(&hfi1_mutex);
|
mutex_unlock(&hfi1_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,9 +433,9 @@ void hfi1_netdev_disable_queues(struct hfi1_devdata *dd)
|
|||||||
*/
|
*/
|
||||||
int hfi1_netdev_add_data(struct hfi1_devdata *dd, int id, void *data)
|
int hfi1_netdev_add_data(struct hfi1_devdata *dd, int id, void *data)
|
||||||
{
|
{
|
||||||
struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
|
struct hfi1_netdev_rx *rx = dd->netdev_rx;
|
||||||
|
|
||||||
return xa_insert(&priv->dev_tbl, id, data, GFP_NOWAIT);
|
return xa_insert(&rx->dev_tbl, id, data, GFP_NOWAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -445,9 +447,9 @@ int hfi1_netdev_add_data(struct hfi1_devdata *dd, int id, void *data)
|
|||||||
*/
|
*/
|
||||||
void *hfi1_netdev_remove_data(struct hfi1_devdata *dd, int id)
|
void *hfi1_netdev_remove_data(struct hfi1_devdata *dd, int id)
|
||||||
{
|
{
|
||||||
struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
|
struct hfi1_netdev_rx *rx = dd->netdev_rx;
|
||||||
|
|
||||||
return xa_erase(&priv->dev_tbl, id);
|
return xa_erase(&rx->dev_tbl, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -458,9 +460,9 @@ void *hfi1_netdev_remove_data(struct hfi1_devdata *dd, int id)
|
|||||||
*/
|
*/
|
||||||
void *hfi1_netdev_get_data(struct hfi1_devdata *dd, int id)
|
void *hfi1_netdev_get_data(struct hfi1_devdata *dd, int id)
|
||||||
{
|
{
|
||||||
struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
|
struct hfi1_netdev_rx *rx = dd->netdev_rx;
|
||||||
|
|
||||||
return xa_load(&priv->dev_tbl, id);
|
return xa_load(&rx->dev_tbl, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -471,11 +473,11 @@ void *hfi1_netdev_get_data(struct hfi1_devdata *dd, int id)
|
|||||||
*/
|
*/
|
||||||
void *hfi1_netdev_get_first_data(struct hfi1_devdata *dd, int *start_id)
|
void *hfi1_netdev_get_first_data(struct hfi1_devdata *dd, int *start_id)
|
||||||
{
|
{
|
||||||
struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
|
struct hfi1_netdev_rx *rx = dd->netdev_rx;
|
||||||
unsigned long index = *start_id;
|
unsigned long index = *start_id;
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
ret = xa_find(&priv->dev_tbl, &index, UINT_MAX, XA_PRESENT);
|
ret = xa_find(&rx->dev_tbl, &index, UINT_MAX, XA_PRESENT);
|
||||||
*start_id = (int)index;
|
*start_id = (int)index;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user