Message ID | 1716960955-3195-1-git-send-email-shradhagupta@linux.microsoft.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [net-next,v2] net: mana: Allow variable size indirection table | expand |
On Tue, May 28, 2024 at 10:35:55PM -0700, Shradha Gupta wrote: > Allow variable size indirection table allocation in MANA instead > of using a constant value MANA_INDIRECT_TABLE_SIZE. > The size is now derived from the MANA_QUERY_VPORT_CONFIG and the > indirection table is allocated dynamically. > > Signed-off-by: Shradha Gupta <shradhagupta@linux.microsoft.com> > Reviewed-by: Dexuan Cui <decui@microsoft.com> > Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> > --- > Changes in v2: > * Rebased to latest net-next tree > * Rearranged cleanup code in mana_probe_port to avoid extra operations > --- > drivers/infiniband/hw/mana/qp.c | 10 +-- Jakub, Once you are ok with this patch, let me create shared branch for it. It is -rc1 and Konstantin already submitted some changes to qp.c https://lore.kernel.org/all/1716366242-558-1-git-send-email-kotaranov@linux.microsoft.com/ This specific patch applies on top of Konstantin's changes cleanly. Thanks > drivers/net/ethernet/microsoft/mana/mana_en.c | 68 ++++++++++++++++--- > .../ethernet/microsoft/mana/mana_ethtool.c | 20 ++++-- > include/net/mana/gdma.h | 4 +- > include/net/mana/mana.h | 9 +-- > 5 files changed, 84 insertions(+), 27 deletions(-) > > diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c > index ba13c5abf8ef..2d411a16a127 100644 > --- a/drivers/infiniband/hw/mana/qp.c > +++ b/drivers/infiniband/hw/mana/qp.c > @@ -21,7 +21,7 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev *dev, > > gc = mdev_to_gc(dev); > > - req_buf_size = struct_size(req, indir_tab, MANA_INDIRECT_TABLE_SIZE); > + req_buf_size = struct_size(req, indir_tab, MANA_INDIRECT_TABLE_DEF_SIZE); > req = kzalloc(req_buf_size, GFP_KERNEL); > if (!req) > return -ENOMEM; > @@ -41,18 +41,18 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev *dev, > if (log_ind_tbl_size) > req->rss_enable = true; > > - req->num_indir_entries = MANA_INDIRECT_TABLE_SIZE; > + req->num_indir_entries = MANA_INDIRECT_TABLE_DEF_SIZE; > req->indir_tab_offset = offsetof(struct mana_cfg_rx_steer_req_v2, > indir_tab); > req->update_indir_tab = true; > req->cqe_coalescing_enable = 1; > > /* The ind table passed to the hardware must have > - * MANA_INDIRECT_TABLE_SIZE entries. Adjust the verb > + * MANA_INDIRECT_TABLE_DEF_SIZE entries. Adjust the verb > * ind_table to MANA_INDIRECT_TABLE_SIZE if required > */ > ibdev_dbg(&dev->ib_dev, "ind table size %u\n", 1 << log_ind_tbl_size); > - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) { > + for (i = 0; i < MANA_INDIRECT_TABLE_DEF_SIZE; i++) { > req->indir_tab[i] = ind_table[i % (1 << log_ind_tbl_size)]; > ibdev_dbg(&dev->ib_dev, "index %u handle 0x%llx\n", i, > req->indir_tab[i]); > @@ -137,7 +137,7 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd, > } > > ind_tbl_size = 1 << ind_tbl->log_ind_tbl_size; > - if (ind_tbl_size > MANA_INDIRECT_TABLE_SIZE) { > + if (ind_tbl_size > MANA_INDIRECT_TABLE_DEF_SIZE) { > ibdev_dbg(&mdev->ib_dev, > "Indirect table size %d exceeding limit\n", > ind_tbl_size); > diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c > index d087cf954f75..851e1b9761b3 100644 > --- a/drivers/net/ethernet/microsoft/mana/mana_en.c > +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c > @@ -481,7 +481,7 @@ static int mana_get_tx_queue(struct net_device *ndev, struct sk_buff *skb, > struct sock *sk = skb->sk; > int txq; > > - txq = apc->indir_table[hash & MANA_INDIRECT_TABLE_MASK]; > + txq = apc->indir_table[hash & (apc->indir_table_sz - 1)]; > > if (txq != old_q && sk && sk_fullsock(sk) && > rcu_access_pointer(sk->sk_dst_cache)) > @@ -962,7 +962,16 @@ static int mana_query_vport_cfg(struct mana_port_context *apc, u32 vport_index, > > *max_sq = resp.max_num_sq; > *max_rq = resp.max_num_rq; > - *num_indir_entry = resp.num_indirection_ent; > + if (resp.num_indirection_ent > 0 && > + resp.num_indirection_ent <= MANA_INDIRECT_TABLE_MAX_SIZE && > + is_power_of_2(resp.num_indirection_ent)) { > + *num_indir_entry = resp.num_indirection_ent; > + } else { > + netdev_warn(apc->ndev, > + "Setting indirection table size to default %d for vPort %d\n", > + MANA_INDIRECT_TABLE_DEF_SIZE, apc->port_idx); > + *num_indir_entry = MANA_INDIRECT_TABLE_DEF_SIZE; > + } > > apc->port_handle = resp.vport; > ether_addr_copy(apc->mac_addr, resp.mac_addr); > @@ -1054,14 +1063,13 @@ static int mana_cfg_vport_steering(struct mana_port_context *apc, > bool update_default_rxobj, bool update_key, > bool update_tab) > { > - u16 num_entries = MANA_INDIRECT_TABLE_SIZE; > struct mana_cfg_rx_steer_req_v2 *req; > struct mana_cfg_rx_steer_resp resp = {}; > struct net_device *ndev = apc->ndev; > u32 req_buf_size; > int err; > > - req_buf_size = struct_size(req, indir_tab, num_entries); > + req_buf_size = struct_size(req, indir_tab, apc->indir_table_sz); > req = kzalloc(req_buf_size, GFP_KERNEL); > if (!req) > return -ENOMEM; > @@ -1072,7 +1080,7 @@ static int mana_cfg_vport_steering(struct mana_port_context *apc, > req->hdr.req.msg_version = GDMA_MESSAGE_V2; > > req->vport = apc->port_handle; > - req->num_indir_entries = num_entries; > + req->num_indir_entries = apc->indir_table_sz; > req->indir_tab_offset = offsetof(struct mana_cfg_rx_steer_req_v2, > indir_tab); > req->rx_enable = rx; > @@ -1111,7 +1119,7 @@ static int mana_cfg_vport_steering(struct mana_port_context *apc, > } > > netdev_info(ndev, "Configured steering vPort %llu entries %u\n", > - apc->port_handle, num_entries); > + apc->port_handle, apc->indir_table_sz); > out: > kfree(req); > return err; > @@ -2344,11 +2352,33 @@ static int mana_create_vport(struct mana_port_context *apc, > return mana_create_txq(apc, net); > } > > +static int mana_rss_table_alloc(struct mana_port_context *apc) > +{ > + if (!apc->indir_table_sz) { > + netdev_err(apc->ndev, > + "Indirection table size not set for vPort %d\n", > + apc->port_idx); > + return -EINVAL; > + } > + > + apc->indir_table = kcalloc(apc->indir_table_sz, sizeof(u32), GFP_KERNEL); > + if (!apc->indir_table) > + return -ENOMEM; > + > + apc->rxobj_table = kcalloc(apc->indir_table_sz, sizeof(mana_handle_t), GFP_KERNEL); > + if (!apc->rxobj_table) { > + kfree(apc->indir_table); > + return -ENOMEM; > + } > + > + return 0; > +} > + > static void mana_rss_table_init(struct mana_port_context *apc) > { > int i; > > - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) > + for (i = 0; i < apc->indir_table_sz; i++) > apc->indir_table[i] = > ethtool_rxfh_indir_default(i, apc->num_queues); > } > @@ -2361,7 +2391,7 @@ int mana_config_rss(struct mana_port_context *apc, enum TRI_STATE rx, > int i; > > if (update_tab) { > - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) { > + for (i = 0; i < apc->indir_table_sz; i++) { > queue_idx = apc->indir_table[i]; > apc->rxobj_table[i] = apc->rxqs[queue_idx]->rxobj; > } > @@ -2466,7 +2496,6 @@ static int mana_init_port(struct net_device *ndev) > struct mana_port_context *apc = netdev_priv(ndev); > u32 max_txq, max_rxq, max_queues; > int port_idx = apc->port_idx; > - u32 num_indirect_entries; > int err; > > err = mana_init_port_context(apc); > @@ -2474,7 +2503,7 @@ static int mana_init_port(struct net_device *ndev) > return err; > > err = mana_query_vport_cfg(apc, port_idx, &max_txq, &max_rxq, > - &num_indirect_entries); > + &apc->indir_table_sz); > if (err) { > netdev_err(ndev, "Failed to query info for vPort %d\n", > port_idx); > @@ -2723,6 +2752,10 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, > if (err) > goto free_net; > > + err = mana_rss_table_alloc(apc); > + if (err) > + goto reset_apc; > + > netdev_lockdep_set_classes(ndev); > > ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; > @@ -2739,11 +2772,17 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, > err = register_netdev(ndev); > if (err) { > netdev_err(ndev, "Unable to register netdev.\n"); > - goto reset_apc; > + goto free_indir; > } > > return 0; > > +free_indir: > + apc->indir_table_sz = 0; > + kfree(apc->indir_table); > + apc->indir_table = NULL; > + kfree(apc->rxobj_table); > + apc->rxobj_table = NULL; > reset_apc: > kfree(apc->rxqs); > apc->rxqs = NULL; > @@ -2897,6 +2936,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending) > { > struct gdma_context *gc = gd->gdma_context; > struct mana_context *ac = gd->driver_data; > + struct mana_port_context *apc; > struct device *dev = gc->dev; > struct net_device *ndev; > int err; > @@ -2908,6 +2948,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending) > > for (i = 0; i < ac->num_ports; i++) { > ndev = ac->ports[i]; > + apc = netdev_priv(ndev); > if (!ndev) { > if (i == 0) > dev_err(dev, "No net device to remove\n"); > @@ -2931,6 +2972,11 @@ void mana_remove(struct gdma_dev *gd, bool suspending) > } > > unregister_netdevice(ndev); > + apc->indir_table_sz = 0; > + kfree(apc->indir_table); > + apc->indir_table = NULL; > + kfree(apc->rxobj_table); > + apc->rxobj_table = NULL; > > rtnl_unlock(); > > diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c > index ab2413d71f6c..1667f18046d2 100644 > --- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c > +++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c > @@ -245,7 +245,9 @@ static u32 mana_get_rxfh_key_size(struct net_device *ndev) > > static u32 mana_rss_indir_size(struct net_device *ndev) > { > - return MANA_INDIRECT_TABLE_SIZE; > + struct mana_port_context *apc = netdev_priv(ndev); > + > + return apc->indir_table_sz; > } > > static int mana_get_rxfh(struct net_device *ndev, > @@ -257,7 +259,7 @@ static int mana_get_rxfh(struct net_device *ndev, > rxfh->hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */ > > if (rxfh->indir) { > - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) > + for (i = 0; i < apc->indir_table_sz; i++) > rxfh->indir[i] = apc->indir_table[i]; > } > > @@ -273,8 +275,8 @@ static int mana_set_rxfh(struct net_device *ndev, > { > struct mana_port_context *apc = netdev_priv(ndev); > bool update_hash = false, update_table = false; > - u32 save_table[MANA_INDIRECT_TABLE_SIZE]; > u8 save_key[MANA_HASH_KEY_SIZE]; > + u32 *save_table; > int i, err; > > if (!apc->port_is_up) > @@ -284,13 +286,17 @@ static int mana_set_rxfh(struct net_device *ndev, > rxfh->hfunc != ETH_RSS_HASH_TOP) > return -EOPNOTSUPP; > > + save_table = kcalloc(apc->indir_table_sz, sizeof(u32), GFP_KERNEL); > + if (!save_table) > + return -ENOMEM; > + > if (rxfh->indir) { > - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) > + for (i = 0; i < apc->indir_table_sz; i++) > if (rxfh->indir[i] >= apc->num_queues) > return -EINVAL; > > update_table = true; > - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) { > + for (i = 0; i < apc->indir_table_sz; i++) { > save_table[i] = apc->indir_table[i]; > apc->indir_table[i] = rxfh->indir[i]; > } > @@ -306,7 +312,7 @@ static int mana_set_rxfh(struct net_device *ndev, > > if (err) { /* recover to original values */ > if (update_table) { > - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) > + for (i = 0; i < apc->indir_table_sz; i++) > apc->indir_table[i] = save_table[i]; > } > > @@ -316,6 +322,8 @@ static int mana_set_rxfh(struct net_device *ndev, > mana_config_rss(apc, TRI_STATE_TRUE, update_hash, update_table); > } > > + kfree(save_table); > + > return err; > } > > diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h > index 27684135bb4d..c547756c4284 100644 > --- a/include/net/mana/gdma.h > +++ b/include/net/mana/gdma.h > @@ -543,11 +543,13 @@ enum { > */ > #define GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX BIT(2) > #define GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECONFIG BIT(3) > +#define GDMA_DRV_CAP_FLAG_1_VARIABLE_INDIRECTION_TABLE_SUPPORT BIT(5) > > #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_HWC_TIMEOUT_RECONFIG | \ > + GDMA_DRV_CAP_FLAG_1_VARIABLE_INDIRECTION_TABLE_SUPPORT) > > #define GDMA_DRV_CAP_FLAGS2 0 > > diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h > index 561f6719fb4e..59823901b74f 100644 > --- a/include/net/mana/mana.h > +++ b/include/net/mana/mana.h > @@ -30,8 +30,8 @@ enum TRI_STATE { > }; > > /* Number of entries for hardware indirection table must be in power of 2 */ > -#define MANA_INDIRECT_TABLE_SIZE 64 > -#define MANA_INDIRECT_TABLE_MASK (MANA_INDIRECT_TABLE_SIZE - 1) > +#define MANA_INDIRECT_TABLE_MAX_SIZE 512 > +#define MANA_INDIRECT_TABLE_DEF_SIZE 64 > > /* The Toeplitz hash key's length in bytes: should be multiple of 8 */ > #define MANA_HASH_KEY_SIZE 40 > @@ -410,10 +410,11 @@ struct mana_port_context { > struct mana_tx_qp *tx_qp; > > /* Indirection Table for RX & TX. The values are queue indexes */ > - u32 indir_table[MANA_INDIRECT_TABLE_SIZE]; > + u32 *indir_table; > + u32 indir_table_sz; > > /* Indirection table containing RxObject Handles */ > - mana_handle_t rxobj_table[MANA_INDIRECT_TABLE_SIZE]; > + mana_handle_t *rxobj_table; > > /* Hash key used by the NIC */ > u8 hashkey[MANA_HASH_KEY_SIZE]; > -- > 2.34.1 >
On Tue, 28 May 2024 22:35:55 -0700 Shradha Gupta wrote: > + save_table = kcalloc(apc->indir_table_sz, sizeof(u32), GFP_KERNEL); > + if (!save_table) > + return -ENOMEM; > + > if (rxfh->indir) { > - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) > + for (i = 0; i < apc->indir_table_sz; i++) > if (rxfh->indir[i] >= apc->num_queues) > return -EINVAL; leaks save_table
On Thu, 30 May 2024 17:37:02 +0300 Leon Romanovsky wrote: > Once you are ok with this patch, let me create shared branch for it. > It is -rc1 and Konstantin already submitted some changes to qp.c > https://lore.kernel.org/all/1716366242-558-1-git-send-email-kotaranov@linux.microsoft.com/ > > This specific patch applies on top of Konstantin's changes cleanly. Yeah, once it's not buggy shared branch SG! Just to be sure, on top of -rc1, right?
On Thu, May 30, 2024 at 08:42:55AM -0700, Jakub Kicinski wrote: > On Thu, 30 May 2024 17:37:02 +0300 Leon Romanovsky wrote: > > Once you are ok with this patch, let me create shared branch for it. > > It is -rc1 and Konstantin already submitted some changes to qp.c > > https://lore.kernel.org/all/1716366242-558-1-git-send-email-kotaranov@linux.microsoft.com/ > > > > This specific patch applies on top of Konstantin's changes cleanly. > > Yeah, once it's not buggy shared branch SG! Just to be sure, on top > of -rc1, right? Yes, it will be based on clean -rc1. Thanks
diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c index ba13c5abf8ef..2d411a16a127 100644 --- a/drivers/infiniband/hw/mana/qp.c +++ b/drivers/infiniband/hw/mana/qp.c @@ -21,7 +21,7 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev *dev, gc = mdev_to_gc(dev); - req_buf_size = struct_size(req, indir_tab, MANA_INDIRECT_TABLE_SIZE); + req_buf_size = struct_size(req, indir_tab, MANA_INDIRECT_TABLE_DEF_SIZE); req = kzalloc(req_buf_size, GFP_KERNEL); if (!req) return -ENOMEM; @@ -41,18 +41,18 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev *dev, if (log_ind_tbl_size) req->rss_enable = true; - req->num_indir_entries = MANA_INDIRECT_TABLE_SIZE; + req->num_indir_entries = MANA_INDIRECT_TABLE_DEF_SIZE; req->indir_tab_offset = offsetof(struct mana_cfg_rx_steer_req_v2, indir_tab); req->update_indir_tab = true; req->cqe_coalescing_enable = 1; /* The ind table passed to the hardware must have - * MANA_INDIRECT_TABLE_SIZE entries. Adjust the verb + * MANA_INDIRECT_TABLE_DEF_SIZE entries. Adjust the verb * ind_table to MANA_INDIRECT_TABLE_SIZE if required */ ibdev_dbg(&dev->ib_dev, "ind table size %u\n", 1 << log_ind_tbl_size); - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) { + for (i = 0; i < MANA_INDIRECT_TABLE_DEF_SIZE; i++) { req->indir_tab[i] = ind_table[i % (1 << log_ind_tbl_size)]; ibdev_dbg(&dev->ib_dev, "index %u handle 0x%llx\n", i, req->indir_tab[i]); @@ -137,7 +137,7 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd, } ind_tbl_size = 1 << ind_tbl->log_ind_tbl_size; - if (ind_tbl_size > MANA_INDIRECT_TABLE_SIZE) { + if (ind_tbl_size > MANA_INDIRECT_TABLE_DEF_SIZE) { ibdev_dbg(&mdev->ib_dev, "Indirect table size %d exceeding limit\n", ind_tbl_size); diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index d087cf954f75..851e1b9761b3 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -481,7 +481,7 @@ static int mana_get_tx_queue(struct net_device *ndev, struct sk_buff *skb, struct sock *sk = skb->sk; int txq; - txq = apc->indir_table[hash & MANA_INDIRECT_TABLE_MASK]; + txq = apc->indir_table[hash & (apc->indir_table_sz - 1)]; if (txq != old_q && sk && sk_fullsock(sk) && rcu_access_pointer(sk->sk_dst_cache)) @@ -962,7 +962,16 @@ static int mana_query_vport_cfg(struct mana_port_context *apc, u32 vport_index, *max_sq = resp.max_num_sq; *max_rq = resp.max_num_rq; - *num_indir_entry = resp.num_indirection_ent; + if (resp.num_indirection_ent > 0 && + resp.num_indirection_ent <= MANA_INDIRECT_TABLE_MAX_SIZE && + is_power_of_2(resp.num_indirection_ent)) { + *num_indir_entry = resp.num_indirection_ent; + } else { + netdev_warn(apc->ndev, + "Setting indirection table size to default %d for vPort %d\n", + MANA_INDIRECT_TABLE_DEF_SIZE, apc->port_idx); + *num_indir_entry = MANA_INDIRECT_TABLE_DEF_SIZE; + } apc->port_handle = resp.vport; ether_addr_copy(apc->mac_addr, resp.mac_addr); @@ -1054,14 +1063,13 @@ static int mana_cfg_vport_steering(struct mana_port_context *apc, bool update_default_rxobj, bool update_key, bool update_tab) { - u16 num_entries = MANA_INDIRECT_TABLE_SIZE; struct mana_cfg_rx_steer_req_v2 *req; struct mana_cfg_rx_steer_resp resp = {}; struct net_device *ndev = apc->ndev; u32 req_buf_size; int err; - req_buf_size = struct_size(req, indir_tab, num_entries); + req_buf_size = struct_size(req, indir_tab, apc->indir_table_sz); req = kzalloc(req_buf_size, GFP_KERNEL); if (!req) return -ENOMEM; @@ -1072,7 +1080,7 @@ static int mana_cfg_vport_steering(struct mana_port_context *apc, req->hdr.req.msg_version = GDMA_MESSAGE_V2; req->vport = apc->port_handle; - req->num_indir_entries = num_entries; + req->num_indir_entries = apc->indir_table_sz; req->indir_tab_offset = offsetof(struct mana_cfg_rx_steer_req_v2, indir_tab); req->rx_enable = rx; @@ -1111,7 +1119,7 @@ static int mana_cfg_vport_steering(struct mana_port_context *apc, } netdev_info(ndev, "Configured steering vPort %llu entries %u\n", - apc->port_handle, num_entries); + apc->port_handle, apc->indir_table_sz); out: kfree(req); return err; @@ -2344,11 +2352,33 @@ static int mana_create_vport(struct mana_port_context *apc, return mana_create_txq(apc, net); } +static int mana_rss_table_alloc(struct mana_port_context *apc) +{ + if (!apc->indir_table_sz) { + netdev_err(apc->ndev, + "Indirection table size not set for vPort %d\n", + apc->port_idx); + return -EINVAL; + } + + apc->indir_table = kcalloc(apc->indir_table_sz, sizeof(u32), GFP_KERNEL); + if (!apc->indir_table) + return -ENOMEM; + + apc->rxobj_table = kcalloc(apc->indir_table_sz, sizeof(mana_handle_t), GFP_KERNEL); + if (!apc->rxobj_table) { + kfree(apc->indir_table); + return -ENOMEM; + } + + return 0; +} + static void mana_rss_table_init(struct mana_port_context *apc) { int i; - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) + for (i = 0; i < apc->indir_table_sz; i++) apc->indir_table[i] = ethtool_rxfh_indir_default(i, apc->num_queues); } @@ -2361,7 +2391,7 @@ int mana_config_rss(struct mana_port_context *apc, enum TRI_STATE rx, int i; if (update_tab) { - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) { + for (i = 0; i < apc->indir_table_sz; i++) { queue_idx = apc->indir_table[i]; apc->rxobj_table[i] = apc->rxqs[queue_idx]->rxobj; } @@ -2466,7 +2496,6 @@ static int mana_init_port(struct net_device *ndev) struct mana_port_context *apc = netdev_priv(ndev); u32 max_txq, max_rxq, max_queues; int port_idx = apc->port_idx; - u32 num_indirect_entries; int err; err = mana_init_port_context(apc); @@ -2474,7 +2503,7 @@ static int mana_init_port(struct net_device *ndev) return err; err = mana_query_vport_cfg(apc, port_idx, &max_txq, &max_rxq, - &num_indirect_entries); + &apc->indir_table_sz); if (err) { netdev_err(ndev, "Failed to query info for vPort %d\n", port_idx); @@ -2723,6 +2752,10 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, if (err) goto free_net; + err = mana_rss_table_alloc(apc); + if (err) + goto reset_apc; + netdev_lockdep_set_classes(ndev); ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; @@ -2739,11 +2772,17 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, err = register_netdev(ndev); if (err) { netdev_err(ndev, "Unable to register netdev.\n"); - goto reset_apc; + goto free_indir; } return 0; +free_indir: + apc->indir_table_sz = 0; + kfree(apc->indir_table); + apc->indir_table = NULL; + kfree(apc->rxobj_table); + apc->rxobj_table = NULL; reset_apc: kfree(apc->rxqs); apc->rxqs = NULL; @@ -2897,6 +2936,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending) { struct gdma_context *gc = gd->gdma_context; struct mana_context *ac = gd->driver_data; + struct mana_port_context *apc; struct device *dev = gc->dev; struct net_device *ndev; int err; @@ -2908,6 +2948,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending) for (i = 0; i < ac->num_ports; i++) { ndev = ac->ports[i]; + apc = netdev_priv(ndev); if (!ndev) { if (i == 0) dev_err(dev, "No net device to remove\n"); @@ -2931,6 +2972,11 @@ void mana_remove(struct gdma_dev *gd, bool suspending) } unregister_netdevice(ndev); + apc->indir_table_sz = 0; + kfree(apc->indir_table); + apc->indir_table = NULL; + kfree(apc->rxobj_table); + apc->rxobj_table = NULL; rtnl_unlock(); diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c index ab2413d71f6c..1667f18046d2 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c @@ -245,7 +245,9 @@ static u32 mana_get_rxfh_key_size(struct net_device *ndev) static u32 mana_rss_indir_size(struct net_device *ndev) { - return MANA_INDIRECT_TABLE_SIZE; + struct mana_port_context *apc = netdev_priv(ndev); + + return apc->indir_table_sz; } static int mana_get_rxfh(struct net_device *ndev, @@ -257,7 +259,7 @@ static int mana_get_rxfh(struct net_device *ndev, rxfh->hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */ if (rxfh->indir) { - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) + for (i = 0; i < apc->indir_table_sz; i++) rxfh->indir[i] = apc->indir_table[i]; } @@ -273,8 +275,8 @@ static int mana_set_rxfh(struct net_device *ndev, { struct mana_port_context *apc = netdev_priv(ndev); bool update_hash = false, update_table = false; - u32 save_table[MANA_INDIRECT_TABLE_SIZE]; u8 save_key[MANA_HASH_KEY_SIZE]; + u32 *save_table; int i, err; if (!apc->port_is_up) @@ -284,13 +286,17 @@ static int mana_set_rxfh(struct net_device *ndev, rxfh->hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; + save_table = kcalloc(apc->indir_table_sz, sizeof(u32), GFP_KERNEL); + if (!save_table) + return -ENOMEM; + if (rxfh->indir) { - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) + for (i = 0; i < apc->indir_table_sz; i++) if (rxfh->indir[i] >= apc->num_queues) return -EINVAL; update_table = true; - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) { + for (i = 0; i < apc->indir_table_sz; i++) { save_table[i] = apc->indir_table[i]; apc->indir_table[i] = rxfh->indir[i]; } @@ -306,7 +312,7 @@ static int mana_set_rxfh(struct net_device *ndev, if (err) { /* recover to original values */ if (update_table) { - for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) + for (i = 0; i < apc->indir_table_sz; i++) apc->indir_table[i] = save_table[i]; } @@ -316,6 +322,8 @@ static int mana_set_rxfh(struct net_device *ndev, mana_config_rss(apc, TRI_STATE_TRUE, update_hash, update_table); } + kfree(save_table); + return err; } diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h index 27684135bb4d..c547756c4284 100644 --- a/include/net/mana/gdma.h +++ b/include/net/mana/gdma.h @@ -543,11 +543,13 @@ enum { */ #define GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX BIT(2) #define GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECONFIG BIT(3) +#define GDMA_DRV_CAP_FLAG_1_VARIABLE_INDIRECTION_TABLE_SUPPORT BIT(5) #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_HWC_TIMEOUT_RECONFIG | \ + GDMA_DRV_CAP_FLAG_1_VARIABLE_INDIRECTION_TABLE_SUPPORT) #define GDMA_DRV_CAP_FLAGS2 0 diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h index 561f6719fb4e..59823901b74f 100644 --- a/include/net/mana/mana.h +++ b/include/net/mana/mana.h @@ -30,8 +30,8 @@ enum TRI_STATE { }; /* Number of entries for hardware indirection table must be in power of 2 */ -#define MANA_INDIRECT_TABLE_SIZE 64 -#define MANA_INDIRECT_TABLE_MASK (MANA_INDIRECT_TABLE_SIZE - 1) +#define MANA_INDIRECT_TABLE_MAX_SIZE 512 +#define MANA_INDIRECT_TABLE_DEF_SIZE 64 /* The Toeplitz hash key's length in bytes: should be multiple of 8 */ #define MANA_HASH_KEY_SIZE 40 @@ -410,10 +410,11 @@ struct mana_port_context { struct mana_tx_qp *tx_qp; /* Indirection Table for RX & TX. The values are queue indexes */ - u32 indir_table[MANA_INDIRECT_TABLE_SIZE]; + u32 *indir_table; + u32 indir_table_sz; /* Indirection table containing RxObject Handles */ - mana_handle_t rxobj_table[MANA_INDIRECT_TABLE_SIZE]; + mana_handle_t *rxobj_table; /* Hash key used by the NIC */ u8 hashkey[MANA_HASH_KEY_SIZE];