Commit 56f1be79 authored by Linus Torvalds's avatar Linus Torvalds

Merge

parents 166c69fe 83f56aef
......@@ -104,9 +104,12 @@ include/asm-ia64/.offsets.h.stamp:
boot: lib/lib.a vmlinux
$(Q)$(MAKE) $(build)=$(boot) $@
install: vmlinux.gz
sh $(srctree)/arch/ia64/install.sh $(KERNELRELEASE) $< System.map "$(INSTALL_PATH)"
define archhelp
echo '* compressed - Build compressed kernel image'
echo ' install - Install compressed kernel image'
echo ' boot - Build vmlinux and bootloader for Ski simulator'
echo '* unwcheck - Check vmlinux for invalid unwind info'
endef
......@@ -68,6 +68,7 @@ CONFIG_IA64_L1_CACHE_SHIFT=7
# CONFIG_NUMA is not set
CONFIG_VIRTUAL_MEM_MAP=y
CONFIG_IA64_MCA=y
# CONFIG_IA64_CYCLONE is not set
CONFIG_PM=y
CONFIG_IOSAPIC=y
CONFIG_FORCE_MAX_ZONEORDER=18
......@@ -587,7 +588,6 @@ CONFIG_EFI_RTC=y
#
# CONFIG_FTAPE is not set
CONFIG_AGP=m
CONFIG_AGP_I460=m
CONFIG_AGP_HP_ZX1=m
CONFIG_DRM=y
# CONFIG_DRM_TDFX is not set
......@@ -778,7 +778,9 @@ CONFIG_FB=y
# CONFIG_FB_IMSTT is not set
CONFIG_FB_RIVA=m
# CONFIG_FB_MATROX is not set
# CONFIG_FB_RADEON_OLD is not set
CONFIG_FB_RADEON=y
# CONFIG_FB_RADEON_DEBUG is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
# CONFIG_FB_SIS is not set
......
#!/bin/sh
#
# arch/ia64/install.sh
#
# 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.
#
# Copyright (C) 1995 by Linus Torvalds
#
# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
#
# "make install" script for ia64 architecture
#
# Arguments:
# $1 - kernel version
# $2 - kernel image file
# $3 - kernel map file
# $4 - default install path (blank if root directory)
#
# User may have a custom install script
if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi
if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi
# Default install - same as make zlilo
if [ -f $4/vmlinuz ]; then
mv $4/vmlinuz $4/vmlinuz.old
fi
if [ -f $4/System.map ]; then
mv $4/System.map $4/System.old
fi
cat $2 > $4/vmlinuz
cp $3 $4/System.map
test -x /usr/sbin/elilo && /usr/sbin/elilo
......@@ -23,15 +23,15 @@ obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
# The gate DSO image is built using a special linker script.
targets += gate.so gate-syms.o
extra-y += gate.so gate-syms.o gate.lds.s gate.o
AFLAGS_gate.lds.o += -P -C -U$(ARCH)
arch/ia64/kernel/gate.lds.s: %.s: %.S scripts FORCE
$(call if_changed_dep,as_s_S)
quiet_cmd_gate = GATE $@
cmd_gate = $(CC) -nostdlib $(GATECFLAGS_$(@F)) -Wl,-T,$(filter-out FORCE,$^) -o $@
GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1
$(obj)/gate.so: $(src)/gate.lds.s $(obj)/gate.o FORCE
$(obj)/gate.so: $(obj)/gate.lds.s $(obj)/gate.o FORCE
$(call if_changed,gate)
$(obj)/built-in.o: $(obj)/gate-syms.o
......
......@@ -75,12 +75,25 @@ ia64_get_scratch_nat_bits (struct pt_regs *pt, unsigned long scratch_unat)
({ \
unsigned long bit = ia64_unat_pos(&pt->r##first); \
unsigned long mask = ((1UL << (last - first + 1)) - 1) << first; \
(ia64_rotl(unat, first) >> bit) & mask; \
unsigned long dist; \
if (bit < first) \
dist = 64 + bit - first; \
else \
dist = bit - first; \
ia64_rotr(unat, dist) & mask; \
})
unsigned long val;
val = GET_BITS( 1, 3, scratch_unat);
val |= GET_BITS(12, 15, scratch_unat);
/*
* Registers that are stored consecutively in struct pt_regs can be handled in
* parallel. If the register order in struct_pt_regs changes, this code MUST be
* updated.
*/
val = GET_BITS( 1, 1, scratch_unat);
val |= GET_BITS( 2, 3, scratch_unat);
val |= GET_BITS(12, 13, scratch_unat);
val |= GET_BITS(14, 14, scratch_unat);
val |= GET_BITS(15, 15, scratch_unat);
val |= GET_BITS( 8, 11, scratch_unat);
val |= GET_BITS(16, 31, scratch_unat);
return val;
......@@ -96,16 +109,29 @@ ia64_get_scratch_nat_bits (struct pt_regs *pt, unsigned long scratch_unat)
unsigned long
ia64_put_scratch_nat_bits (struct pt_regs *pt, unsigned long nat)
{
# define PUT_BITS(first, last, nat) \
({ \
unsigned long bit = ia64_unat_pos(&pt->r##first); \
unsigned long mask = ((1UL << (last - first + 1)) - 1) << first; \
long dist; \
if (bit < first) \
dist = 64 + bit - first; \
else \
dist = bit - first; \
ia64_rotl(nat & mask, dist); \
})
unsigned long scratch_unat;
# define PUT_BITS(first, last, nat) \
({ \
unsigned long bit = ia64_unat_pos(&pt->r##first); \
unsigned long mask = ((1UL << (last - first + 1)) - 1) << bit; \
(ia64_rotr(nat, first) << bit) & mask; \
})
scratch_unat = PUT_BITS( 1, 3, nat);
scratch_unat |= PUT_BITS(12, 15, nat);
/*
* Registers that are stored consecutively in struct pt_regs can be handled in
* parallel. If the register order in struct_pt_regs changes, this code MUST be
* updated.
*/
scratch_unat = PUT_BITS( 1, 1, nat);
scratch_unat |= PUT_BITS( 2, 3, nat);
scratch_unat |= PUT_BITS(12, 13, nat);
scratch_unat |= PUT_BITS(14, 14, nat);
scratch_unat |= PUT_BITS(15, 15, nat);
scratch_unat |= PUT_BITS( 8, 11, nat);
scratch_unat |= PUT_BITS(16, 31, nat);
......
......@@ -106,7 +106,7 @@ ia64_sal_init (struct ia64_sal_systab *systab)
/*
* revisions are coded in BCD, so %x does the job for us
*/
printk(KERN_INFO "SAL v%x.%02x: oem=%.32s, product=%.32s\n",
printk(KERN_INFO "SAL v%x.%x: oem=%.32s, product=%.32s\n",
systab->sal_rev_major, systab->sal_rev_minor,
systab->oem_id, systab->product_id);
......
......@@ -347,12 +347,6 @@ setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr)
__copy_to_user(&sc->sc_fr[32], current->thread.fph, 96*16);
}
/*
* Note: sw->ar_unat is UNDEFINED unless the process is being
* PTRACED. However, this is OK because the NaT bits of the
* preserved registers (r4-r7) are never being looked at by
* the signal handler (registers r4-r7 are used instead).
*/
nat = ia64_get_scratch_nat_bits(&scr->pt, scr->scratch_unat);
err = __put_user(flags, &sc->sc_flags);
......
......@@ -40,6 +40,125 @@ struct early_node_data {
static struct early_node_data mem_data[NR_NODES] __initdata;
/**
* reassign_cpu_only_nodes - called from find_memory to move CPU-only nodes to a memory node
*
* This function will move nodes with only CPUs (no memory)
* to a node with memory which is at the minimum numa_slit distance.
* Any reassigments will result in the compression of the nodes
* and renumbering the nid values where appropriate.
* The static declarations below are to avoid large stack size which
* makes the code not re-entrant.
*/
static void __init reassign_cpu_only_nodes(void)
{
struct node_memblk_s *p;
int i, j, k, nnode, nid, cpu, cpunid;
u8 cslit, slit;
static DECLARE_BITMAP(nodes_with_mem, NR_NODES) __initdata;
static u8 numa_slit_fix[MAX_NUMNODES * MAX_NUMNODES] __initdata;
static int node_flip[NR_NODES] __initdata;
for (nnode = 0, p = &node_memblk[0]; p < &node_memblk[num_node_memblks]; p++)
if (!test_bit(p->nid, (void *) nodes_with_mem)) {
set_bit(p->nid, (void *) nodes_with_mem);
nnode++;
}
/*
* All nids with memory.
*/
if (nnode == numnodes)
return;
/*
* Change nids and attempt to migrate CPU-only nodes
* to the best numa_slit (closest neighbor) possible.
* For reassigned CPU nodes a nid can't be arrived at
* until after this loop because the target nid's new
* identity might not have been established yet. So
* new nid values are fabricated above numnodes and
* mapped back later to their true value.
*/
for (nid = 0, i = 0; i < numnodes; i++) {
if (test_bit(i, (void *) nodes_with_mem)) {
/*
* Save original nid value for numa_slit
* fixup and node_cpuid reassignments.
*/
node_flip[nid] = i;
if (i == nid) {
nid++;
continue;
}
for (p = &node_memblk[0]; p < &node_memblk[num_node_memblks]; p++)
if (p->nid == i)
p->nid = nid;
cpunid = nid;
nid++;
} else
cpunid = numnodes;
for (cpu = 0; cpu < NR_CPUS; cpu++)
if (node_cpuid[cpu].nid == i) {
/* For nodes not being reassigned just fix the cpu's nid. */
if (cpunid < numnodes) {
node_cpuid[cpu].nid = cpunid;
continue;
}
/*
* For nodes being reassigned, find best node by
* numa_slit information and then make a temporary
* nid value based on current nid and numnodes.
*/
for (slit = 0xff, k = numnodes + numnodes, j = 0; j < numnodes; j++)
if (i == j)
continue;
else if (test_bit(j, (void *) nodes_with_mem)) {
cslit = numa_slit[i * numnodes + j];
if (cslit < slit) {
k = numnodes + j;
slit = cslit;
}
}
node_cpuid[cpu].nid = k;
}
}
/*
* Fixup temporary nid values for CPU-only nodes.
*/
for (cpu = 0; cpu < NR_CPUS; cpu++)
if (node_cpuid[cpu].nid == (numnodes + numnodes))
node_cpuid[cpu].nid = nnode - 1;
else
for (i = 0; i < nnode; i++)
if (node_flip[i] == (node_cpuid[cpu].nid - numnodes)) {
node_cpuid[cpu].nid = i;
break;
}
/*
* Fix numa_slit by compressing from larger
* nid array to reduced nid array.
*/
for (i = 0; i < nnode; i++)
for (j = 0; j < nnode; j++)
numa_slit_fix[i * nnode + j] =
numa_slit[node_flip[i] * numnodes + node_flip[j]];
memcpy(numa_slit, numa_slit_fix, sizeof (numa_slit));
numnodes = nnode;
return;
}
/*
* To prevent cache aliasing effects, align per-node structures so that they
* start at addresses that are strided by node number.
......@@ -301,6 +420,9 @@ void __init find_memory(void)
min_low_pfn = -1;
max_low_pfn = 0;
if (numnodes > 1)
reassign_cpu_only_nodes();
/* These actually end up getting called by call_pernode_memory() */
efi_memmap_walk(filter_rsvd_memory, build_node_maps);
efi_memmap_walk(filter_rsvd_memory, find_pernode_space);
......
......@@ -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)
{
......
......@@ -212,5 +212,13 @@ config HOTPLUG_PCI_RPA_DLPAR
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
......@@ -655,24 +655,13 @@ ia64_get_dbr (__u64 regnum)
return retval;
}
/* XXX remove the handcoded version once we have a sufficiently clever compiler... */
#ifdef SMART_COMPILER
# define ia64_rotr(w,n) \
({ \
__u64 __ia64_rotr_w = (w), _n = (n); \
\
(__ia64_rotr_w >> _n) | (__ia64_rotr_w << (64 - _n)); \
})
#else
# define ia64_rotr(w,n) \
({ \
__u64 __ia64_rotr_w; \
__ia64_rotr_w = ia64_shrp((w), (w), (n)); \
__ia64_rotr_w; \
})
#endif
static inline __u64
ia64_rotr (__u64 w, __u64 n)
{
return (w >> n) | (w << (64 - n));
}
#define ia64_rotl(w,n) ia64_rotr((w),(64)-(n))
#define ia64_rotl(w,n) ia64_rotr((w), (64) - (n))
/*
* Take a mapped kernel address and return the equivalent address
......
......@@ -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