Commit 66fb291b authored by Julian Wiedmann's avatar Julian Wiedmann Committed by Greg Kroah-Hartman

s390/qeth: uninstall IRQ handler on device removal

[ Upstream commit 121ca39a ]

When setting up, qeth installs its IRQ handler on the ccw devices. But
the IRQ handler is not cleared on removal - so even after qeth yields
control of the ccw devices, spurious interrupts would still be presented
to us.

Make (de-)installation of the IRQ handler part of the ccw channel
setup/removal helpers, and while at it also add the appropriate locking.
Shift around qeth_setup_channel() to avoid a forward declaration for
qeth_irq().
Signed-off-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent ccc1e600
...@@ -901,44 +901,6 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel, ...@@ -901,44 +901,6 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel,
qeth_release_buffer(channel, iob); qeth_release_buffer(channel, iob);
} }
static int qeth_setup_channel(struct qeth_channel *channel, bool alloc_buffers)
{
int cnt;
QETH_DBF_TEXT(SETUP, 2, "setupch");
channel->ccw = kmalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
if (!channel->ccw)
return -ENOMEM;
channel->state = CH_STATE_DOWN;
atomic_set(&channel->irq_pending, 0);
init_waitqueue_head(&channel->wait_q);
if (!alloc_buffers)
return 0;
for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) {
channel->iob[cnt].data =
kzalloc(QETH_BUFSIZE, GFP_DMA|GFP_KERNEL);
if (channel->iob[cnt].data == NULL)
break;
channel->iob[cnt].state = BUF_STATE_FREE;
channel->iob[cnt].channel = channel;
channel->iob[cnt].callback = qeth_send_control_data_cb;
channel->iob[cnt].rc = 0;
}
if (cnt < QETH_CMD_BUFFER_NO) {
kfree(channel->ccw);
while (cnt-- > 0)
kfree(channel->iob[cnt].data);
return -ENOMEM;
}
channel->io_buf_no = 0;
spin_lock_init(&channel->iob_lock);
return 0;
}
static int qeth_set_thread_start_bit(struct qeth_card *card, static int qeth_set_thread_start_bit(struct qeth_card *card,
unsigned long thread) unsigned long thread)
{ {
...@@ -1339,14 +1301,61 @@ static void qeth_free_buffer_pool(struct qeth_card *card) ...@@ -1339,14 +1301,61 @@ static void qeth_free_buffer_pool(struct qeth_card *card)
static void qeth_clean_channel(struct qeth_channel *channel) static void qeth_clean_channel(struct qeth_channel *channel)
{ {
struct ccw_device *cdev = channel->ccwdev;
int cnt; int cnt;
QETH_DBF_TEXT(SETUP, 2, "freech"); QETH_DBF_TEXT(SETUP, 2, "freech");
spin_lock_irq(get_ccwdev_lock(cdev));
cdev->handler = NULL;
spin_unlock_irq(get_ccwdev_lock(cdev));
for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++)
kfree(channel->iob[cnt].data); kfree(channel->iob[cnt].data);
kfree(channel->ccw); kfree(channel->ccw);
} }
static int qeth_setup_channel(struct qeth_channel *channel, bool alloc_buffers)
{
struct ccw_device *cdev = channel->ccwdev;
int cnt;
QETH_DBF_TEXT(SETUP, 2, "setupch");
channel->ccw = kmalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
if (!channel->ccw)
return -ENOMEM;
channel->state = CH_STATE_DOWN;
atomic_set(&channel->irq_pending, 0);
init_waitqueue_head(&channel->wait_q);
spin_lock_irq(get_ccwdev_lock(cdev));
cdev->handler = qeth_irq;
spin_unlock_irq(get_ccwdev_lock(cdev));
if (!alloc_buffers)
return 0;
for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) {
channel->iob[cnt].data =
kzalloc(QETH_BUFSIZE, GFP_DMA|GFP_KERNEL);
if (channel->iob[cnt].data == NULL)
break;
channel->iob[cnt].state = BUF_STATE_FREE;
channel->iob[cnt].channel = channel;
channel->iob[cnt].callback = qeth_send_control_data_cb;
channel->iob[cnt].rc = 0;
}
if (cnt < QETH_CMD_BUFFER_NO) {
qeth_clean_channel(channel);
return -ENOMEM;
}
channel->io_buf_no = 0;
spin_lock_init(&channel->iob_lock);
return 0;
}
static void qeth_set_single_write_queues(struct qeth_card *card) static void qeth_set_single_write_queues(struct qeth_card *card)
{ {
if ((atomic_read(&card->qdio.state) != QETH_QDIO_UNINITIALIZED) && if ((atomic_read(&card->qdio.state) != QETH_QDIO_UNINITIALIZED) &&
...@@ -1498,7 +1507,7 @@ static void qeth_core_sl_print(struct seq_file *m, struct service_level *slr) ...@@ -1498,7 +1507,7 @@ static void qeth_core_sl_print(struct seq_file *m, struct service_level *slr)
CARD_BUS_ID(card), card->info.mcl_level); CARD_BUS_ID(card), card->info.mcl_level);
} }
static struct qeth_card *qeth_alloc_card(void) static struct qeth_card *qeth_alloc_card(struct ccwgroup_device *gdev)
{ {
struct qeth_card *card; struct qeth_card *card;
...@@ -1507,6 +1516,11 @@ static struct qeth_card *qeth_alloc_card(void) ...@@ -1507,6 +1516,11 @@ static struct qeth_card *qeth_alloc_card(void)
if (!card) if (!card)
goto out; goto out;
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
card->gdev = gdev;
CARD_RDEV(card) = gdev->cdev[0];
CARD_WDEV(card) = gdev->cdev[1];
CARD_DDEV(card) = gdev->cdev[2];
if (qeth_setup_channel(&card->read, true)) if (qeth_setup_channel(&card->read, true))
goto out_ip; goto out_ip;
if (qeth_setup_channel(&card->write, true)) if (qeth_setup_channel(&card->write, true))
...@@ -5745,7 +5759,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) ...@@ -5745,7 +5759,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
QETH_DBF_TEXT_(SETUP, 2, "%s", dev_name(&gdev->dev)); QETH_DBF_TEXT_(SETUP, 2, "%s", dev_name(&gdev->dev));
card = qeth_alloc_card(); card = qeth_alloc_card(gdev);
if (!card) { if (!card) {
QETH_DBF_TEXT_(SETUP, 2, "1err%d", -ENOMEM); QETH_DBF_TEXT_(SETUP, 2, "1err%d", -ENOMEM);
rc = -ENOMEM; rc = -ENOMEM;
...@@ -5761,15 +5775,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) ...@@ -5761,15 +5775,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
goto err_card; goto err_card;
} }
card->read.ccwdev = gdev->cdev[0];
card->write.ccwdev = gdev->cdev[1];
card->data.ccwdev = gdev->cdev[2];
dev_set_drvdata(&gdev->dev, card); dev_set_drvdata(&gdev->dev, card);
card->gdev = gdev;
gdev->cdev[0]->handler = qeth_irq;
gdev->cdev[1]->handler = qeth_irq;
gdev->cdev[2]->handler = qeth_irq;
qeth_setup_card(card); qeth_setup_card(card);
rc = qeth_update_from_chp_desc(card); rc = qeth_update_from_chp_desc(card);
if (rc) if (rc)
......
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