[parisc-linux-cvs] Diff for PCXS fixes
John Marvin
jsm@udlkern.fc.hp.com
Wed, 3 Oct 2001 02:15:49 -0600 (MDT)
Here are the diffs for some code I just committed to fix some PCXS issues
that have been mentioned here. I also fixed a small bug in the
unaligned handler (bad opcode value), and I fixed a bug where we weren't
properly programming Viper for asp interrupts. We were relying on
whatever firmware happened to leave there, which works for 720/730, but
didn't work for 710's.
John
P.S. ls still hangs randomly. The problem is that we still have some
16 byte alignment problems for ldcw in the C library. We fixed static
and dynamic allocations, but the compiler ignores the align attribute
for stack allocations. I'm surprised we are not seeing problems on
PCXT and PCXT' machines.
--- arch/parisc/kernel/unaligned.c.old Sun Sep 30 01:02:45 2001
+++ arch/parisc/kernel/unaligned.c Mon Oct 1 06:55:14 2001
@@ -101,7 +101,7 @@
#define OPCODE_FSTW_L OPCODE3(0x1f,0)
#define OPCODE_STW_M OPCODE3(0x1f,1)
-#define OPCODE_LDH_L OPCODE4(0x06)
+#define OPCODE_LDH_L OPCODE4(0x11)
#define OPCODE_LDW_L OPCODE4(0x12)
#define OPCODE_LDW_L2 OPCODE4(0x13)
#define OPCODE_STH_L OPCODE4(0x19)
@@ -379,3 +379,51 @@ void handle_unaligned(struct pt_regs *re
regs->iaoq[1] = regs->iaoq[0] + 4;
}
+/*
+ * NB: check_unaligned() is only used for PCXS processors right
+ * now, so we only check for PA1.1 encodings at this point.
+ */
+
+int
+check_unaligned(struct pt_regs *regs)
+{
+ unsigned long align_mask;
+
+ /* Get alignment mask */
+
+ align_mask = 0UL;
+ switch (regs->iir & OPCODE1_MASK) {
+
+ case OPCODE_LDH_I:
+ case OPCODE_LDH_S:
+ case OPCODE_STH:
+ align_mask = 1UL;
+ break;
+
+ case OPCODE_LDW_I:
+ case OPCODE_LDWA_I:
+ case OPCODE_LDW_S:
+ case OPCODE_LDWA_S:
+ case OPCODE_STW:
+ case OPCODE_STWA:
+ align_mask = 3UL;
+ break;
+
+ default:
+ switch (regs->iir & OPCODE4_MASK) {
+ case OPCODE_LDH_L:
+ case OPCODE_STH_L:
+ align_mask = 1UL;
+ break;
+ case OPCODE_LDW_L:
+ case OPCODE_LDW_L2:
+ case OPCODE_STW_L:
+ case OPCODE_STW_L2:
+ align_mask = 3UL;
+ break;
+ }
+ break;
+ }
+
+ return (int)(regs->ior & align_mask);
+}
--- arch/parisc/kernel/traps.c.old Sun Sep 30 01:02:35 2001
+++ arch/parisc/kernel/traps.c Wed Oct 3 01:43:24 2001
@@ -46,7 +46,8 @@
#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
/* dumped to the console via printk) */
-void handle_unaligned(struct pt_regs *regs);
+extern void handle_unaligned(struct pt_regs *regs);
+extern int check_unaligned(struct pt_regs *regs);
static int printbinary(char *buf, unsigned long x, int nbits)
{
@@ -322,6 +323,19 @@ void handle_interruption(int code, struc
fault_address = regs->ior;
parisc_terminate("Non access data tlb fault!",regs,code,fault_address);
+ case 18:
+
+ /* PCXS only -- later cpu's split this into types 26,27 & 28 */
+
+ /* Check for unaligned access */
+
+ if (check_unaligned(regs)) {
+ handle_unaligned(regs);
+ return;
+ }
+
+ /* Fall Through */
+
case 15:
case 26:
fault_address = regs->ior;
@@ -363,6 +377,23 @@ void handle_interruption(int code, struc
si.si_code = ILL_PRVOPC;
goto give_sigill;
case 11:
+ if ((regs->iir & 0xffdfffe0) == 0x034008a0) {
+
+ /* This is a MFCTL cr26/cr27 to gr instruction.
+ * PCXS traps on this, so we need to emulate it.
+ */
+
+ if (regs->iir & 0x00200000)
+ regs->gr[regs->iir & 0x1f] = mfctl(27);
+ else
+ regs->gr[regs->iir & 0x1f] = mfctl(26);
+
+ regs->iaoq[0] = regs->iaoq[1];
+ regs->iaoq[1] += 4;
+ regs->iasq[0] = regs->iasq[1];
+ return;
+ }
+
die_if_kernel("Privileged register - shouldn't happen!", regs, code);
si.si_code = ILL_PRVREG;
give_sigill:
--- drivers/gsc/asp.c.old Wed Aug 29 23:29:53 2001
+++ drivers/gsc/asp.c Wed Oct 3 01:31:04 2001
@@ -28,7 +28,7 @@
#define OFFSET_ASP_LED 0x20 /* offset to HPA of the LED */
-#undef USE_VIPER /* VIPER - graphics-board */
+#define VIPER_INT_WORD 0xFFFBF088 /* addr of viper interrupt word */
static int
asp_find_irq(struct busdevice *busdev_dev, struct parisc_device *dev)
@@ -78,9 +78,6 @@ asp_init_chip(struct parisc_device *dev)
printk(KERN_INFO "%s version %d at 0x%lx found.\n",
asp->name, asp->version, asp->hpa);
- /* Stop ASP hissing for a bit */
-// asp_init_irq(asp);
-
/* the IRQ ASP should use */
ret = -EBUSY;
irq = gsc_claim_irq(&gsc_irq, ASP_GSC_IRQ);
@@ -97,14 +94,8 @@ asp_init_chip(struct parisc_device *dev)
asp->parent_irq = gsc_irq.irq;
asp->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
-#ifdef USE_VIPER
- /* Tell VIPER which IRQ ASP has been assigned. */
- gsc_writel(1<<gsc_irq.irq, 0xfffbf088);
- gsc_writel(~0, 0xfffbf088);
-#endif
-
- /* enable IRQ's for devices below ASP */
-// gsc_writel(asp->eim, asp->hpa + OFFSET_IAR);
+ /* Program VIPER to interrupt on the ASP irq */
+ gsc_writel((1 << (31 - ASP_GSC_IRQ)),VIPER_INT_WORD);
/* Done init'ing, register this driver */
ret = register_busdevice(dev, asp);