Commit 5e72b237 authored by David S. Miller's avatar David S. Miller

Merge branch 's390-qeth-fixes'

Julian Wiedmann says:

====================
s390/qeth: fixes 2020-03-11

please apply the following patch series for qeth to netdev's net tree.

Just one fix to get the RX buffer pool resizing right, with two
preparatory cleanups.
This is on the larger side given where we are in the -rc cycle, but a
big chunk of the delta is just refactoring to make the fix look nice.

I intentionally split these off from yesterday's series. No objections
if you'd rather punt them to net-next, the series should apply cleanly.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 26776253 5d4f7856
...@@ -369,7 +369,7 @@ enum qeth_qdio_info_states { ...@@ -369,7 +369,7 @@ enum qeth_qdio_info_states {
struct qeth_buffer_pool_entry { struct qeth_buffer_pool_entry {
struct list_head list; struct list_head list;
struct list_head init_list; struct list_head init_list;
void *elements[QDIO_MAX_ELEMENTS_PER_BUFFER]; struct page *elements[QDIO_MAX_ELEMENTS_PER_BUFFER];
}; };
struct qeth_qdio_buffer_pool { struct qeth_qdio_buffer_pool {
...@@ -983,7 +983,7 @@ extern const struct attribute_group qeth_device_blkt_group; ...@@ -983,7 +983,7 @@ extern const struct attribute_group qeth_device_blkt_group;
extern const struct device_type qeth_generic_devtype; extern const struct device_type qeth_generic_devtype;
const char *qeth_get_cardname_short(struct qeth_card *); const char *qeth_get_cardname_short(struct qeth_card *);
int qeth_realloc_buffer_pool(struct qeth_card *, int); int qeth_resize_buffer_pool(struct qeth_card *card, unsigned int count);
int qeth_core_load_discipline(struct qeth_card *, enum qeth_discipline_id); int qeth_core_load_discipline(struct qeth_card *, enum qeth_discipline_id);
void qeth_core_free_discipline(struct qeth_card *); void qeth_core_free_discipline(struct qeth_card *);
......
...@@ -65,7 +65,6 @@ static struct lock_class_key qdio_out_skb_queue_key; ...@@ -65,7 +65,6 @@ static struct lock_class_key qdio_out_skb_queue_key;
static void qeth_issue_next_read_cb(struct qeth_card *card, static void qeth_issue_next_read_cb(struct qeth_card *card,
struct qeth_cmd_buffer *iob, struct qeth_cmd_buffer *iob,
unsigned int data_length); unsigned int data_length);
static void qeth_free_buffer_pool(struct qeth_card *);
static int qeth_qdio_establish(struct qeth_card *); static int qeth_qdio_establish(struct qeth_card *);
static void qeth_free_qdio_queues(struct qeth_card *card); static void qeth_free_qdio_queues(struct qeth_card *card);
static void qeth_notify_skbs(struct qeth_qdio_out_q *queue, static void qeth_notify_skbs(struct qeth_qdio_out_q *queue,
...@@ -212,49 +211,121 @@ void qeth_clear_working_pool_list(struct qeth_card *card) ...@@ -212,49 +211,121 @@ void qeth_clear_working_pool_list(struct qeth_card *card)
} }
EXPORT_SYMBOL_GPL(qeth_clear_working_pool_list); EXPORT_SYMBOL_GPL(qeth_clear_working_pool_list);
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] = 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 int qeth_alloc_buffer_pool(struct qeth_card *card)
{ {
struct qeth_buffer_pool_entry *pool_entry; unsigned int buf_elements = QETH_MAX_BUFFER_ELEMENTS(card);
void *ptr; unsigned int i;
int i, j;
QETH_CARD_TEXT(card, 5, "alocpool"); QETH_CARD_TEXT(card, 5, "alocpool");
for (i = 0; i < card->qdio.init_pool.buf_count; ++i) { for (i = 0; i < card->qdio.init_pool.buf_count; ++i) {
pool_entry = kzalloc(sizeof(*pool_entry), GFP_KERNEL); struct qeth_buffer_pool_entry *entry;
if (!pool_entry) {
qeth_free_buffer_pool(card); entry = qeth_alloc_pool_entry(buf_elements);
return -ENOMEM; if (!entry) {
}
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); qeth_free_buffer_pool(card);
return -ENOMEM; return -ENOMEM;
} }
pool_entry->elements[j] = ptr;
} list_add(&entry->init_list, &card->qdio.init_pool.entry_list);
list_add(&pool_entry->init_list,
&card->qdio.init_pool.entry_list);
} }
return 0; return 0;
} }
int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt) int qeth_resize_buffer_pool(struct qeth_card *card, unsigned int count)
{ {
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"); QETH_CARD_TEXT(card, 2, "realcbp");
/* TODO: steel/add buffers from/to a running card's buffer pool (?) */ /* Defer until queue is allocated: */
qeth_clear_working_pool_list(card); if (!card->qdio.in_q)
qeth_free_buffer_pool(card); goto out;
card->qdio.in_buf_pool.buf_count = bufcnt;
card->qdio.init_pool.buf_count = bufcnt; /* Remove entries from the pool: */
return qeth_alloc_buffer_pool(card); while (delta < 0) {
entry = list_first_entry(&pool->entry_list,
struct qeth_buffer_pool_entry,
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);
}
return -ENOMEM;
}
list_add(&entry->init_list, &entries);
delta--;
}
list_splice(&entries, &pool->entry_list);
out:
card->qdio.in_buf_pool.buf_count = count;
pool->buf_count = count;
return 0;
} }
EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool); EXPORT_SYMBOL_GPL(qeth_resize_buffer_pool);
static void qeth_free_qdio_queue(struct qeth_qdio_q *q) static void qeth_free_qdio_queue(struct qeth_qdio_q *q)
{ {
...@@ -1170,19 +1241,6 @@ void qeth_drain_output_queues(struct qeth_card *card) ...@@ -1170,19 +1241,6 @@ void qeth_drain_output_queues(struct qeth_card *card)
} }
EXPORT_SYMBOL_GPL(qeth_drain_output_queues); EXPORT_SYMBOL_GPL(qeth_drain_output_queues);
static void qeth_free_buffer_pool(struct qeth_card *card)
{
struct qeth_buffer_pool_entry *pool_entry, *tmp;
int i = 0;
list_for_each_entry_safe(pool_entry, tmp,
&card->qdio.init_pool.entry_list, init_list){
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i)
free_page((unsigned long)pool_entry->elements[i]);
list_del(&pool_entry->init_list);
kfree(pool_entry);
}
}
static int qeth_osa_set_output_queues(struct qeth_card *card, bool single) static int qeth_osa_set_output_queues(struct qeth_card *card, bool single)
{ {
unsigned int count = single ? 1 : card->dev->num_tx_queues; unsigned int count = single ? 1 : card->dev->num_tx_queues;
...@@ -2573,7 +2631,6 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry( ...@@ -2573,7 +2631,6 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry(
struct list_head *plh; struct list_head *plh;
struct qeth_buffer_pool_entry *entry; struct qeth_buffer_pool_entry *entry;
int i, free; int i, free;
struct page *page;
if (list_empty(&card->qdio.in_buf_pool.entry_list)) if (list_empty(&card->qdio.in_buf_pool.entry_list))
return NULL; return NULL;
...@@ -2582,7 +2639,7 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry( ...@@ -2582,7 +2639,7 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry(
entry = list_entry(plh, struct qeth_buffer_pool_entry, list); entry = list_entry(plh, struct qeth_buffer_pool_entry, list);
free = 1; free = 1;
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
if (page_count(virt_to_page(entry->elements[i])) > 1) { if (page_count(entry->elements[i]) > 1) {
free = 0; free = 0;
break; break;
} }
...@@ -2597,17 +2654,17 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry( ...@@ -2597,17 +2654,17 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry(
entry = list_entry(card->qdio.in_buf_pool.entry_list.next, entry = list_entry(card->qdio.in_buf_pool.entry_list.next,
struct qeth_buffer_pool_entry, list); struct qeth_buffer_pool_entry, list);
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
if (page_count(virt_to_page(entry->elements[i])) > 1) { if (page_count(entry->elements[i]) > 1) {
page = alloc_page(GFP_ATOMIC); struct page *page = alloc_page(GFP_ATOMIC);
if (!page) {
if (!page)
return NULL; return NULL;
} else {
free_page((unsigned long)entry->elements[i]); __free_page(entry->elements[i]);
entry->elements[i] = page_address(page); entry->elements[i] = page;
QETH_CARD_STAT_INC(card, rx_sg_alloc_page); QETH_CARD_STAT_INC(card, rx_sg_alloc_page);
} }
} }
}
list_del_init(&entry->list); list_del_init(&entry->list);
return entry; return entry;
} }
...@@ -2641,7 +2698,7 @@ static int qeth_init_input_buffer(struct qeth_card *card, ...@@ -2641,7 +2698,7 @@ static int qeth_init_input_buffer(struct qeth_card *card,
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
buf->buffer->element[i].length = PAGE_SIZE; buf->buffer->element[i].length = PAGE_SIZE;
buf->buffer->element[i].addr = buf->buffer->element[i].addr =
virt_to_phys(pool_entry->elements[i]); page_to_phys(pool_entry->elements[i]);
if (i == QETH_MAX_BUFFER_ELEMENTS(card) - 1) if (i == QETH_MAX_BUFFER_ELEMENTS(card) - 1)
buf->buffer->element[i].eflags = SBAL_EFLAGS_LAST_ENTRY; buf->buffer->element[i].eflags = SBAL_EFLAGS_LAST_ENTRY;
else else
......
...@@ -247,8 +247,8 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev, ...@@ -247,8 +247,8 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count) struct device_attribute *attr, const char *buf, size_t count)
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
unsigned int cnt;
char *tmp; char *tmp;
int cnt, old_cnt;
int rc = 0; int rc = 0;
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
...@@ -257,13 +257,12 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev, ...@@ -257,13 +257,12 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev,
goto out; goto out;
} }
old_cnt = card->qdio.in_buf_pool.buf_count;
cnt = simple_strtoul(buf, &tmp, 10); cnt = simple_strtoul(buf, &tmp, 10);
cnt = (cnt < QETH_IN_BUF_COUNT_MIN) ? QETH_IN_BUF_COUNT_MIN : cnt = (cnt < QETH_IN_BUF_COUNT_MIN) ? QETH_IN_BUF_COUNT_MIN :
((cnt > QETH_IN_BUF_COUNT_MAX) ? QETH_IN_BUF_COUNT_MAX : cnt); ((cnt > QETH_IN_BUF_COUNT_MAX) ? QETH_IN_BUF_COUNT_MAX : cnt);
if (old_cnt != cnt) {
rc = qeth_realloc_buffer_pool(card, cnt); rc = qeth_resize_buffer_pool(card, cnt);
}
out: out:
mutex_unlock(&card->conf_mutex); mutex_unlock(&card->conf_mutex);
return rc ? rc : count; return rc ? rc : count;
......
...@@ -206,12 +206,11 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev, ...@@ -206,12 +206,11 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd); qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
if (card->ssqd.qdioac2 & CHSC_AC2_SNIFFER_AVAILABLE) { if (card->ssqd.qdioac2 & CHSC_AC2_SNIFFER_AVAILABLE) {
card->options.sniffer = i; card->options.sniffer = i;
if (card->qdio.init_pool.buf_count != qeth_resize_buffer_pool(card, QETH_IN_BUF_COUNT_MAX);
QETH_IN_BUF_COUNT_MAX) } else {
qeth_realloc_buffer_pool(card,
QETH_IN_BUF_COUNT_MAX);
} else
rc = -EPERM; rc = -EPERM;
}
break; break;
default: default:
rc = -EINVAL; rc = -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment