sgi_hotplug.c 18 KB
Newer Older
1 2 3 4 5
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
6
 * Copyright (C) 2005-2006 Silicon Graphics, Inc. All rights reserved.
7 8 9 10 11
 *
 * This work was based on the 2.4/2.6 kernel development by Dick Reigner.
 * Work to add BIOS PROM support was completed by Mike Habeck.
 */

12
#include <linux/acpi.h>
13 14 15 16
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
17
#include <linux/pci_hotplug.h>
18
#include <linux/proc_fs.h>
19
#include <linux/slab.h>
20
#include <linux/types.h>
21
#include <linux/mutex.h>
22 23

#include <asm/sn/addrs.h>
24
#include <asm/sn/geo.h>
25 26 27 28 29
#include <asm/sn/l1.h>
#include <asm/sn/module.h>
#include <asm/sn/pcibr_provider.h>
#include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h>
30
#include <asm/sn/sn_feature_sets.h>
31 32
#include <asm/sn/sn_sal.h>
#include <asm/sn/types.h>
33
#include <asm/sn/acpi.h>
34 35 36 37 38 39 40

#include "../pci.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver");

41 42

/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */
43 44 45 46
#define PCI_SLOT_ALREADY_UP		2	/* slot already up */
#define PCI_SLOT_ALREADY_DOWN		3	/* slot already down */
#define PCI_L1_ERR			7	/* L1 console command error */
#define PCI_EMPTY_33MHZ			15	/* empty 33 MHz bus */
47 48 49


#define PCIIO_ASIC_TYPE_TIOCA		4
50 51 52
#define PCI_L1_QSIZE			128	/* our L1 message buffer size */
#define SN_MAX_HP_SLOTS			32	/* max hotplug slots */
#define SN_SLOT_NAME_SIZE		33	/* size of name string */
53 54 55 56 57 58 59 60 61 62 63

/* internal list head */
static struct list_head sn_hp_list;

/* hotplug_slot struct's private pointer */
struct slot {
	int device_num;
	struct pci_bus *pci_bus;
	/* this struct for glue internal only */
	struct hotplug_slot *hotplug_slot;
	struct list_head hp_list;
64
	char physical_path[SN_SLOT_NAME_SIZE];
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
};

struct pcibr_slot_enable_resp {
	int resp_sub_errno;
	char resp_l1_msg[PCI_L1_QSIZE + 1];
};

struct pcibr_slot_disable_resp {
	int resp_sub_errno;
	char resp_l1_msg[PCI_L1_QSIZE + 1];
};

enum sn_pci_req_e {
	PCI_REQ_SLOT_ELIGIBLE,
	PCI_REQ_SLOT_DISABLE
};

static int enable_slot(struct hotplug_slot *slot);
static int disable_slot(struct hotplug_slot *slot);
84
static inline int get_power_status(struct hotplug_slot *slot, u8 *value);
85 86 87 88 89 90 91

static struct hotplug_slot_ops sn_hotplug_slot_ops = {
	.enable_slot            = enable_slot,
	.disable_slot           = disable_slot,
	.get_power_status       = get_power_status,
};

92
static DEFINE_MUTEX(sn_hotplug_mutex);
93

94
static ssize_t path_show(struct pci_slot *pci_slot, char *buf)
95 96
{
	int retval = -ENOENT;
97
	struct slot *slot = pci_slot->hotplug->private;
98 99 100 101 102 103 104 105

	if (!slot)
		return retval;

	retval = sprintf (buf, "%s\n", slot->physical_path);
	return retval;
}

106
static struct pci_slot_attribute sn_slot_path_attr = __ATTR_RO(path);
107

108 109 110
static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device)
{
	struct pcibus_info *pcibus_info;
111
	u16 busnum, segment, ioboard_type;
112 113 114 115 116 117 118

	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);

	/* Check to see if this is a valid slot on 'pci_bus' */
	if (!(pcibus_info->pbi_valid_devices & (1 << device)))
		return -EPERM;

119 120 121
	ioboard_type = sn_ioboard_to_pci_bus(pci_bus);
	busnum = pcibus_info->pbi_buscommon.bs_persist_busnum;
	segment = pci_domain_nr(pci_bus) & 0xf;
122 123

	/* Do not allow hotplug operations on base I/O cards */
124 125 126
	if ((ioboard_type == L1_BRICKTYPE_IX ||
	     ioboard_type == L1_BRICKTYPE_IA) &&
	    (segment == 1 && busnum == 0 && device != 1))
127 128 129 130 131 132 133 134
		return -EPERM;

	return 1;
}

static int sn_pci_bus_valid(struct pci_bus *pci_bus)
{
	struct pcibus_info *pcibus_info;
135 136
	u32 asic_type;
	u16 ioboard_type;
137 138

	/* Don't register slots hanging off the TIOCA bus */
139
	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
140 141 142 143 144
	asic_type = pcibus_info->pbi_buscommon.bs_asic_type;
	if (asic_type == PCIIO_ASIC_TYPE_TIOCA)
		return -EPERM;

	/* Only register slots in I/O Bricks that support hotplug */
145 146
	ioboard_type = sn_ioboard_to_pci_bus(pci_bus);
	switch (ioboard_type) {
147 148 149 150
		case L1_BRICKTYPE_IX:
		case L1_BRICKTYPE_PX:
		case L1_BRICKTYPE_IA:
		case L1_BRICKTYPE_PA:
151
		case L1_BOARDTYPE_PCIX3SLOT:
152 153 154 155 156
			return 1;
			break;
		default:
			return -EPERM;
			break;
157 158 159 160 161 162
	}

	return -EIO;
}

static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
163 164
				    struct pci_bus *pci_bus, int device,
				    char *name)
165 166 167 168 169 170
{
	struct pcibus_info *pcibus_info;
	struct slot *slot;

	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);

171
	slot = kzalloc(sizeof(*slot), GFP_KERNEL);
172
	if (!slot)
173
		return -ENOMEM;
174
	bss_hotplug_slot->private = slot;
175 176 177

	slot->device_num = device;
	slot->pci_bus = pci_bus;
178
	sprintf(name, "%04x:%02x:%02x",
179
		pci_domain_nr(pci_bus),
180
		((u16)pcibus_info->pbi_buscommon.bs_persist_busnum),
181
		device + 1);
182 183 184

	sn_generate_path(pci_bus, slot->physical_path);

185 186 187 188 189 190
	slot->hotplug_slot = bss_hotplug_slot;
	list_add(&slot->hp_list, &sn_hp_list);

	return 0;
}

Ryan Desfosses's avatar
Ryan Desfosses committed
191
static struct hotplug_slot *sn_hp_destroy(void)
192 193
{
	struct slot *slot;
Alex Chiang's avatar
Alex Chiang committed
194
	struct pci_slot *pci_slot;
195 196
	struct hotplug_slot *bss_hotplug_slot = NULL;

197
	list_for_each_entry(slot, &sn_hp_list, hp_list) {
198
		bss_hotplug_slot = slot->hotplug_slot;
Alex Chiang's avatar
Alex Chiang committed
199
		pci_slot = bss_hotplug_slot->pci_slot;
200 201
		list_del(&((struct slot *)bss_hotplug_slot->private)->
			 hp_list);
Alex Chiang's avatar
Alex Chiang committed
202
		sysfs_remove_file(&pci_slot->kobj,
203
				  &sn_slot_path_attr.attr);
204 205 206 207 208 209 210 211 212 213 214 215 216
		break;
	}
	return bss_hotplug_slot;
}

static void sn_bus_free_data(struct pci_dev *dev)
{
	struct pci_bus *subordinate_bus;
	struct pci_dev *child;

	/* Recursively clean up sn_irq_info structs */
	if (dev->subordinate) {
		subordinate_bus = dev->subordinate;
217
		list_for_each_entry(child, &subordinate_bus->devices, bus_list)
218 219
			sn_bus_free_data(child);
	}
220 221 222 223 224 225 226
	/*
	 * Some drivers may use dma accesses during the
	 * driver remove function. We release the sysdata
	 * areas after the driver remove functions have
	 * been called.
	 */
	sn_bus_store_sysdata(dev);
227 228 229 230
	sn_pci_unfixup_slot(dev);
}

static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
231
			  int device_num, char **ssdt)
232
{
233
	struct slot *slot = bss_hotplug_slot->private;
234 235 236 237 238 239 240 241 242 243
	struct pcibus_info *pcibus_info;
	struct pcibr_slot_enable_resp resp;
	int rc;

	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);

	/*
	 * Power-on and initialize the slot in the SN
	 * PCI infrastructure.
	 */
244 245
	rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt);

246 247

	if (rc == PCI_SLOT_ALREADY_UP) {
248
		dev_dbg(&slot->pci_bus->self->dev, "is already active\n");
249
		return 1; /* return 1 to user */
250 251 252
	}

	if (rc == PCI_L1_ERR) {
253
		dev_dbg(&slot->pci_bus->self->dev, "L1 failure %d with message: %s",
254 255 256 257 258
			resp.resp_sub_errno, resp.resp_l1_msg);
		return -EPERM;
	}

	if (rc) {
259
		dev_dbg(&slot->pci_bus->self->dev, "insert failed with error %d sub-error %d\n",
260 261 262 263
			rc, resp.resp_sub_errno);
		return -EIO;
	}

264 265
	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
	pcibus_info->pbi_enabled_devices |= (1 << device_num);
266 267 268 269 270 271 272

	return 0;
}

static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot,
			   int device_num, int action)
{
273
	struct slot *slot = bss_hotplug_slot->private;
274 275 276 277 278 279 280 281
	struct pcibus_info *pcibus_info;
	struct pcibr_slot_disable_resp resp;
	int rc;

	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);

	rc = sal_pcibr_slot_disable(pcibus_info, device_num, action, &resp);

282 283
	if ((action == PCI_REQ_SLOT_ELIGIBLE) &&
	    (rc == PCI_SLOT_ALREADY_DOWN)) {
284
		dev_dbg(&slot->pci_bus->self->dev, "Slot %s already inactive\n", slot->physical_path);
285
		return 1; /* return 1 to user */
286 287
	}

288
	if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_EMPTY_33MHZ)) {
289
		dev_dbg(&slot->pci_bus->self->dev, "Cannot remove last 33MHz card\n");
290 291 292
		return -EPERM;
	}

293
	if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_L1_ERR)) {
294
		dev_dbg(&slot->pci_bus->self->dev, "L1 failure %d with message \n%s\n",
295 296 297 298
			resp.resp_sub_errno, resp.resp_l1_msg);
		return -EPERM;
	}

299
	if ((action == PCI_REQ_SLOT_ELIGIBLE) && rc) {
300
		dev_dbg(&slot->pci_bus->self->dev, "remove failed with error %d sub-error %d\n",
301 302 303 304
			rc, resp.resp_sub_errno);
		return -EIO;
	}

305
	if ((action == PCI_REQ_SLOT_ELIGIBLE) && !rc)
306 307
		return 0;

308 309 310
	if ((action == PCI_REQ_SLOT_DISABLE) && !rc) {
		pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
		pcibus_info->pbi_enabled_devices &= ~(1 << device_num);
311
		dev_dbg(&slot->pci_bus->self->dev, "remove successful\n");
312 313 314
		return 0;
	}

315
	if ((action == PCI_REQ_SLOT_DISABLE) && rc) {
316
		dev_dbg(&slot->pci_bus->self->dev,"remove failed rc = %d\n", rc);
317 318 319 320 321
	}

	return rc;
}

322 323 324 325 326
/*
 * Power up and configure the slot via a SAL call to PROM.
 * Scan slot (and any children), do any platform specific fixup,
 * and find device driver.
 */
327 328
static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
{
329
	struct slot *slot = bss_hotplug_slot->private;
330 331
	struct pci_bus *new_bus = NULL;
	struct pci_dev *dev;
332
	int num_funcs;
333 334
	int new_ppb = 0;
	int rc;
335
	char *ssdt = NULL;
336
	void pcibios_fixup_device_resources(struct pci_dev *);
337 338

	/* Serialize the Linux PCI infrastructure */
339
	mutex_lock(&sn_hotplug_mutex);
340 341 342

	/*
	 * Power-on and initialize the slot in the SN
343 344
	 * PCI infrastructure. Also, retrieve the ACPI SSDT
	 * table for the slot (if ACPI capable PROM).
345
	 */
346
	rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt);
347
	if (rc) {
348
		mutex_unlock(&sn_hotplug_mutex);
349 350 351
		return rc;
	}

352 353 354 355 356 357 358 359 360
	if (ssdt)
		ssdt = __va(ssdt);
	/* Add the new SSDT for the slot to the ACPI namespace */
	if (SN_ACPI_BASE_SUPPORT() && ssdt) {
		acpi_status ret;

		ret = acpi_load_table((struct acpi_table_header *)ssdt);
		if (ACPI_FAILURE(ret)) {
			printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n",
361
			       __func__, ret);
362 363 364 365
			/* try to continue on */
		}
	}

366 367
	num_funcs = pci_scan_slot(slot->pci_bus,
				  PCI_DEVFN(slot->device_num + 1, 0));
368
	if (!num_funcs) {
369
		dev_dbg(&slot->pci_bus->self->dev, "no device in slot\n");
370
		mutex_unlock(&sn_hotplug_mutex);
371 372 373 374 375 376 377 378
		return -ENODEV;
	}

	/*
	 * Map SN resources for all functions on the card
	 * to the Linux PCI interface and tell the drivers
	 * about them.
	 */
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
	list_for_each_entry(dev, &slot->pci_bus->devices, bus_list) {
		if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
			continue;

		/* Need to do slot fixup on PPB before fixup of children
		 * (PPB's pcidev_info needs to be in pcidev_info list
		 * before child's SN_PCIDEV_INFO() call to setup
		 * pdi_host_pcidev_info).
		 */
		pcibios_fixup_device_resources(dev);
		if (SN_ACPI_BASE_SUPPORT())
			sn_acpi_slot_fixup(dev);
		else
			sn_io_slot_fixup(dev);
		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
			pci_hp_add_bridge(dev);
			if (dev->subordinate) {
				new_bus = dev->subordinate;
				new_ppb = 1;
398 399 400 401
			}
		}
	}

402 403 404
	/*
	 * Add the slot's devices to the ACPI infrastructure */
	if (SN_ACPI_BASE_SUPPORT() && ssdt) {
405
		unsigned long long adr;
406 407 408 409 410 411
		struct acpi_device *pdevice;
		acpi_handle phandle;
		acpi_handle chandle = NULL;
		acpi_handle rethandle;
		acpi_status ret;

412
		phandle = acpi_device_handle(PCI_CONTROLLER(slot->pci_bus)->companion);
413 414

		if (acpi_bus_get_device(phandle, &pdevice)) {
415
			dev_dbg(&slot->pci_bus->self->dev, "no parent device, assuming NULL\n");
416 417 418
			pdevice = NULL;
		}

419
		acpi_scan_lock_acquire();
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
		/*
		 * Walk the rootbus node's immediate children looking for
		 * the slot's device node(s). There can be more than
		 * one for multifunction devices.
		 */
		for (;;) {
			rethandle = NULL;
			ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
						   phandle, chandle,
						   &rethandle);

			if (ret == AE_NOT_FOUND || rethandle == NULL)
				break;

			chandle = rethandle;

			ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR,
						    NULL, &adr);

			if (ACPI_SUCCESS(ret) &&
			    (adr>>16) == (slot->device_num + 1)) {

442
				ret = acpi_bus_scan(chandle);
443
				if (ACPI_FAILURE(ret)) {
444 445
					printk(KERN_ERR "%s: acpi_bus_scan failed (0x%x) for slot %d func %d\n",
					       __func__, ret, (int)(adr>>16),
446 447 448 449 450
					       (int)(adr&0xffff));
					/* try to continue on */
				}
			}
		}
451
		acpi_scan_lock_release();
452 453
	}

454 455
	pci_lock_rescan_remove();

456 457 458 459 460 461
	/* Call the driver for the new device */
	pci_bus_add_devices(slot->pci_bus);
	/* Call the drivers for the new devices subordinate to PPB */
	if (new_ppb)
		pci_bus_add_devices(new_bus);

462
	pci_unlock_rescan_remove();
463
	mutex_unlock(&sn_hotplug_mutex);
464 465

	if (rc == 0)
466
		dev_dbg(&slot->pci_bus->self->dev, "insert operation successful\n");
467
	else
468
		dev_dbg(&slot->pci_bus->self->dev, "insert operation failed rc = %d\n", rc);
469 470 471 472 473 474

	return rc;
}

static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
{
475
	struct slot *slot = bss_hotplug_slot->private;
476
	struct pci_dev *dev, *temp;
477
	int rc;
478
	acpi_handle ssdt_hdl = NULL;
479 480

	/* Acquire update access to the bus */
481
	mutex_lock(&sn_hotplug_mutex);
482 483 484 485 486 487 488

	/* is it okay to bring this slot down? */
	rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
			     PCI_REQ_SLOT_ELIGIBLE);
	if (rc)
		goto leaving;

489 490
	/* free the ACPI resources for the slot */
	if (SN_ACPI_BASE_SUPPORT() &&
491
            PCI_CONTROLLER(slot->pci_bus)->companion) {
492
		unsigned long long adr;
493 494 495 496 497 498 499
		struct acpi_device *device;
		acpi_handle phandle;
		acpi_handle chandle = NULL;
		acpi_handle rethandle;
		acpi_status ret;

		/* Get the rootbus node pointer */
500
		phandle = acpi_device_handle(PCI_CONTROLLER(slot->pci_bus)->companion);
501

502
		acpi_scan_lock_acquire();
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
		/*
		 * Walk the rootbus node's immediate children looking for
		 * the slot's device node(s). There can be more than
		 * one for multifunction devices.
		 */
		for (;;) {
			rethandle = NULL;
			ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
						   phandle, chandle,
						   &rethandle);

			if (ret == AE_NOT_FOUND || rethandle == NULL)
				break;

			chandle = rethandle;

			ret = acpi_evaluate_integer(chandle,
						    METHOD_NAME__ADR,
						    NULL, &adr);
			if (ACPI_SUCCESS(ret) &&
			    (adr>>16) == (slot->device_num + 1)) {
				/* retain the owner id */
525
				ssdt_hdl = chandle;
526 527 528 529

				ret = acpi_bus_get_device(chandle,
							  &device);
				if (ACPI_SUCCESS(ret))
530
					acpi_bus_trim(device);
531 532
			}
		}
533
		acpi_scan_lock_release();
534 535
	}

536
	pci_lock_rescan_remove();
537
	/* Free the SN resources assigned to the Linux device.*/
538 539 540 541 542 543 544 545
	list_for_each_entry_safe(dev, temp, &slot->pci_bus->devices, bus_list) {
		if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
			continue;

		pci_dev_get(dev);
		sn_bus_free_data(dev);
		pci_stop_and_remove_bus_device(dev);
		pci_dev_put(dev);
546
	}
547
	pci_unlock_rescan_remove();
548

549
	/* Remove the SSDT for the slot from the ACPI namespace */
550
	if (SN_ACPI_BASE_SUPPORT() && ssdt_hdl) {
551
		acpi_status ret;
552
		ret = acpi_unload_parent_table(ssdt_hdl);
553
		if (ACPI_FAILURE(ret)) {
554 555 556
			acpi_handle_err(ssdt_hdl,
					"%s: acpi_unload_parent_table failed (0x%x)\n",
					__func__, ret);
557 558 559 560
			/* try to continue on */
		}
	}

561 562 563 564 565 566 567 568
	/* free the collected sysdata pointers */
	sn_bus_free_sysdata();

	/* Deactivate slot */
	rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
			     PCI_REQ_SLOT_DISABLE);
 leaving:
	/* Release the bus lock */
569
	mutex_unlock(&sn_hotplug_mutex);
570 571 572 573

	return rc;
}

574 575
static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot,
				   u8 *value)
576
{
577 578
	struct slot *slot = bss_hotplug_slot->private;
	struct pcibus_info *pcibus_info;
579
	u32 power;
580 581

	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
582
	mutex_lock(&sn_hotplug_mutex);
583 584
	power = pcibus_info->pbi_enabled_devices & (1 << slot->device_num);
	*value = power ? 1 : 0;
585
	mutex_unlock(&sn_hotplug_mutex);
586 587 588 589 590 591 592 593 594 595 596 597 598
	return 0;
}

static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot)
{
	kfree(bss_hotplug_slot->info);
	kfree(bss_hotplug_slot->private);
	kfree(bss_hotplug_slot);
}

static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
{
	int device;
Alex Chiang's avatar
Alex Chiang committed
599
	struct pci_slot *pci_slot;
600
	struct hotplug_slot *bss_hotplug_slot;
601
	char name[SN_SLOT_NAME_SIZE];
602 603 604 605 606 607 608 609 610 611 612
	int rc = 0;

	/*
	 * Currently only four devices are supported,
	 * in the future there maybe more -- up to 32.
	 */

	for (device = 0; device < SN_MAX_HP_SLOTS ; device++) {
		if (sn_pci_slot_valid(pci_bus, device) != 1)
			continue;

613
		bss_hotplug_slot = kzalloc(sizeof(*bss_hotplug_slot),
614 615 616 617 618 619 620
					   GFP_KERNEL);
		if (!bss_hotplug_slot) {
			rc = -ENOMEM;
			goto alloc_err;
		}

		bss_hotplug_slot->info =
621
			kzalloc(sizeof(struct hotplug_slot_info),
622 623 624 625 626 627 628
				GFP_KERNEL);
		if (!bss_hotplug_slot->info) {
			rc = -ENOMEM;
			goto alloc_err;
		}

		if (sn_hp_slot_private_alloc(bss_hotplug_slot,
629
					     pci_bus, device, name)) {
630 631 632 633 634 635
			rc = -ENOMEM;
			goto alloc_err;
		}
		bss_hotplug_slot->ops = &sn_hotplug_slot_ops;
		bss_hotplug_slot->release = &sn_release_slot;

636
		rc = pci_hp_register(bss_hotplug_slot, pci_bus, device, name);
637 638
		if (rc)
			goto register_err;
639

Alex Chiang's avatar
Alex Chiang committed
640 641
		pci_slot = bss_hotplug_slot->pci_slot;
		rc = sysfs_create_file(&pci_slot->kobj,
642 643 644
				       &sn_slot_path_attr.attr);
		if (rc)
			goto register_err;
645
	}
646
	dev_dbg(&pci_bus->self->dev, "Registered bus with hotplug\n");
647 648 649
	return rc;

register_err:
650
	dev_dbg(&pci_bus->self->dev, "bus failed to register with err = %d\n",
651
		rc);
652 653 654

alloc_err:
	if (rc == -ENOMEM)
655
		dev_dbg(&pci_bus->self->dev, "Memory allocation error\n");
656 657 658 659 660 661 662 663 664 665 666 667

	/* destroy THIS element */
	if (bss_hotplug_slot)
		sn_release_slot(bss_hotplug_slot);

	/* destroy anything else on the list */
	while ((bss_hotplug_slot = sn_hp_destroy()))
		pci_hp_deregister(bss_hotplug_slot);

	return rc;
}

668
static int __init sn_pci_hotplug_init(void)
669 670 671 672 673
{
	struct pci_bus *pci_bus = NULL;
	int rc;
	int registered = 0;

674 675
	if (!sn_prom_feature_available(PRF_HOTPLUG_SUPPORT)) {
		printk(KERN_ERR "%s: PROM version does not support hotplug.\n",
676
		       __func__);
677 678 679
		return -EPERM;
	}

680 681
	INIT_LIST_HEAD(&sn_hp_list);

682 683 684 685 686 687
	while ((pci_bus = pci_find_next_bus(pci_bus))) {
		if (!pci_bus->sysdata)
			continue;

		rc = sn_pci_bus_valid(pci_bus);
		if (rc != 1) {
688
			dev_dbg(&pci_bus->self->dev, "not a valid hotplug bus\n");
689 690
			continue;
		}
691
		dev_dbg(&pci_bus->self->dev, "valid hotplug bus\n");
692 693

		rc = sn_hotplug_slot_register(pci_bus);
694
		if (!rc) {
695
			registered = 1;
696
		} else {
697 698 699 700 701 702 703 704
			registered = 0;
			break;
		}
	}

	return registered == 1 ? 0 : -ENODEV;
}

705
static void __exit sn_pci_hotplug_exit(void)
706 707 708
{
	struct hotplug_slot *bss_hotplug_slot;

709
	while ((bss_hotplug_slot = sn_hp_destroy()))
710 711 712 713 714 715 716 717
		pci_hp_deregister(bss_hotplug_slot);

	if (!list_empty(&sn_hp_list))
		printk(KERN_ERR "%s: internal list is not empty\n", __FILE__);
}

module_init(sn_pci_hotplug_init);
module_exit(sn_pci_hotplug_exit);