root/drivers/s390/char/sclp_config.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sclp_cpu_capability_notify
  2. sclp_cpu_change_notify
  3. sclp_conf_receiver_fn
  4. sclp_ofb_send_req
  5. sysfs_ofb_data_write
  6. sclp_ofb_setup
  7. sclp_conf_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *    Copyright IBM Corp. 2007
   4  *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
   5  */
   6 
   7 #define KMSG_COMPONENT "sclp_config"
   8 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
   9 
  10 #include <linux/init.h>
  11 #include <linux/errno.h>
  12 #include <linux/cpu.h>
  13 #include <linux/device.h>
  14 #include <linux/workqueue.h>
  15 #include <linux/slab.h>
  16 #include <linux/sysfs.h>
  17 #include <asm/smp.h>
  18 
  19 #include "sclp.h"
  20 
  21 struct conf_mgm_data {
  22         u8 reserved;
  23         u8 ev_qualifier;
  24 } __attribute__((packed));
  25 
  26 #define OFB_DATA_MAX 64
  27 
  28 struct sclp_ofb_evbuf {
  29         struct evbuf_header header;
  30         struct conf_mgm_data cm_data;
  31         char ev_data[OFB_DATA_MAX];
  32 } __packed;
  33 
  34 struct sclp_ofb_sccb {
  35         struct sccb_header header;
  36         struct sclp_ofb_evbuf ofb_evbuf;
  37 } __packed;
  38 
  39 #define EV_QUAL_CPU_CHANGE      1
  40 #define EV_QUAL_CAP_CHANGE      3
  41 #define EV_QUAL_OPEN4BUSINESS   5
  42 
  43 static struct work_struct sclp_cpu_capability_work;
  44 static struct work_struct sclp_cpu_change_work;
  45 
  46 static void sclp_cpu_capability_notify(struct work_struct *work)
  47 {
  48         int cpu;
  49         struct device *dev;
  50 
  51         s390_update_cpu_mhz();
  52         pr_info("CPU capability may have changed\n");
  53         get_online_cpus();
  54         for_each_online_cpu(cpu) {
  55                 dev = get_cpu_device(cpu);
  56                 kobject_uevent(&dev->kobj, KOBJ_CHANGE);
  57         }
  58         put_online_cpus();
  59 }
  60 
  61 static void __ref sclp_cpu_change_notify(struct work_struct *work)
  62 {
  63         lock_device_hotplug();
  64         smp_rescan_cpus();
  65         unlock_device_hotplug();
  66 }
  67 
  68 static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
  69 {
  70         struct conf_mgm_data *cdata;
  71 
  72         cdata = (struct conf_mgm_data *)(evbuf + 1);
  73         switch (cdata->ev_qualifier) {
  74         case EV_QUAL_CPU_CHANGE:
  75                 schedule_work(&sclp_cpu_change_work);
  76                 break;
  77         case EV_QUAL_CAP_CHANGE:
  78                 schedule_work(&sclp_cpu_capability_work);
  79                 break;
  80         }
  81 }
  82 
  83 static struct sclp_register sclp_conf_register =
  84 {
  85 #ifdef CONFIG_SCLP_OFB
  86         .send_mask    = EVTYP_CONFMGMDATA_MASK,
  87 #endif
  88         .receive_mask = EVTYP_CONFMGMDATA_MASK,
  89         .receiver_fn  = sclp_conf_receiver_fn,
  90 };
  91 
  92 #ifdef CONFIG_SCLP_OFB
  93 static int sclp_ofb_send_req(char *ev_data, size_t len)
  94 {
  95         static DEFINE_MUTEX(send_mutex);
  96         struct sclp_ofb_sccb *sccb;
  97         int rc, response;
  98 
  99         if (len > OFB_DATA_MAX)
 100                 return -EINVAL;
 101         sccb = (struct sclp_ofb_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
 102         if (!sccb)
 103                 return -ENOMEM;
 104         /* Setup SCCB for Control-Program Identification */
 105         sccb->header.length = sizeof(struct sclp_ofb_sccb);
 106         sccb->ofb_evbuf.header.length = sizeof(struct sclp_ofb_evbuf);
 107         sccb->ofb_evbuf.header.type = EVTYP_CONFMGMDATA;
 108         sccb->ofb_evbuf.cm_data.ev_qualifier = EV_QUAL_OPEN4BUSINESS;
 109         memcpy(sccb->ofb_evbuf.ev_data, ev_data, len);
 110 
 111         if (!(sclp_conf_register.sclp_receive_mask & EVTYP_CONFMGMDATA_MASK))
 112                 pr_warn("SCLP receiver did not register to receive "
 113                         "Configuration Management Data Events.\n");
 114 
 115         mutex_lock(&send_mutex);
 116         rc = sclp_sync_request(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
 117         mutex_unlock(&send_mutex);
 118         if (rc)
 119                 goto out;
 120         response = sccb->header.response_code;
 121         if (response != 0x0020) {
 122                 pr_err("Open for Business request failed with response code "
 123                        "0x%04x\n", response);
 124                 rc = -EIO;
 125         }
 126 out:
 127         free_page((unsigned long)sccb);
 128         return rc;
 129 }
 130 
 131 static ssize_t sysfs_ofb_data_write(struct file *filp, struct kobject *kobj,
 132                                     struct bin_attribute *bin_attr,
 133                                     char *buf, loff_t off, size_t count)
 134 {
 135         int rc;
 136 
 137         rc = sclp_ofb_send_req(buf, count);
 138         return rc ?: count;
 139 }
 140 
 141 static const struct bin_attribute ofb_bin_attr = {
 142         .attr = {
 143                 .name = "event_data",
 144                 .mode = S_IWUSR,
 145         },
 146         .write = sysfs_ofb_data_write,
 147 };
 148 #endif
 149 
 150 static int __init sclp_ofb_setup(void)
 151 {
 152 #ifdef CONFIG_SCLP_OFB
 153         struct kset *ofb_kset;
 154         int rc;
 155 
 156         ofb_kset = kset_create_and_add("ofb", NULL, firmware_kobj);
 157         if (!ofb_kset)
 158                 return -ENOMEM;
 159         rc = sysfs_create_bin_file(&ofb_kset->kobj, &ofb_bin_attr);
 160         if (rc) {
 161                 kset_unregister(ofb_kset);
 162                 return rc;
 163         }
 164 #endif
 165         return 0;
 166 }
 167 
 168 static int __init sclp_conf_init(void)
 169 {
 170         int rc;
 171 
 172         INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
 173         INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
 174         rc = sclp_register(&sclp_conf_register);
 175         if (rc)
 176                 return rc;
 177         return sclp_ofb_setup();
 178 }
 179 
 180 __initcall(sclp_conf_init);

/* [<][>][^][v][top][bottom][index][help] */