| b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | From fe7ed61721646077de5eb06a105e60634374a00c Mon Sep 17 00:00:00 2001 | 
 | 2 | From: Camelia Groza <camelia.groza@nxp.com> | 
 | 3 | Date: Thu, 31 May 2018 10:45:50 +0300 | 
 | 4 | Subject: [PATCH] sdk_dpaa: ceetm: drain the ceetm CQs on destroy | 
 | 5 |  | 
 | 6 | The CEETM CQs must be empty when configured. To guarantee this, stop all | 
 | 7 | transmissions and wait for them to drain before releasing them. On the | 
 | 8 | next configuration, we are certain they will be empty. | 
 | 9 |  | 
 | 10 | Signed-off-by: Camelia Groza <camelia.groza@nxp.com> | 
 | 11 | --- | 
 | 12 |  .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 62 ++++++++++++++++++++++ | 
 | 13 |  1 file changed, 62 insertions(+) | 
 | 14 |  | 
 | 15 | --- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 
 | 16 | +++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 
 | 17 | @@ -90,6 +90,51 @@ static void dpaa_drain_fqs(struct net_de | 
 | 18 |  	} | 
 | 19 |  } | 
 | 20 |   | 
 | 21 | +/* Wait for the DPAA CEETM TX CQs to empty */ | 
 | 22 | +static void ceetm_drain_class(struct ceetm_class *cl) | 
 | 23 | +{ | 
 | 24 | +	struct qm_mcr_ceetm_cq_query cq_query; | 
 | 25 | +	struct qm_ceetm_cq *cq; | 
 | 26 | +	unsigned int idx; | 
 | 27 | +	int ret; | 
 | 28 | + | 
 | 29 | +	if (!cl) | 
 | 30 | +		return; | 
 | 31 | + | 
 | 32 | +	switch (cl->type) { | 
 | 33 | +	case CEETM_ROOT: | 
 | 34 | +		/* The ROOT classes aren't directly linked to CEETM CQs */ | 
 | 35 | +		return; | 
 | 36 | +	case CEETM_PRIO: | 
 | 37 | +		cq = (struct qm_ceetm_cq*)cl->prio.cq; | 
 | 38 | +		break; | 
 | 39 | +	case CEETM_WBFS: | 
 | 40 | +		cq = (struct qm_ceetm_cq*)cl->wbfs.cq; | 
 | 41 | +		break; | 
 | 42 | +	} | 
 | 43 | + | 
 | 44 | +	if (!cq || !cl->ch) | 
 | 45 | +		return; | 
 | 46 | + | 
 | 47 | +	/* Build the query CQID by merging the channel and the CQ IDs */ | 
 | 48 | +	idx = (cq->parent->idx << 4) | cq->idx; | 
 | 49 | + | 
 | 50 | +	while (true) { | 
 | 51 | +		ret = qman_ceetm_query_cq(idx, | 
 | 52 | +					  cl->ch->dcp_idx, | 
 | 53 | +					  &cq_query); | 
 | 54 | +		if (unlikely(ret)) { | 
 | 55 | +			pr_err(KBUILD_BASENAME | 
 | 56 | +			       " : %s : unable to query CQ %x: %d\n", | 
 | 57 | +			       __func__, idx, ret); | 
 | 58 | +			break; | 
 | 59 | +		} | 
 | 60 | + | 
 | 61 | +		if (cq_query.frm_cnt == 0) | 
 | 62 | +			break; | 
 | 63 | +	} | 
 | 64 | +} | 
 | 65 | + | 
 | 66 |  /* Enqueue Rejection Notification callback */ | 
 | 67 |  static void ceetm_ern(struct qman_portal *portal, struct qman_fq *fq, | 
 | 68 |  		      const struct qm_mr_entry *msg) | 
 | 69 | @@ -376,6 +421,8 @@ static void ceetm_link_class(struct Qdis | 
 | 70 |  /* Destroy a ceetm class */ | 
 | 71 |  static void ceetm_cls_destroy(struct Qdisc *sch, struct ceetm_class *cl) | 
 | 72 |  { | 
 | 73 | +	struct net_device *dev = qdisc_dev(sch); | 
 | 74 | + | 
 | 75 |  	if (!cl) | 
 | 76 |  		return; | 
 | 77 |   | 
 | 78 | @@ -402,6 +449,12 @@ static void ceetm_cls_destroy(struct Qdi | 
 | 79 |  			cl->prio.child = NULL; | 
 | 80 |  		} | 
 | 81 |   | 
 | 82 | +		/* We must make sure the CQ is empty before releasing it. | 
 | 83 | +		 * Pause all transmissions while we wait for it to drain. | 
 | 84 | +		 */ | 
 | 85 | +		netif_tx_stop_all_queues(dev); | 
 | 86 | +		ceetm_drain_class(cl); | 
 | 87 | + | 
 | 88 |  		if (cl->prio.lfq && qman_ceetm_lfq_release(cl->prio.lfq)) | 
 | 89 |  			pr_err(KBUILD_BASENAME | 
 | 90 |  			       " : %s : error releasing the LFQ %d\n", | 
 | 91 | @@ -422,9 +475,16 @@ static void ceetm_cls_destroy(struct Qdi | 
 | 92 |  		if (cl->prio.cstats) | 
 | 93 |  			free_percpu(cl->prio.cstats); | 
 | 94 |   | 
 | 95 | +		netif_tx_wake_all_queues(dev); | 
 | 96 |  		break; | 
 | 97 |   | 
 | 98 |  	case CEETM_WBFS: | 
 | 99 | +		/* We must make sure the CQ is empty before releasing it. | 
 | 100 | +		 * Pause all transmissions while we wait for it to drain. | 
 | 101 | +		 */ | 
 | 102 | +		netif_tx_stop_all_queues(dev); | 
 | 103 | +		ceetm_drain_class(cl); | 
 | 104 | + | 
 | 105 |  		if (cl->wbfs.lfq && qman_ceetm_lfq_release(cl->wbfs.lfq)) | 
 | 106 |  			pr_err(KBUILD_BASENAME | 
 | 107 |  			       " : %s : error releasing the LFQ %d\n", | 
 | 108 | @@ -444,6 +504,8 @@ static void ceetm_cls_destroy(struct Qdi | 
 | 109 |   | 
 | 110 |  		if (cl->wbfs.cstats) | 
 | 111 |  			free_percpu(cl->wbfs.cstats); | 
 | 112 | + | 
 | 113 | +		netif_tx_wake_all_queues(dev); | 
 | 114 |  	} | 
 | 115 |   | 
 | 116 |  	tcf_block_put(cl->block); |