diff options
-rw-r--r-- | drivers/pci/Makefile | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp.h | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_core.c | 25 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 23 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_ibm.c | 6 | ||||
-rw-r--r-- | drivers/pci/hotplug/cpci_hotplug_core.c | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/cpqphp_core.c | 4 | ||||
-rw-r--r-- | drivers/pci/hotplug/fakephp.c | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/ibmphp_ebda.c | 3 | ||||
-rw-r--r-- | drivers/pci/hotplug/pci_hotplug_core.c | 258 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 32 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpadlpar_sysfs.c | 5 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpaphp_slot.c | 44 | ||||
-rw-r--r-- | drivers/pci/hotplug/sgi_hotplug.c | 10 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_core.c | 20 | ||||
-rw-r--r-- | drivers/pci/pci.h | 13 | ||||
-rw-r--r-- | drivers/pci/probe.c | 1 | ||||
-rw-r--r-- | drivers/pci/slot.c | 233 | ||||
-rw-r--r-- | include/linux/pci.h | 19 | ||||
-rw-r--r-- | include/linux/pci_hotplug.h | 12 |
20 files changed, 422 insertions, 293 deletions
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 4d1ce2e7361e..7d63f8ced24b 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | # Makefile for the PCI bus specific drivers. | 2 | # Makefile for the PCI bus specific drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \ | 5 | obj-y += access.o bus.o probe.o remove.o pci.o quirks.o slot.o \ |
6 | pci-driver.o search.o pci-sysfs.o rom.o setup-res.o | 6 | pci-driver.o search.o pci-sysfs.o rom.o setup-res.o |
7 | obj-$(CONFIG_PROC_FS) += proc.o | 7 | obj-$(CONFIG_PROC_FS) += proc.o |
8 | 8 | ||
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 7a29164d4b32..eecf7cbf4139 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h | |||
@@ -215,7 +215,6 @@ extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot); | |||
215 | extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot); | 215 | extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot); |
216 | extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); | 216 | extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); |
217 | extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); | 217 | extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); |
218 | extern u32 acpiphp_get_address (struct acpiphp_slot *slot); | ||
219 | 218 | ||
220 | /* variables */ | 219 | /* variables */ |
221 | extern int acpiphp_debug; | 220 | extern int acpiphp_debug; |
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 7af68ba27903..0e496e866a84 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c | |||
@@ -70,7 +70,6 @@ static int disable_slot (struct hotplug_slot *slot); | |||
70 | static int set_attention_status (struct hotplug_slot *slot, u8 value); | 70 | static int set_attention_status (struct hotplug_slot *slot, u8 value); |
71 | static int get_power_status (struct hotplug_slot *slot, u8 *value); | 71 | static int get_power_status (struct hotplug_slot *slot, u8 *value); |
72 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); | 72 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); |
73 | static int get_address (struct hotplug_slot *slot, u32 *value); | ||
74 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); | 73 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); |
75 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); | 74 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); |
76 | 75 | ||
@@ -83,7 +82,6 @@ static struct hotplug_slot_ops acpi_hotplug_slot_ops = { | |||
83 | .get_attention_status = get_attention_status, | 82 | .get_attention_status = get_attention_status, |
84 | .get_latch_status = get_latch_status, | 83 | .get_latch_status = get_latch_status, |
85 | .get_adapter_status = get_adapter_status, | 84 | .get_adapter_status = get_adapter_status, |
86 | .get_address = get_address, | ||
87 | }; | 85 | }; |
88 | 86 | ||
89 | 87 | ||
@@ -274,23 +272,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) | |||
274 | return 0; | 272 | return 0; |
275 | } | 273 | } |
276 | 274 | ||
277 | |||
278 | /** | ||
279 | * get_address - get pci address of a slot | ||
280 | * @hotplug_slot: slot to get status | ||
281 | * @value: pointer to struct pci_busdev (seg, bus, dev) | ||
282 | */ | ||
283 | static int get_address(struct hotplug_slot *hotplug_slot, u32 *value) | ||
284 | { | ||
285 | struct slot *slot = hotplug_slot->private; | ||
286 | |||
287 | dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); | ||
288 | |||
289 | *value = acpiphp_get_address(slot->acpi_slot); | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int __init init_acpi(void) | 275 | static int __init init_acpi(void) |
295 | { | 276 | { |
296 | int retval; | 277 | int retval; |
@@ -357,7 +338,11 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot) | |||
357 | acpiphp_slot->slot = slot; | 338 | acpiphp_slot->slot = slot; |
358 | snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun); | 339 | snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun); |
359 | 340 | ||
360 | retval = pci_hp_register(slot->hotplug_slot); | 341 | retval = pci_hp_register(slot->hotplug_slot, |
342 | acpiphp_slot->bridge->pci_bus, | ||
343 | acpiphp_slot->device); | ||
344 | if (retval == -EBUSY) | ||
345 | goto error_hpslot; | ||
361 | if (retval) { | 346 | if (retval) { |
362 | err("pci_hp_register failed with error %d\n", retval); | 347 | err("pci_hp_register failed with error %d\n", retval); |
363 | goto error_hpslot; | 348 | goto error_hpslot; |
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 648596d469f6..9342c848db29 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -258,7 +258,12 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
258 | bridge->pci_bus->number, slot->device); | 258 | bridge->pci_bus->number, slot->device); |
259 | retval = acpiphp_register_hotplug_slot(slot); | 259 | retval = acpiphp_register_hotplug_slot(slot); |
260 | if (retval) { | 260 | if (retval) { |
261 | warn("acpiphp_register_hotplug_slot failed(err code = 0x%x)\n", retval); | 261 | if (retval == -EBUSY) |
262 | warn("Slot %d already registered by another " | ||
263 | "hotplug driver\n", slot->sun); | ||
264 | else | ||
265 | warn("acpiphp_register_hotplug_slot failed " | ||
266 | "(err code = 0x%x)\n", retval); | ||
262 | goto err_exit; | 267 | goto err_exit; |
263 | } | 268 | } |
264 | } | 269 | } |
@@ -1867,19 +1872,3 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) | |||
1867 | 1872 | ||
1868 | return (sta == 0) ? 0 : 1; | 1873 | return (sta == 0) ? 0 : 1; |
1869 | } | 1874 | } |
1870 | |||
1871 | |||
1872 | /* | ||
1873 | * pci address (seg/bus/dev) | ||
1874 | */ | ||
1875 | u32 acpiphp_get_address(struct acpiphp_slot *slot) | ||
1876 | { | ||
1877 | u32 address; | ||
1878 | struct pci_bus *pci_bus = slot->bridge->pci_bus; | ||
1879 | |||
1880 | address = (pci_domain_nr(pci_bus) << 16) | | ||
1881 | (pci_bus->number << 8) | | ||
1882 | slot->device; | ||
1883 | |||
1884 | return address; | ||
1885 | } | ||
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index ede9051fdb5d..2b7c45e39370 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c | |||
@@ -33,8 +33,10 @@ | |||
33 | #include <linux/kobject.h> | 33 | #include <linux/kobject.h> |
34 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
35 | #include <linux/moduleparam.h> | 35 | #include <linux/moduleparam.h> |
36 | #include <linux/pci.h> | ||
36 | 37 | ||
37 | #include "acpiphp.h" | 38 | #include "acpiphp.h" |
39 | #include "../pci.h" | ||
38 | 40 | ||
39 | #define DRIVER_VERSION "1.0.1" | 41 | #define DRIVER_VERSION "1.0.1" |
40 | #define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>" | 42 | #define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>" |
@@ -430,7 +432,7 @@ static int __init ibm_acpiphp_init(void) | |||
430 | int retval = 0; | 432 | int retval = 0; |
431 | acpi_status status; | 433 | acpi_status status; |
432 | struct acpi_device *device; | 434 | struct acpi_device *device; |
433 | struct kobject *sysdir = &pci_hotplug_slots_kset->kobj; | 435 | struct kobject *sysdir = &pci_slots_kset->kobj; |
434 | 436 | ||
435 | dbg("%s\n", __func__); | 437 | dbg("%s\n", __func__); |
436 | 438 | ||
@@ -477,7 +479,7 @@ init_return: | |||
477 | static void __exit ibm_acpiphp_exit(void) | 479 | static void __exit ibm_acpiphp_exit(void) |
478 | { | 480 | { |
479 | acpi_status status; | 481 | acpi_status status; |
480 | struct kobject *sysdir = &pci_hotplug_slots_kset->kobj; | 482 | struct kobject *sysdir = &pci_slots_kset->kobj; |
481 | 483 | ||
482 | dbg("%s\n", __func__); | 484 | dbg("%s\n", __func__); |
483 | 485 | ||
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index d8a6b80ab42a..935947991dc9 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c | |||
@@ -285,7 +285,7 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) | |||
285 | info->attention_status = cpci_get_attention_status(slot); | 285 | info->attention_status = cpci_get_attention_status(slot); |
286 | 286 | ||
287 | dbg("registering slot %s", slot->hotplug_slot->name); | 287 | dbg("registering slot %s", slot->hotplug_slot->name); |
288 | status = pci_hp_register(slot->hotplug_slot); | 288 | status = pci_hp_register(slot->hotplug_slot, bus, i); |
289 | if (status) { | 289 | if (status) { |
290 | err("pci_hp_register failed with error %d", status); | 290 | err("pci_hp_register failed with error %d", status); |
291 | goto error_name; | 291 | goto error_name; |
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 36b115b27b0b..54defec51d08 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c | |||
@@ -434,7 +434,9 @@ static int ctrl_slot_setup(struct controller *ctrl, | |||
434 | slot->bus, slot->device, | 434 | slot->bus, slot->device, |
435 | slot->number, ctrl->slot_device_offset, | 435 | slot->number, ctrl->slot_device_offset, |
436 | slot_number); | 436 | slot_number); |
437 | result = pci_hp_register(hotplug_slot); | 437 | result = pci_hp_register(hotplug_slot, |
438 | ctrl->pci_dev->subordinate, | ||
439 | slot->device); | ||
438 | if (result) { | 440 | if (result) { |
439 | err("pci_hp_register failed with error %d\n", result); | 441 | err("pci_hp_register failed with error %d\n", result); |
440 | goto error_name; | 442 | goto error_name; |
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index b57223f7e830..40337a06c18a 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c | |||
@@ -126,7 +126,7 @@ static int add_slot(struct pci_dev *dev) | |||
126 | slot->release = &dummy_release; | 126 | slot->release = &dummy_release; |
127 | slot->private = dslot; | 127 | slot->private = dslot; |
128 | 128 | ||
129 | retval = pci_hp_register(slot); | 129 | retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn)); |
130 | if (retval) { | 130 | if (retval) { |
131 | err("pci_hp_register failed with error %d\n", retval); | 131 | err("pci_hp_register failed with error %d\n", retval); |
132 | goto error_dslot; | 132 | goto error_dslot; |
diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c index dca7efc14be2..8467d0287325 100644 --- a/drivers/pci/hotplug/ibmphp_ebda.c +++ b/drivers/pci/hotplug/ibmphp_ebda.c | |||
@@ -1001,7 +1001,8 @@ static int __init ebda_rsrc_controller (void) | |||
1001 | tmp_slot = list_entry (list, struct slot, ibm_slot_list); | 1001 | tmp_slot = list_entry (list, struct slot, ibm_slot_list); |
1002 | 1002 | ||
1003 | snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot)); | 1003 | snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot)); |
1004 | pci_hp_register (tmp_slot->hotplug_slot); | 1004 | pci_hp_register(tmp_slot->hotplug_slot, |
1005 | pci_find_bus(0, tmp_slot->bus), tmp_slot->device); | ||
1005 | } | 1006 | } |
1006 | 1007 | ||
1007 | print_ebda_hpc (); | 1008 | print_ebda_hpc (); |
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index a11021e8ce37..4df31f375197 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/pci.h> | 40 | #include <linux/pci.h> |
41 | #include <linux/pci_hotplug.h> | 41 | #include <linux/pci_hotplug.h> |
42 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
43 | #include "../pci.h" | ||
43 | 44 | ||
44 | #define MY_NAME "pci_hotplug" | 45 | #define MY_NAME "pci_hotplug" |
45 | 46 | ||
@@ -60,41 +61,7 @@ static int debug; | |||
60 | ////////////////////////////////////////////////////////////////// | 61 | ////////////////////////////////////////////////////////////////// |
61 | 62 | ||
62 | static LIST_HEAD(pci_hotplug_slot_list); | 63 | static LIST_HEAD(pci_hotplug_slot_list); |
63 | 64 | static DEFINE_SPINLOCK(pci_hotplug_slot_list_lock); | |
64 | struct kset *pci_hotplug_slots_kset; | ||
65 | |||
66 | static ssize_t hotplug_slot_attr_show(struct kobject *kobj, | ||
67 | struct attribute *attr, char *buf) | ||
68 | { | ||
69 | struct hotplug_slot *slot = to_hotplug_slot(kobj); | ||
70 | struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr); | ||
71 | return attribute->show ? attribute->show(slot, buf) : -EIO; | ||
72 | } | ||
73 | |||
74 | static ssize_t hotplug_slot_attr_store(struct kobject *kobj, | ||
75 | struct attribute *attr, const char *buf, size_t len) | ||
76 | { | ||
77 | struct hotplug_slot *slot = to_hotplug_slot(kobj); | ||
78 | struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr); | ||
79 | return attribute->store ? attribute->store(slot, buf, len) : -EIO; | ||
80 | } | ||
81 | |||
82 | static struct sysfs_ops hotplug_slot_sysfs_ops = { | ||
83 | .show = hotplug_slot_attr_show, | ||
84 | .store = hotplug_slot_attr_store, | ||
85 | }; | ||
86 | |||
87 | static void hotplug_slot_release(struct kobject *kobj) | ||
88 | { | ||
89 | struct hotplug_slot *slot = to_hotplug_slot(kobj); | ||
90 | if (slot->release) | ||
91 | slot->release(slot); | ||
92 | } | ||
93 | |||
94 | static struct kobj_type hotplug_slot_ktype = { | ||
95 | .sysfs_ops = &hotplug_slot_sysfs_ops, | ||
96 | .release = &hotplug_slot_release, | ||
97 | }; | ||
98 | 65 | ||
99 | /* these strings match up with the values in pci_bus_speed */ | 66 | /* these strings match up with the values in pci_bus_speed */ |
100 | static char *pci_bus_speed_strings[] = { | 67 | static char *pci_bus_speed_strings[] = { |
@@ -149,16 +116,15 @@ GET_STATUS(power_status, u8) | |||
149 | GET_STATUS(attention_status, u8) | 116 | GET_STATUS(attention_status, u8) |
150 | GET_STATUS(latch_status, u8) | 117 | GET_STATUS(latch_status, u8) |
151 | GET_STATUS(adapter_status, u8) | 118 | GET_STATUS(adapter_status, u8) |
152 | GET_STATUS(address, u32) | ||
153 | GET_STATUS(max_bus_speed, enum pci_bus_speed) | 119 | GET_STATUS(max_bus_speed, enum pci_bus_speed) |
154 | GET_STATUS(cur_bus_speed, enum pci_bus_speed) | 120 | GET_STATUS(cur_bus_speed, enum pci_bus_speed) |
155 | 121 | ||
156 | static ssize_t power_read_file (struct hotplug_slot *slot, char *buf) | 122 | static ssize_t power_read_file(struct pci_slot *slot, char *buf) |
157 | { | 123 | { |
158 | int retval; | 124 | int retval; |
159 | u8 value; | 125 | u8 value; |
160 | 126 | ||
161 | retval = get_power_status (slot, &value); | 127 | retval = get_power_status(slot->hotplug, &value); |
162 | if (retval) | 128 | if (retval) |
163 | goto exit; | 129 | goto exit; |
164 | retval = sprintf (buf, "%d\n", value); | 130 | retval = sprintf (buf, "%d\n", value); |
@@ -166,9 +132,10 @@ exit: | |||
166 | return retval; | 132 | return retval; |
167 | } | 133 | } |
168 | 134 | ||
169 | static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf, | 135 | static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf, |
170 | size_t count) | 136 | size_t count) |
171 | { | 137 | { |
138 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
172 | unsigned long lpower; | 139 | unsigned long lpower; |
173 | u8 power; | 140 | u8 power; |
174 | int retval = 0; | 141 | int retval = 0; |
@@ -204,29 +171,30 @@ exit: | |||
204 | return count; | 171 | return count; |
205 | } | 172 | } |
206 | 173 | ||
207 | static struct hotplug_slot_attribute hotplug_slot_attr_power = { | 174 | static struct pci_slot_attribute hotplug_slot_attr_power = { |
208 | .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR}, | 175 | .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR}, |
209 | .show = power_read_file, | 176 | .show = power_read_file, |
210 | .store = power_write_file | 177 | .store = power_write_file |
211 | }; | 178 | }; |
212 | 179 | ||
213 | static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf) | 180 | static ssize_t attention_read_file(struct pci_slot *slot, char *buf) |
214 | { | 181 | { |
215 | int retval; | 182 | int retval; |
216 | u8 value; | 183 | u8 value; |
217 | 184 | ||
218 | retval = get_attention_status (slot, &value); | 185 | retval = get_attention_status(slot->hotplug, &value); |
219 | if (retval) | 186 | if (retval) |
220 | goto exit; | 187 | goto exit; |
221 | retval = sprintf (buf, "%d\n", value); | 188 | retval = sprintf(buf, "%d\n", value); |
222 | 189 | ||
223 | exit: | 190 | exit: |
224 | return retval; | 191 | return retval; |
225 | } | 192 | } |
226 | 193 | ||
227 | static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf, | 194 | static ssize_t attention_write_file(struct pci_slot *slot, const char *buf, |
228 | size_t count) | 195 | size_t count) |
229 | { | 196 | { |
197 | struct hotplug_slot_ops *ops = slot->hotplug->ops; | ||
230 | unsigned long lattention; | 198 | unsigned long lattention; |
231 | u8 attention; | 199 | u8 attention; |
232 | int retval = 0; | 200 | int retval = 0; |
@@ -235,13 +203,13 @@ static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf, | |||
235 | attention = (u8)(lattention & 0xff); | 203 | attention = (u8)(lattention & 0xff); |
236 | dbg (" - attention = %d\n", attention); | 204 | dbg (" - attention = %d\n", attention); |
237 | 205 | ||
238 | if (!try_module_get(slot->ops->owner)) { | 206 | if (!try_module_get(ops->owner)) { |
239 | retval = -ENODEV; | 207 | retval = -ENODEV; |
240 | goto exit; | 208 | goto exit; |
241 | } | 209 | } |
242 | if (slot->ops->set_attention_status) | 210 | if (ops->set_attention_status) |
243 | retval = slot->ops->set_attention_status(slot, attention); | 211 | retval = ops->set_attention_status(slot->hotplug, attention); |
244 | module_put(slot->ops->owner); | 212 | module_put(ops->owner); |
245 | 213 | ||
246 | exit: | 214 | exit: |
247 | if (retval) | 215 | if (retval) |
@@ -249,18 +217,18 @@ exit: | |||
249 | return count; | 217 | return count; |
250 | } | 218 | } |
251 | 219 | ||
252 | static struct hotplug_slot_attribute hotplug_slot_attr_attention = { | 220 | static struct pci_slot_attribute hotplug_slot_attr_attention = { |
253 | .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR}, | 221 | .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR}, |
254 | .show = attention_read_file, | 222 | .show = attention_read_file, |
255 | .store = attention_write_file | 223 | .store = attention_write_file |
256 | }; | 224 | }; |
257 | 225 | ||
258 | static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf) | 226 | static ssize_t latch_read_file(struct pci_slot *slot, char *buf) |
259 | { | 227 | { |
260 | int retval; | 228 | int retval; |
261 | u8 value; | 229 | u8 value; |
262 | 230 | ||
263 | retval = get_latch_status (slot, &value); | 231 | retval = get_latch_status(slot->hotplug, &value); |
264 | if (retval) | 232 | if (retval) |
265 | goto exit; | 233 | goto exit; |
266 | retval = sprintf (buf, "%d\n", value); | 234 | retval = sprintf (buf, "%d\n", value); |
@@ -269,17 +237,17 @@ exit: | |||
269 | return retval; | 237 | return retval; |
270 | } | 238 | } |
271 | 239 | ||
272 | static struct hotplug_slot_attribute hotplug_slot_attr_latch = { | 240 | static struct pci_slot_attribute hotplug_slot_attr_latch = { |
273 | .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO}, | 241 | .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO}, |
274 | .show = latch_read_file, | 242 | .show = latch_read_file, |
275 | }; | 243 | }; |
276 | 244 | ||
277 | static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf) | 245 | static ssize_t presence_read_file(struct pci_slot *slot, char *buf) |
278 | { | 246 | { |
279 | int retval; | 247 | int retval; |
280 | u8 value; | 248 | u8 value; |
281 | 249 | ||
282 | retval = get_adapter_status (slot, &value); | 250 | retval = get_adapter_status(slot->hotplug, &value); |
283 | if (retval) | 251 | if (retval) |
284 | goto exit; | 252 | goto exit; |
285 | retval = sprintf (buf, "%d\n", value); | 253 | retval = sprintf (buf, "%d\n", value); |
@@ -288,42 +256,20 @@ exit: | |||
288 | return retval; | 256 | return retval; |
289 | } | 257 | } |
290 | 258 | ||
291 | static struct hotplug_slot_attribute hotplug_slot_attr_presence = { | 259 | static struct pci_slot_attribute hotplug_slot_attr_presence = { |
292 | .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO}, | 260 | .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO}, |
293 | .show = presence_read_file, | 261 | .show = presence_read_file, |
294 | }; | 262 | }; |
295 | 263 | ||
296 | static ssize_t address_read_file (struct hotplug_slot *slot, char *buf) | ||
297 | { | ||
298 | int retval; | ||
299 | u32 address; | ||
300 | |||
301 | retval = get_address (slot, &address); | ||
302 | if (retval) | ||
303 | goto exit; | ||
304 | retval = sprintf (buf, "%04x:%02x:%02x\n", | ||
305 | (address >> 16) & 0xffff, | ||
306 | (address >> 8) & 0xff, | ||
307 | address & 0xff); | ||
308 | |||
309 | exit: | ||
310 | return retval; | ||
311 | } | ||
312 | |||
313 | static struct hotplug_slot_attribute hotplug_slot_attr_address = { | ||
314 | .attr = {.name = "address", .mode = S_IFREG | S_IRUGO}, | ||
315 | .show = address_read_file, | ||
316 | }; | ||
317 | |||
318 | static char *unknown_speed = "Unknown bus speed"; | 264 | static char *unknown_speed = "Unknown bus speed"; |
319 | 265 | ||
320 | static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf) | 266 | static ssize_t max_bus_speed_read_file(struct pci_slot *slot, char *buf) |
321 | { | 267 | { |
322 | char *speed_string; | 268 | char *speed_string; |
323 | int retval; | 269 | int retval; |
324 | enum pci_bus_speed value; | 270 | enum pci_bus_speed value; |
325 | 271 | ||
326 | retval = get_max_bus_speed (slot, &value); | 272 | retval = get_max_bus_speed(slot->hotplug, &value); |
327 | if (retval) | 273 | if (retval) |
328 | goto exit; | 274 | goto exit; |
329 | 275 | ||
@@ -338,18 +284,18 @@ exit: | |||
338 | return retval; | 284 | return retval; |
339 | } | 285 | } |
340 | 286 | ||
341 | static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = { | 287 | static struct pci_slot_attribute hotplug_slot_attr_max_bus_speed = { |
342 | .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO}, | 288 | .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO}, |
343 | .show = max_bus_speed_read_file, | 289 | .show = max_bus_speed_read_file, |
344 | }; | 290 | }; |
345 | 291 | ||
346 | static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf) | 292 | static ssize_t cur_bus_speed_read_file(struct pci_slot *slot, char *buf) |
347 | { | 293 | { |
348 | char *speed_string; | 294 | char *speed_string; |
349 | int retval; | 295 | int retval; |
350 | enum pci_bus_speed value; | 296 | enum pci_bus_speed value; |
351 | 297 | ||
352 | retval = get_cur_bus_speed (slot, &value); | 298 | retval = get_cur_bus_speed(slot->hotplug, &value); |
353 | if (retval) | 299 | if (retval) |
354 | goto exit; | 300 | goto exit; |
355 | 301 | ||
@@ -364,14 +310,15 @@ exit: | |||
364 | return retval; | 310 | return retval; |
365 | } | 311 | } |
366 | 312 | ||
367 | static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = { | 313 | static struct pci_slot_attribute hotplug_slot_attr_cur_bus_speed = { |
368 | .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO}, | 314 | .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO}, |
369 | .show = cur_bus_speed_read_file, | 315 | .show = cur_bus_speed_read_file, |
370 | }; | 316 | }; |
371 | 317 | ||
372 | static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf, | 318 | static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf, |
373 | size_t count) | 319 | size_t count) |
374 | { | 320 | { |
321 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
375 | unsigned long ltest; | 322 | unsigned long ltest; |
376 | u32 test; | 323 | u32 test; |
377 | int retval = 0; | 324 | int retval = 0; |
@@ -394,13 +341,14 @@ exit: | |||
394 | return count; | 341 | return count; |
395 | } | 342 | } |
396 | 343 | ||
397 | static struct hotplug_slot_attribute hotplug_slot_attr_test = { | 344 | static struct pci_slot_attribute hotplug_slot_attr_test = { |
398 | .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR}, | 345 | .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR}, |
399 | .store = test_write_file | 346 | .store = test_write_file |
400 | }; | 347 | }; |
401 | 348 | ||
402 | static int has_power_file (struct hotplug_slot *slot) | 349 | static int has_power_file(struct pci_slot *pci_slot) |
403 | { | 350 | { |
351 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
404 | if ((!slot) || (!slot->ops)) | 352 | if ((!slot) || (!slot->ops)) |
405 | return -ENODEV; | 353 | return -ENODEV; |
406 | if ((slot->ops->enable_slot) || | 354 | if ((slot->ops->enable_slot) || |
@@ -410,8 +358,9 @@ static int has_power_file (struct hotplug_slot *slot) | |||
410 | return -ENOENT; | 358 | return -ENOENT; |
411 | } | 359 | } |
412 | 360 | ||
413 | static int has_attention_file (struct hotplug_slot *slot) | 361 | static int has_attention_file(struct pci_slot *pci_slot) |
414 | { | 362 | { |
363 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
415 | if ((!slot) || (!slot->ops)) | 364 | if ((!slot) || (!slot->ops)) |
416 | return -ENODEV; | 365 | return -ENODEV; |
417 | if ((slot->ops->set_attention_status) || | 366 | if ((slot->ops->set_attention_status) || |
@@ -420,8 +369,9 @@ static int has_attention_file (struct hotplug_slot *slot) | |||
420 | return -ENOENT; | 369 | return -ENOENT; |
421 | } | 370 | } |
422 | 371 | ||
423 | static int has_latch_file (struct hotplug_slot *slot) | 372 | static int has_latch_file(struct pci_slot *pci_slot) |
424 | { | 373 | { |
374 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
425 | if ((!slot) || (!slot->ops)) | 375 | if ((!slot) || (!slot->ops)) |
426 | return -ENODEV; | 376 | return -ENODEV; |
427 | if (slot->ops->get_latch_status) | 377 | if (slot->ops->get_latch_status) |
@@ -429,8 +379,9 @@ static int has_latch_file (struct hotplug_slot *slot) | |||
429 | return -ENOENT; | 379 | return -ENOENT; |
430 | } | 380 | } |
431 | 381 | ||
432 | static int has_adapter_file (struct hotplug_slot *slot) | 382 | static int has_adapter_file(struct pci_slot *pci_slot) |
433 | { | 383 | { |
384 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
434 | if ((!slot) || (!slot->ops)) | 385 | if ((!slot) || (!slot->ops)) |
435 | return -ENODEV; | 386 | return -ENODEV; |
436 | if (slot->ops->get_adapter_status) | 387 | if (slot->ops->get_adapter_status) |
@@ -438,17 +389,9 @@ static int has_adapter_file (struct hotplug_slot *slot) | |||
438 | return -ENOENT; | 389 | return -ENOENT; |
439 | } | 390 | } |
440 | 391 | ||
441 | static int has_address_file (struct hotplug_slot *slot) | 392 | static int has_max_bus_speed_file(struct pci_slot *pci_slot) |
442 | { | ||
443 | if ((!slot) || (!slot->ops)) | ||
444 | return -ENODEV; | ||
445 | if (slot->ops->get_address) | ||
446 | return 0; | ||
447 | return -ENOENT; | ||
448 | } | ||
449 | |||
450 | static int has_max_bus_speed_file (struct hotplug_slot *slot) | ||
451 | { | 393 | { |
394 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
452 | if ((!slot) || (!slot->ops)) | 395 | if ((!slot) || (!slot->ops)) |
453 | return -ENODEV; | 396 | return -ENODEV; |
454 | if (slot->ops->get_max_bus_speed) | 397 | if (slot->ops->get_max_bus_speed) |
@@ -456,8 +399,9 @@ static int has_max_bus_speed_file (struct hotplug_slot *slot) | |||
456 | return -ENOENT; | 399 | return -ENOENT; |
457 | } | 400 | } |
458 | 401 | ||
459 | static int has_cur_bus_speed_file (struct hotplug_slot *slot) | 402 | static int has_cur_bus_speed_file(struct pci_slot *pci_slot) |
460 | { | 403 | { |
404 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
461 | if ((!slot) || (!slot->ops)) | 405 | if ((!slot) || (!slot->ops)) |
462 | return -ENODEV; | 406 | return -ENODEV; |
463 | if (slot->ops->get_cur_bus_speed) | 407 | if (slot->ops->get_cur_bus_speed) |
@@ -465,8 +409,9 @@ static int has_cur_bus_speed_file (struct hotplug_slot *slot) | |||
465 | return -ENOENT; | 409 | return -ENOENT; |
466 | } | 410 | } |
467 | 411 | ||
468 | static int has_test_file (struct hotplug_slot *slot) | 412 | static int has_test_file(struct pci_slot *pci_slot) |
469 | { | 413 | { |
414 | struct hotplug_slot *slot = pci_slot->hotplug; | ||
470 | if ((!slot) || (!slot->ops)) | 415 | if ((!slot) || (!slot->ops)) |
471 | return -ENODEV; | 416 | return -ENODEV; |
472 | if (slot->ops->hardware_test) | 417 | if (slot->ops->hardware_test) |
@@ -474,7 +419,7 @@ static int has_test_file (struct hotplug_slot *slot) | |||
474 | return -ENOENT; | 419 | return -ENOENT; |
475 | } | 420 | } |
476 | 421 | ||
477 | static int fs_add_slot (struct hotplug_slot *slot) | 422 | static int fs_add_slot(struct pci_slot *slot) |
478 | { | 423 | { |
479 | int retval = 0; | 424 | int retval = 0; |
480 | 425 | ||
@@ -505,13 +450,6 @@ static int fs_add_slot (struct hotplug_slot *slot) | |||
505 | goto exit_adapter; | 450 | goto exit_adapter; |
506 | } | 451 | } |
507 | 452 | ||
508 | if (has_address_file(slot) == 0) { | ||
509 | retval = sysfs_create_file(&slot->kobj, | ||
510 | &hotplug_slot_attr_address.attr); | ||
511 | if (retval) | ||
512 | goto exit_address; | ||
513 | } | ||
514 | |||
515 | if (has_max_bus_speed_file(slot) == 0) { | 453 | if (has_max_bus_speed_file(slot) == 0) { |
516 | retval = sysfs_create_file(&slot->kobj, | 454 | retval = sysfs_create_file(&slot->kobj, |
517 | &hotplug_slot_attr_max_bus_speed.attr); | 455 | &hotplug_slot_attr_max_bus_speed.attr); |
@@ -544,10 +482,6 @@ exit_cur_speed: | |||
544 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); | 482 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); |
545 | 483 | ||
546 | exit_max_speed: | 484 | exit_max_speed: |
547 | if (has_address_file(slot) == 0) | ||
548 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr); | ||
549 | |||
550 | exit_address: | ||
551 | if (has_adapter_file(slot) == 0) | 485 | if (has_adapter_file(slot) == 0) |
552 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); | 486 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); |
553 | 487 | ||
@@ -567,7 +501,7 @@ exit: | |||
567 | return retval; | 501 | return retval; |
568 | } | 502 | } |
569 | 503 | ||
570 | static void fs_remove_slot (struct hotplug_slot *slot) | 504 | static void fs_remove_slot(struct pci_slot *slot) |
571 | { | 505 | { |
572 | if (has_power_file(slot) == 0) | 506 | if (has_power_file(slot) == 0) |
573 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); | 507 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); |
@@ -581,9 +515,6 @@ static void fs_remove_slot (struct hotplug_slot *slot) | |||
581 | if (has_adapter_file(slot) == 0) | 515 | if (has_adapter_file(slot) == 0) |
582 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); | 516 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); |
583 | 517 | ||
584 | if (has_address_file(slot) == 0) | ||
585 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr); | ||
586 | |||
587 | if (has_max_bus_speed_file(slot) == 0) | 518 | if (has_max_bus_speed_file(slot) == 0) |
588 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); | 519 | sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); |
589 | 520 | ||
@@ -599,12 +530,16 @@ static struct hotplug_slot *get_slot_from_name (const char *name) | |||
599 | struct hotplug_slot *slot; | 530 | struct hotplug_slot *slot; |
600 | struct list_head *tmp; | 531 | struct list_head *tmp; |
601 | 532 | ||
533 | spin_lock(&pci_hotplug_slot_list_lock); | ||
602 | list_for_each (tmp, &pci_hotplug_slot_list) { | 534 | list_for_each (tmp, &pci_hotplug_slot_list) { |
603 | slot = list_entry (tmp, struct hotplug_slot, slot_list); | 535 | slot = list_entry (tmp, struct hotplug_slot, slot_list); |
604 | if (strcmp(slot->name, name) == 0) | 536 | if (strcmp(slot->name, name) == 0) |
605 | return slot; | 537 | goto out; |
606 | } | 538 | } |
607 | return NULL; | 539 | slot = NULL; |
540 | out: | ||
541 | spin_unlock(&pci_hotplug_slot_list_lock); | ||
542 | return slot; | ||
608 | } | 543 | } |
609 | 544 | ||
610 | /** | 545 | /** |
@@ -616,9 +551,10 @@ static struct hotplug_slot *get_slot_from_name (const char *name) | |||
616 | * | 551 | * |
617 | * Returns 0 if successful, anything else for an error. | 552 | * Returns 0 if successful, anything else for an error. |
618 | */ | 553 | */ |
619 | int pci_hp_register (struct hotplug_slot *slot) | 554 | int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr) |
620 | { | 555 | { |
621 | int result; | 556 | int result; |
557 | struct pci_slot *pci_slot; | ||
622 | struct hotplug_slot *tmp; | 558 | struct hotplug_slot *tmp; |
623 | 559 | ||
624 | if (slot == NULL) | 560 | if (slot == NULL) |
@@ -636,19 +572,28 @@ int pci_hp_register (struct hotplug_slot *slot) | |||
636 | if (tmp) | 572 | if (tmp) |
637 | return -EEXIST; | 573 | return -EEXIST; |
638 | 574 | ||
639 | slot->kobj.kset = pci_hotplug_slots_kset; | 575 | pci_slot = pci_create_slot(bus, slot_nr, slot->name); |
640 | result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL, | 576 | if (IS_ERR(pci_slot)) |
641 | "%s", slot->name); | 577 | return PTR_ERR(pci_slot); |
642 | if (result) { | 578 | |
643 | err("Unable to register kobject '%s'", slot->name); | 579 | if (pci_slot->hotplug) { |
644 | return -EINVAL; | 580 | dbg("%s: already claimed\n", __func__); |
581 | pci_destroy_slot(pci_slot); | ||
582 | return -EBUSY; | ||
645 | } | 583 | } |
646 | 584 | ||
647 | list_add (&slot->slot_list, &pci_hotplug_slot_list); | 585 | slot->pci_slot = pci_slot; |
586 | pci_slot->hotplug = slot; | ||
587 | |||
588 | spin_lock(&pci_hotplug_slot_list_lock); | ||
589 | list_add(&slot->slot_list, &pci_hotplug_slot_list); | ||
590 | spin_unlock(&pci_hotplug_slot_list_lock); | ||
591 | |||
592 | result = fs_add_slot(pci_slot); | ||
593 | kobject_uevent(&pci_slot->kobj, KOBJ_ADD); | ||
594 | dbg("Added slot %s to the list\n", slot->name); | ||
595 | |||
648 | 596 | ||
649 | result = fs_add_slot (slot); | ||
650 | kobject_uevent(&slot->kobj, KOBJ_ADD); | ||
651 | dbg ("Added slot %s to the list\n", slot->name); | ||
652 | return result; | 597 | return result; |
653 | } | 598 | } |
654 | 599 | ||
@@ -661,22 +606,30 @@ int pci_hp_register (struct hotplug_slot *slot) | |||
661 | * | 606 | * |
662 | * Returns 0 if successful, anything else for an error. | 607 | * Returns 0 if successful, anything else for an error. |
663 | */ | 608 | */ |
664 | int pci_hp_deregister (struct hotplug_slot *slot) | 609 | int pci_hp_deregister(struct hotplug_slot *hotplug) |
665 | { | 610 | { |
666 | struct hotplug_slot *temp; | 611 | struct hotplug_slot *temp; |
612 | struct pci_slot *slot; | ||
667 | 613 | ||
668 | if (slot == NULL) | 614 | if (!hotplug) |
669 | return -ENODEV; | 615 | return -ENODEV; |
670 | 616 | ||
671 | temp = get_slot_from_name (slot->name); | 617 | temp = get_slot_from_name(hotplug->name); |
672 | if (temp != slot) { | 618 | if (temp != hotplug) |
673 | return -ENODEV; | 619 | return -ENODEV; |
674 | } | ||
675 | list_del (&slot->slot_list); | ||
676 | 620 | ||
677 | fs_remove_slot (slot); | 621 | spin_lock(&pci_hotplug_slot_list_lock); |
678 | dbg ("Removed slot %s from the list\n", slot->name); | 622 | list_del(&hotplug->slot_list); |
679 | kobject_put(&slot->kobj); | 623 | spin_unlock(&pci_hotplug_slot_list_lock); |
624 | |||
625 | slot = hotplug->pci_slot; | ||
626 | fs_remove_slot(slot); | ||
627 | dbg("Removed slot %s from the list\n", hotplug->name); | ||
628 | |||
629 | hotplug->release(hotplug); | ||
630 | slot->hotplug = NULL; | ||
631 | pci_destroy_slot(slot); | ||
632 | |||
680 | return 0; | 633 | return 0; |
681 | } | 634 | } |
682 | 635 | ||
@@ -690,13 +643,15 @@ int pci_hp_deregister (struct hotplug_slot *slot) | |||
690 | * | 643 | * |
691 | * Returns 0 if successful, anything else for an error. | 644 | * Returns 0 if successful, anything else for an error. |
692 | */ | 645 | */ |
693 | int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, | 646 | int __must_check pci_hp_change_slot_info(struct hotplug_slot *hotplug, |
694 | struct hotplug_slot_info *info) | 647 | struct hotplug_slot_info *info) |
695 | { | 648 | { |
696 | if ((slot == NULL) || (info == NULL)) | 649 | struct pci_slot *slot; |
650 | if (!hotplug || !info) | ||
697 | return -ENODEV; | 651 | return -ENODEV; |
652 | slot = hotplug->pci_slot; | ||
698 | 653 | ||
699 | memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); | 654 | memcpy(hotplug->info, info, sizeof(struct hotplug_slot_info)); |
700 | 655 | ||
701 | return 0; | 656 | return 0; |
702 | } | 657 | } |
@@ -704,36 +659,22 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, | |||
704 | static int __init pci_hotplug_init (void) | 659 | static int __init pci_hotplug_init (void) |
705 | { | 660 | { |
706 | int result; | 661 | int result; |
707 | struct kset *pci_bus_kset; | ||
708 | 662 | ||
709 | pci_bus_kset = bus_get_kset(&pci_bus_type); | ||
710 | |||
711 | pci_hotplug_slots_kset = kset_create_and_add("slots", NULL, | ||
712 | &pci_bus_kset->kobj); | ||
713 | if (!pci_hotplug_slots_kset) { | ||
714 | result = -ENOMEM; | ||
715 | err("Register subsys error\n"); | ||
716 | goto exit; | ||
717 | } | ||
718 | result = cpci_hotplug_init(debug); | 663 | result = cpci_hotplug_init(debug); |
719 | if (result) { | 664 | if (result) { |
720 | err ("cpci_hotplug_init with error %d\n", result); | 665 | err ("cpci_hotplug_init with error %d\n", result); |
721 | goto err_subsys; | 666 | goto err_cpci; |
722 | } | 667 | } |
723 | 668 | ||
724 | info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); | 669 | info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
725 | goto exit; | ||
726 | 670 | ||
727 | err_subsys: | 671 | err_cpci: |
728 | kset_unregister(pci_hotplug_slots_kset); | ||
729 | exit: | ||
730 | return result; | 672 | return result; |
731 | } | 673 | } |
732 | 674 | ||
733 | static void __exit pci_hotplug_exit (void) | 675 | static void __exit pci_hotplug_exit (void) |
734 | { | 676 | { |
735 | cpci_hotplug_exit(); | 677 | cpci_hotplug_exit(); |
736 | kset_unregister(pci_hotplug_slots_kset); | ||
737 | } | 678 | } |
738 | 679 | ||
739 | module_init(pci_hotplug_init); | 680 | module_init(pci_hotplug_init); |
@@ -745,7 +686,6 @@ MODULE_LICENSE("GPL"); | |||
745 | module_param(debug, bool, 0644); | 686 | module_param(debug, bool, 0644); |
746 | MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); | 687 | MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); |
747 | 688 | ||
748 | EXPORT_SYMBOL_GPL(pci_hotplug_slots_kset); | ||
749 | EXPORT_SYMBOL_GPL(pci_hp_register); | 689 | EXPORT_SYMBOL_GPL(pci_hp_register); |
750 | EXPORT_SYMBOL_GPL(pci_hp_deregister); | 690 | EXPORT_SYMBOL_GPL(pci_hp_deregister); |
751 | EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); | 691 | EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 49414e9100de..7b21c86e4bff 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -72,7 +72,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value); | |||
72 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); | 72 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); |
73 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); | 73 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); |
74 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); | 74 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); |
75 | static int get_address (struct hotplug_slot *slot, u32 *value); | ||
76 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 75 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
77 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 76 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
78 | 77 | ||
@@ -85,7 +84,6 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { | |||
85 | .get_attention_status = get_attention_status, | 84 | .get_attention_status = get_attention_status, |
86 | .get_latch_status = get_latch_status, | 85 | .get_latch_status = get_latch_status, |
87 | .get_adapter_status = get_adapter_status, | 86 | .get_adapter_status = get_adapter_status, |
88 | .get_address = get_address, | ||
89 | .get_max_bus_speed = get_max_bus_speed, | 87 | .get_max_bus_speed = get_max_bus_speed, |
90 | .get_cur_bus_speed = get_cur_bus_speed, | 88 | .get_cur_bus_speed = get_cur_bus_speed, |
91 | }; | 89 | }; |
@@ -252,7 +250,9 @@ static int init_slots(struct controller *ctrl) | |||
252 | dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " | 250 | dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " |
253 | "slot_device_offset=%x\n", slot->bus, slot->device, | 251 | "slot_device_offset=%x\n", slot->bus, slot->device, |
254 | slot->hp_slot, slot->number, ctrl->slot_device_offset); | 252 | slot->hp_slot, slot->number, ctrl->slot_device_offset); |
255 | retval = pci_hp_register(hotplug_slot); | 253 | retval = pci_hp_register(hotplug_slot, |
254 | ctrl->pci_dev->subordinate, | ||
255 | slot->device); | ||
256 | if (retval) { | 256 | if (retval) { |
257 | err("pci_hp_register failed with error %d\n", retval); | 257 | err("pci_hp_register failed with error %d\n", retval); |
258 | if (retval == -EEXIST) | 258 | if (retval == -EEXIST) |
@@ -263,7 +263,7 @@ static int init_slots(struct controller *ctrl) | |||
263 | } | 263 | } |
264 | /* create additional sysfs entries */ | 264 | /* create additional sysfs entries */ |
265 | if (EMI(ctrl)) { | 265 | if (EMI(ctrl)) { |
266 | retval = sysfs_create_file(&hotplug_slot->kobj, | 266 | retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj, |
267 | &hotplug_slot_attr_lock.attr); | 267 | &hotplug_slot_attr_lock.attr); |
268 | if (retval) { | 268 | if (retval) { |
269 | pci_hp_deregister(hotplug_slot); | 269 | pci_hp_deregister(hotplug_slot); |
@@ -296,7 +296,7 @@ static void cleanup_slots(struct controller *ctrl) | |||
296 | slot = list_entry(tmp, struct slot, slot_list); | 296 | slot = list_entry(tmp, struct slot, slot_list); |
297 | list_del(&slot->slot_list); | 297 | list_del(&slot->slot_list); |
298 | if (EMI(ctrl)) | 298 | if (EMI(ctrl)) |
299 | sysfs_remove_file(&slot->hotplug_slot->kobj, | 299 | sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj, |
300 | &hotplug_slot_attr_lock.attr); | 300 | &hotplug_slot_attr_lock.attr); |
301 | cancel_delayed_work(&slot->work); | 301 | cancel_delayed_work(&slot->work); |
302 | flush_scheduled_work(); | 302 | flush_scheduled_work(); |
@@ -398,19 +398,8 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) | |||
398 | return 0; | 398 | return 0; |
399 | } | 399 | } |
400 | 400 | ||
401 | static int get_address(struct hotplug_slot *hotplug_slot, u32 *value) | 401 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, |
402 | { | 402 | enum pci_bus_speed *value) |
403 | struct slot *slot = hotplug_slot->private; | ||
404 | struct pci_bus *bus = slot->ctrl->pci_dev->subordinate; | ||
405 | |||
406 | dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); | ||
407 | |||
408 | *value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device; | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) | ||
414 | { | 403 | { |
415 | struct slot *slot = hotplug_slot->private; | 404 | struct slot *slot = hotplug_slot->private; |
416 | int retval; | 405 | int retval; |
@@ -474,7 +463,12 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ | |||
474 | /* Setup the slot information structures */ | 463 | /* Setup the slot information structures */ |
475 | rc = init_slots(ctrl); | 464 | rc = init_slots(ctrl); |
476 | if (rc) { | 465 | if (rc) { |
477 | err("%s: slot initialization failed\n", PCIE_MODULE_NAME); | 466 | if (rc == -EBUSY) |
467 | warn("%s: slot already registered by another " | ||
468 | "hotplug driver\n", PCIE_MODULE_NAME); | ||
469 | else | ||
470 | err("%s: slot initialization failed\n", | ||
471 | PCIE_MODULE_NAME); | ||
478 | goto err_out_release_ctlr; | 472 | goto err_out_release_ctlr; |
479 | } | 473 | } |
480 | 474 | ||
diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index 779c5db71be4..a796301ea03f 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c | |||
@@ -14,8 +14,10 @@ | |||
14 | */ | 14 | */ |
15 | #include <linux/kobject.h> | 15 | #include <linux/kobject.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/pci.h> | ||
17 | #include <linux/pci_hotplug.h> | 18 | #include <linux/pci_hotplug.h> |
18 | #include "rpadlpar.h" | 19 | #include "rpadlpar.h" |
20 | #include "../pci.h" | ||
19 | 21 | ||
20 | #define DLPAR_KOBJ_NAME "control" | 22 | #define DLPAR_KOBJ_NAME "control" |
21 | 23 | ||
@@ -27,7 +29,6 @@ | |||
27 | 29 | ||
28 | #define MAX_DRC_NAME_LEN 64 | 30 | #define MAX_DRC_NAME_LEN 64 |
29 | 31 | ||
30 | |||
31 | static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr, | 32 | static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr, |
32 | const char *buf, size_t nbytes) | 33 | const char *buf, size_t nbytes) |
33 | { | 34 | { |
@@ -112,7 +113,7 @@ int dlpar_sysfs_init(void) | |||
112 | int error; | 113 | int error; |
113 | 114 | ||
114 | dlpar_kobj = kobject_create_and_add(DLPAR_KOBJ_NAME, | 115 | dlpar_kobj = kobject_create_and_add(DLPAR_KOBJ_NAME, |
115 | &pci_hotplug_slots_kset->kobj); | 116 | &pci_slots_kset->kobj); |
116 | if (!dlpar_kobj) | 117 | if (!dlpar_kobj) |
117 | return -EINVAL; | 118 | return -EINVAL; |
118 | 119 | ||
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index 56197b600d36..9b714ea93d20 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c | |||
@@ -33,33 +33,6 @@ | |||
33 | #include <asm/rtas.h> | 33 | #include <asm/rtas.h> |
34 | #include "rpaphp.h" | 34 | #include "rpaphp.h" |
35 | 35 | ||
36 | static ssize_t address_read_file (struct hotplug_slot *php_slot, char *buf) | ||
37 | { | ||
38 | int retval; | ||
39 | struct slot *slot = (struct slot *)php_slot->private; | ||
40 | struct pci_bus *bus; | ||
41 | |||
42 | if (!slot) | ||
43 | return -ENOENT; | ||
44 | |||
45 | bus = slot->bus; | ||
46 | if (!bus) | ||
47 | return -ENOENT; | ||
48 | |||
49 | if (bus->self) | ||
50 | retval = sprintf(buf, pci_name(bus->self)); | ||
51 | else | ||
52 | retval = sprintf(buf, "%04x:%02x:00.0", | ||
53 | pci_domain_nr(bus), bus->number); | ||
54 | |||
55 | return retval; | ||
56 | } | ||
57 | |||
58 | static struct hotplug_slot_attribute php_attr_address = { | ||
59 | .attr = {.name = "address", .mode = S_IFREG | S_IRUGO}, | ||
60 | .show = address_read_file, | ||
61 | }; | ||
62 | |||
63 | /* free up the memory used by a slot */ | 36 | /* free up the memory used by a slot */ |
64 | static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) | 37 | static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) |
65 | { | 38 | { |
@@ -135,9 +108,6 @@ int rpaphp_deregister_slot(struct slot *slot) | |||
135 | 108 | ||
136 | list_del(&slot->rpaphp_slot_list); | 109 | list_del(&slot->rpaphp_slot_list); |
137 | 110 | ||
138 | /* remove "address" file */ | ||
139 | sysfs_remove_file(&php_slot->kobj, &php_attr_address.attr); | ||
140 | |||
141 | retval = pci_hp_deregister(php_slot); | 111 | retval = pci_hp_deregister(php_slot); |
142 | if (retval) | 112 | if (retval) |
143 | err("Problem unregistering a slot %s\n", slot->name); | 113 | err("Problem unregistering a slot %s\n", slot->name); |
@@ -151,6 +121,7 @@ int rpaphp_register_slot(struct slot *slot) | |||
151 | { | 121 | { |
152 | struct hotplug_slot *php_slot = slot->hotplug_slot; | 122 | struct hotplug_slot *php_slot = slot->hotplug_slot; |
153 | int retval; | 123 | int retval; |
124 | int slotno; | ||
154 | 125 | ||
155 | dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", | 126 | dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", |
156 | __func__, slot->dn->full_name, slot->index, slot->name, | 127 | __func__, slot->dn->full_name, slot->index, slot->name, |
@@ -162,19 +133,16 @@ int rpaphp_register_slot(struct slot *slot) | |||
162 | return -EAGAIN; | 133 | return -EAGAIN; |
163 | } | 134 | } |
164 | 135 | ||
165 | retval = pci_hp_register(php_slot); | 136 | if (slot->dn->child) |
137 | slotno = PCI_SLOT(PCI_DN(slot->dn->child)->devfn); | ||
138 | else | ||
139 | slotno = -1; | ||
140 | retval = pci_hp_register(php_slot, slot->bus, slotno); | ||
166 | if (retval) { | 141 | if (retval) { |
167 | err("pci_hp_register failed with error %d\n", retval); | 142 | err("pci_hp_register failed with error %d\n", retval); |
168 | return retval; | 143 | return retval; |
169 | } | 144 | } |
170 | 145 | ||
171 | /* create "address" file */ | ||
172 | retval = sysfs_create_file(&php_slot->kobj, &php_attr_address.attr); | ||
173 | if (retval) { | ||
174 | err("sysfs_create_file failed with error %d\n", retval); | ||
175 | goto sysfs_fail; | ||
176 | } | ||
177 | |||
178 | /* add slot to our internal list */ | 146 | /* add slot to our internal list */ |
179 | list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); | 147 | list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); |
180 | info("Slot [%s] registered\n", slot->name); | 148 | info("Slot [%s] registered\n", slot->name); |
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 2fe37cd85b69..2036a43ff2fd 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c | |||
@@ -197,13 +197,15 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, | |||
197 | static struct hotplug_slot * sn_hp_destroy(void) | 197 | static struct hotplug_slot * sn_hp_destroy(void) |
198 | { | 198 | { |
199 | struct slot *slot; | 199 | struct slot *slot; |
200 | struct pci_slot *pci_slot; | ||
200 | struct hotplug_slot *bss_hotplug_slot = NULL; | 201 | struct hotplug_slot *bss_hotplug_slot = NULL; |
201 | 202 | ||
202 | list_for_each_entry(slot, &sn_hp_list, hp_list) { | 203 | list_for_each_entry(slot, &sn_hp_list, hp_list) { |
203 | bss_hotplug_slot = slot->hotplug_slot; | 204 | bss_hotplug_slot = slot->hotplug_slot; |
205 | pci_slot = bss_hotplug_slot->pci_slot; | ||
204 | list_del(&((struct slot *)bss_hotplug_slot->private)-> | 206 | list_del(&((struct slot *)bss_hotplug_slot->private)-> |
205 | hp_list); | 207 | hp_list); |
206 | sysfs_remove_file(&bss_hotplug_slot->kobj, | 208 | sysfs_remove_file(&pci_slot->kobj, |
207 | &sn_slot_path_attr.attr); | 209 | &sn_slot_path_attr.attr); |
208 | break; | 210 | break; |
209 | } | 211 | } |
@@ -614,6 +616,7 @@ static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot) | |||
614 | static int sn_hotplug_slot_register(struct pci_bus *pci_bus) | 616 | static int sn_hotplug_slot_register(struct pci_bus *pci_bus) |
615 | { | 617 | { |
616 | int device; | 618 | int device; |
619 | struct pci_slot *pci_slot; | ||
617 | struct hotplug_slot *bss_hotplug_slot; | 620 | struct hotplug_slot *bss_hotplug_slot; |
618 | int rc = 0; | 621 | int rc = 0; |
619 | 622 | ||
@@ -650,11 +653,12 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) | |||
650 | bss_hotplug_slot->ops = &sn_hotplug_slot_ops; | 653 | bss_hotplug_slot->ops = &sn_hotplug_slot_ops; |
651 | bss_hotplug_slot->release = &sn_release_slot; | 654 | bss_hotplug_slot->release = &sn_release_slot; |
652 | 655 | ||
653 | rc = pci_hp_register(bss_hotplug_slot); | 656 | rc = pci_hp_register(bss_hotplug_slot, pci_bus, device); |
654 | if (rc) | 657 | if (rc) |
655 | goto register_err; | 658 | goto register_err; |
656 | 659 | ||
657 | rc = sysfs_create_file(&bss_hotplug_slot->kobj, | 660 | pci_slot = bss_hotplug_slot->pci_slot; |
661 | rc = sysfs_create_file(&pci_slot->kobj, | ||
658 | &sn_slot_path_attr.attr); | 662 | &sn_slot_path_attr.attr); |
659 | if (rc) | 663 | if (rc) |
660 | goto register_err; | 664 | goto register_err; |
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index df41ecc4e7fc..a8cbd039b85b 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c | |||
@@ -68,7 +68,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value); | |||
68 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); | 68 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); |
69 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); | 69 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); |
70 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); | 70 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); |
71 | static int get_address (struct hotplug_slot *slot, u32 *value); | ||
72 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 71 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
73 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 72 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
74 | 73 | ||
@@ -81,7 +80,6 @@ static struct hotplug_slot_ops shpchp_hotplug_slot_ops = { | |||
81 | .get_attention_status = get_attention_status, | 80 | .get_attention_status = get_attention_status, |
82 | .get_latch_status = get_latch_status, | 81 | .get_latch_status = get_latch_status, |
83 | .get_adapter_status = get_adapter_status, | 82 | .get_adapter_status = get_adapter_status, |
84 | .get_address = get_address, | ||
85 | .get_max_bus_speed = get_max_bus_speed, | 83 | .get_max_bus_speed = get_max_bus_speed, |
86 | .get_cur_bus_speed = get_cur_bus_speed, | 84 | .get_cur_bus_speed = get_cur_bus_speed, |
87 | }; | 85 | }; |
@@ -159,7 +157,8 @@ static int init_slots(struct controller *ctrl) | |||
159 | dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " | 157 | dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " |
160 | "slot_device_offset=%x\n", slot->bus, slot->device, | 158 | "slot_device_offset=%x\n", slot->bus, slot->device, |
161 | slot->hp_slot, slot->number, ctrl->slot_device_offset); | 159 | slot->hp_slot, slot->number, ctrl->slot_device_offset); |
162 | retval = pci_hp_register(slot->hotplug_slot); | 160 | retval = pci_hp_register(slot->hotplug_slot, |
161 | ctrl->pci_dev->subordinate, slot->device); | ||
163 | if (retval) { | 162 | if (retval) { |
164 | err("pci_hp_register failed with error %d\n", retval); | 163 | err("pci_hp_register failed with error %d\n", retval); |
165 | if (retval == -EEXIST) | 164 | if (retval == -EEXIST) |
@@ -288,19 +287,8 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) | |||
288 | return 0; | 287 | return 0; |
289 | } | 288 | } |
290 | 289 | ||
291 | static int get_address (struct hotplug_slot *hotplug_slot, u32 *value) | 290 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, |
292 | { | 291 | enum pci_bus_speed *value) |
293 | struct slot *slot = get_slot(hotplug_slot); | ||
294 | struct pci_bus *bus = slot->ctrl->pci_dev->subordinate; | ||
295 | |||
296 | dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); | ||
297 | |||
298 | *value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) | ||
304 | { | 292 | { |
305 | struct slot *slot = get_slot(hotplug_slot); | 293 | struct slot *slot = get_slot(hotplug_slot); |
306 | int retval; | 294 | int retval; |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 0a497c1b4227..e1d7bbf079b4 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
@@ -106,3 +106,16 @@ pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev) | |||
106 | } | 106 | } |
107 | 107 | ||
108 | struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev); | 108 | struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev); |
109 | |||
110 | /* PCI slot sysfs helper code */ | ||
111 | #define to_pci_slot(s) container_of(s, struct pci_slot, kobj) | ||
112 | |||
113 | extern struct kset *pci_slots_kset; | ||
114 | |||
115 | struct pci_slot_attribute { | ||
116 | struct attribute attr; | ||
117 | ssize_t (*show)(struct pci_slot *, char *); | ||
118 | ssize_t (*store)(struct pci_slot *, const char *, size_t); | ||
119 | }; | ||
120 | #define to_pci_slot_attr(s) container_of(s, struct pci_slot_attribute, attr) | ||
121 | |||
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index aebab71abebf..4562827b7e22 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -414,6 +414,7 @@ static struct pci_bus * pci_alloc_bus(void) | |||
414 | INIT_LIST_HEAD(&b->node); | 414 | INIT_LIST_HEAD(&b->node); |
415 | INIT_LIST_HEAD(&b->children); | 415 | INIT_LIST_HEAD(&b->children); |
416 | INIT_LIST_HEAD(&b->devices); | 416 | INIT_LIST_HEAD(&b->devices); |
417 | INIT_LIST_HEAD(&b->slots); | ||
417 | } | 418 | } |
418 | return b; | 419 | return b; |
419 | } | 420 | } |
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c new file mode 100644 index 000000000000..7e5b85cbd948 --- /dev/null +++ b/drivers/pci/slot.c | |||
@@ -0,0 +1,233 @@ | |||
1 | /* | ||
2 | * drivers/pci/slot.c | ||
3 | * Copyright (C) 2006 Matthew Wilcox <matthew@wil.cx> | ||
4 | * Copyright (C) 2006-2008 Hewlett-Packard Development Company, L.P. | ||
5 | * Alex Chiang <achiang@hp.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/kobject.h> | ||
9 | #include <linux/pci.h> | ||
10 | #include <linux/err.h> | ||
11 | #include "pci.h" | ||
12 | |||
13 | struct kset *pci_slots_kset; | ||
14 | EXPORT_SYMBOL_GPL(pci_slots_kset); | ||
15 | |||
16 | static ssize_t pci_slot_attr_show(struct kobject *kobj, | ||
17 | struct attribute *attr, char *buf) | ||
18 | { | ||
19 | struct pci_slot *slot = to_pci_slot(kobj); | ||
20 | struct pci_slot_attribute *attribute = to_pci_slot_attr(attr); | ||
21 | return attribute->show ? attribute->show(slot, buf) : -EIO; | ||
22 | } | ||
23 | |||
24 | static ssize_t pci_slot_attr_store(struct kobject *kobj, | ||
25 | struct attribute *attr, const char *buf, size_t len) | ||
26 | { | ||
27 | struct pci_slot *slot = to_pci_slot(kobj); | ||
28 | struct pci_slot_attribute *attribute = to_pci_slot_attr(attr); | ||
29 | return attribute->store ? attribute->store(slot, buf, len) : -EIO; | ||
30 | } | ||
31 | |||
32 | static struct sysfs_ops pci_slot_sysfs_ops = { | ||
33 | .show = pci_slot_attr_show, | ||
34 | .store = pci_slot_attr_store, | ||
35 | }; | ||
36 | |||
37 | static ssize_t address_read_file(struct pci_slot *slot, char *buf) | ||
38 | { | ||
39 | if (slot->number == 0xff) | ||
40 | return sprintf(buf, "%04x:%02x\n", | ||
41 | pci_domain_nr(slot->bus), | ||
42 | slot->bus->number); | ||
43 | else | ||
44 | return sprintf(buf, "%04x:%02x:%02x\n", | ||
45 | pci_domain_nr(slot->bus), | ||
46 | slot->bus->number, | ||
47 | slot->number); | ||
48 | } | ||
49 | |||
50 | static void pci_slot_release(struct kobject *kobj) | ||
51 | { | ||
52 | struct pci_slot *slot = to_pci_slot(kobj); | ||
53 | |||
54 | pr_debug("%s: releasing pci_slot on %x:%d\n", __func__, | ||
55 | slot->bus->number, slot->number); | ||
56 | |||
57 | list_del(&slot->list); | ||
58 | |||
59 | kfree(slot); | ||
60 | } | ||
61 | |||
62 | static struct pci_slot_attribute pci_slot_attr_address = | ||
63 | __ATTR(address, (S_IFREG | S_IRUGO), address_read_file, NULL); | ||
64 | |||
65 | static struct attribute *pci_slot_default_attrs[] = { | ||
66 | &pci_slot_attr_address.attr, | ||
67 | NULL, | ||
68 | }; | ||
69 | |||
70 | static struct kobj_type pci_slot_ktype = { | ||
71 | .sysfs_ops = &pci_slot_sysfs_ops, | ||
72 | .release = &pci_slot_release, | ||
73 | .default_attrs = pci_slot_default_attrs, | ||
74 | }; | ||
75 | |||
76 | /** | ||
77 | * pci_create_slot - create or increment refcount for physical PCI slot | ||
78 | * @parent: struct pci_bus of parent bridge | ||
79 | * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder | ||
80 | * @name: user visible string presented in /sys/bus/pci/slots/<name> | ||
81 | * | ||
82 | * PCI slots have first class attributes such as address, speed, width, | ||
83 | * and a &struct pci_slot is used to manage them. This interface will | ||
84 | * either return a new &struct pci_slot to the caller, or if the pci_slot | ||
85 | * already exists, its refcount will be incremented. | ||
86 | * | ||
87 | * Slots are uniquely identified by a @pci_bus, @slot_nr, @name tuple. | ||
88 | * | ||
89 | * Placeholder slots: | ||
90 | * In most cases, @pci_bus, @slot_nr will be sufficient to uniquely identify | ||
91 | * a slot. There is one notable exception - pSeries (rpaphp), where the | ||
92 | * @slot_nr cannot be determined until a device is actually inserted into | ||
93 | * the slot. In this scenario, the caller may pass -1 for @slot_nr. | ||
94 | * | ||
95 | * The following semantics are imposed when the caller passes @slot_nr == | ||
96 | * -1. First, the check for existing %struct pci_slot is skipped, as the | ||
97 | * caller may know about several unpopulated slots on a given %struct | ||
98 | * pci_bus, and each slot would have a @slot_nr of -1. Uniqueness for | ||
99 | * these slots is then determined by the @name parameter. We expect | ||
100 | * kobject_init_and_add() to warn us if the caller attempts to create | ||
101 | * multiple slots with the same name. The other change in semantics is | ||
102 | * user-visible, which is the 'address' parameter presented in sysfs will | ||
103 | * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the | ||
104 | * %struct pci_bus and bb is the bus number. In other words, the devfn of | ||
105 | * the 'placeholder' slot will not be displayed. | ||
106 | */ | ||
107 | |||
108 | struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, | ||
109 | const char *name) | ||
110 | { | ||
111 | struct pci_slot *slot; | ||
112 | int err; | ||
113 | |||
114 | down_write(&pci_bus_sem); | ||
115 | |||
116 | if (slot_nr == -1) | ||
117 | goto placeholder; | ||
118 | |||
119 | /* If we've already created this slot, bump refcount and return. */ | ||
120 | list_for_each_entry(slot, &parent->slots, list) { | ||
121 | if (slot->number == slot_nr) { | ||
122 | kobject_get(&slot->kobj); | ||
123 | pr_debug("%s: inc refcount to %d on %04x:%02x:%02x\n", | ||
124 | __func__, | ||
125 | atomic_read(&slot->kobj.kref.refcount), | ||
126 | pci_domain_nr(parent), parent->number, | ||
127 | slot_nr); | ||
128 | goto out; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | placeholder: | ||
133 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | ||
134 | if (!slot) { | ||
135 | slot = ERR_PTR(-ENOMEM); | ||
136 | goto out; | ||
137 | } | ||
138 | |||
139 | slot->bus = parent; | ||
140 | slot->number = slot_nr; | ||
141 | |||
142 | slot->kobj.kset = pci_slots_kset; | ||
143 | err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL, | ||
144 | "%s", name); | ||
145 | if (err) { | ||
146 | printk(KERN_ERR "Unable to register kobject %s\n", name); | ||
147 | goto err; | ||
148 | } | ||
149 | |||
150 | INIT_LIST_HEAD(&slot->list); | ||
151 | list_add(&slot->list, &parent->slots); | ||
152 | |||
153 | /* Don't care if debug printk has a -1 for slot_nr */ | ||
154 | pr_debug("%s: created pci_slot on %04x:%02x:%02x\n", | ||
155 | __func__, pci_domain_nr(parent), parent->number, slot_nr); | ||
156 | |||
157 | out: | ||
158 | up_write(&pci_bus_sem); | ||
159 | return slot; | ||
160 | err: | ||
161 | kfree(slot); | ||
162 | slot = ERR_PTR(err); | ||
163 | goto out; | ||
164 | } | ||
165 | EXPORT_SYMBOL_GPL(pci_create_slot); | ||
166 | |||
167 | /** | ||
168 | * pci_update_slot_number - update %struct pci_slot -> number | ||
169 | * @slot - %struct pci_slot to update | ||
170 | * @slot_nr - new number for slot | ||
171 | * | ||
172 | * The primary purpose of this interface is to allow callers who earlier | ||
173 | * created a placeholder slot in pci_create_slot() by passing a -1 as | ||
174 | * slot_nr, to update their %struct pci_slot with the correct @slot_nr. | ||
175 | */ | ||
176 | |||
177 | void pci_update_slot_number(struct pci_slot *slot, int slot_nr) | ||
178 | { | ||
179 | int name_count = 0; | ||
180 | struct pci_slot *tmp; | ||
181 | |||
182 | down_write(&pci_bus_sem); | ||
183 | |||
184 | list_for_each_entry(tmp, &slot->bus->slots, list) { | ||
185 | WARN_ON(tmp->number == slot_nr); | ||
186 | if (!strcmp(kobject_name(&tmp->kobj), kobject_name(&slot->kobj))) | ||
187 | name_count++; | ||
188 | } | ||
189 | |||
190 | if (name_count > 1) | ||
191 | printk(KERN_WARNING "pci_update_slot_number found %d slots with the same name: %s\n", name_count, kobject_name(&slot->kobj)); | ||
192 | |||
193 | slot->number = slot_nr; | ||
194 | up_write(&pci_bus_sem); | ||
195 | } | ||
196 | EXPORT_SYMBOL_GPL(pci_update_slot_number); | ||
197 | |||
198 | /** | ||
199 | * pci_destroy_slot - decrement refcount for physical PCI slot | ||
200 | * @slot: struct pci_slot to decrement | ||
201 | * | ||
202 | * %struct pci_slot is refcounted, so destroying them is really easy; we | ||
203 | * just call kobject_put on its kobj and let our release methods do the | ||
204 | * rest. | ||
205 | */ | ||
206 | |||
207 | void pci_destroy_slot(struct pci_slot *slot) | ||
208 | { | ||
209 | pr_debug("%s: dec refcount to %d on %04x:%02x:%02x\n", __func__, | ||
210 | atomic_read(&slot->kobj.kref.refcount) - 1, | ||
211 | pci_domain_nr(slot->bus), slot->bus->number, slot->number); | ||
212 | |||
213 | down_write(&pci_bus_sem); | ||
214 | kobject_put(&slot->kobj); | ||
215 | up_write(&pci_bus_sem); | ||
216 | } | ||
217 | EXPORT_SYMBOL_GPL(pci_destroy_slot); | ||
218 | |||
219 | static int pci_slot_init(void) | ||
220 | { | ||
221 | struct kset *pci_bus_kset; | ||
222 | |||
223 | pci_bus_kset = bus_get_kset(&pci_bus_type); | ||
224 | pci_slots_kset = kset_create_and_add("slots", NULL, | ||
225 | &pci_bus_kset->kobj); | ||
226 | if (!pci_slots_kset) { | ||
227 | printk(KERN_ERR "PCI: Slot initialization failure\n"); | ||
228 | return -ENOMEM; | ||
229 | } | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | subsys_initcall(pci_slot_init); | ||
diff --git a/include/linux/pci.h b/include/linux/pci.h index 507ee52323cd..f1f73f79a180 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -17,8 +17,7 @@ | |||
17 | #ifndef LINUX_PCI_H | 17 | #ifndef LINUX_PCI_H |
18 | #define LINUX_PCI_H | 18 | #define LINUX_PCI_H |
19 | 19 | ||
20 | /* Include the pci register defines */ | 20 | #include <linux/pci_regs.h> /* The pci register defines */ |
21 | #include <linux/pci_regs.h> | ||
22 | 21 | ||
23 | /* | 22 | /* |
24 | * The PCI interface treats multi-function devices as independent | 23 | * The PCI interface treats multi-function devices as independent |
@@ -49,12 +48,22 @@ | |||
49 | #include <linux/list.h> | 48 | #include <linux/list.h> |
50 | #include <linux/compiler.h> | 49 | #include <linux/compiler.h> |
51 | #include <linux/errno.h> | 50 | #include <linux/errno.h> |
51 | #include <linux/kobject.h> | ||
52 | #include <asm/atomic.h> | 52 | #include <asm/atomic.h> |
53 | #include <linux/device.h> | 53 | #include <linux/device.h> |
54 | 54 | ||
55 | /* Include the ID list */ | 55 | /* Include the ID list */ |
56 | #include <linux/pci_ids.h> | 56 | #include <linux/pci_ids.h> |
57 | 57 | ||
58 | /* pci_slot represents a physical slot */ | ||
59 | struct pci_slot { | ||
60 | struct pci_bus *bus; /* The bus this slot is on */ | ||
61 | struct list_head list; /* node in list of slots on this bus */ | ||
62 | struct hotplug_slot *hotplug; /* Hotplug info (migrate over time) */ | ||
63 | unsigned char number; /* PCI_SLOT(pci_dev->devfn) */ | ||
64 | struct kobject kobj; | ||
65 | }; | ||
66 | |||
58 | /* File state for mmap()s on /proc/bus/pci/X/Y */ | 67 | /* File state for mmap()s on /proc/bus/pci/X/Y */ |
59 | enum pci_mmap_state { | 68 | enum pci_mmap_state { |
60 | pci_mmap_io, | 69 | pci_mmap_io, |
@@ -142,6 +151,7 @@ struct pci_dev { | |||
142 | 151 | ||
143 | void *sysdata; /* hook for sys-specific extension */ | 152 | void *sysdata; /* hook for sys-specific extension */ |
144 | struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */ | 153 | struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */ |
154 | struct pci_slot *slot; /* Physical slot this device is in */ | ||
145 | 155 | ||
146 | unsigned int devfn; /* encoded device & function index */ | 156 | unsigned int devfn; /* encoded device & function index */ |
147 | unsigned short vendor; | 157 | unsigned short vendor; |
@@ -266,6 +276,7 @@ struct pci_bus { | |||
266 | struct list_head children; /* list of child buses */ | 276 | struct list_head children; /* list of child buses */ |
267 | struct list_head devices; /* list of devices on this bus */ | 277 | struct list_head devices; /* list of devices on this bus */ |
268 | struct pci_dev *self; /* bridge device as seen by parent */ | 278 | struct pci_dev *self; /* bridge device as seen by parent */ |
279 | struct list_head slots; /* list of slots on this bus */ | ||
269 | struct resource *resource[PCI_BUS_NUM_RESOURCES]; | 280 | struct resource *resource[PCI_BUS_NUM_RESOURCES]; |
270 | /* address space routed to this bus */ | 281 | /* address space routed to this bus */ |
271 | 282 | ||
@@ -488,6 +499,10 @@ struct pci_bus *pci_create_bus(struct device *parent, int bus, | |||
488 | struct pci_ops *ops, void *sysdata); | 499 | struct pci_ops *ops, void *sysdata); |
489 | struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, | 500 | struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, |
490 | int busnr); | 501 | int busnr); |
502 | struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, | ||
503 | const char *name); | ||
504 | void pci_destroy_slot(struct pci_slot *slot); | ||
505 | void pci_update_slot_number(struct pci_slot *slot, int slot_nr); | ||
491 | int pci_scan_slot(struct pci_bus *bus, int devfn); | 506 | int pci_scan_slot(struct pci_bus *bus, int devfn); |
492 | struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn); | 507 | struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn); |
493 | void pci_device_add(struct pci_dev *dev, struct pci_bus *bus); | 508 | void pci_device_add(struct pci_dev *dev, struct pci_bus *bus); |
diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index dbdcd1ad3c6a..a08cd06b541a 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h | |||
@@ -95,9 +95,6 @@ struct hotplug_slot_attribute { | |||
95 | * @get_adapter_status: Called to get see if an adapter is present in the slot or not. | 95 | * @get_adapter_status: Called to get see if an adapter is present in the slot or not. |
96 | * If this field is NULL, the value passed in the struct hotplug_slot_info | 96 | * If this field is NULL, the value passed in the struct hotplug_slot_info |
97 | * will be used when this value is requested by a user. | 97 | * will be used when this value is requested by a user. |
98 | * @get_address: Called to get pci address of a slot. | ||
99 | * If this field is NULL, the value passed in the struct hotplug_slot_info | ||
100 | * will be used when this value is requested by a user. | ||
101 | * @get_max_bus_speed: Called to get the max bus speed for a slot. | 98 | * @get_max_bus_speed: Called to get the max bus speed for a slot. |
102 | * If this field is NULL, the value passed in the struct hotplug_slot_info | 99 | * If this field is NULL, the value passed in the struct hotplug_slot_info |
103 | * will be used when this value is requested by a user. | 100 | * will be used when this value is requested by a user. |
@@ -120,7 +117,6 @@ struct hotplug_slot_ops { | |||
120 | int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); | 117 | int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); |
121 | int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); | 118 | int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); |
122 | int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); | 119 | int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); |
123 | int (*get_address) (struct hotplug_slot *slot, u32 *value); | ||
124 | int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); | 120 | int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); |
125 | int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); | 121 | int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); |
126 | }; | 122 | }; |
@@ -140,7 +136,6 @@ struct hotplug_slot_info { | |||
140 | u8 attention_status; | 136 | u8 attention_status; |
141 | u8 latch_status; | 137 | u8 latch_status; |
142 | u8 adapter_status; | 138 | u8 adapter_status; |
143 | u32 address; | ||
144 | enum pci_bus_speed max_bus_speed; | 139 | enum pci_bus_speed max_bus_speed; |
145 | enum pci_bus_speed cur_bus_speed; | 140 | enum pci_bus_speed cur_bus_speed; |
146 | }; | 141 | }; |
@@ -166,15 +161,14 @@ struct hotplug_slot { | |||
166 | 161 | ||
167 | /* Variables below this are for use only by the hotplug pci core. */ | 162 | /* Variables below this are for use only by the hotplug pci core. */ |
168 | struct list_head slot_list; | 163 | struct list_head slot_list; |
169 | struct kobject kobj; | 164 | struct pci_slot *pci_slot; |
170 | }; | 165 | }; |
171 | #define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj) | 166 | #define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj) |
172 | 167 | ||
173 | extern int pci_hp_register (struct hotplug_slot *slot); | 168 | extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr); |
174 | extern int pci_hp_deregister (struct hotplug_slot *slot); | 169 | extern int pci_hp_deregister(struct hotplug_slot *slot); |
175 | extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot, | 170 | extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot, |
176 | struct hotplug_slot_info *info); | 171 | struct hotplug_slot_info *info); |
177 | extern struct kset *pci_hotplug_slots_kset; | ||
178 | 172 | ||
179 | /* PCI Setting Record (Type 0) */ | 173 | /* PCI Setting Record (Type 0) */ |
180 | struct hpp_type0 { | 174 | struct hpp_type0 { |