patch-2.4.14 linux/arch/sparc64/mm/init.c
Next file: linux/arch/sparc64/mm/ultra.S
Previous file: linux/arch/sparc64/kernel/sys_sparc.c
Back to the patch index
Back to the overall index
- Lines: 174
- Date:
Tue Oct 30 15:08:11 2001
- Orig file:
v2.4.13/linux/arch/sparc64/mm/init.c
- Orig date:
Tue Oct 23 22:48:50 2001
diff -u --recursive --new-file v2.4.13/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.194 2001/10/17 18:26:58 davem Exp $
+/* $Id: init.c,v 1.199 2001/10/25 18:48:03 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -132,21 +132,69 @@
#endif
}
+#define PG_dcache_dirty PG_arch_1
+
+#define dcache_dirty_cpu(page) \
+ (((page)->flags >> 24) & (NR_CPUS - 1UL))
+
+static __inline__ void set_dcache_dirty(struct page *page)
+{
+ unsigned long mask = smp_processor_id();
+ unsigned long non_cpu_bits = (1UL << 24UL) - 1UL;
+ mask = (mask << 24) | (1UL << PG_dcache_dirty);
+ __asm__ __volatile__("1:\n\t"
+ "ldx [%2], %%g7\n\t"
+ "and %%g7, %1, %%g5\n\t"
+ "or %%g5, %0, %%g5\n\t"
+ "casx [%2], %%g7, %%g5\n\t"
+ "cmp %%g7, %%g5\n\t"
+ "bne,pn %%xcc, 1b\n\t"
+ " nop"
+ : /* no outputs */
+ : "r" (mask), "r" (non_cpu_bits), "r" (&page->flags)
+ : "g5", "g7");
+}
+
+static __inline__ void clear_dcache_dirty_cpu(struct page *page, unsigned long cpu)
+{
+ unsigned long mask = (1UL << PG_dcache_dirty);
+
+ __asm__ __volatile__("! test_and_clear_dcache_dirty\n"
+ "1:\n\t"
+ "ldx [%2], %%g7\n\t"
+ "srlx %%g7, 24, %%g5\n\t"
+ "cmp %%g5, %0\n\t"
+ "bne,pn %%icc, 2f\n\t"
+ " andn %%g7, %1, %%g5\n\t"
+ "casx [%2], %%g7, %%g5\n\t"
+ "cmp %%g7, %%g5\n\t"
+ "bne,pn %%xcc, 1b\n\t"
+ " nop\n"
+ "2:"
+ : /* no outputs */
+ : "r" (cpu), "r" (mask), "r" (&page->flags)
+ : "g5", "g7");
+}
+
void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
{
struct page *page = pte_page(pte);
+ unsigned long pg_flags;
+
+ if (VALID_PAGE(page) &&
+ page->mapping &&
+ ((pg_flags = page->flags) & (1UL << PG_dcache_dirty))) {
+ int cpu = (pg_flags >> 24);
- if (VALID_PAGE(page) && page->mapping &&
- test_bit(PG_dcache_dirty, &page->flags)) {
/* This is just to optimize away some function calls
* in the SMP case.
*/
- if (dcache_dirty_cpu(page) == smp_processor_id())
+ if (cpu == smp_processor_id())
flush_dcache_page_impl(page);
else
- smp_flush_dcache_page_impl(page);
+ smp_flush_dcache_page_impl(page, cpu);
- clear_dcache_dirty(page);
+ clear_dcache_dirty_cpu(page, cpu);
}
__update_mmu_cache(vma, address, pte);
}
@@ -162,7 +210,7 @@
if (dirty) {
if (dirty_cpu == smp_processor_id())
return;
- smp_flush_dcache_page_impl(page);
+ smp_flush_dcache_page_impl(page, dirty_cpu);
}
set_dcache_dirty(page);
} else {
@@ -244,12 +292,44 @@
prom_halt();
}
+#define BASE_PAGE_SIZE 8192
+static pmd_t *prompmd;
+
+/*
+ * Translate PROM's mapping we capture at boot time into physical address.
+ * The second parameter is only set from prom_callback() invocations.
+ */
+unsigned long prom_virt_to_phys(unsigned long promva, int *error)
+{
+ pmd_t *pmdp = prompmd + ((promva >> 23) & 0x7ff);
+ pte_t *ptep;
+ unsigned long base;
+
+ if (pmd_none(*pmdp)) {
+ if (error)
+ *error = 1;
+ return(0);
+ }
+ ptep = (pte_t *)pmd_page(*pmdp) + ((promva >> 13) & 0x3ff);
+ if (!pte_present(*ptep)) {
+ if (error)
+ *error = 1;
+ return(0);
+ }
+ if (error) {
+ *error = 0;
+ return(pte_val(*ptep));
+ }
+ base = pte_val(*ptep) & _PAGE_PADDR;
+ return(base + (promva & (BASE_PAGE_SIZE - 1)));
+}
+
static void inherit_prom_mappings(void)
{
struct linux_prom_translation *trans;
unsigned long phys_page, tte_vaddr, tte_data;
void (*remap_func)(unsigned long, unsigned long, int);
- pmd_t *pmdp, *pmd;
+ pmd_t *pmdp;
pte_t *ptep;
int node, n, i, tsz;
extern unsigned int obp_iaddr_patch[2], obp_daddr_patch[2];
@@ -283,21 +363,21 @@
* in inherit_locked_prom_mappings()).
*/
#define OBP_PMD_SIZE 2048
-#define BASE_PAGE_SIZE 8192
- pmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, 0UL);
- if (pmd == NULL)
+ prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, 0UL);
+ if (prompmd == NULL)
early_pgtable_allocfail("pmd");
- memset(pmd, 0, OBP_PMD_SIZE);
+ memset(prompmd, 0, OBP_PMD_SIZE);
for (i = 0; i < n; i++) {
unsigned long vaddr;
- if (trans[i].virt >= 0xf0000000 && trans[i].virt < 0x100000000) {
+ if (trans[i].virt >= LOW_OBP_ADDRESS && trans[i].virt < HI_OBP_ADDRESS) {
for (vaddr = trans[i].virt;
- vaddr < trans[i].virt + trans[i].size;
+ ((vaddr < trans[i].virt + trans[i].size) &&
+ (vaddr < HI_OBP_ADDRESS));
vaddr += BASE_PAGE_SIZE) {
unsigned long val;
- pmdp = pmd + ((vaddr >> 23) & 0x7ff);
+ pmdp = prompmd + ((vaddr >> 23) & 0x7ff);
if (pmd_none(*pmdp)) {
ptep = __alloc_bootmem(BASE_PAGE_SIZE,
BASE_PAGE_SIZE,
@@ -321,7 +401,7 @@
}
}
}
- phys_page = __pa(pmd);
+ phys_page = __pa(prompmd);
obp_iaddr_patch[0] |= (phys_page >> 10);
obp_iaddr_patch[1] |= (phys_page & 0x3ff);
flushi((long)&obp_iaddr_patch[0]);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)