Commit e0292b9d authored by David Mosberger's avatar David Mosberger

ia64: Sync with 2.5.64.

parents 236b5445 9b3ed4c1
......@@ -4,7 +4,7 @@
-----------------------------------
Started: 13-Jan-2003
Last update: 24-Jan-2003
Last update: 11-Feb-2003
David Mosberger-Tang
<davidm@hpl.hp.com>
......@@ -42,9 +42,9 @@ In contrast, fsys-mode has the following special properties:
can disable interrupts and avoid all other interruption-sources
to avoid preemption)
- neither the memory nor the register stack can be trusted while
- neither the memory-stack nor the register-stack can be trusted while
in fsys-mode (they point to the user-level stacks, which may
be invalid)
be invalid, or completely bogus addresses)
In summary, fsys-mode is much more similar to running in user-mode
than it is to running in kernel-mode. Of course, given that the
......
......@@ -26,7 +26,7 @@ config SWAP
bool
default y
config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
bool
default y
......@@ -424,6 +424,18 @@ config SMP
If you don't know what to do here, say N.
config PREEMPT
bool "Preemptible Kernel"
help
This option reduces the latency of the kernel when reacting to
real-time or interactive events by allowing a low priority process to
be preempted even if it is in kernel mode executing a system call.
This allows applications to run more reliably even when the system is
under load.
Say Y here if you are building a kernel for a desktop, embedded
or real-time system. Say N if you are unsure.
config IA32_SUPPORT
bool "Support running of Linux/x86 binaries"
help
......@@ -875,6 +887,12 @@ config DEBUG_SPINLOCK
best used in conjunction with the NMI watchdog so that spinlock
deadlocks are also debuggable.
config DEBUG_SPINLOCK_SLEEP
bool "Sleep-inside-spinlock checking"
help
If you say Y here, various routines which may sleep will become very
noisy if they are called with a spinlock held.
config IA64_DEBUG_CMPXCHG
bool "Turn on compare-and-exchange bug checking (slow!)"
depends on DEBUG_KERNEL
......
......@@ -52,18 +52,19 @@ core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/ arch/ia64/hp/common/ arch/ia64/hp
core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/
core-$(CONFIG_IA64_SGI_SN) += arch/ia64/sn/kernel/ \
arch/ia64/sn/io/ \
arch/ia64/sn/io/sn2/ \
arch/ia64/sn/io/sn2/pcibr/ \
arch/ia64/sn/kernel/sn2/
drivers-$(CONFIG_PCI) += arch/ia64/pci/
drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/
drivers-$(CONFIG_IA64_HP_ZX1) += arch/ia64/hp/common/ arch/ia64/hp/zx1/
drivers-$(CONFIG_IA64_SGI_SN) += arch/ia64/sn/fakeprom/
boot := arch/ia64/boot
tools := arch/ia64/tools
.PHONY: boot compressed include/asm-ia64/offsets.h
all: vmlinux
all: prepare vmlinux
compressed: vmlinux.gz
......
......@@ -156,7 +156,7 @@ simscsi_readwrite (Scsi_Cmnd *sc, int mode, unsigned long offset, unsigned long
if (sc->request_bufflen < req.len)
return;
stat.fd = desc[sc->target];
stat.fd = desc[sc->device->id];
if (DBG)
printk("simscsi_%s @ %lx (off %lx)\n",
mode == SSC_READ ? "read":"write", req.addr, offset);
......@@ -178,7 +178,7 @@ simscsi_sg_readwrite (Scsi_Cmnd *sc, int mode, unsigned long offset)
struct disk_stat stat;
struct disk_req req;
stat.fd = desc[sc->target];
stat.fd = desc[sc->device->id];
while (list_len) {
req.addr = __pa(page_address(sl->page) + sl->offset);
......@@ -259,6 +259,7 @@ simscsi_readwrite10 (Scsi_Cmnd *sc, int mode)
int
simscsi_queuecommand (Scsi_Cmnd *sc, void (*done)(Scsi_Cmnd *))
{
unsigned int target_id = sc->device->id;
char fname[MAX_ROOT_LEN+16];
size_t disk_size;
char *buf;
......@@ -267,21 +268,21 @@ simscsi_queuecommand (Scsi_Cmnd *sc, void (*done)(Scsi_Cmnd *))
if (DBG)
printk("simscsi_queuecommand: target=%d,cmnd=%u,sc=%lu,sp=%lx,done=%p\n",
sc->target, sc->cmnd[0], sc->serial_number, sp, done);
target_id, sc->cmnd[0], sc->serial_number, sp, done);
#endif
sc->result = DID_BAD_TARGET << 16;
sc->scsi_done = done;
if (sc->target <= 15 && sc->lun == 0) {
if (target_id <= 15 && sc->device->lun == 0) {
switch (sc->cmnd[0]) {
case INQUIRY:
if (sc->request_bufflen < 35) {
break;
}
sprintf (fname, "%s%c", simscsi_root, 'a' + sc->target);
desc[sc->target] = ia64_ssc(__pa(fname), SSC_READ_ACCESS|SSC_WRITE_ACCESS,
sprintf (fname, "%s%c", simscsi_root, 'a' + target_id);
desc[target_id] = ia64_ssc(__pa(fname), SSC_READ_ACCESS|SSC_WRITE_ACCESS,
0, 0, SSC_OPEN);
if (desc[sc->target] < 0) {
if (desc[target_id] < 0) {
/* disk doesn't exist... */
break;
}
......@@ -303,37 +304,37 @@ simscsi_queuecommand (Scsi_Cmnd *sc, void (*done)(Scsi_Cmnd *))
break;
case READ_6:
if (desc[sc->target] < 0 )
if (desc[target_id] < 0 )
break;
simscsi_readwrite6(sc, SSC_READ);
break;
case READ_10:
if (desc[sc->target] < 0 )
if (desc[target_id] < 0 )
break;
simscsi_readwrite10(sc, SSC_READ);
break;
case WRITE_6:
if (desc[sc->target] < 0)
if (desc[target_id] < 0)
break;
simscsi_readwrite6(sc, SSC_WRITE);
break;
case WRITE_10:
if (desc[sc->target] < 0)
if (desc[target_id] < 0)
break;
simscsi_readwrite10(sc, SSC_WRITE);
break;
case READ_CAPACITY:
if (desc[sc->target] < 0 || sc->request_bufflen < 8) {
if (desc[target_id] < 0 || sc->request_bufflen < 8) {
break;
}
buf = sc->request_buffer;
disk_size = simscsi_get_disk_size(desc[sc->target]);
disk_size = simscsi_get_disk_size(desc[target_id]);
/* pretend to be a 1GB disk (partition table contains real stuff): */
buf[0] = (disk_size >> 24) & 0xff;
......
......@@ -63,7 +63,6 @@ extern void ia64_ssc_connect_irq (long intr, long irq);
static char *serial_name = "SimSerial driver";
static char *serial_version = "0.6";
static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;
/*
* This has been extracted from asm/serial.h. We need one eventually but
......@@ -235,14 +234,14 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch)
if (!tty || !info->xmit.buf) return;
spin_lock_irqsave(&serial_lock, flags);
local_irq_save(flags);
if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) {
spin_unlock_irqrestore(&serial_lock, flags);
local_irq_restore(flags);
return;
}
info->xmit.buf[info->xmit.head] = ch;
info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
spin_unlock_irqrestore(&serial_lock, flags);
local_irq_restore(flags);
}
static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
......@@ -250,7 +249,8 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
int count;
unsigned long flags;
spin_lock_irqsave(&serial_lock, flags);
local_irq_save(flags);
if (info->x_char) {
char c = info->x_char;
......@@ -293,7 +293,7 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
info->xmit.tail += count;
}
out:
spin_unlock_irqrestore(&serial_lock, flags);
local_irq_restore(flags);
}
static void rs_flush_chars(struct tty_struct *tty)
......@@ -334,7 +334,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
break;
}
spin_lock_irqsave(&serial_lock, flags);
local_irq_save(flags);
{
c1 = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail,
SERIAL_XMIT_SIZE);
......@@ -344,7 +344,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
info->xmit.head = ((info->xmit.head + c) &
(SERIAL_XMIT_SIZE-1));
}
spin_unlock_irqrestore(&serial_lock, flags);
local_irq_restore(flags);
buf += c;
count -= c;
......@@ -352,7 +352,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
}
up(&tmp_buf_sem);
} else {
spin_lock_irqsave(&serial_lock, flags);
local_irq_save(flags);
while (1) {
c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
if (count < c)
......@@ -367,7 +367,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
count -= c;
ret += c;
}
spin_unlock_irqrestore(&serial_lock, flags);
local_irq_restore(flags);
}
/*
* Hey, we transmit directly from here in our case
......@@ -398,9 +398,9 @@ static void rs_flush_buffer(struct tty_struct *tty)
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&serial_lock, flags);
local_irq_save(flags);
info->xmit.head = info->xmit.tail = 0;
spin_unlock_irqrestore(&serial_lock, flags);
local_irq_restore(flags);
wake_up_interruptible(&tty->write_wait);
......@@ -573,7 +573,7 @@ static void shutdown(struct async_struct * info)
state->irq);
#endif
spin_lock_irqsave(&serial_lock, flags);
local_irq_save(flags);
{
/*
* First unlink the serial port from the IRQ chain...
......@@ -611,7 +611,7 @@ static void shutdown(struct async_struct * info)
info->flags &= ~ASYNC_INITIALIZED;
}
spin_unlock_irqrestore(&serial_lock, flags);
local_irq_restore(flags);
}
/*
......@@ -634,13 +634,13 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
state = info->state;
spin_lock_irqsave(&serial_lock, flags);
local_irq_save(flags);
if (tty_hung_up_p(filp)) {
#ifdef SIMSERIAL_DEBUG
printk("rs_close: hung_up\n");
#endif
MOD_DEC_USE_COUNT;
spin_unlock_irqrestore(&serial_lock, flags);
local_irq_restore(flags);
return;
}
#ifdef SIMSERIAL_DEBUG
......@@ -665,11 +665,11 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
}
if (state->count) {
MOD_DEC_USE_COUNT;
spin_unlock_irqrestore(&serial_lock, flags);
local_irq_restore(flags);
return;
}
info->flags |= ASYNC_CLOSING;
spin_unlock_irqrestore(&serial_lock, flags);
local_irq_restore(flags);
/*
* Now we wait for the transmit buffer to clear; and we notify
......@@ -776,7 +776,7 @@ startup(struct async_struct *info)
if (!page)
return -ENOMEM;
spin_lock_irqsave(&serial_lock, flags);
local_irq_save(flags);
if (info->flags & ASYNC_INITIALIZED) {
free_page(page);
......@@ -857,11 +857,11 @@ startup(struct async_struct *info)
}
info->flags |= ASYNC_INITIALIZED;
spin_unlock_irqrestore(&serial_lock, flags);
local_irq_restore(flags);
return 0;
errout:
spin_unlock_irqrestore(&serial_lock, flags);
local_irq_restore(flags);
return retval;
}
......
......@@ -93,7 +93,7 @@ ia32_load_state (struct task_struct *t)
{
unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd;
struct pt_regs *regs = ia64_task_regs(t);
int nr = smp_processor_id(); /* LDT and TSS depend on CPU number: */
int nr = get_cpu(); /* LDT and TSS depend on CPU number: */
eflag = t->thread.eflag;
fsr = t->thread.fsr;
......@@ -119,6 +119,7 @@ ia32_load_state (struct task_struct *t)
regs->r17 = (_TSS(nr) << 48) | (_LDT(nr) << 32) | (__u32) regs->r17;
regs->r30 = load_desc(_LDT(nr)); /* LDTD */
put_cpu();
}
/*
......
......@@ -3433,8 +3433,12 @@ struct sysinfo32 {
u32 bufferram;
u32 totalswap;
u32 freeswap;
unsigned short procs;
char _f[22];
u16 procs;
u16 pad;
u32 totalhigh;
u32 freehigh;
u32 mem_unit;
char _f[8];
};
asmlinkage long
......@@ -3463,6 +3467,9 @@ sys32_sysinfo (struct sysinfo32 *info)
err |= __put_user(s.totalswap, &info->totalswap);
err |= __put_user(s.freeswap, &info->freeswap);
err |= __put_user(s.procs, &info->procs);
err |= __put_user (s.totalhigh, &info->totalhigh);
err |= __put_user (s.freehigh, &info->freehigh);
err |= __put_user (s.mem_unit, &info->mem_unit);
if (err)
return -EFAULT;
return ret;
......
......@@ -55,6 +55,7 @@ asm (".weak iosapic_register_intr");
asm (".weak iosapic_override_isa_irq");
asm (".weak iosapic_register_platform_intr");
asm (".weak iosapic_init");
asm (".weak iosapic_system_init");
asm (".weak iosapic_version");
void (*pm_idle) (void);
......@@ -290,40 +291,6 @@ acpi_parse_lapic_nmi (acpi_table_entry_header *header)
}
static int __init
acpi_find_iosapic (unsigned int gsi, u32 *gsi_base, char **iosapic_address)
{
struct acpi_table_iosapic *iosapic;
int ver;
int max_pin;
char *p;
char *end;
if (!gsi_base || !iosapic_address)
return -ENODEV;
p = (char *) (acpi_madt + 1);
end = p + (acpi_madt->header.length - sizeof(struct acpi_table_madt));
while (p < end) {
if (*p == ACPI_MADT_IOSAPIC) {
iosapic = (struct acpi_table_iosapic *) p;
*gsi_base = iosapic->global_irq_base;
*iosapic_address = ioremap(iosapic->address, 0);
ver = iosapic_version(*iosapic_address);
max_pin = (ver >> 16) & 0xff;
if ((gsi - *gsi_base) <= max_pin)
return 0; /* Found it! */
}
p += p[1];
}
return -ENODEV;
}
static int __init
acpi_parse_iosapic (acpi_table_entry_header *header)
{
......@@ -335,16 +302,9 @@ acpi_parse_iosapic (acpi_table_entry_header *header)
acpi_table_print_madt_entry(header);
if (iosapic_init) {
#ifndef CONFIG_ITANIUM
/* PCAT_COMPAT flag indicates dual-8259 setup */
iosapic_init(iosapic->address, iosapic->global_irq_base,
acpi_madt->flags.pcat_compat);
#else
/* Firmware on old Itanium systems is broken */
iosapic_init(iosapic->address, iosapic->global_irq_base, 1);
#endif
}
if (iosapic_init)
iosapic_init(iosapic->address, iosapic->global_irq_base);
return 0;
}
......@@ -354,8 +314,6 @@ acpi_parse_plat_int_src (acpi_table_entry_header *header)
{
struct acpi_table_plat_int_src *plintsrc;
int vector;
u32 gsi_base;
char *iosapic_address;
plintsrc = (struct acpi_table_plat_int_src *) header;
if (!plintsrc)
......@@ -368,11 +326,6 @@ acpi_parse_plat_int_src (acpi_table_entry_header *header)
return -ENODEV;
}
if (acpi_find_iosapic(plintsrc->global_irq, &gsi_base, &iosapic_address)) {
printk(KERN_WARNING PREFIX "IOSAPIC not found\n");
return -ENODEV;
}
/*
* Get vector assignment for this interrupt, set attributes,
* and program the IOSAPIC routing table.
......@@ -382,10 +335,8 @@ acpi_parse_plat_int_src (acpi_table_entry_header *header)
plintsrc->iosapic_vector,
plintsrc->eid,
plintsrc->id,
(plintsrc->flags.polarity == 1) ? 1 : 0,
(plintsrc->flags.trigger == 1) ? 1 : 0,
gsi_base,
iosapic_address);
(plintsrc->flags.polarity == 1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
(plintsrc->flags.trigger == 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
platform_intr_list[plintsrc->type] = vector;
return 0;
......@@ -408,8 +359,8 @@ acpi_parse_int_src_ovr (acpi_table_entry_header *header)
return 0;
iosapic_override_isa_irq(p->bus_irq, p->global_irq,
(p->flags.polarity == 1) ? 1 : 0,
(p->flags.trigger == 1) ? 1 : 0);
(p->flags.polarity == 1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
(p->flags.trigger == 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
return 0;
}
......@@ -439,7 +390,13 @@ acpi_parse_madt (unsigned long phys_addr, unsigned long size)
acpi_madt = (struct acpi_table_madt *) __va(phys_addr);
/* remember the value for reference after free_initmem() */
#ifdef CONFIG_ITANIUM
has_8259 = 1; /* Firmware on old Itanium systems is broken */
#else
has_8259 = acpi_madt->flags.pcat_compat;
#endif
if (iosapic_system_init)
iosapic_system_init(has_8259);
/* Get base address of IPI Message Block */
......@@ -639,8 +596,7 @@ acpi_parse_fadt (unsigned long phys_addr, unsigned long size)
{
struct acpi_table_header *fadt_header;
struct fadt_descriptor_rev2 *fadt;
u32 sci_irq, gsi_base;
char *iosapic_address;
u32 sci_irq;
if (!phys_addr || !size)
return -EINVAL;
......@@ -662,8 +618,7 @@ acpi_parse_fadt (unsigned long phys_addr, unsigned long size)
if (has_8259 && sci_irq < 16)
return 0; /* legacy, no setup required */
if (!acpi_find_iosapic(sci_irq, &gsi_base, &iosapic_address))
iosapic_register_intr(sci_irq, 0, 0, gsi_base, iosapic_address);
iosapic_register_intr(sci_irq, IOSAPIC_POL_LOW, IOSAPIC_LEVEL);
return 0;
}
......@@ -717,8 +672,6 @@ acpi_parse_spcr (unsigned long phys_addr, unsigned long size)
if ((spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE) &&
(spcr->int_type == ACPI_SERIAL_INT_SAPIC))
{
u32 gsi_base;
char *iosapic_address;
int vector;
/* We have a UART in memory space with an SAPIC interrupt */
......@@ -728,11 +681,7 @@ acpi_parse_spcr (unsigned long phys_addr, unsigned long size)
(spcr->global_int[1] << 8) |
(spcr->global_int[0]) );
/* Which iosapic does this interrupt belong to? */
if (!acpi_find_iosapic(gsi, &gsi_base, &iosapic_address))
vector = iosapic_register_intr(gsi, 1, 1,
gsi_base, iosapic_address);
vector = iosapic_register_intr(gsi, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
}
return 0;
}
......@@ -741,7 +690,7 @@ acpi_parse_spcr (unsigned long phys_addr, unsigned long size)
int __init
acpi_boot_init (char *cmdline)
acpi_boot_init (void)
{
/*
......@@ -888,12 +837,10 @@ acpi_irq_to_vector (u32 irq)
return gsi_to_vector(irq);
}
int __init
int
acpi_register_irq (u32 gsi, u32 polarity, u32 trigger)
{
int vector = 0;
u32 irq_base;
char *iosapic_address;
if (acpi_madt->flags.pcat_compat && (gsi < 16))
return isa_irq_to_vector(gsi);
......@@ -901,12 +848,9 @@ acpi_register_irq (u32 gsi, u32 polarity, u32 trigger)
if (!iosapic_register_intr)
return 0;
/* Find the IOSAPIC */
if (!acpi_find_iosapic(gsi, &irq_base, &iosapic_address)) {
/* Turn it on */
vector = iosapic_register_intr (gsi, polarity, trigger,
irq_base, iosapic_address);
}
vector = iosapic_register_intr (gsi, polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
trigger ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
return vector;
}
......
......@@ -586,10 +586,21 @@ GLOBAL_ENTRY(ia64_leave_kernel)
// work.need_resched etc. mustn't get changed by this CPU before it returns to
// user- or fsys-mode:
(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk
#ifdef CONFIG_PREEMPT
rsm psr.i // disable interrupts
adds r17=TI_FLAGS+IA64_TASK_SIZE,r13
(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13
;;
(pKStk) ld4 r21=[r20] // preempt_count ->r21
;;
(pKStk) cmp4.eq p6,p0=r21,r0 // p6 <- preempt_count == 0
;;
#else /* CONFIG_PREEMPT */
(pUStk) rsm psr.i
;;
(pUStk) adds r17=TI_FLAGS+IA64_TASK_SIZE,r13
;;
#endif /* CONFIG_PREEMPT */
.work_processed:
(p6) ld4 r18=[r17] // load current_thread_info()->flags
adds r2=PT(R8)+16,r12
......@@ -701,7 +712,7 @@ GLOBAL_ENTRY(ia64_leave_kernel)
* NOTE: alloc, loadrs, and cover can't be predicated.
*/
(pNonSys) br.cond.dpnt dont_preserve_current_frame
cover // add current frame into dirty partition
cover // add current frame into dirty partition and set cr.ifs
;;
mov r19=ar.bsp // get new backing store pointer
sub r16=r16,r18 // krbs = old bsp - size of dirty partition
......@@ -727,7 +738,7 @@ dont_preserve_current_frame:
# define Nregs 14
#endif
alloc loc0=ar.pfs,2,Nregs-2,2,0
shr.u loc1=r18,9 // RNaTslots <= dirtySize / (64*8) + 1
shr.u loc1=r18,9 // RNaTslots <= floor(dirtySize / (64*8))
sub r17=r17,r18 // r17 = (physStackedSize + 8) - dirtySize
;;
mov ar.rsc=r19 // load ar.rsc to be used for "loadrs"
......@@ -774,13 +785,13 @@ rse_clear_invalid:
;;
mov loc3=0
mov loc4=0
mov loc9=0
mov loc5=0
mov loc6=0
mov loc7=0
(pRecurse) br.call.sptk.many b6=rse_clear_invalid
;;
mov loc7=0
mov loc8=0
mov loc9=0
cmp.ne pReturn,p0=r0,in1 // if recursion count != 0, we need to do a br.ret
mov loc10=0
mov loc11=0
......@@ -810,15 +821,27 @@ skip_rbs_switch:
.work_pending:
tbit.z p6,p0=r18,TIF_NEED_RESCHED // current_thread_info()->need_resched==0?
(p6) br.cond.sptk.few .notify
#ifdef CONFIG_PREEMPT
(pKStk) dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1
;;
(pKStk) st4 [r20]=r21
ssm psr.i // enable interrupts
#endif
#if __GNUC__ < 3
br.call.spnt.many rp=invoke_schedule
#else
br.call.spnt.many rp=schedule
#endif
.ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1
rsm psr.i
rsm psr.i // disable interrupts
;;
adds r17=TI_FLAGS+IA64_TASK_SIZE,r13
#if CONFIG_PREEMPT
(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13
;;
(pKStk) st4 [r20]=r0 // preempt_count() <- 0
#endif
br.cond.sptk.many .work_processed // re-check
.notify:
......@@ -904,13 +927,14 @@ ENTRY(notify_resume_user)
mov r9=ar.unat
mov loc0=rp // save return address
mov out0=0 // there is no "oldset"
adds out1=0,sp // out1=&sigscratch
adds out1=8,sp // out1=&sigscratch->ar_pfs
(pSys) mov out2=1 // out2==1 => we're in a syscall
;;
(pNonSys) mov out2=0 // out2==0 => not a syscall
.fframe 16
.spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!)
st8 [sp]=r9,-16 // allocate space for ar.unat and save it
st8 [out1]=loc1,-8 // save ar.pfs, out1=&sigscratch
.body
br.call.sptk.many rp=do_notify_resume_user
.ret15: .restore sp
......@@ -931,11 +955,12 @@ GLOBAL_ENTRY(sys_rt_sigsuspend)
mov loc0=rp // save return address
mov out0=in0 // mask
mov out1=in1 // sigsetsize
adds out2=0,sp // out2=&sigscratch
adds out2=8,sp // out2=&sigscratch->ar_pfs
;;
.fframe 16
.spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!)
st8 [sp]=r9,-16 // allocate space for ar.unat and save it
st8 [out2]=loc1,-8 // save ar.pfs, out2=&sigscratch
.body
br.call.sptk.many rp=ia64_rt_sigsuspend
.ret17: .restore sp
......@@ -1242,7 +1267,7 @@ sys_call_table:
data8 sys_sched_setaffinity
data8 sys_sched_getaffinity
data8 sys_set_tid_address
data8 ia64_ni_syscall
data8 sys_fadvise64
data8 ia64_ni_syscall // 1235
data8 sys_exit_group
data8 sys_lookup_dcookie
......
......@@ -3,11 +3,16 @@
*
* Copyright (C) 2003 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com>
*
* 18-Feb-03 louisk Implement fsys_gettimeofday().
* 28-Feb-03 davidm Fixed several bugs in fsys_gettimeofday(). Tuned it some more,
* probably broke it along the way... ;-)
*/
#include <asm/asmmacro.h>
#include <asm/errno.h>
#include <asm/offsets.h>
#include <asm/percpu.h>
#include <asm/thread_info.h>
/*
......@@ -123,6 +128,183 @@ ENTRY(fsys_set_tid_address)
br.ret.sptk.many b6
END(fsys_set_tid_address)
/*
* Note 1: This routine uses floating-point registers, but only with registers that
* operate on integers. Because of that, we don't need to set ar.fpsr to the
* kernel default value.
*
* Note 2: For now, we will assume that all CPUs run at the same clock-frequency.
* If that wasn't the case, we would have to disable preemption (e.g.,
* by disabling interrupts) between reading the ITC and reading
* local_cpu_data->nsec_per_cyc.
*
* Note 3: On platforms where the ITC-drift bit is set in the SAL feature vector,
* we ought to either skip the ITC-based interpolation or run an ntp-like
* daemon to keep the ITCs from drifting too far apart.
*/
ENTRY(fsys_gettimeofday)
add r9=TI_FLAGS+IA64_TASK_SIZE,r16
movl r3=THIS_CPU(cpu_info)
mov.m r31=ar.itc // put time stamp into r31 (ITC) == now (35 cyc)
movl r19=xtime // xtime is a timespec struct
;;
#ifdef CONFIG_SMP
movl r10=__per_cpu_offset
;;
ld8 r10=[r10] // r10 <- __per_cpu_offset[0]
movl r21=cpu_info__per_cpu
;;
add r10=r21, r10 // r10 <- &cpu_data(time_keeper_id)
#else
mov r10=r3
#endif
ld4 r9=[r9]
movl r17=xtime_lock
;;
// r32, r33 should contain the 2 args of gettimeofday
adds r21=IA64_CPUINFO_ITM_NEXT_OFFSET, r10
mov r2=-1
tnat.nz p6,p7=r32 // guard against NaT args
;;
adds r10=IA64_CPUINFO_ITM_DELTA_OFFSET, r10
(p7) tnat.nz p6,p0=r33
(p6) br.cond.spnt.few .fail
adds r8=IA64_CPUINFO_NSEC_PER_CYC_OFFSET, r3
movl r24=2361183241434822607 // for division hack (only for / 1000)
;;
ldf8 f7=[r10] // f7 now contains itm_delta
setf.sig f11=r2
adds r10=8, r32
adds r20=IA64_TIMESPEC_TV_NSEC_OFFSET, r19 // r20 = &xtime->tv_nsec
movl r26=jiffies
setf.sig f9=r24 // f9 is used for division hack
movl r27=wall_jiffies
and r9=TIF_ALLWORK_MASK,r9
movl r25=last_nsec_offset
;;
/*
* Verify that we have permission to write to struct timeval. Note:
* Another thread might unmap the mapping before we actually get
* to store the result. That's OK as long as the stores are also
* protect by EX().
*/
EX(.fail, probe.w.fault r32, 3) // this must come _after_ NaT-check
EX(.fail, probe.w.fault r10, 3) // this must come _after_ NaT-check
nop 0
ldf8 f10=[r8] // f10 <- local_cpu_data->nsec_per_cyc value
cmp.ne p8, p0=0, r9
(p8) br.spnt.many fsys_fallback_syscall
;;
.retry: // *** seq = read_seqbegin(&xtime_lock); ***
ld4.acq r23=[r17] // since &xtime_lock == &xtime_lock->sequence
ld8 r14=[r25] // r14 (old) = last_nsec_offset
ld8 r28=[r26] // r28 = jiffies
ld8 r29=[r27] // r29 = wall_jiffies
;;
ldf8 f8=[r21] // f8 now contains itm_next
sub r28=r29, r28, 1 // r28 now contains "-(lost + 1)"
tbit.nz p9, p10=r23, 0 // p9 <- is_odd(r23), p10 <- is_even(r23)
;;
ld8 r2=[r19] // r2 = sec = xtime.tv_sec
ld8 r29=[r20] // r29 = nsec = xtime.tv_nsec
setf.sig f6=r28 // f6 <- -(lost + 1) (6 cyc)
;;
mf
xma.l f8=f6, f7, f8 // f8 (last_tick) <- -(lost + 1)*itm_delta + itm_next (5 cyc)
nop 0
setf.sig f12=r31 // f12 <- ITC (6 cyc)
// *** if (unlikely(read_seqretry(&xtime_lock, seq))) continue; ***
ld4 r24=[r17] // r24 = xtime_lock->sequence (re-read)
nop 0
;;
mov r31=ar.itc // re-read ITC in case we .retry (35 cyc)
xma.l f8=f11, f8, f12 // f8 (elapsed_cycles) <- (-1*last_tick + now) = (now - last_tick)
nop 0
;;
getf.sig r18=f8 // r18 <- (now - last_tick)
xmpy.l f8=f8, f10 // f8 <- elapsed_cycles*nsec_per_cyc (5 cyc)
add r3=r29, r14 // r3 = (nsec + old)
;;
cmp.lt p7, p8=r18, r0 // if now < last_tick, set p7 = 1, p8 = 0
getf.sig r18=f8 // r18 = elapsed_cycles*nsec_per_cyc (6 cyc)
nop 0
;;
(p10) cmp.ne p9, p0=r23, r24 // if xtime_lock->sequence != seq, set p9
shr.u r18=r18, IA64_NSEC_PER_CYC_SHIFT // r18 <- offset
(p9) br.spnt.many .retry
;;
mov ar.ccv=r14 // ar.ccv = old (1 cyc)
cmp.leu p7, p8=r18, r14 // if (offset <= old), set p7 = 1, p8 = 0
;;
(p8) cmpxchg8.rel r24=[r25], r18, ar.ccv // compare-and-exchange (atomic!)
(p8) add r3=r29, r18 // r3 = (nsec + offset)
;;
shr.u r3=r3, 3 // initiate dividing r3 by 1000
;;
setf.sig f8=r3 // (6 cyc)
mov r10=1000000 // r10 = 1000000
;;
(p8) cmp.ne.unc p9, p0=r24, r14
xmpy.hu f6=f8, f9 // (5 cyc)
(p9) br.spnt.many .retry
;;
getf.sig r3=f6 // (6 cyc)
;;
shr.u r3=r3, 4 // end of division, r3 is divided by 1000 (=usec)
;;
1: cmp.geu p7, p0=r3, r10 // while (usec >= 1000000)
;;
(p7) sub r3=r3, r10 // usec -= 1000000
(p7) adds r2=1, r2 // ++sec
(p7) br.spnt.many 1b
// finally: r2 = sec, r3 = usec
EX(.fail, st8 [r32]=r2)
adds r9=8, r32
mov r8=r0 // success
;;
EX(.fail, st8 [r9]=r3) // store them in the timeval struct
mov r10=0
MCKINLEY_E9_WORKAROUND
br.ret.sptk.many b6 // return to caller
/*
* Note: We are NOT clearing the scratch registers here. Since the only things
* in those registers are time-related variables and some addresses (which
* can be obtained from System.map), none of this should be security-sensitive
* and we should be fine.
*/
.fail: adds r8=EINVAL, r0 // r8 = EINVAL
adds r10=-1, r0 // r10 = -1
MCKINLEY_E9_WORKAROUND
br.ret.spnt.many b6 // return with r8 set to EINVAL
END(fsys_gettimeofday)
.rodata
.align 8
.globl fsyscall_table
......@@ -190,7 +372,7 @@ fsyscall_table:
data8 fsys_fallback_syscall // setrlimit
data8 fsys_fallback_syscall // getrlimit // 1085
data8 fsys_fallback_syscall // getrusage
data8 fsys_fallback_syscall // gettimeofday
data8 fsys_gettimeofday // gettimeofday
data8 fsys_fallback_syscall // settimeofday
data8 fsys_fallback_syscall // select
data8 fsys_fallback_syscall // poll // 1090
......
......@@ -145,11 +145,12 @@ END(fsys_fallback_syscall)
*/
#define SIGTRAMP_SAVES \
.unwabi @svr4, 's' // mark this as a sigtramp handler (saves scratch regs) \
.savesp ar.unat, UNAT_OFF+SIGCONTEXT_OFF \
.savesp ar.fpsr, FPSR_OFF+SIGCONTEXT_OFF \
.savesp pr, PR_OFF+SIGCONTEXT_OFF \
.savesp rp, RP_OFF+SIGCONTEXT_OFF \
.unwabi @svr4, 's'; /* mark this as a sigtramp handler (saves scratch regs) */ \
.savesp ar.unat, UNAT_OFF+SIGCONTEXT_OFF; \
.savesp ar.fpsr, FPSR_OFF+SIGCONTEXT_OFF; \
.savesp pr, PR_OFF+SIGCONTEXT_OFF; \
.savesp rp, RP_OFF+SIGCONTEXT_OFF; \
.savesp ar.pfs, CFM_OFF+SIGCONTEXT_OFF; \
.vframesp SP_OFF+SIGCONTEXT_OFF
GLOBAL_ENTRY(ia64_sigtramp)
......@@ -173,9 +174,7 @@ GLOBAL_ENTRY(ia64_sigtramp)
.spillsp.p p8, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
(p8) br.cond.spnt setup_rbs // yup -> (clobbers r14, r15, and r16)
back_from_setup_rbs:
.spillreg ar.pfs, r8
alloc r8=ar.pfs,0,0,3,0 // get CFM0, EC0, and CPL0 into r8
alloc r8=ar.pfs,0,0,3,0
ld8 out0=[base0],16 // load arg0 (signum)
adds base1=(ARG1_OFF-(RBS_BASE_OFF+SIGCONTEXT_OFF)),base1
;;
......@@ -184,17 +183,12 @@ back_from_setup_rbs:
;;
ld8 out2=[base0] // load arg2 (sigcontextp)
ld8 gp=[r17] // get signal handler's global pointer
adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
;;
.spillsp ar.bsp, BSP_OFF+SIGCONTEXT_OFF
st8 [base0]=r9,(CFM_OFF-BSP_OFF) // save sc_ar_bsp
dep r8=0,r8,38,26 // clear EC0, CPL0 and reserved bits
adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
;;
.spillsp ar.pfs, CFM_OFF+SIGCONTEXT_OFF
st8 [base0]=r8 // save CFM0
st8 [base0]=r9 // save sc_ar_bsp
adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
;;
stf.spill [base0]=f6,32
stf.spill [base1]=f7,32
......@@ -217,7 +211,6 @@ back_from_setup_rbs:
ld8 r15=[base0],(CFM_OFF-BSP_OFF) // fetch sc_ar_bsp and advance to CFM_OFF
mov r14=ar.bsp
;;
ld8 r8=[base0] // restore (perhaps modified) CFM0, EC0, and CPL0
cmp.ne p8,p0=r14,r15 // do we need to restore the rbs?
(p8) br.cond.spnt restore_rbs // yup -> (clobbers r14-r18, f6 & f7)
;;
......
......@@ -17,6 +17,7 @@
static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
struct mm_struct init_mm = INIT_MM(init_mm);
/*
......
This diff is collapsed.
......@@ -340,12 +340,14 @@ unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs)
* 0 return value means that this irq is already being
* handled by some other CPU. (or is disabled)
*/
int cpu = smp_processor_id();
int cpu;
irq_desc_t *desc = irq_desc(irq);
struct irqaction * action;
unsigned int status;
irq_enter();
cpu = smp_processor_id();
kstat_cpu(cpu).irqs[irq]++;
if (desc->status & IRQ_PER_CPU) {
......
......@@ -10,19 +10,6 @@
struct ia64_machine_vector ia64_mv;
/*
* Most platforms use this routine for mapping page frame addresses into a memory map
* index.
*
* Note: we can't use __pa() because map_nr_dense(X) MUST map to something >= max_mapnr if
* X is outside the identity mapped kernel space.
*/
unsigned long
map_nr_dense (unsigned long addr)
{
return (addr - PAGE_OFFSET) >> PAGE_SHIFT;
}
static struct ia64_machine_vector *
lookup_machvec (const char *name)
{
......
......@@ -825,7 +825,7 @@ ia64_init_handler (struct pt_regs *regs)
plog_ptr=(ia64_err_rec_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT);
proc_ptr = &plog_ptr->proc_err;
ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area);
ia64_process_min_state_save(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area);
/* Clear the INIT SAL logs now that they have been saved in the OS buffer */
ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT);
......@@ -1620,7 +1620,7 @@ ia64_log_proc_dev_err_info_print (sal_log_processor_info_t *slpi,
* absent. Also, current implementations only allocate space for number of
* elements used. So we walk the data pointer from here on.
*/
p_data = &slpi->cache_check_info[0];
p_data = &slpi->info[0];
/* Print the cache check information if any*/
for (i = 0 ; i < slpi->valid.num_cache_check; i++, p_data++)
......
......@@ -341,11 +341,11 @@ vm_info(char *page)
return 0;
}
p += sprintf(p, "\nTLB walker : %s implemented\n" \
p += sprintf(p, "\nTLB walker : %simplemented\n" \
"Number of DTR : %d\n" \
"Number of ITR : %d\n" \
"TLB insertable page sizes : ",
vm_info_1.pal_vm_info_1_s.vw ? "\b":"not",
vm_info_1.pal_vm_info_1_s.vw ? "" : "not ",
vm_info_1.pal_vm_info_1_s.max_dtr_entry+1,
vm_info_1.pal_vm_info_1_s.max_itr_entry+1);
......@@ -894,11 +894,13 @@ palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, voi
* in SMP mode, we may need to call another CPU to get correct
* information. PAL, by definition, is processor specific
*/
if (f->req_cpu == smp_processor_id())
if (f->req_cpu == get_cpu())
len = (*palinfo_entries[f->func_id].proc_read)(page);
else
len = palinfo_handle_smp(f, page);
put_cpu();
if (len <= off+count) *eof = 1;
*start = page + off;
......
This diff is collapsed.
/*
* Kernel support for the ptrace() and syscall tracing interfaces.
*
* Copyright (C) 1999-2002 Hewlett-Packard Co
* Copyright (C) 1999-2003 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com>
*
* Derived from the x86 and Alpha versions. Most of the code in here
......@@ -1235,19 +1235,12 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data,
ret = 0;
goto out_tsk;
case PTRACE_GETSIGINFO:
ret = -EIO;
if (!access_ok(VERIFY_WRITE, data, sizeof (siginfo_t)) || !child->thread.siginfo)
goto out_tsk;
ret = copy_siginfo_to_user((siginfo_t *) data, child->thread.siginfo);
case PTRACE_OLD_GETSIGINFO: /* for backwards-compatibility */
ret = ptrace_request(child, PTRACE_GETSIGINFO, addr, data);
goto out_tsk;
case PTRACE_SETSIGINFO:
ret = -EIO;
if (!access_ok(VERIFY_READ, data, sizeof (siginfo_t))
|| child->thread.siginfo == 0)
goto out_tsk;
ret = copy_siginfo_from_user(child->thread.siginfo, (siginfo_t *) data);
case PTRACE_OLD_SETSIGINFO: /* for backwards-compatibility */
ret = ptrace_request(child, PTRACE_SETSIGINFO, addr, data);
goto out_tsk;
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
......
......@@ -363,7 +363,7 @@ setup_arch (char **cmdline_p)
#ifdef CONFIG_ACPI_BOOT
/* Initialize the ACPI boot-time table parser */
acpi_table_init(*cmdline_p);
acpi_table_init();
# ifdef CONFIG_ACPI_NUMA
acpi_numa_init();
# endif
......@@ -422,7 +422,7 @@ setup_arch (char **cmdline_p)
cpu_init(); /* initialize the bootstrap CPU */
#ifdef CONFIG_ACPI_BOOT
acpi_boot_init(*cmdline_p);
acpi_boot_init();
#endif
#ifdef CONFIG_SERIAL_HCDP
if (efi.hcdp) {
......
struct sigscratch {
unsigned long scratch_unat; /* ar.unat for the general registers saved in pt */
unsigned long pad;
unsigned long ar_pfs; /* for syscalls, the user-level function-state */
struct pt_regs pt;
};
......
......@@ -315,7 +315,7 @@ ia64_rt_sigreturn (struct sigscratch *scr)
static long
setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr)
{
unsigned long flags = 0, ifs, nat;
unsigned long flags = 0, ifs, cfm, nat;
long err;
ifs = scr->pt.cr_ifs;
......@@ -325,7 +325,9 @@ setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr)
if ((ifs & (1UL << 63)) == 0) {
/* if cr_ifs isn't valid, we got here through a syscall */
flags |= IA64_SC_FLAG_IN_SYSCALL;
}
cfm = scr->ar_pfs & ((1UL << 38) - 1);
} else
cfm = ifs & ((1UL << 38) - 1);
ia64_flush_fph(current);
if ((current->thread.flags & IA64_THREAD_FPH_VALID)) {
flags |= IA64_SC_FLAG_FPH_VALID;
......@@ -344,6 +346,7 @@ setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr)
err |= __put_user(nat, &sc->sc_nat);
err |= PUT_SIGSET(mask, &sc->sc_mask);
err |= __put_user(cfm, &sc->sc_cfm);
err |= __put_user(scr->pt.cr_ipsr & IA64_PSR_UM, &sc->sc_um);
err |= __put_user(scr->pt.ar_rsc, &sc->sc_ar_rsc);
err |= __put_user(scr->pt.ar_ccv, &sc->sc_ar_ccv);
......@@ -422,6 +425,15 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
scr->pt.ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */
scr->pt.cr_iip = tramp_addr;
ia64_psr(&scr->pt)->ri = 0; /* start executing in first slot */
/*
* Force the interruption function mask to zero. This has no effect when a
* system-call got interrupted by a signal (since, in that case, scr->pt_cr_ifs is
* ignored), but it has the desirable effect of making it possible to deliver a
* signal with an incomplete register frame (which happens when a mandatory RSE
* load faults). Furthermore, it has no negative effect on the getting the user's
* dirty partition preserved, because that's governed by scr->pt.loadrs.
*/
scr->pt.cr_ifs = (1UL << 63);
/*
* Note: this affects only the NaT bits of the scratch regs (the ones saved in
......@@ -522,7 +534,7 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
if (signr <= 0)
break;
ka = &current->sig->action[signr - 1];
ka = &current->sighand->action[signr - 1];
if (restart) {
switch (errno) {
......
......@@ -90,7 +90,7 @@ stop_this_cpu (void)
void
handle_IPI (int irq, void *dev_id, struct pt_regs *regs)
{
int this_cpu = smp_processor_id();
int this_cpu = get_cpu();
unsigned long *pending_ipis = &__get_cpu_var(ipi_operation);
unsigned long ops;
......@@ -146,8 +146,12 @@ handle_IPI (int irq, void *dev_id, struct pt_regs *regs)
} while (ops);
mb(); /* Order data access and bit testing. */
}
put_cpu();
}
/*
* Called with preeemption disabled
*/
static inline void
send_IPI_single (int dest_cpu, int op)
{
......@@ -155,6 +159,9 @@ send_IPI_single (int dest_cpu, int op)
platform_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0);
}
/*
* Called with preeemption disabled
*/
static inline void
send_IPI_allbutself (int op)
{
......@@ -166,6 +173,9 @@ send_IPI_allbutself (int op)
}
}
/*
* Called with preeemption disabled
*/
static inline void
send_IPI_all (int op)
{
......@@ -176,12 +186,18 @@ send_IPI_all (int op)
send_IPI_single(i, op);
}
/*
* Called with preeemption disabled
*/
static inline void
send_IPI_self (int op)
{
send_IPI_single(smp_processor_id(), op);
}
/*
* Called with preeemption disabled
*/
void
smp_send_reschedule (int cpu)
{
......@@ -197,12 +213,15 @@ void
smp_send_reschedule_all (void)
{
int i;
int cpu = get_cpu(); /* disable preemption */
for (i = 0; i < NR_CPUS; i++)
if (cpu_online(i) && i != smp_processor_id())
if (cpu_online(i) && i != cpu)
smp_send_reschedule(i);
put_cpu();
}
void
smp_flush_tlb_all (void)
{
......@@ -247,9 +266,11 @@ smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int
{
struct call_data_struct data;
int cpus = 1;
int me = get_cpu(); /* prevent preemption and reschedule on another processor */
if (cpuid == smp_processor_id()) {
if (cpuid == me) {
printk("%s: trying to call self\n", __FUNCTION__);
put_cpu();
return -EBUSY;
}
......@@ -276,6 +297,7 @@ smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int
call_data = NULL;
spin_unlock_bh(&call_lock);
put_cpu();
return 0;
}
......
......@@ -33,17 +33,8 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len
return -ENOMEM;
#ifdef CONFIG_HUGETLB_PAGE
#define COLOR_HALIGN(addr) ((addr + HPAGE_SIZE - 1) & ~(HPAGE_SIZE - 1))
#define TASK_HPAGE_BASE ((REGION_HPAGE << REGION_SHIFT) | HPAGE_SIZE)
if (filp && is_file_hugepages(filp)) {
if ((REGION_NUMBER(addr) != REGION_HPAGE) || (addr & (HPAGE_SIZE -1)))
addr = TASK_HPAGE_BASE;
addr = COLOR_HALIGN(addr);
}
else {
if (REGION_NUMBER(addr) == REGION_HPAGE)
addr = 0;
}
#endif
if (!addr)
addr = TASK_UNMAPPED_BASE;
......
......@@ -25,7 +25,7 @@
#include <asm/system.h>
extern unsigned long wall_jiffies;
extern unsigned long last_time_offset;
extern unsigned long last_nsec_offset;
u64 jiffies_64 = INITIAL_JIFFIES;
......@@ -74,13 +74,13 @@ gettimeoffset (void)
- (lost + 1)*cpu_data(time_keeper_id)->itm_delta);
now = ia64_get_itc();
if ((long) (now - last_tick) < 0) {
if (unlikely((long) (now - last_tick) < 0)) {
printk(KERN_ERR "CPU %d: now < last_tick (now=0x%lx,last_tick=0x%lx)!\n",
smp_processor_id(), now, last_tick);
return last_time_offset;
return last_nsec_offset;
}
elapsed_cycles = now - last_tick;
return (elapsed_cycles*local_cpu_data->usec_per_cyc) >> IA64_USEC_PER_CYC_SHIFT;
return (elapsed_cycles*local_cpu_data->nsec_per_cyc) >> IA64_NSEC_PER_CYC_SHIFT;
}
void
......@@ -115,30 +115,55 @@ do_settimeofday (struct timeval *tv)
void
do_gettimeofday (struct timeval *tv)
{
unsigned long seq, usec, sec, old;
unsigned long seq, nsec, usec, sec, old, offset;
do {
while (1) {
seq = read_seqbegin(&xtime_lock);
usec = gettimeoffset();
{
old = last_nsec_offset;
offset = gettimeoffset();
sec = xtime.tv_sec;
nsec = xtime.tv_nsec;
}
if (unlikely(read_seqretry(&xtime_lock, seq)))
continue;
/*
* Ensure time never goes backwards, even when ITC on
* different CPUs are not perfectly synchronized.
* Ensure that for any pair of causally ordered gettimeofday() calls, time
* never goes backwards (even when ITC on different CPUs are not perfectly
* synchronized). (A pair of concurrent calls to gettimeofday() is by
* definition non-causal and hence it makes no sense to talk about
* time-continuity for such calls.)
*
* Doing this in a lock-free and race-free manner is tricky. Here is why
* it works (most of the time): read_seqretry() just succeeded, which
* implies we calculated a consistent (valid) value for "offset". If the
* cmpxchg() below succeeds, we further know that last_nsec_offset still
* has the same value as at the beginning of the loop, so there was
* presumably no timer-tick or other updates to last_nsec_offset in the
* meantime. This isn't 100% true though: there _is_ a possibility of a
* timer-tick occurring right right after read_seqretry() and then getting
* zero or more other readers which will set last_nsec_offset to the same
* value as the one we read at the beginning of the loop. If this
* happens, we'll end up returning a slightly newer time than we ought to
* (the jump forward is at most "offset" nano-seconds). There is no
* danger of causing time to go backwards, though, so we are safe in that
* sense. We could make the probability of this unlucky case occurring
* arbitrarily small by encoding a version number in last_nsec_offset, but
* even without versioning, the probability of this unlucky case should be
* so small that we won't worry about it.
*/
do {
old = last_time_offset;
if (usec <= old) {
usec = old;
if (offset <= old) {
offset = old;
break;
} else if (likely(cmpxchg(&last_nsec_offset, old, offset) == old))
break;
}
} while (cmpxchg(&last_time_offset, old, usec) != old);
sec = xtime.tv_sec;
usec += xtime.tv_nsec / 1000;
} while (read_seqend(&xtime_lock, seq));
/* someone else beat us to updating last_nsec_offset; try again */
}
usec = (nsec + offset) / 1000;
while (usec >= 1000000) {
while (unlikely(usec >= 1000000)) {
usec -= 1000000;
++sec;
}
......@@ -278,7 +303,7 @@ ia64_init_itm (void)
local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den;
local_cpu_data->itc_freq = itc_freq;
local_cpu_data->cyc_per_usec = (itc_freq + 500000) / 1000000;
local_cpu_data->usec_per_cyc = ((1000000UL<<IA64_USEC_PER_CYC_SHIFT)
local_cpu_data->nsec_per_cyc = ((1000000000UL<<IA64_NSEC_PER_CYC_SHIFT)
+ itc_freq/2)/itc_freq;
/* Setup the CPU local timer tick */
......
This diff is collapsed.
......@@ -137,7 +137,8 @@ enum unw_insn_opcode {
UNW_INSN_SETNAT_MEMSTK, /* s[dst+1].nat.type = MEMSTK;
s[dst+1].nat.off = *s.pri_unat - s[dst] */
UNW_INSN_SETNAT_TYPE, /* s[dst+1].nat.type = val */
UNW_INSN_LOAD /* s[dst] = *s[val] */
UNW_INSN_LOAD, /* s[dst] = *s[val] */
UNW_INSN_MOVE_SCRATCH, /* s[dst] = scratch reg "val" */
};
struct unw_insn {
......
......@@ -55,7 +55,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
/*
* If we're in an interrupt or have no user context, we must not take the fault..
*/
if (in_interrupt() || !mm)
if (in_atomic() || !mm)
goto no_context;
down_read(&mm->mmap_sem);
......@@ -79,7 +79,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
# if (((1 << VM_READ_BIT) != VM_READ || (1 << VM_WRITE_BIT) != VM_WRITE) \
|| (1 << VM_EXEC_BIT) != VM_EXEC)
# error File is out of sync with <linux/mm.h>. Pleaes update.
# error File is out of sync with <linux/mm.h>. Please update.
# endif
mask = ( (((isr >> IA64_ISR_X_BIT) & 1UL) << VM_EXEC_BIT)
......
......@@ -19,6 +19,8 @@
#include <linux/sysctl.h>
#define TASK_HPAGE_BASE (REGION_HPAGE << REGION_SHIFT)
static long htlbpagemem;
int htlbpage_max;
static long htlbzone_pages;
......@@ -98,7 +100,6 @@ set_huge_pte (struct mm_struct *mm, struct vm_area_struct *vma,
set_pte(page_table, entry);
return;
}
/*
* This function checks for proper alignment of input addr and len parameters.
*/
......@@ -108,6 +109,20 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
return -EINVAL;
if (addr & ~HPAGE_MASK)
return -EINVAL;
if (REGION_NUMBER(addr) != REGION_HPAGE)
return -EINVAL;
return 0;
}
/* This function checks if the address and address+len falls out of HugeTLB region. It
* return -EINVAL if any part of address range falls in HugeTLB region.
*/
int is_invalid_hugepage_range(unsigned long addr, unsigned long len)
{
if (REGION_NUMBER(addr) == REGION_HPAGE)
return -EINVAL;
if (REGION_NUMBER(addr+len) == REGION_HPAGE)
return -EINVAL;
return 0;
}
......@@ -173,6 +188,39 @@ follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
return i;
}
struct vm_area_struct *hugepage_vma(struct mm_struct *mm, unsigned long addr)
{
if (mm->used_hugetlb) {
if (REGION_NUMBER(addr) == REGION_HPAGE) {
struct vm_area_struct *vma = find_vma(mm, addr);
if (vma && is_vm_hugetlb_page(vma))
return vma;
}
}
return NULL;
}
struct page *follow_huge_addr(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, int write)
{
struct page *page;
pte_t *ptep;
ptep = huge_pte_offset(mm, addr);
page = pte_page(*ptep);
page += ((addr & ~HPAGE_MASK) >> PAGE_SHIFT);
get_page(page);
return page;
}
int pmd_huge(pmd_t pmd)
{
return 0;
}
struct page *
follow_huge_pmd(struct mm_struct *mm, unsigned long address, pmd_t *pmd, int write)
{
return NULL;
}
void free_huge_page(struct page *page)
{
BUG_ON(page_count(page));
......@@ -204,8 +252,6 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsig
BUG_ON(start & (HPAGE_SIZE - 1));
BUG_ON(end & (HPAGE_SIZE - 1));
spin_lock(&htlbpage_lock);
spin_unlock(&htlbpage_lock);
for (address = start; address < end; address += HPAGE_SIZE) {
pte = huge_pte_offset(mm, address);
if (pte_none(*pte))
......@@ -257,8 +303,12 @@ int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
ret = -ENOMEM;
goto out;
}
add_to_page_cache(page, mapping, idx, GFP_ATOMIC);
ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC);
unlock_page(page);
if (ret) {
free_huge_page(page);
goto out;
}
}
set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE);
}
......@@ -267,6 +317,29 @@ int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
return ret;
}
unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags)
{
struct vm_area_struct *vmm;
if (len > RGN_MAP_LIMIT)
return -ENOMEM;
if (len & ~HPAGE_MASK)
return -EINVAL;
/* This code assumes that REGION_HPAGE != 0. */
if ((REGION_NUMBER(addr) != REGION_HPAGE) || (addr & (HPAGE_SIZE - 1)))
addr = TASK_HPAGE_BASE;
else
addr = ALIGN(addr, HPAGE_SIZE);
for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
/* At this point: (!vmm || addr < vmm->vm_end). */
if (REGION_OFFSET(addr) + len > RGN_MAP_LIMIT)
return -ENOMEM;
if (!vmm || (addr + len) <= vmm->vm_start)
return addr;
addr = ALIGN(vmm->vm_end, HPAGE_SIZE);
}
}
void update_and_free_page(struct page *page)
{
int j;
......@@ -302,7 +375,7 @@ int try_to_free_low(int count)
break;
}
page = list_entry(p, struct page, list);
if ((page_zone(page))->name[0] != 'H') // Look for non-Highmem
if (!PageHighMem(page))
map = page;
}
if (map) {
......@@ -317,8 +390,8 @@ int try_to_free_low(int count)
int set_hugetlb_mem_size(int count)
{
int j, lcount;
struct page *page, *map;
int lcount;
struct page *page ;
extern long htlbzone_pages;
extern struct list_head htlbpage_freelist;
......@@ -417,5 +490,4 @@ static struct page *hugetlb_nopage(struct vm_area_struct * area, unsigned long a
struct vm_operations_struct hugetlb_vm_ops = {
.nopage = hugetlb_nopage,
.close = zap_hugetlb_resources,
};
......@@ -81,9 +81,13 @@ wrap_mmu_context (struct mm_struct *mm)
}
read_unlock(&tasklist_lock);
/* can't call flush_tlb_all() here because of race condition with O(1) scheduler [EF] */
{
int cpu = get_cpu(); /* prevent preemption/migration */
for (i = 0; i < NR_CPUS; ++i)
if (i != smp_processor_id())
if (i != cpu)
per_cpu(ia64_need_tlb_flush, i) = 1;
put_cpu();
}
local_flush_tlb_all();
}
......
......@@ -272,3 +272,76 @@ pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
return 0;
}
/**
* pci_cacheline_size - determine cacheline size for PCI devices
* @dev: void
*
* We want to use the line-size of the outer-most cache. We assume
* that this line-size is the same for all CPUs.
*
* Code mostly taken from arch/ia64/kernel/palinfo.c:cache_info().
*
* RETURNS: An appropriate -ERRNO error value on eror, or zero for success.
*/
static unsigned long
pci_cacheline_size (void)
{
u64 levels, unique_caches;
s64 status;
pal_cache_config_info_t cci;
static u8 cacheline_size;
if (cacheline_size)
return cacheline_size;
status = ia64_pal_cache_summary(&levels, &unique_caches);
if (status != 0) {
printk(KERN_ERR "%s: ia64_pal_cache_summary() failed (status=%ld)\n",
__FUNCTION__, status);
return SMP_CACHE_BYTES;
}
status = ia64_pal_cache_config_info(levels - 1, /* cache_type (data_or_unified)= */ 2,
&cci);
if (status != 0) {
printk(KERN_ERR "%s: ia64_pal_cache_config_info() failed (status=%ld)\n",
__FUNCTION__, status);
return SMP_CACHE_BYTES;
}
cacheline_size = 1 << cci.pcci_line_size;
return cacheline_size;
}
/**
* pcibios_prep_mwi - helper function for drivers/pci/pci.c:pci_set_mwi()
* @dev: the PCI device for which MWI is enabled
*
* For ia64, we can get the cacheline sizes from PAL.
*
* RETURNS: An appropriate -ERRNO error value on eror, or zero for success.
*/
int
pcibios_prep_mwi (struct pci_dev *dev)
{
unsigned long desired_linesize, current_linesize;
int rc = 0;
u8 pci_linesize;
desired_linesize = pci_cacheline_size();
pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &pci_linesize);
current_linesize = 4 * pci_linesize;
if (desired_linesize != current_linesize) {
printk(KERN_WARNING "PCI: slot %s has incorrect PCI cache line size of %lu bytes,",
dev->slot_name, current_linesize);
if (current_linesize > desired_linesize) {
printk(" expected %lu bytes instead\n", desired_linesize);
rc = -EINVAL;
} else {
printk(" correcting to %lu\n", desired_linesize);
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, desired_linesize / 4);
}
}
return rc;
}
......@@ -17,6 +17,6 @@ obj-$(CONFIG_IA64_SGI_SN) += stubs.o sgi_if.o xswitch.o klgraph_hack.o \
hcl.o labelcl.o invent.o sgi_io_sim.o \
klgraph_hack.o hcl_util.o cdl.o hubdev.o hubspc.o \
alenlist.o pci.o pci_dma.o ate_utils.o \
ifconfig_net.o io.o ifconfig_bus.o
ifconfig_net.o io.o ioconfig_bus.o
obj-$(CONFIG_PCIBA) += pciba.o
/* $Id$
*
* 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.
*
* ioconfig_bus - SGI's Persistent PCI Bus Numbering.
*
* Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
*/
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/sn/sgi.h>
#include <linux/devfs_fs.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/io.h>
#include <asm/sn/iograph.h>
#include <asm/sn/invent.h>
#include <asm/sn/hcl.h>
#include <asm/sn/labelcl.h>
#include <asm//sn/sn_sal.h>
#include <asm/sn/addrs.h>
#include <asm/sn/ioconfig_bus.h>
#define SGI_IOCONFIG_BUS "SGI-PERSISTENT PCI BUS NUMBERING"
#define SGI_IOCONFIG_BUS_VERSION "1.0"
/*
* Some Global definitions.
*/
devfs_handle_t ioconfig_bus_handle = NULL;
unsigned long ioconfig_bus_debug = 0;
#ifdef IOCONFIG_BUS_DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
u64 ioconfig_file = 0;
u64 ioconfig_file_size = 0;
u64 ioconfig_activated = 0;
char ioconfig_kernopts[128];
/*
* For debugging purpose .. hardcode a table ..
*/
struct ascii_moduleid *ioconfig_bus_table;
u64 ioconfig_bus_table_size = 0;
int free_entry = 0;
int new_entry = 0;
int next_basebus_number = 0;
void
ioconfig_get_busnum(char *io_moduleid, int *bus_num)
{
struct ascii_moduleid *temp;
int index;
DBG("ioconfig_get_busnum io_moduleid %s\n", io_moduleid);
*bus_num = -1;
temp = ioconfig_bus_table;
for (index = 0; index < free_entry; temp++, index++) {
if ( (io_moduleid[0] == temp->io_moduleid[0]) &&
(io_moduleid[1] == temp->io_moduleid[1]) &&
(io_moduleid[2] == temp->io_moduleid[2]) &&
(io_moduleid[4] == temp->io_moduleid[4]) &&
(io_moduleid[5] == temp->io_moduleid[5]) ) {
*bus_num = index * 0x10;
return;
}
}
/*
* New IO Brick encountered.
*/
if (((int)io_moduleid[0]) == 0) {
DBG("ioconfig_get_busnum: Invalid Module Id given %s\n", io_moduleid);
return;
}
io_moduleid[3] = '#';
strcpy((char *)&(ioconfig_bus_table[free_entry].io_moduleid), io_moduleid);
*bus_num = free_entry * 0x10;
free_entry++;
}
void
dump_ioconfig_table()
{
int index = 0;
struct ascii_moduleid *temp;
temp = ioconfig_bus_table;
while (index < free_entry) {
DBG("ASSCI Module ID %s\n", temp->io_moduleid);
temp++;
index++;
}
}
/*
* nextline
* This routine returns the nextline in the buffer.
*/
int nextline(char *buffer, char **next, char *line)
{
char *temp;
if (buffer[0] == 0x0) {
return(0);
}
temp = buffer;
while (*temp != 0) {
*line = *temp;
if (*temp != '\n'){
*line = *temp;
temp++; line++;
} else
break;
}
if (*temp == 0)
*next = temp;
else
*next = ++temp;
return(1);
}
/*
* build_pcibus_name
* This routine parses the ioconfig contents read into
* memory by ioconfig command in EFI and builds the
* persistent pci bus naming table.
*/
void
build_moduleid_table(char *file_contents, struct ascii_moduleid *table)
{
/*
* Read the whole file into memory.
*/
int rc;
char *name;
char *temp;
char *next;
char *current;
char *line;
struct ascii_moduleid *moduleid;
line = kmalloc(256, GFP_KERNEL);
memset(line, 0,256);
name = kmalloc(125, GFP_KERNEL);
memset(name, 0, 125);
moduleid = table;
current = file_contents;
while (nextline(current, &next, line)){
DBG("current 0x%lx next 0x%lx\n", current, next);
temp = line;
/*
* Skip all leading Blank lines ..
*/
while (isspace(*temp))
if (*temp != '\n')
temp++;
else
break;
if (*temp == '\n') {
current = next;
memset(line, 0, 256);
continue;
}
/*
* Skip comment lines
*/
if (*temp == '#') {
current = next;
memset(line, 0, 256);
continue;
}
/*
* Get the next free entry in the table.
*/
rc = sscanf(temp, "%s", name);
strcpy(&moduleid->io_moduleid[0], name);
DBG("Found %s\n", name);
moduleid++;
free_entry++;
current = next;
memset(line, 0, 256);
}
new_entry = free_entry;
kfree(line);
kfree(name);
return;
}
void
ioconfig_bus_init(void)
{
struct ia64_sal_retval ret_stuff;
u64 *temp;
int cnode;
DBG("ioconfig_bus_init called.\n");
for (cnode = 0; cnode < numnodes; cnode++) {
nasid_t nasid;
/*
* Make SAL call to get the address of the bus configuration table.
*/
ret_stuff.status = (uint64_t)0;
ret_stuff.v0 = (uint64_t)0;
ret_stuff.v1 = (uint64_t)0;
ret_stuff.v2 = (uint64_t)0;
nasid = COMPACT_TO_NASID_NODEID(cnode);
SAL_CALL(ret_stuff, SN_SAL_BUS_CONFIG, 0, nasid, 0, 0, 0, 0, 0);
temp = (u64 *)TO_NODE_CAC(nasid, ret_stuff.v0);
ioconfig_file = *temp;
DBG("ioconfig_bus_init: Nasid %d ret_stuff.v0 0x%lx\n", nasid,
ret_stuff.v0);
if (ioconfig_file) {
ioconfig_file_size = ret_stuff.v1;
ioconfig_file = (ioconfig_file | CACHEABLE_MEM_SPACE);
ioconfig_activated = 1;
break;
}
}
DBG("ioconfig_bus_init: ret_stuff.v0 %p ioconfig_file %p %d\n",
ret_stuff.v0, (void *)ioconfig_file, (int)ioconfig_file_size);
ioconfig_bus_table = kmalloc( 512, GFP_KERNEL );
memset(ioconfig_bus_table, 0, 512);
/*
* If ioconfig options are given on the bootline .. take it.
*/
if (*ioconfig_kernopts != '\0') {
/*
* ioconfig="..." kernel options given.
*/
DBG("ioconfig_bus_init: Kernel Options given.\n");
(void) build_moduleid_table((char *)ioconfig_kernopts, ioconfig_bus_table);
(void) dump_ioconfig_table(ioconfig_bus_table);
return;
}
if (ioconfig_activated) {
DBG("ioconfig_bus_init: ioconfig file given.\n");
(void) build_moduleid_table((char *)ioconfig_file, ioconfig_bus_table);
(void) dump_ioconfig_table(ioconfig_bus_table);
} else {
DBG("ioconfig_bus_init: ioconfig command not executed in prom\n");
}
}
void
ioconfig_bus_new_entries(void)
{
int index = 0;
struct ascii_moduleid *temp;
if ((ioconfig_activated) && (free_entry > new_entry)) {
printk("### Please add the following new IO Bricks Module ID \n");
printk("### to your Persistent Bus Numbering Config File\n");
} else
return;
index = new_entry;
temp = &ioconfig_bus_table[index];
while (index < free_entry) {
printk("%s\n", temp);
temp++;
index++;
}
printk("### End\n");
}
static int ioconfig_bus_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct ioconfig_parm parm;
/*
* Copy in the parameters.
*/
copy_from_user(&parm, (char *)arg, sizeof(struct ioconfig_parm));
parm.number = free_entry - new_entry;
parm.ioconfig_activated = ioconfig_activated;
copy_to_user((char *)arg, &parm, sizeof(struct ioconfig_parm));
copy_to_user((char *)parm.buffer, &ioconfig_bus_table[new_entry], sizeof(struct ascii_moduleid) * (free_entry - new_entry));
return 0;
}
/*
* ioconfig_bus_open - Opens the special device node "/dev/hw/.ioconfig_bus".
*/
static int ioconfig_bus_open(struct inode * inode, struct file * filp)
{
if (ioconfig_bus_debug) {
DBG("ioconfig_bus_open called.\n");
}
return(0);
}
/*
* ioconfig_bus_close - Closes the special device node "/dev/hw/.ioconfig_bus".
*/
static int ioconfig_bus_close(struct inode * inode, struct file * filp)
{
if (ioconfig_bus_debug) {
DBG("ioconfig_bus_close called.\n");
}
return(0);
}
struct file_operations ioconfig_bus_fops = {
ioctl:ioconfig_bus_ioctl,
open:ioconfig_bus_open, /* open */
release:ioconfig_bus_close /* release */
};
/*
* init_ifconfig_bus() - Boot time initialization. Ensure that it is called
* after devfs has been initialized.
*
*/
int init_ioconfig_bus(void)
{
ioconfig_bus_handle = NULL;
ioconfig_bus_handle = hwgraph_register(hwgraph_root, ".ioconfig_bus",
0, DEVFS_FL_AUTO_DEVNUM,
0, 0,
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
&ioconfig_bus_fops, NULL);
if (ioconfig_bus_handle == NULL) {
panic("Unable to create SGI PERSISTENT BUS NUMBERING Driver.\n");
}
return(0);
}
static int __init ioconfig_bus_setup (char *str)
{
char *temp;
DBG("ioconfig_bus_setup: Kernel Options %s\n", str);
temp = (char *)ioconfig_kernopts;
memset(temp, 0, 128);
while ( (*str != '\0') && !isspace (*str) ) {
if (*str == ',') {
*temp = '\n';
temp++;
str++;
continue;
}
*temp = *str;
temp++;
str++;
}
return(0);
}
__setup("ioconfig=", ioconfig_bus_setup);
#
# 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) 2002-2003 Silicon Graphics, Inc. All Rights Reserved.
#
# Makefile for the sn2 specific io routines.
EXTRA_CFLAGS := -DLITTLE_ENDIAN
obj-y += bte_error.o geo_op.o klconflib.o klgraph.o l1.o \
l1_command.o ml_iograph.o ml_SN_init.o ml_SN_intr.o module.o \
pci_bus_cvlink.o pciio.o pic.o sgi_io_init.o shub.o shuberror.o \
shub_intr.o shubio.o xbow.o xtalk.o
obj-$(CONFIG_KDB) += kdba_io.o
obj-$(CONFIG_SHUB_1_0_SPECIFIC) += efi-rtc.o
/* $Id$
*
* 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) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
*/
/*
* @doc file m:hwcfg
* DESCRIPTION:
*
* This file contains routines for manipulating and generating
* Geographic IDs. They are in a file by themself since they have
* no dependencies on other modules.
*
* ORIGIN:
*
* New for SN2
*/
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <asm/smp.h>
#include <asm/irq.h>
#include <asm/hw_irq.h>
#include <asm/sn/types.h>
#include <asm/sn/sgi.h>
#include <asm/sn/iograph.h>
#include <asm/sn/invent.h>
#include <asm/sn/hcl.h>
#include <asm/sn/labelcl.h>
#include <asm/sn/io.h>
#include <asm/sn/sn_private.h>
#include <asm/sn/klconfig.h>
#include <asm/sn/sn_cpuid.h>
#include <asm/sn/pci/pciio.h>
#include <asm/sn/pci/pcibr.h>
#include <asm/sn/xtalk/xtalk.h>
#include <asm/sn/pci/pcibr_private.h>
#include <asm/sn/intr.h>
#include <asm/sn/sn2/shub_mmr_t.h>
#include <asm/sn/sn2/shubio.h>
#include <asm/sal.h>
#include <asm/sn/sn_sal.h>
#include <asm/sn/module.h>
#include <asm/sn/geo.h>
/********** Global functions and data (visible outside the module) ***********/
/*
* @doc gf:geo_module
*
* moduleid_t geo_module(geoid_t g)
*
* DESCRIPTION:
*
* Return the moduleid component of a geoid.
*
* INTERNALS:
*
* Return INVALID_MODULE for an invalid geoid. Otherwise extract the
* moduleid from the structure, and return it.
*
* ORIGIN:
*
* New for SN2
*/
moduleid_t
geo_module(geoid_t g)
{
if (g.any.type == GEO_TYPE_INVALID)
return INVALID_MODULE;
else
return g.any.module;
}
/*
* @doc gf:geo_slab
*
* slabid_t geo_slab(geoid_t g)
*
* DESCRIPTION:
*
* Return the slabid component of a geoid.
*
* INTERNALS:
*
* Return INVALID_SLAB for an invalid geoid. Otherwise extract the
* slabid from the structure, and return it.
*
* ORIGIN:
*
* New for SN2
*/
slabid_t
geo_slab(geoid_t g)
{
if (g.any.type == GEO_TYPE_INVALID)
return INVALID_SLAB;
else
return g.any.slab;
}
/*
* @doc gf:geo_type
*
* geo_type_t geo_type(geoid_t g)
*
* DESCRIPTION:
*
* Return the type component of a geoid.
*
* INTERNALS:
*
* Extract the type from the structure, and return it.
*
* ORIGIN:
*
* New for SN2
*/
geo_type_t
geo_type(geoid_t g)
{
return g.any.type;
}
/*
* @doc gf:geo_valid
*
* int geo_valid(geoid_t g)
*
* DESCRIPTION:
*
* Return nonzero if g has a valid geoid type.
*
* INTERNALS:
*
* Test the type against GEO_TYPE_INVALID, and return the result.
*
* ORIGIN:
*
* New for SN2
*/
int
geo_valid(geoid_t g)
{
return g.any.type != GEO_TYPE_INVALID;
}
/*
* @doc gf:geo_cmp
*
* int geo_cmp(geoid_t g0, geoid_t g1)
*
* DESCRIPTION:
*
* Compare two geoid_t values, from the coarsest field to the finest.
* The comparison should be consistent with the physical locations of
* of the hardware named by the geoids.
*
* INTERNALS:
*
* First compare the module, then the slab, type, and type-specific fields.
*
* ORIGIN:
*
* New for SN2
*/
int
geo_cmp(geoid_t g0, geoid_t g1)
{
int rv;
/* Compare the common fields */
rv = MODULE_CMP(geo_module(g0), geo_module(g1));
if (rv != 0)
return rv;
rv = geo_slab(g0) - geo_slab(g1);
if (rv != 0)
return rv;
/* Within a slab, sort by type */
rv = geo_type(g0) - geo_type(g1);
if (rv != 0)
return rv;
switch(geo_type(g0)) {
case GEO_TYPE_CPU:
rv = g0.cpu.slice - g1.cpu.slice;
break;
case GEO_TYPE_IOCARD:
rv = g0.pcicard.bus - g1.pcicard.bus;
if (rv) break;
rv = SLOTNUM_GETSLOT(g0.pcicard.slot) -
SLOTNUM_GETSLOT(g1.pcicard.slot);
break;
case GEO_TYPE_MEM:
rv = g0.mem.membus - g1.mem.membus;
if (rv) break;
rv = g0.mem.memslot - g1.mem.memslot;
break;
default:
rv = 0;
}
return rv;
}
/*
* @doc gf:geo_new
*
* geoid_t geo_new(geo_type_t type, ...)
*
* DESCRIPTION:
*
* Generate a new geoid_t value of the given type from its components.
* Expected calling sequences:
* \@itemize \@bullet
* \@item
* \@code\{geo_new(GEO_TYPE_INVALID)\}
* \@item
* \@code\{geo_new(GEO_TYPE_MODULE, moduleid_t m)\}
* \@item
* \@code\{geo_new(GEO_TYPE_NODE, moduleid_t m, slabid_t s)\}
* \@item
* \@code\{geo_new(GEO_TYPE_RTR, moduleid_t m, slabid_t s)\}
* \@item
* \@code\{geo_new(GEO_TYPE_IOCNTL, moduleid_t m, slabid_t s)\}
* \@item
* \@code\{geo_new(GEO_TYPE_IOCARD, moduleid_t m, slabid_t s, char bus, slotid_t slot)\}
* \@item
* \@code\{geo_new(GEO_TYPE_CPU, moduleid_t m, slabid_t s, char slice)\}
* \@item
* \@code\{geo_new(GEO_TYPE_MEM, moduleid_t m, slabid_t s, char membus, char slot)\}
* \@end itemize
*
* Invalid types return a GEO_TYPE_INVALID geoid_t.
*
* INTERNALS:
*
* Use the type to determine which fields to expect. Write the fields into
* a new geoid_t and return it. Note: scalars smaller than an "int" are
* promoted to "int" by the "..." operator, so we need extra casts on "char",
* "slotid_t", and "slabid_t".
*
* ORIGIN:
*
* New for SN2
*/
geoid_t
geo_new(geo_type_t type, ...)
{
va_list al;
geoid_t g;
memset(&g, 0, sizeof(g));
va_start(al, type);
/* Make sure the type is sane */
if (type >= GEO_TYPE_MAX)
type = GEO_TYPE_INVALID;
g.any.type = type;
if (type == GEO_TYPE_INVALID)
goto done; /* invalid geoids have no components at all */
g.any.module = va_arg(al, moduleid_t);
if (type == GEO_TYPE_MODULE)
goto done;
g.any.slab = (slabid_t)va_arg(al, int);
/* Some types have additional components */
switch(type) {
case GEO_TYPE_CPU:
g.cpu.slice = (char)va_arg(al, int);
break;
case GEO_TYPE_IOCARD:
g.pcicard.bus = (char)va_arg(al, int);
g.pcicard.slot = (slotid_t)va_arg(al, int);
break;
case GEO_TYPE_MEM:
g.mem.membus = (char)va_arg(al, int);
g.mem.memslot = (char)va_arg(al, int);
break;
default:
break;
}
done:
va_end(al);
return g;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -267,7 +267,7 @@ sn_setup(char **cmdline_p)
/* PROM has wrong value on SN1 */
sn_rtc_cycles_per_second = 990177;
#endif
sn_rtc_usec_per_cyc = ((1000000UL<<IA64_USEC_PER_CYC_SHIFT)
sn_rtc_usec_per_cyc = ((1000000000UL<<IA64_NSEC_PER_CYC_SHIFT)
+ sn_rtc_cycles_per_second/2) / sn_rtc_cycles_per_second;
for (i=0;i<NR_CPUS;i++)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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