Merge master.kernel.org:/pub/scm/linux/kernel/git/willy/parisc-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/willy/parisc-2.6: (41 commits) [PARISC] Kill wall_jiffies use [PARISC] Honour "panic_on_oops" sysctl [PARISC] Fix fs/binfmt_som.c [PARISC] Export clear_user_page to modules [PARISC] Make DMA routines more stubby [PARISC] Define pci_get_legacy_ide_irq [PARISC] Fix CONFIG_DEBUG_SPINLOCK [PARISC] Fix HPUX compat compile with current GCC [PARISC] Fix iounmap compile warning [PARISC] Add support for Quicksilver AGPGART [PARISC] Move LBA and SBA register defines to the common ropes.h [PARISC] Create shared <asm/ropes.h> header [PARISC] Stash the lba_device in its struct device drvdata [PARISC] Generalize IS_ASTRO et al to take a parisc_device like [PARISC] Pretty print the name of the lba type on kernel boot [PARISC] Remove some obsolete comments and I checked that Reo is similar to Ike [PARISC] Add hardware found in the rp8400 [PARISC] Allow nested interrupts [PARISC] Further updates to timer_interrupt() [PARISC] remove halftick and copy clocktick to local var (gcc can optimize usage) ...
This commit is contained in:
commit
5a96c5d0c5
|
@ -127,7 +127,7 @@ config PA11
|
|||
|
||||
config PREFETCH
|
||||
def_bool y
|
||||
depends on PA8X00
|
||||
depends on PA8X00 || PA7200
|
||||
|
||||
config 64BIT
|
||||
bool "64-bit kernel"
|
||||
|
|
|
@ -96,7 +96,7 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
|
|||
put_user(namlen, &dirent->d_namlen);
|
||||
copy_to_user(dirent->d_name, name, namlen);
|
||||
put_user(0, dirent->d_name + namlen);
|
||||
((char *) dirent) += reclen;
|
||||
dirent = (void __user *)dirent + reclen;
|
||||
buf->current_dir = dirent;
|
||||
buf->count -= reclen;
|
||||
return 0;
|
||||
|
|
|
@ -87,7 +87,7 @@ struct elf_prpsinfo32
|
|||
*/
|
||||
|
||||
#define SET_PERSONALITY(ex, ibcs2) \
|
||||
current->personality = PER_LINUX32; \
|
||||
set_thread_flag(TIF_32BIT); \
|
||||
current->thread.map_base = DEFAULT_MAP_BASE32; \
|
||||
current->thread.task_size = DEFAULT_TASK_SIZE32 \
|
||||
|
||||
|
@ -102,25 +102,3 @@ cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
|
|||
}
|
||||
|
||||
#include "../../../fs/binfmt_elf.c"
|
||||
|
||||
/* Set up a separate execution domain for ELF32 binaries running
|
||||
* on an ELF64 kernel */
|
||||
|
||||
static struct exec_domain parisc32_exec_domain = {
|
||||
.name = "Linux/ELF32",
|
||||
.pers_low = PER_LINUX32,
|
||||
.pers_high = PER_LINUX32,
|
||||
};
|
||||
|
||||
static int __init parisc32_exec_init(void)
|
||||
{
|
||||
/* steal the identity signal mappings from the default domain */
|
||||
parisc32_exec_domain.signal_map = default_exec_domain.signal_map;
|
||||
parisc32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
|
||||
|
||||
register_exec_domain(&parisc32_exec_domain);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__initcall(parisc32_exec_init);
|
||||
|
|
|
@ -35,15 +35,12 @@ int icache_stride __read_mostly;
|
|||
EXPORT_SYMBOL(dcache_stride);
|
||||
|
||||
|
||||
#if defined(CONFIG_SMP)
|
||||
/* On some machines (e.g. ones with the Merced bus), there can be
|
||||
* only a single PxTLB broadcast at a time; this must be guaranteed
|
||||
* by software. We put a spinlock around all TLB flushes to
|
||||
* ensure this.
|
||||
*/
|
||||
DEFINE_SPINLOCK(pa_tlb_lock);
|
||||
EXPORT_SYMBOL(pa_tlb_lock);
|
||||
#endif
|
||||
|
||||
struct pdc_cache_info cache_info __read_mostly;
|
||||
#ifndef CONFIG_PA20
|
||||
|
@ -91,7 +88,8 @@ update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
|
|||
|
||||
flush_kernel_dcache_page(page);
|
||||
clear_bit(PG_dcache_dirty, &page->flags);
|
||||
}
|
||||
} else if (parisc_requires_coherency())
|
||||
flush_kernel_dcache_page(page);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -370,3 +368,45 @@ void parisc_setup_cache_timing(void)
|
|||
|
||||
printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus());
|
||||
}
|
||||
|
||||
extern void purge_kernel_dcache_page(unsigned long);
|
||||
extern void clear_user_page_asm(void *page, unsigned long vaddr);
|
||||
|
||||
void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
|
||||
{
|
||||
purge_kernel_dcache_page((unsigned long)page);
|
||||
purge_tlb_start();
|
||||
pdtlb_kernel(page);
|
||||
purge_tlb_end();
|
||||
clear_user_page_asm(page, vaddr);
|
||||
}
|
||||
EXPORT_SYMBOL(clear_user_page);
|
||||
|
||||
void flush_kernel_dcache_page_addr(void *addr)
|
||||
{
|
||||
flush_kernel_dcache_page_asm(addr);
|
||||
purge_tlb_start();
|
||||
pdtlb_kernel(addr);
|
||||
purge_tlb_end();
|
||||
}
|
||||
EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
|
||||
|
||||
void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
|
||||
struct page *pg)
|
||||
{
|
||||
/* no coherency needed (all in kmap/kunmap) */
|
||||
copy_user_page_asm(vto, vfrom);
|
||||
if (!parisc_requires_coherency())
|
||||
flush_kernel_dcache_page_asm(vto);
|
||||
}
|
||||
EXPORT_SYMBOL(copy_user_page);
|
||||
|
||||
#ifdef CONFIG_PA8X00
|
||||
|
||||
void kunmap_parisc(void *addr)
|
||||
{
|
||||
if (parisc_requires_coherency())
|
||||
flush_kernel_dcache_page_addr(addr);
|
||||
}
|
||||
EXPORT_SYMBOL(kunmap_parisc);
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
|
||||
#include <asm/psw.h>
|
||||
#include <asm/cache.h> /* for L1_CACHE_SHIFT */
|
||||
#include <asm/assembly.h> /* for LDREG/STREG defines */
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/signal.h>
|
||||
|
@ -478,11 +479,7 @@
|
|||
bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault
|
||||
DEP %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */
|
||||
copy \pmd,%r9
|
||||
#ifdef CONFIG_64BIT
|
||||
shld %r9,PxD_VALUE_SHIFT,\pmd
|
||||
#else
|
||||
shlw %r9,PxD_VALUE_SHIFT,\pmd
|
||||
#endif
|
||||
SHLREG %r9,PxD_VALUE_SHIFT,\pmd
|
||||
EXTR \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
|
||||
DEP %r0,31,PAGE_SHIFT,\pmd /* clear offset */
|
||||
shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd
|
||||
|
@ -970,11 +967,7 @@ intr_return:
|
|||
/* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount
|
||||
** irq_stat[] is defined using ____cacheline_aligned.
|
||||
*/
|
||||
#ifdef CONFIG_64BIT
|
||||
shld %r1, 6, %r20
|
||||
#else
|
||||
shlw %r1, 5, %r20
|
||||
#endif
|
||||
SHLREG %r1,L1_CACHE_SHIFT,%r20
|
||||
add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
|
@ -1076,7 +1069,7 @@ intr_do_preempt:
|
|||
BL preempt_schedule_irq, %r2
|
||||
nop
|
||||
|
||||
b intr_restore /* ssm PSW_SM_I done by intr_restore */
|
||||
b,n intr_restore /* ssm PSW_SM_I done by intr_restore */
|
||||
#endif /* CONFIG_PREEMPT */
|
||||
|
||||
.import do_signal,code
|
||||
|
@ -2115,11 +2108,7 @@ syscall_check_bh:
|
|||
ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */
|
||||
|
||||
/* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */
|
||||
#ifdef CONFIG_64BIT
|
||||
shld %r26, 6, %r20
|
||||
#else
|
||||
shlw %r26, 5, %r20
|
||||
#endif
|
||||
SHLREG %r26,L1_CACHE_SHIFT,%r20
|
||||
add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
|
|
|
@ -231,6 +231,7 @@ static struct hp_hardware hp_hardware_list[] __initdata = {
|
|||
{HPHW_NPROC,0x5E6,0x4,0x91,"Keystone/Matterhorn W2 650"},
|
||||
{HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"},
|
||||
{HPHW_NPROC,0x5E8,0x4,0x91,"Pikes Peak W2"},
|
||||
{HPHW_NPROC,0x5EB,0x4,0x91,"Perf/Leone 875 W2+"},
|
||||
{HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"},
|
||||
{HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"},
|
||||
{HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"},
|
||||
|
@ -584,8 +585,10 @@ static struct hp_hardware hp_hardware_list[] __initdata = {
|
|||
{HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"},
|
||||
{HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"},
|
||||
{HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"},
|
||||
{HPHW_FABRIC, 0x005, 0x000AA, 0x80, "Keystone DNA Central Agent"},
|
||||
{HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"},
|
||||
{HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"},
|
||||
{HPHW_FABRIC, 0x005, 0x000AB, 0x00, "Keystone TOGO Fabric Crossbar"},
|
||||
{HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"},
|
||||
{HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"},
|
||||
{HPHW_FIO, 0x004, 0x0004F, 0x0, "8-Port X.25 EISA-ACC (AMSO)"},
|
||||
|
|
|
@ -45,6 +45,17 @@ extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *);
|
|||
*/
|
||||
static volatile unsigned long cpu_eiem = 0;
|
||||
|
||||
/*
|
||||
** ack bitmap ... habitually set to 1, but reset to zero
|
||||
** between ->ack() and ->end() of the interrupt to prevent
|
||||
** re-interruption of a processing interrupt.
|
||||
*/
|
||||
static volatile unsigned long global_ack_eiem = ~0UL;
|
||||
/*
|
||||
** Local bitmap, same as above but for per-cpu interrupts
|
||||
*/
|
||||
static DEFINE_PER_CPU(unsigned long, local_ack_eiem) = ~0UL;
|
||||
|
||||
static void cpu_disable_irq(unsigned int irq)
|
||||
{
|
||||
unsigned long eirr_bit = EIEM_MASK(irq);
|
||||
|
@ -62,13 +73,6 @@ static void cpu_enable_irq(unsigned int irq)
|
|||
|
||||
cpu_eiem |= eirr_bit;
|
||||
|
||||
/* FIXME: while our interrupts aren't nested, we cannot reset
|
||||
* the eiem mask if we're already in an interrupt. Once we
|
||||
* implement nested interrupts, this can go away
|
||||
*/
|
||||
if (!in_interrupt())
|
||||
set_eiem(cpu_eiem);
|
||||
|
||||
/* This is just a simple NOP IPI. But what it does is cause
|
||||
* all the other CPUs to do a set_eiem(cpu_eiem) at the end
|
||||
* of the interrupt handler */
|
||||
|
@ -84,13 +88,45 @@ static unsigned int cpu_startup_irq(unsigned int irq)
|
|||
void no_ack_irq(unsigned int irq) { }
|
||||
void no_end_irq(unsigned int irq) { }
|
||||
|
||||
void cpu_ack_irq(unsigned int irq)
|
||||
{
|
||||
unsigned long mask = EIEM_MASK(irq);
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
/* Clear in EIEM so we can no longer process */
|
||||
if (CHECK_IRQ_PER_CPU(irq_desc[irq].status))
|
||||
per_cpu(local_ack_eiem, cpu) &= ~mask;
|
||||
else
|
||||
global_ack_eiem &= ~mask;
|
||||
|
||||
/* disable the interrupt */
|
||||
set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
|
||||
/* and now ack it */
|
||||
mtctl(mask, 23);
|
||||
}
|
||||
|
||||
void cpu_end_irq(unsigned int irq)
|
||||
{
|
||||
unsigned long mask = EIEM_MASK(irq);
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
/* set it in the eiems---it's no longer in process */
|
||||
if (CHECK_IRQ_PER_CPU(irq_desc[irq].status))
|
||||
per_cpu(local_ack_eiem, cpu) |= mask;
|
||||
else
|
||||
global_ack_eiem |= mask;
|
||||
|
||||
/* enable the interrupt */
|
||||
set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int cpu_check_affinity(unsigned int irq, cpumask_t *dest)
|
||||
{
|
||||
int cpu_dest;
|
||||
|
||||
/* timer and ipi have to always be received on all CPUs */
|
||||
if (irq == TIMER_IRQ || irq == IPI_IRQ) {
|
||||
if (CHECK_IRQ_PER_CPU(irq)) {
|
||||
/* Bad linux design decision. The mask has already
|
||||
* been set; we must reset it */
|
||||
irq_desc[irq].affinity = CPU_MASK_ALL;
|
||||
|
@ -119,8 +155,8 @@ static struct hw_interrupt_type cpu_interrupt_type = {
|
|||
.shutdown = cpu_disable_irq,
|
||||
.enable = cpu_enable_irq,
|
||||
.disable = cpu_disable_irq,
|
||||
.ack = no_ack_irq,
|
||||
.end = no_end_irq,
|
||||
.ack = cpu_ack_irq,
|
||||
.end = cpu_end_irq,
|
||||
#ifdef CONFIG_SMP
|
||||
.set_affinity = cpu_set_affinity_irq,
|
||||
#endif
|
||||
|
@ -209,7 +245,7 @@ int show_interrupts(struct seq_file *p, void *v)
|
|||
** Then use that to get the Transaction address and data.
|
||||
*/
|
||||
|
||||
int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *type, void *data)
|
||||
int cpu_claim_irq(unsigned int irq, struct irq_chip *type, void *data)
|
||||
{
|
||||
if (irq_desc[irq].action)
|
||||
return -EBUSY;
|
||||
|
@ -298,82 +334,69 @@ unsigned int txn_alloc_data(unsigned int virt_irq)
|
|||
return virt_irq - CPU_IRQ_BASE;
|
||||
}
|
||||
|
||||
static inline int eirr_to_irq(unsigned long eirr)
|
||||
{
|
||||
#ifdef CONFIG_64BIT
|
||||
int bit = fls64(eirr);
|
||||
#else
|
||||
int bit = fls(eirr);
|
||||
#endif
|
||||
return (BITS_PER_LONG - bit) + TIMER_IRQ;
|
||||
}
|
||||
|
||||
/* ONLY called from entry.S:intr_extint() */
|
||||
void do_cpu_irq_mask(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long eirr_val;
|
||||
int irq, cpu = smp_processor_id();
|
||||
#ifdef CONFIG_SMP
|
||||
cpumask_t dest;
|
||||
#endif
|
||||
|
||||
local_irq_disable();
|
||||
irq_enter();
|
||||
|
||||
/*
|
||||
* Don't allow TIMER or IPI nested interrupts.
|
||||
* Allowing any single interrupt to nest can lead to that CPU
|
||||
* handling interrupts with all enabled interrupts unmasked.
|
||||
*/
|
||||
set_eiem(0UL);
|
||||
|
||||
/* 1) only process IRQs that are enabled/unmasked (cpu_eiem)
|
||||
* 2) We loop here on EIRR contents in order to avoid
|
||||
* nested interrupts or having to take another interrupt
|
||||
* when we could have just handled it right away.
|
||||
*/
|
||||
for (;;) {
|
||||
unsigned long bit = (1UL << (BITS_PER_LONG - 1));
|
||||
unsigned int irq;
|
||||
eirr_val = mfctl(23) & cpu_eiem;
|
||||
if (!eirr_val)
|
||||
break;
|
||||
|
||||
mtctl(eirr_val, 23); /* reset bits we are going to process */
|
||||
|
||||
/* Work our way from MSb to LSb...same order we alloc EIRs */
|
||||
for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) {
|
||||
#ifdef CONFIG_SMP
|
||||
cpumask_t dest = irq_desc[irq].affinity;
|
||||
#endif
|
||||
if (!(bit & eirr_val))
|
||||
continue;
|
||||
|
||||
/* clear bit in mask - can exit loop sooner */
|
||||
eirr_val &= ~bit;
|
||||
eirr_val = mfctl(23) & cpu_eiem & global_ack_eiem &
|
||||
per_cpu(local_ack_eiem, cpu);
|
||||
if (!eirr_val)
|
||||
goto set_out;
|
||||
irq = eirr_to_irq(eirr_val);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* FIXME: because generic set affinity mucks
|
||||
* with the affinity before sending it to us
|
||||
* we can get the situation where the affinity is
|
||||
* wrong for our CPU type interrupts */
|
||||
if (irq != TIMER_IRQ && irq != IPI_IRQ &&
|
||||
!cpu_isset(smp_processor_id(), dest)) {
|
||||
int cpu = first_cpu(dest);
|
||||
dest = irq_desc[irq].affinity;
|
||||
if (CHECK_IRQ_PER_CPU(irq_desc[irq].status) &&
|
||||
!cpu_isset(smp_processor_id(), dest)) {
|
||||
int cpu = first_cpu(dest);
|
||||
|
||||
printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n",
|
||||
irq, smp_processor_id(), cpu);
|
||||
gsc_writel(irq + CPU_IRQ_BASE,
|
||||
cpu_data[cpu].hpa);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
__do_IRQ(irq, regs);
|
||||
}
|
||||
printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n",
|
||||
irq, smp_processor_id(), cpu);
|
||||
gsc_writel(irq + CPU_IRQ_BASE,
|
||||
cpu_data[cpu].hpa);
|
||||
goto set_out;
|
||||
}
|
||||
#endif
|
||||
__do_IRQ(irq, regs);
|
||||
|
||||
set_eiem(cpu_eiem); /* restore original mask */
|
||||
out:
|
||||
irq_exit();
|
||||
}
|
||||
return;
|
||||
|
||||
set_out:
|
||||
set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
|
||||
goto out;
|
||||
}
|
||||
|
||||
static struct irqaction timer_action = {
|
||||
.handler = timer_interrupt,
|
||||
.name = "timer",
|
||||
.flags = IRQF_DISABLED,
|
||||
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static struct irqaction ipi_action = {
|
||||
.handler = ipi_interrupt,
|
||||
.name = "IPI",
|
||||
.flags = IRQF_DISABLED,
|
||||
.flags = IRQF_DISABLED | IRQF_PERCPU,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
|
@ -143,8 +143,9 @@ static int __init processor_probe(struct parisc_device *dev)
|
|||
p = &cpu_data[cpuid];
|
||||
boot_cpu_data.cpu_count++;
|
||||
|
||||
/* initialize counters */
|
||||
memset(p, 0, sizeof(struct cpuinfo_parisc));
|
||||
/* initialize counters - CPU 0 gets it_value set in time_init() */
|
||||
if (cpuid)
|
||||
memset(p, 0, sizeof(struct cpuinfo_parisc));
|
||||
|
||||
p->loops_per_jiffy = loops_per_jiffy;
|
||||
p->dev = dev; /* Save IODC data in case we need it */
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <linux/stddef.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/personality.h>
|
||||
#include <asm/ucontext.h>
|
||||
#include <asm/rt_sigframe.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
@ -433,13 +432,13 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||
if (in_syscall) {
|
||||
regs->gr[31] = haddr;
|
||||
#ifdef __LP64__
|
||||
if (personality(current->personality) == PER_LINUX)
|
||||
if (!test_thread_flag(TIF_32BIT))
|
||||
sigframe_size |= 1;
|
||||
#endif
|
||||
} else {
|
||||
unsigned long psw = USER_PSW;
|
||||
#ifdef __LP64__
|
||||
if (personality(current->personality) == PER_LINUX)
|
||||
if (!test_thread_flag(TIF_32BIT))
|
||||
psw |= PSW_W;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -262,6 +262,9 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
|||
this_cpu, which);
|
||||
return IRQ_NONE;
|
||||
} /* Switch */
|
||||
/* let in any pending interrupts */
|
||||
local_irq_enable();
|
||||
local_irq_disable();
|
||||
} /* while (ops) */
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
|
@ -430,8 +433,9 @@ smp_do_timer(struct pt_regs *regs)
|
|||
static void __init
|
||||
smp_cpu_init(int cpunum)
|
||||
{
|
||||
extern int init_per_cpu(int); /* arch/parisc/kernel/setup.c */
|
||||
extern int init_per_cpu(int); /* arch/parisc/kernel/processor.c */
|
||||
extern void init_IRQ(void); /* arch/parisc/kernel/irq.c */
|
||||
extern void start_cpu_itimer(void); /* arch/parisc/kernel/time.c */
|
||||
|
||||
/* Set modes and Enable floating point coprocessor */
|
||||
(void) init_per_cpu(cpunum);
|
||||
|
@ -457,6 +461,7 @@ smp_cpu_init(int cpunum)
|
|||
enter_lazy_tlb(&init_mm, current);
|
||||
|
||||
init_IRQ(); /* make sure no IRQ's are enabled or pending */
|
||||
start_cpu_itimer();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include <linux/shm.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/personality.h>
|
||||
|
||||
int sys_pipe(int __user *fildes)
|
||||
{
|
||||
|
@ -248,3 +250,46 @@ asmlinkage int sys_free_hugepages(unsigned long addr)
|
|||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
long parisc_personality(unsigned long personality)
|
||||
{
|
||||
long err;
|
||||
|
||||
if (personality(current->personality) == PER_LINUX32
|
||||
&& personality == PER_LINUX)
|
||||
personality = PER_LINUX32;
|
||||
|
||||
err = sys_personality(personality);
|
||||
if (err == PER_LINUX32)
|
||||
err = PER_LINUX;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int override_machine(char __user *mach) {
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (personality(current->personality) == PER_LINUX32) {
|
||||
if (__put_user(0, mach + 6) ||
|
||||
__put_user(0, mach + 7))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else /*!CONFIG_COMPAT*/
|
||||
return 0;
|
||||
#endif /*CONFIG_COMPAT*/
|
||||
}
|
||||
|
||||
long parisc_newuname(struct new_utsname __user *utsname)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
down_read(&uts_sem);
|
||||
if (copy_to_user(utsname, &system_utsname, sizeof(*utsname)))
|
||||
err = -EFAULT;
|
||||
up_read(&uts_sem);
|
||||
|
||||
err = override_machine(utsname->machine);
|
||||
|
||||
return (long)err;
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@
|
|||
ENTRY_SAME(socketpair)
|
||||
ENTRY_SAME(setpgid)
|
||||
ENTRY_SAME(send)
|
||||
ENTRY_SAME(newuname)
|
||||
ENTRY_OURS(newuname)
|
||||
ENTRY_SAME(umask) /* 60 */
|
||||
ENTRY_SAME(chroot)
|
||||
ENTRY_SAME(ustat)
|
||||
|
@ -221,7 +221,7 @@
|
|||
ENTRY_SAME(fchdir)
|
||||
ENTRY_SAME(bdflush)
|
||||
ENTRY_SAME(sysfs) /* 135 */
|
||||
ENTRY_SAME(personality)
|
||||
ENTRY_OURS(personality)
|
||||
ENTRY_SAME(ni_syscall) /* for afs_syscall */
|
||||
ENTRY_SAME(setfsuid)
|
||||
ENTRY_SAME(setfsgid)
|
||||
|
|
|
@ -32,8 +32,7 @@
|
|||
|
||||
#include <linux/timex.h>
|
||||
|
||||
static long clocktick __read_mostly; /* timer cycles per tick */
|
||||
static long halftick __read_mostly;
|
||||
static unsigned long clocktick __read_mostly; /* timer cycles per tick */
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
extern void smp_do_timer(struct pt_regs *regs);
|
||||
|
@ -41,46 +40,106 @@ extern void smp_do_timer(struct pt_regs *regs);
|
|||
|
||||
irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
long now;
|
||||
long next_tick;
|
||||
int nticks;
|
||||
int cpu = smp_processor_id();
|
||||
unsigned long now;
|
||||
unsigned long next_tick;
|
||||
unsigned long cycles_elapsed;
|
||||
unsigned long cycles_remainder;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
|
||||
/* gcc can optimize for "read-only" case with a local clocktick */
|
||||
unsigned long cpt = clocktick;
|
||||
|
||||
profile_tick(CPU_PROFILING, regs);
|
||||
|
||||
now = mfctl(16);
|
||||
/* initialize next_tick to time at last clocktick */
|
||||
/* Initialize next_tick to the expected tick time. */
|
||||
next_tick = cpu_data[cpu].it_value;
|
||||
|
||||
/* since time passes between the interrupt and the mfctl()
|
||||
* above, it is never true that last_tick + clocktick == now. If we
|
||||
* never miss a clocktick, we could set next_tick = last_tick + clocktick
|
||||
* but maybe we'll miss ticks, hence the loop.
|
||||
*
|
||||
* Variables are *signed*.
|
||||
/* Get current interval timer.
|
||||
* CR16 reads as 64 bits in CPU wide mode.
|
||||
* CR16 reads as 32 bits in CPU narrow mode.
|
||||
*/
|
||||
now = mfctl(16);
|
||||
|
||||
nticks = 0;
|
||||
while((next_tick - now) < halftick) {
|
||||
next_tick += clocktick;
|
||||
nticks++;
|
||||
cycles_elapsed = now - next_tick;
|
||||
|
||||
if ((cycles_elapsed >> 5) < cpt) {
|
||||
/* use "cheap" math (add/subtract) instead
|
||||
* of the more expensive div/mul method
|
||||
*/
|
||||
cycles_remainder = cycles_elapsed;
|
||||
while (cycles_remainder > cpt) {
|
||||
cycles_remainder -= cpt;
|
||||
}
|
||||
} else {
|
||||
cycles_remainder = cycles_elapsed % cpt;
|
||||
}
|
||||
mtctl(next_tick, 16);
|
||||
|
||||
/* Can we differentiate between "early CR16" (aka Scenario 1) and
|
||||
* "long delay" (aka Scenario 3)? I don't think so.
|
||||
*
|
||||
* We expected timer_interrupt to be delivered at least a few hundred
|
||||
* cycles after the IT fires. But it's arbitrary how much time passes
|
||||
* before we call it "late". I've picked one second.
|
||||
*/
|
||||
/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */
|
||||
#if HZ == 1000
|
||||
if (cycles_elapsed > (cpt << 10) )
|
||||
#elif HZ == 250
|
||||
if (cycles_elapsed > (cpt << 8) )
|
||||
#elif HZ == 100
|
||||
if (cycles_elapsed > (cpt << 7) )
|
||||
#else
|
||||
#warn WTF is HZ set to anyway?
|
||||
if (cycles_elapsed > (HZ * cpt) )
|
||||
#endif
|
||||
{
|
||||
/* Scenario 3: very long delay? bad in any case */
|
||||
printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!"
|
||||
" cycles %lX rem %lX "
|
||||
" next/now %lX/%lX\n",
|
||||
cpu,
|
||||
cycles_elapsed, cycles_remainder,
|
||||
next_tick, now );
|
||||
}
|
||||
|
||||
/* convert from "division remainder" to "remainder of clock tick" */
|
||||
cycles_remainder = cpt - cycles_remainder;
|
||||
|
||||
/* Determine when (in CR16 cycles) next IT interrupt will fire.
|
||||
* We want IT to fire modulo clocktick even if we miss/skip some.
|
||||
* But those interrupts don't in fact get delivered that regularly.
|
||||
*/
|
||||
next_tick = now + cycles_remainder;
|
||||
|
||||
cpu_data[cpu].it_value = next_tick;
|
||||
|
||||
while (nticks--) {
|
||||
/* Skip one clocktick on purpose if we are likely to miss next_tick.
|
||||
* We want to avoid the new next_tick being less than CR16.
|
||||
* If that happened, itimer wouldn't fire until CR16 wrapped.
|
||||
* We'll catch the tick we missed on the tick after that.
|
||||
*/
|
||||
if (!(cycles_remainder >> 13))
|
||||
next_tick += cpt;
|
||||
|
||||
/* Program the IT when to deliver the next interrupt. */
|
||||
/* Only bottom 32-bits of next_tick are written to cr16. */
|
||||
mtctl(next_tick, 16);
|
||||
|
||||
|
||||
/* Done mucking with unreliable delivery of interrupts.
|
||||
* Go do system house keeping.
|
||||
*/
|
||||
#ifdef CONFIG_SMP
|
||||
smp_do_timer(regs);
|
||||
smp_do_timer(regs);
|
||||
#else
|
||||
update_process_times(user_mode(regs));
|
||||
update_process_times(user_mode(regs));
|
||||
#endif
|
||||
if (cpu == 0) {
|
||||
write_seqlock(&xtime_lock);
|
||||
do_timer(1);
|
||||
write_sequnlock(&xtime_lock);
|
||||
}
|
||||
if (cpu == 0) {
|
||||
write_seqlock(&xtime_lock);
|
||||
do_timer(regs);
|
||||
write_sequnlock(&xtime_lock);
|
||||
}
|
||||
|
||||
|
||||
/* check soft power switch status */
|
||||
if (cpu == 0 && !atomic_read(&power_tasklet.count))
|
||||
tasklet_schedule(&power_tasklet);
|
||||
|
@ -106,14 +165,12 @@ unsigned long profile_pc(struct pt_regs *regs)
|
|||
EXPORT_SYMBOL(profile_pc);
|
||||
|
||||
|
||||
/*** converted from ia64 ***/
|
||||
/*
|
||||
* Return the number of micro-seconds that elapsed since the last
|
||||
* update to wall time (aka xtime). The xtime_lock
|
||||
* must be at least read-locked when calling this routine.
|
||||
*/
|
||||
static inline unsigned long
|
||||
gettimeoffset (void)
|
||||
static inline unsigned long gettimeoffset (void)
|
||||
{
|
||||
#ifndef CONFIG_SMP
|
||||
/*
|
||||
|
@ -121,21 +178,44 @@ gettimeoffset (void)
|
|||
* Once parisc-linux learns the cr16 difference between processors,
|
||||
* this could be made to work.
|
||||
*/
|
||||
long last_tick;
|
||||
long elapsed_cycles;
|
||||
unsigned long now;
|
||||
unsigned long prev_tick;
|
||||
unsigned long next_tick;
|
||||
unsigned long elapsed_cycles;
|
||||
unsigned long usec;
|
||||
unsigned long cpuid = smp_processor_id();
|
||||
unsigned long cpt = clocktick;
|
||||
|
||||
/* it_value is the intended time of the next tick */
|
||||
last_tick = cpu_data[smp_processor_id()].it_value;
|
||||
next_tick = cpu_data[cpuid].it_value;
|
||||
now = mfctl(16); /* Read the hardware interval timer. */
|
||||
|
||||
/* Subtract one tick and account for possible difference between
|
||||
* when we expected the tick and when it actually arrived.
|
||||
* (aka wall vs real)
|
||||
*/
|
||||
last_tick -= clocktick * (jiffies - wall_jiffies + 1);
|
||||
elapsed_cycles = mfctl(16) - last_tick;
|
||||
prev_tick = next_tick - cpt;
|
||||
|
||||
/* the precision of this math could be improved */
|
||||
return elapsed_cycles / (PAGE0->mem_10msec / 10000);
|
||||
/* Assume Scenario 1: "now" is later than prev_tick. */
|
||||
elapsed_cycles = now - prev_tick;
|
||||
|
||||
/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */
|
||||
#if HZ == 1000
|
||||
if (elapsed_cycles > (cpt << 10) )
|
||||
#elif HZ == 250
|
||||
if (elapsed_cycles > (cpt << 8) )
|
||||
#elif HZ == 100
|
||||
if (elapsed_cycles > (cpt << 7) )
|
||||
#else
|
||||
#warn WTF is HZ set to anyway?
|
||||
if (elapsed_cycles > (HZ * cpt) )
|
||||
#endif
|
||||
{
|
||||
/* Scenario 3: clock ticks are missing. */
|
||||
printk (KERN_CRIT "gettimeoffset(CPU %ld): missing %ld ticks!"
|
||||
" cycles %lX prev/now/next %lX/%lX/%lX clock %lX\n",
|
||||
cpuid, elapsed_cycles / cpt,
|
||||
elapsed_cycles, prev_tick, now, next_tick, cpt);
|
||||
}
|
||||
|
||||
/* FIXME: Can we improve the precision? Not with PAGE0. */
|
||||
usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec;
|
||||
return usec;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
@ -146,6 +226,7 @@ do_gettimeofday (struct timeval *tv)
|
|||
{
|
||||
unsigned long flags, seq, usec, sec;
|
||||
|
||||
/* Hold xtime_lock and adjust timeval. */
|
||||
do {
|
||||
seq = read_seqbegin_irqsave(&xtime_lock, flags);
|
||||
usec = gettimeoffset();
|
||||
|
@ -153,25 +234,13 @@ do_gettimeofday (struct timeval *tv)
|
|||
usec += (xtime.tv_nsec / 1000);
|
||||
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
|
||||
|
||||
if (unlikely(usec > LONG_MAX)) {
|
||||
/* This can happen if the gettimeoffset adjustment is
|
||||
* negative and xtime.tv_nsec is smaller than the
|
||||
* adjustment */
|
||||
printk(KERN_ERR "do_gettimeofday() spurious xtime.tv_nsec of %ld\n", usec);
|
||||
usec += USEC_PER_SEC;
|
||||
--sec;
|
||||
/* This should never happen, it means the negative
|
||||
* time adjustment was more than a second, so there's
|
||||
* something seriously wrong */
|
||||
BUG_ON(usec > LONG_MAX);
|
||||
}
|
||||
|
||||
|
||||
/* Move adjusted usec's into sec's. */
|
||||
while (usec >= USEC_PER_SEC) {
|
||||
usec -= USEC_PER_SEC;
|
||||
++sec;
|
||||
}
|
||||
|
||||
/* Return adjusted result. */
|
||||
tv->tv_sec = sec;
|
||||
tv->tv_usec = usec;
|
||||
}
|
||||
|
@ -223,22 +292,23 @@ unsigned long long sched_clock(void)
|
|||
}
|
||||
|
||||
|
||||
void __init start_cpu_itimer(void)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
unsigned long next_tick = mfctl(16) + clocktick;
|
||||
|
||||
mtctl(next_tick, 16); /* kick off Interval Timer (CR16) */
|
||||
|
||||
cpu_data[cpu].it_value = next_tick;
|
||||
}
|
||||
|
||||
void __init time_init(void)
|
||||
{
|
||||
unsigned long next_tick;
|
||||
static struct pdc_tod tod_data;
|
||||
|
||||
clocktick = (100 * PAGE0->mem_10msec) / HZ;
|
||||
halftick = clocktick / 2;
|
||||
|
||||
/* Setup clock interrupt timing */
|
||||
|
||||
next_tick = mfctl(16);
|
||||
next_tick += clocktick;
|
||||
cpu_data[smp_processor_id()].it_value = next_tick;
|
||||
|
||||
/* kick off Itimer (CR16) */
|
||||
mtctl(next_tick, 16);
|
||||
start_cpu_itimer(); /* get CPU 0 started */
|
||||
|
||||
if(pdc_tod_read(&tod_data) == 0) {
|
||||
write_seqlock_irq(&xtime_lock);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/smp.h>
|
||||
|
@ -245,6 +246,15 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
|
|||
current->comm, current->pid, str, err);
|
||||
show_regs(regs);
|
||||
|
||||
if (in_interrupt())
|
||||
panic("Fatal exception in interrupt");
|
||||
|
||||
if (panic_on_oops) {
|
||||
printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
|
||||
ssleep(5);
|
||||
panic("Fatal exception");
|
||||
}
|
||||
|
||||
/* Wot's wrong wif bein' racy? */
|
||||
if (current->thread.flags & PARISC_KERNEL_DEATH) {
|
||||
printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__);
|
||||
|
|
|
@ -31,10 +31,7 @@
|
|||
|
||||
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
|
||||
|
||||
extern char _text; /* start of kernel code, defined by linker */
|
||||
extern int data_start;
|
||||
extern char _end; /* end of BSS, defined by linker */
|
||||
extern char __init_begin, __init_end;
|
||||
|
||||
#ifdef CONFIG_DISCONTIGMEM
|
||||
struct node_map_data node_data[MAX_NUMNODES] __read_mostly;
|
||||
|
@ -319,8 +316,8 @@ static void __init setup_bootmem(void)
|
|||
|
||||
reserve_bootmem_node(NODE_DATA(0), 0UL,
|
||||
(unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE));
|
||||
reserve_bootmem_node(NODE_DATA(0),__pa((unsigned long)&_text),
|
||||
(unsigned long)(&_end - &_text));
|
||||
reserve_bootmem_node(NODE_DATA(0), __pa((unsigned long)_text),
|
||||
(unsigned long)(_end - _text));
|
||||
reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT),
|
||||
((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT));
|
||||
|
||||
|
@ -355,8 +352,8 @@ static void __init setup_bootmem(void)
|
|||
#endif
|
||||
|
||||
data_resource.start = virt_to_phys(&data_start);
|
||||
data_resource.end = virt_to_phys(&_end)-1;
|
||||
code_resource.start = virt_to_phys(&_text);
|
||||
data_resource.end = virt_to_phys(_end) - 1;
|
||||
code_resource.start = virt_to_phys(_text);
|
||||
code_resource.end = virt_to_phys(&data_start)-1;
|
||||
|
||||
/* We don't know which region the kernel will be in, so try
|
||||
|
@ -385,12 +382,12 @@ void free_initmem(void)
|
|||
*/
|
||||
local_irq_disable();
|
||||
|
||||
memset(&__init_begin, 0x00,
|
||||
(unsigned long)&__init_end - (unsigned long)&__init_begin);
|
||||
memset(__init_begin, 0x00,
|
||||
(unsigned long)__init_end - (unsigned long)__init_begin);
|
||||
|
||||
flush_data_cache();
|
||||
asm volatile("sync" : : );
|
||||
flush_icache_range((unsigned long)&__init_begin, (unsigned long)&__init_end);
|
||||
flush_icache_range((unsigned long)__init_begin, (unsigned long)__init_end);
|
||||
asm volatile("sync" : : );
|
||||
|
||||
local_irq_enable();
|
||||
|
@ -398,8 +395,8 @@ void free_initmem(void)
|
|||
|
||||
/* align __init_begin and __init_end to page size,
|
||||
ignoring linker script where we might have tried to save RAM */
|
||||
init_begin = PAGE_ALIGN((unsigned long)(&__init_begin));
|
||||
init_end = PAGE_ALIGN((unsigned long)(&__init_end));
|
||||
init_begin = PAGE_ALIGN((unsigned long)(__init_begin));
|
||||
init_end = PAGE_ALIGN((unsigned long)(__init_end));
|
||||
for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) {
|
||||
ClearPageReserved(virt_to_page(addr));
|
||||
init_page_count(virt_to_page(addr));
|
||||
|
@ -578,7 +575,7 @@ static void __init map_pages(unsigned long start_vaddr, unsigned long start_padd
|
|||
extern const unsigned long fault_vector_20;
|
||||
extern void * const linux_gateway_page;
|
||||
|
||||
ro_start = __pa((unsigned long)&_text);
|
||||
ro_start = __pa((unsigned long)_text);
|
||||
ro_end = __pa((unsigned long)&data_start);
|
||||
fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
|
||||
gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
|
||||
|
|
|
@ -188,7 +188,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
|
|||
}
|
||||
EXPORT_SYMBOL(__ioremap);
|
||||
|
||||
void iounmap(void __iomem *addr)
|
||||
void iounmap(const volatile void __iomem *addr)
|
||||
{
|
||||
if (addr > high_memory)
|
||||
return vfree((void *) (PAGE_MASK & (unsigned long __force) addr));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
config AGP
|
||||
tristate "/dev/agpgart (AGP Support)"
|
||||
depends on ALPHA || IA64 || PPC || X86
|
||||
depends on ALPHA || IA64 || PARISC || PPC || X86
|
||||
depends on PCI
|
||||
---help---
|
||||
AGP (Accelerated Graphics Port) is a bus system mainly used to
|
||||
|
@ -122,6 +122,14 @@ config AGP_HP_ZX1
|
|||
This option gives you AGP GART support for the HP ZX1 chipset
|
||||
for IA64 processors.
|
||||
|
||||
config AGP_PARISC
|
||||
tristate "HP Quicksilver AGP support"
|
||||
depends on AGP && PARISC && 64BIT
|
||||
help
|
||||
This option gives you AGP GART support for the HP Quicksilver
|
||||
AGP bus adapter on HP PA-RISC machines (Ok, just on the C8000
|
||||
workstation...)
|
||||
|
||||
config AGP_ALPHA_CORE
|
||||
tristate "Alpha AGP support"
|
||||
depends on AGP && (ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL)
|
||||
|
|
|
@ -8,6 +8,7 @@ obj-$(CONFIG_AGP_AMD64) += amd64-agp.o
|
|||
obj-$(CONFIG_AGP_ALPHA_CORE) += alpha-agp.o
|
||||
obj-$(CONFIG_AGP_EFFICEON) += efficeon-agp.o
|
||||
obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o
|
||||
obj-$(CONFIG_AGP_PARISC) += parisc-agp.o
|
||||
obj-$(CONFIG_AGP_I460) += i460-agp.o
|
||||
obj-$(CONFIG_AGP_INTEL) += intel-agp.o
|
||||
obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o
|
||||
|
|
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* HP Quicksilver AGP GART routines
|
||||
*
|
||||
* Copyright (c) 2006, Kyle McMartin <kyle@parisc-linux.org>
|
||||
*
|
||||
* Based on drivers/char/agpgart/hp-agp.c which is
|
||||
* (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P.
|
||||
* Bjorn Helgaas <bjorn.helgaas@hp.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/klist.h>
|
||||
#include <linux/agp_backend.h>
|
||||
|
||||
#include <asm-parisc/parisc-device.h>
|
||||
#include <asm-parisc/ropes.h>
|
||||
|
||||
#include "agp.h"
|
||||
|
||||
#define DRVNAME "quicksilver"
|
||||
#define DRVPFX DRVNAME ": "
|
||||
|
||||
#ifndef log2
|
||||
#define log2(x) ffz(~(x))
|
||||
#endif
|
||||
|
||||
#define AGP8X_MODE_BIT 3
|
||||
#define AGP8X_MODE (1 << AGP8X_MODE_BIT)
|
||||
|
||||
static struct _parisc_agp_info {
|
||||
void __iomem *ioc_regs;
|
||||
void __iomem *lba_regs;
|
||||
|
||||
int lba_cap_offset;
|
||||
|
||||
u64 *gatt;
|
||||
u64 gatt_entries;
|
||||
|
||||
u64 gart_base;
|
||||
u64 gart_size;
|
||||
|
||||
int io_page_size;
|
||||
int io_pages_per_kpage;
|
||||
} parisc_agp_info;
|
||||
|
||||
static struct gatt_mask parisc_agp_masks[] =
|
||||
{
|
||||
{
|
||||
.mask = SBA_PDIR_VALID_BIT,
|
||||
.type = 0
|
||||
}
|
||||
};
|
||||
|
||||
static struct aper_size_info_fixed parisc_agp_sizes[] =
|
||||
{
|
||||
{0, 0, 0}, /* filled in by parisc_agp_fetch_size() */
|
||||
};
|
||||
|
||||
static int
|
||||
parisc_agp_fetch_size(void)
|
||||
{
|
||||
int size;
|
||||
|
||||
size = parisc_agp_info.gart_size / MB(1);
|
||||
parisc_agp_sizes[0].size = size;
|
||||
agp_bridge->current_size = (void *) &parisc_agp_sizes[0];
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int
|
||||
parisc_agp_configure(void)
|
||||
{
|
||||
struct _parisc_agp_info *info = &parisc_agp_info;
|
||||
|
||||
agp_bridge->gart_bus_addr = info->gart_base;
|
||||
agp_bridge->capndx = info->lba_cap_offset;
|
||||
agp_bridge->mode = readl(info->lba_regs+info->lba_cap_offset+PCI_AGP_STATUS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
parisc_agp_tlbflush(struct agp_memory *mem)
|
||||
{
|
||||
struct _parisc_agp_info *info = &parisc_agp_info;
|
||||
|
||||
writeq(info->gart_base | log2(info->gart_size), info->ioc_regs+IOC_PCOM);
|
||||
readq(info->ioc_regs+IOC_PCOM); /* flush */
|
||||
}
|
||||
|
||||
static int
|
||||
parisc_agp_create_gatt_table(struct agp_bridge_data *bridge)
|
||||
{
|
||||
struct _parisc_agp_info *info = &parisc_agp_info;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < info->gatt_entries; i++) {
|
||||
info->gatt[i] = (unsigned long)agp_bridge->scratch_page;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parisc_agp_free_gatt_table(struct agp_bridge_data *bridge)
|
||||
{
|
||||
struct _parisc_agp_info *info = &parisc_agp_info;
|
||||
|
||||
info->gatt[0] = SBA_AGPGART_COOKIE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
|
||||
{
|
||||
struct _parisc_agp_info *info = &parisc_agp_info;
|
||||
int i, k;
|
||||
off_t j, io_pg_start;
|
||||
int io_pg_count;
|
||||
|
||||
if (type != 0 || mem->type != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
io_pg_start = info->io_pages_per_kpage * pg_start;
|
||||
io_pg_count = info->io_pages_per_kpage * mem->page_count;
|
||||
if ((io_pg_start + io_pg_count) > info->gatt_entries) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
j = io_pg_start;
|
||||
while (j < (io_pg_start + io_pg_count)) {
|
||||
if (info->gatt[j])
|
||||
return -EBUSY;
|
||||
j++;
|
||||
}
|
||||
|
||||
if (mem->is_flushed == FALSE) {
|
||||
global_cache_flush();
|
||||
mem->is_flushed = TRUE;
|
||||
}
|
||||
|
||||
for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
|
||||
unsigned long paddr;
|
||||
|
||||
paddr = mem->memory[i];
|
||||
for (k = 0;
|
||||
k < info->io_pages_per_kpage;
|
||||
k++, j++, paddr += info->io_page_size) {
|
||||
info->gatt[j] =
|
||||
agp_bridge->driver->mask_memory(agp_bridge,
|
||||
paddr, type);
|
||||
}
|
||||
}
|
||||
|
||||
agp_bridge->driver->tlb_flush(mem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
|
||||
{
|
||||
struct _parisc_agp_info *info = &parisc_agp_info;
|
||||
int i, io_pg_start, io_pg_count;
|
||||
|
||||
if (type != 0 || mem->type != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
io_pg_start = info->io_pages_per_kpage * pg_start;
|
||||
io_pg_count = info->io_pages_per_kpage * mem->page_count;
|
||||
for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
|
||||
info->gatt[i] = agp_bridge->scratch_page;
|
||||
}
|
||||
|
||||
agp_bridge->driver->tlb_flush(mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
parisc_agp_mask_memory(struct agp_bridge_data *bridge,
|
||||
unsigned long addr, int type)
|
||||
{
|
||||
return SBA_PDIR_VALID_BIT | addr;
|
||||
}
|
||||
|
||||
static void
|
||||
parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
|
||||
{
|
||||
struct _parisc_agp_info *info = &parisc_agp_info;
|
||||
u32 command;
|
||||
|
||||
command = readl(info->lba_regs + info->lba_cap_offset + PCI_AGP_STATUS);
|
||||
|
||||
command = agp_collect_device_status(bridge, mode, command);
|
||||
command |= 0x00000100;
|
||||
|
||||
writel(command, info->lba_regs + info->lba_cap_offset + PCI_AGP_COMMAND);
|
||||
|
||||
agp_device_command(command, (mode & AGP8X_MODE) != 0);
|
||||
}
|
||||
|
||||
struct agp_bridge_driver parisc_agp_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.size_type = FIXED_APER_SIZE,
|
||||
.configure = parisc_agp_configure,
|
||||
.fetch_size = parisc_agp_fetch_size,
|
||||
.tlb_flush = parisc_agp_tlbflush,
|
||||
.mask_memory = parisc_agp_mask_memory,
|
||||
.masks = parisc_agp_masks,
|
||||
.agp_enable = parisc_agp_enable,
|
||||
.cache_flush = global_cache_flush,
|
||||
.create_gatt_table = parisc_agp_create_gatt_table,
|
||||
.free_gatt_table = parisc_agp_free_gatt_table,
|
||||
.insert_memory = parisc_agp_insert_memory,
|
||||
.remove_memory = parisc_agp_remove_memory,
|
||||
.alloc_by_type = agp_generic_alloc_by_type,
|
||||
.free_by_type = agp_generic_free_by_type,
|
||||
.agp_alloc_page = agp_generic_alloc_page,
|
||||
.agp_destroy_page = agp_generic_destroy_page,
|
||||
.cant_use_aperture = 1,
|
||||
};
|
||||
|
||||
static int __init
|
||||
agp_ioc_init(void __iomem *ioc_regs)
|
||||
{
|
||||
struct _parisc_agp_info *info = &parisc_agp_info;
|
||||
u64 *iova_base, *io_pdir, io_tlb_ps;
|
||||
int io_tlb_shift;
|
||||
|
||||
printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n");
|
||||
|
||||
info->ioc_regs = ioc_regs;
|
||||
|
||||
io_tlb_ps = readq(info->ioc_regs+IOC_TCNFG);
|
||||
switch (io_tlb_ps) {
|
||||
case 0: io_tlb_shift = 12; break;
|
||||
case 1: io_tlb_shift = 13; break;
|
||||
case 2: io_tlb_shift = 14; break;
|
||||
case 3: io_tlb_shift = 16; break;
|
||||
default:
|
||||
printk(KERN_ERR DRVPFX "Invalid IOTLB page size "
|
||||
"configuration 0x%llx\n", io_tlb_ps);
|
||||
info->gatt = NULL;
|
||||
info->gatt_entries = 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
info->io_page_size = 1 << io_tlb_shift;
|
||||
info->io_pages_per_kpage = PAGE_SIZE / info->io_page_size;
|
||||
|
||||
iova_base = readq(info->ioc_regs+IOC_IBASE) & ~0x1;
|
||||
info->gart_base = iova_base + PLUTO_IOVA_SIZE - PLUTO_GART_SIZE;
|
||||
|
||||
info->gart_size = PLUTO_GART_SIZE;
|
||||
info->gatt_entries = info->gart_size / info->io_page_size;
|
||||
|
||||
io_pdir = phys_to_virt(readq(info->ioc_regs+IOC_PDIR_BASE));
|
||||
info->gatt = &io_pdir[(PLUTO_IOVA_SIZE/2) >> PAGE_SHIFT];
|
||||
|
||||
if (info->gatt[0] != SBA_AGPGART_COOKIE) {
|
||||
info->gatt = NULL;
|
||||
info->gatt_entries = 0;
|
||||
printk(KERN_ERR DRVPFX "No reserved IO PDIR entry found; "
|
||||
"GART disabled\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lba_find_capability(int cap)
|
||||
{
|
||||
struct _parisc_agp_info *info = &parisc_agp_info;
|
||||
u16 status;
|
||||
u8 pos, id;
|
||||
int ttl = 48;
|
||||
|
||||
status = readw(info->lba_regs + PCI_STATUS);
|
||||
if (!(status & PCI_STATUS_CAP_LIST))
|
||||
return 0;
|
||||
pos = readb(info->lba_regs + PCI_CAPABILITY_LIST);
|
||||
while (ttl-- && pos >= 0x40) {
|
||||
pos &= ~3;
|
||||
id = readb(info->lba_regs + pos + PCI_CAP_LIST_ID);
|
||||
if (id == 0xff)
|
||||
break;
|
||||
if (id == cap)
|
||||
return pos;
|
||||
pos = readb(info->lba_regs + pos + PCI_CAP_LIST_NEXT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init
|
||||
agp_lba_init(void __iomem *lba_hpa)
|
||||
{
|
||||
struct _parisc_agp_info *info = &parisc_agp_info;
|
||||
int cap;
|
||||
|
||||
info->lba_regs = lba_hpa;
|
||||
info->lba_cap_offset = lba_find_capability(PCI_CAP_ID_AGP);
|
||||
|
||||
cap = readl(lba_hpa + info->lba_cap_offset) & 0xff;
|
||||
if (cap != PCI_CAP_ID_AGP) {
|
||||
printk(KERN_ERR DRVPFX "Invalid capability ID 0x%02x at 0x%x\n",
|
||||
cap, info->lba_cap_offset);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init
|
||||
parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
|
||||
{
|
||||
struct pci_dev *fake_bridge_dev = NULL;
|
||||
struct agp_bridge_data *bridge;
|
||||
int error = 0;
|
||||
|
||||
fake_bridge_dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
|
||||
if (!fake_bridge_dev) {
|
||||
error = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
error = agp_ioc_init(ioc_hpa);
|
||||
if (error)
|
||||
goto fail;
|
||||
|
||||
error = agp_lba_init(lba_hpa);
|
||||
if (error)
|
||||
goto fail;
|
||||
|
||||
bridge = agp_alloc_bridge();
|
||||
if (!bridge) {
|
||||
error = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
bridge->driver = &parisc_agp_driver;
|
||||
|
||||
fake_bridge_dev->vendor = PCI_VENDOR_ID_HP;
|
||||
fake_bridge_dev->device = PCI_DEVICE_ID_HP_PCIX_LBA;
|
||||
bridge->dev = fake_bridge_dev;
|
||||
|
||||
error = agp_add_bridge(bridge);
|
||||
|
||||
fail:
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct device *next_device(struct klist_iter *i) {
|
||||
struct klist_node * n = klist_next(i);
|
||||
return n ? container_of(n, struct device, knode_parent) : NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
parisc_agp_init(void)
|
||||
{
|
||||
extern struct sba_device *sba_list;
|
||||
|
||||
int err = -1;
|
||||
struct parisc_device *sba = NULL, *lba = NULL;
|
||||
struct lba_device *lbadev = NULL;
|
||||
struct device *dev = NULL;
|
||||
struct klist_iter i;
|
||||
|
||||
if (!sba_list)
|
||||
goto out;
|
||||
|
||||
/* Find our parent Pluto */
|
||||
sba = sba_list->dev;
|
||||
if (!IS_PLUTO(sba)) {
|
||||
printk(KERN_INFO DRVPFX "No Pluto found, so no AGPGART for you.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Now search our Pluto for our precious AGP device... */
|
||||
klist_iter_init(&sba->dev.klist_children, &i);
|
||||
while ((dev = next_device(&i))) {
|
||||
struct parisc_device *padev = to_parisc_device(dev);
|
||||
if (IS_QUICKSILVER(padev))
|
||||
lba = padev;
|
||||
}
|
||||
klist_iter_exit(&i);
|
||||
|
||||
if (!lba) {
|
||||
printk(KERN_INFO DRVPFX "No AGP devices found.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
lbadev = parisc_get_drvdata(lba);
|
||||
|
||||
/* w00t, let's go find our cookies... */
|
||||
parisc_agp_setup(sba_list->ioc[0].ioc_hpa, lbadev->hba.base_addr);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
module_init(parisc_agp_init);
|
||||
|
||||
MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -146,7 +146,7 @@
|
|||
#include <asm/superio.h>
|
||||
#endif
|
||||
|
||||
#include <asm/iosapic.h>
|
||||
#include <asm/ropes.h>
|
||||
#include "./iosapic_private.h"
|
||||
|
||||
#define MODULE_NAME "iosapic"
|
||||
|
@ -692,6 +692,7 @@ static void iosapic_end_irq(unsigned int irq)
|
|||
DBG(KERN_DEBUG "end_irq(%d): eoi(%p, 0x%x)\n", irq,
|
||||
vi->eoi_addr, vi->eoi_data);
|
||||
iosapic_eoi(vi->eoi_addr, vi->eoi_data);
|
||||
cpu_end_irq(irq);
|
||||
}
|
||||
|
||||
static unsigned int iosapic_startup_irq(unsigned int irq)
|
||||
|
@ -728,7 +729,7 @@ static struct hw_interrupt_type iosapic_interrupt_type = {
|
|||
.shutdown = iosapic_disable_irq,
|
||||
.enable = iosapic_enable_irq,
|
||||
.disable = iosapic_disable_irq,
|
||||
.ack = no_ack_irq,
|
||||
.ack = cpu_ack_irq,
|
||||
.end = iosapic_end_irq,
|
||||
#ifdef CONFIG_SMP
|
||||
.set_affinity = iosapic_set_affinity_irq,
|
||||
|
|
|
@ -46,9 +46,9 @@
|
|||
#include <asm/page.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include <asm/ropes.h>
|
||||
#include <asm/hardware.h> /* for register_parisc_driver() stuff */
|
||||
#include <asm/parisc-device.h>
|
||||
#include <asm/iosapic.h> /* for iosapic_register() */
|
||||
#include <asm/io.h> /* read/write stuff */
|
||||
|
||||
#undef DEBUG_LBA /* general stuff */
|
||||
|
@ -100,113 +100,10 @@
|
|||
|
||||
#define MODULE_NAME "LBA"
|
||||
|
||||
#define LBA_FUNC_ID 0x0000 /* function id */
|
||||
#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */
|
||||
#define LBA_CAPABLE 0x0030 /* capabilities register */
|
||||
|
||||
#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */
|
||||
#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */
|
||||
|
||||
#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */
|
||||
#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */
|
||||
#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */
|
||||
|
||||
#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */
|
||||
#define LBA_ARB_PRI 0x0088 /* firmware sets this. */
|
||||
#define LBA_ARB_MODE 0x0090 /* firmware sets this. */
|
||||
#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */
|
||||
|
||||
#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */
|
||||
|
||||
#define LBA_STAT_CTL 0x0108 /* Status & Control */
|
||||
#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */
|
||||
#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */
|
||||
#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */
|
||||
#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */
|
||||
|
||||
#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */
|
||||
#define LBA_LMMIO_MASK 0x0208
|
||||
|
||||
#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */
|
||||
#define LBA_GMMIO_MASK 0x0218
|
||||
|
||||
#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */
|
||||
#define LBA_WLMMIO_MASK 0x0228
|
||||
|
||||
#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */
|
||||
#define LBA_WGMMIO_MASK 0x0238
|
||||
|
||||
#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */
|
||||
#define LBA_IOS_MASK 0x0248
|
||||
|
||||
#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */
|
||||
#define LBA_ELMMIO_MASK 0x0258
|
||||
|
||||
#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */
|
||||
#define LBA_EIOS_MASK 0x0268
|
||||
|
||||
#define LBA_GLOBAL_MASK 0x0270 /* Mercury only: Global Address Mask */
|
||||
#define LBA_DMA_CTL 0x0278 /* firmware sets this */
|
||||
|
||||
#define LBA_IBASE 0x0300 /* SBA DMA support */
|
||||
#define LBA_IMASK 0x0308
|
||||
|
||||
/* FIXME: ignore DMA Hint stuff until we can measure performance */
|
||||
#define LBA_HINT_CFG 0x0310
|
||||
#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */
|
||||
|
||||
#define LBA_BUS_MODE 0x0620
|
||||
|
||||
/* ERROR regs are needed for config cycle kluges */
|
||||
#define LBA_ERROR_CONFIG 0x0680
|
||||
#define LBA_SMART_MODE 0x20
|
||||
#define LBA_ERROR_STATUS 0x0688
|
||||
#define LBA_ROPE_CTL 0x06A0
|
||||
|
||||
#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */
|
||||
|
||||
/* non-postable I/O port space, densely packed */
|
||||
#define LBA_PORT_BASE (PCI_F_EXTEND | 0xfee00000UL)
|
||||
static void __iomem *astro_iop_base __read_mostly;
|
||||
|
||||
#define ELROY_HVERS 0x782
|
||||
#define MERCURY_HVERS 0x783
|
||||
#define QUICKSILVER_HVERS 0x784
|
||||
|
||||
static inline int IS_ELROY(struct parisc_device *d)
|
||||
{
|
||||
return (d->id.hversion == ELROY_HVERS);
|
||||
}
|
||||
|
||||
static inline int IS_MERCURY(struct parisc_device *d)
|
||||
{
|
||||
return (d->id.hversion == MERCURY_HVERS);
|
||||
}
|
||||
|
||||
static inline int IS_QUICKSILVER(struct parisc_device *d)
|
||||
{
|
||||
return (d->id.hversion == QUICKSILVER_HVERS);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** lba_device: Per instance Elroy data structure
|
||||
*/
|
||||
struct lba_device {
|
||||
struct pci_hba_data hba;
|
||||
|
||||
spinlock_t lba_lock;
|
||||
void *iosapic_obj;
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
void __iomem * iop_base; /* PA_VIEW - for IO port accessor funcs */
|
||||
#endif
|
||||
|
||||
int flags; /* state/functionality enabled */
|
||||
int hw_rev; /* HW revision of chip */
|
||||
};
|
||||
|
||||
|
||||
static u32 lba_t32;
|
||||
|
||||
/* lba flags */
|
||||
|
@ -1542,8 +1439,8 @@ lba_driver_probe(struct parisc_device *dev)
|
|||
default: version = "TR4+";
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
|
||||
MODULE_NAME, version, func_class & 0xf, dev->hpa.start);
|
||||
printk(KERN_INFO "Elroy version %s (0x%x) found at 0x%lx\n",
|
||||
version, func_class & 0xf, dev->hpa.start);
|
||||
|
||||
if (func_class < 2) {
|
||||
printk(KERN_WARNING "Can't support LBA older than "
|
||||
|
@ -1563,14 +1460,18 @@ lba_driver_probe(struct parisc_device *dev)
|
|||
}
|
||||
|
||||
} else if (IS_MERCURY(dev) || IS_QUICKSILVER(dev)) {
|
||||
int major, minor;
|
||||
|
||||
func_class &= 0xff;
|
||||
version = kmalloc(6, GFP_KERNEL);
|
||||
snprintf(version, 6, "TR%d.%d",(func_class >> 4),(func_class & 0xf));
|
||||
major = func_class >> 4, minor = func_class & 0xf;
|
||||
|
||||
/* We could use one printk for both Elroy and Mercury,
|
||||
* but for the mask for func_class.
|
||||
*/
|
||||
printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
|
||||
MODULE_NAME, version, func_class & 0xff, dev->hpa.start);
|
||||
printk(KERN_INFO "%s version TR%d.%d (0x%x) found at 0x%lx\n",
|
||||
IS_MERCURY(dev) ? "Mercury" : "Quicksilver", major,
|
||||
minor, func_class, dev->hpa.start);
|
||||
|
||||
cfg_ops = &mercury_cfg_ops;
|
||||
} else {
|
||||
printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa.start);
|
||||
|
@ -1600,6 +1501,7 @@ lba_driver_probe(struct parisc_device *dev)
|
|||
lba_dev->hba.dev = dev;
|
||||
lba_dev->iosapic_obj = tmp_obj; /* save interrupt handle */
|
||||
lba_dev->hba.iommu = sba_get_iommu(dev); /* get iommu data */
|
||||
parisc_set_drvdata(dev, lba_dev);
|
||||
|
||||
/* ------------ Second : initialize common stuff ---------- */
|
||||
pci_bios = &lba_bios_ops;
|
||||
|
|
|
@ -38,22 +38,15 @@
|
|||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include <asm/ropes.h>
|
||||
#include <asm/mckinley.h> /* for proc_mckinley_root */
|
||||
#include <asm/runway.h> /* for proc_runway_root */
|
||||
#include <asm/pdc.h> /* for PDC_MODEL_* */
|
||||
#include <asm/pdcpat.h> /* for is_pdc_pat() */
|
||||
#include <asm/parisc-device.h>
|
||||
|
||||
|
||||
/* declared in arch/parisc/kernel/setup.c */
|
||||
extern struct proc_dir_entry * proc_mckinley_root;
|
||||
|
||||
#define MODULE_NAME "SBA"
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
/* depends on proc fs support. But costs CPU performance */
|
||||
#undef SBA_COLLECT_STATS
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The number of debug flags is a clue - this code is fragile.
|
||||
** Don't even think about messing with it unless you have
|
||||
|
@ -92,202 +85,12 @@ extern struct proc_dir_entry * proc_mckinley_root;
|
|||
#define DBG_RES(x...)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_64BIT)
|
||||
/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */
|
||||
#define ZX1_SUPPORT
|
||||
#endif
|
||||
|
||||
#define SBA_INLINE __inline__
|
||||
|
||||
|
||||
/*
|
||||
** The number of pdir entries to "free" before issueing
|
||||
** a read to PCOM register to flush out PCOM writes.
|
||||
** Interacts with allocation granularity (ie 4 or 8 entries
|
||||
** allocated and free'd/purged at a time might make this
|
||||
** less interesting).
|
||||
*/
|
||||
#define DELAYED_RESOURCE_CNT 16
|
||||
|
||||
#define DEFAULT_DMA_HINT_REG 0
|
||||
|
||||
#define ASTRO_RUNWAY_PORT 0x582
|
||||
#define IKE_MERCED_PORT 0x803
|
||||
#define REO_MERCED_PORT 0x804
|
||||
#define REOG_MERCED_PORT 0x805
|
||||
#define PLUTO_MCKINLEY_PORT 0x880
|
||||
|
||||
#define SBA_FUNC_ID 0x0000 /* function id */
|
||||
#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */
|
||||
|
||||
#define IS_ASTRO(id) ((id)->hversion == ASTRO_RUNWAY_PORT)
|
||||
#define IS_IKE(id) ((id)->hversion == IKE_MERCED_PORT)
|
||||
#define IS_PLUTO(id) ((id)->hversion == PLUTO_MCKINLEY_PORT)
|
||||
|
||||
#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */
|
||||
|
||||
#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE)
|
||||
#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE)
|
||||
/* Ike's IOC's occupy functions 2 and 3 */
|
||||
#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE)
|
||||
|
||||
#define IOC_CTRL 0x8 /* IOC_CTRL offset */
|
||||
#define IOC_CTRL_TC (1 << 0) /* TOC Enable */
|
||||
#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */
|
||||
#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */
|
||||
#define IOC_CTRL_RM (1 << 8) /* Real Mode */
|
||||
#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */
|
||||
#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */
|
||||
#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */
|
||||
|
||||
#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */
|
||||
|
||||
#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */
|
||||
|
||||
|
||||
/*
|
||||
** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
|
||||
** Firmware programs this stuff. Don't touch it.
|
||||
*/
|
||||
#define LMMIO_DIRECT0_BASE 0x300
|
||||
#define LMMIO_DIRECT0_MASK 0x308
|
||||
#define LMMIO_DIRECT0_ROUTE 0x310
|
||||
|
||||
#define LMMIO_DIST_BASE 0x360
|
||||
#define LMMIO_DIST_MASK 0x368
|
||||
#define LMMIO_DIST_ROUTE 0x370
|
||||
|
||||
#define IOS_DIST_BASE 0x390
|
||||
#define IOS_DIST_MASK 0x398
|
||||
#define IOS_DIST_ROUTE 0x3A0
|
||||
|
||||
#define IOS_DIRECT_BASE 0x3C0
|
||||
#define IOS_DIRECT_MASK 0x3C8
|
||||
#define IOS_DIRECT_ROUTE 0x3D0
|
||||
|
||||
/*
|
||||
** Offsets into I/O TLB (Function 2 and 3 on Ike)
|
||||
*/
|
||||
#define ROPE0_CTL 0x200 /* "regbus pci0" */
|
||||
#define ROPE1_CTL 0x208
|
||||
#define ROPE2_CTL 0x210
|
||||
#define ROPE3_CTL 0x218
|
||||
#define ROPE4_CTL 0x220
|
||||
#define ROPE5_CTL 0x228
|
||||
#define ROPE6_CTL 0x230
|
||||
#define ROPE7_CTL 0x238
|
||||
|
||||
#define IOC_ROPE0_CFG 0x500 /* pluto only */
|
||||
#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */
|
||||
|
||||
|
||||
|
||||
#define HF_ENABLE 0x40
|
||||
|
||||
|
||||
#define IOC_IBASE 0x300 /* IO TLB */
|
||||
#define IOC_IMASK 0x308
|
||||
#define IOC_PCOM 0x310
|
||||
#define IOC_TCNFG 0x318
|
||||
#define IOC_PDIR_BASE 0x320
|
||||
|
||||
/* AGP GART driver looks for this */
|
||||
#define SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL
|
||||
|
||||
|
||||
/*
|
||||
** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
|
||||
** It's safer (avoid memory corruption) to keep DMA page mappings
|
||||
** equivalently sized to VM PAGE_SIZE.
|
||||
**
|
||||
** We really can't avoid generating a new mapping for each
|
||||
** page since the Virtual Coherence Index has to be generated
|
||||
** and updated for each page.
|
||||
**
|
||||
** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse.
|
||||
*/
|
||||
#define IOVP_SIZE PAGE_SIZE
|
||||
#define IOVP_SHIFT PAGE_SHIFT
|
||||
#define IOVP_MASK PAGE_MASK
|
||||
|
||||
#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */
|
||||
#define SBA_PERF_MASK1 0x718
|
||||
#define SBA_PERF_MASK2 0x730
|
||||
|
||||
|
||||
/*
|
||||
** Offsets into PCI Performance Counters (functions 12 and 13)
|
||||
** Controlled by PERF registers in function 2 & 3 respectively.
|
||||
*/
|
||||
#define SBA_PERF_CNT1 0x200
|
||||
#define SBA_PERF_CNT2 0x208
|
||||
#define SBA_PERF_CNT3 0x210
|
||||
|
||||
|
||||
struct ioc {
|
||||
void __iomem *ioc_hpa; /* I/O MMU base address */
|
||||
char *res_map; /* resource map, bit == pdir entry */
|
||||
u64 *pdir_base; /* physical base address */
|
||||
unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */
|
||||
unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */
|
||||
#ifdef ZX1_SUPPORT
|
||||
unsigned long iovp_mask; /* help convert IOVA to IOVP */
|
||||
#endif
|
||||
unsigned long *res_hint; /* next avail IOVP - circular search */
|
||||
spinlock_t res_lock;
|
||||
unsigned int res_bitshift; /* from the LEFT! */
|
||||
unsigned int res_size; /* size of resource map in bytes */
|
||||
#ifdef SBA_HINT_SUPPORT
|
||||
/* FIXME : DMA HINTs not used */
|
||||
unsigned long hint_mask_pdir; /* bits used for DMA hints */
|
||||
unsigned int hint_shift_pdir;
|
||||
#endif
|
||||
#if DELAYED_RESOURCE_CNT > 0
|
||||
int saved_cnt;
|
||||
struct sba_dma_pair {
|
||||
dma_addr_t iova;
|
||||
size_t size;
|
||||
} saved[DELAYED_RESOURCE_CNT];
|
||||
#endif
|
||||
|
||||
#ifdef SBA_COLLECT_STATS
|
||||
#define SBA_SEARCH_SAMPLE 0x100
|
||||
unsigned long avg_search[SBA_SEARCH_SAMPLE];
|
||||
unsigned long avg_idx; /* current index into avg_search */
|
||||
unsigned long used_pages;
|
||||
unsigned long msingle_calls;
|
||||
unsigned long msingle_pages;
|
||||
unsigned long msg_calls;
|
||||
unsigned long msg_pages;
|
||||
unsigned long usingle_calls;
|
||||
unsigned long usingle_pages;
|
||||
unsigned long usg_calls;
|
||||
unsigned long usg_pages;
|
||||
#endif
|
||||
|
||||
/* STUFF We don't need in performance path */
|
||||
unsigned int pdir_size; /* in bytes, determined by IOV Space size */
|
||||
};
|
||||
|
||||
struct sba_device {
|
||||
struct sba_device *next; /* list of SBA's in system */
|
||||
struct parisc_device *dev; /* dev found in bus walk */
|
||||
struct parisc_device_id *iodc; /* data about dev from firmware */
|
||||
const char *name;
|
||||
void __iomem *sba_hpa; /* base address */
|
||||
spinlock_t sba_lock;
|
||||
unsigned int flags; /* state/functionality enabled */
|
||||
unsigned int hw_rev; /* HW revision of chip */
|
||||
|
||||
struct resource chip_resv; /* MMIO reserved for chip */
|
||||
struct resource iommu_resv; /* MMIO reserved for iommu */
|
||||
|
||||
unsigned int num_ioc; /* number of on-board IOC's */
|
||||
struct ioc ioc[MAX_IOC];
|
||||
};
|
||||
|
||||
|
||||
static struct sba_device *sba_list;
|
||||
struct sba_device *sba_list;
|
||||
EXPORT_SYMBOL_GPL(sba_list);
|
||||
|
||||
static unsigned long ioc_needs_fdc = 0;
|
||||
|
||||
|
@ -300,8 +103,14 @@ static unsigned long piranha_bad_128k = 0;
|
|||
/* Looks nice and keeps the compiler happy */
|
||||
#define SBA_DEV(d) ((struct sba_device *) (d))
|
||||
|
||||
#ifdef CONFIG_AGP_PARISC
|
||||
#define SBA_AGP_SUPPORT
|
||||
#endif /*CONFIG_AGP_PARISC*/
|
||||
|
||||
#ifdef SBA_AGP_SUPPORT
|
||||
static int reserve_sba_gart = 1;
|
||||
static int sba_reserve_agpgart = 1;
|
||||
module_param(sba_reserve_agpgart, int, 1);
|
||||
MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART");
|
||||
#endif
|
||||
|
||||
#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1))
|
||||
|
@ -741,7 +550,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
|
|||
asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
|
||||
pa |= (ci >> 12) & 0xff; /* move CI (8 bits) into lowest byte */
|
||||
|
||||
pa |= 0x8000000000000000ULL; /* set "valid" bit */
|
||||
pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */
|
||||
*pdir_ptr = cpu_to_le64(pa); /* swap and store into I/O Pdir */
|
||||
|
||||
/*
|
||||
|
@ -1498,6 +1307,10 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
|
|||
WRITE_REG(ioc->ibase | 31, ioc->ioc_hpa + IOC_PCOM);
|
||||
|
||||
#ifdef SBA_AGP_SUPPORT
|
||||
{
|
||||
struct klist_iter i;
|
||||
struct device *dev = NULL;
|
||||
|
||||
/*
|
||||
** If an AGP device is present, only use half of the IOV space
|
||||
** for PCI DMA. Unfortunately we can't know ahead of time
|
||||
|
@ -1506,20 +1319,22 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
|
|||
** We program the next pdir index after we stop w/ a key for
|
||||
** the GART code to handshake on.
|
||||
*/
|
||||
device=NULL;
|
||||
for (lba = sba->child; lba; lba = lba->sibling) {
|
||||
klist_iter_init(&sba->dev.klist_children, &i);
|
||||
while (dev = next_device(&i)) {
|
||||
struct parisc_device *lba = to_parisc_device(dev);
|
||||
if (IS_QUICKSILVER(lba))
|
||||
break;
|
||||
agp_found = 1;
|
||||
}
|
||||
klist_iter_exit(&sba->dev.klist_children, &i);
|
||||
|
||||
if (lba) {
|
||||
DBG_INIT("%s: Reserving half of IOVA space for AGP GART support\n", __FUNCTION__);
|
||||
if (agp_found && sba_reserve_agpgart) {
|
||||
printk(KERN_INFO "%s: reserving %dMb of IOVA space for agpgart\n",
|
||||
__FUNCTION__, (iova_space_size/2) >> 20);
|
||||
ioc->pdir_size /= 2;
|
||||
((u64 *)ioc->pdir_base)[PDIR_INDEX(iova_space_size/2)] = SBA_IOMMU_COOKIE;
|
||||
} else {
|
||||
DBG_INIT("%s: No GART needed - no AGP controller found\n", __FUNCTION__);
|
||||
ioc->pdir_base[PDIR_INDEX(iova_space_size/2)] = SBA_AGPGART_COOKIE;
|
||||
}
|
||||
#endif /* 0 */
|
||||
}
|
||||
#endif /*SBA_AGP_SUPPORT*/
|
||||
|
||||
}
|
||||
|
||||
|
@ -1701,7 +1516,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
|
|||
}
|
||||
#endif
|
||||
|
||||
if (!IS_PLUTO(sba_dev->iodc)) {
|
||||
if (!IS_PLUTO(sba_dev->dev)) {
|
||||
ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
|
||||
DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
|
||||
__FUNCTION__, sba_dev->sba_hpa, ioc_ctl);
|
||||
|
@ -1718,9 +1533,8 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
|
|||
#endif
|
||||
} /* if !PLUTO */
|
||||
|
||||
if (IS_ASTRO(sba_dev->iodc)) {
|
||||
if (IS_ASTRO(sba_dev->dev)) {
|
||||
int err;
|
||||
/* PAT_PDC (L-class) also reports the same goofy base */
|
||||
sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, ASTRO_IOC_OFFSET);
|
||||
num_ioc = 1;
|
||||
|
||||
|
@ -1730,13 +1544,9 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
|
|||
err = request_resource(&iomem_resource, &(sba_dev->chip_resv));
|
||||
BUG_ON(err < 0);
|
||||
|
||||
} else if (IS_PLUTO(sba_dev->iodc)) {
|
||||
} else if (IS_PLUTO(sba_dev->dev)) {
|
||||
int err;
|
||||
|
||||
/* We use a negative value for IOC HPA so it gets
|
||||
* corrected when we add it with IKE's IOC offset.
|
||||
* Doesnt look clean, but fewer code.
|
||||
*/
|
||||
sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, PLUTO_IOC_OFFSET);
|
||||
num_ioc = 1;
|
||||
|
||||
|
@ -1752,14 +1562,14 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
|
|||
err = request_resource(&iomem_resource, &(sba_dev->iommu_resv));
|
||||
WARN_ON(err < 0);
|
||||
} else {
|
||||
/* IS_IKE (ie N-class, L3000, L1500) */
|
||||
/* IKE, REO */
|
||||
sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(0));
|
||||
sba_dev->ioc[1].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(1));
|
||||
num_ioc = 2;
|
||||
|
||||
/* TODO - LOOKUP Ike/Stretch chipset mem map */
|
||||
}
|
||||
/* XXX: What about Reo? */
|
||||
/* XXX: What about Reo Grande? */
|
||||
|
||||
sba_dev->num_ioc = num_ioc;
|
||||
for (i = 0; i < num_ioc; i++) {
|
||||
|
@ -1774,7 +1584,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
|
|||
* Overrides bit 1 in DMA Hint Sets.
|
||||
* Improves netperf UDP_STREAM by ~10% for bcm5701.
|
||||
*/
|
||||
if (IS_PLUTO(sba_dev->iodc)) {
|
||||
if (IS_PLUTO(sba_dev->dev)) {
|
||||
void __iomem *rope_cfg;
|
||||
unsigned long cfg_val;
|
||||
|
||||
|
@ -1803,7 +1613,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
|
|||
READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400)
|
||||
);
|
||||
|
||||
if (IS_PLUTO(sba_dev->iodc)) {
|
||||
if (IS_PLUTO(sba_dev->dev)) {
|
||||
sba_ioc_init_pluto(sba_dev->dev, &(sba_dev->ioc[i]), i);
|
||||
} else {
|
||||
sba_ioc_init(sba_dev->dev, &(sba_dev->ioc[i]), i);
|
||||
|
@ -2067,7 +1877,7 @@ sba_driver_callback(struct parisc_device *dev)
|
|||
/* Read HW Rev First */
|
||||
func_class = READ_REG(sba_addr + SBA_FCLASS);
|
||||
|
||||
if (IS_ASTRO(&dev->id)) {
|
||||
if (IS_ASTRO(dev)) {
|
||||
unsigned long fclass;
|
||||
static char astro_rev[]="Astro ?.?";
|
||||
|
||||
|
@ -2078,11 +1888,11 @@ sba_driver_callback(struct parisc_device *dev)
|
|||
astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3);
|
||||
version = astro_rev;
|
||||
|
||||
} else if (IS_IKE(&dev->id)) {
|
||||
} else if (IS_IKE(dev)) {
|
||||
static char ike_rev[] = "Ike rev ?";
|
||||
ike_rev[8] = '0' + (char) (func_class & 0xff);
|
||||
version = ike_rev;
|
||||
} else if (IS_PLUTO(&dev->id)) {
|
||||
} else if (IS_PLUTO(dev)) {
|
||||
static char pluto_rev[]="Pluto ?.?";
|
||||
pluto_rev[6] = '0' + (char) ((func_class & 0xf0) >> 4);
|
||||
pluto_rev[8] = '0' + (char) (func_class & 0x0f);
|
||||
|
@ -2097,7 +1907,7 @@ sba_driver_callback(struct parisc_device *dev)
|
|||
global_ioc_cnt = count_parisc_driver(&sba_driver);
|
||||
|
||||
/* Astro and Pluto have one IOC per SBA */
|
||||
if ((!IS_ASTRO(&dev->id)) || (!IS_PLUTO(&dev->id)))
|
||||
if ((!IS_ASTRO(dev)) || (!IS_PLUTO(dev)))
|
||||
global_ioc_cnt *= 2;
|
||||
}
|
||||
|
||||
|
@ -2117,7 +1927,6 @@ sba_driver_callback(struct parisc_device *dev)
|
|||
|
||||
sba_dev->dev = dev;
|
||||
sba_dev->hw_rev = func_class;
|
||||
sba_dev->iodc = &dev->id;
|
||||
sba_dev->name = dev->name;
|
||||
sba_dev->sba_hpa = sba_addr;
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include <asm/hardware.h>
|
||||
#include <asm/parisc-device.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/serial.h> /* for LASI_BASE_BAUD */
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
|
@ -54,7 +53,8 @@ serial_init_chip(struct parisc_device *dev)
|
|||
|
||||
memset(&port, 0, sizeof(port));
|
||||
port.iotype = UPIO_MEM;
|
||||
port.uartclk = LASI_BASE_BAUD * 16;
|
||||
/* 7.272727MHz on Lasi. Assumed the same for Dino, Wax and Timi. */
|
||||
port.uartclk = 7272727;
|
||||
port.mapbase = address;
|
||||
port.membase = ioremap_nocache(address, 16);
|
||||
port.irq = dev->irq;
|
||||
|
|
|
@ -556,10 +556,11 @@ config SERIAL_MUX
|
|||
default y
|
||||
---help---
|
||||
Saying Y here will enable the hardware MUX serial driver for
|
||||
the Nova and K class systems. The hardware MUX is not 8250/16550
|
||||
compatible therefore the /dev/ttyB0 device is shared between the
|
||||
Serial MUX and the PDC software console. The following steps
|
||||
need to be completed to use the Serial MUX:
|
||||
the Nova, K class systems and D class with a 'remote control card'.
|
||||
The hardware MUX is not 8250/16550 compatible therefore the
|
||||
/dev/ttyB0 device is shared between the Serial MUX and the PDC
|
||||
software console. The following steps need to be completed to use
|
||||
the Serial MUX:
|
||||
|
||||
1. create the device entry (mknod /dev/ttyB0 c 11 0)
|
||||
2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/personality.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/a.out.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
|
@ -194,6 +195,7 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
|
|||
unsigned long som_entry;
|
||||
struct som_hdr *som_ex;
|
||||
struct som_exec_auxhdr *hpuxhdr;
|
||||
struct files_struct *files;
|
||||
|
||||
/* Get the exec-header */
|
||||
som_ex = (struct som_hdr *) bprm->buf;
|
||||
|
@ -208,15 +210,27 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
|
|||
size = som_ex->aux_header_size;
|
||||
if (size > SOM_PAGESIZE)
|
||||
goto out;
|
||||
hpuxhdr = (struct som_exec_auxhdr *) kmalloc(size, GFP_KERNEL);
|
||||
hpuxhdr = kmalloc(size, GFP_KERNEL);
|
||||
if (!hpuxhdr)
|
||||
goto out;
|
||||
|
||||
retval = kernel_read(bprm->file, som_ex->aux_header_location,
|
||||
(char *) hpuxhdr, size);
|
||||
if (retval != size) {
|
||||
if (retval >= 0)
|
||||
retval = -EIO;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
files = current->files; /* Refcounted so ok */
|
||||
retval = unshare_files();
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
#error "Fix security hole before enabling me"
|
||||
if (files == current->files) {
|
||||
put_files_struct(files);
|
||||
files = NULL;
|
||||
}
|
||||
|
||||
retval = get_unused_fd();
|
||||
if (retval < 0)
|
||||
goto out_free;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef _ASM_PARISC_AGP_H
|
||||
#define _ASM_PARISC_AGP_H
|
||||
|
||||
/*
|
||||
* PARISC specific AGP definitions.
|
||||
* Copyright (c) 2006 Kyle McMartin <kyle@parisc-linux.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#define map_page_into_agp(page) /* nothing */
|
||||
#define unmap_page_from_agp(page) /* nothing */
|
||||
#define flush_agp_mappings() /* nothing */
|
||||
#define flush_agp_cache() mb()
|
||||
|
||||
/* Convert a physical address to an address suitable for the GART. */
|
||||
#define phys_to_gart(x) (x)
|
||||
#define gart_to_phys(x) (x)
|
||||
|
||||
/* GATT allocation. Returns/accepts GATT kernel virtual address. */
|
||||
#define alloc_gatt_pages(order) \
|
||||
((char *)__get_free_pages(GFP_KERNEL, (order)))
|
||||
#define free_gatt_pages(table, order) \
|
||||
free_pages((unsigned long)(table), (order))
|
||||
|
||||
#endif /* _ASM_PARISC_AGP_H */
|
|
@ -29,7 +29,8 @@
|
|||
#define LDREGX ldd,s
|
||||
#define LDREGM ldd,mb
|
||||
#define STREGM std,ma
|
||||
#define SHRREG shrd
|
||||
#define SHRREG shrd
|
||||
#define SHLREG shld
|
||||
#define RP_OFFSET 16
|
||||
#define FRAME_SIZE 128
|
||||
#define CALLEE_REG_FRAME_SIZE 144
|
||||
|
@ -39,7 +40,8 @@
|
|||
#define LDREGX ldwx,s
|
||||
#define LDREGM ldwm
|
||||
#define STREGM stwm
|
||||
#define SHRREG shr
|
||||
#define SHRREG shr
|
||||
#define SHLREG shlw
|
||||
#define RP_OFFSET 20
|
||||
#define FRAME_SIZE 64
|
||||
#define CALLEE_REG_FRAME_SIZE 128
|
||||
|
|
|
@ -191,16 +191,38 @@ flush_anon_page(struct page *page, unsigned long vmaddr)
|
|||
}
|
||||
#define ARCH_HAS_FLUSH_ANON_PAGE
|
||||
|
||||
static inline void
|
||||
flush_kernel_dcache_page(struct page *page)
|
||||
{
|
||||
flush_kernel_dcache_page_asm(page_address(page));
|
||||
}
|
||||
#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
|
||||
void flush_kernel_dcache_page_addr(void *addr);
|
||||
static inline void flush_kernel_dcache_page(struct page *page)
|
||||
{
|
||||
flush_kernel_dcache_page_addr(page_address(page));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_RODATA
|
||||
void mark_rodata_ro(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PA8X00
|
||||
/* Only pa8800, pa8900 needs this */
|
||||
#define ARCH_HAS_KMAP
|
||||
|
||||
void kunmap_parisc(void *addr);
|
||||
|
||||
static inline void *kmap(struct page *page)
|
||||
{
|
||||
might_sleep();
|
||||
return page_address(page);
|
||||
}
|
||||
|
||||
#define kunmap(page) kunmap_parisc(page_address(page))
|
||||
|
||||
#define kmap_atomic(page, idx) page_address(page)
|
||||
|
||||
#define kunmap_atomic(addr, idx) kunmap_parisc(addr)
|
||||
|
||||
#define kmap_atomic_pfn(pfn, idx) page_address(pfn_to_page(pfn))
|
||||
#define kmap_atomic_to_page(ptr) virt_to_page(ptr)
|
||||
#endif
|
||||
|
||||
#endif /* _PARISC_CACHEFLUSH_H */
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/thread_info.h>
|
||||
|
||||
#define COMPAT_USER_HZ 100
|
||||
|
||||
|
@ -152,7 +152,7 @@ static __inline__ void __user *compat_alloc_user_space(long len)
|
|||
|
||||
static inline int __is_compat_task(struct task_struct *t)
|
||||
{
|
||||
return personality(t->personality) == PER_LINUX32;
|
||||
return test_ti_thread_flag(t->thread_info, TIF_32BIT);
|
||||
}
|
||||
|
||||
static inline int is_compat_task(void)
|
||||
|
|
|
@ -72,18 +72,13 @@
|
|||
#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
|
||||
#define DMA2_EXT_MODE_REG (0x400 | DMA2_MODE_REG)
|
||||
|
||||
extern spinlock_t dma_spin_lock;
|
||||
|
||||
static __inline__ unsigned long claim_dma_lock(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&dma_spin_lock, flags);
|
||||
return flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __inline__ void release_dma_lock(unsigned long flags)
|
||||
{
|
||||
spin_unlock_irqrestore(&dma_spin_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,71 @@
|
|||
#ifndef _ASM_FUTEX_H
|
||||
#define _ASM_FUTEX_H
|
||||
#ifndef _ASM_PARISC_FUTEX_H
|
||||
#define _ASM_PARISC_FUTEX_H
|
||||
|
||||
#include <asm-generic/futex.h>
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/futex.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static inline int
|
||||
futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
|
||||
{
|
||||
int op = (encoded_op >> 28) & 7;
|
||||
int cmp = (encoded_op >> 24) & 15;
|
||||
int oparg = (encoded_op << 8) >> 20;
|
||||
int cmparg = (encoded_op << 20) >> 20;
|
||||
int oldval = 0, ret;
|
||||
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
||||
oparg = 1 << oparg;
|
||||
|
||||
if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
|
||||
return -EFAULT;
|
||||
|
||||
inc_preempt_count();
|
||||
|
||||
switch (op) {
|
||||
case FUTEX_OP_SET:
|
||||
case FUTEX_OP_ADD:
|
||||
case FUTEX_OP_OR:
|
||||
case FUTEX_OP_ANDN:
|
||||
case FUTEX_OP_XOR:
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
|
||||
dec_preempt_count();
|
||||
|
||||
if (!ret) {
|
||||
switch (cmp) {
|
||||
case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
||||
case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
||||
case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
||||
case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
||||
case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
||||
case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
||||
default: ret = -ENOSYS;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Non-atomic version */
|
||||
static inline int
|
||||
futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
|
||||
{
|
||||
int err = 0;
|
||||
int uval;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
|
||||
return -EFAULT;
|
||||
|
||||
err = get_user(uval, uaddr);
|
||||
if (err) return -EFAULT;
|
||||
if (uval == oldval)
|
||||
err = put_user(newval, uaddr);
|
||||
if (err) return -EFAULT;
|
||||
return uval;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -134,7 +134,7 @@ extern inline void __iomem * ioremap(unsigned long offset, unsigned long size)
|
|||
}
|
||||
#define ioremap_nocache(off, sz) ioremap((off), (sz))
|
||||
|
||||
extern void iounmap(void __iomem *addr);
|
||||
extern void iounmap(const volatile void __iomem *addr);
|
||||
|
||||
static inline unsigned char __raw_readb(const volatile void __iomem *addr)
|
||||
{
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
** This file is private to iosapic driver.
|
||||
** If stuff needs to be used by another driver, move it to a common file.
|
||||
**
|
||||
** WARNING: fields most data structures here are ordered to make sure
|
||||
** they pack nicely for 64-bit compilation. (ie sizeof(long) == 8)
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** I/O SAPIC init function
|
||||
** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC.
|
||||
** Call setup as part of per instance initialization.
|
||||
** (ie *not* init_module() function unless only one is present.)
|
||||
** fixup_irq is to initialize PCI IRQ line support and
|
||||
** virtualize pcidev->irq value. To be called by pci_fixup_bus().
|
||||
*/
|
||||
extern void *iosapic_register(unsigned long hpa);
|
||||
extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev);
|
||||
|
||||
|
||||
#ifdef __IA64__
|
||||
/*
|
||||
** PA: PIB (Processor Interrupt Block) is handled by Runway bus adapter.
|
||||
** and is hardcoded to 0xfeeNNNN0 where NNNN is id_eid field.
|
||||
**
|
||||
** IA64: PIB is handled by "Local SAPIC" (integrated in the processor).
|
||||
*/
|
||||
struct local_sapic_info {
|
||||
struct local_sapic_info *lsi_next; /* point to next CPU info */
|
||||
int *lsi_cpu_id; /* point to logical CPU id */
|
||||
unsigned long *lsi_id_eid; /* point to IA-64 CPU id */
|
||||
int *lsi_status; /* point to CPU status */
|
||||
void *lsi_private; /* point to special info */
|
||||
};
|
||||
|
||||
/*
|
||||
** "root" data structure which ties everything together.
|
||||
** Should always be able to start with sapic_root and locate
|
||||
** the desired information.
|
||||
*/
|
||||
struct sapic_info {
|
||||
struct sapic_info *si_next; /* info is per cell */
|
||||
int si_cellid; /* cell id */
|
||||
unsigned int si_status; /* status */
|
||||
char *si_pib_base; /* intr blk base address */
|
||||
local_sapic_info_t *si_local_info;
|
||||
io_sapic_info_t *si_io_info;
|
||||
extint_info_t *si_extint_info;/* External Intr info */
|
||||
};
|
||||
|
||||
#endif /* IA64 */
|
||||
|
|
@ -31,7 +31,7 @@ static __inline__ int irq_canonicalize(int irq)
|
|||
return (irq == 2) ? 9 : irq;
|
||||
}
|
||||
|
||||
struct hw_interrupt_type;
|
||||
struct irq_chip;
|
||||
|
||||
/*
|
||||
* Some useful "we don't have to do anything here" handlers. Should
|
||||
|
@ -39,6 +39,8 @@ struct hw_interrupt_type;
|
|||
*/
|
||||
void no_ack_irq(unsigned int irq);
|
||||
void no_end_irq(unsigned int irq);
|
||||
void cpu_ack_irq(unsigned int irq);
|
||||
void cpu_end_irq(unsigned int irq);
|
||||
|
||||
extern int txn_alloc_irq(unsigned int nbits);
|
||||
extern int txn_claim_irq(int);
|
||||
|
@ -46,7 +48,7 @@ extern unsigned int txn_alloc_data(unsigned int);
|
|||
extern unsigned long txn_alloc_addr(unsigned int);
|
||||
extern unsigned long txn_affinity_addr(unsigned int irq, int cpu);
|
||||
|
||||
extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *);
|
||||
extern int cpu_claim_irq(unsigned int irq, struct irq_chip *, void *);
|
||||
extern int cpu_check_affinity(unsigned int irq, cpumask_t *dest);
|
||||
|
||||
/* soft power switch support (power.c) */
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef ASM_PARISC_MCKINLEY_H
|
||||
#define ASM_PARISC_MCKINLEY_H
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* declared in arch/parisc/kernel/setup.c */
|
||||
extern struct proc_dir_entry * proc_mckinley_root;
|
||||
|
||||
#endif /*__KERNEL__*/
|
||||
#endif /*ASM_PARISC_MCKINLEY_H*/
|
|
@ -26,24 +26,10 @@
|
|||
|
||||
struct page;
|
||||
|
||||
extern void purge_kernel_dcache_page(unsigned long);
|
||||
extern void copy_user_page_asm(void *to, void *from);
|
||||
extern void clear_user_page_asm(void *page, unsigned long vaddr);
|
||||
|
||||
static inline void
|
||||
copy_user_page(void *vto, void *vfrom, unsigned long vaddr, struct page *pg)
|
||||
{
|
||||
copy_user_page_asm(vto, vfrom);
|
||||
flush_kernel_dcache_page_asm(vto);
|
||||
/* XXX: ppc flushes icache too, should we? */
|
||||
}
|
||||
|
||||
static inline void
|
||||
clear_user_page(void *page, unsigned long vaddr, struct page *pg)
|
||||
{
|
||||
purge_kernel_dcache_page((unsigned long)page);
|
||||
clear_user_page_asm(page, vaddr);
|
||||
}
|
||||
void copy_user_page_asm(void *to, void *from);
|
||||
void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
|
||||
struct page *pg);
|
||||
void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
|
||||
|
||||
/*
|
||||
* These are used to make use of C type-checking..
|
||||
|
|
|
@ -2,13 +2,9 @@
|
|||
#define _ASMPARISC_PARAM_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
# ifdef CONFIG_PA20
|
||||
# define HZ 1000 /* Faster machines */
|
||||
# else
|
||||
# define HZ 100 /* Internal kernel timer frequency */
|
||||
# endif
|
||||
# define USER_HZ 100 /* .. some user interfaces are in "ticks" */
|
||||
# define CLOCKS_PER_SEC (USER_HZ) /* like times() */
|
||||
#define HZ CONFIG_HZ
|
||||
#define USER_HZ 100 /* some user API use "ticks" */
|
||||
#define CLOCKS_PER_SEC (USER_HZ) /* like times() */
|
||||
#endif
|
||||
|
||||
#ifndef HZ
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef _ASM_PARISC_PARISC_DEVICE_H_
|
||||
#define _ASM_PARISC_PARISC_DEVICE_H_
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
struct parisc_device {
|
||||
|
@ -57,3 +60,5 @@ parisc_get_drvdata(struct parisc_device *d)
|
|||
}
|
||||
|
||||
extern struct bus_type parisc_bus_type;
|
||||
|
||||
#endif /*_ASM_PARISC_PARISC_DEVICE_H_*/
|
||||
|
|
|
@ -293,4 +293,9 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
|
|||
/* We don't need to penalize isa irq's */
|
||||
}
|
||||
|
||||
static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
|
||||
{
|
||||
return channel ? 15 : 14;
|
||||
}
|
||||
|
||||
#endif /* __ASM_PARISC_PCI_H */
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* include/asm-parisc/prefetch.h
|
||||
*
|
||||
* PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book.
|
||||
* In addition, many implementations do hardware prefetching of both
|
||||
* instructions and data.
|
||||
*
|
||||
* PA7300LC (page 14-4 of the ERS) also implements prefetching by a load
|
||||
* to gr0 but not in a way that Linux can use. If the load would cause an
|
||||
* interruption (eg due to prefetching 0), it is suppressed on PA2.0
|
||||
* processors, but not on 7300LC.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ASM_PARISC_PREFETCH_H
|
||||
#define __ASM_PARISC_PREFETCH_H
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifdef CONFIG_PREFETCH
|
||||
|
||||
#define ARCH_HAS_PREFETCH
|
||||
extern inline void prefetch(const void *addr)
|
||||
{
|
||||
__asm__("ldw 0(%0), %%r0" : : "r" (addr));
|
||||
}
|
||||
|
||||
/* LDD is a PA2.0 addition. */
|
||||
#ifdef CONFIG_PA20
|
||||
#define ARCH_HAS_PREFETCHW
|
||||
extern inline void prefetchw(const void *addr)
|
||||
{
|
||||
__asm__("ldd 0(%0), %%r0" : : "r" (addr));
|
||||
}
|
||||
#endif /* CONFIG_PA20 */
|
||||
|
||||
#endif /* CONFIG_PREFETCH */
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __ASM_PARISC_PROCESSOR_H */
|
|
@ -9,6 +9,8 @@
|
|||
#define __ASM_PARISC_PROCESSOR_H
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <asm/prefetch.h> /* lockdep.h needs <linux/prefetch.h> */
|
||||
|
||||
#include <linux/threads.h>
|
||||
#include <linux/spinlock_types.h>
|
||||
|
||||
|
@ -276,7 +278,7 @@ on downward growing arches, it looks like this:
|
|||
*/
|
||||
|
||||
#ifdef __LP64__
|
||||
#define USER_WIDE_MODE (personality(current->personality) == PER_LINUX)
|
||||
#define USER_WIDE_MODE (!test_thread_flag(TIF_32BIT))
|
||||
#else
|
||||
#define USER_WIDE_MODE 0
|
||||
#endif
|
||||
|
@ -328,34 +330,21 @@ extern unsigned long get_wchan(struct task_struct *p);
|
|||
#define KSTK_EIP(tsk) ((tsk)->thread.regs.iaoq[0])
|
||||
#define KSTK_ESP(tsk) ((tsk)->thread.regs.gr[30])
|
||||
|
||||
|
||||
/*
|
||||
* PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book.
|
||||
* In addition, many implementations do hardware prefetching of both
|
||||
* instructions and data.
|
||||
*
|
||||
* PA7300LC (page 14-4 of the ERS) also implements prefetching by a load
|
||||
* to gr0 but not in a way that Linux can use. If the load would cause an
|
||||
* interruption (eg due to prefetching 0), it is suppressed on PA2.0
|
||||
* processors, but not on 7300LC.
|
||||
*/
|
||||
#ifdef CONFIG_PREFETCH
|
||||
#define ARCH_HAS_PREFETCH
|
||||
#define ARCH_HAS_PREFETCHW
|
||||
|
||||
extern inline void prefetch(const void *addr)
|
||||
{
|
||||
__asm__("ldw 0(%0), %%r0" : : "r" (addr));
|
||||
}
|
||||
|
||||
extern inline void prefetchw(const void *addr)
|
||||
{
|
||||
__asm__("ldd 0(%0), %%r0" : : "r" (addr));
|
||||
}
|
||||
#endif
|
||||
|
||||
#define cpu_relax() barrier()
|
||||
|
||||
/* Used as a macro to identify the combined VIPT/PIPT cached
|
||||
* CPUs which require a guarantee of coherency (no inequivalent
|
||||
* aliases with different data, whether clean or not) to operate */
|
||||
static inline int parisc_requires_coherency(void)
|
||||
{
|
||||
#ifdef CONFIG_PA8X00
|
||||
/* FIXME: also pa8900 - when we see one */
|
||||
return boot_cpu_data.cpu_type == mako;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __ASM_PARISC_PROCESSOR_H */
|
||||
|
|
|
@ -0,0 +1,322 @@
|
|||
#ifndef _ASM_PARISC_ROPES_H_
|
||||
#define _ASM_PARISC_ROPES_H_
|
||||
|
||||
#include <asm-parisc/parisc-device.h>
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */
|
||||
#define ZX1_SUPPORT
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
/* depends on proc fs support. But costs CPU performance */
|
||||
#undef SBA_COLLECT_STATS
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The number of pdir entries to "free" before issueing
|
||||
** a read to PCOM register to flush out PCOM writes.
|
||||
** Interacts with allocation granularity (ie 4 or 8 entries
|
||||
** allocated and free'd/purged at a time might make this
|
||||
** less interesting).
|
||||
*/
|
||||
#define DELAYED_RESOURCE_CNT 16
|
||||
|
||||
#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */
|
||||
#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */
|
||||
|
||||
struct ioc {
|
||||
void __iomem *ioc_hpa; /* I/O MMU base address */
|
||||
char *res_map; /* resource map, bit == pdir entry */
|
||||
u64 *pdir_base; /* physical base address */
|
||||
unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */
|
||||
unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */
|
||||
#ifdef ZX1_SUPPORT
|
||||
unsigned long iovp_mask; /* help convert IOVA to IOVP */
|
||||
#endif
|
||||
unsigned long *res_hint; /* next avail IOVP - circular search */
|
||||
spinlock_t res_lock;
|
||||
unsigned int res_bitshift; /* from the LEFT! */
|
||||
unsigned int res_size; /* size of resource map in bytes */
|
||||
#ifdef SBA_HINT_SUPPORT
|
||||
/* FIXME : DMA HINTs not used */
|
||||
unsigned long hint_mask_pdir; /* bits used for DMA hints */
|
||||
unsigned int hint_shift_pdir;
|
||||
#endif
|
||||
#if DELAYED_RESOURCE_CNT > 0
|
||||
int saved_cnt;
|
||||
struct sba_dma_pair {
|
||||
dma_addr_t iova;
|
||||
size_t size;
|
||||
} saved[DELAYED_RESOURCE_CNT];
|
||||
#endif
|
||||
|
||||
#ifdef SBA_COLLECT_STATS
|
||||
#define SBA_SEARCH_SAMPLE 0x100
|
||||
unsigned long avg_search[SBA_SEARCH_SAMPLE];
|
||||
unsigned long avg_idx; /* current index into avg_search */
|
||||
unsigned long used_pages;
|
||||
unsigned long msingle_calls;
|
||||
unsigned long msingle_pages;
|
||||
unsigned long msg_calls;
|
||||
unsigned long msg_pages;
|
||||
unsigned long usingle_calls;
|
||||
unsigned long usingle_pages;
|
||||
unsigned long usg_calls;
|
||||
unsigned long usg_pages;
|
||||
#endif
|
||||
/* STUFF We don't need in performance path */
|
||||
unsigned int pdir_size; /* in bytes, determined by IOV Space size */
|
||||
};
|
||||
|
||||
struct sba_device {
|
||||
struct sba_device *next; /* list of SBA's in system */
|
||||
struct parisc_device *dev; /* dev found in bus walk */
|
||||
const char *name;
|
||||
void __iomem *sba_hpa; /* base address */
|
||||
spinlock_t sba_lock;
|
||||
unsigned int flags; /* state/functionality enabled */
|
||||
unsigned int hw_rev; /* HW revision of chip */
|
||||
|
||||
struct resource chip_resv; /* MMIO reserved for chip */
|
||||
struct resource iommu_resv; /* MMIO reserved for iommu */
|
||||
|
||||
unsigned int num_ioc; /* number of on-board IOC's */
|
||||
struct ioc ioc[MAX_IOC];
|
||||
};
|
||||
|
||||
#define ASTRO_RUNWAY_PORT 0x582
|
||||
#define IKE_MERCED_PORT 0x803
|
||||
#define REO_MERCED_PORT 0x804
|
||||
#define REOG_MERCED_PORT 0x805
|
||||
#define PLUTO_MCKINLEY_PORT 0x880
|
||||
|
||||
static inline int IS_ASTRO(struct parisc_device *d) {
|
||||
return d->id.hversion == ASTRO_RUNWAY_PORT;
|
||||
}
|
||||
|
||||
static inline int IS_IKE(struct parisc_device *d) {
|
||||
return d->id.hversion == IKE_MERCED_PORT;
|
||||
}
|
||||
|
||||
static inline int IS_PLUTO(struct parisc_device *d) {
|
||||
return d->id.hversion == PLUTO_MCKINLEY_PORT;
|
||||
}
|
||||
|
||||
#define PLUTO_IOVA_BASE (1UL*1024*1024*1024) /* 1GB */
|
||||
#define PLUTO_IOVA_SIZE (1UL*1024*1024*1024) /* 1GB */
|
||||
#define PLUTO_GART_SIZE (PLUTO_IOVA_SIZE / 2)
|
||||
|
||||
#define SBA_PDIR_VALID_BIT 0x8000000000000000ULL
|
||||
|
||||
#define SBA_AGPGART_COOKIE 0x0000badbadc0ffeeULL
|
||||
|
||||
#define SBA_FUNC_ID 0x0000 /* function id */
|
||||
#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */
|
||||
|
||||
#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */
|
||||
|
||||
#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE)
|
||||
#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE)
|
||||
/* Ike's IOC's occupy functions 2 and 3 */
|
||||
#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE)
|
||||
|
||||
#define IOC_CTRL 0x8 /* IOC_CTRL offset */
|
||||
#define IOC_CTRL_TC (1 << 0) /* TOC Enable */
|
||||
#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */
|
||||
#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */
|
||||
#define IOC_CTRL_RM (1 << 8) /* Real Mode */
|
||||
#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */
|
||||
#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */
|
||||
#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */
|
||||
|
||||
/*
|
||||
** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
|
||||
** Firmware programs this stuff. Don't touch it.
|
||||
*/
|
||||
#define LMMIO_DIRECT0_BASE 0x300
|
||||
#define LMMIO_DIRECT0_MASK 0x308
|
||||
#define LMMIO_DIRECT0_ROUTE 0x310
|
||||
|
||||
#define LMMIO_DIST_BASE 0x360
|
||||
#define LMMIO_DIST_MASK 0x368
|
||||
#define LMMIO_DIST_ROUTE 0x370
|
||||
|
||||
#define IOS_DIST_BASE 0x390
|
||||
#define IOS_DIST_MASK 0x398
|
||||
#define IOS_DIST_ROUTE 0x3A0
|
||||
|
||||
#define IOS_DIRECT_BASE 0x3C0
|
||||
#define IOS_DIRECT_MASK 0x3C8
|
||||
#define IOS_DIRECT_ROUTE 0x3D0
|
||||
|
||||
/*
|
||||
** Offsets into I/O TLB (Function 2 and 3 on Ike)
|
||||
*/
|
||||
#define ROPE0_CTL 0x200 /* "regbus pci0" */
|
||||
#define ROPE1_CTL 0x208
|
||||
#define ROPE2_CTL 0x210
|
||||
#define ROPE3_CTL 0x218
|
||||
#define ROPE4_CTL 0x220
|
||||
#define ROPE5_CTL 0x228
|
||||
#define ROPE6_CTL 0x230
|
||||
#define ROPE7_CTL 0x238
|
||||
|
||||
#define IOC_ROPE0_CFG 0x500 /* pluto only */
|
||||
#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */
|
||||
|
||||
#define HF_ENABLE 0x40
|
||||
|
||||
#define IOC_IBASE 0x300 /* IO TLB */
|
||||
#define IOC_IMASK 0x308
|
||||
#define IOC_PCOM 0x310
|
||||
#define IOC_TCNFG 0x318
|
||||
#define IOC_PDIR_BASE 0x320
|
||||
|
||||
/*
|
||||
** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
|
||||
** It's safer (avoid memory corruption) to keep DMA page mappings
|
||||
** equivalently sized to VM PAGE_SIZE.
|
||||
**
|
||||
** We really can't avoid generating a new mapping for each
|
||||
** page since the Virtual Coherence Index has to be generated
|
||||
** and updated for each page.
|
||||
**
|
||||
** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse.
|
||||
*/
|
||||
#define IOVP_SIZE PAGE_SIZE
|
||||
#define IOVP_SHIFT PAGE_SHIFT
|
||||
#define IOVP_MASK PAGE_MASK
|
||||
|
||||
#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */
|
||||
#define SBA_PERF_MASK1 0x718
|
||||
#define SBA_PERF_MASK2 0x730
|
||||
|
||||
/*
|
||||
** Offsets into PCI Performance Counters (functions 12 and 13)
|
||||
** Controlled by PERF registers in function 2 & 3 respectively.
|
||||
*/
|
||||
#define SBA_PERF_CNT1 0x200
|
||||
#define SBA_PERF_CNT2 0x208
|
||||
#define SBA_PERF_CNT3 0x210
|
||||
|
||||
/*
|
||||
** lba_device: Per instance Elroy data structure
|
||||
*/
|
||||
struct lba_device {
|
||||
struct pci_hba_data hba;
|
||||
|
||||
spinlock_t lba_lock;
|
||||
void *iosapic_obj;
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
void __iomem *iop_base; /* PA_VIEW - for IO port accessor funcs */
|
||||
#endif
|
||||
|
||||
int flags; /* state/functionality enabled */
|
||||
int hw_rev; /* HW revision of chip */
|
||||
};
|
||||
|
||||
#define ELROY_HVERS 0x782
|
||||
#define MERCURY_HVERS 0x783
|
||||
#define QUICKSILVER_HVERS 0x784
|
||||
|
||||
static inline int IS_ELROY(struct parisc_device *d) {
|
||||
return (d->id.hversion == ELROY_HVERS);
|
||||
}
|
||||
|
||||
static inline int IS_MERCURY(struct parisc_device *d) {
|
||||
return (d->id.hversion == MERCURY_HVERS);
|
||||
}
|
||||
|
||||
static inline int IS_QUICKSILVER(struct parisc_device *d) {
|
||||
return (d->id.hversion == QUICKSILVER_HVERS);
|
||||
}
|
||||
|
||||
static inline int agp_mode_mercury(void __iomem *hpa) {
|
||||
u64 bus_mode;
|
||||
|
||||
bus_mode = readl(hpa + 0x0620);
|
||||
if (bus_mode & 1)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** I/O SAPIC init function
|
||||
** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC.
|
||||
** Call setup as part of per instance initialization.
|
||||
** (ie *not* init_module() function unless only one is present.)
|
||||
** fixup_irq is to initialize PCI IRQ line support and
|
||||
** virtualize pcidev->irq value. To be called by pci_fixup_bus().
|
||||
*/
|
||||
extern void *iosapic_register(unsigned long hpa);
|
||||
extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev);
|
||||
|
||||
#define LBA_FUNC_ID 0x0000 /* function id */
|
||||
#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */
|
||||
#define LBA_CAPABLE 0x0030 /* capabilities register */
|
||||
|
||||
#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */
|
||||
#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */
|
||||
|
||||
#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */
|
||||
#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */
|
||||
#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */
|
||||
|
||||
#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */
|
||||
#define LBA_ARB_PRI 0x0088 /* firmware sets this. */
|
||||
#define LBA_ARB_MODE 0x0090 /* firmware sets this. */
|
||||
#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */
|
||||
|
||||
#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */
|
||||
|
||||
#define LBA_STAT_CTL 0x0108 /* Status & Control */
|
||||
#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */
|
||||
#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */
|
||||
#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */
|
||||
#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */
|
||||
|
||||
#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */
|
||||
#define LBA_LMMIO_MASK 0x0208
|
||||
|
||||
#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */
|
||||
#define LBA_GMMIO_MASK 0x0218
|
||||
|
||||
#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */
|
||||
#define LBA_WLMMIO_MASK 0x0228
|
||||
|
||||
#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */
|
||||
#define LBA_WGMMIO_MASK 0x0238
|
||||
|
||||
#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */
|
||||
#define LBA_IOS_MASK 0x0248
|
||||
|
||||
#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */
|
||||
#define LBA_ELMMIO_MASK 0x0258
|
||||
|
||||
#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */
|
||||
#define LBA_EIOS_MASK 0x0268
|
||||
|
||||
#define LBA_GLOBAL_MASK 0x0270 /* Mercury only: Global Address Mask */
|
||||
#define LBA_DMA_CTL 0x0278 /* firmware sets this */
|
||||
|
||||
#define LBA_IBASE 0x0300 /* SBA DMA support */
|
||||
#define LBA_IMASK 0x0308
|
||||
|
||||
/* FIXME: ignore DMA Hint stuff until we can measure performance */
|
||||
#define LBA_HINT_CFG 0x0310
|
||||
#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */
|
||||
|
||||
#define LBA_BUS_MODE 0x0620
|
||||
|
||||
/* ERROR regs are needed for config cycle kluges */
|
||||
#define LBA_ERROR_CONFIG 0x0680
|
||||
#define LBA_SMART_MODE 0x20
|
||||
#define LBA_ERROR_STATUS 0x0688
|
||||
#define LBA_ROPE_CTL 0x06A0
|
||||
|
||||
#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */
|
||||
|
||||
#endif /*_ASM_PARISC_ROPES_H_*/
|
|
@ -3,20 +3,8 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* This assumes you have a 7.272727 MHz clock for your UART.
|
||||
* The documentation implies a 40Mhz clock, and elsewhere a 7Mhz clock
|
||||
* Clarified: 7.2727MHz on LASI. Not yet clarified for DINO
|
||||
* This is used for 16550-compatible UARTs
|
||||
*/
|
||||
#define BASE_BAUD ( 1843200 / 16 )
|
||||
|
||||
#define LASI_BASE_BAUD ( 7272727 / 16 )
|
||||
#define BASE_BAUD LASI_BASE_BAUD
|
||||
|
||||
/*
|
||||
* We don't use the ISA probing code, so these entries are just to reserve
|
||||
* space. Some example (maximal) configurations:
|
||||
* - 712 w/ additional Lasi & RJ16 ports: 4
|
||||
* - J5k w/ PCI serial cards: 2 + 4 * card ~= 34
|
||||
* A500 w/ PCI serial cards: 5 + 4 * card ~= 17
|
||||
*/
|
||||
|
||||
#define SERIAL_PORT_DFNS
|
||||
|
|
|
@ -56,50 +56,79 @@ static inline int __raw_spin_trylock(raw_spinlock_t *x)
|
|||
}
|
||||
|
||||
/*
|
||||
* Read-write spinlocks, allowing multiple readers
|
||||
* but only one writer.
|
||||
* Read-write spinlocks, allowing multiple readers but only one writer.
|
||||
* Linux rwlocks are unfair to writers; they can be starved for an indefinite
|
||||
* time by readers. With care, they can also be taken in interrupt context.
|
||||
*
|
||||
* In the PA-RISC implementation, we have a spinlock and a counter.
|
||||
* Readers use the lock to serialise their access to the counter (which
|
||||
* records how many readers currently hold the lock).
|
||||
* Writers hold the spinlock, preventing any readers or other writers from
|
||||
* grabbing the rwlock.
|
||||
*/
|
||||
|
||||
#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
|
||||
|
||||
/* read_lock, read_unlock are pretty straightforward. Of course it somehow
|
||||
* sucks we end up saving/restoring flags twice for read_lock_irqsave aso. */
|
||||
|
||||
/* Note that we have to ensure interrupts are disabled in case we're
|
||||
* interrupted by some other code that wants to grab the same read lock */
|
||||
static __inline__ void __raw_read_lock(raw_rwlock_t *rw)
|
||||
{
|
||||
__raw_spin_lock(&rw->lock);
|
||||
|
||||
unsigned long flags;
|
||||
local_irq_save(flags);
|
||||
__raw_spin_lock_flags(&rw->lock, flags);
|
||||
rw->counter++;
|
||||
|
||||
__raw_spin_unlock(&rw->lock);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/* Note that we have to ensure interrupts are disabled in case we're
|
||||
* interrupted by some other code that wants to grab the same read lock */
|
||||
static __inline__ void __raw_read_unlock(raw_rwlock_t *rw)
|
||||
{
|
||||
__raw_spin_lock(&rw->lock);
|
||||
|
||||
unsigned long flags;
|
||||
local_irq_save(flags);
|
||||
__raw_spin_lock_flags(&rw->lock, flags);
|
||||
rw->counter--;
|
||||
|
||||
__raw_spin_unlock(&rw->lock);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/* write_lock is less trivial. We optimistically grab the lock and check
|
||||
* if we surprised any readers. If so we release the lock and wait till
|
||||
* they're all gone before trying again
|
||||
*
|
||||
* Also note that we don't use the _irqsave / _irqrestore suffixes here.
|
||||
* If we're called with interrupts enabled and we've got readers (or other
|
||||
* writers) in interrupt handlers someone fucked up and we'd dead-lock
|
||||
* sooner or later anyway. prumpf */
|
||||
|
||||
static __inline__ void __raw_write_lock(raw_rwlock_t *rw)
|
||||
/* Note that we have to ensure interrupts are disabled in case we're
|
||||
* interrupted by some other code that wants to grab the same read lock */
|
||||
static __inline__ int __raw_read_trylock(raw_rwlock_t *rw)
|
||||
{
|
||||
retry:
|
||||
__raw_spin_lock(&rw->lock);
|
||||
|
||||
if(rw->counter != 0) {
|
||||
/* this basically never happens */
|
||||
unsigned long flags;
|
||||
retry:
|
||||
local_irq_save(flags);
|
||||
if (__raw_spin_trylock(&rw->lock)) {
|
||||
rw->counter++;
|
||||
__raw_spin_unlock(&rw->lock);
|
||||
local_irq_restore(flags);
|
||||
return 1;
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
/* If write-locked, we fail to acquire the lock */
|
||||
if (rw->counter < 0)
|
||||
return 0;
|
||||
|
||||
/* Wait until we have a realistic chance at the lock */
|
||||
while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0)
|
||||
cpu_relax();
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/* Note that we have to ensure interrupts are disabled in case we're
|
||||
* interrupted by some other code that wants to read_trylock() this lock */
|
||||
static __inline__ void __raw_write_lock(raw_rwlock_t *rw)
|
||||
{
|
||||
unsigned long flags;
|
||||
retry:
|
||||
local_irq_save(flags);
|
||||
__raw_spin_lock_flags(&rw->lock, flags);
|
||||
|
||||
if (rw->counter != 0) {
|
||||
__raw_spin_unlock(&rw->lock);
|
||||
local_irq_restore(flags);
|
||||
|
||||
while (rw->counter != 0)
|
||||
cpu_relax();
|
||||
|
@ -107,31 +136,37 @@ retry:
|
|||
goto retry;
|
||||
}
|
||||
|
||||
/* got it. now leave without unlocking */
|
||||
rw->counter = -1; /* remember we are locked */
|
||||
rw->counter = -1; /* mark as write-locked */
|
||||
mb();
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/* write_unlock is absolutely trivial - we don't have to wait for anything */
|
||||
|
||||
static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
|
||||
static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
|
||||
{
|
||||
rw->counter = 0;
|
||||
__raw_spin_unlock(&rw->lock);
|
||||
}
|
||||
|
||||
static __inline__ int __raw_write_trylock(raw_rwlock_t *rw)
|
||||
/* Note that we have to ensure interrupts are disabled in case we're
|
||||
* interrupted by some other code that wants to read_trylock() this lock */
|
||||
static __inline__ int __raw_write_trylock(raw_rwlock_t *rw)
|
||||
{
|
||||
__raw_spin_lock(&rw->lock);
|
||||
if (rw->counter != 0) {
|
||||
/* this basically never happens */
|
||||
__raw_spin_unlock(&rw->lock);
|
||||
unsigned long flags;
|
||||
int result = 0;
|
||||
|
||||
return 0;
|
||||
local_irq_save(flags);
|
||||
if (__raw_spin_trylock(&rw->lock)) {
|
||||
if (rw->counter == 0) {
|
||||
rw->counter = -1;
|
||||
result = 1;
|
||||
} else {
|
||||
/* Read-locked. Oh well. */
|
||||
__raw_spin_unlock(&rw->lock);
|
||||
}
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
|
||||
/* got it. now leave without unlocking */
|
||||
rw->counter = -1; /* remember we are locked */
|
||||
return 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -43,6 +43,8 @@ extern int debug_locks_off(void);
|
|||
# define locking_selftest() do { } while (0)
|
||||
#endif
|
||||
|
||||
struct task_struct;
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
extern void debug_show_all_locks(void);
|
||||
extern void debug_show_held_locks(struct task_struct *task);
|
||||
|
|
Loading…
Reference in New Issue