Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * sysfs.c - ACPI sysfs interface to userspace.
0004  */
0005 
0006 #define pr_fmt(fmt) "ACPI: " fmt
0007 
0008 #include <linux/acpi.h>
0009 #include <linux/bitmap.h>
0010 #include <linux/init.h>
0011 #include <linux/kernel.h>
0012 #include <linux/moduleparam.h>
0013 
0014 #include "internal.h"
0015 
0016 #ifdef CONFIG_ACPI_DEBUG
0017 /*
0018  * ACPI debug sysfs I/F, including:
0019  * /sys/modules/acpi/parameters/debug_layer
0020  * /sys/modules/acpi/parameters/debug_level
0021  * /sys/modules/acpi/parameters/trace_method_name
0022  * /sys/modules/acpi/parameters/trace_state
0023  * /sys/modules/acpi/parameters/trace_debug_layer
0024  * /sys/modules/acpi/parameters/trace_debug_level
0025  */
0026 
0027 struct acpi_dlayer {
0028     const char *name;
0029     unsigned long value;
0030 };
0031 struct acpi_dlevel {
0032     const char *name;
0033     unsigned long value;
0034 };
0035 #define ACPI_DEBUG_INIT(v)  { .name = #v, .value = v }
0036 
0037 static const struct acpi_dlayer acpi_debug_layers[] = {
0038     ACPI_DEBUG_INIT(ACPI_UTILITIES),
0039     ACPI_DEBUG_INIT(ACPI_HARDWARE),
0040     ACPI_DEBUG_INIT(ACPI_EVENTS),
0041     ACPI_DEBUG_INIT(ACPI_TABLES),
0042     ACPI_DEBUG_INIT(ACPI_NAMESPACE),
0043     ACPI_DEBUG_INIT(ACPI_PARSER),
0044     ACPI_DEBUG_INIT(ACPI_DISPATCHER),
0045     ACPI_DEBUG_INIT(ACPI_EXECUTER),
0046     ACPI_DEBUG_INIT(ACPI_RESOURCES),
0047     ACPI_DEBUG_INIT(ACPI_CA_DEBUGGER),
0048     ACPI_DEBUG_INIT(ACPI_OS_SERVICES),
0049     ACPI_DEBUG_INIT(ACPI_CA_DISASSEMBLER),
0050     ACPI_DEBUG_INIT(ACPI_COMPILER),
0051     ACPI_DEBUG_INIT(ACPI_TOOLS),
0052 };
0053 
0054 static const struct acpi_dlevel acpi_debug_levels[] = {
0055     ACPI_DEBUG_INIT(ACPI_LV_INIT),
0056     ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT),
0057     ACPI_DEBUG_INIT(ACPI_LV_INFO),
0058     ACPI_DEBUG_INIT(ACPI_LV_REPAIR),
0059     ACPI_DEBUG_INIT(ACPI_LV_TRACE_POINT),
0060 
0061     ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES),
0062     ACPI_DEBUG_INIT(ACPI_LV_PARSE),
0063     ACPI_DEBUG_INIT(ACPI_LV_LOAD),
0064     ACPI_DEBUG_INIT(ACPI_LV_DISPATCH),
0065     ACPI_DEBUG_INIT(ACPI_LV_EXEC),
0066     ACPI_DEBUG_INIT(ACPI_LV_NAMES),
0067     ACPI_DEBUG_INIT(ACPI_LV_OPREGION),
0068     ACPI_DEBUG_INIT(ACPI_LV_BFIELD),
0069     ACPI_DEBUG_INIT(ACPI_LV_TABLES),
0070     ACPI_DEBUG_INIT(ACPI_LV_VALUES),
0071     ACPI_DEBUG_INIT(ACPI_LV_OBJECTS),
0072     ACPI_DEBUG_INIT(ACPI_LV_RESOURCES),
0073     ACPI_DEBUG_INIT(ACPI_LV_USER_REQUESTS),
0074     ACPI_DEBUG_INIT(ACPI_LV_PACKAGE),
0075 
0076     ACPI_DEBUG_INIT(ACPI_LV_ALLOCATIONS),
0077     ACPI_DEBUG_INIT(ACPI_LV_FUNCTIONS),
0078     ACPI_DEBUG_INIT(ACPI_LV_OPTIMIZATIONS),
0079 
0080     ACPI_DEBUG_INIT(ACPI_LV_MUTEX),
0081     ACPI_DEBUG_INIT(ACPI_LV_THREADS),
0082     ACPI_DEBUG_INIT(ACPI_LV_IO),
0083     ACPI_DEBUG_INIT(ACPI_LV_INTERRUPTS),
0084 
0085     ACPI_DEBUG_INIT(ACPI_LV_AML_DISASSEMBLE),
0086     ACPI_DEBUG_INIT(ACPI_LV_VERBOSE_INFO),
0087     ACPI_DEBUG_INIT(ACPI_LV_FULL_TABLES),
0088     ACPI_DEBUG_INIT(ACPI_LV_EVENTS),
0089 };
0090 
0091 static int param_get_debug_layer(char *buffer, const struct kernel_param *kp)
0092 {
0093     int result = 0;
0094     int i;
0095 
0096     result = sprintf(buffer, "%-25s\tHex        SET\n", "Description");
0097 
0098     for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) {
0099         result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n",
0100                   acpi_debug_layers[i].name,
0101                   acpi_debug_layers[i].value,
0102                   (acpi_dbg_layer & acpi_debug_layers[i].value)
0103                   ? '*' : ' ');
0104     }
0105     result +=
0106         sprintf(buffer + result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
0107             ACPI_ALL_DRIVERS,
0108             (acpi_dbg_layer & ACPI_ALL_DRIVERS) ==
0109             ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS)
0110             == 0 ? ' ' : '-');
0111     result +=
0112         sprintf(buffer + result,
0113             "--\ndebug_layer = 0x%08X ( * = enabled)\n",
0114             acpi_dbg_layer);
0115 
0116     return result;
0117 }
0118 
0119 static int param_get_debug_level(char *buffer, const struct kernel_param *kp)
0120 {
0121     int result = 0;
0122     int i;
0123 
0124     result = sprintf(buffer, "%-25s\tHex        SET\n", "Description");
0125 
0126     for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {
0127         result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n",
0128                   acpi_debug_levels[i].name,
0129                   acpi_debug_levels[i].value,
0130                   (acpi_dbg_level & acpi_debug_levels[i].value)
0131                   ? '*' : ' ');
0132     }
0133     result +=
0134         sprintf(buffer + result, "--\ndebug_level = 0x%08X (* = enabled)\n",
0135             acpi_dbg_level);
0136 
0137     return result;
0138 }
0139 
0140 static const struct kernel_param_ops param_ops_debug_layer = {
0141     .set = param_set_uint,
0142     .get = param_get_debug_layer,
0143 };
0144 
0145 static const struct kernel_param_ops param_ops_debug_level = {
0146     .set = param_set_uint,
0147     .get = param_get_debug_level,
0148 };
0149 
0150 module_param_cb(debug_layer, &param_ops_debug_layer, &acpi_dbg_layer, 0644);
0151 module_param_cb(debug_level, &param_ops_debug_level, &acpi_dbg_level, 0644);
0152 
0153 static char trace_method_name[1024];
0154 
0155 static int param_set_trace_method_name(const char *val,
0156                        const struct kernel_param *kp)
0157 {
0158     u32 saved_flags = 0;
0159     bool is_abs_path = true;
0160 
0161     if (*val != '\\')
0162         is_abs_path = false;
0163 
0164     if ((is_abs_path && strlen(val) > 1023) ||
0165         (!is_abs_path && strlen(val) > 1022)) {
0166         pr_err("%s: string parameter too long\n", kp->name);
0167         return -ENOSPC;
0168     }
0169 
0170     /*
0171      * It's not safe to update acpi_gbl_trace_method_name without
0172      * having the tracer stopped, so we save the original tracer
0173      * state and disable it.
0174      */
0175     saved_flags = acpi_gbl_trace_flags;
0176     (void)acpi_debug_trace(NULL,
0177                    acpi_gbl_trace_dbg_level,
0178                    acpi_gbl_trace_dbg_layer,
0179                    0);
0180 
0181     /* This is a hack.  We can't kmalloc in early boot. */
0182     if (is_abs_path)
0183         strcpy(trace_method_name, val);
0184     else {
0185         trace_method_name[0] = '\\';
0186         strcpy(trace_method_name+1, val);
0187     }
0188 
0189     /* Restore the original tracer state */
0190     (void)acpi_debug_trace(trace_method_name,
0191                    acpi_gbl_trace_dbg_level,
0192                    acpi_gbl_trace_dbg_layer,
0193                    saved_flags);
0194 
0195     return 0;
0196 }
0197 
0198 static int param_get_trace_method_name(char *buffer, const struct kernel_param *kp)
0199 {
0200     return scnprintf(buffer, PAGE_SIZE, "%s\n", acpi_gbl_trace_method_name);
0201 }
0202 
0203 static const struct kernel_param_ops param_ops_trace_method = {
0204     .set = param_set_trace_method_name,
0205     .get = param_get_trace_method_name,
0206 };
0207 
0208 static const struct kernel_param_ops param_ops_trace_attrib = {
0209     .set = param_set_uint,
0210     .get = param_get_uint,
0211 };
0212 
0213 module_param_cb(trace_method_name, &param_ops_trace_method, &trace_method_name, 0644);
0214 module_param_cb(trace_debug_layer, &param_ops_trace_attrib, &acpi_gbl_trace_dbg_layer, 0644);
0215 module_param_cb(trace_debug_level, &param_ops_trace_attrib, &acpi_gbl_trace_dbg_level, 0644);
0216 
0217 static int param_set_trace_state(const char *val,
0218                  const struct kernel_param *kp)
0219 {
0220     acpi_status status;
0221     const char *method = trace_method_name;
0222     u32 flags = 0;
0223 
0224 /* So "xxx-once" comparison should go prior than "xxx" comparison */
0225 #define acpi_compare_param(val, key)    \
0226     strncmp((val), (key), sizeof(key) - 1)
0227 
0228     if (!acpi_compare_param(val, "enable")) {
0229         method = NULL;
0230         flags = ACPI_TRACE_ENABLED;
0231     } else if (!acpi_compare_param(val, "disable"))
0232         method = NULL;
0233     else if (!acpi_compare_param(val, "method-once"))
0234         flags = ACPI_TRACE_ENABLED | ACPI_TRACE_ONESHOT;
0235     else if (!acpi_compare_param(val, "method"))
0236         flags = ACPI_TRACE_ENABLED;
0237     else if (!acpi_compare_param(val, "opcode-once"))
0238         flags = ACPI_TRACE_ENABLED | ACPI_TRACE_ONESHOT | ACPI_TRACE_OPCODE;
0239     else if (!acpi_compare_param(val, "opcode"))
0240         flags = ACPI_TRACE_ENABLED | ACPI_TRACE_OPCODE;
0241     else
0242         return -EINVAL;
0243 
0244     status = acpi_debug_trace(method,
0245                   acpi_gbl_trace_dbg_level,
0246                   acpi_gbl_trace_dbg_layer,
0247                   flags);
0248     if (ACPI_FAILURE(status))
0249         return -EBUSY;
0250 
0251     return 0;
0252 }
0253 
0254 static int param_get_trace_state(char *buffer, const struct kernel_param *kp)
0255 {
0256     if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED))
0257         return sprintf(buffer, "disable\n");
0258     if (!acpi_gbl_trace_method_name)
0259         return sprintf(buffer, "enable\n");
0260     if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT)
0261         return sprintf(buffer, "method-once\n");
0262     else
0263         return sprintf(buffer, "method\n");
0264 }
0265 
0266 module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
0267           NULL, 0644);
0268 #endif /* CONFIG_ACPI_DEBUG */
0269 
0270 
0271 /* /sys/modules/acpi/parameters/aml_debug_output */
0272 
0273 module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object,
0274            byte, 0644);
0275 MODULE_PARM_DESC(aml_debug_output,
0276          "To enable/disable the ACPI Debug Object output.");
0277 
0278 /* /sys/module/acpi/parameters/acpica_version */
0279 static int param_get_acpica_version(char *buffer,
0280                     const struct kernel_param *kp)
0281 {
0282     int result;
0283 
0284     result = sprintf(buffer, "%x\n", ACPI_CA_VERSION);
0285 
0286     return result;
0287 }
0288 
0289 module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
0290 
0291 /*
0292  * ACPI table sysfs I/F:
0293  * /sys/firmware/acpi/tables/
0294  * /sys/firmware/acpi/tables/data/
0295  * /sys/firmware/acpi/tables/dynamic/
0296  */
0297 
0298 static LIST_HEAD(acpi_table_attr_list);
0299 static struct kobject *tables_kobj;
0300 static struct kobject *tables_data_kobj;
0301 static struct kobject *dynamic_tables_kobj;
0302 static struct kobject *hotplug_kobj;
0303 
0304 #define ACPI_MAX_TABLE_INSTANCES    999
0305 #define ACPI_INST_SIZE          4 /* including trailing 0 */
0306 
0307 struct acpi_table_attr {
0308     struct bin_attribute attr;
0309     char name[ACPI_NAMESEG_SIZE];
0310     int instance;
0311     char filename[ACPI_NAMESEG_SIZE+ACPI_INST_SIZE];
0312     struct list_head node;
0313 };
0314 
0315 struct acpi_data_attr {
0316     struct bin_attribute attr;
0317     u64 addr;
0318 };
0319 
0320 static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj,
0321                    struct bin_attribute *bin_attr, char *buf,
0322                    loff_t offset, size_t count)
0323 {
0324     struct acpi_table_attr *table_attr =
0325         container_of(bin_attr, struct acpi_table_attr, attr);
0326     struct acpi_table_header *table_header = NULL;
0327     acpi_status status;
0328     ssize_t rc;
0329 
0330     status = acpi_get_table(table_attr->name, table_attr->instance,
0331                 &table_header);
0332     if (ACPI_FAILURE(status))
0333         return -ENODEV;
0334 
0335     rc = memory_read_from_buffer(buf, count, &offset, table_header,
0336             table_header->length);
0337     acpi_put_table(table_header);
0338     return rc;
0339 }
0340 
0341 static int acpi_table_attr_init(struct kobject *tables_obj,
0342                 struct acpi_table_attr *table_attr,
0343                 struct acpi_table_header *table_header)
0344 {
0345     struct acpi_table_header *header = NULL;
0346     struct acpi_table_attr *attr = NULL;
0347     char instance_str[ACPI_INST_SIZE];
0348 
0349     sysfs_attr_init(&table_attr->attr.attr);
0350     ACPI_COPY_NAMESEG(table_attr->name, table_header->signature);
0351 
0352     list_for_each_entry(attr, &acpi_table_attr_list, node) {
0353         if (ACPI_COMPARE_NAMESEG(table_attr->name, attr->name))
0354             if (table_attr->instance < attr->instance)
0355                 table_attr->instance = attr->instance;
0356     }
0357     table_attr->instance++;
0358     if (table_attr->instance > ACPI_MAX_TABLE_INSTANCES) {
0359         pr_warn("%4.4s: too many table instances\n", table_attr->name);
0360         return -ERANGE;
0361     }
0362 
0363     ACPI_COPY_NAMESEG(table_attr->filename, table_header->signature);
0364     table_attr->filename[ACPI_NAMESEG_SIZE] = '\0';
0365     if (table_attr->instance > 1 || (table_attr->instance == 1 &&
0366                      !acpi_get_table
0367                      (table_header->signature, 2, &header))) {
0368         snprintf(instance_str, sizeof(instance_str), "%u",
0369              table_attr->instance);
0370         strcat(table_attr->filename, instance_str);
0371     }
0372 
0373     table_attr->attr.size = table_header->length;
0374     table_attr->attr.read = acpi_table_show;
0375     table_attr->attr.attr.name = table_attr->filename;
0376     table_attr->attr.attr.mode = 0400;
0377 
0378     return sysfs_create_bin_file(tables_obj, &table_attr->attr);
0379 }
0380 
0381 acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context)
0382 {
0383     struct acpi_table_attr *table_attr;
0384 
0385     switch (event) {
0386     case ACPI_TABLE_EVENT_INSTALL:
0387         table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL);
0388         if (!table_attr)
0389             return AE_NO_MEMORY;
0390 
0391         if (acpi_table_attr_init(dynamic_tables_kobj,
0392                      table_attr, table)) {
0393             kfree(table_attr);
0394             return AE_ERROR;
0395         }
0396         list_add_tail(&table_attr->node, &acpi_table_attr_list);
0397         break;
0398     case ACPI_TABLE_EVENT_LOAD:
0399     case ACPI_TABLE_EVENT_UNLOAD:
0400     case ACPI_TABLE_EVENT_UNINSTALL:
0401         /*
0402          * we do not need to do anything right now
0403          * because the table is not deleted from the
0404          * global table list when unloading it.
0405          */
0406         break;
0407     default:
0408         return AE_BAD_PARAMETER;
0409     }
0410     return AE_OK;
0411 }
0412 
0413 static ssize_t acpi_data_show(struct file *filp, struct kobject *kobj,
0414                   struct bin_attribute *bin_attr, char *buf,
0415                   loff_t offset, size_t count)
0416 {
0417     struct acpi_data_attr *data_attr;
0418     void __iomem *base;
0419     ssize_t size;
0420 
0421     data_attr = container_of(bin_attr, struct acpi_data_attr, attr);
0422     size = data_attr->attr.size;
0423 
0424     if (offset < 0)
0425         return -EINVAL;
0426 
0427     if (offset >= size)
0428         return 0;
0429 
0430     if (count > size - offset)
0431         count = size - offset;
0432 
0433     base = acpi_os_map_iomem(data_attr->addr, size);
0434     if (!base)
0435         return -ENOMEM;
0436 
0437     memcpy_fromio(buf, base + offset, count);
0438 
0439     acpi_os_unmap_iomem(base, size);
0440 
0441     return count;
0442 }
0443 
0444 static int acpi_bert_data_init(void *th, struct acpi_data_attr *data_attr)
0445 {
0446     struct acpi_table_bert *bert = th;
0447 
0448     if (bert->header.length < sizeof(struct acpi_table_bert) ||
0449         bert->region_length < sizeof(struct acpi_hest_generic_status)) {
0450         kfree(data_attr);
0451         return -EINVAL;
0452     }
0453     data_attr->addr = bert->address;
0454     data_attr->attr.size = bert->region_length;
0455     data_attr->attr.attr.name = "BERT";
0456 
0457     return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr);
0458 }
0459 
0460 static struct acpi_data_obj {
0461     char *name;
0462     int (*fn)(void *, struct acpi_data_attr *);
0463 } acpi_data_objs[] = {
0464     { ACPI_SIG_BERT, acpi_bert_data_init },
0465 };
0466 
0467 #define NUM_ACPI_DATA_OBJS ARRAY_SIZE(acpi_data_objs)
0468 
0469 static int acpi_table_data_init(struct acpi_table_header *th)
0470 {
0471     struct acpi_data_attr *data_attr;
0472     int i;
0473 
0474     for (i = 0; i < NUM_ACPI_DATA_OBJS; i++) {
0475         if (ACPI_COMPARE_NAMESEG(th->signature, acpi_data_objs[i].name)) {
0476             data_attr = kzalloc(sizeof(*data_attr), GFP_KERNEL);
0477             if (!data_attr)
0478                 return -ENOMEM;
0479             sysfs_attr_init(&data_attr->attr.attr);
0480             data_attr->attr.read = acpi_data_show;
0481             data_attr->attr.attr.mode = 0400;
0482             return acpi_data_objs[i].fn(th, data_attr);
0483         }
0484     }
0485     return 0;
0486 }
0487 
0488 static int acpi_tables_sysfs_init(void)
0489 {
0490     struct acpi_table_attr *table_attr;
0491     struct acpi_table_header *table_header = NULL;
0492     int table_index;
0493     acpi_status status;
0494     int ret;
0495 
0496     tables_kobj = kobject_create_and_add("tables", acpi_kobj);
0497     if (!tables_kobj)
0498         goto err;
0499 
0500     tables_data_kobj = kobject_create_and_add("data", tables_kobj);
0501     if (!tables_data_kobj)
0502         goto err_tables_data;
0503 
0504     dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj);
0505     if (!dynamic_tables_kobj)
0506         goto err_dynamic_tables;
0507 
0508     for (table_index = 0;; table_index++) {
0509         status = acpi_get_table_by_index(table_index, &table_header);
0510 
0511         if (status == AE_BAD_PARAMETER)
0512             break;
0513 
0514         if (ACPI_FAILURE(status))
0515             continue;
0516 
0517         table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL);
0518         if (!table_attr)
0519             return -ENOMEM;
0520 
0521         ret = acpi_table_attr_init(tables_kobj,
0522                        table_attr, table_header);
0523         if (ret) {
0524             kfree(table_attr);
0525             return ret;
0526         }
0527         list_add_tail(&table_attr->node, &acpi_table_attr_list);
0528         acpi_table_data_init(table_header);
0529     }
0530 
0531     kobject_uevent(tables_kobj, KOBJ_ADD);
0532     kobject_uevent(tables_data_kobj, KOBJ_ADD);
0533     kobject_uevent(dynamic_tables_kobj, KOBJ_ADD);
0534 
0535     return 0;
0536 err_dynamic_tables:
0537     kobject_put(tables_data_kobj);
0538 err_tables_data:
0539     kobject_put(tables_kobj);
0540 err:
0541     return -ENOMEM;
0542 }
0543 
0544 /*
0545  * Detailed ACPI IRQ counters:
0546  * /sys/firmware/acpi/interrupts/
0547  */
0548 
0549 u32 acpi_irq_handled;
0550 u32 acpi_irq_not_handled;
0551 
0552 #define COUNT_GPE 0
0553 #define COUNT_SCI 1     /* acpi_irq_handled */
0554 #define COUNT_SCI_NOT 2     /* acpi_irq_not_handled */
0555 #define COUNT_ERROR 3       /* other */
0556 #define NUM_COUNTERS_EXTRA 4
0557 
0558 struct event_counter {
0559     u32 count;
0560     u32 flags;
0561 };
0562 
0563 static struct event_counter *all_counters;
0564 static u32 num_gpes;
0565 static u32 num_counters;
0566 static struct attribute **all_attrs;
0567 static u32 acpi_gpe_count;
0568 
0569 static struct attribute_group interrupt_stats_attr_group = {
0570     .name = "interrupts",
0571 };
0572 
0573 static struct kobj_attribute *counter_attrs;
0574 
0575 static void delete_gpe_attr_array(void)
0576 {
0577     struct event_counter *tmp = all_counters;
0578 
0579     all_counters = NULL;
0580     kfree(tmp);
0581 
0582     if (counter_attrs) {
0583         int i;
0584 
0585         for (i = 0; i < num_gpes; i++)
0586             kfree(counter_attrs[i].attr.name);
0587 
0588         kfree(counter_attrs);
0589     }
0590     kfree(all_attrs);
0591 }
0592 
0593 static void gpe_count(u32 gpe_number)
0594 {
0595     acpi_gpe_count++;
0596 
0597     if (!all_counters)
0598         return;
0599 
0600     if (gpe_number < num_gpes)
0601         all_counters[gpe_number].count++;
0602     else
0603         all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS +
0604                  COUNT_ERROR].count++;
0605 }
0606 
0607 static void fixed_event_count(u32 event_number)
0608 {
0609     if (!all_counters)
0610         return;
0611 
0612     if (event_number < ACPI_NUM_FIXED_EVENTS)
0613         all_counters[num_gpes + event_number].count++;
0614     else
0615         all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS +
0616                  COUNT_ERROR].count++;
0617 }
0618 
0619 static void acpi_global_event_handler(u32 event_type, acpi_handle device,
0620     u32 event_number, void *context)
0621 {
0622     if (event_type == ACPI_EVENT_TYPE_GPE) {
0623         gpe_count(event_number);
0624         pr_debug("GPE event 0x%02x\n", event_number);
0625     } else if (event_type == ACPI_EVENT_TYPE_FIXED) {
0626         fixed_event_count(event_number);
0627         pr_debug("Fixed event 0x%02x\n", event_number);
0628     } else {
0629         pr_debug("Other event 0x%02x\n", event_number);
0630     }
0631 }
0632 
0633 static int get_status(u32 index, acpi_event_status *ret,
0634               acpi_handle *handle)
0635 {
0636     acpi_status status;
0637 
0638     if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS)
0639         return -EINVAL;
0640 
0641     if (index < num_gpes) {
0642         status = acpi_get_gpe_device(index, handle);
0643         if (ACPI_FAILURE(status)) {
0644             pr_warn("Invalid GPE 0x%x", index);
0645             return -ENXIO;
0646         }
0647         status = acpi_get_gpe_status(*handle, index, ret);
0648     } else {
0649         status = acpi_get_event_status(index - num_gpes, ret);
0650     }
0651     if (ACPI_FAILURE(status))
0652         return -EIO;
0653 
0654     return 0;
0655 }
0656 
0657 static ssize_t counter_show(struct kobject *kobj,
0658                 struct kobj_attribute *attr, char *buf)
0659 {
0660     int index = attr - counter_attrs;
0661     int size;
0662     acpi_handle handle;
0663     acpi_event_status status;
0664     int result = 0;
0665 
0666     all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI].count =
0667         acpi_irq_handled;
0668     all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT].count =
0669         acpi_irq_not_handled;
0670     all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE].count =
0671         acpi_gpe_count;
0672     size = sprintf(buf, "%8u", all_counters[index].count);
0673 
0674     /* "gpe_all" or "sci" */
0675     if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS)
0676         goto end;
0677 
0678     result = get_status(index, &status, &handle);
0679     if (result)
0680         goto end;
0681 
0682     if (status & ACPI_EVENT_FLAG_ENABLE_SET)
0683         size += sprintf(buf + size, "  EN");
0684     else
0685         size += sprintf(buf + size, "    ");
0686     if (status & ACPI_EVENT_FLAG_STATUS_SET)
0687         size += sprintf(buf + size, " STS");
0688     else
0689         size += sprintf(buf + size, "    ");
0690 
0691     if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER))
0692         size += sprintf(buf + size, " invalid     ");
0693     else if (status & ACPI_EVENT_FLAG_ENABLED)
0694         size += sprintf(buf + size, " enabled     ");
0695     else if (status & ACPI_EVENT_FLAG_WAKE_ENABLED)
0696         size += sprintf(buf + size, " wake_enabled");
0697     else
0698         size += sprintf(buf + size, " disabled    ");
0699     if (status & ACPI_EVENT_FLAG_MASKED)
0700         size += sprintf(buf + size, " masked  ");
0701     else
0702         size += sprintf(buf + size, " unmasked");
0703 
0704 end:
0705     size += sprintf(buf + size, "\n");
0706     return result ? result : size;
0707 }
0708 
0709 /*
0710  * counter_set() sets the specified counter.
0711  * setting the total "sci" file to any value clears all counters.
0712  * enable/disable/clear a gpe/fixed event in user space.
0713  */
0714 static ssize_t counter_set(struct kobject *kobj,
0715                struct kobj_attribute *attr, const char *buf,
0716                size_t size)
0717 {
0718     int index = attr - counter_attrs;
0719     acpi_event_status status;
0720     acpi_handle handle;
0721     int result = 0;
0722     unsigned long tmp;
0723 
0724     if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) {
0725         int i;
0726         for (i = 0; i < num_counters; ++i)
0727             all_counters[i].count = 0;
0728         acpi_gpe_count = 0;
0729         acpi_irq_handled = 0;
0730         acpi_irq_not_handled = 0;
0731         goto end;
0732     }
0733 
0734     /* show the event status for both GPEs and Fixed Events */
0735     result = get_status(index, &status, &handle);
0736     if (result)
0737         goto end;
0738 
0739     if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER)) {
0740         pr_warn("Can not change Invalid GPE/Fixed Event status\n");
0741         return -EINVAL;
0742     }
0743 
0744     if (index < num_gpes) {
0745         if (!strcmp(buf, "disable\n") &&
0746             (status & ACPI_EVENT_FLAG_ENABLED))
0747             result = acpi_disable_gpe(handle, index);
0748         else if (!strcmp(buf, "enable\n") &&
0749              !(status & ACPI_EVENT_FLAG_ENABLED))
0750             result = acpi_enable_gpe(handle, index);
0751         else if (!strcmp(buf, "clear\n") &&
0752              (status & ACPI_EVENT_FLAG_STATUS_SET))
0753             result = acpi_clear_gpe(handle, index);
0754         else if (!strcmp(buf, "mask\n"))
0755             result = acpi_mask_gpe(handle, index, TRUE);
0756         else if (!strcmp(buf, "unmask\n"))
0757             result = acpi_mask_gpe(handle, index, FALSE);
0758         else if (!kstrtoul(buf, 0, &tmp))
0759             all_counters[index].count = tmp;
0760         else
0761             result = -EINVAL;
0762     } else if (index < num_gpes + ACPI_NUM_FIXED_EVENTS) {
0763         int event = index - num_gpes;
0764         if (!strcmp(buf, "disable\n") &&
0765             (status & ACPI_EVENT_FLAG_ENABLE_SET))
0766             result = acpi_disable_event(event, ACPI_NOT_ISR);
0767         else if (!strcmp(buf, "enable\n") &&
0768              !(status & ACPI_EVENT_FLAG_ENABLE_SET))
0769             result = acpi_enable_event(event, ACPI_NOT_ISR);
0770         else if (!strcmp(buf, "clear\n") &&
0771              (status & ACPI_EVENT_FLAG_STATUS_SET))
0772             result = acpi_clear_event(event);
0773         else if (!kstrtoul(buf, 0, &tmp))
0774             all_counters[index].count = tmp;
0775         else
0776             result = -EINVAL;
0777     } else
0778         all_counters[index].count = strtoul(buf, NULL, 0);
0779 
0780     if (ACPI_FAILURE(result))
0781         result = -EINVAL;
0782 end:
0783     return result ? result : size;
0784 }
0785 
0786 /*
0787  * A Quirk Mechanism for GPE Flooding Prevention:
0788  *
0789  * Quirks may be needed to prevent GPE flooding on a specific GPE. The
0790  * flooding typically cannot be detected and automatically prevented by
0791  * ACPI_GPE_DISPATCH_NONE check because there is a _Lxx/_Exx prepared in
0792  * the AML tables. This normally indicates a feature gap in Linux, thus
0793  * instead of providing endless quirk tables, we provide a boot parameter
0794  * for those who want this quirk. For example, if the users want to prevent
0795  * the GPE flooding for GPE 00, they need to specify the following boot
0796  * parameter:
0797  *   acpi_mask_gpe=0x00
0798  * Note, the parameter can be a list (see bitmap_parselist() for the details).
0799  * The masking status can be modified by the following runtime controlling
0800  * interface:
0801  *   echo unmask > /sys/firmware/acpi/interrupts/gpe00
0802  */
0803 #define ACPI_MASKABLE_GPE_MAX   0x100
0804 static DECLARE_BITMAP(acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) __initdata;
0805 
0806 static int __init acpi_gpe_set_masked_gpes(char *val)
0807 {
0808     int ret;
0809     u8 gpe;
0810 
0811     ret = kstrtou8(val, 0, &gpe);
0812     if (ret) {
0813         ret = bitmap_parselist(val, acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX);
0814         if (ret)
0815             return ret;
0816     } else
0817         set_bit(gpe, acpi_masked_gpes_map);
0818 
0819     return 1;
0820 }
0821 __setup("acpi_mask_gpe=", acpi_gpe_set_masked_gpes);
0822 
0823 void __init acpi_gpe_apply_masked_gpes(void)
0824 {
0825     acpi_handle handle;
0826     acpi_status status;
0827     u16 gpe;
0828 
0829     for_each_set_bit(gpe, acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) {
0830         status = acpi_get_gpe_device(gpe, &handle);
0831         if (ACPI_SUCCESS(status)) {
0832             pr_info("Masking GPE 0x%x.\n", gpe);
0833             (void)acpi_mask_gpe(handle, gpe, TRUE);
0834         }
0835     }
0836 }
0837 
0838 void acpi_irq_stats_init(void)
0839 {
0840     acpi_status status;
0841     int i;
0842 
0843     if (all_counters)
0844         return;
0845 
0846     num_gpes = acpi_current_gpe_count;
0847     num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA;
0848 
0849     all_attrs = kcalloc(num_counters + 1, sizeof(*all_attrs), GFP_KERNEL);
0850     if (all_attrs == NULL)
0851         return;
0852 
0853     all_counters = kcalloc(num_counters, sizeof(*all_counters), GFP_KERNEL);
0854     if (all_counters == NULL)
0855         goto fail;
0856 
0857     status = acpi_install_global_event_handler(acpi_global_event_handler, NULL);
0858     if (ACPI_FAILURE(status))
0859         goto fail;
0860 
0861     counter_attrs = kcalloc(num_counters, sizeof(*counter_attrs), GFP_KERNEL);
0862     if (counter_attrs == NULL)
0863         goto fail;
0864 
0865     for (i = 0; i < num_counters; ++i) {
0866         char buffer[12];
0867         char *name;
0868 
0869         if (i < num_gpes)
0870             sprintf(buffer, "gpe%02X", i);
0871         else if (i == num_gpes + ACPI_EVENT_PMTIMER)
0872             sprintf(buffer, "ff_pmtimer");
0873         else if (i == num_gpes + ACPI_EVENT_GLOBAL)
0874             sprintf(buffer, "ff_gbl_lock");
0875         else if (i == num_gpes + ACPI_EVENT_POWER_BUTTON)
0876             sprintf(buffer, "ff_pwr_btn");
0877         else if (i == num_gpes + ACPI_EVENT_SLEEP_BUTTON)
0878             sprintf(buffer, "ff_slp_btn");
0879         else if (i == num_gpes + ACPI_EVENT_RTC)
0880             sprintf(buffer, "ff_rt_clk");
0881         else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE)
0882             sprintf(buffer, "gpe_all");
0883         else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI)
0884             sprintf(buffer, "sci");
0885         else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT)
0886             sprintf(buffer, "sci_not");
0887         else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR)
0888             sprintf(buffer, "error");
0889         else
0890             sprintf(buffer, "bug%02X", i);
0891 
0892         name = kstrdup(buffer, GFP_KERNEL);
0893         if (name == NULL)
0894             goto fail;
0895 
0896         sysfs_attr_init(&counter_attrs[i].attr);
0897         counter_attrs[i].attr.name = name;
0898         counter_attrs[i].attr.mode = 0644;
0899         counter_attrs[i].show = counter_show;
0900         counter_attrs[i].store = counter_set;
0901 
0902         all_attrs[i] = &counter_attrs[i].attr;
0903     }
0904 
0905     interrupt_stats_attr_group.attrs = all_attrs;
0906     if (!sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group))
0907         return;
0908 
0909 fail:
0910     delete_gpe_attr_array();
0911 }
0912 
0913 static void __exit interrupt_stats_exit(void)
0914 {
0915     sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group);
0916 
0917     delete_gpe_attr_array();
0918 }
0919 
0920 static ssize_t pm_profile_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
0921 {
0922     return sprintf(buf, "%d\n", acpi_gbl_FADT.preferred_profile);
0923 }
0924 
0925 static const struct kobj_attribute pm_profile_attr = __ATTR_RO(pm_profile);
0926 
0927 static ssize_t enabled_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
0928 {
0929     struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
0930 
0931     return sprintf(buf, "%d\n", hotplug->enabled);
0932 }
0933 
0934 static ssize_t enabled_store(struct kobject *kobj, struct kobj_attribute *attr,
0935                  const char *buf, size_t size)
0936 {
0937     struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
0938     unsigned int val;
0939 
0940     if (kstrtouint(buf, 10, &val) || val > 1)
0941         return -EINVAL;
0942 
0943     acpi_scan_hotplug_enabled(hotplug, val);
0944     return size;
0945 }
0946 
0947 static struct kobj_attribute hotplug_enabled_attr = __ATTR_RW(enabled);
0948 
0949 static struct attribute *hotplug_profile_attrs[] = {
0950     &hotplug_enabled_attr.attr,
0951     NULL
0952 };
0953 ATTRIBUTE_GROUPS(hotplug_profile);
0954 
0955 static struct kobj_type acpi_hotplug_profile_ktype = {
0956     .sysfs_ops = &kobj_sysfs_ops,
0957     .default_groups = hotplug_profile_groups,
0958 };
0959 
0960 void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
0961                     const char *name)
0962 {
0963     int error;
0964 
0965     if (!hotplug_kobj)
0966         goto err_out;
0967 
0968     error = kobject_init_and_add(&hotplug->kobj,
0969         &acpi_hotplug_profile_ktype, hotplug_kobj, "%s", name);
0970     if (error) {
0971         kobject_put(&hotplug->kobj);
0972         goto err_out;
0973     }
0974 
0975     kobject_uevent(&hotplug->kobj, KOBJ_ADD);
0976     return;
0977 
0978  err_out:
0979     pr_err("Unable to add hotplug profile '%s'\n", name);
0980 }
0981 
0982 static ssize_t force_remove_show(struct kobject *kobj,
0983                  struct kobj_attribute *attr, char *buf)
0984 {
0985     return sprintf(buf, "%d\n", 0);
0986 }
0987 
0988 static ssize_t force_remove_store(struct kobject *kobj,
0989                   struct kobj_attribute *attr,
0990                   const char *buf, size_t size)
0991 {
0992     bool val;
0993     int ret;
0994 
0995     ret = strtobool(buf, &val);
0996     if (ret < 0)
0997         return ret;
0998 
0999     if (val) {
1000         pr_err("Enabling force_remove is not supported anymore. Please report to linux-acpi@vger.kernel.org if you depend on this functionality\n");
1001         return -EINVAL;
1002     }
1003     return size;
1004 }
1005 
1006 static const struct kobj_attribute force_remove_attr = __ATTR_RW(force_remove);
1007 
1008 int __init acpi_sysfs_init(void)
1009 {
1010     int result;
1011 
1012     result = acpi_tables_sysfs_init();
1013     if (result)
1014         return result;
1015 
1016     hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj);
1017     if (!hotplug_kobj)
1018         return -ENOMEM;
1019 
1020     result = sysfs_create_file(hotplug_kobj, &force_remove_attr.attr);
1021     if (result)
1022         return result;
1023 
1024     result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr);
1025     return result;
1026 }