^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * ACPI PCI Hot Plug IBM Extension
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2004 Vernon Mauery <vernux@us.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2004 IBM Corp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Send feedback to <vernux@us.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define pr_fmt(fmt) "acpiphp_ibm: " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/kobject.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "acpiphp.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include "../pci.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define DRIVER_VERSION "1.0.1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver IBM extension"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) MODULE_AUTHOR(DRIVER_AUTHOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) MODULE_DESCRIPTION(DRIVER_DESC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) MODULE_VERSION(DRIVER_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define FOUND_APCI 0x61504349
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /* these are the names for the IBM ACPI pseudo-device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define IBM_HARDWARE_ID1 "IBM37D0"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define IBM_HARDWARE_ID2 "IBM37D4"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define hpslot_to_sun(A) (to_slot(A)->sun)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* union apci_descriptor - allows access to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * various device descriptors that are embedded in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * aPCI table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) union apci_descriptor {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) char sig[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) u8 len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) } header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) u8 type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) u8 len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) u16 slot_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) u8 bus_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) u8 dev_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) u8 slot_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) u8 slot_attr[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) u8 attn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) u8 status[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u8 sun;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) u8 res[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) } slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) u8 type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u8 len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) } generic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /* struct notification - keeps info about the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * that cause the ACPI notification event
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct notification {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) struct acpi_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) u8 event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static void ibm_handle_events(acpi_handle handle, u32 event, void *context);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int ibm_get_table_from_acpi(char **bufp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static ssize_t ibm_read_apci_table(struct file *filp, struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct bin_attribute *bin_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) char *buffer, loff_t pos, size_t size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) u32 lvl, void *context, void **rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static int __init ibm_acpiphp_init(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static void __exit ibm_acpiphp_exit(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static acpi_handle ibm_acpi_handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static struct notification ibm_note;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static struct bin_attribute ibm_apci_table_attr __ro_after_init = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .attr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .name = "apci_table",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .mode = S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .read = ibm_read_apci_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .write = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static struct acpiphp_attention_info ibm_attention_info =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .set_attn = ibm_set_attention_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .get_attn = ibm_get_attention_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * ibm_slot_from_id - workaround for bad ibm hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * @id: the slot number that linux refers to the slot by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * Description: This method returns the aCPI slot descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * corresponding to the Linux slot number. This descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * has info about the aPCI slot id and attention status.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * This descriptor must be freed using kfree when done.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static union apci_descriptor *ibm_slot_from_id(int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) int ind = 0, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) union apci_descriptor *ret = NULL, *des;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) char *table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) size = ibm_get_table_from_acpi(&table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (size < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) des = (union apci_descriptor *)table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (memcmp(des->header.sig, "aPCI", 4) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) goto ibm_slot_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) des = (union apci_descriptor *)&table[ind += des->header.len];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) while (ind < size && (des->generic.type != 0x82 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) des->slot.slot_num != id)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) des = (union apci_descriptor *)&table[ind += des->generic.len];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (ind < size && des->slot.slot_num == id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ret = des;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) ibm_slot_done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ret = kmalloc(sizeof(union apci_descriptor), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) memcpy(ret, des, sizeof(union apci_descriptor));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) kfree(table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * ibm_set_attention_status - callback method to set the attention LED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * @slot: the hotplug_slot to work with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * @status: what to set the LED to (0 or 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * Description: This method is registered with the acpiphp module as a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * callback to do the device specific task of setting the LED status.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) union acpi_object args[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) struct acpi_object_list params = { .pointer = args, .count = 2 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) acpi_status stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) unsigned long long rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) union apci_descriptor *ibm_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) int id = hpslot_to_sun(slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) ibm_slot = ibm_slot_from_id(id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (!ibm_slot) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) pr_err("APLS null ACPI descriptor for slot %d\n", id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) pr_debug("%s: set slot %d (%d) attention status to %d\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) ibm_slot->slot.slot_num, ibm_slot->slot.slot_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) (status ? 1 : 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) args[0].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) args[0].integer.value = ibm_slot->slot.slot_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) args[1].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) args[1].integer.value = (status) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) kfree(ibm_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) stat = acpi_evaluate_integer(ibm_acpi_handle, "APLS", ¶ms, &rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (ACPI_FAILURE(stat)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) pr_err("APLS evaluation failed: 0x%08x\n", stat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) } else if (!rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) pr_err("APLS method failed: 0x%08llx\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * ibm_get_attention_status - callback method to get attention LED status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * @slot: the hotplug_slot to work with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * @status: returns what the LED is set to (0 or 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * Description: This method is registered with the acpiphp module as a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * callback to do the device specific task of getting the LED status.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * Because there is no direct method of getting the LED status directly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * from an ACPI call, we read the aPCI table and parse out our
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * slot descriptor to read the status from that.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) union apci_descriptor *ibm_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) int id = hpslot_to_sun(slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) ibm_slot = ibm_slot_from_id(id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (!ibm_slot) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) pr_err("APLS null ACPI descriptor for slot %d\n", id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (ibm_slot->slot.attn & 0xa0 || ibm_slot->slot.status[1] & 0x08)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) *status = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) *status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) pr_debug("%s: get slot %d (%d) attention status is %d\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) ibm_slot->slot.slot_num, ibm_slot->slot.slot_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) *status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) kfree(ibm_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) * ibm_handle_events - listens for ACPI events for the IBM37D0 device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * @handle: an ACPI handle to the device that caused the event
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) * @event: the event info (device specific)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) * @context: passed context (our notification struct)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * Description: This method is registered as a callback with the ACPI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * subsystem it is called when this device has an event to notify the OS of.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * The events actually come from the device as two events that get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * synthesized into one event with data by this function. The event
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * ID comes first and then the slot number that caused it. We report
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * this as one event to the OS.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) * From section 5.6.2.2 of the ACPI 2.0 spec, I understand that the OSPM will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) * only re-enable the interrupt that causes this event AFTER this method
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) * has returned, thereby enforcing serial access for the notification struct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) static void ibm_handle_events(acpi_handle handle, u32 event, void *context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) u8 detail = event & 0x0f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) u8 subevent = event & 0xf0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) struct notification *note = context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) pr_debug("%s: Received notification %02x\n", __func__, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (subevent == 0x80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) pr_debug("%s: generating bus event\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) acpi_bus_generate_netlink_event(note->device->pnp.device_class,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) dev_name(¬e->device->dev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) note->event, detail);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) note->event = event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) * ibm_get_table_from_acpi - reads the APLS buffer from ACPI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) * @bufp: address to pointer to allocate for the table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * Description: This method reads the APLS buffer in from ACPI and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * stores the "stripped" table into a single buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) * it allocates and passes the address back in bufp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) * If NULL is passed in as buffer, this method only calculates
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) * the size of the table and returns that without filling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * in the buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * Returns < 0 on error or the size of the table on success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) static int ibm_get_table_from_acpi(char **bufp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) union acpi_object *package;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) char *lbuf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) int i, size = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) status = acpi_evaluate_object(ibm_acpi_handle, "APCI", NULL, &buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) pr_err("%s: APCI evaluation failed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) package = (union acpi_object *) buffer.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (!(package) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) (package->type != ACPI_TYPE_PACKAGE) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) !(package->package.elements)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) pr_err("%s: Invalid APCI object\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) goto read_table_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) for (size = 0, i = 0; i < package->package.count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (package->package.elements[i].type != ACPI_TYPE_BUFFER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) pr_err("%s: Invalid APCI element %d\n", __func__, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) goto read_table_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) size += package->package.elements[i].buffer.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (bufp == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) goto read_table_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) lbuf = kzalloc(size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) pr_debug("%s: element count: %i, ASL table size: %i, &table = 0x%p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) __func__, package->package.count, size, lbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (lbuf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) *bufp = lbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) size = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) goto read_table_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) for (i = 0; i < package->package.count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) memcpy(&lbuf[size],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) package->package.elements[i].buffer.pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) package->package.elements[i].buffer.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) size += package->package.elements[i].buffer.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) read_table_done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) kfree(buffer.pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) * ibm_read_apci_table - callback for the sysfs apci_table file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * @filp: the open sysfs file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * @kobj: the kobject this binary attribute is a part of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) * @bin_attr: struct bin_attribute for this file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) * @buffer: the kernel space buffer to fill
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) * @pos: the offset into the file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) * @size: the number of bytes requested
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) * Description: Gets registered with sysfs as the reader callback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) * to be executed when /sys/bus/pci/slots/apci_table gets read.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) * Since we don't get notified on open and close for this file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) * things get really tricky here...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) * our solution is to only allow reading the table in all at once.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) static ssize_t ibm_read_apci_table(struct file *filp, struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) struct bin_attribute *bin_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) char *buffer, loff_t pos, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) int bytes_read = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) char *table = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) pr_debug("%s: pos = %d, size = %zd\n", __func__, (int)pos, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) if (pos == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) bytes_read = ibm_get_table_from_acpi(&table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (bytes_read > 0 && bytes_read <= size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) memcpy(buffer, table, bytes_read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) kfree(table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return bytes_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) * ibm_find_acpi_device - callback to find our ACPI device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) * @handle: the ACPI handle of the device we are inspecting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) * @lvl: depth into the namespace tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) * @context: a pointer to our handle to fill when we find the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) * @rv: a return value to fill if desired
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * Description: Used as a callback when calling acpi_walk_namespace
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) * to find our device. When this method returns non-zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) * acpi_walk_namespace quits its search and returns our value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) u32 lvl, void *context, void **rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) acpi_handle *phandle = (acpi_handle *)context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) unsigned long long current_status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) struct acpi_device_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) status = acpi_get_object_info(handle, &info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) pr_err("%s: Failed to get device information status=0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) __func__, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) acpi_bus_get_status_handle(handle, ¤t_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) if (current_status && (info->valid & ACPI_VALID_HID) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) (!strcmp(info->hardware_id.string, IBM_HARDWARE_ID1) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) !strcmp(info->hardware_id.string, IBM_HARDWARE_ID2))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) pr_debug("found hardware: %s, handle: %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) info->hardware_id.string, handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) *phandle = handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) /* returning non-zero causes the search to stop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) * and returns this value to the caller of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) * acpi_walk_namespace, but it also causes some warnings
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) * in the acpi debug code to print...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) retval = FOUND_APCI;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) static int __init ibm_acpiphp_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) struct acpi_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) struct kobject *sysdir = &pci_slots_kset->kobj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) pr_debug("%s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) ACPI_UINT32_MAX, ibm_find_acpi_device, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) &ibm_acpi_handle, NULL) != FOUND_APCI) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) pr_err("%s: acpi_walk_namespace failed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) goto init_return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) pr_debug("%s: found IBM aPCI device\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (acpi_bus_get_device(ibm_acpi_handle, &device)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) pr_err("%s: acpi_bus_get_device failed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) goto init_return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) if (acpiphp_register_attention(&ibm_attention_info)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) goto init_return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) ibm_note.device = device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) status = acpi_install_notify_handler(ibm_acpi_handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) ACPI_DEVICE_NOTIFY, ibm_handle_events,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) &ibm_note);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) pr_err("%s: Failed to register notification handler\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) retval = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) goto init_cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) ibm_apci_table_attr.size = ibm_get_table_from_acpi(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) retval = sysfs_create_bin_file(sysdir, &ibm_apci_table_attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) init_cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) acpiphp_unregister_attention(&ibm_attention_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) init_return:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) static void __exit ibm_acpiphp_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) struct kobject *sysdir = &pci_slots_kset->kobj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) pr_debug("%s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) if (acpiphp_unregister_attention(&ibm_attention_info))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) pr_err("%s: attention info deregistration failed", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) status = acpi_remove_notify_handler(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) ibm_acpi_handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) ACPI_DEVICE_NOTIFY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) ibm_handle_events);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) pr_err("%s: Notification handler removal failed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) /* remove the /sys entries */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) module_init(ibm_acpiphp_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) module_exit(ibm_acpiphp_exit);