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

Commit e3850508 authored by Harald Freudenberger's avatar Harald Freudenberger Committed by Martin Schwidefsky
Browse files

s390/zcrypt: Fix blocking queue device after unbind/bind.



When the association between a queue device and the
driver is released via unbind and later re-associated
the queue device was not operational any more. Reason
was a wrong administration of the card/queue lists
within the ap device driver.

This patch introduces revised card/queue list handling
within the ap device driver: when an ap device is
detected it is initial not added to the card/queue list
any more. With driver probe the card device is added to
the card list/the queue device is added to the queue list
within a card. With driver remove the device is removed
from the card/queue list. Additionally there are some
situations within the ap device live where the lists
need update upon card/queue device release (for example
device hot unplug or suspend/resume).

Signed-off-by: default avatarHarald Freudenberger <freude@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 698be5d6
Loading
Loading
Loading
Loading
+24 −14
Original line number Diff line number Diff line
@@ -668,10 +668,28 @@ static int ap_device_probe(struct device *dev)
	struct ap_driver *ap_drv = to_ap_drv(dev->driver);
	int rc;

	/* Add queue/card to list of active queues/cards */
	spin_lock_bh(&ap_list_lock);
	if (is_card_dev(dev))
		list_add(&to_ap_card(dev)->list, &ap_card_list);
	else
		list_add(&to_ap_queue(dev)->list,
			 &to_ap_queue(dev)->card->queues);
	spin_unlock_bh(&ap_list_lock);

	ap_dev->drv = ap_drv;
	rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV;
	if (rc)

	if (rc) {
		spin_lock_bh(&ap_list_lock);
		if (is_card_dev(dev))
			list_del_init(&to_ap_card(dev)->list);
		else
			list_del_init(&to_ap_queue(dev)->list);
		spin_unlock_bh(&ap_list_lock);
		ap_dev->drv = NULL;
	}

	return rc;
}

@@ -680,14 +698,17 @@ static int ap_device_remove(struct device *dev)
	struct ap_device *ap_dev = to_ap_dev(dev);
	struct ap_driver *ap_drv = ap_dev->drv;

	if (ap_drv->remove)
		ap_drv->remove(ap_dev);

	/* Remove queue/card from list of active queues/cards */
	spin_lock_bh(&ap_list_lock);
	if (is_card_dev(dev))
		list_del_init(&to_ap_card(dev)->list);
	else
		list_del_init(&to_ap_queue(dev)->list);
	spin_unlock_bh(&ap_list_lock);
	if (ap_drv->remove)
		ap_drv->remove(ap_dev);

	return 0;
}

@@ -1056,10 +1077,6 @@ static void ap_scan_bus(struct work_struct *unused)
				}
				/* get it and thus adjust reference counter */
				get_device(&ac->ap_dev.device);
				/* Add card device to card list */
				spin_lock_bh(&ap_list_lock);
				list_add(&ac->list, &ap_card_list);
				spin_unlock_bh(&ap_list_lock);
			}
			/* now create the new queue device */
			aq = ap_queue_create(qid, type);
@@ -1070,10 +1087,6 @@ static void ap_scan_bus(struct work_struct *unused)
			aq->ap_dev.device.parent = &ac->ap_dev.device;
			dev_set_name(&aq->ap_dev.device,
				     "%02x.%04x", id, dom);
			/* Add queue device to card queue list */
			spin_lock_bh(&ap_list_lock);
			list_add(&aq->list, &ac->queues);
			spin_unlock_bh(&ap_list_lock);
			/* Start with a device reset */
			spin_lock_bh(&aq->lock);
			ap_wait(ap_sm_event(aq, AP_EVENT_POLL));
@@ -1081,9 +1094,6 @@ static void ap_scan_bus(struct work_struct *unused)
			/* Register device */
			rc = device_register(&aq->ap_dev.device);
			if (rc) {
				spin_lock_bh(&ap_list_lock);
				list_del_init(&aq->list);
				spin_unlock_bh(&ap_list_lock);
				put_device(&aq->ap_dev.device);
				continue;
			}
+8 −1
Original line number Diff line number Diff line
@@ -160,7 +160,14 @@ static struct device_type ap_card_type = {

static void ap_card_device_release(struct device *dev)
{
	kfree(to_ap_card(dev));
	struct ap_card *ac = to_ap_card(dev);

	if (!list_empty(&ac->list)) {
		spin_lock_bh(&ap_list_lock);
		list_del_init(&ac->list);
		spin_unlock_bh(&ap_list_lock);
	}
	kfree(ac);
}

struct ap_card *ap_card_create(int id, int queue_depth, int device_type,
+8 −1
Original line number Diff line number Diff line
@@ -584,7 +584,14 @@ static struct device_type ap_queue_type = {

static void ap_queue_device_release(struct device *dev)
{
	kfree(to_ap_queue(dev));
	struct ap_queue *aq = to_ap_queue(dev);

	if (!list_empty(&aq->list)) {
		spin_lock_bh(&ap_list_lock);
		list_del_init(&aq->list);
		spin_unlock_bh(&ap_list_lock);
	}
	kfree(aq);
}

struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type)