Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 48 additions & 6 deletions drivers/infiniband/hw/mana/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,38 @@ static const struct ib_device_ops mana_ib_dev_ops = {
ib_ind_table),
};

static int mana_ib_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct mana_ib_dev *dev = container_of(this, struct mana_ib_dev, nb);
struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
struct gdma_context *gc = dev->gdma_dev->gdma_context;
struct mana_context *mc = gc->mana.driver_data;
struct net_device *ndev;

/* Only process events from our parent device */
if (event_dev != mc->ports[0])
return NOTIFY_DONE;

switch (event) {
case NETDEV_CHANGEUPPER:
ndev = mana_get_primary_netdev(mc, 0, &dev->dev_tracker);
/*
* RDMA core will setup GID based on updated netdev.
* It's not possible to race with the core as rtnl lock is being
* held.
*/
ib_device_set_netdev(&dev->ib_dev, ndev, 1);

/* mana_get_primary_netdev() returns ndev with refcount held */
netdev_put(ndev, &dev->dev_tracker);

return NOTIFY_OK;
default:
return NOTIFY_DONE;
}
}

static int mana_ib_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
Expand Down Expand Up @@ -85,18 +117,17 @@ static int mana_ib_probe(struct auxiliary_device *adev,
dev->ib_dev.num_comp_vectors = mdev->gdma_context->max_num_queues;
dev->ib_dev.dev.parent = mdev->gdma_context->dev;

rcu_read_lock(); /* required to get primary netdev */
ndev = mana_get_primary_netdev_rcu(mc, 0);
ndev = mana_get_primary_netdev(mc, 0, &dev->dev_tracker);
if (!ndev) {
rcu_read_unlock();
ret = -ENODEV;
ibdev_err(&dev->ib_dev, "Failed to get netdev for IB port 1");
goto free_ib_device;
}
ether_addr_copy(mac_addr, ndev->dev_addr);
addrconf_addr_eui48((u8 *)&dev->ib_dev.node_guid, ndev->dev_addr);
ret = ib_device_set_netdev(&dev->ib_dev, ndev, 1);
rcu_read_unlock();
/* mana_get_primary_netdev() returns ndev with refcount held */
netdev_put(ndev, &dev->dev_tracker);
if (ret) {
ibdev_err(&dev->ib_dev, "Failed to set ib netdev, ret %d", ret);
goto free_ib_device;
Expand All @@ -110,17 +141,25 @@ static int mana_ib_probe(struct auxiliary_device *adev,
}
dev->gdma_dev = &mdev->gdma_context->mana_ib;

dev->nb.notifier_call = mana_ib_netdev_event;
ret = register_netdevice_notifier(&dev->nb);
if (ret) {
ibdev_err(&dev->ib_dev, "Failed to register net notifier, %d",
ret);
goto deregister_device;
}

ret = mana_ib_gd_query_adapter_caps(dev);
if (ret) {
ibdev_err(&dev->ib_dev, "Failed to query device caps, ret %d",
ret);
goto deregister_device;
goto deregister_net_notifier;
}

ret = mana_ib_create_eqs(dev);
if (ret) {
ibdev_err(&dev->ib_dev, "Failed to create EQs, ret %d", ret);
goto deregister_device;
goto deregister_net_notifier;
}

ret = mana_ib_gd_create_rnic_adapter(dev);
Expand Down Expand Up @@ -149,6 +188,8 @@ static int mana_ib_probe(struct auxiliary_device *adev,
mana_ib_gd_destroy_rnic_adapter(dev);
destroy_eqs:
mana_ib_destroy_eqs(dev);
deregister_net_notifier:
unregister_netdevice_notifier(&dev->nb);
deregister_device:
mana_gd_deregister_device(dev->gdma_dev);
free_ib_device:
Expand All @@ -164,6 +205,7 @@ static void mana_ib_remove(struct auxiliary_device *adev)
xa_destroy(&dev->qp_table_wq);
mana_ib_gd_destroy_rnic_adapter(dev);
mana_ib_destroy_eqs(dev);
unregister_netdevice_notifier(&dev->nb);
mana_gd_deregister_device(dev->gdma_dev);
ib_dealloc_device(&dev->ib_dev);
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/infiniband/hw/mana/mana_ib.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ struct mana_ib_dev {
struct gdma_queue **eqs;
struct xarray qp_table_wq;
struct mana_ib_adapter_caps adapter_caps;
netdevice_tracker dev_tracker;
struct notifier_block nb;
};

struct mana_ib_wq {
Expand Down
14 changes: 10 additions & 4 deletions drivers/net/ethernet/microsoft/mana/gdma_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,10 @@ static int mana_gd_detect_devices(struct pci_dev *pdev)
struct gdma_list_devices_resp resp = {};
struct gdma_general_req req = {};
struct gdma_dev_id dev;
u32 i, max_num_devs;
int found_dev = 0;
u16 dev_type;
int err;
u32 i;

mana_gd_init_req_hdr(&req.hdr, GDMA_LIST_DEVICES, sizeof(req),
sizeof(resp));
Expand All @@ -149,12 +150,17 @@ static int mana_gd_detect_devices(struct pci_dev *pdev)
return err ? err : -EPROTO;
}

max_num_devs = min_t(u32, MAX_NUM_GDMA_DEVICES, resp.num_of_devs);

for (i = 0; i < max_num_devs; i++) {
for (i = 0; i < GDMA_DEV_LIST_SIZE &&
found_dev < resp.num_of_devs; i++) {
dev = resp.devs[i];
dev_type = dev.type;

/* Skip empty devices */
if (dev.as_uint32 == 0)
continue;

found_dev++;

/* HWC is already detected in mana_hwc_create_channel(). */
if (dev_type == GDMA_DEVICE_HWC)
continue;
Expand Down
68 changes: 23 additions & 45 deletions drivers/net/ethernet/microsoft/mana/mana_en.c
Original file line number Diff line number Diff line change
Expand Up @@ -655,30 +655,16 @@ int mana_pre_alloc_rxbufs(struct mana_port_context *mpc, int new_mtu, int num_qu
mpc->rxbpre_total = 0;

for (i = 0; i < num_rxb; i++) {
if (mpc->rxbpre_alloc_size > PAGE_SIZE) {
va = netdev_alloc_frag(mpc->rxbpre_alloc_size);
if (!va)
goto error;

page = virt_to_head_page(va);
/* Check if the frag falls back to single page */
if (compound_order(page) <
get_order(mpc->rxbpre_alloc_size)) {
put_page(page);
goto error;
}
} else {
page = dev_alloc_page();
if (!page)
goto error;
page = dev_alloc_pages(get_order(mpc->rxbpre_alloc_size));
if (!page)
goto error;

va = page_to_virt(page);
}
va = page_to_virt(page);

da = dma_map_single(dev, va + mpc->rxbpre_headroom,
mpc->rxbpre_datasize, DMA_FROM_DEVICE);
if (dma_mapping_error(dev, da)) {
put_page(virt_to_head_page(va));
put_page(page);
goto error;
}

Expand Down Expand Up @@ -1671,7 +1657,7 @@ static void mana_rx_skb(void *buf_va, bool from_pool,
}

static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev,
dma_addr_t *da, bool *from_pool, bool is_napi)
dma_addr_t *da, bool *from_pool)
{
struct page *page;
void *va;
Expand All @@ -1682,21 +1668,6 @@ static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev,
if (rxq->xdp_save_va) {
va = rxq->xdp_save_va;
rxq->xdp_save_va = NULL;
} else if (rxq->alloc_size > PAGE_SIZE) {
if (is_napi)
va = napi_alloc_frag(rxq->alloc_size);
else
va = netdev_alloc_frag(rxq->alloc_size);

if (!va)
return NULL;

page = virt_to_head_page(va);
/* Check if the frag falls back to single page */
if (compound_order(page) < get_order(rxq->alloc_size)) {
put_page(page);
return NULL;
}
} else {
page = page_pool_dev_alloc_pages(rxq->page_pool);
if (!page)
Expand Down Expand Up @@ -1729,7 +1700,7 @@ static void mana_refill_rx_oob(struct device *dev, struct mana_rxq *rxq,
dma_addr_t da;
void *va;

va = mana_get_rxfrag(rxq, dev, &da, &from_pool, true);
va = mana_get_rxfrag(rxq, dev, &da, &from_pool);
if (!va)
return;

Expand Down Expand Up @@ -2165,7 +2136,7 @@ static int mana_fill_rx_oob(struct mana_recv_buf_oob *rx_oob, u32 mem_key,
if (mpc->rxbufs_pre)
va = mana_get_rxbuf_pre(rxq, &da);
else
va = mana_get_rxfrag(rxq, dev, &da, &from_pool, false);
va = mana_get_rxfrag(rxq, dev, &da, &from_pool);

if (!va)
return -ENOMEM;
Expand Down Expand Up @@ -2251,6 +2222,7 @@ static int mana_create_page_pool(struct mana_rxq *rxq, struct gdma_context *gc)
pprm.nid = gc->numa_node;
pprm.napi = &rxq->rx_cq.napi;
pprm.netdev = rxq->ndev;
pprm.order = get_order(rxq->alloc_size);

rxq->page_pool = page_pool_create(&pprm);

Expand Down Expand Up @@ -3171,21 +3143,27 @@ void mana_remove(struct gdma_dev *gd, bool suspending)
dev_dbg(dev, "%s succeeded\n", __func__);
}

struct net_device *mana_get_primary_netdev_rcu(struct mana_context *ac, u32 port_index)
struct net_device *mana_get_primary_netdev(struct mana_context *ac,
u32 port_index,
netdevice_tracker *tracker)
{
struct net_device *ndev;

RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
"Taking primary netdev without holding the RCU read lock");
if (port_index >= ac->num_ports)
return NULL;

/* When mana is used in netvsc, the upper netdevice should be returned. */
if (ac->ports[port_index]->flags & IFF_SLAVE)
ndev = netdev_master_upper_dev_get_rcu(ac->ports[port_index]);
else
rcu_read_lock();

/* If mana is used in netvsc, the upper netdevice should be returned. */
ndev = netdev_master_upper_dev_get_rcu(ac->ports[port_index]);

/* If there is no upper device, use the parent Ethernet device */
if (!ndev)
ndev = ac->ports[port_index];

netdev_hold(ndev, tracker, GFP_ATOMIC);
rcu_read_unlock();

return ndev;
}
EXPORT_SYMBOL_NS(mana_get_primary_netdev_rcu, NET_MANA);
EXPORT_SYMBOL_NS(mana_get_primary_netdev, NET_MANA);
11 changes: 7 additions & 4 deletions include/net/mana/gdma.h
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,6 @@ struct gdma_context {
struct gdma_dev mana_ib;
};

#define MAX_NUM_GDMA_DEVICES 4

static inline bool mana_gd_is_mana(struct gdma_dev *gd)
{
return gd->dev_id.type == GDMA_DEVICE_MANA;
Expand Down Expand Up @@ -556,11 +554,15 @@ enum {
#define GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECONFIG BIT(3)
#define GDMA_DRV_CAP_FLAG_1_VARIABLE_INDIRECTION_TABLE_SUPPORT BIT(5)

/* Driver can handle holes (zeros) in the device list */
#define GDMA_DRV_CAP_FLAG_1_DEV_LIST_HOLES_SUP BIT(11)

#define GDMA_DRV_CAP_FLAGS1 \
(GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \
GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \
GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECONFIG | \
GDMA_DRV_CAP_FLAG_1_VARIABLE_INDIRECTION_TABLE_SUPPORT)
GDMA_DRV_CAP_FLAG_1_VARIABLE_INDIRECTION_TABLE_SUPPORT | \
GDMA_DRV_CAP_FLAG_1_DEV_LIST_HOLES_SUP)

#define GDMA_DRV_CAP_FLAGS2 0

Expand Down Expand Up @@ -621,11 +623,12 @@ struct gdma_query_max_resources_resp {
}; /* HW DATA */

/* GDMA_LIST_DEVICES */
#define GDMA_DEV_LIST_SIZE 64
struct gdma_list_devices_resp {
struct gdma_resp_hdr hdr;
u32 num_of_devs;
u32 reserved;
struct gdma_dev_id devs[64];
struct gdma_dev_id devs[GDMA_DEV_LIST_SIZE];
}; /* HW DATA */

/* GDMA_REGISTER_DEVICE */
Expand Down
4 changes: 3 additions & 1 deletion include/net/mana/mana.h
Original file line number Diff line number Diff line change
Expand Up @@ -826,5 +826,7 @@ int mana_cfg_vport(struct mana_port_context *apc, u32 protection_dom_id,
u32 doorbell_pg_id);
void mana_uncfg_vport(struct mana_port_context *apc);

struct net_device *mana_get_primary_netdev_rcu(struct mana_context *ac, u32 port_index);
struct net_device *mana_get_primary_netdev(struct mana_context *ac,
u32 port_index,
netdevice_tracker *tracker);
#endif /* _MANA_H */