forked from Minki/linux
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: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
32e85a0d83
commit
308946b074
@ -572,16 +572,26 @@ struct qeth_channel {
|
||||
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 list_head list;
|
||||
struct completion done;
|
||||
spinlock_t lock;
|
||||
unsigned int length;
|
||||
refcount_t ref_count;
|
||||
struct qeth_channel *channel;
|
||||
struct qeth_reply *reply;
|
||||
struct qeth_reply reply;
|
||||
long timeout;
|
||||
unsigned char *data;
|
||||
void (*finalize)(struct qeth_card *card, struct qeth_cmd_buffer *iob);
|
||||
void (*callback)(struct qeth_card *card, struct qeth_cmd_buffer *iob,
|
||||
unsigned int data_length);
|
||||
int rc;
|
||||
};
|
||||
|
||||
static inline void qeth_get_cmd(struct qeth_cmd_buffer *iob)
|
||||
@ -627,18 +637,6 @@ struct qeth_seqno {
|
||||
__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 {
|
||||
int time_total;
|
||||
int inter_packet;
|
||||
@ -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,
|
||||
enum qeth_diags_cmds sub_cmd,
|
||||
unsigned int data_length);
|
||||
void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason);
|
||||
void qeth_put_cmd(struct qeth_cmd_buffer *iob);
|
||||
|
||||
struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
|
||||
@ -1008,7 +1007,6 @@ void qeth_drain_output_queues(struct qeth_card *card);
|
||||
void qeth_setadp_promisc_mode(struct qeth_card *);
|
||||
int qeth_setadpparms_change_macaddr(struct qeth_card *);
|
||||
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,
|
||||
u16 cmd_length);
|
||||
int qeth_query_switch_attributes(struct qeth_card *card,
|
||||
|
@ -537,50 +537,28 @@ static int qeth_issue_next_read(struct qeth_card *card)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
|
||||
{
|
||||
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)
|
||||
static void qeth_enqueue_cmd(struct qeth_card *card,
|
||||
struct qeth_cmd_buffer *iob)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
list_del(&reply->list);
|
||||
list_del(&iob->list);
|
||||
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;
|
||||
complete(&reply->received);
|
||||
iob->rc = reason;
|
||||
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,
|
||||
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)
|
||||
{
|
||||
struct qeth_reply *reply;
|
||||
struct qeth_cmd_buffer *iob;
|
||||
unsigned long flags;
|
||||
|
||||
QETH_CARD_TEXT(card, 4, "clipalst");
|
||||
|
||||
spin_lock_irqsave(&card->lock, flags);
|
||||
list_for_each_entry(reply, &card->cmd_waiter_list, list)
|
||||
qeth_notify_reply(reply, -EIO);
|
||||
list_for_each_entry(iob, &card->cmd_waiter_list, list)
|
||||
qeth_notify_cmd(iob, -EIO);
|
||||
spin_unlock_irqrestore(&card->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list);
|
||||
@ -694,8 +672,6 @@ static int qeth_check_idx_response(struct qeth_card *card,
|
||||
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);
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
struct qeth_reply *reply = iob->reply;
|
||||
|
||||
if (reply)
|
||||
qeth_notify_reply(reply, rc);
|
||||
qeth_notify_cmd(iob, rc);
|
||||
qeth_put_cmd(iob);
|
||||
}
|
||||
|
||||
@ -738,6 +711,9 @@ struct qeth_cmd_buffer *qeth_alloc_cmd(struct qeth_channel *channel,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
init_completion(&iob->done);
|
||||
spin_lock_init(&iob->lock);
|
||||
INIT_LIST_HEAD(&iob->list);
|
||||
refcount_set(&iob->ref_count, 1);
|
||||
iob->channel = channel;
|
||||
iob->timeout = timeout;
|
||||
@ -750,9 +726,10 @@ static void qeth_issue_next_read_cb(struct qeth_card *card,
|
||||
struct qeth_cmd_buffer *iob,
|
||||
unsigned int data_length)
|
||||
{
|
||||
struct qeth_cmd_buffer *request = NULL;
|
||||
struct qeth_ipa_cmd *cmd = NULL;
|
||||
struct qeth_reply *reply = NULL;
|
||||
struct qeth_reply *r;
|
||||
struct qeth_cmd_buffer *tmp;
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
|
||||
@ -787,39 +764,39 @@ static void qeth_issue_next_read_cb(struct qeth_card *card,
|
||||
|
||||
/* match against pending cmd requests */
|
||||
spin_lock_irqsave(&card->lock, flags);
|
||||
list_for_each_entry(r, &card->cmd_waiter_list, list) {
|
||||
if ((r->seqno == QETH_IDX_COMMAND_SEQNO) ||
|
||||
(cmd && (r->seqno == cmd->hdr.seqno))) {
|
||||
reply = r;
|
||||
list_for_each_entry(tmp, &card->cmd_waiter_list, list) {
|
||||
if (!IS_IPA(tmp->data) ||
|
||||
__ipa_cmd(tmp)->hdr.seqno == cmd->hdr.seqno) {
|
||||
request = tmp;
|
||||
/* take the object outside the lock */
|
||||
qeth_get_reply(reply);
|
||||
qeth_get_cmd(request);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&card->lock, flags);
|
||||
|
||||
if (!reply)
|
||||
if (!request)
|
||||
goto out;
|
||||
|
||||
reply = &request->reply;
|
||||
if (!reply->callback) {
|
||||
rc = 0;
|
||||
goto no_callback;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&reply->lock, flags);
|
||||
if (reply->rc)
|
||||
spin_lock_irqsave(&request->lock, flags);
|
||||
if (request->rc)
|
||||
/* Bail out when the requestor has already left: */
|
||||
rc = reply->rc;
|
||||
rc = request->rc;
|
||||
else
|
||||
rc = reply->callback(card, reply, cmd ? (unsigned long)cmd :
|
||||
(unsigned long)iob);
|
||||
spin_unlock_irqrestore(&reply->lock, flags);
|
||||
spin_unlock_irqrestore(&request->lock, flags);
|
||||
|
||||
no_callback:
|
||||
if (rc <= 0)
|
||||
qeth_notify_reply(reply, rc);
|
||||
qeth_put_reply(reply);
|
||||
|
||||
qeth_notify_cmd(request, rc);
|
||||
qeth_put_cmd(request);
|
||||
out:
|
||||
memcpy(&card->seqno.pdu_hdr_ack,
|
||||
QETH_PDU_HEADER_SEQ_NO(iob->data),
|
||||
@ -1658,7 +1635,6 @@ static void qeth_mpc_finalize_cmd(struct qeth_card *card,
|
||||
memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data),
|
||||
&card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH);
|
||||
|
||||
iob->reply->seqno = QETH_IDX_COMMAND_SEQNO;
|
||||
iob->callback = qeth_release_buffer_cb;
|
||||
}
|
||||
|
||||
@ -1709,29 +1685,19 @@ static int qeth_send_control_data(struct qeth_card *card,
|
||||
void *reply_param)
|
||||
{
|
||||
struct qeth_channel *channel = iob->channel;
|
||||
struct qeth_reply *reply = &iob->reply;
|
||||
long timeout = iob->timeout;
|
||||
int rc;
|
||||
struct qeth_reply *reply = NULL;
|
||||
|
||||
QETH_CARD_TEXT(card, 2, "sendctl");
|
||||
|
||||
reply = qeth_alloc_reply(card);
|
||||
if (!reply) {
|
||||
qeth_put_cmd(iob);
|
||||
return -ENOMEM;
|
||||
}
|
||||
reply->callback = reply_cb;
|
||||
reply->param = reply_param;
|
||||
|
||||
/* pairs with qeth_put_cmd(): */
|
||||
qeth_get_reply(reply);
|
||||
iob->reply = reply;
|
||||
|
||||
timeout = wait_event_interruptible_timeout(card->wait_q,
|
||||
qeth_trylock_channel(channel),
|
||||
timeout);
|
||||
if (timeout <= 0) {
|
||||
qeth_put_reply(reply);
|
||||
qeth_put_cmd(iob);
|
||||
return (timeout == -ERESTARTSYS) ? -EINTR : -ETIME;
|
||||
}
|
||||
@ -1740,7 +1706,7 @@ static int qeth_send_control_data(struct qeth_card *card,
|
||||
iob->finalize(card, iob);
|
||||
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: */
|
||||
qeth_get_cmd(iob);
|
||||
@ -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",
|
||||
CARD_DEVID(card), rc);
|
||||
QETH_CARD_TEXT_(card, 2, " err%d", rc);
|
||||
qeth_dequeue_reply(card, reply);
|
||||
qeth_dequeue_cmd(card, iob);
|
||||
qeth_put_cmd(iob);
|
||||
atomic_set(&channel->irq_pending, 0);
|
||||
wake_up(&card->wait_q);
|
||||
goto out;
|
||||
}
|
||||
|
||||
timeout = wait_for_completion_interruptible_timeout(&reply->received,
|
||||
timeout = wait_for_completion_interruptible_timeout(&iob->done,
|
||||
timeout);
|
||||
if (timeout <= 0)
|
||||
rc = (timeout == -ERESTARTSYS) ? -EINTR : -ETIME;
|
||||
|
||||
qeth_dequeue_reply(card, reply);
|
||||
qeth_dequeue_cmd(card, iob);
|
||||
|
||||
if (reply_cb) {
|
||||
/* Wait until the callback for a late reply has completed: */
|
||||
spin_lock_irq(&reply->lock);
|
||||
spin_lock_irq(&iob->lock);
|
||||
if (rc)
|
||||
/* Zap any callback that's still pending: */
|
||||
reply->rc = rc;
|
||||
spin_unlock_irq(&reply->lock);
|
||||
iob->rc = rc;
|
||||
spin_unlock_irq(&iob->lock);
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
rc = reply->rc;
|
||||
rc = iob->rc;
|
||||
|
||||
out:
|
||||
qeth_put_reply(reply);
|
||||
qeth_put_cmd(iob);
|
||||
return rc;
|
||||
}
|
||||
@ -1822,7 +1787,7 @@ static void qeth_read_conf_data_cb(struct qeth_card *card,
|
||||
nd->nd3.model[2] <= 0xF4;
|
||||
|
||||
out:
|
||||
qeth_notify_reply(iob->reply, rc);
|
||||
qeth_notify_cmd(iob, rc);
|
||||
qeth_put_cmd(iob);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
out:
|
||||
qeth_notify_reply(iob->reply, rc);
|
||||
qeth_notify_cmd(iob, rc);
|
||||
qeth_put_cmd(iob);
|
||||
}
|
||||
|
||||
@ -1942,7 +1907,7 @@ static void qeth_idx_activate_write_channel_cb(struct qeth_card *card,
|
||||
}
|
||||
|
||||
out:
|
||||
qeth_notify_reply(iob->reply, rc);
|
||||
qeth_notify_cmd(iob, rc);
|
||||
qeth_put_cmd(iob);
|
||||
}
|
||||
|
||||
@ -2675,8 +2640,7 @@ static void qeth_ipa_finalize_cmd(struct qeth_card *card,
|
||||
qeth_mpc_finalize_cmd(card, iob);
|
||||
|
||||
/* override with IPA-specific values: */
|
||||
__ipa_cmd(iob)->hdr.seqno = card->seqno.ipa;
|
||||
iob->reply->seqno = card->seqno.ipa++;
|
||||
__ipa_cmd(iob)->hdr.seqno = card->seqno.ipa++;
|
||||
}
|
||||
|
||||
void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
|
||||
|
@ -27,7 +27,6 @@ extern unsigned char IPA_PDU_HEADER[];
|
||||
|
||||
#define QETH_TIMEOUT (10 * HZ)
|
||||
#define QETH_IPA_TIMEOUT (45 * HZ)
|
||||
#define QETH_IDX_COMMAND_SEQNO 0xffff0000
|
||||
|
||||
#define QETH_CLEAR_CHANNEL_PARM -10
|
||||
#define QETH_HALT_CHANNEL_PARM -11
|
||||
|
@ -1003,7 +1003,7 @@ static void qeth_osn_assist_cb(struct qeth_card *card,
|
||||
struct qeth_cmd_buffer *iob,
|
||||
unsigned int data_length)
|
||||
{
|
||||
qeth_notify_reply(iob->reply, 0);
|
||||
qeth_notify_cmd(iob, 0);
|
||||
qeth_put_cmd(iob);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user