Commit 934b6519 authored by Pat Gefre's avatar Pat Gefre Committed by David Mosberger

[PATCH] ia64: add Altix hotplug support

parent 4ce0447a
......@@ -384,6 +384,80 @@ sn_pci_fixup_slot(struct pci_dev *dev)
return 0;
}
#ifdef CONFIG_HOTPLUG_PCI_SGI
void
sn_dma_flush_clear(struct sn_flush_device_list *dma_flush_list,
unsigned long start, unsigned long end)
{
int i;
dma_flush_list->pin = -1;
dma_flush_list->bus = -1;
dma_flush_list->slot = -1;
for (i = 0; i < PCI_ROM_RESOURCE; i++)
if ((dma_flush_list->bar_list[i].start == start) &&
(dma_flush_list->bar_list[i].end == end)) {
dma_flush_list->bar_list[i].start = 0;
dma_flush_list->bar_list[i].end = 0;
break;
}
}
/*
* sn_pci_unfixup_slot() - This routine frees a slot's resources
* consistent with the Linux PCI abstraction layer. Resources released
* back to our PCI provider include PIO maps to BAR space and interrupt
* objects.
*/
void
sn_pci_unfixup_slot(struct pci_dev *dev)
{
struct sn_device_sysdata *device_sysdata;
vertex_hdl_t vhdl;
pciio_intr_t intr_handle;
unsigned int irq;
unsigned long size;
int idx;
device_sysdata = SN_DEVICE_SYSDATA(dev);
vhdl = device_sysdata->vhdl;
if (device_sysdata->dma_flush_list)
for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) {
size = dev->resource[idx].end -
dev->resource[idx].start;
if (size == 0) continue;
sn_dma_flush_clear(device_sysdata->dma_flush_list,
dev->resource[idx].start,
dev->resource[idx].end);
}
intr_handle = device_sysdata->intr_handle;
if (intr_handle) {
extern void unregister_pcibr_intr(int, pcibr_intr_t);
irq = intr_handle->pi_irq;
irqpdaindr->device_dev[irq] = NULL;
unregister_pcibr_intr(irq, (pcibr_intr_t) intr_handle);
pciio_intr_disconnect(intr_handle);
pciio_intr_free(intr_handle);
}
for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) {
if (device_sysdata->pio_map[idx]) {
pciio_piomap_done (device_sysdata->pio_map[idx]);
pciio_piomap_free (device_sysdata->pio_map[idx]);
}
}
}
#endif /* CONFIG_HOTPLUG_PCI_SGI */
struct sn_flush_nasid_entry flush_nasid_list[MAX_NASIDS];
/* Initialize the data structures for flushing write buffers after a PIO read.
......@@ -534,6 +608,7 @@ sn_dma_flush_init(unsigned long start, unsigned long end, int idx, int pin, int
return p;
}
/*
* linux_bus_cvlink() Creates a link between the Linux PCI Bus number
* to the actual hardware component that it represents:
......@@ -774,7 +849,7 @@ sn_pci_init (void)
printk(KERN_WARNING
"sn_pci_fixup: sn_pci_fixup_bus fails : error %d\n",
ret);
return;
return 0;
}
}
......@@ -805,7 +880,7 @@ sn_pci_init (void)
printk(KERN_WARNING
"sn_pci_fixup: sn_pci_fixup_slot fails : error %d\n",
ret);
return;
return 0;
}
}
......
......@@ -629,6 +629,8 @@ pcibr_driver_reg_callback(vertex_hdl_t pconn_vhdl,
pcibr_soft = pcibr_soft_get(pcibr_vhdl);
pcibr_info->f_att_det_error = error;
#ifdef CONFIG_HOTPLUG_PCI_SGI
pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
if (error) {
......@@ -636,6 +638,7 @@ pcibr_driver_reg_callback(vertex_hdl_t pconn_vhdl,
} else {
pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT;
}
#endif /* CONFIG_HOTPLUG_PCI_SGI */
}
/*
......@@ -668,6 +671,7 @@ pcibr_driver_unreg_callback(vertex_hdl_t pconn_vhdl,
pcibr_soft = pcibr_soft_get(pcibr_vhdl);
pcibr_info->f_att_det_error = error;
#ifdef CONFIG_HOTPLUG_PCI_SGI
pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
if (error) {
......@@ -675,6 +679,7 @@ pcibr_driver_unreg_callback(vertex_hdl_t pconn_vhdl,
} else {
pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT;
}
#endif /* CONFIG_HOTPLUG_PCI_SGI */
}
/*
......
......@@ -16,6 +16,7 @@
#include <asm/sn/pci/pcibr_private.h>
#include <asm/sn/pci/pci_defs.h>
#include <asm/sn/sn_private.h>
#include <asm/sn/sn_sal.h>
extern pcibr_info_t pcibr_info_get(vertex_hdl_t);
extern int pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl);
......@@ -58,6 +59,411 @@ void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t);
int max_splittrans_to_numbuf[MAX_SPLIT_TABLE] = {1, 2, 3, 4, 8, 12, 16, 32};
int max_readcount_to_bufsize[MAX_READCNT_TABLE] = {512, 1024, 2048, 4096 };
#ifdef CONFIG_HOTPLUG_PCI_SGI
/*
* PCI slot manipulation errors from the system controller, and their
* associated descriptions
*/
#define SYSCTL_REQERR_BASE (-106000)
#define SYSCTL_PCI_ERROR_BASE (SYSCTL_REQERR_BASE - 100)
#define SYSCTL_PCIX_ERROR_BASE (SYSCTL_REQERR_BASE - 3000)
struct sysctl_pci_error_s {
int error;
char *msg;
} sysctl_pci_errors[] = {
#define SYSCTL_PCI_UNINITIALIZED (SYSCTL_PCI_ERROR_BASE - 0)
{ SYSCTL_PCI_UNINITIALIZED, "module not initialized" },
#define SYSCTL_PCI_UNSUPPORTED_BUS (SYSCTL_PCI_ERROR_BASE - 1)
{ SYSCTL_PCI_UNSUPPORTED_BUS, "unsupported bus" },
#define SYSCTL_PCI_UNSUPPORTED_SLOT (SYSCTL_PCI_ERROR_BASE - 2)
{ SYSCTL_PCI_UNSUPPORTED_SLOT, "unsupported slot" },
#define SYSCTL_PCI_POWER_NOT_OKAY (SYSCTL_PCI_ERROR_BASE - 3)
{ SYSCTL_PCI_POWER_NOT_OKAY, "slot power not okay" },
#define SYSCTL_PCI_CARD_NOT_PRESENT (SYSCTL_PCI_ERROR_BASE - 4)
{ SYSCTL_PCI_CARD_NOT_PRESENT, "card not present" },
#define SYSCTL_PCI_POWER_LIMIT (SYSCTL_PCI_ERROR_BASE - 5)
{ SYSCTL_PCI_POWER_LIMIT, "power limit reached - some cards not powered up" },
#define SYSCTL_PCI_33MHZ_ON_66MHZ (SYSCTL_PCI_ERROR_BASE - 6)
{ SYSCTL_PCI_33MHZ_ON_66MHZ, "cannot add a 33 MHz card to an active 66 MHz bus" },
#define SYSCTL_PCI_INVALID_ORDER (SYSCTL_PCI_ERROR_BASE - 7)
{ SYSCTL_PCI_INVALID_ORDER, "invalid reset order" },
#define SYSCTL_PCI_DOWN_33MHZ (SYSCTL_PCI_ERROR_BASE - 8)
{ SYSCTL_PCI_DOWN_33MHZ, "cannot power down a 33 MHz card on an active bus" },
#define SYSCTL_PCI_RESET_33MHZ (SYSCTL_PCI_ERROR_BASE - 9)
{ SYSCTL_PCI_RESET_33MHZ, "cannot reset a 33 MHz card on an active bus" },
#define SYSCTL_PCI_SLOT_NOT_UP (SYSCTL_PCI_ERROR_BASE - 10)
{ SYSCTL_PCI_SLOT_NOT_UP, "cannot reset a slot that is not powered up" },
#define SYSCTL_PCIX_UNINITIALIZED (SYSCTL_PCIX_ERROR_BASE - 0)
{ SYSCTL_PCIX_UNINITIALIZED, "module not initialized" },
#define SYSCTL_PCIX_UNSUPPORTED_BUS (SYSCTL_PCIX_ERROR_BASE - 1)
{ SYSCTL_PCIX_UNSUPPORTED_BUS, "unsupported bus" },
#define SYSCTL_PCIX_UNSUPPORTED_SLOT (SYSCTL_PCIX_ERROR_BASE - 2)
{ SYSCTL_PCIX_UNSUPPORTED_SLOT, "unsupported slot" },
#define SYSCTL_PCIX_POWER_NOT_OKAY (SYSCTL_PCIX_ERROR_BASE - 3)
{ SYSCTL_PCIX_POWER_NOT_OKAY, "slot power not okay" },
#define SYSCTL_PCIX_CARD_NOT_PRESENT (SYSCTL_PCIX_ERROR_BASE - 4)
{ SYSCTL_PCIX_CARD_NOT_PRESENT, "card not present" },
#define SYSCTL_PCIX_POWER_LIMIT (SYSCTL_PCIX_ERROR_BASE - 5)
{ SYSCTL_PCIX_POWER_LIMIT, "power limit reached - some cards not powered up" },
#define SYSCTL_PCIX_33MHZ_ON_66MHZ (SYSCTL_PCIX_ERROR_BASE - 6)
{ SYSCTL_PCIX_33MHZ_ON_66MHZ, "cannot add a 33 MHz card to an active 66 MHz bus" },
#define SYSCTL_PCIX_PCI_ON_PCIX (SYSCTL_PCIX_ERROR_BASE - 7)
{ SYSCTL_PCIX_PCI_ON_PCIX, "cannot add a PCI card to an active PCIX bus" },
#define SYSCTL_PCIX_ANYTHING_ON_133MHZ (SYSCTL_PCIX_ERROR_BASE - 8)
{ SYSCTL_PCIX_ANYTHING_ON_133MHZ, "cannot add any card to an active 133MHz PCIX bus" },
#define SYSCTL_PCIX_X66MHZ_ON_X100MHZ (SYSCTL_PCIX_ERROR_BASE - 9)
{ SYSCTL_PCIX_X66MHZ_ON_X100MHZ, "cannot add a PCIX 66MHz card to an active 100MHz PCIX bus" },
#define SYSCTL_PCIX_INVALID_ORDER (SYSCTL_PCIX_ERROR_BASE - 10)
{ SYSCTL_PCIX_INVALID_ORDER, "invalid reset order" },
#define SYSCTL_PCIX_DOWN_33MHZ (SYSCTL_PCIX_ERROR_BASE - 11)
{ SYSCTL_PCIX_DOWN_33MHZ, "cannot power down a 33 MHz card on an active bus" },
#define SYSCTL_PCIX_RESET_33MHZ (SYSCTL_PCIX_ERROR_BASE - 12)
{ SYSCTL_PCIX_RESET_33MHZ, "cannot reset a 33 MHz card on an active bus" },
#define SYSCTL_PCIX_SLOT_NOT_UP (SYSCTL_PCIX_ERROR_BASE - 13)
{ SYSCTL_PCIX_SLOT_NOT_UP, "cannot reset a slot that is not powered up" },
#define SYSCTL_PCIX_INVALID_BUS_SETTING (SYSCTL_PCIX_ERROR_BASE - 14)
{ SYSCTL_PCIX_INVALID_BUS_SETTING, "invalid bus type/speed selection (PCIX<66MHz, PCI>66MHz)" },
#define SYSCTL_PCIX_INVALID_DEPENDENT_SLOT (SYSCTL_PCIX_ERROR_BASE - 15)
{ SYSCTL_PCIX_INVALID_DEPENDENT_SLOT, "invalid dependent slot in PCI slot configuration" },
#define SYSCTL_PCIX_SHARED_IDSELECT (SYSCTL_PCIX_ERROR_BASE - 16)
{ SYSCTL_PCIX_SHARED_IDSELECT, "cannot enable two slots sharing the same IDSELECT" },
#define SYSCTL_PCIX_SLOT_DISABLED (SYSCTL_PCIX_ERROR_BASE - 17)
{ SYSCTL_PCIX_SLOT_DISABLED, "slot is disabled" },
}; /* end sysctl_pci_errors[] */
/*
* look up an error message for PCI operations that fail
*/
static void
sysctl_pci_error_lookup(int error, char *err_msg)
{
int i;
struct sysctl_pci_error_s *e = sysctl_pci_errors;
for (i = 0;
i < (sizeof(sysctl_pci_errors) / sizeof(*e));
i++, e++ )
{
if (e->error == error)
{
strcpy(err_msg, e->msg);
return;
}
}
sprintf(err_msg, "unrecognized PCI error type");
}
/*
* pcibr_slot_attach
* This is a place holder routine to keep track of all the
* slot-specific initialization that needs to be done.
* This is usually called when we want to initialize a new
* PCI card on the bus.
*/
int
pcibr_slot_attach(vertex_hdl_t pcibr_vhdl,
pciio_slot_t slot,
int drv_flags,
char *l1_msg,
int *sub_errorp)
{
pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl);
int error;
if (!(pcibr_soft->bs_slot[slot].slot_status & PCI_SLOT_POWER_ON)) {
uint64_t speed;
uint64_t mode;
/* Power-up the slot */
error = pcibr_slot_pwr(pcibr_vhdl, slot, PCI_REQ_SLOT_POWER_ON, l1_msg);
if (error) {
if (sub_errorp)
*sub_errorp = error;
return(PCI_L1_ERR);
} else {
pcibr_soft->bs_slot[slot].slot_status &= ~PCI_SLOT_POWER_MASK;
pcibr_soft->bs_slot[slot].slot_status |= PCI_SLOT_POWER_ON;
}
/* The speed/mode of the bus may have changed due to the hotplug */
speed = pcireg_speed_get(pcibr_soft);
mode = pcireg_mode_get(pcibr_soft);
pcibr_soft->bs_bridge_mode = ((speed << 1) | mode);
/*
* Allow cards like the Alteon Gigabit Ethernet Adapter to complete
* on-card initialization following the slot reset
*/
set_current_state (TASK_INTERRUPTIBLE);
schedule_timeout (HZ);
/* Find out what is out there */
error = pcibr_slot_info_init(pcibr_vhdl, slot);
if (error) {
if (sub_errorp)
*sub_errorp = error;
return(PCI_SLOT_INFO_INIT_ERR);
}
/* Set up the address space for this slot in the PCI land */
error = pcibr_slot_addr_space_init(pcibr_vhdl, slot);
if (error) {
if (sub_errorp)
*sub_errorp = error;
return(PCI_SLOT_ADDR_INIT_ERR);
}
/* Allocate the PCI-X Read Buffer Attribute Registers (RBARs)*/
if (IS_PCIX(pcibr_soft)) {
int tmp_slot;
/* Recalculate the RBARs for all the devices on the bus. Only
* return an error if we error for the given 'slot'
*/
pcibr_soft->bs_pcix_rbar_inuse = 0;
pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR;
pcibr_soft->bs_pcix_rbar_percent_allowed =
pcibr_pcix_rbars_calc(pcibr_soft);
for (tmp_slot = pcibr_soft->bs_min_slot;
tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); ++tmp_slot) {
if (tmp_slot == slot)
continue; /* skip this 'slot', we do it below */
(void)pcibr_slot_pcix_rbar_init(pcibr_soft, tmp_slot);
}
error = pcibr_slot_pcix_rbar_init(pcibr_soft, slot);
if (error) {
if (sub_errorp)
*sub_errorp = error;
return(PCI_SLOT_RBAR_ALLOC_ERR);
}
}
/* Setup the device register */
error = pcibr_slot_device_init(pcibr_vhdl, slot);
if (error) {
if (sub_errorp)
*sub_errorp = error;
return(PCI_SLOT_DEV_INIT_ERR);
}
/* Setup host/guest relations */
error = pcibr_slot_guest_info_init(pcibr_vhdl, slot);
if (error) {
if (sub_errorp)
*sub_errorp = error;
return(PCI_SLOT_GUEST_INIT_ERR);
}
/* Initial RRB management */
error = pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot);
if (error) {
if (sub_errorp)
*sub_errorp = error;
return(PCI_SLOT_RRB_ALLOC_ERR);
}
}
/* Call the device attach */
error = pcibr_slot_call_device_attach(pcibr_vhdl, slot, drv_flags);
if (error) {
if (sub_errorp)
*sub_errorp = error;
if (error == EUNATCH)
return(PCI_NO_DRIVER);
else
return(PCI_SLOT_DRV_ATTACH_ERR);
}
return(0);
}
/*
* pcibr_slot_enable
* Enable the PCI slot for a hot-plug insert.
*/
int
pcibr_slot_enable(vertex_hdl_t pcibr_vhdl, struct pcibr_slot_enable_req_s *req_p)
{
pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl);
pciio_slot_t slot = req_p->req_device;
int error = 0;
/* Make sure that we are dealing with a bridge device vertex */
if (!pcibr_soft) {
return(PCI_NOT_A_BRIDGE);
}
PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HOTPLUG, pcibr_vhdl,
"pcibr_slot_enable: pcibr_soft=0x%lx, slot=%d, req_p=0x%lx\n",
pcibr_soft, slot, req_p));
/* Check for the valid slot */
if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
return(PCI_NOT_A_SLOT);
if (pcibr_soft->bs_slot[slot].slot_status & PCI_SLOT_ENABLE_CMPLT) {
error = PCI_SLOT_ALREADY_UP;
goto enable_unlock;
}
error = pcibr_slot_attach(pcibr_vhdl, slot, NULL,
req_p->req_resp.resp_l1_msg,
&req_p->req_resp.resp_sub_errno);
req_p->req_resp.resp_l1_msg[PCI_L1_QSIZE] = '\0';
enable_unlock:
return(error);
}
/*
* pcibr_slot_disable
* Disable the PCI slot for a hot-plug removal.
*/
int
pcibr_slot_disable(vertex_hdl_t pcibr_vhdl, struct pcibr_slot_disable_req_s *req_p)
{
pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl);
pciio_slot_t slot = req_p->req_device;
int error = 0;
pciio_slot_t tmp_slot;
/* Make sure that we are dealing with a bridge device vertex */
if (!pcibr_soft) {
return(PCI_NOT_A_BRIDGE);
}
PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HOTPLUG, pcibr_vhdl,
"pcibr_slot_disable: pcibr_soft=0x%lx, slot=%d, req_p=0x%lx\n",
pcibr_soft, slot, req_p));
/* Check for valid slot */
if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
return(PCI_NOT_A_SLOT);
if ((pcibr_soft->bs_slot[slot].slot_status & PCI_SLOT_DISABLE_CMPLT) ||
((pcibr_soft->bs_slot[slot].slot_status & PCI_SLOT_STATUS_MASK) == 0)) {
error = PCI_SLOT_ALREADY_DOWN;
/*
* RJR - Should we invoke an L1 slot power-down command just in case
* a previous shut-down failed to power-down the slot?
*/
goto disable_unlock;
}
/* Do not allow the last 33 MHz card to be removed */
if (IS_33MHZ(pcibr_soft)) {
for (tmp_slot = pcibr_soft->bs_first_slot;
tmp_slot <= pcibr_soft->bs_last_slot; tmp_slot++)
if (tmp_slot != slot)
if (pcibr_soft->bs_slot[tmp_slot].slot_status & PCI_SLOT_POWER_ON) {
error++;
break;
}
if (!error) {
error = PCI_EMPTY_33MHZ;
goto disable_unlock;
}
}
if (req_p->req_action == PCI_REQ_SLOT_ELIGIBLE)
return(0);
error = pcibr_slot_detach(pcibr_vhdl, slot, 1,
req_p->req_resp.resp_l1_msg,
&req_p->req_resp.resp_sub_errno);
req_p->req_resp.resp_l1_msg[PCI_L1_QSIZE] = '\0';
disable_unlock:
return(error);
}
/*
* pcibr_slot_pwr
* Power-up or power-down a PCI slot. This routines makes calls to
* the L1 system controller driver which requires "external" slot#.
*/
int
pcibr_slot_pwr(vertex_hdl_t pcibr_vhdl,
pciio_slot_t slot,
int up,
char *err_msg)
{
pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl);
nasid_t nasid;
u64 connection_type;
int rv;
nasid = NASID_GET(pcibr_soft->bs_base);
connection_type = SAL_SYSCTL_IO_XTALK;
rv = (int) ia64_sn_sysctl_iobrick_pci_op
(nasid,
connection_type,
(u64) pcibr_widget_to_bus(pcibr_vhdl),
PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),
(up ? SAL_SYSCTL_PCI_POWER_UP : SAL_SYSCTL_PCI_POWER_DOWN));
if (!rv) {
/* everything's okay; no error message */
*err_msg = '\0';
}
else {
/* there was a problem; look up an appropriate error message */
sysctl_pci_error_lookup(rv, err_msg);
}
return rv;
}
#endif /* CONFIG_HOTPLUG_PCI_SGI */
/*
* pcibr_slot_info_init
......@@ -114,7 +520,9 @@ pcibr_slot_info_init(vertex_hdl_t pcibr_vhdl,
return -ENODEV;
slotp = &pcibr_soft->bs_slot[slot];
#ifdef CONFIG_HOTPLUG_PCI_SGI
slotp->slot_status |= SLOT_POWER_UP;
#endif
vendor = 0xFFFF & idword;
device = 0xFFFF & (idword >> 16);
......@@ -1019,6 +1427,7 @@ pcibr_slot_call_device_attach(vertex_hdl_t pcibr_vhdl,
} /* next func */
#ifdef CONFIG_HOTPLUG_PCI_SGI
if (error) {
if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) {
pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
......@@ -1028,7 +1437,7 @@ pcibr_slot_call_device_attach(vertex_hdl_t pcibr_vhdl,
pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT;
}
#endif /* CONFIG_HOTPLUG_PCI_SGI */
return error;
}
......@@ -1103,7 +1512,7 @@ pcibr_slot_call_device_detach(vertex_hdl_t pcibr_vhdl,
} /* next func */
#ifdef CONFIG_HOTPLUG_PCI_SGI
if (error) {
if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) {
pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
......@@ -1115,10 +1524,12 @@ pcibr_slot_call_device_detach(vertex_hdl_t pcibr_vhdl,
pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT;
}
#endif /* CONFIG_HOTPLUG_PCI_SGI */
return error;
}
/*
* pcibr_slot_detach
* This is a place holder routine to keep track of all the
......
......@@ -211,6 +211,49 @@ register_pcibr_intr(int irq, pcibr_intr_t intr)
}
}
void
unregister_pcibr_intr(int irq, pcibr_intr_t intr)
{
struct sn_intr_list_t **prev, *curr;
int cpu = intr->bi_cpu;
int i;
if (sn_intr_list[irq] == NULL)
return;
prev = &sn_intr_list[irq];
curr = sn_intr_list[irq];
while (curr) {
if (curr->intr == intr) {
*prev = curr->next;
break;
}
prev = &curr->next;
curr = curr->next;
}
if (curr)
kfree(curr);
if (!sn_intr_list[irq]) {
if (pdacpu(cpu)->sn_last_irq == irq) {
for (i = pdacpu(cpu)->sn_last_irq - 1; i; i--)
if (sn_intr_list[i])
break;
pdacpu(cpu)->sn_last_irq = i;
}
if (pdacpu(cpu)->sn_first_irq == irq) {
pdacpu(cpu)->sn_first_irq = 0;
for (i = pdacpu(cpu)->sn_first_irq + 1; i < NR_IRQS; i++)
if (sn_intr_list[i])
pdacpu(cpu)->sn_first_irq = i;
}
}
}
void
force_polled_int(void)
{
......
......@@ -122,5 +122,13 @@ config HOTPLUG_PCI_CPCI_GENERIC
When in doubt, say N.
config HOTPLUG_PCI_SGI
tristate "SGI PCI Hotplug Support"
depends on HOTPLUG_PCI && IA64_SGI_SN2
help
Say Y here if you have an SGI IA64 Altix system.
When in doubt, say N.
endmenu
......@@ -325,9 +325,27 @@ extern int pcibr_asic_rev(vertex_hdl_t);
#define PCIBR 'p'
#define _PCIBR(x) ((PCIBR << 8) | (x))
#define PCIBR_SLOT_STARTUP _PCIBR(1)
#define PCIBR_SLOT_SHUTDOWN _PCIBR(2)
#define PCIBR_SLOT_QUERY _PCIBR(3)
/*
* Bit defintions for variable slot_status in struct
* pcibr_soft_slot_s. They are here so that the user
* hot-plug utility can interpret the slot's power
* status.
*/
#ifdef CONFIG_HOTPLUG_PCI_SGI
#define PCI_SLOT_ENABLE_CMPLT 0x01
#define PCI_SLOT_ENABLE_INCMPLT 0x02
#define PCI_SLOT_DISABLE_CMPLT 0x04
#define PCI_SLOT_DISABLE_INCMPLT 0x08
#define PCI_SLOT_POWER_ON 0x10
#define PCI_SLOT_POWER_OFF 0x20
#define PCI_SLOT_IS_SYS_CRITICAL 0x40
#define PCI_SLOT_PCIBA_LOADED 0x80
#define PCI_SLOT_STATUS_MASK (PCI_SLOT_ENABLE_CMPLT | \
PCI_SLOT_ENABLE_INCMPLT | \
PCI_SLOT_DISABLE_CMPLT | \
PCI_SLOT_DISABLE_INCMPLT)
#define PCI_SLOT_POWER_MASK (PCI_SLOT_POWER_ON | PCI_SLOT_POWER_OFF)
/*
* Bit defintions for variable slot_status in struct
......@@ -356,26 +374,20 @@ extern int pcibr_asic_rev(vertex_hdl_t);
#define FUNC_IS_SYS_CRITICAL 0x02
/*
* Structures for requesting PCI bridge information and receiving a response
* L1 slot power operations for PCI hot-plug
*/
typedef struct pcibr_slot_req_s *pcibr_slot_req_t;
typedef struct pcibr_slot_up_resp_s *pcibr_slot_up_resp_t;
typedef struct pcibr_slot_down_resp_s *pcibr_slot_down_resp_t;
typedef struct pcibr_slot_info_resp_s *pcibr_slot_info_resp_t;
typedef struct pcibr_slot_func_info_resp_s *pcibr_slot_func_info_resp_t;
#define PCI_REQ_SLOT_POWER_ON 1
#define PCI_L1_QSIZE 128 /* our L1 message buffer size */
#define L1_QSIZE 128 /* our L1 message buffer size */
struct pcibr_slot_req_s {
int req_slot;
union {
pcibr_slot_up_resp_t up;
pcibr_slot_down_resp_t down;
pcibr_slot_info_resp_t query;
void *any;
} req_respp;
int req_size;
enum pcibr_slot_disable_action_e {
PCI_REQ_SLOT_ELIGIBLE,
PCI_REQ_SLOT_DISABLE
};
struct pcibr_slot_up_resp_s {
int resp_sub_errno;
char resp_l1_msg[L1_QSIZE + 1];
......@@ -444,6 +456,45 @@ struct pcibr_slot_info_resp_s {
} resp_func[8];
};
struct pcibr_slot_req_s {
int req_slot;
union {
enum pcibr_slot_disable_action_e up;
struct pcibr_slot_down_resp_s *down;
struct pcibr_slot_info_resp_s *query;
void *any;
} req_respp;
int req_size;
};
struct pcibr_slot_enable_resp_s {
int resp_sub_errno;
char resp_l1_msg[PCI_L1_QSIZE + 1];
};
struct pcibr_slot_disable_resp_s {
int resp_sub_errno;
char resp_l1_msg[PCI_L1_QSIZE + 1];
};
struct pcibr_slot_enable_req_s {
pciio_slot_t req_device;
struct pcibr_slot_enable_resp_s req_resp;
};
struct pcibr_slot_disable_req_s {
pciio_slot_t req_device;
enum pcibr_slot_disable_action_e req_action;
struct pcibr_slot_disable_resp_s req_resp;
};
struct pcibr_slot_info_req_s {
pciio_slot_t req_device;
struct pcibr_slot_info_resp_s req_resp;
};
#endif /* CONFIG_HOTPLUG_PCI_SGI */
/*
* PCI specific errors, interpreted by pciconfig command
......
......@@ -475,6 +475,12 @@ struct pcibr_soft_s {
vertex_hdl_t bs_noslot_conn; /* NO-SLOT connection point */
pcibr_info_t bs_noslot_info;
#ifdef CONFIG_HOTPLUG_PCI_SGI
/* Linux PCI bus structure pointer */
struct pci_bus *bs_pci_bus;
#endif
struct pcibr_soft_slot_s {
/* information we keep about each CFG slot */
......@@ -492,9 +498,14 @@ struct pcibr_soft_s {
pciio_slot_t host_slot;
vertex_hdl_t slot_conn;
#ifdef CONFIG_HOTPLUG_PCI_SGI
/* PCI Hot-Plug status word */
int slot_status;
/* PCI Hot-Plug core structure pointer */
struct hotplug_slot *bss_hotplug_slot;
#endif /* CONFIG_HOTPLUG_PCI_SGI */
/* Potentially several connection points
* for this slot. bss_ninfo is how many,
* and bss_infos is a pointer to
......
......@@ -58,6 +58,7 @@
#define SN_SAL_MEMPROTECT 0x0200003e
#define SN_SAL_SYSCTL_FRU_CAPTURE 0x0200003f
#define SN_SAL_SYSCTL_IOBRICK_PCI_OP 0x02000042 // reentrant
/*
* Service-specific constants
......@@ -72,6 +73,16 @@
#define SAL_CONSOLE_INTR_XMIT 1 /* output interrupt */
#define SAL_CONSOLE_INTR_RECV 2 /* input interrupt */
#ifdef CONFIG_HOTPLUG_PCI_SGI
/* power up / power down / reset a PCI slot or bus */
#define SAL_SYSCTL_PCI_POWER_UP 0
#define SAL_SYSCTL_PCI_POWER_DOWN 1
#define SAL_SYSCTL_PCI_RESET 2
/* what type of I/O brick? */
#define SAL_SYSCTL_IO_XTALK 0 /* connected via a compute node */
#endif /* CONFIG_HOTPLUG_PCI_SGI */
/*
* SN_SAL_GET_PARTITION_ADDR return constants
......@@ -641,4 +652,22 @@ ia64_sn_fru_capture(void)
return isrv.v0;
}
/*
* Performs an operation on a PCI bus or slot -- power up, power down
* or reset.
*/
static inline u64
ia64_sn_sysctl_iobrick_pci_op(nasid_t n, u64 connection_type,
u64 bus, slotid_t slot,
u64 action)
{
struct ia64_sal_retval rv = {0, 0, 0, 0};
SAL_CALL_NOLOCK(rv, SN_SAL_SYSCTL_IOBRICK_PCI_OP, connection_type, n, action,
bus, (u64) slot, 0, 0);
if (rv.status)
return rv.v0;
return 0;
}
#endif /* _ASM_IA64_SN_SN_SAL_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