diff options
| author | Hariprasad Shenai <hariprasad@chelsio.com> | 2015-03-26 00:34:25 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-03-29 15:24:42 -0400 |
| commit | 4b8e27a86d209063d8aacfb918668bbb75e56019 (patch) | |
| tree | 36b896c22a4259766c37f7e64a452c58e64dcffb | |
| parent | f243e5a7859a24d10975afb9a1708cac624ba6f1 (diff) | |
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: Hariprasad Shenai <hariprasad@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 12 | ||||
| -rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 79 | ||||
| -rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/sge.c | 7 |
3 files changed, 83 insertions, 15 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 97842d03675b..8816c645de7d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | |||
| @@ -376,8 +376,6 @@ enum { | |||
| 376 | enum { | 376 | enum { |
| 377 | INGQ_EXTRAS = 2, /* firmware event queue and */ | 377 | INGQ_EXTRAS = 2, /* firmware event queue and */ |
| 378 | /* forwarded interrupts */ | 378 | /* forwarded interrupts */ |
| 379 | MAX_EGRQ = MAX_ETH_QSETS*2 + MAX_OFLD_QSETS*2 | ||
| 380 | + MAX_CTRL_QUEUES + MAX_RDMA_QUEUES + MAX_ISCSI_QUEUES, | ||
| 381 | MAX_INGQ = MAX_ETH_QSETS + MAX_OFLD_QSETS + MAX_RDMA_QUEUES | 379 | MAX_INGQ = MAX_ETH_QSETS + MAX_OFLD_QSETS + MAX_RDMA_QUEUES |
| 382 | + MAX_RDMA_CIQS + MAX_ISCSI_QUEUES + INGQ_EXTRAS, | 380 | + MAX_RDMA_CIQS + MAX_ISCSI_QUEUES + INGQ_EXTRAS, |
| 383 | }; | 381 | }; |
| @@ -616,11 +614,13 @@ struct sge { | |||
| 616 | unsigned int idma_qid[2]; /* SGE IDMA Hung Ingress Queue ID */ | 614 | unsigned int idma_qid[2]; /* SGE IDMA Hung Ingress Queue ID */ |
| 617 | 615 | ||
| 618 | unsigned int egr_start; | 616 | unsigned int egr_start; |
| 617 | unsigned int egr_sz; | ||
| 619 | unsigned int ingr_start; | 618 | unsigned int ingr_start; |
| 620 | void *egr_map[MAX_EGRQ]; /* qid->queue egress queue map */ | 619 | unsigned int ingr_sz; |
| 621 | struct sge_rspq *ingr_map[MAX_INGQ]; /* qid->queue ingress queue map */ | 620 | void **egr_map; /* qid->queue egress queue map */ |
| 622 | DECLARE_BITMAP(starving_fl, MAX_EGRQ); | 621 | struct sge_rspq **ingr_map; /* qid->queue ingress queue map */ |
| 623 | DECLARE_BITMAP(txq_maperr, MAX_EGRQ); | 622 | unsigned long *starving_fl; |
| 623 | unsigned long *txq_maperr; | ||
| 624 | struct timer_list rx_timer; /* refills starving FLs */ | 624 | struct timer_list rx_timer; /* refills starving FLs */ |
| 625 | struct timer_list tx_timer; /* checks Tx queues */ | 625 | struct timer_list tx_timer; /* checks Tx queues */ |
| 626 | }; | 626 | }; |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index a22cf932ca35..b9b5a7b1a116 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | |||
| @@ -920,7 +920,7 @@ static void quiesce_rx(struct adapter *adap) | |||
| 920 | { | 920 | { |
| 921 | int i; | 921 | int i; |
| 922 | 922 | ||
| 923 | for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) { | 923 | for (i = 0; i < adap->sge.ingr_sz; i++) { |
| 924 | struct sge_rspq *q = adap->sge.ingr_map[i]; | 924 | struct sge_rspq *q = adap->sge.ingr_map[i]; |
| 925 | 925 | ||
| 926 | if (q && q->handler) { | 926 | if (q && q->handler) { |
| @@ -941,7 +941,7 @@ static void enable_rx(struct adapter *adap) | |||
| 941 | { | 941 | { |
| 942 | int i; | 942 | int i; |
| 943 | 943 | ||
| 944 | for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) { | 944 | for (i = 0; i < adap->sge.ingr_sz; i++) { |
| 945 | struct sge_rspq *q = adap->sge.ingr_map[i]; | 945 | struct sge_rspq *q = adap->sge.ingr_map[i]; |
| 946 | 946 | ||
| 947 | if (!q) | 947 | if (!q) |
| @@ -970,8 +970,8 @@ static int setup_sge_queues(struct adapter *adap) | |||
| 970 | int err, msi_idx, i, j; | 970 | int err, msi_idx, i, j; |
| 971 | struct sge *s = &adap->sge; | 971 | struct sge *s = &adap->sge; |
| 972 | 972 | ||
| 973 | bitmap_zero(s->starving_fl, MAX_EGRQ); | 973 | bitmap_zero(s->starving_fl, s->egr_sz); |
| 974 | bitmap_zero(s->txq_maperr, MAX_EGRQ); | 974 | bitmap_zero(s->txq_maperr, s->egr_sz); |
| 975 | 975 | ||
| 976 | if (adap->flags & USING_MSIX) | 976 | if (adap->flags & USING_MSIX) |
| 977 | msi_idx = 1; /* vector 0 is for non-queue interrupts */ | 977 | msi_idx = 1; /* vector 0 is for non-queue interrupts */ |
| @@ -983,6 +983,19 @@ static int setup_sge_queues(struct adapter *adap) | |||
| 983 | msi_idx = -((int)s->intrq.abs_id + 1); | 983 | msi_idx = -((int)s->intrq.abs_id + 1); |
| 984 | } | 984 | } |
| 985 | 985 | ||
| 986 | /* NOTE: If you add/delete any Ingress/Egress Queue allocations in here, | ||
| 987 | * don't forget to update the following which need to be | ||
| 988 | * synchronized to and changes here. | ||
| 989 | * | ||
| 990 | * 1. The calculations of MAX_INGQ in cxgb4.h. | ||
| 991 | * | ||
| 992 | * 2. Update enable_msix/name_msix_vecs/request_msix_queue_irqs | ||
| 993 | * to accommodate any new/deleted Ingress Queues | ||
| 994 | * which need MSI-X Vectors. | ||
| 995 | * | ||
| 996 | * 3. Update sge_qinfo_show() to include information on the | ||
| 997 | * new/deleted queues. | ||
| 998 | */ | ||
| 986 | err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0], | 999 | err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0], |
| 987 | msi_idx, NULL, fwevtq_handler); | 1000 | msi_idx, NULL, fwevtq_handler); |
| 988 | if (err) { | 1001 | if (err) { |
| @@ -4733,8 +4746,9 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c) | |||
| 4733 | if (ret < 0) | 4746 | if (ret < 0) |
| 4734 | return ret; | 4747 | return ret; |
| 4735 | 4748 | ||
| 4736 | ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, MAX_EGRQ, 64, MAX_INGQ, | 4749 | ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, adap->sge.egr_sz, 64, |
| 4737 | 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, FW_CMD_CAP_PF); | 4750 | MAX_INGQ, 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, |
| 4751 | FW_CMD_CAP_PF); | ||
| 4738 | if (ret < 0) | 4752 | if (ret < 0) |
| 4739 | return ret; | 4753 | return ret; |
| 4740 | 4754 | ||
| @@ -5293,6 +5307,51 @@ static int adap_init0(struct adapter *adap) | |||
| 5293 | adap->tids.nftids = val[4] - val[3] + 1; | 5307 | adap->tids.nftids = val[4] - val[3] + 1; |
| 5294 | adap->sge.ingr_start = val[5]; | 5308 | adap->sge.ingr_start = val[5]; |
| 5295 | 5309 | ||
| 5310 | /* qids (ingress/egress) returned from firmware can be anywhere | ||
| 5311 | * in the range from EQ(IQFLINT)_START to EQ(IQFLINT)_END. | ||
| 5312 | * Hence driver needs to allocate memory for this range to | ||
| 5313 | * store the queue info. Get the highest IQFLINT/EQ index returned | ||
| 5314 | * in FW_EQ_*_CMD.alloc command. | ||
| 5315 | */ | ||
| 5316 | params[0] = FW_PARAM_PFVF(EQ_END); | ||
| 5317 | params[1] = FW_PARAM_PFVF(IQFLINT_END); | ||
| 5318 | ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val); | ||
| 5319 | if (ret < 0) | ||
| 5320 | goto bye; | ||
| 5321 | adap->sge.egr_sz = val[0] - adap->sge.egr_start + 1; | ||
| 5322 | adap->sge.ingr_sz = val[1] - adap->sge.ingr_start + 1; | ||
| 5323 | |||
| 5324 | adap->sge.egr_map = kcalloc(adap->sge.egr_sz, | ||
| 5325 | sizeof(*adap->sge.egr_map), GFP_KERNEL); | ||
| 5326 | if (!adap->sge.egr_map) { | ||
| 5327 | ret = -ENOMEM; | ||
| 5328 | goto bye; | ||
| 5329 | } | ||
| 5330 | |||
| 5331 | adap->sge.ingr_map = kcalloc(adap->sge.ingr_sz, | ||
| 5332 | sizeof(*adap->sge.ingr_map), GFP_KERNEL); | ||
| 5333 | if (!adap->sge.ingr_map) { | ||
| 5334 | ret = -ENOMEM; | ||
| 5335 | goto bye; | ||
| 5336 | } | ||
| 5337 | |||
| 5338 | /* Allocate the memory for the vaious egress queue bitmaps | ||
| 5339 | * ie starving_fl and txq_maperr. | ||
| 5340 | */ | ||
| 5341 | adap->sge.starving_fl = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz), | ||
| 5342 | sizeof(long), GFP_KERNEL); | ||
| 5343 | if (!adap->sge.starving_fl) { | ||
| 5344 | ret = -ENOMEM; | ||
| 5345 | goto bye; | ||
| 5346 | } | ||
| 5347 | |||
| 5348 | adap->sge.txq_maperr = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz), | ||
| 5349 | sizeof(long), GFP_KERNEL); | ||
| 5350 | if (!adap->sge.txq_maperr) { | ||
| 5351 | ret = -ENOMEM; | ||
| 5352 | goto bye; | ||
| 5353 | } | ||
| 5354 | |||
| 5296 | params[0] = FW_PARAM_PFVF(CLIP_START); | 5355 | params[0] = FW_PARAM_PFVF(CLIP_START); |
| 5297 | params[1] = FW_PARAM_PFVF(CLIP_END); | 5356 | params[1] = FW_PARAM_PFVF(CLIP_END); |
| 5298 | ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val); | 5357 | ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val); |
| @@ -5501,6 +5560,10 @@ static int adap_init0(struct adapter *adap) | |||
| 5501 | * happened to HW/FW, stop issuing commands. | 5560 | * happened to HW/FW, stop issuing commands. |
| 5502 | */ | 5561 | */ |
| 5503 | bye: | 5562 | bye: |
| 5563 | kfree(adap->sge.egr_map); | ||
| 5564 | kfree(adap->sge.ingr_map); | ||
| 5565 | kfree(adap->sge.starving_fl); | ||
| 5566 | kfree(adap->sge.txq_maperr); | ||
| 5504 | if (ret != -ETIMEDOUT && ret != -EIO) | 5567 | if (ret != -ETIMEDOUT && ret != -EIO) |
| 5505 | t4_fw_bye(adap, adap->mbox); | 5568 | t4_fw_bye(adap, adap->mbox); |
| 5506 | return ret; | 5569 | return ret; |
| @@ -5912,6 +5975,10 @@ static void free_some_resources(struct adapter *adapter) | |||
| 5912 | 5975 | ||
| 5913 | t4_free_mem(adapter->l2t); | 5976 | t4_free_mem(adapter->l2t); |
| 5914 | t4_free_mem(adapter->tids.tid_tab); | 5977 | t4_free_mem(adapter->tids.tid_tab); |
| 5978 | kfree(adapter->sge.egr_map); | ||
| 5979 | kfree(adapter->sge.ingr_map); | ||
| 5980 | kfree(adapter->sge.starving_fl); | ||
| 5981 | kfree(adapter->sge.txq_maperr); | ||
| 5915 | disable_msi(adapter); | 5982 | disable_msi(adapter); |
| 5916 | 5983 | ||
| 5917 | for_each_port(adapter, i) | 5984 | for_each_port(adapter, i) |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index b4b9f6048fe7..b688b32c21fe 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c | |||
| @@ -2171,7 +2171,7 @@ static void sge_rx_timer_cb(unsigned long data) | |||
| 2171 | struct adapter *adap = (struct adapter *)data; | 2171 | struct adapter *adap = (struct adapter *)data; |
| 2172 | struct sge *s = &adap->sge; | 2172 | struct sge *s = &adap->sge; |
| 2173 | 2173 | ||
| 2174 | for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++) | 2174 | for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++) |
| 2175 | for (m = s->starving_fl[i]; m; m &= m - 1) { | 2175 | for (m = s->starving_fl[i]; m; m &= m - 1) { |
| 2176 | struct sge_eth_rxq *rxq; | 2176 | struct sge_eth_rxq *rxq; |
| 2177 | unsigned int id = __ffs(m) + i * BITS_PER_LONG; | 2177 | unsigned int id = __ffs(m) + i * BITS_PER_LONG; |
| @@ -2259,7 +2259,7 @@ static void sge_tx_timer_cb(unsigned long data) | |||
| 2259 | struct adapter *adap = (struct adapter *)data; | 2259 | struct adapter *adap = (struct adapter *)data; |
| 2260 | struct sge *s = &adap->sge; | 2260 | struct sge *s = &adap->sge; |
| 2261 | 2261 | ||
| 2262 | for (i = 0; i < ARRAY_SIZE(s->txq_maperr); i++) | 2262 | for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++) |
| 2263 | for (m = s->txq_maperr[i]; m; m &= m - 1) { | 2263 | for (m = s->txq_maperr[i]; m; m &= m - 1) { |
| 2264 | unsigned long id = __ffs(m) + i * BITS_PER_LONG; | 2264 | unsigned long id = __ffs(m) + i * BITS_PER_LONG; |
| 2265 | struct sge_ofld_txq *txq = s->egr_map[id]; | 2265 | struct sge_ofld_txq *txq = s->egr_map[id]; |
| @@ -2741,7 +2741,8 @@ void t4_free_sge_resources(struct adapter *adap) | |||
| 2741 | free_rspq_fl(adap, &adap->sge.intrq, NULL); | 2741 | free_rspq_fl(adap, &adap->sge.intrq, NULL); |
| 2742 | 2742 | ||
| 2743 | /* clear the reverse egress queue map */ | 2743 | /* clear the reverse egress queue map */ |
| 2744 | memset(adap->sge.egr_map, 0, sizeof(adap->sge.egr_map)); | 2744 | memset(adap->sge.egr_map, 0, |
| 2745 | adap->sge.egr_sz * sizeof(*adap->sge.egr_map)); | ||
| 2745 | } | 2746 | } |
| 2746 | 2747 | ||
| 2747 | void t4_sge_start(struct adapter *adap) | 2748 | void t4_sge_start(struct adapter *adap) |
