0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0018
0019 #include <linux/kernel.h>
0020 #include <linux/init.h>
0021 #include <linux/slab.h>
0022 #include <linux/types.h>
0023 #include <linux/list.h>
0024 #include <linux/pci.h>
0025 #include <linux/acpi.h>
0026 #include <linux/dmi.h>
0027 #include <linux/pci-acpi.h>
0028
0029 static int check_sta_before_sun;
0030
0031 #define SLOT_NAME_SIZE 21
0032
0033 struct acpi_pci_slot {
0034 struct pci_slot *pci_slot;
0035 struct list_head list;
0036 };
0037
0038 static LIST_HEAD(slot_list);
0039 static DEFINE_MUTEX(slot_list_lock);
0040
0041 static int
0042 check_slot(acpi_handle handle, unsigned long long *sun)
0043 {
0044 int device = -1;
0045 unsigned long long adr, sta;
0046 acpi_status status;
0047 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
0048
0049 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
0050 pr_debug("Checking slot on path: %s\n", (char *)buffer.pointer);
0051
0052 if (check_sta_before_sun) {
0053
0054 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
0055 if (ACPI_SUCCESS(status) && !(sta & ACPI_STA_DEVICE_PRESENT))
0056 goto out;
0057 }
0058
0059 status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
0060 if (ACPI_FAILURE(status)) {
0061 pr_debug("_ADR returned %d on %s\n",
0062 status, (char *)buffer.pointer);
0063 goto out;
0064 }
0065
0066
0067 status = acpi_evaluate_integer(handle, "_SUN", NULL, sun);
0068 if (ACPI_FAILURE(status)) {
0069 pr_debug("_SUN returned %d on %s\n",
0070 status, (char *)buffer.pointer);
0071 goto out;
0072 }
0073
0074 device = (adr >> 16) & 0xffff;
0075 out:
0076 kfree(buffer.pointer);
0077 return device;
0078 }
0079
0080
0081
0082
0083 static acpi_status
0084 register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
0085 {
0086 int device;
0087 unsigned long long sun;
0088 char name[SLOT_NAME_SIZE];
0089 struct acpi_pci_slot *slot;
0090 struct pci_slot *pci_slot;
0091 struct pci_bus *pci_bus = context;
0092
0093 device = check_slot(handle, &sun);
0094 if (device < 0)
0095 return AE_OK;
0096
0097
0098
0099
0100
0101 list_for_each_entry(slot, &slot_list, list) {
0102 pci_slot = slot->pci_slot;
0103 if (pci_slot->bus == pci_bus && pci_slot->number == device)
0104 return AE_OK;
0105 }
0106
0107 slot = kmalloc(sizeof(*slot), GFP_KERNEL);
0108 if (!slot)
0109 return AE_OK;
0110
0111 snprintf(name, sizeof(name), "%llu", sun);
0112 pci_slot = pci_create_slot(pci_bus, device, name, NULL);
0113 if (IS_ERR(pci_slot)) {
0114 pr_err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot));
0115 kfree(slot);
0116 return AE_OK;
0117 }
0118
0119 slot->pci_slot = pci_slot;
0120 list_add(&slot->list, &slot_list);
0121
0122 get_device(&pci_bus->dev);
0123
0124 pr_debug("%p, pci_bus: %x, device: %d, name: %s\n",
0125 pci_slot, pci_bus->number, device, name);
0126
0127 return AE_OK;
0128 }
0129
0130 void acpi_pci_slot_enumerate(struct pci_bus *bus)
0131 {
0132 acpi_handle handle = ACPI_HANDLE(bus->bridge);
0133
0134 if (handle) {
0135 mutex_lock(&slot_list_lock);
0136 acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
0137 register_slot, NULL, bus, NULL);
0138 mutex_unlock(&slot_list_lock);
0139 }
0140 }
0141
0142 void acpi_pci_slot_remove(struct pci_bus *bus)
0143 {
0144 struct acpi_pci_slot *slot, *tmp;
0145
0146 mutex_lock(&slot_list_lock);
0147 list_for_each_entry_safe(slot, tmp, &slot_list, list) {
0148 if (slot->pci_slot->bus == bus) {
0149 list_del(&slot->list);
0150 pci_destroy_slot(slot->pci_slot);
0151 put_device(&bus->dev);
0152 kfree(slot);
0153 }
0154 }
0155 mutex_unlock(&slot_list_lock);
0156 }
0157
0158 static int do_sta_before_sun(const struct dmi_system_id *d)
0159 {
0160 pr_info("%s detected: will evaluate _STA before calling _SUN\n",
0161 d->ident);
0162 check_sta_before_sun = 1;
0163 return 0;
0164 }
0165
0166 static const struct dmi_system_id acpi_pci_slot_dmi_table[] __initconst = {
0167
0168
0169
0170
0171
0172
0173 {
0174 .callback = do_sta_before_sun,
0175 .ident = "Fujitsu PRIMEQUEST",
0176 .matches = {
0177 DMI_MATCH(DMI_BIOS_VENDOR, "FUJITSU LIMITED"),
0178 DMI_MATCH(DMI_BIOS_VERSION, "PRIMEQUEST"),
0179 },
0180 },
0181 {}
0182 };
0183
0184 void __init acpi_pci_slot_init(void)
0185 {
0186 dmi_check_system(acpi_pci_slot_dmi_table);
0187 }