diff options
Diffstat (limited to 'drivers/net/ethernet/microsoft/mana/mana_en.c')
| -rw-r--r-- | drivers/net/ethernet/microsoft/mana/mana_en.c | 203 | 
1 files changed, 173 insertions, 30 deletions
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index 9259a74eca40..6120f2b6684f 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -12,7 +12,20 @@  #include <net/checksum.h>  #include <net/ip6_checksum.h> -#include "mana.h" +#include <net/mana/mana.h> +#include <net/mana/mana_auxiliary.h> + +static DEFINE_IDA(mana_adev_ida); + +static int mana_adev_idx_alloc(void) +{ +	return ida_alloc(&mana_adev_ida, GFP_KERNEL); +} + +static void mana_adev_idx_free(int idx) +{ +	ida_free(&mana_adev_ida, idx); +}  /* Microsoft Azure Network Adapter (MANA) functions */ @@ -128,7 +141,7 @@ frag_err:  	return -ENOMEM;  } -int mana_start_xmit(struct sk_buff *skb, struct net_device *ndev) +netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)  {  	enum mana_tx_pkt_format pkt_fmt = MANA_SHORT_PKT_FMT;  	struct mana_port_context *apc = netdev_priv(ndev); @@ -176,7 +189,7 @@ int mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)  	pkg.wqe_req.client_data_unit = 0;  	pkg.wqe_req.num_sge = 1 + skb_shinfo(skb)->nr_frags; -	WARN_ON_ONCE(pkg.wqe_req.num_sge > 30); +	WARN_ON_ONCE(pkg.wqe_req.num_sge > MAX_TX_WQE_SGL_ENTRIES);  	if (pkg.wqe_req.num_sge <= ARRAY_SIZE(pkg.sgl_array)) {  		pkg.wqe_req.sgl = pkg.sgl_array; @@ -315,10 +328,10 @@ static void mana_get_stats64(struct net_device *ndev,  		rx_stats = &apc->rxqs[q]->stats;  		do { -			start = u64_stats_fetch_begin_irq(&rx_stats->syncp); +			start = u64_stats_fetch_begin(&rx_stats->syncp);  			packets = rx_stats->packets;  			bytes = rx_stats->bytes; -		} while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); +		} while (u64_stats_fetch_retry(&rx_stats->syncp, start));  		st->rx_packets += packets;  		st->rx_bytes += bytes; @@ -328,10 +341,10 @@ static void mana_get_stats64(struct net_device *ndev,  		tx_stats = &apc->tx_qp[q].txq.stats;  		do { -			start = u64_stats_fetch_begin_irq(&tx_stats->syncp); +			start = u64_stats_fetch_begin(&tx_stats->syncp);  			packets = tx_stats->packets;  			bytes = tx_stats->bytes; -		} while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); +		} while (u64_stats_fetch_retry(&tx_stats->syncp, start));  		st->tx_packets += packets;  		st->tx_bytes += bytes; @@ -633,13 +646,48 @@ static int mana_query_vport_cfg(struct mana_port_context *apc, u32 vport_index,  	return 0;  } -static 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) +{ +	mutex_lock(&apc->vport_mutex); +	apc->vport_use_count--; +	WARN_ON(apc->vport_use_count < 0); +	mutex_unlock(&apc->vport_mutex); +} +EXPORT_SYMBOL_NS(mana_uncfg_vport, NET_MANA); + +int mana_cfg_vport(struct mana_port_context *apc, u32 protection_dom_id, +		   u32 doorbell_pg_id)  {  	struct mana_config_vport_resp resp = {};  	struct mana_config_vport_req req = {};  	int err; +	/* This function is used to program the Ethernet port in the hardware +	 * table. It can be called from the Ethernet driver or the RDMA driver. +	 * +	 * For Ethernet usage, the hardware supports only one active user on a +	 * physical port. The driver checks on the port usage before programming +	 * the hardware when creating the RAW QP (RDMA driver) or exposing the +	 * device to kernel NET layer (Ethernet driver). +	 * +	 * Because the RDMA driver doesn't know in advance which QP type the +	 * user will create, it exposes the device with all its ports. The user +	 * may not be able to create RAW QP on a port if this port is already +	 * in used by the Ethernet driver from the kernel. +	 * +	 * This physical port limitation only applies to the RAW QP. For RC QP, +	 * the hardware doesn't have this limitation. The user can create RC +	 * QPs on a physical port up to the hardware limits independent of the +	 * Ethernet usage on the same port. +	 */ +	mutex_lock(&apc->vport_mutex); +	if (apc->vport_use_count > 0) { +		mutex_unlock(&apc->vport_mutex); +		return -EBUSY; +	} +	apc->vport_use_count++; +	mutex_unlock(&apc->vport_mutex); +  	mana_gd_init_req_hdr(&req.hdr, MANA_CONFIG_VPORT_TX,  			     sizeof(req), sizeof(resp));  	req.vport = apc->port_handle; @@ -666,9 +714,16 @@ static int mana_cfg_vport(struct mana_port_context *apc, u32 protection_dom_id,  	apc->tx_shortform_allowed = resp.short_form_allowed;  	apc->tx_vp_offset = resp.tx_vport_offset; + +	netdev_info(apc->ndev, "Configured vPort %llu PD %u DB %u\n", +		    apc->port_handle, protection_dom_id, doorbell_pg_id);  out: +	if (err) +		mana_uncfg_vport(apc); +  	return err;  } +EXPORT_SYMBOL_NS(mana_cfg_vport, NET_MANA);  static int mana_cfg_vport_steering(struct mana_port_context *apc,  				   enum TRI_STATE rx, @@ -729,16 +784,19 @@ static int mana_cfg_vport_steering(struct mana_port_context *apc,  			   resp.hdr.status);  		err = -EPROTO;  	} + +	netdev_info(ndev, "Configured steering vPort %llu entries %u\n", +		    apc->port_handle, num_entries);  out:  	kfree(req);  	return err;  } -static int mana_create_wq_obj(struct mana_port_context *apc, -			      mana_handle_t vport, -			      u32 wq_type, struct mana_obj_spec *wq_spec, -			      struct mana_obj_spec *cq_spec, -			      mana_handle_t *wq_obj) +int mana_create_wq_obj(struct mana_port_context *apc, +		       mana_handle_t vport, +		       u32 wq_type, struct mana_obj_spec *wq_spec, +		       struct mana_obj_spec *cq_spec, +		       mana_handle_t *wq_obj)  {  	struct mana_create_wqobj_resp resp = {};  	struct mana_create_wqobj_req req = {}; @@ -787,9 +845,10 @@ static int mana_create_wq_obj(struct mana_port_context *apc,  out:  	return err;  } +EXPORT_SYMBOL_NS(mana_create_wq_obj, NET_MANA); -static void mana_destroy_wq_obj(struct mana_port_context *apc, u32 wq_type, -				mana_handle_t wq_obj) +void mana_destroy_wq_obj(struct mana_port_context *apc, u32 wq_type, +			 mana_handle_t wq_obj)  {  	struct mana_destroy_wqobj_resp resp = {};  	struct mana_destroy_wqobj_req req = {}; @@ -814,6 +873,7 @@ static void mana_destroy_wq_obj(struct mana_port_context *apc, u32 wq_type,  		netdev_err(ndev, "Failed to destroy WQ object: %d, 0x%x\n", err,  			   resp.hdr.status);  } +EXPORT_SYMBOL_NS(mana_destroy_wq_obj, NET_MANA);  static void mana_destroy_eq(struct mana_context *ac)  { @@ -1303,10 +1363,11 @@ static void mana_poll_rx_cq(struct mana_cq *cq)  		xdp_do_flush();  } -static void mana_cq_handler(void *context, struct gdma_queue *gdma_queue) +static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)  {  	struct mana_cq *cq = context;  	u8 arm_bit; +	int w;  	WARN_ON_ONCE(cq->gdma_cq != gdma_queue); @@ -1315,26 +1376,31 @@ static void mana_cq_handler(void *context, struct gdma_queue *gdma_queue)  	else  		mana_poll_tx_cq(cq); -	if (cq->work_done < cq->budget && -	    napi_complete_done(&cq->napi, cq->work_done)) { +	w = cq->work_done; + +	if (w < cq->budget && +	    napi_complete_done(&cq->napi, w)) {  		arm_bit = SET_ARM_BIT;  	} else {  		arm_bit = 0;  	}  	mana_gd_ring_cq(gdma_queue, arm_bit); + +	return w;  }  static int mana_poll(struct napi_struct *napi, int budget)  {  	struct mana_cq *cq = container_of(napi, struct mana_cq, napi); +	int w;  	cq->work_done = 0;  	cq->budget = budget; -	mana_cq_handler(cq, cq->gdma_cq); +	w = mana_cq_handler(cq, cq->gdma_cq); -	return min(cq->work_done, budget); +	return min(w, budget);  }  static void mana_schedule_napi(void *context, struct gdma_queue *gdma_queue) @@ -1463,10 +1529,10 @@ static int mana_create_txq(struct mana_port_context *apc,  		memset(&wq_spec, 0, sizeof(wq_spec));  		memset(&cq_spec, 0, sizeof(cq_spec)); -		wq_spec.gdma_region = txq->gdma_sq->mem_info.gdma_region; +		wq_spec.gdma_region = txq->gdma_sq->mem_info.dma_region_handle;  		wq_spec.queue_size = txq->gdma_sq->queue_size; -		cq_spec.gdma_region = cq->gdma_cq->mem_info.gdma_region; +		cq_spec.gdma_region = cq->gdma_cq->mem_info.dma_region_handle;  		cq_spec.queue_size = cq->gdma_cq->queue_size;  		cq_spec.modr_ctx_id = 0;  		cq_spec.attached_eq = cq->gdma_cq->cq.parent->id; @@ -1481,8 +1547,10 @@ static int mana_create_txq(struct mana_port_context *apc,  		txq->gdma_sq->id = wq_spec.queue_index;  		cq->gdma_cq->id = cq_spec.queue_index; -		txq->gdma_sq->mem_info.gdma_region = GDMA_INVALID_DMA_REGION; -		cq->gdma_cq->mem_info.gdma_region = GDMA_INVALID_DMA_REGION; +		txq->gdma_sq->mem_info.dma_region_handle = +			GDMA_INVALID_DMA_REGION; +		cq->gdma_cq->mem_info.dma_region_handle = +			GDMA_INVALID_DMA_REGION;  		txq->gdma_txq_id = txq->gdma_sq->id; @@ -1693,10 +1761,10 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,  	memset(&wq_spec, 0, sizeof(wq_spec));  	memset(&cq_spec, 0, sizeof(cq_spec)); -	wq_spec.gdma_region = rxq->gdma_rq->mem_info.gdma_region; +	wq_spec.gdma_region = rxq->gdma_rq->mem_info.dma_region_handle;  	wq_spec.queue_size = rxq->gdma_rq->queue_size; -	cq_spec.gdma_region = cq->gdma_cq->mem_info.gdma_region; +	cq_spec.gdma_region = cq->gdma_cq->mem_info.dma_region_handle;  	cq_spec.queue_size = cq->gdma_cq->queue_size;  	cq_spec.modr_ctx_id = 0;  	cq_spec.attached_eq = cq->gdma_cq->cq.parent->id; @@ -1709,8 +1777,8 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,  	rxq->gdma_rq->id = wq_spec.queue_index;  	cq->gdma_cq->id = cq_spec.queue_index; -	rxq->gdma_rq->mem_info.gdma_region = GDMA_INVALID_DMA_REGION; -	cq->gdma_cq->mem_info.gdma_region = GDMA_INVALID_DMA_REGION; +	rxq->gdma_rq->mem_info.dma_region_handle = GDMA_INVALID_DMA_REGION; +	cq->gdma_cq->mem_info.dma_region_handle = GDMA_INVALID_DMA_REGION;  	rxq->gdma_id = rxq->gdma_rq->id;  	cq->gdma_id = cq->gdma_cq->id; @@ -1791,6 +1859,7 @@ static void mana_destroy_vport(struct mana_port_context *apc)  	}  	mana_destroy_txq(apc); +	mana_uncfg_vport(apc);  	if (gd->gdma_context->is_pf)  		mana_pf_deregister_hw_vport(apc); @@ -2063,12 +2132,16 @@ static int mana_probe_port(struct mana_context *ac, int port_idx,  	apc->pf_filter_handle = INVALID_MANA_HANDLE;  	apc->port_idx = port_idx; +	mutex_init(&apc->vport_mutex); +	apc->vport_use_count = 0; +  	ndev->netdev_ops = &mana_devops;  	ndev->ethtool_ops = &mana_ethtool_ops;  	ndev->mtu = ETH_DATA_LEN;  	ndev->max_mtu = ndev->mtu;  	ndev->min_mtu = ndev->mtu;  	ndev->needed_headroom = MANA_HEADROOM; +	ndev->dev_port = port_idx;  	SET_NETDEV_DEV(ndev, gc->dev);  	netif_carrier_off(ndev); @@ -2087,6 +2160,8 @@ static int mana_probe_port(struct mana_context *ac, int port_idx,  	ndev->hw_features |= NETIF_F_RXHASH;  	ndev->features = ndev->hw_features;  	ndev->vlan_features = 0; +	ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | +			     NETDEV_XDP_ACT_NDO_XMIT;  	err = register_netdev(ndev);  	if (err) { @@ -2106,6 +2181,69 @@ free_net:  	return err;  } +static void adev_release(struct device *dev) +{ +	struct mana_adev *madev = container_of(dev, struct mana_adev, adev.dev); + +	kfree(madev); +} + +static void remove_adev(struct gdma_dev *gd) +{ +	struct auxiliary_device *adev = gd->adev; +	int id = adev->id; + +	auxiliary_device_delete(adev); +	auxiliary_device_uninit(adev); + +	mana_adev_idx_free(id); +	gd->adev = NULL; +} + +static int add_adev(struct gdma_dev *gd) +{ +	struct auxiliary_device *adev; +	struct mana_adev *madev; +	int ret; + +	madev = kzalloc(sizeof(*madev), GFP_KERNEL); +	if (!madev) +		return -ENOMEM; + +	adev = &madev->adev; +	ret = mana_adev_idx_alloc(); +	if (ret < 0) +		goto idx_fail; +	adev->id = ret; + +	adev->name = "rdma"; +	adev->dev.parent = gd->gdma_context->dev; +	adev->dev.release = adev_release; +	madev->mdev = gd; + +	ret = auxiliary_device_init(adev); +	if (ret) +		goto init_fail; + +	ret = auxiliary_device_add(adev); +	if (ret) +		goto add_fail; + +	gd->adev = adev; +	return 0; + +add_fail: +	auxiliary_device_uninit(adev); + +init_fail: +	mana_adev_idx_free(adev->id); + +idx_fail: +	kfree(madev); + +	return ret; +} +  int mana_probe(struct gdma_dev *gd, bool resuming)  {  	struct gdma_context *gc = gd->gdma_context; @@ -2173,6 +2311,8 @@ int mana_probe(struct gdma_dev *gd, bool resuming)  				break;  		}  	} + +	err = add_adev(gd);  out:  	if (err)  		mana_remove(gd, false); @@ -2189,6 +2329,10 @@ void mana_remove(struct gdma_dev *gd, bool suspending)  	int err;  	int i; +	/* adev currently doesn't support suspending, always remove it */ +	if (gd->adev) +		remove_adev(gd); +  	for (i = 0; i < ac->num_ports; i++) {  		ndev = ac->ports[i];  		if (!ndev) { @@ -2221,7 +2365,6 @@ void mana_remove(struct gdma_dev *gd, bool suspending)  	}  	mana_destroy_eq(ac); -  out:  	mana_gd_deregister_device(gd);  |