drivers/s390/char/sclp_config.c

Source file repositories/reference/linux-study-clean/drivers/s390/char/sclp_config.c

File Facts

System
Linux kernel
Corpus path
drivers/s390/char/sclp_config.c
Extension
.c
Size
3973 bytes
Lines
173
Domain
Driver Families
Bucket
drivers/s390
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct conf_mgm_data {
	u8 reserved;
	u8 ev_qualifier;
} __attribute__((packed));

#define OFB_DATA_MAX 64

struct sclp_ofb_evbuf {
	struct evbuf_header header;
	struct conf_mgm_data cm_data;
	char ev_data[OFB_DATA_MAX];
} __packed;

struct sclp_ofb_sccb {
	struct sccb_header header;
	struct sclp_ofb_evbuf ofb_evbuf;
} __packed;

#define EV_QUAL_CPU_CHANGE	1
#define EV_QUAL_CAP_CHANGE	3
#define EV_QUAL_OPEN4BUSINESS	5

static struct work_struct sclp_cpu_capability_work;
static struct work_struct sclp_cpu_change_work;

static void sclp_cpu_capability_notify(struct work_struct *work)
{
	int cpu;
	struct device *dev;

	s390_update_cpu_mhz();
	pr_info("CPU capability may have changed\n");
	cpus_read_lock();
	for_each_online_cpu(cpu) {
		dev = get_cpu_device(cpu);
		kobject_uevent(&dev->kobj, KOBJ_CHANGE);
	}
	cpus_read_unlock();
}

static void __ref sclp_cpu_change_notify(struct work_struct *work)
{
	lock_device_hotplug();
	smp_rescan_cpus(false);
	unlock_device_hotplug();
}

static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
{
	struct conf_mgm_data *cdata;

	cdata = (struct conf_mgm_data *)(evbuf + 1);
	switch (cdata->ev_qualifier) {
	case EV_QUAL_CPU_CHANGE:
		schedule_work(&sclp_cpu_change_work);
		break;
	case EV_QUAL_CAP_CHANGE:
		schedule_work(&sclp_cpu_capability_work);
		break;
	}
}

static struct sclp_register sclp_conf_register =
{
	.send_mask    = EVTYP_CONFMGMDATA_MASK,
	.receive_mask = EVTYP_CONFMGMDATA_MASK,
	.receiver_fn  = sclp_conf_receiver_fn,
};

static int sclp_ofb_send_req(char *ev_data, size_t len)
{
	static DEFINE_MUTEX(send_mutex);
	struct sclp_ofb_sccb *sccb;
	int rc, response;

	if (len > OFB_DATA_MAX)
		return -EINVAL;
	sccb = (struct sclp_ofb_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
	if (!sccb)
		return -ENOMEM;
	/* Setup SCCB for Control-Program Identification */
	sccb->header.length = sizeof(struct sclp_ofb_sccb);
	sccb->ofb_evbuf.header.length = sizeof(struct sclp_ofb_evbuf);
	sccb->ofb_evbuf.header.type = EVTYP_CONFMGMDATA;
	sccb->ofb_evbuf.cm_data.ev_qualifier = EV_QUAL_OPEN4BUSINESS;
	memcpy(sccb->ofb_evbuf.ev_data, ev_data, len);

	if (!(sclp_conf_register.sclp_receive_mask & EVTYP_CONFMGMDATA_MASK))
		pr_warn("SCLP receiver did not register to receive "
			"Configuration Management Data Events.\n");

Annotation

Implementation Notes