[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Кú@