Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b8e27a8 authored by Hariprasad Shenai's avatar Hariprasad Shenai Committed by David S. Miller
Browse files

cxgb4: Allocate dynamic mem. for egress and ingress queue maps



QIDs (egress/ingress) from firmware in FW_*_CMD.alloc command
can be anywhere in the range from EQ(IQFLINT)_START to EQ(IQFLINT)_END.
For eg, in the first load eqid can be from 100 to 300.
In the next load it can be from 301 to 500 (assume eq_start is 100 and eq_end is
1000).

The driver was assuming them to always start from EQ(IQFLINT)_START till
MAX_EGRQ(INGQ). This was causing stack overflow and subsequent crash.

Fixed it by dynamically allocating memory (of qsize (x_END - x_START + 1)) for
these structures.

Based on original work by Santosh Rastapur <santosh@chelsio.com>

Signed-off-by: default avatarHariprasad Shenai <hariprasad@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f243e5a7
Loading
Loading
Loading
Loading
+6 −6
Original line number Original line Diff line number Diff line
@@ -376,8 +376,6 @@ enum {
enum {
enum {
	INGQ_EXTRAS = 2,        /* firmware event queue and */
	INGQ_EXTRAS = 2,        /* firmware event queue and */
				/*   forwarded interrupts */
				/*   forwarded interrupts */
	MAX_EGRQ = MAX_ETH_QSETS*2 + MAX_OFLD_QSETS*2
		   + MAX_CTRL_QUEUES + MAX_RDMA_QUEUES + MAX_ISCSI_QUEUES,
	MAX_INGQ = MAX_ETH_QSETS + MAX_OFLD_QSETS + MAX_RDMA_QUEUES
	MAX_INGQ = MAX_ETH_QSETS + MAX_OFLD_QSETS + MAX_RDMA_QUEUES
		   + MAX_RDMA_CIQS + MAX_ISCSI_QUEUES + INGQ_EXTRAS,
		   + MAX_RDMA_CIQS + MAX_ISCSI_QUEUES + INGQ_EXTRAS,
};
};
@@ -616,11 +614,13 @@ struct sge {
	unsigned int idma_qid[2];   /* SGE IDMA Hung Ingress Queue ID */
	unsigned int idma_qid[2];   /* SGE IDMA Hung Ingress Queue ID */


	unsigned int egr_start;
	unsigned int egr_start;
	unsigned int egr_sz;
	unsigned int ingr_start;
	unsigned int ingr_start;
	void *egr_map[MAX_EGRQ];    /* qid->queue egress queue map */
	unsigned int ingr_sz;
	struct sge_rspq *ingr_map[MAX_INGQ]; /* qid->queue ingress queue map */
	void **egr_map;    /* qid->queue egress queue map */
	DECLARE_BITMAP(starving_fl, MAX_EGRQ);
	struct sge_rspq **ingr_map; /* qid->queue ingress queue map */
	DECLARE_BITMAP(txq_maperr, MAX_EGRQ);
	unsigned long *starving_fl;
	unsigned long *txq_maperr;
	struct timer_list rx_timer; /* refills starving FLs */
	struct timer_list rx_timer; /* refills starving FLs */
	struct timer_list tx_timer; /* checks Tx queues */
	struct timer_list tx_timer; /* checks Tx queues */
};
};
+73 −6
Original line number Original line Diff line number Diff line
@@ -920,7 +920,7 @@ static void quiesce_rx(struct adapter *adap)
{
{
	int i;
	int i;


	for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) {
	for (i = 0; i < adap->sge.ingr_sz; i++) {
		struct sge_rspq *q = adap->sge.ingr_map[i];
		struct sge_rspq *q = adap->sge.ingr_map[i];


		if (q && q->handler) {
		if (q && q->handler) {
@@ -941,7 +941,7 @@ static void enable_rx(struct adapter *adap)
{
{
	int i;
	int i;


	for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) {
	for (i = 0; i < adap->sge.ingr_sz; i++) {
		struct sge_rspq *q = adap->sge.ingr_map[i];
		struct sge_rspq *q = adap->sge.ingr_map[i];


		if (!q)
		if (!q)
@@ -970,8 +970,8 @@ static int setup_sge_queues(struct adapter *adap)
	int err, msi_idx, i, j;
	int err, msi_idx, i, j;
	struct sge *s = &adap->sge;
	struct sge *s = &adap->sge;


	bitmap_zero(s->starving_fl, MAX_EGRQ);
	bitmap_zero(s->starving_fl, s->egr_sz);
	bitmap_zero(s->txq_maperr, MAX_EGRQ);
	bitmap_zero(s->txq_maperr, s->egr_sz);


	if (adap->flags & USING_MSIX)
	if (adap->flags & USING_MSIX)
		msi_idx = 1;         /* vector 0 is for non-queue interrupts */
		msi_idx = 1;         /* vector 0 is for non-queue interrupts */
@@ -983,6 +983,19 @@ static int setup_sge_queues(struct adapter *adap)
		msi_idx = -((int)s->intrq.abs_id + 1);
		msi_idx = -((int)s->intrq.abs_id + 1);
	}
	}


	/* NOTE: If you add/delete any Ingress/Egress Queue allocations in here,
	 * don't forget to update the following which need to be
	 * synchronized to and changes here.
	 *
	 * 1. The calculations of MAX_INGQ in cxgb4.h.
	 *
	 * 2. Update enable_msix/name_msix_vecs/request_msix_queue_irqs
	 *    to accommodate any new/deleted Ingress Queues
	 *    which need MSI-X Vectors.
	 *
	 * 3. Update sge_qinfo_show() to include information on the
	 *    new/deleted queues.
	 */
	err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0],
	err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0],
			       msi_idx, NULL, fwevtq_handler);
			       msi_idx, NULL, fwevtq_handler);
	if (err) {
	if (err) {
@@ -4733,8 +4746,9 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
	if (ret < 0)
	if (ret < 0)
		return ret;
		return ret;


	ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, MAX_EGRQ, 64, MAX_INGQ,
	ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, adap->sge.egr_sz, 64,
			  0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, FW_CMD_CAP_PF);
			  MAX_INGQ, 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF,
			  FW_CMD_CAP_PF);
	if (ret < 0)
	if (ret < 0)
		return ret;
		return ret;


@@ -5293,6 +5307,51 @@ static int adap_init0(struct adapter *adap)
	adap->tids.nftids = val[4] - val[3] + 1;
	adap->tids.nftids = val[4] - val[3] + 1;
	adap->sge.ingr_start = val[5];
	adap->sge.ingr_start = val[5];


	/* qids (ingress/egress) returned from firmware can be anywhere
	 * in the range from EQ(IQFLINT)_START to EQ(IQFLINT)_END.
	 * Hence driver needs to allocate memory for this range to
	 * store the queue info. Get the highest IQFLINT/EQ index returned
	 * in FW_EQ_*_CMD.alloc command.
	 */
	params[0] = FW_PARAM_PFVF(EQ_END);
	params[1] = FW_PARAM_PFVF(IQFLINT_END);
	ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
	if (ret < 0)
		goto bye;
	adap->sge.egr_sz = val[0] - adap->sge.egr_start + 1;
	adap->sge.ingr_sz = val[1] - adap->sge.ingr_start + 1;

	adap->sge.egr_map = kcalloc(adap->sge.egr_sz,
				    sizeof(*adap->sge.egr_map), GFP_KERNEL);
	if (!adap->sge.egr_map) {
		ret = -ENOMEM;
		goto bye;
	}

	adap->sge.ingr_map = kcalloc(adap->sge.ingr_sz,
				     sizeof(*adap->sge.ingr_map), GFP_KERNEL);
	if (!adap->sge.ingr_map) {
		ret = -ENOMEM;
		goto bye;
	}

	/* Allocate the memory for the vaious egress queue bitmaps
	 * ie starving_fl and txq_maperr.
	 */
	adap->sge.starving_fl =	kcalloc(BITS_TO_LONGS(adap->sge.egr_sz),
					sizeof(long), GFP_KERNEL);
	if (!adap->sge.starving_fl) {
		ret = -ENOMEM;
		goto bye;
	}

	adap->sge.txq_maperr = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz),
				       sizeof(long), GFP_KERNEL);
	if (!adap->sge.txq_maperr) {
		ret = -ENOMEM;
		goto bye;
	}

	params[0] = FW_PARAM_PFVF(CLIP_START);
	params[0] = FW_PARAM_PFVF(CLIP_START);
	params[1] = FW_PARAM_PFVF(CLIP_END);
	params[1] = FW_PARAM_PFVF(CLIP_END);
	ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
	ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
@@ -5501,6 +5560,10 @@ static int adap_init0(struct adapter *adap)
	 * happened to HW/FW, stop issuing commands.
	 * happened to HW/FW, stop issuing commands.
	 */
	 */
bye:
bye:
	kfree(adap->sge.egr_map);
	kfree(adap->sge.ingr_map);
	kfree(adap->sge.starving_fl);
	kfree(adap->sge.txq_maperr);
	if (ret != -ETIMEDOUT && ret != -EIO)
	if (ret != -ETIMEDOUT && ret != -EIO)
		t4_fw_bye(adap, adap->mbox);
		t4_fw_bye(adap, adap->mbox);
	return ret;
	return ret;
@@ -5912,6 +5975,10 @@ static void free_some_resources(struct adapter *adapter)


	t4_free_mem(adapter->l2t);
	t4_free_mem(adapter->l2t);
	t4_free_mem(adapter->tids.tid_tab);
	t4_free_mem(adapter->tids.tid_tab);
	kfree(adapter->sge.egr_map);
	kfree(adapter->sge.ingr_map);
	kfree(adapter->sge.starving_fl);
	kfree(adapter->sge.txq_maperr);
	disable_msi(adapter);
	disable_msi(adapter);


	for_each_port(adapter, i)
	for_each_port(adapter, i)
+4 −3
Original line number Original line Diff line number Diff line
@@ -2171,7 +2171,7 @@ static void sge_rx_timer_cb(unsigned long data)
	struct adapter *adap = (struct adapter *)data;
	struct adapter *adap = (struct adapter *)data;
	struct sge *s = &adap->sge;
	struct sge *s = &adap->sge;


	for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++)
	for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++)
		for (m = s->starving_fl[i]; m; m &= m - 1) {
		for (m = s->starving_fl[i]; m; m &= m - 1) {
			struct sge_eth_rxq *rxq;
			struct sge_eth_rxq *rxq;
			unsigned int id = __ffs(m) + i * BITS_PER_LONG;
			unsigned int id = __ffs(m) + i * BITS_PER_LONG;
@@ -2259,7 +2259,7 @@ static void sge_tx_timer_cb(unsigned long data)
	struct adapter *adap = (struct adapter *)data;
	struct adapter *adap = (struct adapter *)data;
	struct sge *s = &adap->sge;
	struct sge *s = &adap->sge;


	for (i = 0; i < ARRAY_SIZE(s->txq_maperr); i++)
	for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++)
		for (m = s->txq_maperr[i]; m; m &= m - 1) {
		for (m = s->txq_maperr[i]; m; m &= m - 1) {
			unsigned long id = __ffs(m) + i * BITS_PER_LONG;
			unsigned long id = __ffs(m) + i * BITS_PER_LONG;
			struct sge_ofld_txq *txq = s->egr_map[id];
			struct sge_ofld_txq *txq = s->egr_map[id];
@@ -2741,7 +2741,8 @@ void t4_free_sge_resources(struct adapter *adap)
		free_rspq_fl(adap, &adap->sge.intrq, NULL);
		free_rspq_fl(adap, &adap->sge.intrq, NULL);


	/* clear the reverse egress queue map */
	/* clear the reverse egress queue map */
	memset(adap->sge.egr_map, 0, sizeof(adap->sge.egr_map));
	memset(adap->sge.egr_map, 0,
	       adap->sge.egr_sz * sizeof(*adap->sge.egr_map));
}
}


void t4_sge_start(struct adapter *adap)
void t4_sge_start(struct adapter *adap)