$ git diff diff --cc drivers/s390/net/qeth_core_main.c index ec8c7a640d9e,be3f6295309b..000000000000 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@@ -213,52 -211,121 +213,144 @@@ void qeth_clear_working_pool_list(struc } EXPORT_SYMBOL_GPL(qeth_clear_working_pool_list); ++<<<<<<< HEAD ++||||||| parent of 714c91088517... s390/qeth: use memory reserves to back RX buffers + static void qeth_free_pool_entry(struct qeth_buffer_pool_entry *entry) + { + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(entry->elements); i++) { + if (entry->elements[i]) + __free_page(entry->elements[i]); + } + + kfree(entry); + } + + static void qeth_free_buffer_pool(struct qeth_card *card) + { + struct qeth_buffer_pool_entry *entry, *tmp; + + list_for_each_entry_safe(entry, tmp, &card->qdio.init_pool.entry_list, + init_list) { + list_del(&entry->init_list); + qeth_free_pool_entry(entry); + } + } + + static struct qeth_buffer_pool_entry *qeth_alloc_pool_entry(unsigned int pages) + { + struct qeth_buffer_pool_entry *entry; + unsigned int i; + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return NULL; + + for (i = 0; i < pages; i++) { - entry->elements[i] = __dev_alloc_page(GFP_KERNEL); ++ entry->elements[i] = alloc_page(GFP_KERNEL); + + if (!entry->elements[i]) { + qeth_free_pool_entry(entry); + return NULL; + } + } + + return entry; + } + -static int qeth_alloc_buffer_pool(struct qeth_card *card) ++======= ++static void qeth_free_pool_entry(struct qeth_buffer_pool_entry *entry) + { - unsigned int buf_elements = QETH_MAX_BUFFER_ELEMENTS(card); + unsigned int i; + - QETH_CARD_TEXT(card, 5, "alocpool"); - for (i = 0; i < card->qdio.init_pool.buf_count; ++i) { - struct qeth_buffer_pool_entry *entry; - - entry = qeth_alloc_pool_entry(buf_elements); - if (!entry) { - qeth_free_buffer_pool(card); - return -ENOMEM; - } - - list_add(&entry->init_list, &card->qdio.init_pool.entry_list); ++ for (i = 0; i < ARRAY_SIZE(entry->elements); i++) { ++ if (entry->elements[i]) ++ __free_page(entry->elements[i]); + } - return 0; ++ ++ kfree(entry); + } + -int qeth_resize_buffer_pool(struct qeth_card *card, unsigned int count) ++static void qeth_free_buffer_pool(struct qeth_card *card) + { - unsigned int buf_elements = QETH_MAX_BUFFER_ELEMENTS(card); - struct qeth_qdio_buffer_pool *pool = &card->qdio.init_pool; + struct qeth_buffer_pool_entry *entry, *tmp; - int delta = count - pool->buf_count; - LIST_HEAD(entries); + - QETH_CARD_TEXT(card, 2, "realcbp"); - - /* Defer until queue is allocated: */ - if (!card->qdio.in_q) - goto out; - - /* Remove entries from the pool: */ - while (delta < 0) { - entry = list_first_entry(&pool->entry_list, - struct qeth_buffer_pool_entry, - init_list); ++ list_for_each_entry_safe(entry, tmp, &card->qdio.init_pool.entry_list, ++ init_list) { + list_del(&entry->init_list); + qeth_free_pool_entry(entry); - - delta++; + } ++} + - /* Allocate additional entries: */ - while (delta > 0) { - entry = qeth_alloc_pool_entry(buf_elements); - if (!entry) { - list_for_each_entry_safe(entry, tmp, &entries, - init_list) { - list_del(&entry->init_list); - qeth_free_pool_entry(entry); - } ++static struct qeth_buffer_pool_entry *qeth_alloc_pool_entry(unsigned int pages) ++{ ++ struct qeth_buffer_pool_entry *entry; ++ unsigned int i; + - return -ENOMEM; - } ++ entry = kzalloc(sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return NULL; + - list_add(&entry->init_list, &entries); ++ for (i = 0; i < pages; i++) { ++ entry->elements[i] = __dev_alloc_page(GFP_KERNEL); + - delta--; ++ if (!entry->elements[i]) { ++ qeth_free_pool_entry(entry); ++ return NULL; ++ } + } + - list_splice(&entries, &pool->entry_list); ++ return entry; ++} + -out: - card->qdio.in_buf_pool.buf_count = count; - pool->buf_count = count; ++>>>>>>> 714c91088517... s390/qeth: use memory reserves to back RX buffers +static int qeth_alloc_buffer_pool(struct qeth_card *card) +{ + struct qeth_buffer_pool_entry *pool_entry; + void *ptr; + int i, j; + + QETH_CARD_TEXT(card, 5, "alocpool"); + for (i = 0; i < card->qdio.init_pool.buf_count; ++i) { + pool_entry = kzalloc(sizeof(*pool_entry), GFP_KERNEL); + if (!pool_entry) { + qeth_free_buffer_pool(card); + return -ENOMEM; + } + for (j = 0; j < QETH_MAX_BUFFER_ELEMENTS(card); ++j) { + ptr = (void *) __get_free_page(GFP_KERNEL); + if (!ptr) { + while (j > 0) + free_page((unsigned long) + pool_entry->elements[--j]); + kfree(pool_entry); + qeth_free_buffer_pool(card); + return -ENOMEM; + } + pool_entry->elements[j] = ptr; + } + list_add(&pool_entry->init_list, + &card->qdio.init_pool.entry_list); + } return 0; } -EXPORT_SYMBOL_GPL(qeth_resize_buffer_pool); + +int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt) +{ + QETH_CARD_TEXT(card, 2, "realcbp"); + + if (card->state != CARD_STATE_DOWN) + return -EPERM; + + /* TODO: steel/add buffers from/to a running card's buffer pool (?) */ + qeth_clear_working_pool_list(card); + qeth_free_buffer_pool(card); + card->qdio.in_buf_pool.buf_count = bufcnt; + card->qdio.init_pool.buf_count = bufcnt; + return qeth_alloc_buffer_pool(card); +} +EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool); static void qeth_free_qdio_queue(struct qeth_qdio_q *q) { @@@ -2611,15 -2653,15 +2703,27 @@@ static struct qeth_buffer_pool_entry *q entry = list_entry(card->qdio.in_buf_pool.entry_list.next, struct qeth_buffer_pool_entry, list); for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { ++<<<<<<< HEAD + if (page_count(virt_to_page(entry->elements[i])) > 1) { + page = alloc_page(GFP_ATOMIC); + if (!page) { ++||||||| parent of 714c91088517... s390/qeth: use memory reserves to back RX buffers ++ if (page_count(entry->elements[i]) > 1) { ++ struct page *page = alloc_page(GFP_ATOMIC); ++ ++ if (!page) ++======= + if (page_count(entry->elements[i]) > 1) { + struct page *page = dev_alloc_page(); + + if (!page) ++>>>>>>> 714c91088517... s390/qeth: use memory reserves to back RX buffers return NULL; - - __free_page(entry->elements[i]); - entry->elements[i] = page; - QETH_CARD_STAT_INC(card, rx_sg_alloc_page); + } else { + free_page((unsigned long)entry->elements[i]); + entry->elements[i] = page_address(page); + QETH_CARD_STAT_INC(card, rx_sg_alloc_page); + } } } list_del_init(&entry->list);