Commit ee2db684 authored by Frank Blaschka's avatar Frank Blaschka Committed by Jeff Garzik
Browse files

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: default avatarFrank Pavlic <fpavlic@de.ibm.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 2d36c16e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -710,7 +710,7 @@ struct qeth_reply {
	int (*callback)(struct qeth_card *,struct qeth_reply *,unsigned long);
 	u32 seqno;
	unsigned long offset;
	int received;
	atomic_t received;
	int rc;
	void *param;
	struct qeth_card *card;
+29 −96
Original line number Diff line number Diff line
@@ -471,7 +471,7 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
	    channel->state == CH_STATE_UP)
		qeth_issue_next_read(card);

	tasklet_schedule(&channel->irq_tasklet);
	qeth_irq_tasklet((unsigned long)channel);
	return;
out:
	wake_up(&card->wait_q);
@@ -950,40 +950,6 @@ qeth_do_run_thread(struct qeth_card *card, unsigned long thread)
	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
qeth_recover(void *ptr)
{
@@ -1047,11 +1013,6 @@ qeth_start_kernel_thread(struct work_struct *work)
	if (card->read.state != CH_STATE_UP &&
	    card->write.state != CH_STATE_UP)
		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))
		kernel_thread(qeth_recover, (void *) card, SIGCHLD);
}
@@ -1613,8 +1574,6 @@ qeth_issue_next_read(struct qeth_card *card)
		return -ENOMEM;
	}
	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");
	rc = ccw_device_start(card->read.ccwdev, &card->read.ccw,
			      (addr_t) iob, 0, 0);
@@ -1635,6 +1594,7 @@ qeth_alloc_reply(struct qeth_card *card)
	reply = kzalloc(sizeof(struct qeth_reply), GFP_ATOMIC);
	if (reply){
		atomic_set(&reply->refcnt, 1);
		atomic_set(&reply->received, 0);
		reply->card = card;
	};
	return reply;
@@ -1655,31 +1615,6 @@ qeth_put_reply(struct qeth_reply *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 *
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) {
		qeth_get_reply(reply);
		reply->rc = -EIO;
		reply->received = 1;
		atomic_inc(&reply->received);
		list_del_init(&reply->list);
		wake_up(&reply->wait_q);
		qeth_put_reply(reply);
@@ -1814,7 +1749,7 @@ qeth_send_control_data_cb(struct qeth_channel *channel,
					      &card->cmd_waiter_list);
				spin_unlock_irqrestore(&card->lock, flags);
			} else {
				reply->received = 1;
				atomic_inc(&reply->received);
				wake_up(&reply->wait_q);
			}
			qeth_put_reply(reply);
@@ -1858,7 +1793,7 @@ qeth_send_control_data(struct qeth_card *card, int len,
	int rc;
	unsigned long flags;
	struct qeth_reply *reply = NULL;
	struct timer_list timer;
	unsigned long timeout;

	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;
	else
		reply->seqno = card->seqno.ipa++;
	init_timer(&timer);
	timer.function = qeth_cmd_timeout;
	timer.data = (unsigned long) reply;
	init_waitqueue_head(&reply->wait_q);
	spin_lock_irqsave(&card->lock, flags);
	list_add_tail(&reply->list, &card->cmd_waiter_list);
	spin_unlock_irqrestore(&card->lock, flags);
	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);

	if (IS_IPA(iob->data))
		timer.expires = jiffies + QETH_IPA_TIMEOUT;
		timeout = jiffies + QETH_IPA_TIMEOUT;
	else
		timer.expires = jiffies + QETH_TIMEOUT;
		timeout = jiffies + QETH_TIMEOUT;

	QETH_DBF_TEXT(trace, 6, "noirqpnd");
	spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
	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);
		return rc;
	}
	add_timer(&timer);
	wait_event(reply->wait_q, reply->received);
	del_timer_sync(&timer);
	while (!atomic_read(&reply->received)) {
		if (time_after(jiffies, timeout)) {
			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;
	qeth_put_reply(reply);
	return rc;
@@ -5541,12 +5482,10 @@ qeth_set_multicast_list(struct net_device *dev)
	qeth_add_multicast_ipv6(card);
#endif
out:
 	if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
		schedule_work(&card->kernel_thread_starter);
	qeth_set_ip_addr_list(card);
	if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
		return;
	if (qeth_set_thread_start_bit(card, QETH_SET_PROMISC_MODE_THREAD)==0)
		schedule_work(&card->kernel_thread_starter);
	qeth_setadp_promisc_mode(card);
}

static int
@@ -8271,8 +8210,7 @@ qeth_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
	}
	if (!qeth_add_ip(card, ipaddr))
		kfree(ipaddr);
 	if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
		schedule_work(&card->kernel_thread_starter);
	qeth_set_ip_addr_list(card);
	return rc;
}

@@ -8300,8 +8238,7 @@ qeth_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
		return;
	if (!qeth_delete_ip(card, ipaddr))
		kfree(ipaddr);
 	if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
		schedule_work(&card->kernel_thread_starter);
	qeth_set_ip_addr_list(card);
}

/*
@@ -8344,8 +8281,7 @@ qeth_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
	}
	if (!qeth_add_ip(card, ipaddr))
		kfree(ipaddr);
 	if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
		schedule_work(&card->kernel_thread_starter);
	qeth_set_ip_addr_list(card);
	return 0;
}

@@ -8373,8 +8309,7 @@ qeth_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
		return;
	if (!qeth_delete_ip(card, ipaddr))
		kfree(ipaddr);
 	if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
		schedule_work(&card->kernel_thread_starter);
	qeth_set_ip_addr_list(card);
}

/**
@@ -8416,8 +8351,7 @@ qeth_ip_event(struct notifier_block *this,
	default:
		break;
	}
 	if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
		schedule_work(&card->kernel_thread_starter);
	qeth_set_ip_addr_list(card);
out:
	return NOTIFY_DONE;
}
@@ -8469,8 +8403,7 @@ qeth_ip6_event(struct notifier_block *this,
	default:
		break;
	}
 	if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
		schedule_work(&card->kernel_thread_starter);
	qeth_set_ip_addr_list(card);
out:
	return NOTIFY_DONE;
}