s390: qeth driver fixes: atomic context fixups
- qeth device functions were not callable in atomic context due to usage of wait_event_xxx operations in qeth. "schedule while atomic" message appeared and kernel dumped when removing slave from bond device. Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
parent
2d36c16eb0
commit
ee2db684b4
|
@ -710,7 +710,7 @@ struct qeth_reply {
|
||||||
int (*callback)(struct qeth_card *,struct qeth_reply *,unsigned long);
|
int (*callback)(struct qeth_card *,struct qeth_reply *,unsigned long);
|
||||||
u32 seqno;
|
u32 seqno;
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
int received;
|
atomic_t received;
|
||||||
int rc;
|
int rc;
|
||||||
void *param;
|
void *param;
|
||||||
struct qeth_card *card;
|
struct qeth_card *card;
|
||||||
|
|
|
@ -471,7 +471,7 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
|
||||||
channel->state == CH_STATE_UP)
|
channel->state == CH_STATE_UP)
|
||||||
qeth_issue_next_read(card);
|
qeth_issue_next_read(card);
|
||||||
|
|
||||||
tasklet_schedule(&channel->irq_tasklet);
|
qeth_irq_tasklet((unsigned long)channel);
|
||||||
return;
|
return;
|
||||||
out:
|
out:
|
||||||
wake_up(&card->wait_q);
|
wake_up(&card->wait_q);
|
||||||
|
@ -950,40 +950,6 @@ qeth_do_run_thread(struct qeth_card *card, unsigned long thread)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
qeth_register_ip_addresses(void *ptr)
|
|
||||||
{
|
|
||||||
struct qeth_card *card;
|
|
||||||
|
|
||||||
card = (struct qeth_card *) ptr;
|
|
||||||
daemonize("qeth_reg_ip");
|
|
||||||
QETH_DBF_TEXT(trace,4,"regipth1");
|
|
||||||
if (!qeth_do_run_thread(card, QETH_SET_IP_THREAD))
|
|
||||||
return 0;
|
|
||||||
QETH_DBF_TEXT(trace,4,"regipth2");
|
|
||||||
qeth_set_ip_addr_list(card);
|
|
||||||
qeth_clear_thread_running_bit(card, QETH_SET_IP_THREAD);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Drive the SET_PROMISC_MODE thread
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
qeth_set_promisc_mode(void *ptr)
|
|
||||||
{
|
|
||||||
struct qeth_card *card = (struct qeth_card *) ptr;
|
|
||||||
|
|
||||||
daemonize("qeth_setprm");
|
|
||||||
QETH_DBF_TEXT(trace,4,"setprm1");
|
|
||||||
if (!qeth_do_run_thread(card, QETH_SET_PROMISC_MODE_THREAD))
|
|
||||||
return 0;
|
|
||||||
QETH_DBF_TEXT(trace,4,"setprm2");
|
|
||||||
qeth_setadp_promisc_mode(card);
|
|
||||||
qeth_clear_thread_running_bit(card, QETH_SET_PROMISC_MODE_THREAD);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qeth_recover(void *ptr)
|
qeth_recover(void *ptr)
|
||||||
{
|
{
|
||||||
|
@ -1047,11 +1013,6 @@ qeth_start_kernel_thread(struct work_struct *work)
|
||||||
if (card->read.state != CH_STATE_UP &&
|
if (card->read.state != CH_STATE_UP &&
|
||||||
card->write.state != CH_STATE_UP)
|
card->write.state != CH_STATE_UP)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (qeth_do_start_thread(card, QETH_SET_IP_THREAD))
|
|
||||||
kernel_thread(qeth_register_ip_addresses, (void *)card,SIGCHLD);
|
|
||||||
if (qeth_do_start_thread(card, QETH_SET_PROMISC_MODE_THREAD))
|
|
||||||
kernel_thread(qeth_set_promisc_mode, (void *)card, SIGCHLD);
|
|
||||||
if (qeth_do_start_thread(card, QETH_RECOVER_THREAD))
|
if (qeth_do_start_thread(card, QETH_RECOVER_THREAD))
|
||||||
kernel_thread(qeth_recover, (void *) card, SIGCHLD);
|
kernel_thread(qeth_recover, (void *) card, SIGCHLD);
|
||||||
}
|
}
|
||||||
|
@ -1613,8 +1574,6 @@ qeth_issue_next_read(struct qeth_card *card)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE);
|
qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE);
|
||||||
wait_event(card->wait_q,
|
|
||||||
atomic_cmpxchg(&card->read.irq_pending, 0, 1) == 0);
|
|
||||||
QETH_DBF_TEXT(trace, 6, "noirqpnd");
|
QETH_DBF_TEXT(trace, 6, "noirqpnd");
|
||||||
rc = ccw_device_start(card->read.ccwdev, &card->read.ccw,
|
rc = ccw_device_start(card->read.ccwdev, &card->read.ccw,
|
||||||
(addr_t) iob, 0, 0);
|
(addr_t) iob, 0, 0);
|
||||||
|
@ -1635,6 +1594,7 @@ qeth_alloc_reply(struct qeth_card *card)
|
||||||
reply = kzalloc(sizeof(struct qeth_reply), GFP_ATOMIC);
|
reply = kzalloc(sizeof(struct qeth_reply), GFP_ATOMIC);
|
||||||
if (reply){
|
if (reply){
|
||||||
atomic_set(&reply->refcnt, 1);
|
atomic_set(&reply->refcnt, 1);
|
||||||
|
atomic_set(&reply->received, 0);
|
||||||
reply->card = card;
|
reply->card = card;
|
||||||
};
|
};
|
||||||
return reply;
|
return reply;
|
||||||
|
@ -1655,31 +1615,6 @@ qeth_put_reply(struct qeth_reply *reply)
|
||||||
kfree(reply);
|
kfree(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
qeth_cmd_timeout(unsigned long data)
|
|
||||||
{
|
|
||||||
struct qeth_reply *reply, *list_reply, *r;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
reply = (struct qeth_reply *) data;
|
|
||||||
spin_lock_irqsave(&reply->card->lock, flags);
|
|
||||||
list_for_each_entry_safe(list_reply, r,
|
|
||||||
&reply->card->cmd_waiter_list, list) {
|
|
||||||
if (reply == list_reply){
|
|
||||||
qeth_get_reply(reply);
|
|
||||||
list_del_init(&reply->list);
|
|
||||||
spin_unlock_irqrestore(&reply->card->lock, flags);
|
|
||||||
reply->rc = -ETIME;
|
|
||||||
reply->received = 1;
|
|
||||||
wake_up(&reply->wait_q);
|
|
||||||
qeth_put_reply(reply);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&reply->card->lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct qeth_ipa_cmd *
|
static struct qeth_ipa_cmd *
|
||||||
qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
|
qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
|
||||||
{
|
{
|
||||||
|
@ -1745,7 +1680,7 @@ qeth_clear_ipacmd_list(struct qeth_card *card)
|
||||||
list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) {
|
list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) {
|
||||||
qeth_get_reply(reply);
|
qeth_get_reply(reply);
|
||||||
reply->rc = -EIO;
|
reply->rc = -EIO;
|
||||||
reply->received = 1;
|
atomic_inc(&reply->received);
|
||||||
list_del_init(&reply->list);
|
list_del_init(&reply->list);
|
||||||
wake_up(&reply->wait_q);
|
wake_up(&reply->wait_q);
|
||||||
qeth_put_reply(reply);
|
qeth_put_reply(reply);
|
||||||
|
@ -1814,7 +1749,7 @@ qeth_send_control_data_cb(struct qeth_channel *channel,
|
||||||
&card->cmd_waiter_list);
|
&card->cmd_waiter_list);
|
||||||
spin_unlock_irqrestore(&card->lock, flags);
|
spin_unlock_irqrestore(&card->lock, flags);
|
||||||
} else {
|
} else {
|
||||||
reply->received = 1;
|
atomic_inc(&reply->received);
|
||||||
wake_up(&reply->wait_q);
|
wake_up(&reply->wait_q);
|
||||||
}
|
}
|
||||||
qeth_put_reply(reply);
|
qeth_put_reply(reply);
|
||||||
|
@ -1858,7 +1793,7 @@ qeth_send_control_data(struct qeth_card *card, int len,
|
||||||
int rc;
|
int rc;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct qeth_reply *reply = NULL;
|
struct qeth_reply *reply = NULL;
|
||||||
struct timer_list timer;
|
unsigned long timeout;
|
||||||
|
|
||||||
QETH_DBF_TEXT(trace, 2, "sendctl");
|
QETH_DBF_TEXT(trace, 2, "sendctl");
|
||||||
|
|
||||||
|
@ -1873,21 +1808,20 @@ qeth_send_control_data(struct qeth_card *card, int len,
|
||||||
reply->seqno = QETH_IDX_COMMAND_SEQNO;
|
reply->seqno = QETH_IDX_COMMAND_SEQNO;
|
||||||
else
|
else
|
||||||
reply->seqno = card->seqno.ipa++;
|
reply->seqno = card->seqno.ipa++;
|
||||||
init_timer(&timer);
|
|
||||||
timer.function = qeth_cmd_timeout;
|
|
||||||
timer.data = (unsigned long) reply;
|
|
||||||
init_waitqueue_head(&reply->wait_q);
|
init_waitqueue_head(&reply->wait_q);
|
||||||
spin_lock_irqsave(&card->lock, flags);
|
spin_lock_irqsave(&card->lock, flags);
|
||||||
list_add_tail(&reply->list, &card->cmd_waiter_list);
|
list_add_tail(&reply->list, &card->cmd_waiter_list);
|
||||||
spin_unlock_irqrestore(&card->lock, flags);
|
spin_unlock_irqrestore(&card->lock, flags);
|
||||||
QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN);
|
QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN);
|
||||||
wait_event(card->wait_q,
|
|
||||||
atomic_cmpxchg(&card->write.irq_pending, 0, 1) == 0);
|
while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ;
|
||||||
qeth_prepare_control_data(card, len, iob);
|
qeth_prepare_control_data(card, len, iob);
|
||||||
|
|
||||||
if (IS_IPA(iob->data))
|
if (IS_IPA(iob->data))
|
||||||
timer.expires = jiffies + QETH_IPA_TIMEOUT;
|
timeout = jiffies + QETH_IPA_TIMEOUT;
|
||||||
else
|
else
|
||||||
timer.expires = jiffies + QETH_TIMEOUT;
|
timeout = jiffies + QETH_TIMEOUT;
|
||||||
|
|
||||||
QETH_DBF_TEXT(trace, 6, "noirqpnd");
|
QETH_DBF_TEXT(trace, 6, "noirqpnd");
|
||||||
spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
|
spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
|
||||||
rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
|
rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
|
||||||
|
@ -1906,9 +1840,16 @@ qeth_send_control_data(struct qeth_card *card, int len,
|
||||||
wake_up(&card->wait_q);
|
wake_up(&card->wait_q);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
add_timer(&timer);
|
while (!atomic_read(&reply->received)) {
|
||||||
wait_event(reply->wait_q, reply->received);
|
if (time_after(jiffies, timeout)) {
|
||||||
del_timer_sync(&timer);
|
spin_lock_irqsave(&reply->card->lock, flags);
|
||||||
|
list_del_init(&reply->list);
|
||||||
|
spin_unlock_irqrestore(&reply->card->lock, flags);
|
||||||
|
reply->rc = -ETIME;
|
||||||
|
atomic_inc(&reply->received);
|
||||||
|
wake_up(&reply->wait_q);
|
||||||
|
}
|
||||||
|
};
|
||||||
rc = reply->rc;
|
rc = reply->rc;
|
||||||
qeth_put_reply(reply);
|
qeth_put_reply(reply);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -5541,12 +5482,10 @@ qeth_set_multicast_list(struct net_device *dev)
|
||||||
qeth_add_multicast_ipv6(card);
|
qeth_add_multicast_ipv6(card);
|
||||||
#endif
|
#endif
|
||||||
out:
|
out:
|
||||||
if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
|
qeth_set_ip_addr_list(card);
|
||||||
schedule_work(&card->kernel_thread_starter);
|
|
||||||
if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
|
if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
|
||||||
return;
|
return;
|
||||||
if (qeth_set_thread_start_bit(card, QETH_SET_PROMISC_MODE_THREAD)==0)
|
qeth_setadp_promisc_mode(card);
|
||||||
schedule_work(&card->kernel_thread_starter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -8271,8 +8210,7 @@ qeth_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
|
||||||
}
|
}
|
||||||
if (!qeth_add_ip(card, ipaddr))
|
if (!qeth_add_ip(card, ipaddr))
|
||||||
kfree(ipaddr);
|
kfree(ipaddr);
|
||||||
if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
|
qeth_set_ip_addr_list(card);
|
||||||
schedule_work(&card->kernel_thread_starter);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8300,8 +8238,7 @@ qeth_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
|
||||||
return;
|
return;
|
||||||
if (!qeth_delete_ip(card, ipaddr))
|
if (!qeth_delete_ip(card, ipaddr))
|
||||||
kfree(ipaddr);
|
kfree(ipaddr);
|
||||||
if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
|
qeth_set_ip_addr_list(card);
|
||||||
schedule_work(&card->kernel_thread_starter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8344,8 +8281,7 @@ qeth_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
|
||||||
}
|
}
|
||||||
if (!qeth_add_ip(card, ipaddr))
|
if (!qeth_add_ip(card, ipaddr))
|
||||||
kfree(ipaddr);
|
kfree(ipaddr);
|
||||||
if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
|
qeth_set_ip_addr_list(card);
|
||||||
schedule_work(&card->kernel_thread_starter);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8373,8 +8309,7 @@ qeth_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
|
||||||
return;
|
return;
|
||||||
if (!qeth_delete_ip(card, ipaddr))
|
if (!qeth_delete_ip(card, ipaddr))
|
||||||
kfree(ipaddr);
|
kfree(ipaddr);
|
||||||
if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
|
qeth_set_ip_addr_list(card);
|
||||||
schedule_work(&card->kernel_thread_starter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8416,8 +8351,7 @@ qeth_ip_event(struct notifier_block *this,
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
|
qeth_set_ip_addr_list(card);
|
||||||
schedule_work(&card->kernel_thread_starter);
|
|
||||||
out:
|
out:
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
}
|
}
|
||||||
|
@ -8469,8 +8403,7 @@ qeth_ip6_event(struct notifier_block *this,
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
|
qeth_set_ip_addr_list(card);
|
||||||
schedule_work(&card->kernel_thread_starter);
|
|
||||||
out:
|
out:
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue