summaryrefslogtreecommitdiffstats
path: root/arch/alpha
diff options
context:
space:
mode:
Diffstat (limited to 'arch/alpha')
-rw-r--r--arch/alpha/config.in5
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c6
-rw-r--r--arch/alpha/kernel/core_tsunami.c35
-rw-r--r--arch/alpha/kernel/irq.c68
-rw-r--r--arch/alpha/kernel/pci_iommu.c53
-rw-r--r--arch/alpha/kernel/process.c109
-rw-r--r--arch/alpha/kernel/proto.h3
-rw-r--r--arch/alpha/kernel/semaphore.c4
-rw-r--r--arch/alpha/kernel/setup.c4
-rw-r--r--arch/alpha/kernel/smp.c41
-rw-r--r--arch/alpha/kernel/sys_cabriolet.c26
-rw-r--r--arch/alpha/kernel/sys_dp264.c124
-rw-r--r--arch/alpha/kernel/sys_sio.c2
-rw-r--r--arch/alpha/kernel/time.c1
-rw-r--r--arch/alpha/kernel/traps.c4
-rw-r--r--arch/alpha/vmlinux.lds1
16 files changed, 313 insertions, 173 deletions
diff --git a/arch/alpha/config.in b/arch/alpha/config.in
index 8e44bb0e2..1686fefbc 100644
--- a/arch/alpha/config.in
+++ b/arch/alpha/config.in
@@ -60,6 +60,7 @@ unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA
unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS
unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA
unset CONFIG_ALPHA_IRONGATE
+unset CONFIG_ALPHA_BROKEN_IRQ_MASK
# Most of these machines have ISA slots; not exactly sure which don't,
# and this doesn't activate hordes of code, so do it always.
@@ -178,6 +179,10 @@ if [ "$CONFIG_ALPHA_XL" = "y" ]
then
define_bool CONFIG_ALPHA_AVANTI y
fi
+if [ "$CONFIG_ALPHA_GENERIC" = "y" -o "$CONFIG_ALPHA_PC164" = "y" ]
+then
+ define_bool CONFIG_ALPHA_BROKEN_IRQ_MASK y
+fi
if [ "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
-o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_GENERIC" = "y" ]
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index 725dd4f51..25d9583dd 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -98,6 +98,8 @@ EXPORT_SYMBOL(__memset);
EXPORT_SYMBOL(__memsetw);
EXPORT_SYMBOL(__constant_c_memset);
+EXPORT_SYMBOL(__direct_map_base);
+EXPORT_SYMBOL(__direct_map_size);
EXPORT_SYMBOL(pci_alloc_consistent);
EXPORT_SYMBOL(pci_free_consistent);
EXPORT_SYMBOL(pci_map_single);
@@ -144,6 +146,10 @@ EXPORT_SYMBOL(alpha_fp_emul_imprecise);
EXPORT_SYMBOL(alpha_fp_emul);
#endif
+#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
+EXPORT_SYMBOL(__min_ipl);
+#endif
+
/*
* The following are specially called from the uaccess assembly stubs.
*/
diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c
index 5fa112173..1452b6336 100644
--- a/arch/alpha/kernel/core_tsunami.c
+++ b/arch/alpha/kernel/core_tsunami.c
@@ -24,7 +24,6 @@
#include "proto.h"
#include "pci_impl.h"
-int TSUNAMI_bootcpu;
static struct
{
@@ -210,17 +209,23 @@ void
tsunami_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
{
tsunami_pchip *pchip = hose->index ? TSUNAMI_pchip1 : TSUNAMI_pchip0;
-
- wmb();
+ volatile unsigned long *csr;
+ unsigned long value;
/* We can invalidate up to 8 tlb entries in a go. The flush
matches against <31:16> in the pci address. */
+ csr = &pchip->tlbia.csr;
if (((start ^ end) & 0xffff0000) == 0)
- pchip->tlbiv.csr = (start & 0xffff0000) >> 12;
- else
- pchip->tlbia.csr = 0;
+ csr = &pchip->tlbiv.csr;
+ /* For TBIA, it doesn't matter what value we write. For TBI,
+ it's the shifted tag bits. */
+ value = (start & 0xffff0000) >> 12;
+
+ wmb();
+ *csr = value;
mb();
+ *csr;
}
#ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI
@@ -229,7 +234,7 @@ tsunami_probe_read(volatile unsigned long *vaddr)
{
long dont_care, probe_result;
int cpu = smp_processor_id();
- int s = swpipl(6); /* Block everything but machine checks. */
+ int s = swpipl(IPL_MCHECK - 1);
mcheck_taken(cpu) = 0;
mcheck_expected(cpu) = 1;
@@ -338,9 +343,13 @@ tsunami_init_one_pchip(tsunami_pchip *pchip, int index)
* because of an idiot-syncrasy of the CYPRESS chip. It may
* respond to a PCI bus address in the last 1MB of the 4GB
* address range.
+ *
+ * Note that the TLB lookup logic uses bitwise concatenation,
+ * not addition, so the required arena alignment is based on
+ * the size of the window.
*/
- hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, PAGE_SIZE);
- hose->sg_pci = iommu_arena_new(0xc0000000, 0x08000000, PAGE_SIZE);
+ hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, 0x00800000>>10);
+ hose->sg_pci = iommu_arena_new(0xc0000000, 0x08000000, 0x08000000>>10);
__direct_map_base = 0x40000000;
__direct_map_size = 0x80000000;
@@ -399,8 +408,6 @@ tsunami_init_arch(void)
printk("%s: CSR_STR 0x%lx\n", FN, TSUNAMI_dchip->str.csr);
printk("%s: CSR_DREV 0x%lx\n", FN, TSUNAMI_dchip->drev.csr);
#endif
- TSUNAMI_bootcpu = __hard_smp_processor_id();
-
/* With multiple PCI busses, we play with I/O as physical addrs. */
ioport_resource.end = ~0UL;
iomem_resource.end = ~0UL;
@@ -444,12 +451,10 @@ tsunami_kill_arch(int mode)
static inline void
tsunami_pci_clr_err_1(tsunami_pchip *pchip)
{
- unsigned int jd;
-
- jd = pchip->perror.csr;
+ pchip->perror.csr;
pchip->perror.csr = 0x040;
mb();
- jd = pchip->perror.csr;
+ pchip->perror.csr;
}
static inline void
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index 3d593acf3..613a633ba 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -48,6 +48,12 @@ unsigned long __irq_attempt[NR_IRQS];
#define ACTUAL_NR_IRQS NR_IRQS
#endif
+/* Hack minimum IPL during interupt processing for broken hardware. */
+
+#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
+int __min_ipl;
+#endif
+
/*
* Performance counter hook. A module can override this to
* do something useful.
@@ -283,30 +289,32 @@ handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
struct irqaction *action)
{
int status, cpu = smp_processor_id();
- unsigned long ipl;
+ int old_ipl, ipl;
kstat.irqs[cpu][irq]++;
irq_enter(cpu, irq);
status = 1; /* Force the "do bottom halves" bit */
- ipl = rdps() & 7;
+ old_ipl = ipl = getipl();
do {
- unsigned long newipl = (action->flags & SA_INTERRUPT ? 7 : 0);
- if (newipl != ipl) {
- swpipl(newipl);
- ipl = newipl;
+ int new_ipl = IPL_MIN;
+ if (action->flags & SA_INTERRUPT)
+ new_ipl = IPL_MAX;
+ if (new_ipl != ipl) {
+ setipl(new_ipl);
+ ipl = new_ipl;
}
status |= action->flags;
action->handler(irq, action->dev_id, regs);
action = action->next;
} while (action);
+ if (ipl != old_ipl)
+ setipl(old_ipl);
+
if (status & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
- if (ipl == 0)
- __cli();
-
irq_exit(cpu, irq);
return status;
@@ -325,7 +333,7 @@ disable_irq_nosync(unsigned int irq)
spin_lock_irqsave(&irq_controller_lock, flags);
if (!irq_desc[irq].depth++) {
- irq_desc[irq].status |= IRQ_DISABLED;
+ irq_desc[irq].status |= IRQ_DISABLED | IRQ_MASKED;
irq_desc[irq].handler->disable(irq);
}
spin_unlock_irqrestore(&irq_controller_lock, flags);
@@ -356,14 +364,15 @@ enable_irq(unsigned int irq)
switch (irq_desc[irq].depth) {
case 1:
{
- unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED;
- irq_desc[irq].status = status;
- if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
- irq_desc[irq].status = status | IRQ_REPLAY;
+ unsigned int status = irq_desc[irq].status;
+ status &= ~(IRQ_DISABLED | IRQ_MASKED);
+ if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+ status |= IRQ_REPLAY;
/* ??? We can't re-send on (most?) alpha hw.
hw_resend_irq(irq_desc[irq].handler,irq); */
}
+ irq_desc[irq].status = status;
irq_desc[irq].handler->enable(irq);
/* fall-through */
}
@@ -425,7 +434,7 @@ setup_irq(unsigned int irq, struct irqaction * new)
if (!shared) {
irq_desc[irq].depth = 0;
- irq_desc[irq].status &= ~IRQ_DISABLED;
+ irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_MASKED);
irq_desc[irq].handler->startup(irq);
}
spin_unlock_irqrestore(&irq_controller_lock,flags);
@@ -500,7 +509,7 @@ free_irq(unsigned int irq, void *dev_id)
/* Found - now remove it from the list of entries. */
*pp = action->next;
if (!irq_desc[irq].action) {
- irq_desc[irq].status |= IRQ_DISABLED;
+ irq_desc[irq].status |= IRQ_DISABLED|IRQ_MASKED;
irq_desc[irq].handler->shutdown(irq);
}
spin_unlock_irqrestore(&irq_controller_lock,flags);
@@ -669,7 +678,7 @@ __global_cli(void)
* Maximize ipl. If ipl was previously 0 and if this thread
* is not in an irq, then take global_irq_lock.
*/
- if (swpipl(7) == 0 && !local_irq_count(cpu))
+ if (swpipl(IPL_MAX) == IPL_MIN && !local_irq_count(cpu))
get_irqlock(cpu, where);
}
@@ -841,13 +850,25 @@ handle_irq(int irq, struct pt_regs * regs)
desc = irq_desc + irq;
spin_lock_irq(&irq_controller_lock); /* mask also the RTC */
desc->handler->ack(irq);
+ status = desc->status;
+
+#ifndef CONFIG_SMP
+ /* Look for broken irq masking. */
+ if (status & IRQ_MASKED) {
+ static unsigned long last_printed;
+ if (time_after(jiffies, last_printed+HZ)) {
+ printk(KERN_CRIT "Mask didn't work for irq %d!\n", irq);
+ last_printed = jiffies;
+ }
+ }
+#endif
/*
* REPLAY is when Linux resends an IRQ that was dropped earlier.
* WAITING is used by probe to mark irqs that are being tested.
*/
- status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
- status |= IRQ_PENDING; /* we _want_ to handle it */
+ status &= ~(IRQ_REPLAY | IRQ_WAITING);
+ status |= IRQ_PENDING | IRQ_MASKED; /* we _want_ to handle it */
/*
* If the IRQ is disabled for whatever reason, we cannot
@@ -890,9 +911,12 @@ handle_irq(int irq, struct pt_regs * regs)
desc->status &= ~IRQ_PENDING;
spin_unlock(&irq_controller_lock);
}
- desc->status &= ~IRQ_INPROGRESS;
- if (!(desc->status & IRQ_DISABLED))
+ status = desc->status & ~IRQ_INPROGRESS;
+ if (!(status & IRQ_DISABLED)) {
+ status &= ~IRQ_MASKED;
desc->handler->end(irq);
+ }
+ desc->status = status;
spin_unlock(&irq_controller_lock);
}
@@ -1056,7 +1080,7 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
#ifdef CONFIG_SMP
cpu_data[smp_processor_id()].smp_local_irq_count++;
smp_percpu_timer_interrupt(&regs);
- if (smp_processor_id() == smp_boot_cpuid)
+ if (smp_processor_id() == boot_cpuid)
#endif
handle_irq(RTC_IRQ, &regs);
return;
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index 72ce8bcb6..f5a9bd990 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -133,6 +133,9 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction)
unsigned long paddr;
dma_addr_t ret;
+ if (direction == PCI_DMA_NONE)
+ BUG();
+
paddr = virt_to_phys(cpu_addr);
/* First check to see if we can use the direct map window. */
@@ -186,12 +189,15 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction)
wrote there. */
void
-pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, int direction)
+pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size,
+ int direction)
{
struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose;
struct pci_iommu_arena *arena;
long dma_ofs, npages;
+ if (direction == PCI_DMA_NONE)
+ BUG();
if (dma_addr >= __direct_map_base
&& dma_addr < __direct_map_base + __direct_map_size) {
@@ -247,7 +253,8 @@ pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp)
}
memset(cpu_addr, 0, size);
- *dma_addrp = pci_map_single(pdev, cpu_addr, size, PCI_DMA_BIDIRECTIONAL);
+ *dma_addrp = pci_map_single(pdev, cpu_addr, size,
+ PCI_DMA_BIDIRECTIONAL);
if (*dma_addrp == 0) {
free_pages((unsigned long)cpu_addr, order);
return NULL;
@@ -424,13 +431,17 @@ sg_fill(struct scatterlist *leader, struct scatterlist *end,
}
int
-pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction)
+pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
+ int direction)
{
struct scatterlist *start, *end, *out;
struct pci_controler *hose;
struct pci_iommu_arena *arena;
dma_addr_t max_dma;
+ if (direction == PCI_DMA_NONE)
+ BUG();
+
/* Fast path single entry scatterlists. */
if (nents == 1) {
sg->dma_length = sg->length;
@@ -499,7 +510,8 @@ error:
above. */
void
-pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction)
+pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
+ int direction)
{
struct pci_controler *hose;
struct pci_iommu_arena *arena;
@@ -507,6 +519,9 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direct
dma_addr_t max_dma;
dma_addr_t fstart, fend;
+ if (direction == PCI_DMA_NONE)
+ BUG();
+
if (! alpha_mv.mv_pci_tbi)
return;
@@ -555,3 +570,33 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direct
DBGA("pci_unmap_sg: %d entries\n", nents - (end - sg));
}
+
+/* Return whether the given PCI device DMA address mask can be
+ supported properly. */
+
+int
+pci_dma_supported(struct pci_dev *pdev, dma_addr_t mask)
+{
+ struct pci_controler *hose;
+ struct pci_iommu_arena *arena;
+
+ /* If there exists a direct map, and the mask fits either
+ MAX_DMA_ADDRESS defined such that GFP_DMA does something
+ useful, or the total system memory as shifted by the
+ map base. */
+ if (__direct_map_size != 0
+ && (__direct_map_base + MAX_DMA_ADDRESS-IDENT_ADDR-1 <= mask
+ || __direct_map_base + (max_low_pfn<<PAGE_SHIFT)-1 <= mask))
+ return 1;
+
+ /* Check that we have a scatter-gather arena that fits. */
+ hose = pdev ? pdev->sysdata : pci_isa_hose;
+ arena = hose->sg_isa;
+ if (arena && arena->dma_base + arena->size <= mask)
+ return 1;
+ arena = hose->sg_pci;
+ if (arena && arena->dma_base + arena->size <= mask)
+ return 1;
+
+ return 0;
+}
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 31a818209..2e462550f 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -90,55 +90,82 @@ cpu_idle(void)
}
}
+
+struct halt_info {
+ int mode;
+ char *restart_cmd;
+};
+
static void
-common_shutdown(int mode, char *restart_cmd)
+common_shutdown_1(void *generic_ptr)
{
- /* The following currently only has any effect on SRM. We should
- fix MILO to understand it. Should be pretty easy. Also we can
- support RESTART2 via the ipc_buffer machinations pictured below,
- which SRM ignores. */
+ struct halt_info *how = (struct halt_info *)generic_ptr;
+ struct percpu_struct *cpup;
+ unsigned long *pflags, flags;
+ int cpuid = smp_processor_id();
- if (alpha_using_srm) {
- struct percpu_struct *cpup;
- unsigned long flags;
-
- cpup = (struct percpu_struct *)
- ((unsigned long)hwrpb + hwrpb->processor_offset);
-
- flags = cpup->flags;
-
- /* Clear reason to "default"; clear "bootstrap in progress". */
- flags &= ~0x00ff0001UL;
-
- if (mode == LINUX_REBOOT_CMD_RESTART) {
- if (!restart_cmd) {
- flags |= 0x00020000UL; /* "cold bootstrap" */
- cpup->ipc_buffer[0] = 0;
- } else {
- flags |= 0x00030000UL; /* "warm bootstrap" */
- strncpy((char *)cpup->ipc_buffer, restart_cmd,
- sizeof(cpup->ipc_buffer));
- }
+ /* No point in taking interrupts anymore. */
+ __cli();
+
+ cpup = (struct percpu_struct *)
+ ((unsigned long)hwrpb + hwrpb->processor_offset
+ + hwrpb->processor_size * cpuid);
+ pflags = &cpup->flags;
+ flags = *pflags;
+
+ /* Clear reason to "default"; clear "bootstrap in progress". */
+ flags &= ~0x00ff0001UL;
+
+#ifdef __SMP__
+ /* Secondaries halt here. */
+ if (cpuid != boot_cpuid) {
+ flags |= 0x00040000UL; /* "remain halted" */
+ *pflags = flags;
+ clear_bit(cpuid, &cpu_present_mask);
+ halt();
+ }
+#endif
+
+ if (how->mode == LINUX_REBOOT_CMD_RESTART) {
+ if (!how->restart_cmd) {
+ flags |= 0x00020000UL; /* "cold bootstrap" */
} else {
- flags |= 0x00040000UL; /* "remain halted" */
+ /* For SRM, we could probably set environment
+ variables to get this to work. We'd have to
+ delay this until after srm_paging_stop unless
+ we ever got srm_fixup working.
+
+ At the moment, SRM will use the last boot device,
+ but the file and flags will be the defaults, when
+ doing a "warm" bootstrap. */
+ flags |= 0x00030000UL; /* "warm bootstrap" */
}
-
- cpup->flags = flags;
- mb();
+ } else {
+ flags |= 0x00040000UL; /* "remain halted" */
+ }
+ *pflags = flags;
- /* reset_for_srm(); */
- set_hae(srm_hae);
+#ifdef __SMP__
+ /* Wait for the secondaries to halt. */
+ clear_bit(boot_cpuid, &cpu_present_mask);
+ while (cpu_present_mask)
+ barrier();
+#endif
+ /* If booted from SRM, reset some of the original environment. */
+ if (alpha_using_srm) {
#ifdef CONFIG_DUMMY_CONSOLE
- /* This has the effect of reseting the VGA video origin. */
+ /* This has the effect of resetting the VGA video origin. */
take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
#endif
+ /* reset_for_srm(); */
+ set_hae(srm_hae);
}
if (alpha_mv.kill_arch)
- alpha_mv.kill_arch(mode);
+ alpha_mv.kill_arch(how->mode);
- if (!alpha_using_srm && mode != LINUX_REBOOT_CMD_RESTART) {
+ if (! alpha_using_srm && how->mode != LINUX_REBOOT_CMD_RESTART) {
/* Unfortunately, since MILO doesn't currently understand
the hwrpb bits above, we can't reliably halt the
processor and keep it halted. So just loop. */
@@ -151,6 +178,18 @@ common_shutdown(int mode, char *restart_cmd)
halt();
}
+static void
+common_shutdown(int mode, char *restart_cmd)
+{
+ struct halt_info args;
+ args.mode = mode;
+ args.restart_cmd = restart_cmd;
+#ifdef __SMP__
+ smp_call_function(common_shutdown_1, &args, 1, 0);
+#endif
+ common_shutdown_1(&args);
+}
+
void
machine_restart(char *restart_cmd)
{
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index dd63de4d2..a8859059b 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -74,13 +74,14 @@ extern void tsunami_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t);
/* setup.c */
extern unsigned long srm_hae;
+extern int boot_cpuid;
/* smp.c */
extern void setup_smp(void);
extern int smp_info(char *buffer);
extern void handle_ipi(struct pt_regs *);
extern void smp_percpu_timer_interrupt(struct pt_regs *);
-extern int smp_boot_cpuid;
+extern unsigned long cpu_present_mask;
/* bios32.c */
/* extern void reset_for_srm(void); */
diff --git a/arch/alpha/kernel/semaphore.c b/arch/alpha/kernel/semaphore.c
index d4793ecb4..dc5209531 100644
--- a/arch/alpha/kernel/semaphore.c
+++ b/arch/alpha/kernel/semaphore.c
@@ -173,7 +173,7 @@ __down_read(struct rw_semaphore *sem, int count)
" subl %0,1,%0\n"
" stl_c %2,%1\n"
" bne %2,2f\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
".previous"
: "=r"(count), "=m"(sem->count), "=r"(tmp)
@@ -226,7 +226,7 @@ __down_write(struct rw_semaphore *sem, int count)
" ldah %0,%3(%0)\n"
" stl_c %2,%1\n"
" bne %2,2f\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
".previous"
: "=r"(count), "=m"(sem->count), "=r"(tmp)
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index 112976bcb..1311d939b 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -50,6 +50,9 @@
struct hwrpb_struct *hwrpb;
unsigned long srm_hae;
+/* Which processor we booted from. */
+int boot_cpuid;
+
#ifdef CONFIG_ALPHA_GENERIC
struct alpha_machine_vector alpha_mv;
int alpha_using_srm;
@@ -351,6 +354,7 @@ setup_arch(char **cmdline_p)
char *type_name, *var_name, *p;
hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr);
+ boot_cpuid = hard_smp_processor_id();
/*
* Locate the command line.
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index e3ae30973..be1a6440e 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -62,11 +62,13 @@ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
/* Set to a secondary's cpuid when it comes online. */
static unsigned long smp_secondary_alive;
-unsigned long cpu_present_mask; /* Which cpus ids came online. */
-static unsigned long __cpu_present_mask __initdata = 0; /* cpu reported in the hwrpb */
+/* Which cpus ids came online. */
+unsigned long cpu_present_mask;
+
+/* cpus reported in the hwrpb */
+static unsigned long hwrpb_cpu_present_mask __initdata = 0;
static int max_cpus = -1; /* Command-line limitation. */
-int smp_boot_cpuid; /* Which processor we booted from. */
int smp_num_probed; /* Internal processor count */
int smp_num_cpus = 1; /* Number that came online. */
int smp_threads_ready; /* True once the per process idle is forked. */
@@ -486,10 +488,9 @@ setup_smp(void)
struct percpu_struct *cpubase, *cpu;
int i;
- smp_boot_cpuid = hard_smp_processor_id();
- if (smp_boot_cpuid != 0) {
+ if (boot_cpuid != 0) {
printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n",
- smp_boot_cpuid);
+ boot_cpuid);
}
if (hwrpb->nr_processors > 1) {
@@ -508,7 +509,7 @@ setup_smp(void)
if ((cpu->flags & 0x1cc) == 0x1cc) {
smp_num_probed++;
/* Assume here that "whami" == index */
- __cpu_present_mask |= (1L << i);
+ hwrpb_cpu_present_mask |= (1L << i);
cpu->pal_revision = boot_cpu_palrev;
}
@@ -519,12 +520,12 @@ setup_smp(void)
}
} else {
smp_num_probed = 1;
- __cpu_present_mask = (1L << smp_boot_cpuid);
+ hwrpb_cpu_present_mask = (1L << boot_cpuid);
}
- cpu_present_mask = 1L << smp_boot_cpuid;
+ cpu_present_mask = 1L << boot_cpuid;
printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n",
- smp_num_probed, __cpu_present_mask);
+ smp_num_probed, hwrpb_cpu_present_mask);
}
/*
@@ -541,13 +542,13 @@ smp_boot_cpus(void)
memset(__cpu_logical_map, -1, sizeof(__cpu_logical_map));
memset(ipi_data, 0, sizeof(ipi_data));
- __cpu_number_map[smp_boot_cpuid] = 0;
- __cpu_logical_map[0] = smp_boot_cpuid;
- current->processor = smp_boot_cpuid;
+ __cpu_number_map[boot_cpuid] = 0;
+ __cpu_logical_map[0] = boot_cpuid;
+ current->processor = boot_cpuid;
- smp_store_cpu_info(smp_boot_cpuid);
+ smp_store_cpu_info(boot_cpuid);
smp_tune_scheduling();
- smp_setup_percpu_timer(smp_boot_cpuid);
+ smp_setup_percpu_timer(boot_cpuid);
init_idle();
@@ -565,10 +566,10 @@ smp_boot_cpus(void)
cpu_count = 1;
for (i = 0; i < NR_CPUS; i++) {
- if (i == smp_boot_cpuid)
+ if (i == boot_cpuid)
continue;
- if (((__cpu_present_mask >> i) & 1) == 0)
+ if (((hwrpb_cpu_present_mask >> i) & 1) == 0)
continue;
if (smp_boot_one_cpu(i, cpu_count))
@@ -1023,7 +1024,7 @@ debug_spin_lock(spinlock_t * lock, const char *base_file, int line_no)
" stl_c %0,%1\n"
" beq %0,3f\n"
"4: mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: ldl %0,%1\n"
" subq %2,1,%2\n"
"3: blt %2,4b\n"
@@ -1097,7 +1098,7 @@ void write_lock(rwlock_t * lock)
" stl_c %1,%0\n"
" beq %1,6f\n"
"4: mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"6: blt %3,4b # debug\n"
" subl %3,1,%3 # debug\n"
" ldl %1,%0\n"
@@ -1140,7 +1141,7 @@ void read_lock(rwlock_t * lock)
" stl_c %1,%0;"
" beq %1,6f;"
"4: mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"6: ldl %1,%0;"
" blt %2,4b # debug\n"
" subl %2,1,%2 # debug\n"
diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c
index 1432496d8..acea58d1e 100644
--- a/arch/alpha/kernel/sys_cabriolet.c
+++ b/arch/alpha/kernel/sys_cabriolet.c
@@ -126,6 +126,30 @@ cabriolet_init_irq(void)
setup_irq(16+4, &isa_cascade_irqaction);
}
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
+static void
+pc164_device_interrupt(unsigned long v, struct pt_regs *r)
+{
+ /* In theory, the PC164 has the same interrupt hardware as
+ the other Cabriolet based systems. However, something
+ got screwed up late in the development cycle which broke
+ the interrupt masking hardware. Repeat, it is not
+ possible to mask and ack interrupts. At all.
+
+ In an attempt to work around this, while processing
+ interrupts, we do not allow the IPL to drop below what
+ it is currently. This prevents the possibility of
+ recursion.
+
+ ??? Another option might be to force all PCI devices
+ to use edge triggered rather than level triggered
+ interrupts. That might be too invasive though. */
+
+ __min_ipl = getipl();
+ cabriolet_device_interrupt(v, r);
+ __min_ipl = 0;
+}
+#endif
/*
* The EB66+ is very similar to the EB66 except that it does not have
@@ -379,7 +403,7 @@ struct alpha_machine_vector pc164_mv __initmv = {
min_mem_address: CIA_DEFAULT_MEM_BASE,
nr_irqs: 35,
- device_interrupt: cabriolet_device_interrupt,
+ device_interrupt: pc164_device_interrupt,
init_arch: cia_init_arch,
init_irq: cabriolet_init_irq,
diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c
index fbebdd5a5..7414b8cc2 100644
--- a/arch/alpha/kernel/sys_dp264.c
+++ b/arch/alpha/kernel/sys_dp264.c
@@ -33,94 +33,80 @@
#include "machvec_impl.h"
+/* Note mask bit is true for ENABLED irqs. */
static unsigned long cached_irq_mask;
-
-#define TSUNAMI_SET_IRQ_MASK(cpu, value) \
-do { \
- volatile unsigned long *csr; \
- csr = &TSUNAMI_cchip->dim##cpu##.csr; \
- *csr = (value); \
- mb(); \
- *csr; \
-} while(0)
-
-static inline void
-do_flush_irq_mask(unsigned long value)
-{
- switch (TSUNAMI_bootcpu) {
- case 0:
- TSUNAMI_SET_IRQ_MASK(0, value);
- break;
- case 1:
- TSUNAMI_SET_IRQ_MASK(1, value);
- break;
- case 2:
- TSUNAMI_SET_IRQ_MASK(2, value);
- break;
- case 3:
- TSUNAMI_SET_IRQ_MASK(3, value);
- break;
- }
-}
-
-#ifdef CONFIG_SMP
-static inline void
-do_flush_smp_irq_mask(unsigned long value)
-{
- extern unsigned long cpu_present_mask;
- unsigned long other_cpus = cpu_present_mask & ~(1L << TSUNAMI_bootcpu);
-
- if (other_cpus & 1)
- TSUNAMI_SET_IRQ_MASK(0, value);
- if (other_cpus & 2)
- TSUNAMI_SET_IRQ_MASK(1, value);
- if (other_cpus & 4)
- TSUNAMI_SET_IRQ_MASK(2, value);
- if (other_cpus & 8)
- TSUNAMI_SET_IRQ_MASK(3, value);
-}
-#endif
-
static void
-dp264_flush_irq_mask(unsigned long mask)
+tsunami_update_irq_hw(unsigned long mask, unsigned long isa_enable)
{
- unsigned long value;
+ register tsunami_cchip *cchip = TSUNAMI_cchip;
+ register int bcpu = boot_cpuid;
#ifdef CONFIG_SMP
- do_flush_smp_irq_mask(mask);
+ register unsigned long cpm = cpu_present_mask;
+ volatile unsigned long *dim0, *dim1, *dim2, *dim3;
+ unsigned long mask0, mask1, mask2, mask3, maskB, dummy;
+
+ mask0 = mask1 = mask2 = mask3 = mask;
+ maskB = mask | isa_enable;
+ if (bcpu == 0) mask0 = maskB;
+ if (bcpu == 1) mask1 = maskB;
+ if (bcpu == 2) mask2 = maskB;
+ if (bcpu == 3) mask3 = maskB;
+
+ dim0 = &cchip->dim0.csr;
+ dim1 = &cchip->dim1.csr;
+ dim2 = &cchip->dim2.csr;
+ dim3 = &cchip->dim3.csr;
+ if ((cpm & 1) == 0) dim0 = &dummy;
+ if ((cpm & 2) == 0) dim1 = &dummy;
+ if ((cpm & 4) == 0) dim2 = &dummy;
+ if ((cpm & 8) == 0) dim3 = &dummy;
+
+ *dim0 = mask0;
+ *dim1 = mask1;
+ *dim2 = mask2;
+ *dim3 = mask3;
+ mb();
+ *dim0;
+ *dim1;
+ *dim2;
+ *dim3;
+#else
+ volatile unsigned long *dimB = &cchip->dim1.csr;
+ if (bcpu == 0) dimB = &cchip->dim0.csr;
+ if (bcpu == 2) dimB = &cchip->dim2.csr;
+ if (bcpu == 3) dimB = &cchip->dim3.csr;
+ *dimB = mask | isa_enable;
+ mb();
+ *dimB;
#endif
-
- value = mask | (1UL << 55) | 0xffff; /* isa irqs always enabled */
- do_flush_irq_mask(value);
}
-static void
-clipper_flush_irq_mask(unsigned long mask)
+static inline void
+dp264_update_irq_hw(unsigned long mask)
{
- unsigned long value;
-
- value = mask >> 16;
-#ifdef CONFIG_SMP
- do_flush_smp_irq_mask(value);
-#endif
+ tsunami_update_irq_hw(mask, (1UL << 55) | 0xffff);
+}
- value = value | (1UL << 55); /* master ISA enable */
- do_flush_irq_mask(value);
+static inline void
+clipper_update_irq_hw(unsigned long mask)
+{
+ tsunami_update_irq_hw(mask, 1UL << 55);
}
static inline void
dp264_enable_irq(unsigned int irq)
{
cached_irq_mask |= 1UL << irq;
- dp264_flush_irq_mask(cached_irq_mask);
+ dp264_update_irq_hw(cached_irq_mask);
}
static void
dp264_disable_irq(unsigned int irq)
{
cached_irq_mask &= ~(1UL << irq);
- dp264_flush_irq_mask(cached_irq_mask);
+ dp264_update_irq_hw(cached_irq_mask);
}
static unsigned int
@@ -134,14 +120,14 @@ static inline void
clipper_enable_irq(unsigned int irq)
{
cached_irq_mask |= 1UL << irq;
- clipper_flush_irq_mask(cached_irq_mask);
+ clipper_update_irq_hw(cached_irq_mask);
}
static void
clipper_disable_irq(unsigned int irq)
{
cached_irq_mask &= ~(1UL << irq);
- clipper_flush_irq_mask(cached_irq_mask);
+ clipper_update_irq_hw(cached_irq_mask);
}
static unsigned int
@@ -271,7 +257,7 @@ dp264_init_irq(void)
if (alpha_using_srm)
alpha_mv.device_interrupt = dp264_srm_device_interrupt;
- dp264_flush_irq_mask(0UL);
+ dp264_update_irq_hw(0UL);
init_i8259a_irqs();
init_rtc_irq();
@@ -289,7 +275,7 @@ clipper_init_irq(void)
if (alpha_using_srm)
alpha_mv.device_interrupt = clipper_srm_device_interrupt;
- clipper_flush_irq_mask(0UL);
+ clipper_update_irq_hw(0UL);
init_i8259a_irqs();
init_rtc_irq();
diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c
index ccdcf3bdb..0230ec6d9 100644
--- a/arch/alpha/kernel/sys_sio.c
+++ b/arch/alpha/kernel/sys_sio.c
@@ -391,7 +391,7 @@ struct alpha_machine_vector xl_mv __initmv = {
nr_irqs: 16,
device_interrupt: isa_device_interrupt,
- init_arch: lca_init_arch,
+ init_arch: apecs_init_arch,
init_irq: sio_init_irq,
init_rtc: common_init_rtc,
init_pci: noname_init_pci,
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index 8211045e8..d7b5cee8c 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -22,7 +22,6 @@
* fixed algorithm in do_gettimeofday() for calculating the precise time
* from processor cycle counter (now taking lost_ticks into account)
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 36b0cc43a..828044b24 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -215,8 +215,10 @@ do_entIF(unsigned long type, unsigned long a1,
/* EV4 does not implement anything except normal
rounding. Everything else will come here as
an illegal instruction. Emulate them. */
- if (alpha_fp_emul(regs.pc - 4))
+ if (alpha_fp_emul(regs.pc)) {
+ regs.pc += 4;
return;
+ }
}
send_sig(SIGILL, current, 1);
break;
diff --git a/arch/alpha/vmlinux.lds b/arch/alpha/vmlinux.lds
index 4b49a5369..4eaac4e42 100644
--- a/arch/alpha/vmlinux.lds
+++ b/arch/alpha/vmlinux.lds
@@ -5,7 +5,6 @@ SECTIONS
. = 0xfffffc0000310000;
_text = .;
.text : { *(.text) }
- .text2 : { *(.text2) }
_etext = .;
/* Exception table */