s390/qeth: allocate a single cmd on read channel
authorJulian Wiedmann <jwi@linux.ibm.com>
Tue, 11 Jun 2019 16:38:00 +0000 (18:38 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 14 Jun 2019 05:39:32 +0000 (22:39 -0700)
We statically allocate 8 cmd buffers on the read channel, when the only
IO left that's still using them is the long-running READ.
Replace this with a single allocated cmd, that gets restarted whenever
the READ completed.

This introduces refcounting for allocated cmds, so that the READ cmd can
survive the IO completion.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c

index 962945a63235f94cb1ea880ec58f538bbd72bb8b..5bcdede5e955f5ef90f7d3e0c2761981a1e5f736 100644 (file)
@@ -579,6 +579,7 @@ struct qeth_channel;
 struct qeth_cmd_buffer {
        enum qeth_cmd_buffer_state state;
        unsigned int length;
+       refcount_t ref_count;
        struct qeth_channel *channel;
        struct qeth_reply *reply;
        long timeout;
@@ -588,6 +589,11 @@ struct qeth_cmd_buffer {
        void (*callback)(struct qeth_card *card, struct qeth_cmd_buffer *iob);
 };
 
+static inline void qeth_get_cmd(struct qeth_cmd_buffer *iob)
+{
+       refcount_inc(&iob->ref_count);
+}
+
 static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob)
 {
        return (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE);
@@ -771,6 +777,7 @@ struct qeth_card {
        enum qeth_card_states state;
        spinlock_t lock;
        struct ccwgroup_device *gdev;
+       struct qeth_cmd_buffer *read_cmd;
        struct qeth_channel read;
        struct qeth_channel write;
        struct qeth_channel data;
index 11e6a3820421884af17f14f875899d7f49ecb435..fe3dfeaf5ceb3e57c913b099c108e840632d8ae2 100644 (file)
@@ -496,26 +496,21 @@ static void qeth_setup_ccw(struct ccw1 *ccw, u8 cmd_code, u8 flags, u32 len,
 
 static int __qeth_issue_next_read(struct qeth_card *card)
 {
-       struct qeth_channel *channel = &card->read;
-       struct qeth_cmd_buffer *iob;
-       struct ccw1 *ccw;
+       struct qeth_cmd_buffer *iob = card->read_cmd;
+       struct qeth_channel *channel = iob->channel;
+       struct ccw1 *ccw = __ccw_from_cmd(iob);
        int rc;
 
        QETH_CARD_TEXT(card, 5, "issnxrd");
        if (channel->state != CH_STATE_UP)
                return -EIO;
-       iob = qeth_get_buffer(channel);
-       if (!iob) {
-               dev_warn(&card->gdev->dev, "The qeth device driver "
-                       "failed to recover an error on the device\n");
-               QETH_DBF_MESSAGE(2, "issue_next_read on device %x failed: no iob available\n",
-                                CARD_DEVID(card));
-               return -ENOMEM;
-       }
 
-       ccw = __ccw_from_cmd(iob);
-       qeth_setup_ccw(ccw, CCW_CMD_READ, 0, QETH_BUFSIZE, iob->data);
+       memset(iob->data, 0, iob->length);
+       qeth_setup_ccw(ccw, CCW_CMD_READ, 0, iob->length, iob->data);
        iob->callback = qeth_issue_next_read_cb;
+       /* keep the cmd alive after completion: */
+       qeth_get_cmd(iob);
+
        QETH_CARD_TEXT(card, 6, "noirqpnd");
        rc = ccw_device_start(channel->ccwdev, ccw, (addr_t) iob, 0, 0);
        if (rc) {
@@ -694,6 +689,16 @@ static int qeth_check_idx_response(struct qeth_card *card,
        return 0;
 }
 
+static void qeth_put_cmd(struct qeth_cmd_buffer *iob)
+{
+       if (refcount_dec_and_test(&iob->ref_count)) {
+               if (iob->reply)
+                       qeth_put_reply(iob->reply);
+               kfree(iob->data);
+               kfree(iob);
+       }
+}
+
 static struct qeth_cmd_buffer *__qeth_get_buffer(struct qeth_channel *channel)
 {
        __u8 index;
@@ -720,10 +725,7 @@ void qeth_release_buffer(struct qeth_cmd_buffer *iob)
        unsigned long flags;
 
        if (iob->state == BUF_STATE_MALLOC) {
-               if (iob->reply)
-                       qeth_put_reply(iob->reply);
-               kfree(iob->data);
-               kfree(iob);
+               qeth_put_cmd(iob);
                return;
        }
 
@@ -787,6 +789,7 @@ static struct qeth_cmd_buffer *qeth_alloc_cmd(struct qeth_channel *channel,
        }
 
        iob->state = BUF_STATE_MALLOC;
+       refcount_set(&iob->ref_count, 1);
        iob->channel = channel;
        iob->timeout = timeout;
        iob->length = length;
@@ -1445,10 +1448,14 @@ static struct qeth_card *qeth_alloc_card(struct ccwgroup_device *gdev)
                                                 dev_name(&gdev->dev));
        if (!card->event_wq)
                goto out_wq;
-       if (qeth_setup_channel(&card->read, true))
-               goto out_ip;
+
+       card->read_cmd = qeth_alloc_cmd(&card->read, QETH_BUFSIZE, 1, 0);
+       if (!card->read_cmd)
+               goto out_read_cmd;
+       if (qeth_setup_channel(&card->read, false))
+               goto out_read;
        if (qeth_setup_channel(&card->write, true))
-               goto out_channel;
+               goto out_write;
        if (qeth_setup_channel(&card->data, false))
                goto out_data;
        card->qeth_service_level.seq_print = qeth_core_sl_print;
@@ -1457,9 +1464,11 @@ static struct qeth_card *qeth_alloc_card(struct ccwgroup_device *gdev)
 
 out_data:
        qeth_clean_channel(&card->write);
-out_channel:
+out_write:
        qeth_clean_channel(&card->read);
-out_ip:
+out_read:
+       qeth_release_buffer(card->read_cmd);
+out_read_cmd:
        destroy_workqueue(card->event_wq);
 out_wq:
        dev_set_drvdata(&gdev->dev, NULL);
@@ -4892,6 +4901,7 @@ static void qeth_core_free_card(struct qeth_card *card)
        qeth_clean_channel(&card->read);
        qeth_clean_channel(&card->write);
        qeth_clean_channel(&card->data);
+       qeth_release_buffer(card->read_cmd);
        destroy_workqueue(card->event_wq);
        qeth_free_qdio_queues(card);
        unregister_service_level(&card->qeth_service_level);
index e1b25084dcd42986c44295f911accf8ed2d23f1d..9565ef9747c177a89a652d1e6bca2f3721a63013 100644 (file)
@@ -292,7 +292,6 @@ static void qeth_l2_stop_card(struct qeth_card *card)
                card->state = CARD_STATE_DOWN;
        }
 
-       qeth_clear_cmd_buffers(&card->read);
        qeth_clear_cmd_buffers(&card->write);
        flush_workqueue(card->event_wq);
        card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
index 15758f45837dbabfd44d8bb6b529ab44bad6e722..4d66f95564515d98b3b78ca1477db96868145b86 100644 (file)
@@ -1436,7 +1436,6 @@ static void qeth_l3_stop_card(struct qeth_card *card)
                card->state = CARD_STATE_DOWN;
        }
 
-       qeth_clear_cmd_buffers(&card->read);
        qeth_clear_cmd_buffers(&card->write);
        flush_workqueue(card->event_wq);
 }