Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *    Copyright IBM Corp. 2007
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     /* Setup SCCB for Control-Program Identification */
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);