Commit 6f09a925 authored by John Keller's avatar John Keller Committed by Len Brown

Altix: ACPI SSDT PCI device support

Add SN platform support for running with an ACPI
capable PROM that defines PCI devices in SSDT
tables. There is a SSDT table for every occupied
slot on a root bus, containing info for every
PPB and/or device on the bus. The SSDTs will be
dynamically loaded/unloaded at hotplug enable/disable.

Platform specific information that is currently
passed via a SAL call, will now be passed via the
Vendor resource in the ACPI Device object(s) defined
in each SSDT.
Signed-off-by: default avatarJohn Keller <jpk@sgi.com>
Cc: Greg KH <greg@kroah.com>
Cc: "Luck, Tony" <tony.luck@intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 647fb47d
This diff is collapsed.
...@@ -26,14 +26,10 @@ ...@@ -26,14 +26,10 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <asm/sn/sn2/sn_hwperf.h> #include <asm/sn/sn2/sn_hwperf.h>
#include <asm/sn/acpi.h> #include <asm/sn/acpi.h>
#include "acpi/acglobal.h"
extern void sn_init_cpei_timer(void); extern void sn_init_cpei_timer(void);
extern void register_sn_procfs(void); extern void register_sn_procfs(void);
extern void sn_acpi_bus_fixup(struct pci_bus *);
extern void sn_bus_fixup(struct pci_bus *);
extern void sn_acpi_slot_fixup(struct pci_dev *, struct pcidev_info *);
extern void sn_more_slot_fixup(struct pci_dev *, struct pcidev_info *);
extern void sn_legacy_pci_window_fixup(struct pci_controller *, u64, u64);
extern void sn_io_acpi_init(void); extern void sn_io_acpi_init(void);
extern void sn_io_init(void); extern void sn_io_init(void);
...@@ -48,16 +44,10 @@ struct sysdata_el { ...@@ -48,16 +44,10 @@ struct sysdata_el {
int sn_ioif_inited; /* SN I/O infrastructure initialized? */ int sn_ioif_inited; /* SN I/O infrastructure initialized? */
struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */ int sn_acpi_rev; /* SN ACPI revision */
EXPORT_SYMBOL_GPL(sn_acpi_rev);
int sn_acpi_base_support(void) struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */
{
struct acpi_table_header *header;
(void)acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header);
if (header && header->oem_revision >= 0x20101)
return 1;
return 0;
}
/* /*
* Hooks and struct for unsupported pci providers * Hooks and struct for unsupported pci providers
...@@ -107,25 +97,6 @@ sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num, ...@@ -107,25 +97,6 @@ sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num,
return ret_stuff.status; return ret_stuff.status;
} }
/*
* Retrieve the pci device information given the bus and device|function number.
*/
static inline u64
sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
u64 sn_irq_info)
{
struct ia64_sal_retval ret_stuff;
ret_stuff.status = 0;
ret_stuff.v0 = 0;
SAL_CALL_NOLOCK(ret_stuff,
(u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
(u64) segment, (u64) bus_number, (u64) devfn,
(u64) pci_dev,
sn_irq_info, 0, 0);
return ret_stuff.v0;
}
/* /*
* sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified
* device. * device.
...@@ -258,50 +229,25 @@ void sn_pci_unfixup_slot(struct pci_dev *dev) ...@@ -258,50 +229,25 @@ void sn_pci_unfixup_slot(struct pci_dev *dev)
} }
/* /*
* sn_pci_fixup_slot() - This routine sets up a slot's resources consistent * sn_pci_fixup_slot()
* with the Linux PCI abstraction layer. Resources
* acquired from our PCI provider include PIO maps
* to BAR space and interrupt objects.
*/ */
void sn_pci_fixup_slot(struct pci_dev *dev) void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *pcidev_info,
struct sn_irq_info *sn_irq_info)
{ {
int segment = pci_domain_nr(dev->bus); int segment = pci_domain_nr(dev->bus);
int status = 0;
struct pcibus_bussoft *bs; struct pcibus_bussoft *bs;
struct pci_bus *host_pci_bus; struct pci_bus *host_pci_bus;
struct pci_dev *host_pci_dev; struct pci_dev *host_pci_dev;
struct pcidev_info *pcidev_info; unsigned int bus_no, devfn;
struct sn_irq_info *sn_irq_info;
unsigned int bus_no, devfn;
pci_dev_get(dev); /* for the sysdata pointer */ pci_dev_get(dev); /* for the sysdata pointer */
pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
if (!pcidev_info)
BUG(); /* Cannot afford to run out of memory */
sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
if (!sn_irq_info)
BUG(); /* Cannot afford to run out of memory */
/* Call to retrieve pci device information needed by kernel. */
status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number,
dev->devfn,
(u64) __pa(pcidev_info),
(u64) __pa(sn_irq_info));
if (status)
BUG(); /* Cannot get platform pci device information */
/* Add pcidev_info to list in pci_controller.platform_data */ /* Add pcidev_info to list in pci_controller.platform_data */
list_add_tail(&pcidev_info->pdi_list, list_add_tail(&pcidev_info->pdi_list,
&(SN_PLATFORM_DATA(dev->bus)->pcidev_info)); &(SN_PLATFORM_DATA(dev->bus)->pcidev_info));
if (SN_ACPI_BASE_SUPPORT())
sn_acpi_slot_fixup(dev, pcidev_info);
else
sn_more_slot_fixup(dev, pcidev_info);
/* /*
* Using the PROMs values for the PCI host bus, get the Linux * Using the PROMs values for the PCI host bus, get the Linux
* PCI host_pci_dev struct and set up host bus linkages * PCI host_pci_dev struct and set up host bus linkages
*/ */
bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff; bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff;
...@@ -498,11 +444,6 @@ void sn_generate_path(struct pci_bus *pci_bus, char *address) ...@@ -498,11 +444,6 @@ void sn_generate_path(struct pci_bus *pci_bus, char *address)
sprintf(address, "%s^%d", address, geo_slot(geoid)); sprintf(address, "%s^%d", address, geo_slot(geoid));
} }
/*
* sn_pci_fixup_bus() - Perform SN specific setup of software structs
* (pcibus_bussoft, pcidev_info) and hardware
* registers, for the specified bus and devices under it.
*/
void __devinit void __devinit
sn_pci_fixup_bus(struct pci_bus *bus) sn_pci_fixup_bus(struct pci_bus *bus)
{ {
...@@ -528,6 +469,15 @@ sn_io_early_init(void) ...@@ -528,6 +469,15 @@ sn_io_early_init(void)
if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM()) if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM())
return 0; return 0;
/* we set the acpi revision to that of the DSDT table OEM rev. */
{
struct acpi_table_header *header = NULL;
acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header);
BUG_ON(header == NULL);
sn_acpi_rev = header->oem_revision;
}
/* /*
* prime sn_pci_provider[]. Individial provider init routines will * prime sn_pci_provider[]. Individial provider init routines will
* override their respective default entries. * override their respective default entries.
...@@ -618,7 +568,6 @@ sn_io_late_init(void) ...@@ -618,7 +568,6 @@ sn_io_late_init(void)
fs_initcall(sn_io_late_init); fs_initcall(sn_io_late_init);
EXPORT_SYMBOL(sn_pci_fixup_slot);
EXPORT_SYMBOL(sn_pci_unfixup_slot); EXPORT_SYMBOL(sn_pci_unfixup_slot);
EXPORT_SYMBOL(sn_bus_store_sysdata); EXPORT_SYMBOL(sn_bus_store_sysdata);
EXPORT_SYMBOL(sn_bus_free_sysdata); EXPORT_SYMBOL(sn_bus_free_sysdata);
......
...@@ -56,6 +56,25 @@ static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address) ...@@ -56,6 +56,25 @@ static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
return ret_stuff.v0; return ret_stuff.v0;
} }
/*
* Retrieve the pci device information given the bus and device|function number.
*/
static inline u64
sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
u64 sn_irq_info)
{
struct ia64_sal_retval ret_stuff;
ret_stuff.status = 0;
ret_stuff.v0 = 0;
SAL_CALL_NOLOCK(ret_stuff,
(u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
(u64) segment, (u64) bus_number, (u64) devfn,
(u64) pci_dev,
sn_irq_info, 0, 0);
return ret_stuff.v0;
}
/* /*
* sn_fixup_ionodes() - This routine initializes the HUB data structure for * sn_fixup_ionodes() - This routine initializes the HUB data structure for
...@@ -172,18 +191,40 @@ sn_pci_window_fixup(struct pci_dev *dev, unsigned int count, ...@@ -172,18 +191,40 @@ sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
} }
/* /*
* sn_more_slot_fixup() - We are not running with an ACPI capable PROM, * sn_io_slot_fixup() - We are not running with an ACPI capable PROM,
* and need to convert the pci_dev->resource * and need to convert the pci_dev->resource
* 'start' and 'end' addresses to mapped addresses, * 'start' and 'end' addresses to mapped addresses,
* and setup the pci_controller->window array entries. * and setup the pci_controller->window array entries.
*/ */
void void
sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info) sn_io_slot_fixup(struct pci_dev *dev)
{ {
unsigned int count = 0; unsigned int count = 0;
int idx; int idx;
s64 pci_addrs[PCI_ROM_RESOURCE + 1]; s64 pci_addrs[PCI_ROM_RESOURCE + 1];
unsigned long addr, end, size, start; unsigned long addr, end, size, start;
struct pcidev_info *pcidev_info;
struct sn_irq_info *sn_irq_info;
int status;
pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
if (!pcidev_info)
panic("%s: Unable to alloc memory for pcidev_info", __FUNCTION__);
sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
if (!sn_irq_info)
panic("%s: Unable to alloc memory for sn_irq_info", __FUNCTION__);
/* Call to retrieve pci device information needed by kernel. */
status = sal_get_pcidev_info((u64) pci_domain_nr(dev),
(u64) dev->bus->number,
dev->devfn,
(u64) __pa(pcidev_info),
(u64) __pa(sn_irq_info));
if (status)
BUG(); /* Cannot get platform pci device information */
/* Copy over PIO Mapped Addresses */ /* Copy over PIO Mapped Addresses */
for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
...@@ -219,8 +260,12 @@ sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info) ...@@ -219,8 +260,12 @@ sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
*/ */
if (count > 0) if (count > 0)
sn_pci_window_fixup(dev, count, pci_addrs); sn_pci_window_fixup(dev, count, pci_addrs);
sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
} }
EXPORT_SYMBOL(sn_io_slot_fixup);
/* /*
* sn_pci_controller_fixup() - This routine sets up a bus's resources * sn_pci_controller_fixup() - This routine sets up a bus's resources
* consistent with the Linux PCI abstraction layer. * consistent with the Linux PCI abstraction layer.
...@@ -272,9 +317,6 @@ sn_bus_fixup(struct pci_bus *bus) ...@@ -272,9 +317,6 @@ sn_bus_fixup(struct pci_bus *bus)
{ {
struct pci_dev *pci_dev = NULL; struct pci_dev *pci_dev = NULL;
struct pcibus_bussoft *prom_bussoft_ptr; struct pcibus_bussoft *prom_bussoft_ptr;
extern void sn_common_bus_fixup(struct pci_bus *,
struct pcibus_bussoft *);
if (!bus->parent) { /* If root bus */ if (!bus->parent) { /* If root bus */
prom_bussoft_ptr = PCI_CONTROLLER(bus)->platform_data; prom_bussoft_ptr = PCI_CONTROLLER(bus)->platform_data;
...@@ -291,7 +333,7 @@ sn_bus_fixup(struct pci_bus *bus) ...@@ -291,7 +333,7 @@ sn_bus_fixup(struct pci_bus *bus)
prom_bussoft_ptr->bs_legacy_mem); prom_bussoft_ptr->bs_legacy_mem);
} }
list_for_each_entry(pci_dev, &bus->devices, bus_list) { list_for_each_entry(pci_dev, &bus->devices, bus_list) {
sn_pci_fixup_slot(pci_dev); sn_io_slot_fixup(pci_dev);
} }
} }
......
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
#include "xtalk/hubdev.h" #include "xtalk/hubdev.h"
int int
sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp) sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp,
char **ssdt)
{ {
struct ia64_sal_retval ret_stuff; struct ia64_sal_retval ret_stuff;
u64 busnum; u64 busnum;
...@@ -32,7 +33,8 @@ sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp) ...@@ -32,7 +33,8 @@ sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp)
segment = soft->pbi_buscommon.bs_persist_segment; segment = soft->pbi_buscommon.bs_persist_segment;
busnum = soft->pbi_buscommon.bs_persist_busnum; busnum = soft->pbi_buscommon.bs_persist_busnum;
SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, segment, SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, segment,
busnum, (u64) device, (u64) resp, 0, 0, 0); busnum, (u64) device, (u64) resp, (u64)ia64_tpa(ssdt),
0, 0);
return (int)ret_stuff.v0; return (int)ret_stuff.v0;
} }
......
...@@ -11,8 +11,7 @@ ...@@ -11,8 +11,7 @@
#include "acpi/acglobal.h" #include "acpi/acglobal.h"
#define SN_ACPI_BASE_SUPPORT() sn_acpi_base_support() extern int sn_acpi_rev;
#define SN_ACPI_BASE_SUPPORT() (sn_acpi_rev >= 0x20101)
extern int sn_acpi_base_support(void);
#endif /* _ASM_IA64_SN_ACPI_H */ #endif /* _ASM_IA64_SN_ACPI_H */
...@@ -142,7 +142,7 @@ extern int pcibr_ate_alloc(struct pcibus_info *, int); ...@@ -142,7 +142,7 @@ extern int pcibr_ate_alloc(struct pcibus_info *, int);
extern void pcibr_ate_free(struct pcibus_info *, int); extern void pcibr_ate_free(struct pcibus_info *, int);
extern void ate_write(struct pcibus_info *, int, int, u64); extern void ate_write(struct pcibus_info *, int, int, u64);
extern int sal_pcibr_slot_enable(struct pcibus_info *soft, int device, extern int sal_pcibr_slot_enable(struct pcibus_info *soft, int device,
void *resp); void *resp, char **ssdt);
extern int sal_pcibr_slot_disable(struct pcibus_info *soft, int device, extern int sal_pcibr_slot_disable(struct pcibus_info *soft, int device,
int action, void *resp); int action, void *resp);
extern u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus); extern u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus);
......
...@@ -70,10 +70,16 @@ extern void sn_irq_fixup(struct pci_dev *pci_dev, ...@@ -70,10 +70,16 @@ extern void sn_irq_fixup(struct pci_dev *pci_dev,
struct sn_irq_info *sn_irq_info); struct sn_irq_info *sn_irq_info);
extern void sn_irq_unfixup(struct pci_dev *pci_dev); extern void sn_irq_unfixup(struct pci_dev *pci_dev);
extern struct pcidev_info * sn_pcidev_info_get(struct pci_dev *); extern struct pcidev_info * sn_pcidev_info_get(struct pci_dev *);
extern void sn_bus_fixup(struct pci_bus *);
extern void sn_acpi_bus_fixup(struct pci_bus *);
extern void sn_common_bus_fixup(struct pci_bus *, struct pcibus_bussoft *);
extern void sn_bus_store_sysdata(struct pci_dev *dev); extern void sn_bus_store_sysdata(struct pci_dev *dev);
extern void sn_bus_free_sysdata(void); extern void sn_bus_free_sysdata(void);
extern void sn_generate_path(struct pci_bus *pci_bus, char *address); extern void sn_generate_path(struct pci_bus *pci_bus, char *address);
extern void sn_pci_fixup_slot(struct pci_dev *dev); extern void sn_io_slot_fixup(struct pci_dev *);
extern void sn_acpi_slot_fixup(struct pci_dev *);
extern void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *,
struct sn_irq_info *);
extern void sn_pci_unfixup_slot(struct pci_dev *dev); extern void sn_pci_unfixup_slot(struct pci_dev *dev);
extern void sn_irq_lh_init(void); extern void sn_irq_lh_init(void);
#endif /* _ASM_IA64_SN_PCI_PCIDEV_H */ #endif /* _ASM_IA64_SN_PCI_PCIDEV_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment