Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 46425
b: refs/heads/master
c: 3e643e7
h: refs/heads/master
i:
  46423: e4e38cf
v: v3
  • Loading branch information
John Keller authored and Len Brown committed Feb 3, 2007
1 parent 6e80102 commit 3b134b3
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 8 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6f09a9250a5d76c0765cd51a33e0a042e9761cfc
refs/heads/master: 3e643e77a929202455a0cc868c2030a5ba8d1371
155 changes: 148 additions & 7 deletions trunk/drivers/pci/hotplug/sgi_hotplug.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,26 @@
#include <asm/sn/sn_feature_sets.h>
#include <asm/sn/sn_sal.h>
#include <asm/sn/types.h>
#include <linux/acpi.h>
#include <asm/sn/acpi.h>

#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");

#define PCIIO_ASIC_TYPE_TIOCA 4

/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */
#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 */


#define PCIIO_ASIC_TYPE_TIOCA 4
#define PCI_L1_QSIZE 128 /* our L1 message buffer size */
#define SN_MAX_HP_SLOTS 32 /* max hotplug slots */
#define SGI_HOTPLUG_PROM_REV 0x0430 /* Min. required PROM version */
#define SN_SLOT_NAME_SIZE 33 /* size of name string */

/* internal list head */
Expand Down Expand Up @@ -227,7 +232,7 @@ static void sn_bus_free_data(struct pci_dev *dev)
}

static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
int device_num)
int device_num, char **ssdt)
{
struct slot *slot = bss_hotplug_slot->private;
struct pcibus_info *pcibus_info;
Expand All @@ -240,7 +245,8 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
* Power-on and initialize the slot in the SN
* PCI infrastructure.
*/
rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp);
rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt);


if (rc == PCI_SLOT_ALREADY_UP) {
dev_dbg(slot->pci_bus->self, "is already active\n");
Expand Down Expand Up @@ -335,21 +341,37 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
int func, num_funcs;
int new_ppb = 0;
int rc;
char *ssdt = NULL;
void pcibios_fixup_device_resources(struct pci_dev *);

/* Serialize the Linux PCI infrastructure */
mutex_lock(&sn_hotplug_mutex);

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

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",
__FUNCTION__, ret);
/* try to continue on */
}
}

num_funcs = pci_scan_slot(slot->pci_bus,
PCI_DEVFN(slot->device_num + 1, 0));
if (!num_funcs) {
Expand All @@ -374,7 +396,10 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
* pdi_host_pcidev_info).
*/
pcibios_fixup_device_resources(dev);
sn_pci_fixup_slot(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) {
unsigned char sec_bus;
pci_read_config_byte(dev, PCI_SECONDARY_BUS,
Expand All @@ -388,6 +413,63 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
}
}

/*
* Add the slot's devices to the ACPI infrastructure */
if (SN_ACPI_BASE_SUPPORT() && ssdt) {
unsigned long adr;
struct acpi_device *pdevice;
struct acpi_device *device;
acpi_handle phandle;
acpi_handle chandle = NULL;
acpi_handle rethandle;
acpi_status ret;

phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;

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

/*
* 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)) {

ret = acpi_bus_add(&device, pdevice, chandle,
ACPI_BUS_TYPE_DEVICE);
if (ACPI_FAILURE(ret)) {
printk(KERN_ERR "%s: acpi_bus_add "
"failed (0x%x) for slot %d "
"func %d\n", __FUNCTION__,
ret, (int)(adr>>16),
(int)(adr&0xffff));
/* try to continue on */
} else {
acpi_bus_start(device);
}
}
}
}

/* Call the driver for the new device */
pci_bus_add_devices(slot->pci_bus);
/* Call the drivers for the new devices subordinate to PPB */
Expand All @@ -412,6 +494,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
struct pci_dev *dev;
int func;
int rc;
acpi_owner_id ssdt_id = 0;

/* Acquire update access to the bus */
mutex_lock(&sn_hotplug_mutex);
Expand All @@ -422,6 +505,52 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
if (rc)
goto leaving;

/* free the ACPI resources for the slot */
if (SN_ACPI_BASE_SUPPORT() &&
PCI_CONTROLLER(slot->pci_bus)->acpi_handle) {
unsigned long adr;
struct acpi_device *device;
acpi_handle phandle;
acpi_handle chandle = NULL;
acpi_handle rethandle;
acpi_status ret;

/* Get the rootbus node pointer */
phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;

/*
* 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 */
acpi_get_id(chandle, &ssdt_id);

ret = acpi_bus_get_device(chandle,
&device);
if (ACPI_SUCCESS(ret))
acpi_bus_trim(device, 1);
}
}

}

/* Free the SN resources assigned to the Linux device.*/
for (func = 0; func < 8; func++) {
dev = pci_get_slot(slot->pci_bus,
Expand All @@ -434,6 +563,18 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
}
}

/* Remove the SSDT for the slot from the ACPI namespace */
if (SN_ACPI_BASE_SUPPORT() && ssdt_id) {
acpi_status ret;
ret = acpi_unload_table_id(ssdt_id);
if (ACPI_FAILURE(ret)) {
printk(KERN_ERR "%s: acpi_unload_table_id "
"failed (0x%x) for id %d\n",
__FUNCTION__, ret, ssdt_id);
/* try to continue on */
}
}

/* free the collected sysdata pointers */
sn_bus_free_sysdata();

Expand Down

0 comments on commit 3b134b3

Please sign in to comment.