Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Sebastian Ott and committed by
Martin Schwidefsky
d445a4e2 6d284bde

+58 -37
+2 -2
drivers/s390/net/qeth_core.h
··· 465 465 }; 466 466 467 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 469 struct qeth_qdio_out_buffer *bufs[QDIO_MAX_BUFFERS_PER_Q]; 470 470 struct qdio_outbuf_state *bufstates; /* convenience pointer */ 471 471 int queue_no; ··· 483 483 atomic_t used_buffers; 484 484 /* indicates whether PCI flag must be set (or if one is outstanding) */ 485 485 atomic_t set_pci_flags_count; 486 - } __attribute__ ((aligned(256))); 486 + }; 487 487 488 488 struct qeth_qdio_info { 489 489 atomic_t state;
+56 -35
drivers/s390/net/qeth_core_main.c
··· 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 1305 static void qeth_clean_channel(struct qeth_channel *channel) 1335 1306 { 1336 1307 int cnt; ··· 2383 2412 rc = -ENOMEM; 2384 2413 goto out; 2385 2414 } 2386 - newbuf->buffer = &q->qdio_bufs[bidx]; 2415 + newbuf->buffer = q->qdio_bufs[bidx]; 2387 2416 skb_queue_head_init(&newbuf->skb_list); 2388 2417 lockdep_set_class(&newbuf->skb_list.lock, &qdio_out_skb_queue_key); 2389 2418 newbuf->q = q; ··· 2402 2431 return rc; 2403 2432 } 2404 2433 2434 + static void qeth_free_qdio_out_buf(struct qeth_qdio_out_q *q) 2435 + { 2436 + if (!q) 2437 + return; 2438 + 2439 + qdio_free_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q); 2440 + kfree(q); 2441 + } 2442 + 2443 + static struct qeth_qdio_out_q *qeth_alloc_qdio_out_buf(void) 2444 + { 2445 + struct qeth_qdio_out_q *q = kzalloc(sizeof(*q), GFP_KERNEL); 2446 + 2447 + if (!q) 2448 + return NULL; 2449 + 2450 + if (qdio_alloc_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q)) { 2451 + kfree(q); 2452 + return NULL; 2453 + } 2454 + return q; 2455 + } 2405 2456 2406 2457 static int qeth_alloc_qdio_buffers(struct qeth_card *card) 2407 2458 { ··· 2451 2458 if (!card->qdio.out_qs) 2452 2459 goto out_freepool; 2453 2460 for (i = 0; i < card->qdio.no_out_queues; ++i) { 2454 - card->qdio.out_qs[i] = kzalloc(sizeof(struct qeth_qdio_out_q), 2455 - GFP_KERNEL); 2461 + card->qdio.out_qs[i] = qeth_alloc_qdio_out_buf(); 2456 2462 if (!card->qdio.out_qs[i]) 2457 2463 goto out_freeoutq; 2458 2464 QETH_DBF_TEXT_(SETUP, 2, "outq %i", i); ··· 2480 2488 } 2481 2489 out_freeoutq: 2482 2490 while (i > 0) { 2483 - kfree(card->qdio.out_qs[--i]); 2491 + qeth_free_qdio_out_buf(card->qdio.out_qs[--i]); 2484 2492 qeth_clear_outq_buffers(card->qdio.out_qs[i], 1); 2485 2493 } 2486 2494 kfree(card->qdio.out_qs); ··· 2493 2501 out_nomem: 2494 2502 atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED); 2495 2503 return -ENOMEM; 2504 + } 2505 + 2506 + static void qeth_free_qdio_buffers(struct qeth_card *card) 2507 + { 2508 + int i, j; 2509 + 2510 + if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) == 2511 + QETH_QDIO_UNINITIALIZED) 2512 + return; 2513 + 2514 + qeth_free_cq(card); 2515 + cancel_delayed_work_sync(&card->buffer_reclaim_work); 2516 + for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { 2517 + if (card->qdio.in_q->bufs[j].rx_skb) 2518 + dev_kfree_skb_any(card->qdio.in_q->bufs[j].rx_skb); 2519 + } 2520 + qeth_free_qdio_queue(card->qdio.in_q); 2521 + card->qdio.in_q = NULL; 2522 + /* inbound buffer pool */ 2523 + qeth_free_buffer_pool(card); 2524 + /* free outbound qdio_qs */ 2525 + if (card->qdio.out_qs) { 2526 + for (i = 0; i < card->qdio.no_out_queues; ++i) { 2527 + qeth_clear_outq_buffers(card->qdio.out_qs[i], 1); 2528 + qeth_free_qdio_out_buf(card->qdio.out_qs[i]); 2529 + } 2530 + kfree(card->qdio.out_qs); 2531 + card->qdio.out_qs = NULL; 2532 + } 2496 2533 } 2497 2534 2498 2535 static void qeth_create_qib_param_field(struct qeth_card *card, ··· 2844 2823 2845 2824 /* outbound queue */ 2846 2825 for (i = 0; i < card->qdio.no_out_queues; ++i) { 2847 - memset(card->qdio.out_qs[i]->qdio_bufs, 0, 2848 - QDIO_MAX_BUFFERS_PER_Q * sizeof(struct qdio_buffer)); 2826 + qdio_reset_buffers(card->qdio.out_qs[i]->qdio_bufs, 2827 + QDIO_MAX_BUFFERS_PER_Q); 2849 2828 for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { 2850 2829 qeth_clear_output_buffer(card->qdio.out_qs[i], 2851 2830 card->qdio.out_qs[i]->bufs[j],