/* sys_cacheflush -- flush (part of) the processor cache. */ asmlinkage int sys_cacheflush (unsigned long addr, unsigned long len, int op) { struct vm_area_struct *vma; if ((op < 0) || (op > (CACHEFLUSH_D_PURGE|CACHEFLUSH_I))) return -EINVAL; /* * Verify that the specified address region actually belongs * to this process. */ if (addr + len < addr) return -EFAULT; vma = find_vma (current->mm, addr); if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) return -EFAULT; switch (op & CACHEFLUSH_D_PURGE) { case CACHEFLUSH_D_INVAL: __flush_invalidate_region(addr, len); break; case CACHEFLUSH_D_WB: __flush_wback_region(addr, len); break; case CACHEFLUSH_D_PURGE: __flush_purge_region(addr, len); break; } if (op & CACHEFLUSH_I) { flush_icache_all(); } return 0; }
/* * clear_user_page * @to: P1 address * @address: U0 address to be mapped */ void clear_user_page(void *to, unsigned long address, struct page *pg) { struct page *page = virt_to_page(to); __set_bit(PG_mapped, &page->flags); if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) { clear_page(to); __flush_wback_region(to, PAGE_SIZE); } else { __flush_purge_virtual_region(to, (void *)(address & 0xfffff000), PAGE_SIZE); clear_page(to); __flush_wback_region(to, PAGE_SIZE); } }
/* * Write back the range of D-cache, and purge the I-cache. * * Called from kernel/module.c:sys_init_module and routine for a.out format. */ static void sh7705_flush_icache_range(void *args) { struct flusher_data *data = args; unsigned long start, end; start = data->addr1; end = data->addr2; __flush_wback_region((void *)start, end - start); }
void __init mem_init(void) { int codesize, datasize, initsize; int nid; num_physpages = 0; high_memory = NULL; for_each_online_node(nid) { pg_data_t *pgdat = NODE_DATA(nid); unsigned long node_pages = 0; void *node_high_memory; num_physpages += pgdat->node_present_pages; if (pgdat->node_spanned_pages) node_pages = free_all_bootmem_node(pgdat); totalram_pages += node_pages; node_high_memory = (void *)__va((pgdat->node_start_pfn + pgdat->node_spanned_pages) << PAGE_SHIFT); if (node_high_memory > high_memory) high_memory = node_high_memory; } /* clear the zero-page */ memset(empty_zero_page, 0, PAGE_SIZE); __flush_wback_region(empty_zero_page, PAGE_SIZE); after_bootmem = 1; codesize = (unsigned long) &_etext - (unsigned long) &_text; datasize = (unsigned long) &_edata - (unsigned long) &_etext; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT); kclist_add(&kcore_vmalloc, (void *)VMALLOC_START, VMALLOC_END - VMALLOC_START); printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, " "%dk data, %dk init)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), num_physpages << (PAGE_SHIFT-10), codesize >> 10, datasize >> 10, initsize >> 10); p3_cache_init(); /* Initialize the vDSO */ vsyscall_init(); }
void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) { unsigned long flags; unsigned long pteval; unsigned long vpn; /* Ptrace may call this routine. */ if (vma && current->active_mm != vma->vm_mm) return; #if defined(CONFIG_SH7705_CACHE_32KB) { struct page *page = pte_page(pte); unsigned long pfn = pte_pfn(pte); if (pfn_valid(pfn) && !test_bit(PG_mapped, &page->flags)) { unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; __flush_wback_region((void *)P1SEGADDR(phys), PAGE_SIZE); __set_bit(PG_mapped, &page->flags); } } #endif local_irq_save(flags); /* Set PTEH register */ vpn = (address & MMU_VPN_MASK) | get_asid(); ctrl_outl(vpn, MMU_PTEH); pteval = pte_val(pte); /* Set PTEL register */ pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ /* conveniently, we want all the software flags to be 0 anyway */ ctrl_outl(pteval, MMU_PTEL); /* Load the TLB */ asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); local_irq_restore(flags); }
void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr, size_t size, enum dma_data_direction dir) { void *addr = sh_cacheop_vaddr(phys_to_virt(paddr)); switch (dir) { case DMA_FROM_DEVICE: /* invalidate only */ __flush_invalidate_region(addr, size); break; case DMA_TO_DEVICE: /* writeback only */ __flush_wback_region(addr, size); break; case DMA_BIDIRECTIONAL: /* writeback and invalidate */ __flush_purge_region(addr, size); break; default: BUG(); } }
void sh_sync_dma_for_device(void *vaddr, size_t size, enum dma_data_direction direction) { void *addr; addr = __in_29bit_mode() ? (void *)CAC_ADDR((unsigned long)vaddr) : vaddr; switch (direction) { case DMA_FROM_DEVICE: /* invalidate only */ __flush_invalidate_region(addr, size); break; case DMA_TO_DEVICE: /* writeback only */ __flush_wback_region(addr, size); break; case DMA_BIDIRECTIONAL: /* writeback and invalidate */ __flush_purge_region(addr, size); break; default: BUG(); } }
void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { #if defined(CONFIG_CPU_SH5) || defined(CONFIG_PMB) void *p1addr = vaddr; #else void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr); #endif switch (direction) { case DMA_FROM_DEVICE: /* invalidate only */ __flush_invalidate_region(p1addr, size); break; case DMA_TO_DEVICE: /* writeback only */ __flush_wback_region(p1addr, size); break; case DMA_BIDIRECTIONAL: /* writeback and invalidate */ __flush_purge_region(p1addr, size); break; default: BUG(); } }
/* * Write back the range of D-cache, and purge the I-cache. * * Called from kernel/module.c:sys_init_module and routine for a.out format. */ void flush_icache_range(unsigned long start, unsigned long end) { __flush_wback_region((void *)start, end - start); }