Commit 0951c6ba authored by Julian Wiedmann's avatar Julian Wiedmann Committed by David S. Miller

s390/qeth: simplify reply object handling

Current code enqueues & dequeues a reply object from the waiter list
in various places. In particular, the dequeue & enqueue in
qeth_send_control_data_cb() looks fragile - this can cause
qeth_clear_ipacmd_list() to skip the active object.
Add some helpers, and boil the logic down by giving
qeth_send_control_data() the sole responsibility to add and remove
objects.

qeth_send_control_data_cb() and qeth_clear_ipacmd_list() will now only
notify the reply object to interrupt its wait cycle. This can cause
a slight delay in the removal, but that's no concern.
Signed-off-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 51581fd0
...@@ -566,6 +566,7 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) ...@@ -566,6 +566,7 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
if (reply) { if (reply) {
refcount_set(&reply->refcnt, 1); refcount_set(&reply->refcnt, 1);
atomic_set(&reply->received, 0); atomic_set(&reply->received, 0);
init_waitqueue_head(&reply->wait_q);
} }
return reply; return reply;
} }
...@@ -581,6 +582,26 @@ static void qeth_put_reply(struct qeth_reply *reply) ...@@ -581,6 +582,26 @@ static void qeth_put_reply(struct qeth_reply *reply)
kfree(reply); kfree(reply);
} }
static void qeth_enqueue_reply(struct qeth_card *card, struct qeth_reply *reply)
{
spin_lock_irq(&card->lock);
list_add_tail(&reply->list, &card->cmd_waiter_list);
spin_unlock_irq(&card->lock);
}
static void qeth_dequeue_reply(struct qeth_card *card, struct qeth_reply *reply)
{
spin_lock_irq(&card->lock);
list_del(&reply->list);
spin_unlock_irq(&card->lock);
}
static void qeth_notify_reply(struct qeth_reply *reply)
{
atomic_inc(&reply->received);
wake_up(&reply->wait_q);
}
static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc, static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc,
struct qeth_card *card) struct qeth_card *card)
{ {
...@@ -657,19 +678,15 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, ...@@ -657,19 +678,15 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
void qeth_clear_ipacmd_list(struct qeth_card *card) void qeth_clear_ipacmd_list(struct qeth_card *card)
{ {
struct qeth_reply *reply, *r; struct qeth_reply *reply;
unsigned long flags; unsigned long flags;
QETH_CARD_TEXT(card, 4, "clipalst"); QETH_CARD_TEXT(card, 4, "clipalst");
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&card->lock, flags);
list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) { list_for_each_entry(reply, &card->cmd_waiter_list, list) {
qeth_get_reply(reply);
reply->rc = -EIO; reply->rc = -EIO;
atomic_inc(&reply->received); qeth_notify_reply(reply);
list_del_init(&reply->list);
wake_up(&reply->wait_q);
qeth_put_reply(reply);
} }
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
} }
...@@ -774,9 +791,10 @@ static void qeth_send_control_data_cb(struct qeth_card *card, ...@@ -774,9 +791,10 @@ static void qeth_send_control_data_cb(struct qeth_card *card,
struct qeth_cmd_buffer *iob) struct qeth_cmd_buffer *iob)
{ {
struct qeth_ipa_cmd *cmd = NULL; struct qeth_ipa_cmd *cmd = NULL;
struct qeth_reply *reply, *r; struct qeth_reply *reply = NULL;
struct qeth_reply *r;
unsigned long flags; unsigned long flags;
int keep_reply; int keep_reply = 0;
int rc = 0; int rc = 0;
QETH_CARD_TEXT(card, 4, "sndctlcb"); QETH_CARD_TEXT(card, 4, "sndctlcb");
...@@ -808,44 +826,40 @@ static void qeth_send_control_data_cb(struct qeth_card *card, ...@@ -808,44 +826,40 @@ static void qeth_send_control_data_cb(struct qeth_card *card,
goto out; goto out;
} }
/* match against pending cmd requests */
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&card->lock, flags);
list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) { list_for_each_entry(r, &card->cmd_waiter_list, list) {
if ((reply->seqno == QETH_IDX_COMMAND_SEQNO) || if ((r->seqno == QETH_IDX_COMMAND_SEQNO) ||
((cmd) && (reply->seqno == cmd->hdr.seqno))) { (cmd && (r->seqno == cmd->hdr.seqno))) {
reply = r;
/* take the object outside the lock */
qeth_get_reply(reply); qeth_get_reply(reply);
list_del_init(&reply->list); break;
spin_unlock_irqrestore(&card->lock, flags);
keep_reply = 0;
if (reply->callback != NULL) {
if (cmd) {
reply->offset = (__u16)((char *)cmd -
(char *)iob->data);
keep_reply = reply->callback(card,
reply,
(unsigned long)cmd);
} else
keep_reply = reply->callback(card,
reply,
(unsigned long)iob);
}
if (cmd)
reply->rc = (u16) cmd->hdr.return_code;
else if (iob->rc)
reply->rc = iob->rc;
if (keep_reply) {
spin_lock_irqsave(&card->lock, flags);
list_add_tail(&reply->list,
&card->cmd_waiter_list);
spin_unlock_irqrestore(&card->lock, flags);
} else {
atomic_inc(&reply->received);
wake_up(&reply->wait_q);
}
qeth_put_reply(reply);
goto out;
} }
} }
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
if (!reply)
goto out;
if (reply->callback) {
if (cmd) {
reply->offset = (u16)((char *)cmd - (char *)iob->data);
keep_reply = reply->callback(card, reply,
(unsigned long)cmd);
} else
keep_reply = reply->callback(card, reply,
(unsigned long)iob);
}
if (cmd)
reply->rc = (u16) cmd->hdr.return_code;
else if (iob->rc)
reply->rc = iob->rc;
if (!keep_reply)
qeth_notify_reply(reply);
qeth_put_reply(reply);
out: out:
memcpy(&card->seqno.pdu_hdr_ack, memcpy(&card->seqno.pdu_hdr_ack,
QETH_PDU_HEADER_SEQ_NO(iob->data), QETH_PDU_HEADER_SEQ_NO(iob->data),
...@@ -2047,8 +2061,6 @@ static int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2047,8 +2061,6 @@ static int qeth_send_control_data(struct qeth_card *card, int len,
reply->callback = reply_cb; reply->callback = reply_cb;
reply->param = reply_param; reply->param = reply_param;
init_waitqueue_head(&reply->wait_q);
while (atomic_cmpxchg(&channel->irq_pending, 0, 1)) ; while (atomic_cmpxchg(&channel->irq_pending, 0, 1)) ;
if (IS_IPA(iob->data)) { if (IS_IPA(iob->data)) {
...@@ -2062,9 +2074,7 @@ static int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2062,9 +2074,7 @@ static int qeth_send_control_data(struct qeth_card *card, int len,
} }
qeth_prepare_control_data(card, len, iob); qeth_prepare_control_data(card, len, iob);
spin_lock_irq(&card->lock); qeth_enqueue_reply(card, reply);
list_add_tail(&reply->list, &card->cmd_waiter_list);
spin_unlock_irq(&card->lock);
timeout = jiffies + event_timeout; timeout = jiffies + event_timeout;
...@@ -2077,10 +2087,8 @@ static int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2077,10 +2087,8 @@ static int qeth_send_control_data(struct qeth_card *card, int len,
QETH_DBF_MESSAGE(2, "qeth_send_control_data on device %x: ccw_device_start rc = %i\n", QETH_DBF_MESSAGE(2, "qeth_send_control_data on device %x: ccw_device_start rc = %i\n",
CARD_DEVID(card), rc); CARD_DEVID(card), rc);
QETH_CARD_TEXT_(card, 2, " err%d", rc); QETH_CARD_TEXT_(card, 2, " err%d", rc);
spin_lock_irq(&card->lock); qeth_dequeue_reply(card, reply);
list_del_init(&reply->list);
qeth_put_reply(reply); qeth_put_reply(reply);
spin_unlock_irq(&card->lock);
qeth_release_buffer(channel, iob); qeth_release_buffer(channel, iob);
atomic_set(&channel->irq_pending, 0); atomic_set(&channel->irq_pending, 0);
wake_up(&card->wait_q); wake_up(&card->wait_q);
...@@ -2102,19 +2110,15 @@ static int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2102,19 +2110,15 @@ static int qeth_send_control_data(struct qeth_card *card, int len,
} }
} }
qeth_dequeue_reply(card, reply);
rc = reply->rc; rc = reply->rc;
qeth_put_reply(reply); qeth_put_reply(reply);
return rc; return rc;
time_err: time_err:
reply->rc = -ETIME; qeth_dequeue_reply(card, reply);
spin_lock_irq(&card->lock);
list_del_init(&reply->list);
spin_unlock_irq(&card->lock);
atomic_inc(&reply->received);
rc = reply->rc;
qeth_put_reply(reply); qeth_put_reply(reply);
return rc; return -ETIME;
} }
static int qeth_cm_enable_cb(struct qeth_card *card, struct qeth_reply *reply, static int qeth_cm_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
......
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