Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags   |
^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", &params, &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(&note->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, &current_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);