Commit df6f508c authored by Harald Freudenberger's avatar Harald Freudenberger Committed by Vasily Gorbik
Browse files

s390/ap/zcrypt: notify userspace with online, config and mode info



This patch brings 3 reworked/new uevent changes:
* All AP uevents caused by an ap card or queue device now carry an
  additional uevent env value MODE=<accel|cca|ep11>. Here is an
  example:
    KERNEL[1267.301292] add	 /devices/ap/card0a (ap)
    ACTION=add
    DEVPATH=/devices/ap/card0a
    SUBSYSTEM=ap
    DEVTYPE=ap_card
    DEV_TYPE=000D
    MODALIAS=ap:t0D
    MODE=ep11			 <- this is new
    SEQNUM=1095
  This is true for bind, unbind, add, remove, and change uevents
  related to ap card or ap queue devices.
* On a change of the soft online attribute on a zcrypt queue or card
  device a new CHANGE uevent is sent with an env value ONLINE=<0|1>.
  Example uevent:
    KERNEL[613.067531] change	/devices/ap/card09/09.0011 (ap)
    ACTION=change
    DEVPATH=/devices/ap/card09/09.0011
    SUBSYSTEM=ap
    ONLINE=0			<- this is new
    DEVTYPE=ap_queue
    DRIVER=cex4queue
    MODE=cca
    SEQNUM=1070
- On a change of the config state of an zcrypt card device a new
  CHANGE uevent is sent with an env value CONFIG=<0|1>.
  Example uevent:
    KERNEL[876.258680] change	/devices/ap/card09 (ap)
    ACTION=change
    DEVPATH=/devices/ap/card09
    SUBSYSTEM=ap
    CONFIG=0			<- this is new
    DEVTYPE=ap_card
    DRIVER=cex4card
    DEV_TYPE=000D
    MODALIAS=ap:t0D
    MODE=cca
    SEQNUM=1073
  Setting a card config on/off causes the dependent queue devices to
  follow the config state change and thus uevents informing about the
  config state change for the queue devices are also emitted.

Signed-off-by: default avatarHarald Freudenberger <freude@linux.ibm.com>
Reviewed-by: default avatarIngo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent 113af8e6
Loading
Loading
Loading
Loading
+60 −10
Original line number Diff line number Diff line
@@ -587,23 +587,48 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv)
 */
static int ap_uevent(struct device *dev, struct kobj_uevent_env *env)
{
	int rc;
	int rc = 0;
	struct ap_device *ap_dev = to_ap_dev(dev);

	/* Uevents from ap bus core don't need extensions to the env */
	if (dev == ap_root_device)
		return 0;

	if (is_card_dev(dev)) {
		struct ap_card *ac = to_ap_card(&ap_dev->device);

		/* Set up DEV_TYPE environment variable. */
		rc = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
		if (rc)
			return rc;

		/* Add MODALIAS= */
		rc = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
		if (rc)
			return rc;

		/* Add MODE=<accel|cca|ep11> */
		if (ap_test_bit(&ac->functions, AP_FUNC_ACCEL))
			rc = add_uevent_var(env, "MODE=accel");
		else if (ap_test_bit(&ac->functions, AP_FUNC_COPRO))
			rc = add_uevent_var(env, "MODE=cca");
		else if (ap_test_bit(&ac->functions, AP_FUNC_EP11))
			rc = add_uevent_var(env, "MODE=ep11");
		if (rc)
			return rc;
	} else {
		struct ap_queue *aq = to_ap_queue(&ap_dev->device);

		/* Add MODE=<accel|cca|ep11> */
		if (ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL))
			rc = add_uevent_var(env, "MODE=accel");
		else if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO))
			rc = add_uevent_var(env, "MODE=cca");
		else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11))
			rc = add_uevent_var(env, "MODE=ep11");
		if (rc)
			return rc;
	}

	return 0;
}

@@ -624,6 +649,28 @@ static void ap_send_bindings_complete_uevent(void)
	kobject_uevent_env(&ap_root_device->kobj, KOBJ_CHANGE, envp);
}

void ap_send_config_uevent(struct ap_device *ap_dev, bool cfg)
{
	char buf[16];
	char *envp[] = { buf, NULL };

	snprintf(buf, sizeof(buf), "CONFIG=%d", cfg ? 1 : 0);

	kobject_uevent_env(&ap_dev->device.kobj, KOBJ_CHANGE, envp);
}
EXPORT_SYMBOL(ap_send_config_uevent);

void ap_send_online_uevent(struct ap_device *ap_dev, int online)
{
	char buf[16];
	char *envp[] = { buf, NULL };

	snprintf(buf, sizeof(buf), "ONLINE=%d", online ? 1 : 0);

	kobject_uevent_env(&ap_dev->device.kobj, KOBJ_CHANGE, envp);
}
EXPORT_SYMBOL(ap_send_online_uevent);

/*
 * calc # of bound APQNs
 */
@@ -1546,6 +1593,7 @@ static inline void ap_scan_domains(struct ap_card *ac)
			spin_unlock_bh(&aq->lock);
			AP_DBF_INFO("%s(%d,%d) queue device config off\n",
				    __func__, ac->id, dom);
			ap_send_config_uevent(&aq->ap_dev, aq->config);
			/* 'receive' pending messages with -EAGAIN */
			ap_flush_queue(aq);
			goto put_dev_and_continue;
@@ -1560,6 +1608,7 @@ static inline void ap_scan_domains(struct ap_card *ac)
			spin_unlock_bh(&aq->lock);
			AP_DBF_INFO("%s(%d,%d) queue device config on\n",
				    __func__, ac->id, dom);
			ap_send_config_uevent(&aq->ap_dev, aq->config);
			goto put_dev_and_continue;
		}
		/* handle other error states */
@@ -1669,12 +1718,13 @@ static inline void ap_scan_adapter(int ap)
				ac->config = false;
				AP_DBF_INFO("%s(%d) card device config off\n",
					    __func__, ap);

				ap_send_config_uevent(&ac->ap_dev, ac->config);
			}
			if (!decfg && !ac->config) {
				ac->config = true;
				AP_DBF_INFO("%s(%d) card device config on\n",
					    __func__, ap);
				ap_send_config_uevent(&ac->ap_dev, ac->config);
			}
		}
	}
+3 −0
Original line number Diff line number Diff line
@@ -362,4 +362,7 @@ int ap_parse_mask_str(const char *str,
 */
int ap_wait_init_apqn_bindings_complete(unsigned long timeout);

void ap_send_config_uevent(struct ap_device *ap_dev, bool cfg);
void ap_send_online_uevent(struct ap_device *ap_dev, int online);

#endif /* _AP_BUS_H_ */
+2 −0
Original line number Diff line number Diff line
@@ -167,6 +167,8 @@ static ssize_t config_store(struct device *dev,

	ac->config = cfg ? true : false;

	ap_send_config_uevent(&ac->ap_dev, ac->config);

	return count;
}

+1 −1
Original line number Diff line number Diff line
@@ -145,7 +145,7 @@ void zcrypt_queue_get(struct zcrypt_queue *);
int zcrypt_queue_put(struct zcrypt_queue *);
int zcrypt_queue_register(struct zcrypt_queue *);
void zcrypt_queue_unregister(struct zcrypt_queue *);
void zcrypt_queue_force_online(struct zcrypt_queue *, int);
bool zcrypt_queue_force_online(struct zcrypt_queue *zq, int online);

int zcrypt_rng_device_add(void);
void zcrypt_rng_device_remove(void);
+28 −2
Original line number Diff line number Diff line
@@ -64,7 +64,8 @@ static ssize_t online_store(struct device *dev,
	struct ap_card *ac = to_ap_card(dev);
	struct zcrypt_card *zc = ac->private;
	struct zcrypt_queue *zq;
	int online, id;
	int online, id, i = 0, maxzqs = 0;
	struct zcrypt_queue **zq_uelist = NULL;

	if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
		return -EINVAL;
@@ -77,10 +78,35 @@ static ssize_t online_store(struct device *dev,

	ZCRYPT_DBF(DBF_INFO, "card=%02x online=%d\n", id, online);

	ap_send_online_uevent(&ac->ap_dev, online);

	spin_lock(&zcrypt_list_lock);
	/*
	 * As we are in atomic context here, directly sending uevents
	 * does not work. So collect the zqueues in a dynamic array
	 * and process them after zcrypt_list_lock release. As we get/put
	 * the zqueue objects, we make sure they exist after lock release.
	 */
	list_for_each_entry(zq, &zc->zqueues, list)
		maxzqs++;
	if (maxzqs > 0)
		zq_uelist = kcalloc(maxzqs + 1, sizeof(zq), GFP_ATOMIC);
	list_for_each_entry(zq, &zc->zqueues, list)
		zcrypt_queue_force_online(zq, online);
		if (zcrypt_queue_force_online(zq, online))
			if (zq_uelist) {
				zcrypt_queue_get(zq);
				zq_uelist[i++] = zq;
			}
	spin_unlock(&zcrypt_list_lock);
	if (zq_uelist) {
		for (i = 0; zq_uelist[i]; i++) {
			zq = zq_uelist[i];
			ap_send_online_uevent(&zq->queue->ap_dev, online);
			zcrypt_queue_put(zq);
		}
		kfree(zq_uelist);
	}

	return count;
}

Loading