mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 23:21:31 +00:00
s390/qeth: allocate a single cmd on read channel
We statically allocate 8 cmd buffers on the read channel, when the only IO left that's still using them is the long-running READ. Replace this with a single allocated cmd, that gets restarted whenever the READ completed. This introduces refcounting for allocated cmds, so that the READ cmd can survive the IO completion. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f3b783b1d0
commit
d9b9f40bba
@ -579,6 +579,7 @@ struct qeth_channel;
|
||||
struct qeth_cmd_buffer {
|
||||
enum qeth_cmd_buffer_state state;
|
||||
unsigned int length;
|
||||
refcount_t ref_count;
|
||||
struct qeth_channel *channel;
|
||||
struct qeth_reply *reply;
|
||||
long timeout;
|
||||
@ -588,6 +589,11 @@ struct qeth_cmd_buffer {
|
||||
void (*callback)(struct qeth_card *card, struct qeth_cmd_buffer *iob);
|
||||
};
|
||||
|
||||
static inline void qeth_get_cmd(struct qeth_cmd_buffer *iob)
|
||||
{
|
||||
refcount_inc(&iob->ref_count);
|
||||
}
|
||||
|
||||
static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob)
|
||||
{
|
||||
return (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE);
|
||||
@ -771,6 +777,7 @@ struct qeth_card {
|
||||
enum qeth_card_states state;
|
||||
spinlock_t lock;
|
||||
struct ccwgroup_device *gdev;
|
||||
struct qeth_cmd_buffer *read_cmd;
|
||||
struct qeth_channel read;
|
||||
struct qeth_channel write;
|
||||
struct qeth_channel data;
|
||||
|
@ -496,26 +496,21 @@ static void qeth_setup_ccw(struct ccw1 *ccw, u8 cmd_code, u8 flags, u32 len,
|
||||
|
||||
static int __qeth_issue_next_read(struct qeth_card *card)
|
||||
{
|
||||
struct qeth_channel *channel = &card->read;
|
||||
struct qeth_cmd_buffer *iob;
|
||||
struct ccw1 *ccw;
|
||||
struct qeth_cmd_buffer *iob = card->read_cmd;
|
||||
struct qeth_channel *channel = iob->channel;
|
||||
struct ccw1 *ccw = __ccw_from_cmd(iob);
|
||||
int rc;
|
||||
|
||||
QETH_CARD_TEXT(card, 5, "issnxrd");
|
||||
if (channel->state != CH_STATE_UP)
|
||||
return -EIO;
|
||||
iob = qeth_get_buffer(channel);
|
||||
if (!iob) {
|
||||
dev_warn(&card->gdev->dev, "The qeth device driver "
|
||||
"failed to recover an error on the device\n");
|
||||
QETH_DBF_MESSAGE(2, "issue_next_read on device %x failed: no iob available\n",
|
||||
CARD_DEVID(card));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ccw = __ccw_from_cmd(iob);
|
||||
qeth_setup_ccw(ccw, CCW_CMD_READ, 0, QETH_BUFSIZE, iob->data);
|
||||
memset(iob->data, 0, iob->length);
|
||||
qeth_setup_ccw(ccw, CCW_CMD_READ, 0, iob->length, iob->data);
|
||||
iob->callback = qeth_issue_next_read_cb;
|
||||
/* keep the cmd alive after completion: */
|
||||
qeth_get_cmd(iob);
|
||||
|
||||
QETH_CARD_TEXT(card, 6, "noirqpnd");
|
||||
rc = ccw_device_start(channel->ccwdev, ccw, (addr_t) iob, 0, 0);
|
||||
if (rc) {
|
||||
@ -694,6 +689,16 @@ static int qeth_check_idx_response(struct qeth_card *card,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static 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);
|
||||
}
|
||||
}
|
||||
|
||||
static struct qeth_cmd_buffer *__qeth_get_buffer(struct qeth_channel *channel)
|
||||
{
|
||||
__u8 index;
|
||||
@ -720,10 +725,7 @@ void qeth_release_buffer(struct qeth_cmd_buffer *iob)
|
||||
unsigned long flags;
|
||||
|
||||
if (iob->state == BUF_STATE_MALLOC) {
|
||||
if (iob->reply)
|
||||
qeth_put_reply(iob->reply);
|
||||
kfree(iob->data);
|
||||
kfree(iob);
|
||||
qeth_put_cmd(iob);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -787,6 +789,7 @@ static struct qeth_cmd_buffer *qeth_alloc_cmd(struct qeth_channel *channel,
|
||||
}
|
||||
|
||||
iob->state = BUF_STATE_MALLOC;
|
||||
refcount_set(&iob->ref_count, 1);
|
||||
iob->channel = channel;
|
||||
iob->timeout = timeout;
|
||||
iob->length = length;
|
||||
@ -1445,10 +1448,14 @@ static struct qeth_card *qeth_alloc_card(struct ccwgroup_device *gdev)
|
||||
dev_name(&gdev->dev));
|
||||
if (!card->event_wq)
|
||||
goto out_wq;
|
||||
if (qeth_setup_channel(&card->read, true))
|
||||
goto out_ip;
|
||||
|
||||
card->read_cmd = qeth_alloc_cmd(&card->read, QETH_BUFSIZE, 1, 0);
|
||||
if (!card->read_cmd)
|
||||
goto out_read_cmd;
|
||||
if (qeth_setup_channel(&card->read, false))
|
||||
goto out_read;
|
||||
if (qeth_setup_channel(&card->write, true))
|
||||
goto out_channel;
|
||||
goto out_write;
|
||||
if (qeth_setup_channel(&card->data, false))
|
||||
goto out_data;
|
||||
card->qeth_service_level.seq_print = qeth_core_sl_print;
|
||||
@ -1457,9 +1464,11 @@ static struct qeth_card *qeth_alloc_card(struct ccwgroup_device *gdev)
|
||||
|
||||
out_data:
|
||||
qeth_clean_channel(&card->write);
|
||||
out_channel:
|
||||
out_write:
|
||||
qeth_clean_channel(&card->read);
|
||||
out_ip:
|
||||
out_read:
|
||||
qeth_release_buffer(card->read_cmd);
|
||||
out_read_cmd:
|
||||
destroy_workqueue(card->event_wq);
|
||||
out_wq:
|
||||
dev_set_drvdata(&gdev->dev, NULL);
|
||||
@ -4892,6 +4901,7 @@ static void qeth_core_free_card(struct qeth_card *card)
|
||||
qeth_clean_channel(&card->read);
|
||||
qeth_clean_channel(&card->write);
|
||||
qeth_clean_channel(&card->data);
|
||||
qeth_release_buffer(card->read_cmd);
|
||||
destroy_workqueue(card->event_wq);
|
||||
qeth_free_qdio_queues(card);
|
||||
unregister_service_level(&card->qeth_service_level);
|
||||
|
@ -292,7 +292,6 @@ static void qeth_l2_stop_card(struct qeth_card *card)
|
||||
card->state = CARD_STATE_DOWN;
|
||||
}
|
||||
|
||||
qeth_clear_cmd_buffers(&card->read);
|
||||
qeth_clear_cmd_buffers(&card->write);
|
||||
flush_workqueue(card->event_wq);
|
||||
card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
|
||||
|
@ -1436,7 +1436,6 @@ static void qeth_l3_stop_card(struct qeth_card *card)
|
||||
card->state = CARD_STATE_DOWN;
|
||||
}
|
||||
|
||||
qeth_clear_cmd_buffers(&card->read);
|
||||
qeth_clear_cmd_buffers(&card->write);
|
||||
flush_workqueue(card->event_wq);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user