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>
This commit is contained in:
Sebastian Ott 2014-06-27 17:09:25 +02:00 committed by Martin Schwidefsky
parent 6d284bde2b
commit d445a4e28c
2 changed files with 58 additions and 37 deletions

View file

@ -465,7 +465,7 @@ enum qeth_out_q_states {
};
struct qeth_qdio_out_q {
struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
struct qdio_buffer *qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
struct qeth_qdio_out_buffer *bufs[QDIO_MAX_BUFFERS_PER_Q];
struct qdio_outbuf_state *bufstates; /* convenience pointer */
int queue_no;
@ -483,7 +483,7 @@ struct qeth_qdio_out_q {
atomic_t used_buffers;
/* indicates whether PCI flag must be set (or if one is outstanding) */
atomic_t set_pci_flags_count;
} __attribute__ ((aligned(256)));
};
struct qeth_qdio_info {
atomic_t state;

View file

@ -1302,35 +1302,6 @@ static void qeth_free_buffer_pool(struct qeth_card *card)
}
}
static void qeth_free_qdio_buffers(struct qeth_card *card)
{
int i, j;
if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) ==
QETH_QDIO_UNINITIALIZED)
return;
qeth_free_cq(card);
cancel_delayed_work_sync(&card->buffer_reclaim_work);
for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) {
if (card->qdio.in_q->bufs[j].rx_skb)
dev_kfree_skb_any(card->qdio.in_q->bufs[j].rx_skb);
}
qeth_free_qdio_queue(card->qdio.in_q);
card->qdio.in_q = NULL;
/* inbound buffer pool */
qeth_free_buffer_pool(card);
/* free outbound qdio_qs */
if (card->qdio.out_qs) {
for (i = 0; i < card->qdio.no_out_queues; ++i) {
qeth_clear_outq_buffers(card->qdio.out_qs[i], 1);
kfree(card->qdio.out_qs[i]);
}
kfree(card->qdio.out_qs);
card->qdio.out_qs = NULL;
}
}
static void qeth_clean_channel(struct qeth_channel *channel)
{
int cnt;
@ -2412,7 +2383,7 @@ static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *q, int bidx)
rc = -ENOMEM;
goto out;
}
newbuf->buffer = &q->qdio_bufs[bidx];
newbuf->buffer = q->qdio_bufs[bidx];
skb_queue_head_init(&newbuf->skb_list);
lockdep_set_class(&newbuf->skb_list.lock, &qdio_out_skb_queue_key);
newbuf->q = q;
@ -2431,6 +2402,28 @@ static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *q, int bidx)
return rc;
}
static void qeth_free_qdio_out_buf(struct qeth_qdio_out_q *q)
{
if (!q)
return;
qdio_free_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q);
kfree(q);
}
static struct qeth_qdio_out_q *qeth_alloc_qdio_out_buf(void)
{
struct qeth_qdio_out_q *q = kzalloc(sizeof(*q), GFP_KERNEL);
if (!q)
return NULL;
if (qdio_alloc_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q)) {
kfree(q);
return NULL;
}
return q;
}
static int qeth_alloc_qdio_buffers(struct qeth_card *card)
{
@ -2458,8 +2451,7 @@ static int qeth_alloc_qdio_buffers(struct qeth_card *card)
if (!card->qdio.out_qs)
goto out_freepool;
for (i = 0; i < card->qdio.no_out_queues; ++i) {
card->qdio.out_qs[i] = kzalloc(sizeof(struct qeth_qdio_out_q),
GFP_KERNEL);
card->qdio.out_qs[i] = qeth_alloc_qdio_out_buf();
if (!card->qdio.out_qs[i])
goto out_freeoutq;
QETH_DBF_TEXT_(SETUP, 2, "outq %i", i);
@ -2488,7 +2480,7 @@ static int qeth_alloc_qdio_buffers(struct qeth_card *card)
}
out_freeoutq:
while (i > 0) {
kfree(card->qdio.out_qs[--i]);
qeth_free_qdio_out_buf(card->qdio.out_qs[--i]);
qeth_clear_outq_buffers(card->qdio.out_qs[i], 1);
}
kfree(card->qdio.out_qs);
@ -2503,6 +2495,35 @@ static int qeth_alloc_qdio_buffers(struct qeth_card *card)
return -ENOMEM;
}
static void qeth_free_qdio_buffers(struct qeth_card *card)
{
int i, j;
if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) ==
QETH_QDIO_UNINITIALIZED)
return;
qeth_free_cq(card);
cancel_delayed_work_sync(&card->buffer_reclaim_work);
for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) {
if (card->qdio.in_q->bufs[j].rx_skb)
dev_kfree_skb_any(card->qdio.in_q->bufs[j].rx_skb);
}
qeth_free_qdio_queue(card->qdio.in_q);
card->qdio.in_q = NULL;
/* inbound buffer pool */
qeth_free_buffer_pool(card);
/* free outbound qdio_qs */
if (card->qdio.out_qs) {
for (i = 0; i < card->qdio.no_out_queues; ++i) {
qeth_clear_outq_buffers(card->qdio.out_qs[i], 1);
qeth_free_qdio_out_buf(card->qdio.out_qs[i]);
}
kfree(card->qdio.out_qs);
card->qdio.out_qs = NULL;
}
}
static void qeth_create_qib_param_field(struct qeth_card *card,
char *param_field)
{
@ -2823,8 +2844,8 @@ int qeth_init_qdio_queues(struct qeth_card *card)
/* outbound queue */
for (i = 0; i < card->qdio.no_out_queues; ++i) {
memset(card->qdio.out_qs[i]->qdio_bufs, 0,
QDIO_MAX_BUFFERS_PER_Q * sizeof(struct qdio_buffer));
qdio_reset_buffers(card->qdio.out_qs[i]->qdio_bufs,
QDIO_MAX_BUFFERS_PER_Q);
for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) {
qeth_clear_output_buffer(card->qdio.out_qs[i],
card->qdio.out_qs[i]->bufs[j],