[parisc-linux-cvs] [PATCH] PDC memory corruption fix, etc

Bjorn Helgaas bjorn_helgaas@hp.com
Wed, 9 May 2001 09:49:41 -0600


This patch

- Fixes the memory corruption caused by the fact that struct
  pdc_pat_cell_mod_maddr_block is larger than pdc_result2.
  Any platform that calls pdc_pat_cell_module() should benefit
  from this fix.

- Adds pdc_model_capabilities() to determine whether the
  platform supports non-equivalent aliasing.

- Makes the first PDC call in head64.S in wide mode (unless
  CONFIG_PDC_NARROW).  In 64-bit kernels, I think all PDC
  calls except that first one are already made in wide mode, and
  Superdome doesn't support narrow-mode PDC calls.

Comments and suggestions welcome.

Bjorn



Index: arch/parisc/kernel/cache.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/cache.c,v
retrieving revision 1.14
diff -u -p -r1.14 cache.c
--- cache.c	2001/04/06 05:10:54	1.14
+++ cache.c	2001/05/09 15:16:39
@@ -100,6 +100,8 @@ int get_cache_info(char *buffer)
 void __init 
 cache_init(void)
 {
+	long capabilities;
+
 	if(pdc_cache_info(&cache_info)<0)
 		panic("cache_init: pdc_cache_info failed");
 
@@ -169,6 +171,12 @@ cache_init(void)
 		memset(&btlb_info, 0, sizeof btlb_info);
 	}
 #endif
+
+	if (pdc_model_capabilities(&capabilities) == 0) {
+		if ((capabilities & PDC_MODEL_NVA_MASK) == PDC_MODEL_NVA_UNSUPPORTED) {
+			printk("Only equivalent aliasing supported\n");
+		}
+	}
 }
 
 void disable_sr_hashing(void)
Index: arch/parisc/kernel/firmware.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/firmware.c,v
retrieving revision 1.26
diff -u -p -r1.26 firmware.c
--- firmware.c	2001/04/06 05:10:54	1.26
+++ firmware.c	2001/05/09 15:16:39
@@ -12,8 +12,9 @@
  *	 - the name of the pdc wrapper should match one of the macros
  *	   used for the first two arguments
  *	 - don't use caps for random parts of the name
- *	 - use ASSERT_ALIGN to ensure the alignment of the arguments is
- *	   correct
+ *	 - use the static PDC result buffers and "copyout" to structs
+ *	   supplied by the caller to encapsulate alignment restrictions
+ *	 - hold pdc_lock while in PDC or using static result buffers
  *	 - use __pa() to convert virtual (kernel) pointers to physical
  *	   ones.
  *	 - the name of the struct used for pdc return values should equal
@@ -27,9 +28,15 @@
  *	Example:
  *	int pdc_cache_info(struct pdc_cache_info *cache_info )
  *	{
- *		ASSERT_ALIGN(cache_info, 8);
- *	
- *		return mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0);
+ *		int retval;
+ *
+ *		spin_lock_irq(&pdc_lock);
+ *		retval = mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0);
+ *		convert_to_wide(pdc_result);
+ *		memcpy(cache_info, pdc_result, sizeof(*cache_info));
+ *		spin_unlock_irq(&pdc_lock);
+ *
+ *		return retval;
  *	}
  *					prumpf	991016	
  */
@@ -74,15 +81,6 @@ static long real32_call(unsigned long fu
 #endif
 
 
-#define ASSERT_ALIGN(ptr, align)					\
-	do { if(((unsigned long)(ptr)) & (align-1)) {			\
-		printk("PDC: %s:%d  %s() called with "	\
-			"unaligned argument from %p", __FILE__, __LINE__, \
-			__FUNCTION__, __builtin_return_address(0));	\
-									\
-		return -1;						\
-	} } while(0)
-	
 /**
  * f_extend - Convert PDC addresses to kernel addresses.
  * @address: Address returned from PDC.
@@ -106,7 +104,7 @@ static unsigned long f_extend(unsigned l
  * convert_to_wide - Convert the return buffer addresses into kernel 
addresses.
  * @address: The return buffer from PDC.
  *
- * This fucntion is used to convert the return buffer addresses retrieved 
from PDC
+ * This function is used to convert the return buffer addresses retrieved 
from PDC
  * into kernel addresses when the PDC address size and kernel address 
size are
  * different.
  */
@@ -350,6 +348,27 @@ int pdc_model_cpuid(unsigned long *cpu_i
 }
 
 /**
+ * pdc_model_capabilities - Returns the platform capabilities.
+ * @capabilities: The return buffer.
+ *
+ * Returns information about platform support for 32- and/or 64-bit
+ * OSes, IO-PDIR coherency, and virtual aliasing.
+ */
+int pdc_model_capabilities(unsigned long *capabilities)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        pdc_result[0] = 0; /* preset zero (call may not be implemented!) 
*/
+        retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, 
__pa(pdc_result), 0);
+        convert_to_wide(pdc_result);
+        *capabilities = pdc_result[0];
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
  * pdc_cache_info - Return cache and TLB information.
  * @cache_info: The return buffer.
  *
@@ -671,13 +690,14 @@ int pdc_pat_cell_module(unsigned long *a
 			unsigned long view_type, void *mem_addr)
 {
 	int retval;
+	static struct pdc_pat_cell_mod_maddr_block result __attribute__ 
((aligned (8)));
 
 	spin_lock_irq(&pdc_lock);
 	retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_MODULE, 
__pa(pdc_result), 
-			      ploc, mod, view_type, __pa(pdc_result2));
+			      ploc, mod, view_type, __pa(&result));
 	if(!retval) {
 		*actcnt = pdc_result[0];
-		memcpy(mem_addr, pdc_result2, *actcnt);
+		memcpy(mem_addr, &result, *actcnt);
 	}
 	spin_unlock_irq(&pdc_lock);
 
Index: arch/parisc/kernel/head64.S
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/head64.S,v
retrieving revision 1.2
diff -u -p -r1.2 head64.S
--- head64.S	2001/03/02 10:31:49	1.2
+++ head64.S	2001/05/09 15:16:39
@@ -168,6 +168,18 @@ common_stext:
 	/* Save the rfi target address */
 	std		%r11,  TASK_PT_GR11-TASK_SZ_ALGN(%sp)
 
+#ifndef CONFIG_PDC_NARROW
+	/* Switch to wide mode; Superdome doesn't support narrow PDC
+	** calls.
+	*/
+1:	mfia		%rp		/* clear upper part of pcoq */
+	ldo		2f-1b(%rp),%rp
+	depdi		0,31,32,%rp
+	bv		(%rp)
+	ssm		PSW_SM_W,%r0
+2:
+#endif /* CONFIG_PDC_NARROW */
+
 	/* Set Wide mode as the "Default" (eg for traps)
 	** First trap occurs *right* after (or part of) rfi for slave CPUs.
 	** Someday, palo might not do this for the Monarch either.
Index: include/asm-parisc/pdc.h
===================================================================
RCS file: /home/cvs/parisc/linux/include/asm-parisc/pdc.h,v
retrieving revision 1.29
diff -u -p -r1.29 pdc.h
--- pdc.h	2001/04/06 05:10:58	1.29
+++ pdc.h	2001/05/09 15:16:41
@@ -395,6 +395,13 @@ struct pdc_model {		/* for PDC_MODEL */
 	unsigned long curr_key;
 };
 
+/* Values for PDC_MODEL_CAPABILITES non-equivalent virtual aliasing 
support */
+
+#define PDC_MODEL_NVA_MASK		(3 << 4)
+#define PDC_MODEL_NVA_SUPPORTED		(0 << 4)
+#define PDC_MODEL_NVA_SLOW		(1 << 4)
+#define PDC_MODEL_NVA_UNSUPPORTED	(3 << 4)
+
 struct pdc_cache_cf {		/* for PDC_CACHE  (I/D-caches) */
     unsigned long
 #ifdef __LP64__
@@ -801,6 +808,7 @@ int pdc_model_info(struct pdc_model *mod
 int pdc_model_sysmodel(char  *name);
 int pdc_model_cpuid(unsigned long *cpu_id);
 int pdc_model_versions(unsigned long *versions, int id);
+int pdc_model_capabilities(unsigned long *capabilities);
 int pdc_cache_info(struct pdc_cache_info *cache);
 #ifndef CONFIG_PA20
 int pdc_btlb_info(struct pdc_btlb_info *btlb);
°nКú@