Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+12 −14
Original line number Original line Diff line number Diff line
@@ -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 {
	__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,
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);
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,
+45 −81
Original line number Original line Diff line number Diff line
@@ -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,


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,
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,


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,
		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,
				    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,


	/* 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,
	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,
				  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,
		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,
		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,
				 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,
	       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,
	}
	}


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,
	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,
+0 −1
Original line number Original line Diff line number Diff line
@@ -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
+1 −1
Original line number Original line Diff line number Diff line
@@ -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);
}
}