diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pci/hotplug/sgi_hotplug.c | 195 |
1 files changed, 91 insertions, 104 deletions
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 323041fd41dc..b1409441c1cd 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c | |||
@@ -32,14 +32,15 @@ MODULE_LICENSE("GPL"); | |||
32 | MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); | 32 | MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); |
33 | MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver"); | 33 | MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver"); |
34 | 34 | ||
35 | #define PCIIO_ASIC_TYPE_TIOCA 4 | 35 | #define PCIIO_ASIC_TYPE_TIOCA 4 |
36 | #define PCI_SLOT_ALREADY_UP 2 /* slot already up */ | 36 | #define PCI_SLOT_ALREADY_UP 2 /* slot already up */ |
37 | #define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */ | 37 | #define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */ |
38 | #define PCI_L1_ERR 7 /* L1 console command error */ | 38 | #define PCI_L1_ERR 7 /* L1 console command error */ |
39 | #define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */ | 39 | #define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */ |
40 | #define PCI_L1_QSIZE 128 /* our L1 message buffer size */ | 40 | #define PCI_L1_QSIZE 128 /* our L1 message buffer size */ |
41 | #define SN_MAX_HP_SLOTS 32 /* max number of hotplug slots */ | 41 | #define SN_MAX_HP_SLOTS 32 /* max hotplug slots */ |
42 | #define SGI_HOTPLUG_PROM_REV 0x0420 /* Min. required PROM version */ | 42 | #define SGI_HOTPLUG_PROM_REV 0x0430 /* Min. required PROM version */ |
43 | #define SN_SLOT_NAME_SIZE 33 /* size of name string */ | ||
43 | 44 | ||
44 | /* internal list head */ | 45 | /* internal list head */ |
45 | static struct list_head sn_hp_list; | 46 | static struct list_head sn_hp_list; |
@@ -51,6 +52,7 @@ struct slot { | |||
51 | /* this struct for glue internal only */ | 52 | /* this struct for glue internal only */ |
52 | struct hotplug_slot *hotplug_slot; | 53 | struct hotplug_slot *hotplug_slot; |
53 | struct list_head hp_list; | 54 | struct list_head hp_list; |
55 | char physical_path[SN_SLOT_NAME_SIZE]; | ||
54 | }; | 56 | }; |
55 | 57 | ||
56 | struct pcibr_slot_enable_resp { | 58 | struct pcibr_slot_enable_resp { |
@@ -70,7 +72,7 @@ enum sn_pci_req_e { | |||
70 | 72 | ||
71 | static int enable_slot(struct hotplug_slot *slot); | 73 | static int enable_slot(struct hotplug_slot *slot); |
72 | static int disable_slot(struct hotplug_slot *slot); | 74 | static int disable_slot(struct hotplug_slot *slot); |
73 | static int get_power_status(struct hotplug_slot *slot, u8 *value); | 75 | static inline int get_power_status(struct hotplug_slot *slot, u8 *value); |
74 | 76 | ||
75 | static struct hotplug_slot_ops sn_hotplug_slot_ops = { | 77 | static struct hotplug_slot_ops sn_hotplug_slot_ops = { |
76 | .owner = THIS_MODULE, | 78 | .owner = THIS_MODULE, |
@@ -81,6 +83,21 @@ static struct hotplug_slot_ops sn_hotplug_slot_ops = { | |||
81 | 83 | ||
82 | static DECLARE_MUTEX(sn_hotplug_sem); | 84 | static DECLARE_MUTEX(sn_hotplug_sem); |
83 | 85 | ||
86 | static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot, | ||
87 | char *buf) | ||
88 | { | ||
89 | int retval = -ENOENT; | ||
90 | struct slot *slot = bss_hotplug_slot->private; | ||
91 | |||
92 | if (!slot) | ||
93 | return retval; | ||
94 | |||
95 | retval = sprintf (buf, "%s\n", slot->physical_path); | ||
96 | return retval; | ||
97 | } | ||
98 | |||
99 | static struct hotplug_slot_attribute sn_slot_path_attr = __ATTR_RO(path); | ||
100 | |||
84 | static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) | 101 | static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) |
85 | { | 102 | { |
86 | struct pcibus_info *pcibus_info; | 103 | struct pcibus_info *pcibus_info; |
@@ -120,15 +137,15 @@ static int sn_pci_bus_valid(struct pci_bus *pci_bus) | |||
120 | /* Only register slots in I/O Bricks that support hotplug */ | 137 | /* Only register slots in I/O Bricks that support hotplug */ |
121 | bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid); | 138 | bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid); |
122 | switch (bricktype) { | 139 | switch (bricktype) { |
123 | case L1_BRICKTYPE_IX: | 140 | case L1_BRICKTYPE_IX: |
124 | case L1_BRICKTYPE_PX: | 141 | case L1_BRICKTYPE_PX: |
125 | case L1_BRICKTYPE_IA: | 142 | case L1_BRICKTYPE_IA: |
126 | case L1_BRICKTYPE_PA: | 143 | case L1_BRICKTYPE_PA: |
127 | return 1; | 144 | return 1; |
128 | break; | 145 | break; |
129 | default: | 146 | default: |
130 | return -EPERM; | 147 | return -EPERM; |
131 | break; | 148 | break; |
132 | } | 149 | } |
133 | 150 | ||
134 | return -EIO; | 151 | return -EIO; |
@@ -142,13 +159,12 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, | |||
142 | 159 | ||
143 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); | 160 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); |
144 | 161 | ||
145 | bss_hotplug_slot->private = kcalloc(1, sizeof(struct slot), | 162 | slot = kcalloc(1, sizeof(*slot), GFP_KERNEL); |
146 | GFP_KERNEL); | 163 | if (!slot) |
147 | if (!bss_hotplug_slot->private) | ||
148 | return -ENOMEM; | 164 | return -ENOMEM; |
149 | slot = (struct slot *)bss_hotplug_slot->private; | 165 | bss_hotplug_slot->private = slot; |
150 | 166 | ||
151 | bss_hotplug_slot->name = kmalloc(33, GFP_KERNEL); | 167 | bss_hotplug_slot->name = kmalloc(SN_SLOT_NAME_SIZE, GFP_KERNEL); |
152 | if (!bss_hotplug_slot->name) { | 168 | if (!bss_hotplug_slot->name) { |
153 | kfree(bss_hotplug_slot->private); | 169 | kfree(bss_hotplug_slot->private); |
154 | return -ENOMEM; | 170 | return -ENOMEM; |
@@ -156,16 +172,16 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, | |||
156 | 172 | ||
157 | slot->device_num = device; | 173 | slot->device_num = device; |
158 | slot->pci_bus = pci_bus; | 174 | slot->pci_bus = pci_bus; |
159 | 175 | sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x", | |
160 | sprintf(bss_hotplug_slot->name, "module_%c%c%c%c%.2d_b_%d_s_%d", | 176 | pci_domain_nr(pci_bus), |
177 | ((int)pcibus_info->pbi_buscommon.bs_persist_busnum) & 0xf, | ||
178 | device + 1); | ||
179 | sprintf(slot->physical_path, "module_%c%c%c%c%.2d", | ||
161 | '0'+RACK_GET_CLASS(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), | 180 | '0'+RACK_GET_CLASS(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), |
162 | '0'+RACK_GET_GROUP(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), | 181 | '0'+RACK_GET_GROUP(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), |
163 | '0'+RACK_GET_NUM(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), | 182 | '0'+RACK_GET_NUM(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), |
164 | MODULE_GET_BTCHAR(pcibus_info->pbi_moduleid), | 183 | MODULE_GET_BTCHAR(pcibus_info->pbi_moduleid), |
165 | MODULE_GET_BPOS(pcibus_info->pbi_moduleid), | 184 | MODULE_GET_BPOS(pcibus_info->pbi_moduleid)); |
166 | ((int)pcibus_info->pbi_buscommon.bs_persist_busnum) & 0xf, | ||
167 | device + 1); | ||
168 | |||
169 | slot->hotplug_slot = bss_hotplug_slot; | 185 | slot->hotplug_slot = bss_hotplug_slot; |
170 | list_add(&slot->hp_list, &sn_hp_list); | 186 | list_add(&slot->hp_list, &sn_hp_list); |
171 | 187 | ||
@@ -175,14 +191,14 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, | |||
175 | static struct hotplug_slot * sn_hp_destroy(void) | 191 | static struct hotplug_slot * sn_hp_destroy(void) |
176 | { | 192 | { |
177 | struct slot *slot; | 193 | struct slot *slot; |
178 | struct list_head *list; | ||
179 | struct hotplug_slot *bss_hotplug_slot = NULL; | 194 | struct hotplug_slot *bss_hotplug_slot = NULL; |
180 | 195 | ||
181 | list_for_each(list, &sn_hp_list) { | 196 | list_for_each_entry(slot, &sn_hp_list, hp_list) { |
182 | slot = list_entry(list, struct slot, hp_list); | ||
183 | bss_hotplug_slot = slot->hotplug_slot; | 197 | bss_hotplug_slot = slot->hotplug_slot; |
184 | list_del(&((struct slot *)bss_hotplug_slot->private)-> | 198 | list_del(&((struct slot *)bss_hotplug_slot->private)-> |
185 | hp_list); | 199 | hp_list); |
200 | sysfs_remove_file(&bss_hotplug_slot->kobj, | ||
201 | &sn_slot_path_attr.attr); | ||
186 | break; | 202 | break; |
187 | } | 203 | } |
188 | return bss_hotplug_slot; | 204 | return bss_hotplug_slot; |
@@ -190,7 +206,6 @@ static struct hotplug_slot * sn_hp_destroy(void) | |||
190 | 206 | ||
191 | static void sn_bus_alloc_data(struct pci_dev *dev) | 207 | static void sn_bus_alloc_data(struct pci_dev *dev) |
192 | { | 208 | { |
193 | struct list_head *node; | ||
194 | struct pci_bus *subordinate_bus; | 209 | struct pci_bus *subordinate_bus; |
195 | struct pci_dev *child; | 210 | struct pci_dev *child; |
196 | 211 | ||
@@ -199,66 +214,29 @@ static void sn_bus_alloc_data(struct pci_dev *dev) | |||
199 | /* Recursively sets up the sn_irq_info structs */ | 214 | /* Recursively sets up the sn_irq_info structs */ |
200 | if (dev->subordinate) { | 215 | if (dev->subordinate) { |
201 | subordinate_bus = dev->subordinate; | 216 | subordinate_bus = dev->subordinate; |
202 | list_for_each(node, &subordinate_bus->devices) { | 217 | list_for_each_entry(child, &subordinate_bus->devices, bus_list) |
203 | child = list_entry(node, struct pci_dev, bus_list); | ||
204 | sn_bus_alloc_data(child); | 218 | sn_bus_alloc_data(child); |
205 | } | ||
206 | } | 219 | } |
207 | } | 220 | } |
208 | 221 | ||
209 | static void sn_bus_free_data(struct pci_dev *dev) | 222 | static void sn_bus_free_data(struct pci_dev *dev) |
210 | { | 223 | { |
211 | struct list_head *node; | ||
212 | struct pci_bus *subordinate_bus; | 224 | struct pci_bus *subordinate_bus; |
213 | struct pci_dev *child; | 225 | struct pci_dev *child; |
214 | 226 | ||
215 | /* Recursively clean up sn_irq_info structs */ | 227 | /* Recursively clean up sn_irq_info structs */ |
216 | if (dev->subordinate) { | 228 | if (dev->subordinate) { |
217 | subordinate_bus = dev->subordinate; | 229 | subordinate_bus = dev->subordinate; |
218 | list_for_each(node, &subordinate_bus->devices) { | 230 | list_for_each_entry(child, &subordinate_bus->devices, bus_list) |
219 | child = list_entry(node, struct pci_dev, bus_list); | ||
220 | sn_bus_free_data(child); | 231 | sn_bus_free_data(child); |
221 | } | ||
222 | } | 232 | } |
223 | sn_pci_unfixup_slot(dev); | 233 | sn_pci_unfixup_slot(dev); |
224 | } | 234 | } |
225 | 235 | ||
226 | static u8 sn_power_status_get(struct hotplug_slot *bss_hotplug_slot) | ||
227 | { | ||
228 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | ||
229 | struct pcibus_info *pcibus_info; | ||
230 | u8 retval; | ||
231 | |||
232 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); | ||
233 | retval = pcibus_info->pbi_enabled_devices & (1 << slot->device_num); | ||
234 | |||
235 | return retval ? 1 : 0; | ||
236 | } | ||
237 | |||
238 | static void sn_slot_mark_enable(struct hotplug_slot *bss_hotplug_slot, | ||
239 | int device_num) | ||
240 | { | ||
241 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | ||
242 | struct pcibus_info *pcibus_info; | ||
243 | |||
244 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); | ||
245 | pcibus_info->pbi_enabled_devices |= (1 << device_num); | ||
246 | } | ||
247 | |||
248 | static void sn_slot_mark_disable(struct hotplug_slot *bss_hotplug_slot, | ||
249 | int device_num) | ||
250 | { | ||
251 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | ||
252 | struct pcibus_info *pcibus_info; | ||
253 | |||
254 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); | ||
255 | pcibus_info->pbi_enabled_devices &= ~(1 << device_num); | ||
256 | } | ||
257 | |||
258 | static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, | 236 | static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, |
259 | int device_num) | 237 | int device_num) |
260 | { | 238 | { |
261 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | 239 | struct slot *slot = bss_hotplug_slot->private; |
262 | struct pcibus_info *pcibus_info; | 240 | struct pcibus_info *pcibus_info; |
263 | struct pcibr_slot_enable_resp resp; | 241 | struct pcibr_slot_enable_resp resp; |
264 | int rc; | 242 | int rc; |
@@ -273,7 +251,7 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, | |||
273 | 251 | ||
274 | if (rc == PCI_SLOT_ALREADY_UP) { | 252 | if (rc == PCI_SLOT_ALREADY_UP) { |
275 | dev_dbg(slot->pci_bus->self, "is already active\n"); | 253 | dev_dbg(slot->pci_bus->self, "is already active\n"); |
276 | return -EPERM; | 254 | return 1; /* return 1 to user */ |
277 | } | 255 | } |
278 | 256 | ||
279 | if (rc == PCI_L1_ERR) { | 257 | if (rc == PCI_L1_ERR) { |
@@ -290,7 +268,8 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, | |||
290 | return -EIO; | 268 | return -EIO; |
291 | } | 269 | } |
292 | 270 | ||
293 | sn_slot_mark_enable(bss_hotplug_slot, device_num); | 271 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); |
272 | pcibus_info->pbi_enabled_devices |= (1 << device_num); | ||
294 | 273 | ||
295 | return 0; | 274 | return 0; |
296 | } | 275 | } |
@@ -298,7 +277,7 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, | |||
298 | static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot, | 277 | static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot, |
299 | int device_num, int action) | 278 | int device_num, int action) |
300 | { | 279 | { |
301 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | 280 | struct slot *slot = bss_hotplug_slot->private; |
302 | struct pcibus_info *pcibus_info; | 281 | struct pcibus_info *pcibus_info; |
303 | struct pcibr_slot_disable_resp resp; | 282 | struct pcibr_slot_disable_resp resp; |
304 | int rc; | 283 | int rc; |
@@ -307,43 +286,44 @@ static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot, | |||
307 | 286 | ||
308 | rc = sal_pcibr_slot_disable(pcibus_info, device_num, action, &resp); | 287 | rc = sal_pcibr_slot_disable(pcibus_info, device_num, action, &resp); |
309 | 288 | ||
310 | if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_SLOT_ALREADY_DOWN) { | 289 | if ((action == PCI_REQ_SLOT_ELIGIBLE) && |
290 | (rc == PCI_SLOT_ALREADY_DOWN)) { | ||
311 | dev_dbg(slot->pci_bus->self, "Slot %s already inactive\n"); | 291 | dev_dbg(slot->pci_bus->self, "Slot %s already inactive\n"); |
312 | return -ENODEV; | 292 | return 1; /* return 1 to user */ |
313 | } | 293 | } |
314 | 294 | ||
315 | if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_EMPTY_33MHZ) { | 295 | if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_EMPTY_33MHZ)) { |
316 | dev_dbg(slot->pci_bus->self, | 296 | dev_dbg(slot->pci_bus->self, |
317 | "Cannot remove last 33MHz card\n"); | 297 | "Cannot remove last 33MHz card\n"); |
318 | return -EPERM; | 298 | return -EPERM; |
319 | } | 299 | } |
320 | 300 | ||
321 | if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_L1_ERR) { | 301 | if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_L1_ERR)) { |
322 | dev_dbg(slot->pci_bus->self, | 302 | dev_dbg(slot->pci_bus->self, |
323 | "L1 failure %d with message \n%s\n", | 303 | "L1 failure %d with message \n%s\n", |
324 | resp.resp_sub_errno, resp.resp_l1_msg); | 304 | resp.resp_sub_errno, resp.resp_l1_msg); |
325 | return -EPERM; | 305 | return -EPERM; |
326 | } | 306 | } |
327 | 307 | ||
328 | if (action == PCI_REQ_SLOT_ELIGIBLE && rc) { | 308 | if ((action == PCI_REQ_SLOT_ELIGIBLE) && rc) { |
329 | dev_dbg(slot->pci_bus->self, | 309 | dev_dbg(slot->pci_bus->self, |
330 | "remove failed with error %d sub-error %d\n", | 310 | "remove failed with error %d sub-error %d\n", |
331 | rc, resp.resp_sub_errno); | 311 | rc, resp.resp_sub_errno); |
332 | return -EIO; | 312 | return -EIO; |
333 | } | 313 | } |
334 | 314 | ||
335 | if (action == PCI_REQ_SLOT_ELIGIBLE && !rc) | 315 | if ((action == PCI_REQ_SLOT_ELIGIBLE) && !rc) |
336 | return 0; | 316 | return 0; |
337 | 317 | ||
338 | if (action == PCI_REQ_SLOT_DISABLE && !rc) { | 318 | if ((action == PCI_REQ_SLOT_DISABLE) && !rc) { |
339 | sn_slot_mark_disable(bss_hotplug_slot, device_num); | 319 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); |
320 | pcibus_info->pbi_enabled_devices &= ~(1 << device_num); | ||
340 | dev_dbg(slot->pci_bus->self, "remove successful\n"); | 321 | dev_dbg(slot->pci_bus->self, "remove successful\n"); |
341 | return 0; | 322 | return 0; |
342 | } | 323 | } |
343 | 324 | ||
344 | if (action == PCI_REQ_SLOT_DISABLE && rc) { | 325 | if ((action == PCI_REQ_SLOT_DISABLE) && rc) { |
345 | dev_dbg(slot->pci_bus->self,"remove failed rc = %d\n", rc); | 326 | dev_dbg(slot->pci_bus->self,"remove failed rc = %d\n", rc); |
346 | return rc; | ||
347 | } | 327 | } |
348 | 328 | ||
349 | return rc; | 329 | return rc; |
@@ -351,7 +331,7 @@ static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot, | |||
351 | 331 | ||
352 | static int enable_slot(struct hotplug_slot *bss_hotplug_slot) | 332 | static int enable_slot(struct hotplug_slot *bss_hotplug_slot) |
353 | { | 333 | { |
354 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | 334 | struct slot *slot = bss_hotplug_slot->private; |
355 | struct pci_bus *new_bus = NULL; | 335 | struct pci_bus *new_bus = NULL; |
356 | struct pci_dev *dev; | 336 | struct pci_dev *dev; |
357 | int func, num_funcs; | 337 | int func, num_funcs; |
@@ -371,8 +351,8 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) | |||
371 | return rc; | 351 | return rc; |
372 | } | 352 | } |
373 | 353 | ||
374 | num_funcs = pci_scan_slot(slot->pci_bus, PCI_DEVFN(slot->device_num+1, | 354 | num_funcs = pci_scan_slot(slot->pci_bus, |
375 | PCI_FUNC(0))); | 355 | PCI_DEVFN(slot->device_num + 1, 0)); |
376 | if (!num_funcs) { | 356 | if (!num_funcs) { |
377 | dev_dbg(slot->pci_bus->self, "no device in slot\n"); | 357 | dev_dbg(slot->pci_bus->self, "no device in slot\n"); |
378 | up(&sn_hotplug_sem); | 358 | up(&sn_hotplug_sem); |
@@ -391,8 +371,6 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) | |||
391 | dev = pci_get_slot(slot->pci_bus, | 371 | dev = pci_get_slot(slot->pci_bus, |
392 | PCI_DEVFN(slot->device_num + 1, | 372 | PCI_DEVFN(slot->device_num + 1, |
393 | PCI_FUNC(func))); | 373 | PCI_FUNC(func))); |
394 | |||
395 | |||
396 | if (dev) { | 374 | if (dev) { |
397 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | 375 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { |
398 | unsigned char sec_bus; | 376 | unsigned char sec_bus; |
@@ -431,7 +409,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) | |||
431 | 409 | ||
432 | static int disable_slot(struct hotplug_slot *bss_hotplug_slot) | 410 | static int disable_slot(struct hotplug_slot *bss_hotplug_slot) |
433 | { | 411 | { |
434 | struct slot *slot = (struct slot *)bss_hotplug_slot->private; | 412 | struct slot *slot = bss_hotplug_slot->private; |
435 | struct pci_dev *dev; | 413 | struct pci_dev *dev; |
436 | int func; | 414 | int func; |
437 | int rc; | 415 | int rc; |
@@ -448,7 +426,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) | |||
448 | /* Free the SN resources assigned to the Linux device.*/ | 426 | /* Free the SN resources assigned to the Linux device.*/ |
449 | for (func = 0; func < 8; func++) { | 427 | for (func = 0; func < 8; func++) { |
450 | dev = pci_get_slot(slot->pci_bus, | 428 | dev = pci_get_slot(slot->pci_bus, |
451 | PCI_DEVFN(slot->device_num+1, | 429 | PCI_DEVFN(slot->device_num + 1, |
452 | PCI_FUNC(func))); | 430 | PCI_FUNC(func))); |
453 | if (dev) { | 431 | if (dev) { |
454 | /* | 432 | /* |
@@ -477,10 +455,15 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) | |||
477 | return rc; | 455 | return rc; |
478 | } | 456 | } |
479 | 457 | ||
480 | static int get_power_status(struct hotplug_slot *bss_hotplug_slot, u8 *value) | 458 | static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot, |
459 | u8 *value) | ||
481 | { | 460 | { |
461 | struct slot *slot = bss_hotplug_slot->private; | ||
462 | struct pcibus_info *pcibus_info; | ||
463 | |||
464 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); | ||
482 | down(&sn_hotplug_sem); | 465 | down(&sn_hotplug_sem); |
483 | *value = sn_power_status_get(bss_hotplug_slot); | 466 | *value = pcibus_info->pbi_enabled_devices & (1 << slot->device_num); |
484 | up(&sn_hotplug_sem); | 467 | up(&sn_hotplug_sem); |
485 | return 0; | 468 | return 0; |
486 | } | 469 | } |
@@ -508,7 +491,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) | |||
508 | if (sn_pci_slot_valid(pci_bus, device) != 1) | 491 | if (sn_pci_slot_valid(pci_bus, device) != 1) |
509 | continue; | 492 | continue; |
510 | 493 | ||
511 | bss_hotplug_slot = kcalloc(1,sizeof(struct hotplug_slot), | 494 | bss_hotplug_slot = kcalloc(1, sizeof(*bss_hotplug_slot), |
512 | GFP_KERNEL); | 495 | GFP_KERNEL); |
513 | if (!bss_hotplug_slot) { | 496 | if (!bss_hotplug_slot) { |
514 | rc = -ENOMEM; | 497 | rc = -ENOMEM; |
@@ -516,7 +499,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) | |||
516 | } | 499 | } |
517 | 500 | ||
518 | bss_hotplug_slot->info = | 501 | bss_hotplug_slot->info = |
519 | kcalloc(1,sizeof(struct hotplug_slot_info), | 502 | kcalloc(1, sizeof(struct hotplug_slot_info), |
520 | GFP_KERNEL); | 503 | GFP_KERNEL); |
521 | if (!bss_hotplug_slot->info) { | 504 | if (!bss_hotplug_slot->info) { |
522 | rc = -ENOMEM; | 505 | rc = -ENOMEM; |
@@ -535,6 +518,11 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) | |||
535 | rc = pci_hp_register(bss_hotplug_slot); | 518 | rc = pci_hp_register(bss_hotplug_slot); |
536 | if (rc) | 519 | if (rc) |
537 | goto register_err; | 520 | goto register_err; |
521 | |||
522 | rc = sysfs_create_file(&bss_hotplug_slot->kobj, | ||
523 | &sn_slot_path_attr.attr); | ||
524 | if (rc) | ||
525 | goto register_err; | ||
538 | } | 526 | } |
539 | dev_dbg(pci_bus->self, "Registered bus with hotplug\n"); | 527 | dev_dbg(pci_bus->self, "Registered bus with hotplug\n"); |
540 | return rc; | 528 | return rc; |
@@ -564,14 +552,14 @@ static int sn_pci_hotplug_init(void) | |||
564 | int rc; | 552 | int rc; |
565 | int registered = 0; | 553 | int registered = 0; |
566 | 554 | ||
567 | INIT_LIST_HEAD(&sn_hp_list); | ||
568 | |||
569 | if (sn_sal_rev() < SGI_HOTPLUG_PROM_REV) { | 555 | if (sn_sal_rev() < SGI_HOTPLUG_PROM_REV) { |
570 | printk(KERN_ERR "%s: PROM version must be greater than 4.05\n", | 556 | printk(KERN_ERR "%s: PROM version must be greater than 4.30\n", |
571 | __FUNCTION__); | 557 | __FUNCTION__); |
572 | return -EPERM; | 558 | return -EPERM; |
573 | } | 559 | } |
574 | 560 | ||
561 | INIT_LIST_HEAD(&sn_hp_list); | ||
562 | |||
575 | while ((pci_bus = pci_find_next_bus(pci_bus))) { | 563 | while ((pci_bus = pci_find_next_bus(pci_bus))) { |
576 | if (!pci_bus->sysdata) | 564 | if (!pci_bus->sysdata) |
577 | continue; | 565 | continue; |
@@ -584,9 +572,9 @@ static int sn_pci_hotplug_init(void) | |||
584 | dev_dbg(pci_bus->self, "valid hotplug bus\n"); | 572 | dev_dbg(pci_bus->self, "valid hotplug bus\n"); |
585 | 573 | ||
586 | rc = sn_hotplug_slot_register(pci_bus); | 574 | rc = sn_hotplug_slot_register(pci_bus); |
587 | if (!rc) | 575 | if (!rc) { |
588 | registered = 1; | 576 | registered = 1; |
589 | else { | 577 | } else { |
590 | registered = 0; | 578 | registered = 0; |
591 | break; | 579 | break; |
592 | } | 580 | } |
@@ -599,9 +587,8 @@ static void sn_pci_hotplug_exit(void) | |||
599 | { | 587 | { |
600 | struct hotplug_slot *bss_hotplug_slot; | 588 | struct hotplug_slot *bss_hotplug_slot; |
601 | 589 | ||
602 | while ((bss_hotplug_slot = sn_hp_destroy())) { | 590 | while ((bss_hotplug_slot = sn_hp_destroy())) |
603 | pci_hp_deregister(bss_hotplug_slot); | 591 | pci_hp_deregister(bss_hotplug_slot); |
604 | } | ||
605 | 592 | ||
606 | if (!list_empty(&sn_hp_list)) | 593 | if (!list_empty(&sn_hp_list)) |
607 | printk(KERN_ERR "%s: internal list is not empty\n", __FILE__); | 594 | printk(KERN_ERR "%s: internal list is not empty\n", __FILE__); |