Skip to content

Commit

Permalink
Merge branch 's390-qeth-fixes'
Browse files Browse the repository at this point in the history
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: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Mar 12, 2020
2 parents 2677625 + 5d4f785 commit 5e72b23
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 64 deletions.
4 changes: 2 additions & 2 deletions drivers/s390/net/qeth_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ enum qeth_qdio_info_states {
struct qeth_buffer_pool_entry {
struct list_head 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 {
Expand Down Expand Up @@ -983,7 +983,7 @@ extern const struct attribute_group qeth_device_blkt_group;
extern const struct device_type qeth_generic_devtype;

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);
void qeth_core_free_discipline(struct qeth_card *);

Expand Down
161 changes: 109 additions & 52 deletions drivers/s390/net/qeth_core_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct qeth_cmd_buffer *iob,
unsigned int data_length);
static void qeth_free_buffer_pool(struct qeth_card *);
static int qeth_qdio_establish(struct qeth_card *);
static void qeth_free_qdio_queues(struct qeth_card *card);
static void qeth_notify_skbs(struct qeth_qdio_out_q *queue,
Expand Down Expand Up @@ -212,49 +211,121 @@ void qeth_clear_working_pool_list(struct qeth_card *card)
}
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)
{
struct qeth_buffer_pool_entry *pool_entry;
void *ptr;
int i, j;
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) {
pool_entry = kzalloc(sizeof(*pool_entry), GFP_KERNEL);
if (!pool_entry) {
struct qeth_buffer_pool_entry *entry;

entry = qeth_alloc_pool_entry(buf_elements);
if (!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);

list_add(&entry->init_list, &card->qdio.init_pool.entry_list);
}
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");

/* 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);
/* 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_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)
{
Expand Down Expand Up @@ -1170,19 +1241,6 @@ void qeth_drain_output_queues(struct qeth_card *card)
}
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)
{
unsigned int count = single ? 1 : card->dev->num_tx_queues;
Expand Down Expand Up @@ -2573,7 +2631,6 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry(
struct list_head *plh;
struct qeth_buffer_pool_entry *entry;
int i, free;
struct page *page;

if (list_empty(&card->qdio.in_buf_pool.entry_list))
return NULL;
Expand All @@ -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);
free = 1;
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;
break;
}
Expand All @@ -2597,15 +2654,15 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry(
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) {
if (page_count(virt_to_page(entry->elements[i])) > 1) {
page = alloc_page(GFP_ATOMIC);
if (!page) {
if (page_count(entry->elements[i]) > 1) {
struct page *page = alloc_page(GFP_ATOMIC);

if (!page)
return NULL;
} else {
free_page((unsigned long)entry->elements[i]);
entry->elements[i] = page_address(page);
QETH_CARD_STAT_INC(card, rx_sg_alloc_page);
}

__free_page(entry->elements[i]);
entry->elements[i] = page;
QETH_CARD_STAT_INC(card, rx_sg_alloc_page);
}
}
list_del_init(&entry->list);
Expand Down Expand Up @@ -2641,7 +2698,7 @@ static int qeth_init_input_buffer(struct qeth_card *card,
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
buf->buffer->element[i].length = PAGE_SIZE;
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)
buf->buffer->element[i].eflags = SBAL_EFLAGS_LAST_ENTRY;
else
Expand Down
9 changes: 4 additions & 5 deletions drivers/s390/net/qeth_core_sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 qeth_card *card = dev_get_drvdata(dev);
unsigned int cnt;
char *tmp;
int cnt, old_cnt;
int rc = 0;

mutex_lock(&card->conf_mutex);
Expand All @@ -257,13 +257,12 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev,
goto out;
}

old_cnt = card->qdio.in_buf_pool.buf_count;
cnt = simple_strtoul(buf, &tmp, 10);
cnt = (cnt < QETH_IN_BUF_COUNT_MIN) ? QETH_IN_BUF_COUNT_MIN :
((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:
mutex_unlock(&card->conf_mutex);
return rc ? rc : count;
Expand Down
9 changes: 4 additions & 5 deletions drivers/s390/net/qeth_l3_sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,11 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
if (card->ssqd.qdioac2 & CHSC_AC2_SNIFFER_AVAILABLE) {
card->options.sniffer = i;
if (card->qdio.init_pool.buf_count !=
QETH_IN_BUF_COUNT_MAX)
qeth_realloc_buffer_pool(card,
QETH_IN_BUF_COUNT_MAX);
} else
qeth_resize_buffer_pool(card, QETH_IN_BUF_COUNT_MAX);
} else {
rc = -EPERM;
}

break;
default:
rc = -EINVAL;
Expand Down

0 comments on commit 5e72b23

Please sign in to comment.