Re: [PATCH net] net: ethernet: ti: am65-cpsw: Fix multi queue Rx on J7

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 29/10/2024 17:05, Roger Quadros wrote:
> On J7 platforms, setting up multiple RX flows was failing
> as the RX free descriptor ring 0 is shared among all flows
> and we did not allocate enough elements in the RX free descriptor
> ring 0 to accommodate for all RX flows.
> 
> This issue is not present on AM62 as separate pair of
> rings are used for free and completion rings for each flow.
> 
> Fix this by allocating enough elements for RX free descriptor
> ring 0.
> 
> However, we can no longer rely on desc_idx (descriptor based
> offsets) to identify the pages in the respective flows as
> free descriptor ring includes elements for all flows.
> To solve this, introduce a new swdata data structure to store
> flow_id and page. This can be used to identify which flow (page_pool)
> and page the descriptor belonged to when popped out of the
> RX rings.
> 
> Fixes: da70d184a8c3 ("net: ethernet: ti: am65-cpsw: Introduce multi queue Rx")
> Signed-off-by: Roger Quadros <rogerq@xxxxxxxxxx>
> ---
>  drivers/net/ethernet/ti/am65-cpsw-nuss.c | 73 +++++++++++++++-----------------
>  drivers/net/ethernet/ti/am65-cpsw-nuss.h |  6 ++-
>  2 files changed, 38 insertions(+), 41 deletions(-)
> 
> diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
> index 0520e9f4bea7..4c46574e111c 100644
> --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
> +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
> @@ -339,7 +339,7 @@ static int am65_cpsw_nuss_rx_push(struct am65_cpsw_common *common,
>  	struct device *dev = common->dev;
>  	dma_addr_t desc_dma;
>  	dma_addr_t buf_dma;
> -	void *swdata;
> +	struct am65_cpsw_swdata *swdata;
>  
>  	desc_rx = k3_cppi_desc_pool_alloc(rx_chn->desc_pool);
>  	if (!desc_rx) {
> @@ -363,7 +363,8 @@ static int am65_cpsw_nuss_rx_push(struct am65_cpsw_common *common,
>  	cppi5_hdesc_attach_buf(desc_rx, buf_dma, AM65_CPSW_MAX_PACKET_SIZE,
>  			       buf_dma, AM65_CPSW_MAX_PACKET_SIZE);
>  	swdata = cppi5_hdesc_get_swdata(desc_rx);
> -	*((void **)swdata) = page_address(page);
> +	swdata->page = page;
> +	swdata->flow_id = flow_idx;
>  
>  	return k3_udma_glue_push_rx_chn(rx_chn->rx_chn, flow_idx,
>  					desc_rx, desc_dma);
> @@ -519,36 +520,31 @@ static enum am65_cpsw_tx_buf_type am65_cpsw_nuss_buf_type(struct am65_cpsw_tx_ch
>  
>  static inline void am65_cpsw_put_page(struct am65_cpsw_rx_flow *flow,
>  				      struct page *page,
> -				      bool allow_direct,
> -				      int desc_idx)
> +				      bool allow_direct)
>  {
>  	page_pool_put_full_page(flow->page_pool, page, allow_direct);
> -	flow->pages[desc_idx] = NULL;
>  }
>  
>  static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma)
>  {
> -	struct am65_cpsw_rx_flow *flow = data;
> +	struct am65_cpsw_rx_chn *rx_chn = data;
>  	struct cppi5_host_desc_t *desc_rx;
> -	struct am65_cpsw_rx_chn *rx_chn;
> +	struct am65_cpsw_swdata *swdata;
>  	dma_addr_t buf_dma;
>  	u32 buf_dma_len;
> -	void *page_addr;
> -	void **swdata;
> -	int desc_idx;
> +	struct page *page;
> +	u32 flow_id;
>  
> -	rx_chn = &flow->common->rx_chns;
>  	desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma);
>  	swdata = cppi5_hdesc_get_swdata(desc_rx);
> -	page_addr = *swdata;
> +	page = swdata->page;
> +	flow_id = swdata->flow_id;
>  	cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len);
>  	k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);
>  	dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE);
>  	k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
>  
> -	desc_idx = am65_cpsw_nuss_desc_idx(rx_chn->desc_pool, desc_rx,
> -					   rx_chn->dsize_log2);
> -	am65_cpsw_put_page(flow, virt_to_page(page_addr), false, desc_idx);
> +	am65_cpsw_put_page(&rx_chn->flows[flow_id], page, false);
>  }
>  
>  static void am65_cpsw_nuss_xmit_free(struct am65_cpsw_tx_chn *tx_chn,
> @@ -703,14 +699,13 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common)
>  				ret = -ENOMEM;
>  				goto fail_rx;
>  			}
> -			flow->pages[i] = page;
>  
>  			ret = am65_cpsw_nuss_rx_push(common, page, flow_idx);
>  			if (ret < 0) {
>  				dev_err(common->dev,
>  					"cannot submit page to rx channel flow %d, error %d\n",
>  					flow_idx, ret);
> -				am65_cpsw_put_page(flow, page, false, i);
> +				am65_cpsw_put_page(flow, page, false);
>  				goto fail_rx;
>  			}
>  		}
> @@ -764,8 +759,8 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common)
>  
>  fail_rx:
>  	for (i = 0; i < common->rx_ch_num_flows; i++)
> -		k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, i, &rx_chn->flows[i],
> -					  am65_cpsw_nuss_rx_cleanup, 0);
> +		k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, i, rx_chn,
> +					  am65_cpsw_nuss_rx_cleanup, !!i);
>  
>  	am65_cpsw_destroy_xdp_rxqs(common);
>  
> @@ -777,6 +772,7 @@ static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common)
>  	struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns;
>  	struct am65_cpsw_tx_chn *tx_chn = common->tx_chns;
>  	int i;
> +	struct am65_cpsw_rx_flow *flow;

This is also unused. Will drop it in v2.

>  
>  	if (common->usage_count != 1)
>  		return 0;
> @@ -817,11 +813,12 @@ static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common)
>  			dev_err(common->dev, "rx teardown timeout\n");
>  	}
>  
> -	for (i = 0; i < common->rx_ch_num_flows; i++) {
> +	for (i = common->rx_ch_num_flows - 1; i >= 0; i--) {
> +		flow = &rx_chn->flows[i];
>  		napi_disable(&rx_chn->flows[i].napi_rx);
>  		hrtimer_cancel(&rx_chn->flows[i].rx_hrtimer);
> -		k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, i, &rx_chn->flows[i],
> -					  am65_cpsw_nuss_rx_cleanup, 0);
> +		k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, i, rx_chn,
> +					  am65_cpsw_nuss_rx_cleanup, !!i);
>  	}
>  
>  	k3_udma_glue_disable_rx_chn(rx_chn->rx_chn);
> @@ -1028,7 +1025,7 @@ static int am65_cpsw_xdp_tx_frame(struct net_device *ndev,
>  static int am65_cpsw_run_xdp(struct am65_cpsw_rx_flow *flow,
>  			     struct am65_cpsw_port *port,
>  			     struct xdp_buff *xdp,
> -			     int desc_idx, int cpu, int *len)
> +			     int cpu, int *len)
>  {
>  	struct am65_cpsw_common *common = flow->common;
>  	struct am65_cpsw_ndev_priv *ndev_priv;
> @@ -1101,7 +1098,7 @@ static int am65_cpsw_run_xdp(struct am65_cpsw_rx_flow *flow,
>  	}
>  
>  	page = virt_to_head_page(xdp->data);
> -	am65_cpsw_put_page(flow, page, true, desc_idx);
> +	am65_cpsw_put_page(flow, page, true);
>  
>  out:
>  	return ret;
> @@ -1150,6 +1147,7 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
>  	struct am65_cpsw_ndev_stats *stats;
>  	struct cppi5_host_desc_t *desc_rx;
>  	struct device *dev = common->dev;
> +	struct am65_cpsw_swdata *swdata;
>  	struct page *page, *new_page;
>  	dma_addr_t desc_dma, buf_dma;
>  	struct am65_cpsw_port *port;
> @@ -1159,7 +1157,6 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
>  	struct sk_buff *skb;
>  	struct xdp_buff	xdp;
>  	void *page_addr;
> -	void **swdata;
>  	u32 *psdata;
>  
>  	*xdp_state = AM65_CPSW_XDP_PASS;
> @@ -1182,8 +1179,8 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
>  		__func__, flow_idx, &desc_dma);
>  
>  	swdata = cppi5_hdesc_get_swdata(desc_rx);
> -	page_addr = *swdata;
> -	page = virt_to_page(page_addr);
> +	page = swdata->page;
> +	page_addr = page_address(page);
>  	cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len);
>  	k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);
>  	pkt_len = cppi5_hdesc_get_pktlen(desc_rx);
> @@ -1201,7 +1198,6 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
>  
>  	desc_idx = am65_cpsw_nuss_desc_idx(rx_chn->desc_pool, desc_rx,
>  					   rx_chn->dsize_log2);

This is no longer required so need to drop it.
Will send a v2.

> -
>  	skb = am65_cpsw_build_skb(page_addr, ndev,
>  				  AM65_CPSW_MAX_PACKET_SIZE);
>  	if (unlikely(!skb)) {
> @@ -1213,7 +1209,7 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
>  		xdp_init_buff(&xdp, PAGE_SIZE, &port->xdp_rxq[flow->id]);
>  		xdp_prepare_buff(&xdp, page_addr, AM65_CPSW_HEADROOM,
>  				 pkt_len, false);
> -		*xdp_state = am65_cpsw_run_xdp(flow, port, &xdp, desc_idx,
> +		*xdp_state = am65_cpsw_run_xdp(flow, port, &xdp,
>  					       cpu, &pkt_len);
>  		if (*xdp_state != AM65_CPSW_XDP_PASS)
>  			goto allocate;
> @@ -1247,10 +1243,8 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
>  		return -ENOMEM;
>  	}
>  
> -	flow->pages[desc_idx] = new_page;
> -
>  	if (netif_dormant(ndev)) {
> -		am65_cpsw_put_page(flow, new_page, true, desc_idx);
> +		am65_cpsw_put_page(flow, new_page, true);
>  		ndev->stats.rx_dropped++;
>  		return 0;
>  	}
> @@ -1258,7 +1252,7 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
>  requeue:
>  	ret = am65_cpsw_nuss_rx_push(common, new_page, flow_idx);
>  	if (WARN_ON(ret < 0)) {
> -		am65_cpsw_put_page(flow, new_page, true, desc_idx);
> +		am65_cpsw_put_page(flow, new_page, true);
>  		ndev->stats.rx_errors++;
>  		ndev->stats.rx_dropped++;
>  	}
> @@ -2402,10 +2396,6 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
>  	for (i = 0; i < common->rx_ch_num_flows; i++) {
>  		flow = &rx_chn->flows[i];
>  		flow->page_pool = NULL;
> -		flow->pages = devm_kcalloc(dev, AM65_CPSW_MAX_RX_DESC,
> -					   sizeof(*flow->pages), GFP_KERNEL);
> -		if (!flow->pages)
> -			return -ENOMEM;
>  	}
>  
>  	rx_chn->rx_chn = k3_udma_glue_request_rx_chn(dev, "rx", &rx_cfg);
> @@ -2455,10 +2445,12 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
>  		flow = &rx_chn->flows[i];
>  		flow->id = i;
>  		flow->common = common;
> +		flow->irq = -EINVAL;
>  
>  		rx_flow_cfg.ring_rxfdq0_id = fdqring_id;
>  		rx_flow_cfg.rx_cfg.size = max_desc_num;
> -		rx_flow_cfg.rxfdq_cfg.size = max_desc_num;
> +		/* share same FDQ for all flows */
> +		rx_flow_cfg.rxfdq_cfg.size = max_desc_num * rx_cfg.flow_id_num;
>  		rx_flow_cfg.rxfdq_cfg.mode = common->pdata.fdqring_mode;
>  
>  		ret = k3_udma_glue_rx_flow_init(rx_chn->rx_chn,
> @@ -2496,6 +2488,7 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
>  		if (ret) {
>  			dev_err(dev, "failure requesting rx %d irq %u, %d\n",
>  				i, flow->irq, ret);
> +			flow->irq = -EINVAL;
>  			goto err;
>  		}
>  	}
> @@ -3349,8 +3342,8 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
>  
>  	for (i = 0; i < common->rx_ch_num_flows; i++)
>  		k3_udma_glue_reset_rx_chn(rx_chan->rx_chn, i,
> -					  &rx_chan->flows[i],
> -					  am65_cpsw_nuss_rx_cleanup, 0);
> +					  rx_chan,
> +					  am65_cpsw_nuss_rx_cleanup, !!i);
>  
>  	k3_udma_glue_disable_rx_chn(rx_chan->rx_chn);
>  
> diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.h b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
> index dc8d544230dc..92a27ba4c601 100644
> --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.h
> +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
> @@ -101,10 +101,14 @@ struct am65_cpsw_rx_flow {
>  	struct hrtimer rx_hrtimer;
>  	unsigned long rx_pace_timeout;
>  	struct page_pool *page_pool;
> -	struct page **pages;
>  	char name[32];
>  };
>  
> +struct am65_cpsw_swdata {
> +	u32 flow_id;
> +	struct page *page;
> +};
> +
>  struct am65_cpsw_rx_chn {
>  	struct device *dev;
>  	struct device *dma_dev;
> 
> ---
> base-commit: 42f7652d3eb527d03665b09edac47f85fb600924
> change-id: 20241023-am65-cpsw-multi-rx-j7-fix-f9a2149be6dd
> 
> Best regards,

-- 
cheers,
-roger




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux