Commit 308946b0 authored by Julian Wiedmann's avatar Julian Wiedmann Committed by David S. Miller

s390/qeth: merge qeth_reply struct into qeth_cmd_buffer

Except for card->read_cmd, every cmd we issue now passes through
qeth_send_control_data() and allocates a qeth_reply struct. The way we
use this struct requires additional refcounting, and pointer tracking.

Clean up things by moving most of qeth_reply's content into the main
cmd struct. This keeps things in one place, saves us the additional
refcounting and simplifies the overall code flow.
A nice little benefit is that we can now match incoming replies against
the pending requests themselves, without caching the requests' seqnos.

The qeth_reply struct stays around for a little bit longer in a shrunk
form, to avoid touching every single callback.
Signed-off-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 32e85a0d
...@@ -572,16 +572,26 @@ struct qeth_channel { ...@@ -572,16 +572,26 @@ struct qeth_channel {
atomic_t irq_pending; atomic_t irq_pending;
}; };
struct qeth_reply {
int (*callback)(struct qeth_card *card, struct qeth_reply *reply,
unsigned long data);
void *param;
};
struct qeth_cmd_buffer { struct qeth_cmd_buffer {
struct list_head list;
struct completion done;
spinlock_t lock;
unsigned int length; unsigned int length;
refcount_t ref_count; refcount_t ref_count;
struct qeth_channel *channel; struct qeth_channel *channel;
struct qeth_reply *reply; struct qeth_reply reply;
long timeout; long timeout;
unsigned char *data; unsigned char *data;
void (*finalize)(struct qeth_card *card, struct qeth_cmd_buffer *iob); void (*finalize)(struct qeth_card *card, struct qeth_cmd_buffer *iob);
void (*callback)(struct qeth_card *card, struct qeth_cmd_buffer *iob, void (*callback)(struct qeth_card *card, struct qeth_cmd_buffer *iob,
unsigned int data_length); unsigned int data_length);
int rc;
}; };
static inline void qeth_get_cmd(struct qeth_cmd_buffer *iob) static inline void qeth_get_cmd(struct qeth_cmd_buffer *iob)
...@@ -627,18 +637,6 @@ struct qeth_seqno { ...@@ -627,18 +637,6 @@ struct qeth_seqno {
__u16 ipa; __u16 ipa;
}; };
struct qeth_reply {
struct list_head list;
struct completion received;
spinlock_t lock;
int (*callback)(struct qeth_card *, struct qeth_reply *,
unsigned long);
u32 seqno;
int rc;
void *param;
refcount_t refcnt;
};
struct qeth_card_blkt { struct qeth_card_blkt {
int time_total; int time_total;
int inter_packet; int inter_packet;
...@@ -994,6 +992,7 @@ struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card, ...@@ -994,6 +992,7 @@ struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card,
struct qeth_cmd_buffer *qeth_get_diag_cmd(struct qeth_card *card, struct qeth_cmd_buffer *qeth_get_diag_cmd(struct qeth_card *card,
enum qeth_diags_cmds sub_cmd, enum qeth_diags_cmds sub_cmd,
unsigned int data_length); unsigned int data_length);
void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason);
void qeth_put_cmd(struct qeth_cmd_buffer *iob); void qeth_put_cmd(struct qeth_cmd_buffer *iob);
struct sk_buff *qeth_core_get_next_skb(struct qeth_card *, struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
...@@ -1008,7 +1007,6 @@ void qeth_drain_output_queues(struct qeth_card *card); ...@@ -1008,7 +1007,6 @@ void qeth_drain_output_queues(struct qeth_card *card);
void qeth_setadp_promisc_mode(struct qeth_card *); void qeth_setadp_promisc_mode(struct qeth_card *);
int qeth_setadpparms_change_macaddr(struct qeth_card *); int qeth_setadpparms_change_macaddr(struct qeth_card *);
void qeth_tx_timeout(struct net_device *); void qeth_tx_timeout(struct net_device *);
void qeth_notify_reply(struct qeth_reply *reply, int reason);
void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
u16 cmd_length); u16 cmd_length);
int qeth_query_switch_attributes(struct qeth_card *card, int qeth_query_switch_attributes(struct qeth_card *card,
......
...@@ -537,50 +537,28 @@ static int qeth_issue_next_read(struct qeth_card *card) ...@@ -537,50 +537,28 @@ static int qeth_issue_next_read(struct qeth_card *card)
return ret; return ret;
} }
static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) static void qeth_enqueue_cmd(struct qeth_card *card,
{ struct qeth_cmd_buffer *iob)
struct qeth_reply *reply;
reply = kzalloc(sizeof(*reply), GFP_KERNEL);
if (reply) {
refcount_set(&reply->refcnt, 1);
init_completion(&reply->received);
spin_lock_init(&reply->lock);
}
return reply;
}
static void qeth_get_reply(struct qeth_reply *reply)
{
refcount_inc(&reply->refcnt);
}
static void qeth_put_reply(struct qeth_reply *reply)
{
if (refcount_dec_and_test(&reply->refcnt))
kfree(reply);
}
static void qeth_enqueue_reply(struct qeth_card *card, struct qeth_reply *reply)
{ {
spin_lock_irq(&card->lock); spin_lock_irq(&card->lock);
list_add_tail(&reply->list, &card->cmd_waiter_list); list_add_tail(&iob->list, &card->cmd_waiter_list);
spin_unlock_irq(&card->lock); spin_unlock_irq(&card->lock);
} }
static void qeth_dequeue_reply(struct qeth_card *card, struct qeth_reply *reply) static void qeth_dequeue_cmd(struct qeth_card *card,
struct qeth_cmd_buffer *iob)
{ {
spin_lock_irq(&card->lock); spin_lock_irq(&card->lock);
list_del(&reply->list); list_del(&iob->list);
spin_unlock_irq(&card->lock); spin_unlock_irq(&card->lock);
} }
void qeth_notify_reply(struct qeth_reply *reply, int reason) void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason)
{ {
reply->rc = reason; iob->rc = reason;
complete(&reply->received); complete(&iob->done);
} }
EXPORT_SYMBOL_GPL(qeth_notify_reply); EXPORT_SYMBOL_GPL(qeth_notify_cmd);
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)
...@@ -658,14 +636,14 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, ...@@ -658,14 +636,14 @@ 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; struct qeth_cmd_buffer *iob;
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(reply, &card->cmd_waiter_list, list) list_for_each_entry(iob, &card->cmd_waiter_list, list)
qeth_notify_reply(reply, -EIO); qeth_notify_cmd(iob, -EIO);
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
} }
EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list); EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list);
...@@ -694,8 +672,6 @@ static int qeth_check_idx_response(struct qeth_card *card, ...@@ -694,8 +672,6 @@ static int qeth_check_idx_response(struct qeth_card *card,
void qeth_put_cmd(struct qeth_cmd_buffer *iob) void qeth_put_cmd(struct qeth_cmd_buffer *iob)
{ {
if (refcount_dec_and_test(&iob->ref_count)) { if (refcount_dec_and_test(&iob->ref_count)) {
if (iob->reply)
qeth_put_reply(iob->reply);
kfree(iob->data); kfree(iob->data);
kfree(iob); kfree(iob);
} }
...@@ -711,10 +687,7 @@ static void qeth_release_buffer_cb(struct qeth_card *card, ...@@ -711,10 +687,7 @@ static void qeth_release_buffer_cb(struct qeth_card *card,
static void qeth_cancel_cmd(struct qeth_cmd_buffer *iob, int rc) static void qeth_cancel_cmd(struct qeth_cmd_buffer *iob, int rc)
{ {
struct qeth_reply *reply = iob->reply; qeth_notify_cmd(iob, rc);
if (reply)
qeth_notify_reply(reply, rc);
qeth_put_cmd(iob); qeth_put_cmd(iob);
} }
...@@ -738,6 +711,9 @@ struct qeth_cmd_buffer *qeth_alloc_cmd(struct qeth_channel *channel, ...@@ -738,6 +711,9 @@ struct qeth_cmd_buffer *qeth_alloc_cmd(struct qeth_channel *channel,
return NULL; return NULL;
} }
init_completion(&iob->done);
spin_lock_init(&iob->lock);
INIT_LIST_HEAD(&iob->list);
refcount_set(&iob->ref_count, 1); refcount_set(&iob->ref_count, 1);
iob->channel = channel; iob->channel = channel;
iob->timeout = timeout; iob->timeout = timeout;
...@@ -750,9 +726,10 @@ static void qeth_issue_next_read_cb(struct qeth_card *card, ...@@ -750,9 +726,10 @@ 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)
{ {
struct qeth_cmd_buffer *request = NULL;
struct qeth_ipa_cmd *cmd = NULL; struct qeth_ipa_cmd *cmd = NULL;
struct qeth_reply *reply = NULL; struct qeth_reply *reply = NULL;
struct qeth_reply *r; struct qeth_cmd_buffer *tmp;
unsigned long flags; unsigned long flags;
int rc = 0; int rc = 0;
...@@ -787,39 +764,39 @@ static void qeth_issue_next_read_cb(struct qeth_card *card, ...@@ -787,39 +764,39 @@ static void qeth_issue_next_read_cb(struct qeth_card *card,
/* match against pending cmd requests */ /* match against pending cmd requests */
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&card->lock, flags);
list_for_each_entry(r, &card->cmd_waiter_list, list) { list_for_each_entry(tmp, &card->cmd_waiter_list, list) {
if ((r->seqno == QETH_IDX_COMMAND_SEQNO) || if (!IS_IPA(tmp->data) ||
(cmd && (r->seqno == cmd->hdr.seqno))) { __ipa_cmd(tmp)->hdr.seqno == cmd->hdr.seqno) {
reply = r; request = tmp;
/* take the object outside the lock */ /* take the object outside the lock */
qeth_get_reply(reply); qeth_get_cmd(request);
break; break;
} }
} }
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
if (!reply) if (!request)
goto out; goto out;
reply = &request->reply;
if (!reply->callback) { if (!reply->callback) {
rc = 0; rc = 0;
goto no_callback; goto no_callback;
} }
spin_lock_irqsave(&reply->lock, flags); spin_lock_irqsave(&request->lock, flags);
if (reply->rc) if (request->rc)
/* Bail out when the requestor has already left: */ /* Bail out when the requestor has already left: */
rc = reply->rc; rc = request->rc;
else else
rc = reply->callback(card, reply, cmd ? (unsigned long)cmd : rc = reply->callback(card, reply, cmd ? (unsigned long)cmd :
(unsigned long)iob); (unsigned long)iob);
spin_unlock_irqrestore(&reply->lock, flags); spin_unlock_irqrestore(&request->lock, flags);
no_callback: no_callback:
if (rc <= 0) if (rc <= 0)
qeth_notify_reply(reply, rc); qeth_notify_cmd(request, rc);
qeth_put_reply(reply); qeth_put_cmd(request);
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),
...@@ -1658,7 +1635,6 @@ static void qeth_mpc_finalize_cmd(struct qeth_card *card, ...@@ -1658,7 +1635,6 @@ static void qeth_mpc_finalize_cmd(struct qeth_card *card,
memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data), memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data),
&card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH); &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH);
iob->reply->seqno = QETH_IDX_COMMAND_SEQNO;
iob->callback = qeth_release_buffer_cb; iob->callback = qeth_release_buffer_cb;
} }
...@@ -1709,29 +1685,19 @@ static int qeth_send_control_data(struct qeth_card *card, ...@@ -1709,29 +1685,19 @@ static int qeth_send_control_data(struct qeth_card *card,
void *reply_param) void *reply_param)
{ {
struct qeth_channel *channel = iob->channel; struct qeth_channel *channel = iob->channel;
struct qeth_reply *reply = &iob->reply;
long timeout = iob->timeout; long timeout = iob->timeout;
int rc; int rc;
struct qeth_reply *reply = NULL;
QETH_CARD_TEXT(card, 2, "sendctl"); QETH_CARD_TEXT(card, 2, "sendctl");
reply = qeth_alloc_reply(card);
if (!reply) {
qeth_put_cmd(iob);
return -ENOMEM;
}
reply->callback = reply_cb; reply->callback = reply_cb;
reply->param = reply_param; reply->param = reply_param;
/* pairs with qeth_put_cmd(): */
qeth_get_reply(reply);
iob->reply = reply;
timeout = wait_event_interruptible_timeout(card->wait_q, timeout = wait_event_interruptible_timeout(card->wait_q,
qeth_trylock_channel(channel), qeth_trylock_channel(channel),
timeout); timeout);
if (timeout <= 0) { if (timeout <= 0) {
qeth_put_reply(reply);
qeth_put_cmd(iob); qeth_put_cmd(iob);
return (timeout == -ERESTARTSYS) ? -EINTR : -ETIME; return (timeout == -ERESTARTSYS) ? -EINTR : -ETIME;
} }
...@@ -1740,7 +1706,7 @@ static int qeth_send_control_data(struct qeth_card *card, ...@@ -1740,7 +1706,7 @@ static int qeth_send_control_data(struct qeth_card *card,
iob->finalize(card, iob); iob->finalize(card, iob);
QETH_DBF_HEX(CTRL, 2, iob->data, min(iob->length, QETH_DBF_CTRL_LEN)); QETH_DBF_HEX(CTRL, 2, iob->data, min(iob->length, QETH_DBF_CTRL_LEN));
qeth_enqueue_reply(card, reply); qeth_enqueue_cmd(card, iob);
/* This pairs with iob->callback, and keeps the iob alive after IO: */ /* This pairs with iob->callback, and keeps the iob alive after IO: */
qeth_get_cmd(iob); qeth_get_cmd(iob);
...@@ -1754,34 +1720,33 @@ static int qeth_send_control_data(struct qeth_card *card, ...@@ -1754,34 +1720,33 @@ static int qeth_send_control_data(struct qeth_card *card,
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);
qeth_dequeue_reply(card, reply); qeth_dequeue_cmd(card, iob);
qeth_put_cmd(iob); qeth_put_cmd(iob);
atomic_set(&channel->irq_pending, 0); atomic_set(&channel->irq_pending, 0);
wake_up(&card->wait_q); wake_up(&card->wait_q);
goto out; goto out;
} }
timeout = wait_for_completion_interruptible_timeout(&reply->received, timeout = wait_for_completion_interruptible_timeout(&iob->done,
timeout); timeout);
if (timeout <= 0) if (timeout <= 0)
rc = (timeout == -ERESTARTSYS) ? -EINTR : -ETIME; rc = (timeout == -ERESTARTSYS) ? -EINTR : -ETIME;
qeth_dequeue_reply(card, reply); qeth_dequeue_cmd(card, iob);
if (reply_cb) { if (reply_cb) {
/* Wait until the callback for a late reply has completed: */ /* Wait until the callback for a late reply has completed: */
spin_lock_irq(&reply->lock); spin_lock_irq(&iob->lock);
if (rc) if (rc)
/* Zap any callback that's still pending: */ /* Zap any callback that's still pending: */
reply->rc = rc; iob->rc = rc;
spin_unlock_irq(&reply->lock); spin_unlock_irq(&iob->lock);
} }
if (!rc) if (!rc)
rc = reply->rc; rc = iob->rc;
out: out:
qeth_put_reply(reply);
qeth_put_cmd(iob); qeth_put_cmd(iob);
return rc; return rc;
} }
...@@ -1822,7 +1787,7 @@ static void qeth_read_conf_data_cb(struct qeth_card *card, ...@@ -1822,7 +1787,7 @@ static void qeth_read_conf_data_cb(struct qeth_card *card,
nd->nd3.model[2] <= 0xF4; nd->nd3.model[2] <= 0xF4;
out: out:
qeth_notify_reply(iob->reply, rc); qeth_notify_cmd(iob, rc);
qeth_put_cmd(iob); qeth_put_cmd(iob);
} }
...@@ -1914,7 +1879,7 @@ static void qeth_idx_activate_read_channel_cb(struct qeth_card *card, ...@@ -1914,7 +1879,7 @@ static void qeth_idx_activate_read_channel_cb(struct qeth_card *card,
QETH_IDX_REPLY_LEVEL(iob->data), QETH_MCL_LENGTH); QETH_IDX_REPLY_LEVEL(iob->data), QETH_MCL_LENGTH);
out: out:
qeth_notify_reply(iob->reply, rc); qeth_notify_cmd(iob, rc);
qeth_put_cmd(iob); qeth_put_cmd(iob);
} }
...@@ -1942,7 +1907,7 @@ static void qeth_idx_activate_write_channel_cb(struct qeth_card *card, ...@@ -1942,7 +1907,7 @@ static void qeth_idx_activate_write_channel_cb(struct qeth_card *card,
} }
out: out:
qeth_notify_reply(iob->reply, rc); qeth_notify_cmd(iob, rc);
qeth_put_cmd(iob); qeth_put_cmd(iob);
} }
...@@ -2675,8 +2640,7 @@ static void qeth_ipa_finalize_cmd(struct qeth_card *card, ...@@ -2675,8 +2640,7 @@ static void qeth_ipa_finalize_cmd(struct qeth_card *card,
qeth_mpc_finalize_cmd(card, iob); qeth_mpc_finalize_cmd(card, iob);
/* override with IPA-specific values: */ /* override with IPA-specific values: */
__ipa_cmd(iob)->hdr.seqno = card->seqno.ipa; __ipa_cmd(iob)->hdr.seqno = card->seqno.ipa++;
iob->reply->seqno = card->seqno.ipa++;
} }
void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
......
...@@ -27,7 +27,6 @@ extern unsigned char IPA_PDU_HEADER[]; ...@@ -27,7 +27,6 @@ extern unsigned char IPA_PDU_HEADER[];
#define QETH_TIMEOUT (10 * HZ) #define QETH_TIMEOUT (10 * HZ)
#define QETH_IPA_TIMEOUT (45 * HZ) #define QETH_IPA_TIMEOUT (45 * HZ)
#define QETH_IDX_COMMAND_SEQNO 0xffff0000
#define QETH_CLEAR_CHANNEL_PARM -10 #define QETH_CLEAR_CHANNEL_PARM -10
#define QETH_HALT_CHANNEL_PARM -11 #define QETH_HALT_CHANNEL_PARM -11
......
...@@ -1003,7 +1003,7 @@ static void qeth_osn_assist_cb(struct qeth_card *card, ...@@ -1003,7 +1003,7 @@ static void qeth_osn_assist_cb(struct qeth_card *card,
struct qeth_cmd_buffer *iob, struct qeth_cmd_buffer *iob,
unsigned int data_length) unsigned int data_length)
{ {
qeth_notify_reply(iob->reply, 0); qeth_notify_cmd(iob, 0);
qeth_put_cmd(iob); qeth_put_cmd(iob);
} }
......
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