[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);