diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2014-06-27 11:09:25 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2014-07-22 03:26:15 -0400 |
commit | d445a4e28c0ff740e946ae22860be85428814c39 (patch) | |
tree | 500daa23bf7efe87fa5e1bbb91f77994f041e787 /drivers/s390 | |
parent | 6d284bde2beef9d4d067281b08f86554f41de799 (diff) |
s390/qeth: extract qdio buffers from output buffer struct
Because of the embedded qdio_buffer array struct qeth_qdio_out_q is
quite large resulting in an order 4 allocation. This is likely to
fail at runtime and wastes a lot of memory since the actual size is
just about 34K.
Since there is no need for this buffer to be contiguous split it up
using qdio buffer helpers.
Reported-by: Neale Ferguson <neale@sinenomine.net>
Reviewed-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/net/qeth_core.h | 4 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 91 |
2 files changed, 58 insertions, 37 deletions
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 4f9a3180f663..4b32608e79f9 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
@@ -465,7 +465,7 @@ enum qeth_out_q_states { | |||
465 | }; | 465 | }; |
466 | 466 | ||
467 | struct qeth_qdio_out_q { | 467 | struct qeth_qdio_out_q { |
468 | struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q]; | 468 | struct qdio_buffer *qdio_bufs[QDIO_MAX_BUFFERS_PER_Q]; |
469 | struct qeth_qdio_out_buffer *bufs[QDIO_MAX_BUFFERS_PER_Q]; | 469 | struct qeth_qdio_out_buffer *bufs[QDIO_MAX_BUFFERS_PER_Q]; |
470 | struct qdio_outbuf_state *bufstates; /* convenience pointer */ | 470 | struct qdio_outbuf_state *bufstates; /* convenience pointer */ |
471 | int queue_no; | 471 | int queue_no; |
@@ -483,7 +483,7 @@ struct qeth_qdio_out_q { | |||
483 | atomic_t used_buffers; | 483 | atomic_t used_buffers; |
484 | /* indicates whether PCI flag must be set (or if one is outstanding) */ | 484 | /* indicates whether PCI flag must be set (or if one is outstanding) */ |
485 | atomic_t set_pci_flags_count; | 485 | atomic_t set_pci_flags_count; |
486 | } __attribute__ ((aligned(256))); | 486 | }; |
487 | 487 | ||
488 | struct qeth_qdio_info { | 488 | struct qeth_qdio_info { |
489 | atomic_t state; | 489 | atomic_t state; |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index acedba8539e4..bececacbc836 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -1302,35 +1302,6 @@ static void qeth_free_buffer_pool(struct qeth_card *card) | |||
1302 | } | 1302 | } |
1303 | } | 1303 | } |
1304 | 1304 | ||
1305 | static void qeth_free_qdio_buffers(struct qeth_card *card) | ||
1306 | { | ||
1307 | int i, j; | ||
1308 | |||
1309 | if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) == | ||
1310 | QETH_QDIO_UNINITIALIZED) | ||
1311 | return; | ||
1312 | |||
1313 | qeth_free_cq(card); | ||
1314 | cancel_delayed_work_sync(&card->buffer_reclaim_work); | ||
1315 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { | ||
1316 | if (card->qdio.in_q->bufs[j].rx_skb) | ||
1317 | dev_kfree_skb_any(card->qdio.in_q->bufs[j].rx_skb); | ||
1318 | } | ||
1319 | qeth_free_qdio_queue(card->qdio.in_q); | ||
1320 | card->qdio.in_q = NULL; | ||
1321 | /* inbound buffer pool */ | ||
1322 | qeth_free_buffer_pool(card); | ||
1323 | /* free outbound qdio_qs */ | ||
1324 | if (card->qdio.out_qs) { | ||
1325 | for (i = 0; i < card->qdio.no_out_queues; ++i) { | ||
1326 | qeth_clear_outq_buffers(card->qdio.out_qs[i], 1); | ||
1327 | kfree(card->qdio.out_qs[i]); | ||
1328 | } | ||
1329 | kfree(card->qdio.out_qs); | ||
1330 | card->qdio.out_qs = NULL; | ||
1331 | } | ||
1332 | } | ||
1333 | |||
1334 | static void qeth_clean_channel(struct qeth_channel *channel) | 1305 | static void qeth_clean_channel(struct qeth_channel *channel) |
1335 | { | 1306 | { |
1336 | int cnt; | 1307 | int cnt; |
@@ -2412,7 +2383,7 @@ static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *q, int bidx) | |||
2412 | rc = -ENOMEM; | 2383 | rc = -ENOMEM; |
2413 | goto out; | 2384 | goto out; |
2414 | } | 2385 | } |
2415 | newbuf->buffer = &q->qdio_bufs[bidx]; | 2386 | newbuf->buffer = q->qdio_bufs[bidx]; |
2416 | skb_queue_head_init(&newbuf->skb_list); | 2387 | skb_queue_head_init(&newbuf->skb_list); |
2417 | lockdep_set_class(&newbuf->skb_list.lock, &qdio_out_skb_queue_key); | 2388 | lockdep_set_class(&newbuf->skb_list.lock, &qdio_out_skb_queue_key); |
2418 | newbuf->q = q; | 2389 | newbuf->q = q; |
@@ -2431,6 +2402,28 @@ out: | |||
2431 | return rc; | 2402 | return rc; |
2432 | } | 2403 | } |
2433 | 2404 | ||
2405 | static void qeth_free_qdio_out_buf(struct qeth_qdio_out_q *q) | ||
2406 | { | ||
2407 | if (!q) | ||
2408 | return; | ||
2409 | |||
2410 | qdio_free_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q); | ||
2411 | kfree(q); | ||
2412 | } | ||
2413 | |||
2414 | static struct qeth_qdio_out_q *qeth_alloc_qdio_out_buf(void) | ||
2415 | { | ||
2416 | struct qeth_qdio_out_q *q = kzalloc(sizeof(*q), GFP_KERNEL); | ||
2417 | |||
2418 | if (!q) | ||
2419 | return NULL; | ||
2420 | |||
2421 | if (qdio_alloc_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q)) { | ||
2422 | kfree(q); | ||
2423 | return NULL; | ||
2424 | } | ||
2425 | return q; | ||
2426 | } | ||
2434 | 2427 | ||
2435 | static int qeth_alloc_qdio_buffers(struct qeth_card *card) | 2428 | static int qeth_alloc_qdio_buffers(struct qeth_card *card) |
2436 | { | 2429 | { |
@@ -2458,8 +2451,7 @@ static int qeth_alloc_qdio_buffers(struct qeth_card *card) | |||
2458 | if (!card->qdio.out_qs) | 2451 | if (!card->qdio.out_qs) |
2459 | goto out_freepool; | 2452 | goto out_freepool; |
2460 | for (i = 0; i < card->qdio.no_out_queues; ++i) { | 2453 | for (i = 0; i < card->qdio.no_out_queues; ++i) { |
2461 | card->qdio.out_qs[i] = kzalloc(sizeof(struct qeth_qdio_out_q), | 2454 | card->qdio.out_qs[i] = qeth_alloc_qdio_out_buf(); |
2462 | GFP_KERNEL); | ||
2463 | if (!card->qdio.out_qs[i]) | 2455 | if (!card->qdio.out_qs[i]) |
2464 | goto out_freeoutq; | 2456 | goto out_freeoutq; |
2465 | QETH_DBF_TEXT_(SETUP, 2, "outq %i", i); | 2457 | QETH_DBF_TEXT_(SETUP, 2, "outq %i", i); |
@@ -2488,7 +2480,7 @@ out_freeoutqbufs: | |||
2488 | } | 2480 | } |
2489 | out_freeoutq: | 2481 | out_freeoutq: |
2490 | while (i > 0) { | 2482 | while (i > 0) { |
2491 | kfree(card->qdio.out_qs[--i]); | 2483 | qeth_free_qdio_out_buf(card->qdio.out_qs[--i]); |
2492 | qeth_clear_outq_buffers(card->qdio.out_qs[i], 1); | 2484 | qeth_clear_outq_buffers(card->qdio.out_qs[i], 1); |
2493 | } | 2485 | } |
2494 | kfree(card->qdio.out_qs); | 2486 | kfree(card->qdio.out_qs); |
@@ -2503,6 +2495,35 @@ out_nomem: | |||
2503 | return -ENOMEM; | 2495 | return -ENOMEM; |
2504 | } | 2496 | } |
2505 | 2497 | ||
2498 | static void qeth_free_qdio_buffers(struct qeth_card *card) | ||
2499 | { | ||
2500 | int i, j; | ||
2501 | |||
2502 | if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) == | ||
2503 | QETH_QDIO_UNINITIALIZED) | ||
2504 | return; | ||
2505 | |||
2506 | qeth_free_cq(card); | ||
2507 | cancel_delayed_work_sync(&card->buffer_reclaim_work); | ||
2508 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { | ||
2509 | if (card->qdio.in_q->bufs[j].rx_skb) | ||
2510 | dev_kfree_skb_any(card->qdio.in_q->bufs[j].rx_skb); | ||
2511 | } | ||
2512 | qeth_free_qdio_queue(card->qdio.in_q); | ||
2513 | card->qdio.in_q = NULL; | ||
2514 | /* inbound buffer pool */ | ||
2515 | qeth_free_buffer_pool(card); | ||
2516 | /* free outbound qdio_qs */ | ||
2517 | if (card->qdio.out_qs) { | ||
2518 | for (i = 0; i < card->qdio.no_out_queues; ++i) { | ||
2519 | qeth_clear_outq_buffers(card->qdio.out_qs[i], 1); | ||
2520 | qeth_free_qdio_out_buf(card->qdio.out_qs[i]); | ||
2521 | } | ||
2522 | kfree(card->qdio.out_qs); | ||
2523 | card->qdio.out_qs = NULL; | ||
2524 | } | ||
2525 | } | ||
2526 | |||
2506 | static void qeth_create_qib_param_field(struct qeth_card *card, | 2527 | static void qeth_create_qib_param_field(struct qeth_card *card, |
2507 | char *param_field) | 2528 | char *param_field) |
2508 | { | 2529 | { |
@@ -2823,8 +2844,8 @@ int qeth_init_qdio_queues(struct qeth_card *card) | |||
2823 | 2844 | ||
2824 | /* outbound queue */ | 2845 | /* outbound queue */ |
2825 | for (i = 0; i < card->qdio.no_out_queues; ++i) { | 2846 | for (i = 0; i < card->qdio.no_out_queues; ++i) { |
2826 | memset(card->qdio.out_qs[i]->qdio_bufs, 0, | 2847 | qdio_reset_buffers(card->qdio.out_qs[i]->qdio_bufs, |
2827 | QDIO_MAX_BUFFERS_PER_Q * sizeof(struct qdio_buffer)); | 2848 | QDIO_MAX_BUFFERS_PER_Q); |
2828 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { | 2849 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { |
2829 | qeth_clear_output_buffer(card->qdio.out_qs[i], | 2850 | qeth_clear_output_buffer(card->qdio.out_qs[i], |
2830 | card->qdio.out_qs[i]->bufs[j], | 2851 | card->qdio.out_qs[i]->bufs[j], |