0001
0002
0003
0004
0005
0006 #define KMSG_COMPONENT "sclp_config"
0007 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
0008
0009 #include <linux/init.h>
0010 #include <linux/errno.h>
0011 #include <linux/cpu.h>
0012 #include <linux/device.h>
0013 #include <linux/workqueue.h>
0014 #include <linux/slab.h>
0015 #include <linux/sysfs.h>
0016 #include <asm/smp.h>
0017
0018 #include "sclp.h"
0019
0020 struct conf_mgm_data {
0021 u8 reserved;
0022 u8 ev_qualifier;
0023 } __attribute__((packed));
0024
0025 #define OFB_DATA_MAX 64
0026
0027 struct sclp_ofb_evbuf {
0028 struct evbuf_header header;
0029 struct conf_mgm_data cm_data;
0030 char ev_data[OFB_DATA_MAX];
0031 } __packed;
0032
0033 struct sclp_ofb_sccb {
0034 struct sccb_header header;
0035 struct sclp_ofb_evbuf ofb_evbuf;
0036 } __packed;
0037
0038 #define EV_QUAL_CPU_CHANGE 1
0039 #define EV_QUAL_CAP_CHANGE 3
0040 #define EV_QUAL_OPEN4BUSINESS 5
0041
0042 static struct work_struct sclp_cpu_capability_work;
0043 static struct work_struct sclp_cpu_change_work;
0044
0045 static void sclp_cpu_capability_notify(struct work_struct *work)
0046 {
0047 int cpu;
0048 struct device *dev;
0049
0050 s390_update_cpu_mhz();
0051 pr_info("CPU capability may have changed\n");
0052 cpus_read_lock();
0053 for_each_online_cpu(cpu) {
0054 dev = get_cpu_device(cpu);
0055 kobject_uevent(&dev->kobj, KOBJ_CHANGE);
0056 }
0057 cpus_read_unlock();
0058 }
0059
0060 static void __ref sclp_cpu_change_notify(struct work_struct *work)
0061 {
0062 lock_device_hotplug();
0063 smp_rescan_cpus();
0064 unlock_device_hotplug();
0065 }
0066
0067 static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
0068 {
0069 struct conf_mgm_data *cdata;
0070
0071 cdata = (struct conf_mgm_data *)(evbuf + 1);
0072 switch (cdata->ev_qualifier) {
0073 case EV_QUAL_CPU_CHANGE:
0074 schedule_work(&sclp_cpu_change_work);
0075 break;
0076 case EV_QUAL_CAP_CHANGE:
0077 schedule_work(&sclp_cpu_capability_work);
0078 break;
0079 }
0080 }
0081
0082 static struct sclp_register sclp_conf_register =
0083 {
0084 #ifdef CONFIG_SCLP_OFB
0085 .send_mask = EVTYP_CONFMGMDATA_MASK,
0086 #endif
0087 .receive_mask = EVTYP_CONFMGMDATA_MASK,
0088 .receiver_fn = sclp_conf_receiver_fn,
0089 };
0090
0091 #ifdef CONFIG_SCLP_OFB
0092 static int sclp_ofb_send_req(char *ev_data, size_t len)
0093 {
0094 static DEFINE_MUTEX(send_mutex);
0095 struct sclp_ofb_sccb *sccb;
0096 int rc, response;
0097
0098 if (len > OFB_DATA_MAX)
0099 return -EINVAL;
0100 sccb = (struct sclp_ofb_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
0101 if (!sccb)
0102 return -ENOMEM;
0103
0104 sccb->header.length = sizeof(struct sclp_ofb_sccb);
0105 sccb->ofb_evbuf.header.length = sizeof(struct sclp_ofb_evbuf);
0106 sccb->ofb_evbuf.header.type = EVTYP_CONFMGMDATA;
0107 sccb->ofb_evbuf.cm_data.ev_qualifier = EV_QUAL_OPEN4BUSINESS;
0108 memcpy(sccb->ofb_evbuf.ev_data, ev_data, len);
0109
0110 if (!(sclp_conf_register.sclp_receive_mask & EVTYP_CONFMGMDATA_MASK))
0111 pr_warn("SCLP receiver did not register to receive "
0112 "Configuration Management Data Events.\n");
0113
0114 mutex_lock(&send_mutex);
0115 rc = sclp_sync_request(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
0116 mutex_unlock(&send_mutex);
0117 if (rc)
0118 goto out;
0119 response = sccb->header.response_code;
0120 if (response != 0x0020) {
0121 pr_err("Open for Business request failed with response code "
0122 "0x%04x\n", response);
0123 rc = -EIO;
0124 }
0125 out:
0126 free_page((unsigned long)sccb);
0127 return rc;
0128 }
0129
0130 static ssize_t sysfs_ofb_data_write(struct file *filp, struct kobject *kobj,
0131 struct bin_attribute *bin_attr,
0132 char *buf, loff_t off, size_t count)
0133 {
0134 int rc;
0135
0136 rc = sclp_ofb_send_req(buf, count);
0137 return rc ?: count;
0138 }
0139
0140 static const struct bin_attribute ofb_bin_attr = {
0141 .attr = {
0142 .name = "event_data",
0143 .mode = S_IWUSR,
0144 },
0145 .write = sysfs_ofb_data_write,
0146 };
0147 #endif
0148
0149 static int __init sclp_ofb_setup(void)
0150 {
0151 #ifdef CONFIG_SCLP_OFB
0152 struct kset *ofb_kset;
0153 int rc;
0154
0155 ofb_kset = kset_create_and_add("ofb", NULL, firmware_kobj);
0156 if (!ofb_kset)
0157 return -ENOMEM;
0158 rc = sysfs_create_bin_file(&ofb_kset->kobj, &ofb_bin_attr);
0159 if (rc) {
0160 kset_unregister(ofb_kset);
0161 return rc;
0162 }
0163 #endif
0164 return 0;
0165 }
0166
0167 static int __init sclp_conf_init(void)
0168 {
0169 int rc;
0170
0171 INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
0172 INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
0173 rc = sclp_register(&sclp_conf_register);
0174 if (rc)
0175 return rc;
0176 return sclp_ofb_setup();
0177 }
0178
0179 __initcall(sclp_conf_init);