PCI: cpci_hotplug: stop managing hotplug_slot->name
[deliverable/linux.git] / drivers / pci / hotplug / cpci_hotplug_core.c
CommitLineData
1da177e4
LT
1/*
2 * CompactPCI Hot Plug Driver
3 *
bcc488ab 4 * Copyright (C) 2002,2005 SOMA Networks, Inc.
1da177e4
LT
5 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
6 * Copyright (C) 2001 IBM Corp.
7 *
8 * All rights reserved.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or (at
13 * your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
18 * NON INFRINGEMENT. See the GNU General Public License for more
19 * details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * Send feedback to <scottm@somanetworks.com>
26 */
27
1da177e4
LT
28#include <linux/module.h>
29#include <linux/kernel.h>
30#include <linux/slab.h>
31#include <linux/pci.h>
7a54f25c 32#include <linux/pci_hotplug.h>
1da177e4
LT
33#include <linux/init.h>
34#include <linux/interrupt.h>
35#include <linux/smp_lock.h>
43b7d7cf 36#include <asm/atomic.h>
1da177e4 37#include <linux/delay.h>
0bec2c85 38#include <linux/kthread.h>
1da177e4
LT
39#include "cpci_hotplug.h"
40
1da177e4
LT
41#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>"
42#define DRIVER_DESC "CompactPCI Hot Plug Core"
43
44#define MY_NAME "cpci_hotplug"
45
46#define dbg(format, arg...) \
47 do { \
bcc488ab 48 if (cpci_debug) \
1da177e4
LT
49 printk (KERN_DEBUG "%s: " format "\n", \
50 MY_NAME , ## arg); \
bcc488ab 51 } while (0)
1da177e4
LT
52#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
53#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
54#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
55
56/* local variables */
43b7d7cf 57static DECLARE_RWSEM(list_rwsem);
1da177e4
LT
58static LIST_HEAD(slot_list);
59static int slots;
43b7d7cf 60static atomic_t extracting;
1da177e4
LT
61int cpci_debug;
62static struct cpci_hp_controller *controller;
0bec2c85
SM
63static struct task_struct *cpci_thread;
64static int thread_finished;
1da177e4
LT
65
66static int enable_slot(struct hotplug_slot *slot);
67static int disable_slot(struct hotplug_slot *slot);
68static int set_attention_status(struct hotplug_slot *slot, u8 value);
69static int get_power_status(struct hotplug_slot *slot, u8 * value);
70static int get_attention_status(struct hotplug_slot *slot, u8 * value);
43b7d7cf
SM
71static int get_adapter_status(struct hotplug_slot *slot, u8 * value);
72static int get_latch_status(struct hotplug_slot *slot, u8 * value);
1da177e4
LT
73
74static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
75 .owner = THIS_MODULE,
76 .enable_slot = enable_slot,
77 .disable_slot = disable_slot,
78 .set_attention_status = set_attention_status,
79 .get_power_status = get_power_status,
80 .get_attention_status = get_attention_status,
43b7d7cf
SM
81 .get_adapter_status = get_adapter_status,
82 .get_latch_status = get_latch_status,
1da177e4
LT
83};
84
85static int
86update_latch_status(struct hotplug_slot *hotplug_slot, u8 value)
87{
88 struct hotplug_slot_info info;
89
90 memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
91 info.latch_status = value;
92 return pci_hp_change_slot_info(hotplug_slot, &info);
93}
94
95static int
96update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value)
97{
98 struct hotplug_slot_info info;
99
100 memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
101 info.adapter_status = value;
102 return pci_hp_change_slot_info(hotplug_slot, &info);
103}
104
105static int
106enable_slot(struct hotplug_slot *hotplug_slot)
107{
108 struct slot *slot = hotplug_slot->private;
109 int retval = 0;
110
d6c479e0 111 dbg("%s - physical_slot = %s", __func__, slot_name(slot));
1da177e4 112
bcc488ab 113 if (controller->ops->set_power)
1da177e4 114 retval = controller->ops->set_power(slot, 1);
1da177e4
LT
115 return retval;
116}
117
118static int
119disable_slot(struct hotplug_slot *hotplug_slot)
120{
121 struct slot *slot = hotplug_slot->private;
122 int retval = 0;
123
d6c479e0 124 dbg("%s - physical_slot = %s", __func__, slot_name(slot));
1da177e4 125
bcc488ab
SM
126 down_write(&list_rwsem);
127
1da177e4 128 /* Unconfigure device */
d6c479e0 129 dbg("%s - unconfiguring slot %s", __func__, slot_name(slot));
bcc488ab 130 if ((retval = cpci_unconfigure_slot(slot))) {
1da177e4 131 err("%s - could not unconfigure slot %s",
d6c479e0 132 __func__, slot_name(slot));
bcc488ab 133 goto disable_error;
1da177e4 134 }
d6c479e0 135 dbg("%s - finished unconfiguring slot %s", __func__, slot_name(slot));
1da177e4
LT
136
137 /* Clear EXT (by setting it) */
bcc488ab 138 if (cpci_clear_ext(slot)) {
1da177e4 139 err("%s - could not clear EXT for slot %s",
d6c479e0 140 __func__, slot_name(slot));
1da177e4 141 retval = -ENODEV;
bcc488ab 142 goto disable_error;
1da177e4
LT
143 }
144 cpci_led_on(slot);
145
bcc488ab
SM
146 if (controller->ops->set_power)
147 if ((retval = controller->ops->set_power(slot, 0)))
148 goto disable_error;
1da177e4 149
bcc488ab 150 if (update_adapter_status(slot->hotplug_slot, 0))
1da177e4 151 warn("failure to update adapter file");
1da177e4 152
bcc488ab 153 if (slot->extracting) {
43b7d7cf
SM
154 slot->extracting = 0;
155 atomic_dec(&extracting);
156 }
bcc488ab
SM
157disable_error:
158 up_write(&list_rwsem);
1da177e4
LT
159 return retval;
160}
161
162static u8
163cpci_get_power_status(struct slot *slot)
164{
165 u8 power = 1;
166
bcc488ab 167 if (controller->ops->get_power)
1da177e4 168 power = controller->ops->get_power(slot);
1da177e4
LT
169 return power;
170}
171
172static int
173get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
174{
175 struct slot *slot = hotplug_slot->private;
176
177 *value = cpci_get_power_status(slot);
178 return 0;
179}
180
181static int
182get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
183{
184 struct slot *slot = hotplug_slot->private;
185
186 *value = cpci_get_attention_status(slot);
187 return 0;
188}
189
190static int
191set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
192{
193 return cpci_set_attention_status(hotplug_slot->private, status);
194}
195
43b7d7cf
SM
196static int
197get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
198{
199 *value = hotplug_slot->info->adapter_status;
200 return 0;
201}
202
203static int
204get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value)
205{
206 *value = hotplug_slot->info->latch_status;
207 return 0;
208}
209
1da177e4
LT
210static void release_slot(struct hotplug_slot *hotplug_slot)
211{
212 struct slot *slot = hotplug_slot->private;
213
214 kfree(slot->hotplug_slot->info);
1da177e4 215 kfree(slot->hotplug_slot);
03e49d40
SM
216 if (slot->dev)
217 pci_dev_put(slot->dev);
1da177e4
LT
218 kfree(slot);
219}
220
221#define SLOT_NAME_SIZE 6
1da177e4
LT
222
223int
224cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
225{
226 struct slot *slot;
227 struct hotplug_slot *hotplug_slot;
228 struct hotplug_slot_info *info;
d6c479e0 229 char name[SLOT_NAME_SIZE];
1da177e4
LT
230 int status = -ENOMEM;
231 int i;
232
bcc488ab 233 if (!(controller && bus))
1da177e4 234 return -ENODEV;
1da177e4
LT
235
236 /*
237 * Create a structure for each slot, and register that slot
238 * with the pci_hotplug subsystem.
239 */
240 for (i = first; i <= last; ++i) {
f5afe806 241 slot = kzalloc(sizeof (struct slot), GFP_KERNEL);
1da177e4
LT
242 if (!slot)
243 goto error;
1da177e4
LT
244
245 hotplug_slot =
f5afe806 246 kzalloc(sizeof (struct hotplug_slot), GFP_KERNEL);
1da177e4
LT
247 if (!hotplug_slot)
248 goto error_slot;
1da177e4
LT
249 slot->hotplug_slot = hotplug_slot;
250
f5afe806 251 info = kzalloc(sizeof (struct hotplug_slot_info), GFP_KERNEL);
1da177e4
LT
252 if (!info)
253 goto error_hpslot;
1da177e4
LT
254 hotplug_slot->info = info;
255
1da177e4
LT
256 slot->bus = bus;
257 slot->number = i;
258 slot->devfn = PCI_DEVFN(i, 0);
259
d6c479e0
AC
260 snprintf(name, SLOT_NAME_SIZE, "%02x:%02x", bus->number, i);
261
1da177e4
LT
262 hotplug_slot->private = slot;
263 hotplug_slot->release = &release_slot;
1da177e4
LT
264 hotplug_slot->ops = &cpci_hotplug_slot_ops;
265
266 /*
267 * Initialize the slot info structure with some known
268 * good values.
269 */
d6c479e0 270 dbg("initializing slot %s", name);
1da177e4
LT
271 info->power_status = cpci_get_power_status(slot);
272 info->attention_status = cpci_get_attention_status(slot);
273
d6c479e0
AC
274 dbg("registering slot %s", name);
275 status = pci_hp_register(slot->hotplug_slot, bus, i, name);
1da177e4
LT
276 if (status) {
277 err("pci_hp_register failed with error %d", status);
d6c479e0 278 goto error_info;
1da177e4 279 }
d6c479e0 280 dbg("slot registered with name: %s", slot_name(slot));
1da177e4
LT
281
282 /* Add slot to our internal list */
43b7d7cf 283 down_write(&list_rwsem);
1da177e4
LT
284 list_add(&slot->slot_list, &slot_list);
285 slots++;
43b7d7cf 286 up_write(&list_rwsem);
1da177e4
LT
287 }
288 return 0;
1da177e4
LT
289error_info:
290 kfree(info);
291error_hpslot:
292 kfree(hotplug_slot);
293error_slot:
294 kfree(slot);
295error:
296 return status;
297}
298
299int
300cpci_hp_unregister_bus(struct pci_bus *bus)
301{
302 struct slot *slot;
bcc488ab
SM
303 struct slot *tmp;
304 int status = 0;
1da177e4 305
43b7d7cf 306 down_write(&list_rwsem);
bcc488ab 307 if (!slots) {
43b7d7cf 308 up_write(&list_rwsem);
1da177e4
LT
309 return -1;
310 }
bcc488ab
SM
311 list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
312 if (slot->bus == bus) {
313 list_del(&slot->slot_list);
314 slots--;
315
d6c479e0 316 dbg("deregistering slot %s", slot_name(slot));
1da177e4 317 status = pci_hp_deregister(slot->hotplug_slot);
bcc488ab 318 if (status) {
1da177e4
LT
319 err("pci_hp_deregister failed with error %d",
320 status);
bcc488ab 321 break;
1da177e4 322 }
1da177e4
LT
323 }
324 }
43b7d7cf 325 up_write(&list_rwsem);
bcc488ab 326 return status;
1da177e4
LT
327}
328
329/* This is the interrupt mode interrupt handler */
330static irqreturn_t
7d12e780 331cpci_hp_intr(int irq, void *data)
1da177e4
LT
332{
333 dbg("entered cpci_hp_intr");
334
335 /* Check to see if it was our interrupt */
6b4486e2 336 if ((controller->irq_flags & IRQF_SHARED) &&
1da177e4
LT
337 !controller->ops->check_irq(controller->dev_id)) {
338 dbg("exited cpci_hp_intr, not our interrupt");
339 return IRQ_NONE;
340 }
341
342 /* Disable ENUM interrupt */
343 controller->ops->disable_irq();
344
345 /* Trigger processing by the event thread */
0bec2c85 346 wake_up_process(cpci_thread);
1da177e4
LT
347 return IRQ_HANDLED;
348}
349
350/*
43b7d7cf 351 * According to PICMG 2.1 R2.0, section 6.3.2, upon
1da177e4
LT
352 * initialization, the system driver shall clear the
353 * INS bits of the cold-inserted devices.
354 */
355static int
bcc488ab 356init_slots(int clear_ins)
1da177e4
LT
357{
358 struct slot *slot;
1da177e4
LT
359 struct pci_dev* dev;
360
66bef8c0 361 dbg("%s - enter", __func__);
43b7d7cf 362 down_read(&list_rwsem);
bcc488ab 363 if (!slots) {
43b7d7cf 364 up_read(&list_rwsem);
1da177e4
LT
365 return -1;
366 }
bcc488ab 367 list_for_each_entry(slot, &slot_list, slot_list) {
d6c479e0 368 dbg("%s - looking at slot %s", __func__, slot_name(slot));
bcc488ab 369 if (clear_ins && cpci_check_and_clear_ins(slot))
1da177e4 370 dbg("%s - cleared INS for slot %s",
d6c479e0 371 __func__, slot_name(slot));
bcc488ab
SM
372 dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0));
373 if (dev) {
374 if (update_adapter_status(slot->hotplug_slot, 1))
375 warn("failure to update adapter file");
376 if (update_latch_status(slot->hotplug_slot, 1))
377 warn("failure to update latch file");
378 slot->dev = dev;
1da177e4
LT
379 }
380 }
43b7d7cf 381 up_read(&list_rwsem);
66bef8c0 382 dbg("%s - exit", __func__);
1da177e4
LT
383 return 0;
384}
385
386static int
387check_slots(void)
388{
389 struct slot *slot;
1da177e4
LT
390 int extracted;
391 int inserted;
43b7d7cf 392 u16 hs_csr;
1da177e4 393
43b7d7cf 394 down_read(&list_rwsem);
bcc488ab 395 if (!slots) {
43b7d7cf 396 up_read(&list_rwsem);
1da177e4
LT
397 err("no slots registered, shutting down");
398 return -1;
399 }
400 extracted = inserted = 0;
bcc488ab 401 list_for_each_entry(slot, &slot_list, slot_list) {
d6c479e0 402 dbg("%s - looking at slot %s", __func__, slot_name(slot));
bcc488ab
SM
403 if (cpci_check_and_clear_ins(slot)) {
404 /*
405 * Some broken hardware (e.g. PLX 9054AB) asserts
406 * ENUM# twice...
407 */
408 if (slot->dev) {
409 warn("slot %s already inserted",
d6c479e0 410 slot_name(slot));
1da177e4
LT
411 inserted++;
412 continue;
413 }
414
415 /* Process insertion */
d6c479e0 416 dbg("%s - slot %s inserted", __func__, slot_name(slot));
1da177e4
LT
417
418 /* GSM, debug */
419 hs_csr = cpci_get_hs_csr(slot);
420 dbg("%s - slot %s HS_CSR (1) = %04x",
d6c479e0 421 __func__, slot_name(slot), hs_csr);
1da177e4
LT
422
423 /* Configure device */
424 dbg("%s - configuring slot %s",
d6c479e0 425 __func__, slot_name(slot));
bcc488ab 426 if (cpci_configure_slot(slot)) {
1da177e4 427 err("%s - could not configure slot %s",
d6c479e0 428 __func__, slot_name(slot));
1da177e4
LT
429 continue;
430 }
431 dbg("%s - finished configuring slot %s",
d6c479e0 432 __func__, slot_name(slot));
1da177e4
LT
433
434 /* GSM, debug */
435 hs_csr = cpci_get_hs_csr(slot);
436 dbg("%s - slot %s HS_CSR (2) = %04x",
d6c479e0 437 __func__, slot_name(slot), hs_csr);
1da177e4 438
bcc488ab 439 if (update_latch_status(slot->hotplug_slot, 1))
1da177e4 440 warn("failure to update latch file");
1da177e4 441
bcc488ab 442 if (update_adapter_status(slot->hotplug_slot, 1))
1da177e4 443 warn("failure to update adapter file");
1da177e4
LT
444
445 cpci_led_off(slot);
446
447 /* GSM, debug */
448 hs_csr = cpci_get_hs_csr(slot);
449 dbg("%s - slot %s HS_CSR (3) = %04x",
d6c479e0 450 __func__, slot_name(slot), hs_csr);
1da177e4
LT
451
452 inserted++;
bcc488ab 453 } else if (cpci_check_ext(slot)) {
1da177e4
LT
454 /* Process extraction request */
455 dbg("%s - slot %s extracted",
d6c479e0 456 __func__, slot_name(slot));
1da177e4
LT
457
458 /* GSM, debug */
459 hs_csr = cpci_get_hs_csr(slot);
460 dbg("%s - slot %s HS_CSR = %04x",
d6c479e0 461 __func__, slot_name(slot), hs_csr);
1da177e4 462
bcc488ab
SM
463 if (!slot->extracting) {
464 if (update_latch_status(slot->hotplug_slot, 0)) {
1da177e4
LT
465 warn("failure to update latch file");
466 }
467 slot->extracting = 1;
bcc488ab 468 atomic_inc(&extracting);
1da177e4
LT
469 }
470 extracted++;
bcc488ab 471 } else if (slot->extracting) {
43b7d7cf 472 hs_csr = cpci_get_hs_csr(slot);
bcc488ab 473 if (hs_csr == 0xffff) {
43b7d7cf
SM
474 /*
475 * Hmmm, we're likely hosed at this point, should we
476 * bother trying to tell the driver or not?
477 */
478 err("card in slot %s was improperly removed",
d6c479e0 479 slot_name(slot));
bcc488ab 480 if (update_adapter_status(slot->hotplug_slot, 0))
43b7d7cf 481 warn("failure to update adapter file");
43b7d7cf
SM
482 slot->extracting = 0;
483 atomic_dec(&extracting);
484 }
1da177e4
LT
485 }
486 }
43b7d7cf
SM
487 up_read(&list_rwsem);
488 dbg("inserted=%d, extracted=%d, extracting=%d",
489 inserted, extracted, atomic_read(&extracting));
bcc488ab 490 if (inserted || extracted)
1da177e4 491 return extracted;
bcc488ab 492 else if (!atomic_read(&extracting)) {
1da177e4
LT
493 err("cannot find ENUM# source, shutting down");
494 return -1;
495 }
43b7d7cf 496 return 0;
1da177e4
LT
497}
498
499/* This is the interrupt mode worker thread body */
500static int
501event_thread(void *data)
502{
503 int rc;
1da177e4 504
66bef8c0 505 dbg("%s - event thread started", __func__);
bcc488ab 506 while (1) {
1da177e4 507 dbg("event thread sleeping");
0bec2c85
SM
508 set_current_state(TASK_INTERRUPTIBLE);
509 schedule();
510 if (kthread_should_stop())
1da177e4 511 break;
43b7d7cf 512 do {
1da177e4 513 rc = check_slots();
43b7d7cf 514 if (rc > 0) {
1da177e4
LT
515 /* Give userspace a chance to handle extraction */
516 msleep(500);
43b7d7cf 517 } else if (rc < 0) {
66bef8c0 518 dbg("%s - error checking slots", __func__);
1da177e4 519 thread_finished = 1;
0bec2c85 520 goto out;
1da177e4 521 }
0bec2c85
SM
522 } while (atomic_read(&extracting) && !kthread_should_stop());
523 if (kthread_should_stop())
bcc488ab 524 break;
1da177e4
LT
525
526 /* Re-enable ENUM# interrupt */
66bef8c0 527 dbg("%s - re-enabling irq", __func__);
1da177e4
LT
528 controller->ops->enable_irq();
529 }
0bec2c85 530 out:
1da177e4
LT
531 return 0;
532}
533
534/* This is the polling mode worker thread body */
535static int
536poll_thread(void *data)
537{
538 int rc;
1da177e4 539
bcc488ab 540 while (1) {
0bec2c85 541 if (kthread_should_stop() || signal_pending(current))
1da177e4 542 break;
bcc488ab 543 if (controller->ops->query_enum()) {
43b7d7cf
SM
544 do {
545 rc = check_slots();
bcc488ab 546 if (rc > 0) {
43b7d7cf
SM
547 /* Give userspace a chance to handle extraction */
548 msleep(500);
bcc488ab 549 } else if (rc < 0) {
66bef8c0 550 dbg("%s - error checking slots", __func__);
43b7d7cf 551 thread_finished = 1;
0bec2c85 552 goto out;
1da177e4 553 }
0bec2c85 554 } while (atomic_read(&extracting) && !kthread_should_stop());
1da177e4 555 }
1da177e4
LT
556 msleep(100);
557 }
0bec2c85 558 out:
1da177e4
LT
559 return 0;
560}
561
562static int
563cpci_start_thread(void)
564{
bcc488ab 565 if (controller->irq)
0bec2c85 566 cpci_thread = kthread_run(event_thread, NULL, "cpci_hp_eventd");
bcc488ab 567 else
0bec2c85
SM
568 cpci_thread = kthread_run(poll_thread, NULL, "cpci_hp_polld");
569 if (IS_ERR(cpci_thread)) {
1da177e4 570 err("Can't start up our thread");
0bec2c85 571 return PTR_ERR(cpci_thread);
1da177e4 572 }
0bec2c85 573 thread_finished = 0;
1da177e4
LT
574 return 0;
575}
576
577static void
578cpci_stop_thread(void)
579{
0bec2c85 580 kthread_stop(cpci_thread);
1da177e4 581 thread_finished = 1;
1da177e4
LT
582}
583
584int
585cpci_hp_register_controller(struct cpci_hp_controller *new_controller)
586{
587 int status = 0;
588
bcc488ab
SM
589 if (controller)
590 return -1;
591 if (!(new_controller && new_controller->ops))
592 return -EINVAL;
593 if (new_controller->irq) {
594 if (!(new_controller->ops->enable_irq &&
595 new_controller->ops->disable_irq))
596 status = -EINVAL;
597 if (request_irq(new_controller->irq,
598 cpci_hp_intr,
599 new_controller->irq_flags,
600 MY_NAME,
601 new_controller->dev_id)) {
602 err("Can't get irq %d for the hotplug cPCI controller",
603 new_controller->irq);
604 status = -ENODEV;
1da177e4 605 }
bcc488ab 606 dbg("%s - acquired controller irq %d",
66bef8c0 607 __func__, new_controller->irq);
1da177e4 608 }
bcc488ab
SM
609 if (!status)
610 controller = new_controller;
1da177e4
LT
611 return status;
612}
613
bcc488ab
SM
614static void
615cleanup_slots(void)
616{
617 struct slot *slot;
618 struct slot *tmp;
619
620 /*
621 * Unregister all of our slots with the pci_hotplug subsystem,
622 * and free up all memory that we had allocated.
623 */
624 down_write(&list_rwsem);
625 if (!slots)
626 goto cleanup_null;
627 list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
628 list_del(&slot->slot_list);
629 pci_hp_deregister(slot->hotplug_slot);
630 }
631cleanup_null:
632 up_write(&list_rwsem);
633 return;
634}
635
1da177e4
LT
636int
637cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
638{
639 int status = 0;
640
bcc488ab
SM
641 if (controller) {
642 if (!thread_finished)
1da177e4 643 cpci_stop_thread();
bcc488ab 644 if (controller->irq)
1da177e4 645 free_irq(controller->irq, controller->dev_id);
1da177e4 646 controller = NULL;
bcc488ab
SM
647 cleanup_slots();
648 } else
1da177e4 649 status = -ENODEV;
1da177e4
LT
650 return status;
651}
652
653int
654cpci_hp_start(void)
655{
656 static int first = 1;
657 int status;
658
66bef8c0 659 dbg("%s - enter", __func__);
bcc488ab 660 if (!controller)
1da177e4 661 return -ENODEV;
1da177e4 662
43b7d7cf 663 down_read(&list_rwsem);
bcc488ab 664 if (list_empty(&slot_list)) {
43b7d7cf 665 up_read(&list_rwsem);
1da177e4
LT
666 return -ENODEV;
667 }
43b7d7cf 668 up_read(&list_rwsem);
1da177e4 669
bcc488ab
SM
670 status = init_slots(first);
671 if (first)
1da177e4 672 first = 0;
bcc488ab
SM
673 if (status)
674 return status;
1da177e4
LT
675
676 status = cpci_start_thread();
bcc488ab 677 if (status)
1da177e4 678 return status;
66bef8c0 679 dbg("%s - thread started", __func__);
1da177e4 680
bcc488ab 681 if (controller->irq) {
1da177e4 682 /* Start enum interrupt processing */
66bef8c0 683 dbg("%s - enabling irq", __func__);
1da177e4
LT
684 controller->ops->enable_irq();
685 }
66bef8c0 686 dbg("%s - exit", __func__);
1da177e4
LT
687 return 0;
688}
689
690int
691cpci_hp_stop(void)
692{
bcc488ab 693 if (!controller)
1da177e4 694 return -ENODEV;
bcc488ab 695 if (controller->irq) {
1da177e4 696 /* Stop enum interrupt processing */
66bef8c0 697 dbg("%s - disabling irq", __func__);
1da177e4
LT
698 controller->ops->disable_irq();
699 }
700 cpci_stop_thread();
701 return 0;
702}
703
1da177e4
LT
704int __init
705cpci_hotplug_init(int debug)
706{
1da177e4 707 cpci_debug = debug;
1da177e4
LT
708 return 0;
709}
710
711void __exit
712cpci_hotplug_exit(void)
713{
714 /*
715 * Clean everything up.
716 */
bcc488ab
SM
717 cpci_hp_stop();
718 cpci_hp_unregister_controller(controller);
1da177e4
LT
719}
720
721EXPORT_SYMBOL_GPL(cpci_hp_register_controller);
722EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller);
723EXPORT_SYMBOL_GPL(cpci_hp_register_bus);
724EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus);
725EXPORT_SYMBOL_GPL(cpci_hp_start);
726EXPORT_SYMBOL_GPL(cpci_hp_stop);
This page took 0.466736 seconds and 5 git commands to generate.