Commit 782e4a79 authored by Julian Wiedmann's avatar Julian Wiedmann Committed by David S. Miller

s390/qeth: don't poll for cmd IO completion

All callers are running in process context now, so we can safely sleep
in qeth_send_control_data() while waiting for a cmd to complete.
Signed-off-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent df2a2a52
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#ifndef __QETH_CORE_H__ #ifndef __QETH_CORE_H__
#define __QETH_CORE_H__ #define __QETH_CORE_H__
#include <linux/completion.h>
#include <linux/if.h> #include <linux/if.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
...@@ -21,6 +22,7 @@ ...@@ -21,6 +22,7 @@
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/refcount.h> #include <linux/refcount.h>
#include <linux/wait.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <net/ipv6.h> #include <net/ipv6.h>
...@@ -585,6 +587,7 @@ struct qeth_cmd_buffer { ...@@ -585,6 +587,7 @@ struct qeth_cmd_buffer {
enum qeth_cmd_buffer_state state; enum qeth_cmd_buffer_state state;
struct qeth_channel *channel; struct qeth_channel *channel;
struct qeth_reply *reply; struct qeth_reply *reply;
long timeout;
unsigned char *data; unsigned char *data;
void (*callback)(struct qeth_card *card, struct qeth_channel *channel, void (*callback)(struct qeth_card *card, struct qeth_channel *channel,
struct qeth_cmd_buffer *iob); struct qeth_cmd_buffer *iob);
...@@ -610,6 +613,11 @@ struct qeth_channel { ...@@ -610,6 +613,11 @@ struct qeth_channel {
int io_buf_no; int io_buf_no;
}; };
static inline bool qeth_trylock_channel(struct qeth_channel *channel)
{
return atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0;
}
/** /**
* OSA card related definitions * OSA card related definitions
*/ */
...@@ -636,12 +644,11 @@ struct qeth_seqno { ...@@ -636,12 +644,11 @@ struct qeth_seqno {
struct qeth_reply { struct qeth_reply {
struct list_head list; struct list_head list;
wait_queue_head_t wait_q; struct completion received;
int (*callback)(struct qeth_card *, struct qeth_reply *, int (*callback)(struct qeth_card *, struct qeth_reply *,
unsigned long); unsigned long);
u32 seqno; u32 seqno;
unsigned long offset; unsigned long offset;
atomic_t received;
int rc; int rc;
void *param; void *param;
refcount_t refcnt; refcount_t refcnt;
......
...@@ -542,11 +542,10 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) ...@@ -542,11 +542,10 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
{ {
struct qeth_reply *reply; struct qeth_reply *reply;
reply = kzalloc(sizeof(struct qeth_reply), GFP_ATOMIC); reply = kzalloc(sizeof(*reply), GFP_KERNEL);
if (reply) { if (reply) {
refcount_set(&reply->refcnt, 1); refcount_set(&reply->refcnt, 1);
atomic_set(&reply->received, 0); init_completion(&reply->received);
init_waitqueue_head(&reply->wait_q);
} }
return reply; return reply;
} }
...@@ -578,8 +577,7 @@ static void qeth_dequeue_reply(struct qeth_card *card, struct qeth_reply *reply) ...@@ -578,8 +577,7 @@ static void qeth_dequeue_reply(struct qeth_card *card, struct qeth_reply *reply)
static void qeth_notify_reply(struct qeth_reply *reply) static void qeth_notify_reply(struct qeth_reply *reply)
{ {
atomic_inc(&reply->received); complete(&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,
...@@ -704,6 +702,7 @@ static struct qeth_cmd_buffer *__qeth_get_buffer(struct qeth_channel *channel) ...@@ -704,6 +702,7 @@ static struct qeth_cmd_buffer *__qeth_get_buffer(struct qeth_channel *channel)
do { do {
if (channel->iob[index].state == BUF_STATE_FREE) { if (channel->iob[index].state == BUF_STATE_FREE) {
channel->iob[index].state = BUF_STATE_LOCKED; channel->iob[index].state = BUF_STATE_LOCKED;
channel->iob[index].timeout = QETH_TIMEOUT;
channel->io_buf_no = (channel->io_buf_no + 1) % channel->io_buf_no = (channel->io_buf_no + 1) %
QETH_CMD_BUFFER_NO; QETH_CMD_BUFFER_NO;
memset(channel->iob[index].data, 0, QETH_BUFSIZE); memset(channel->iob[index].data, 0, QETH_BUFSIZE);
...@@ -1786,8 +1785,7 @@ static int qeth_idx_activate_get_answer(struct qeth_card *card, ...@@ -1786,8 +1785,7 @@ static int qeth_idx_activate_get_answer(struct qeth_card *card,
iob->callback = reply_cb; iob->callback = reply_cb;
qeth_setup_ccw(channel->ccw, CCW_CMD_READ, QETH_BUFSIZE, iob->data); qeth_setup_ccw(channel->ccw, CCW_CMD_READ, QETH_BUFSIZE, iob->data);
wait_event(card->wait_q, wait_event(card->wait_q, qeth_trylock_channel(channel));
atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
QETH_DBF_TEXT(SETUP, 6, "noirqpnd"); QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw, rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw,
...@@ -1855,8 +1853,7 @@ static int qeth_idx_activate_channel(struct qeth_card *card, ...@@ -1855,8 +1853,7 @@ static int qeth_idx_activate_channel(struct qeth_card *card,
temp = (card->info.cula << 8) + card->info.unit_addr2; temp = (card->info.cula << 8) + card->info.unit_addr2;
memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(iob->data), &temp, 2); memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(iob->data), &temp, 2);
wait_event(card->wait_q, wait_event(card->wait_q, qeth_trylock_channel(channel));
atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
QETH_DBF_TEXT(SETUP, 6, "noirqpnd"); QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw, rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw,
...@@ -2034,9 +2031,9 @@ static int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2034,9 +2031,9 @@ static int qeth_send_control_data(struct qeth_card *card, int len,
void *reply_param) void *reply_param)
{ {
struct qeth_channel *channel = iob->channel; struct qeth_channel *channel = iob->channel;
long timeout = iob->timeout;
int rc; int rc;
struct qeth_reply *reply = NULL; struct qeth_reply *reply = NULL;
unsigned long timeout, event_timeout;
struct qeth_ipa_cmd *cmd = NULL; struct qeth_ipa_cmd *cmd = NULL;
QETH_CARD_TEXT(card, 2, "sendctl"); QETH_CARD_TEXT(card, 2, "sendctl");
...@@ -2057,27 +2054,30 @@ static int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2057,27 +2054,30 @@ static int qeth_send_control_data(struct qeth_card *card, int len,
qeth_get_reply(reply); qeth_get_reply(reply);
iob->reply = reply; iob->reply = reply;
while (atomic_cmpxchg(&channel->irq_pending, 0, 1)) ; timeout = wait_event_interruptible_timeout(card->wait_q,
qeth_trylock_channel(channel),
timeout);
if (timeout <= 0) {
qeth_put_reply(reply);
qeth_release_buffer(channel, iob);
return (timeout == -ERESTARTSYS) ? -EINTR : -ETIME;
}
if (IS_IPA(iob->data)) { if (IS_IPA(iob->data)) {
cmd = __ipa_cmd(iob); cmd = __ipa_cmd(iob);
cmd->hdr.seqno = card->seqno.ipa++; cmd->hdr.seqno = card->seqno.ipa++;
reply->seqno = cmd->hdr.seqno; reply->seqno = cmd->hdr.seqno;
event_timeout = QETH_IPA_TIMEOUT;
} else { } else {
reply->seqno = QETH_IDX_COMMAND_SEQNO; reply->seqno = QETH_IDX_COMMAND_SEQNO;
event_timeout = QETH_TIMEOUT;
} }
qeth_prepare_control_data(card, len, iob); qeth_prepare_control_data(card, len, iob);
qeth_enqueue_reply(card, reply); qeth_enqueue_reply(card, reply);
timeout = jiffies + event_timeout;
QETH_CARD_TEXT(card, 6, "noirqpnd"); QETH_CARD_TEXT(card, 6, "noirqpnd");
spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw, rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw,
(addr_t) iob, 0, 0, event_timeout); (addr_t) iob, 0, 0, timeout);
spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
if (rc) { if (rc) {
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",
...@@ -2091,30 +2091,16 @@ static int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2091,30 +2091,16 @@ static int qeth_send_control_data(struct qeth_card *card, int len,
return rc; return rc;
} }
/* we have only one long running ipassist, since we can ensure timeout = wait_for_completion_interruptible_timeout(&reply->received,
process context of this command we can sleep */ timeout);
if (cmd && cmd->hdr.command == IPA_CMD_SETIP && if (timeout <= 0)
cmd->hdr.prot_version == QETH_PROT_IPV4) { rc = (timeout == -ERESTARTSYS) ? -EINTR : -ETIME;
if (!wait_event_timeout(reply->wait_q,
atomic_read(&reply->received), event_timeout))
goto time_err;
} else {
while (!atomic_read(&reply->received)) {
if (time_after(jiffies, timeout))
goto time_err;
cpu_relax();
}
}
qeth_dequeue_reply(card, reply); qeth_dequeue_reply(card, reply);
if (!rc)
rc = reply->rc; rc = reply->rc;
qeth_put_reply(reply); qeth_put_reply(reply);
return rc; return rc;
time_err:
qeth_dequeue_reply(card, reply);
qeth_put_reply(reply);
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,
...@@ -2810,6 +2796,8 @@ void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, ...@@ -2810,6 +2796,8 @@ void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
u16 total_length = IPA_PDU_HEADER_SIZE + cmd_length; u16 total_length = IPA_PDU_HEADER_SIZE + cmd_length;
u8 prot_type = qeth_mpc_select_prot_type(card); u8 prot_type = qeth_mpc_select_prot_type(card);
iob->timeout = QETH_IPA_TIMEOUT;
memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &total_length, 2); memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &total_length, 2);
memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data), &prot_type, 1); memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data), &prot_type, 1);
......
...@@ -1050,13 +1050,12 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len, ...@@ -1050,13 +1050,12 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len,
QETH_CARD_TEXT(card, 5, "osndctrd"); QETH_CARD_TEXT(card, 5, "osndctrd");
wait_event(card->wait_q, wait_event(card->wait_q, qeth_trylock_channel(channel));
atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
qeth_prepare_control_data(card, len, iob); qeth_prepare_control_data(card, len, iob);
QETH_CARD_TEXT(card, 6, "osnoirqp"); QETH_CARD_TEXT(card, 6, "osnoirqp");
spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw, rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw,
(addr_t) iob, 0, 0, QETH_IPA_TIMEOUT); (addr_t) iob, 0, 0, iob->timeout);
spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
if (rc) { if (rc) {
QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: " QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: "
......
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