10c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt/* 20c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt * arch/sh/mm/pmb.c 30c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt * 40c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt * Privileged Space Mapping Buffer (PMB) Support. 50c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt * 6d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundt * Copyright (C) 2005 - 2011 Paul Mundt 73d467676abf5f01f5ee99056273a58486968e252Matt Fleming * Copyright (C) 2010 Matt Fleming 80c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt * 90c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt * This file is subject to the terms and conditions of the GNU General Public 100c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt * License. See the file "COPYING" in the main directory of this archive 110c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt * for more details. 120c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt */ 130c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt#include <linux/init.h> 140c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt#include <linux/kernel.h> 15d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundt#include <linux/syscore_ops.h> 16a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZI#include <linux/cpu.h> 170c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt#include <linux/module.h> 180c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt#include <linux/bitops.h> 190c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt#include <linux/debugfs.h> 200c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt#include <linux/fs.h> 210c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt#include <linux/seq_file.h> 220c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt#include <linux/err.h> 2351becfd96287b3913b13075699433730984e2f4fPaul Mundt#include <linux/io.h> 24d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt#include <linux/spinlock.h> 2590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt#include <linux/vmalloc.h> 26281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt#include <asm/cacheflush.h> 2751becfd96287b3913b13075699433730984e2f4fPaul Mundt#include <asm/sizes.h> 280c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt#include <asm/uaccess.h> 29d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt#include <asm/pgtable.h> 307bdda6209f224aa784a036df54b22cb338d2e859Paul Mundt#include <asm/page.h> 310c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt#include <asm/mmu.h> 32eddeeb32fe303910c58c4e3c27fde4b6f1503350Stuart Menefy#include <asm/mmu_context.h> 330c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 34d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundtstruct pmb_entry; 35d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 36d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundtstruct pmb_entry { 37d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt unsigned long vpn; 38d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt unsigned long ppn; 39d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt unsigned long flags; 40d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt unsigned long size; 41d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 42f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spinlock_t lock; 43d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 44d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt /* 45d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt * 0 .. NR_PMB_ENTRIES for specific entry selection, or 46d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt * PMB_NO_ENTRY to search for a free one 47d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt */ 48d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt int entry; 49d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 50d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt /* Adjacent entry link for contiguous multi-entry mappings */ 51d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt struct pmb_entry *link; 52d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt}; 53d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 5490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundtstatic struct { 5590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt unsigned long size; 5690e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt int flag; 5790e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt} pmb_sizes[] = { 5890e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt { .size = SZ_512M, .flag = PMB_SZ_512M, }, 5990e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt { .size = SZ_128M, .flag = PMB_SZ_128M, }, 6090e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt { .size = SZ_64M, .flag = PMB_SZ_64M, }, 6190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt { .size = SZ_16M, .flag = PMB_SZ_16M, }, 6290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt}; 6390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 64d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundtstatic void pmb_unmap_entry(struct pmb_entry *, int depth); 65fc2bdefdde89b54d8fcde7bbf7d0adc0ce5cb044Matt Fleming 66d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundtstatic DEFINE_RWLOCK(pmb_rwlock); 67edd7de803c79c7df117bf3f0e22ffdba1b1ef256Matt Flemingstatic struct pmb_entry pmb_entry_list[NR_PMB_ENTRIES]; 6851becfd96287b3913b13075699433730984e2f4fPaul Mundtstatic DECLARE_BITMAP(pmb_map, NR_PMB_ENTRIES); 690c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 704cfa8e75d6854699597e21fd570721d63f899934Paul Mundtstatic unsigned int pmb_iomapping_enabled; 714cfa8e75d6854699597e21fd570721d63f899934Paul Mundt 7251becfd96287b3913b13075699433730984e2f4fPaul Mundtstatic __always_inline unsigned long mk_pmb_entry(unsigned int entry) 730c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt{ 740c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt return (entry & PMB_E_MASK) << PMB_E_SHIFT; 750c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt} 760c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 7751becfd96287b3913b13075699433730984e2f4fPaul Mundtstatic __always_inline unsigned long mk_pmb_addr(unsigned int entry) 780c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt{ 790c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt return mk_pmb_entry(entry) | PMB_ADDR; 800c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt} 810c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8251becfd96287b3913b13075699433730984e2f4fPaul Mundtstatic __always_inline unsigned long mk_pmb_data(unsigned int entry) 830c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt{ 840c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt return mk_pmb_entry(entry) | PMB_DATA; 850c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt} 860c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8790e7d649d86f21d478dc134f74c88e19dd472393Paul Mundtstatic __always_inline unsigned int pmb_ppn_in_range(unsigned long ppn) 8890e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt{ 8990e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return ppn >= __pa(memory_start) && ppn < __pa(memory_end); 9090e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt} 9190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 9290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt/* 9390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt * Ensure that the PMB entries match our cache configuration. 9490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt * 9590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt * When we are in 32-bit address extended mode, CCR.CB becomes 9690e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt * invalid, so care must be taken to manually adjust cacheable 9790e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt * translations. 9890e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt */ 9990e7d649d86f21d478dc134f74c88e19dd472393Paul Mundtstatic __always_inline unsigned long pmb_cache_flags(void) 10090e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt{ 10190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt unsigned long flags = 0; 10290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 10390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt#if defined(CONFIG_CACHE_OFF) 10490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt flags |= PMB_WT | PMB_UB; 10590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt#elif defined(CONFIG_CACHE_WRITETHROUGH) 10690e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt flags |= PMB_C | PMB_WT | PMB_UB; 10790e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt#elif defined(CONFIG_CACHE_WRITEBACK) 10890e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt flags |= PMB_C; 10990e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt#endif 11090e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 11190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return flags; 11290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt} 11390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 11490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt/* 11590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt * Convert typical pgprot value to the PMB equivalent 11690e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt */ 11790e7d649d86f21d478dc134f74c88e19dd472393Paul Mundtstatic inline unsigned long pgprot_to_pmb_flags(pgprot_t prot) 11890e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt{ 11990e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt unsigned long pmb_flags = 0; 12090e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt u64 flags = pgprot_val(prot); 12190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 12290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt if (flags & _PAGE_CACHABLE) 12390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt pmb_flags |= PMB_C; 12490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt if (flags & _PAGE_WT) 12590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt pmb_flags |= PMB_WT | PMB_UB; 12690e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 12790e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return pmb_flags; 12890e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt} 12990e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 130a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundtstatic inline bool pmb_can_merge(struct pmb_entry *a, struct pmb_entry *b) 13190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt{ 13290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return (b->vpn == (a->vpn + a->size)) && 13390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt (b->ppn == (a->ppn + a->size)) && 13490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt (b->flags == a->flags); 13590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt} 13690e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 137a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundtstatic bool pmb_mapping_exists(unsigned long vaddr, phys_addr_t phys, 138a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt unsigned long size) 139a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt{ 140a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt int i; 141a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt 142a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt read_lock(&pmb_rwlock); 143a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt 144a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) { 145a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt struct pmb_entry *pmbe, *iter; 146a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt unsigned long span; 147a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt 148a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt if (!test_bit(i, pmb_map)) 149a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt continue; 150a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt 151a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt pmbe = &pmb_entry_list[i]; 152a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt 153a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt /* 154a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt * See if VPN and PPN are bounded by an existing mapping. 155a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt */ 156a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt if ((vaddr < pmbe->vpn) || (vaddr >= (pmbe->vpn + pmbe->size))) 157a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt continue; 158a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt if ((phys < pmbe->ppn) || (phys >= (pmbe->ppn + pmbe->size))) 159a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt continue; 160a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt 161a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt /* 162a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt * Now see if we're in range of a simple mapping. 163a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt */ 164a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt if (size <= pmbe->size) { 165a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt read_unlock(&pmb_rwlock); 166a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt return true; 167a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt } 168a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt 169a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt span = pmbe->size; 170a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt 171a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt /* 172a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt * Finally for sizes that involve compound mappings, walk 173a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt * the chain. 174a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt */ 175a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt for (iter = pmbe->link; iter; iter = iter->link) 176a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt span += iter->size; 177a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt 178a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt /* 179a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt * Nothing else to do if the range requirements are met. 180a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt */ 181a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt if (size <= span) { 182a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt read_unlock(&pmb_rwlock); 183a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt return true; 184a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt } 185a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt } 186a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt 187a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt read_unlock(&pmb_rwlock); 188a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt return false; 189a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt} 190a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt 19190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundtstatic bool pmb_size_valid(unsigned long size) 19290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt{ 19390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt int i; 19490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 19590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) 19690e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt if (pmb_sizes[i].size == size) 19790e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return true; 19890e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 19990e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return false; 20090e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt} 20190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 20290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundtstatic inline bool pmb_addr_valid(unsigned long addr, unsigned long size) 20390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt{ 20490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return (addr >= P1SEG && (addr + size - 1) < P3SEG); 20590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt} 20690e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 20790e7d649d86f21d478dc134f74c88e19dd472393Paul Mundtstatic inline bool pmb_prot_valid(pgprot_t prot) 20890e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt{ 20990e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return (pgprot_val(prot) & _PAGE_USER) == 0; 21090e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt} 21190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 21290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundtstatic int pmb_size_to_flags(unsigned long size) 21390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt{ 21490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt int i; 21590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 21690e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) 21790e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt if (pmb_sizes[i].size == size) 21890e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return pmb_sizes[i].flag; 21990e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 22090e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return 0; 22190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt} 22290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 223067784f6239e08a084b4d8d597e14435331eae51Matt Flemingstatic int pmb_alloc_entry(void) 224067784f6239e08a084b4d8d597e14435331eae51Matt Fleming{ 225d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt int pos; 226067784f6239e08a084b4d8d597e14435331eae51Matt Fleming 22751becfd96287b3913b13075699433730984e2f4fPaul Mundt pos = find_first_zero_bit(pmb_map, NR_PMB_ENTRIES); 228d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt if (pos >= 0 && pos < NR_PMB_ENTRIES) 229d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt __set_bit(pos, pmb_map); 230d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt else 231d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt pos = -ENOSPC; 232067784f6239e08a084b4d8d597e14435331eae51Matt Fleming 233067784f6239e08a084b4d8d597e14435331eae51Matt Fleming return pos; 234067784f6239e08a084b4d8d597e14435331eae51Matt Fleming} 235067784f6239e08a084b4d8d597e14435331eae51Matt Fleming 2368386aebb9e15a94137693ea4f4df84207f71cc75Matt Flemingstatic struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn, 23720b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming unsigned long flags, int entry) 2380c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt{ 2390c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt struct pmb_entry *pmbe; 240d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt unsigned long irqflags; 241d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt void *ret = NULL; 242067784f6239e08a084b4d8d597e14435331eae51Matt Fleming int pos; 243067784f6239e08a084b4d8d597e14435331eae51Matt Fleming 244d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt write_lock_irqsave(&pmb_rwlock, irqflags); 245d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 24620b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming if (entry == PMB_NO_ENTRY) { 24720b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming pos = pmb_alloc_entry(); 248d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt if (unlikely(pos < 0)) { 249d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt ret = ERR_PTR(pos); 250d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt goto out; 251d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt } 25220b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming } else { 253d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt if (__test_and_set_bit(entry, pmb_map)) { 254d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt ret = ERR_PTR(-ENOSPC); 255d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt goto out; 256d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt } 257d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 25820b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming pos = entry; 25920b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming } 2600c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 261d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt write_unlock_irqrestore(&pmb_rwlock, irqflags); 262d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 263edd7de803c79c7df117bf3f0e22ffdba1b1ef256Matt Fleming pmbe = &pmb_entry_list[pos]; 264d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 265d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt memset(pmbe, 0, sizeof(struct pmb_entry)); 266d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 267f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spin_lock_init(&pmbe->lock); 2680c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 2690c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt pmbe->vpn = vpn; 2700c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt pmbe->ppn = ppn; 2710c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt pmbe->flags = flags; 272067784f6239e08a084b4d8d597e14435331eae51Matt Fleming pmbe->entry = pos; 2730c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 2740c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt return pmbe; 275d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 276d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundtout: 277d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt write_unlock_irqrestore(&pmb_rwlock, irqflags); 278d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt return ret; 2790c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt} 2800c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 2818386aebb9e15a94137693ea4f4df84207f71cc75Matt Flemingstatic void pmb_free(struct pmb_entry *pmbe) 2820c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt{ 283d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt __clear_bit(pmbe->entry, pmb_map); 284d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 285d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmbe->entry = PMB_NO_ENTRY; 286d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmbe->link = NULL; 2870c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt} 2880c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 2890c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt/* 29051becfd96287b3913b13075699433730984e2f4fPaul Mundt * Must be run uncached. 2910c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt */ 292d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundtstatic void __set_pmb_entry(struct pmb_entry *pmbe) 2930c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt{ 294281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt unsigned long addr, data; 295281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt 296281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt addr = mk_pmb_addr(pmbe->entry); 297281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt data = mk_pmb_data(pmbe->entry); 298281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt 299281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt jump_to_uncached(); 300281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt 30190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt /* Set V-bit */ 302281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt __raw_writel(pmbe->vpn | PMB_V, addr); 303281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt __raw_writel(pmbe->ppn | pmbe->flags | PMB_V, data); 304281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt 305281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt back_to_cached(); 3060c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt} 3070c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 308d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundtstatic void __clear_pmb_entry(struct pmb_entry *pmbe) 3090c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt{ 3102e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt unsigned long addr, data; 3112e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt unsigned long addr_val, data_val; 3120c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 3132e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt addr = mk_pmb_addr(pmbe->entry); 3142e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt data = mk_pmb_data(pmbe->entry); 3150c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 3162e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt addr_val = __raw_readl(addr); 3172e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt data_val = __raw_readl(data); 3180c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 3192e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt /* Clear V-bit */ 3202e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt writel_uncached(addr_val & ~PMB_V, addr); 3212e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt writel_uncached(data_val & ~PMB_V, data); 3220c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt} 3230c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 3243fe0f36c7edcd20af0a3cafc68bdd62534c0a7f0Matt Fleming#ifdef CONFIG_PM 325d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundtstatic void set_pmb_entry(struct pmb_entry *pmbe) 326d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt{ 327d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt unsigned long flags; 328d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 329f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spin_lock_irqsave(&pmbe->lock, flags); 330d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt __set_pmb_entry(pmbe); 331f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spin_unlock_irqrestore(&pmbe->lock, flags); 332d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt} 3333fe0f36c7edcd20af0a3cafc68bdd62534c0a7f0Matt Fleming#endif /* CONFIG_PM */ 334d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 33590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundtint pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys, 33690e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt unsigned long size, pgprot_t prot) 33790e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt{ 338fc2bdefdde89b54d8fcde7bbf7d0adc0ce5cb044Matt Fleming struct pmb_entry *pmbp, *pmbe; 339281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt unsigned long orig_addr, orig_size; 340a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt unsigned long flags, pmb_flags; 34190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt int i, mapped; 34290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 343dfbca89987b74c34d9b1a2414b0e5ccee65347e0Paul Mundt if (size < SZ_16M) 344dfbca89987b74c34d9b1a2414b0e5ccee65347e0Paul Mundt return -EINVAL; 3456eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt if (!pmb_addr_valid(vaddr, size)) 3466eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt return -EFAULT; 347a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt if (pmb_mapping_exists(vaddr, phys, size)) 348a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt return 0; 3497bdda6209f224aa784a036df54b22cb338d2e859Paul Mundt 350281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt orig_addr = vaddr; 351281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt orig_size = size; 352281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt 353281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt flush_tlb_kernel_range(vaddr, vaddr + size); 354281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt 35590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt pmb_flags = pgprot_to_pmb_flags(prot); 3566eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt pmbp = NULL; 357d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt 358a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt do { 359a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt for (i = mapped = 0; i < ARRAY_SIZE(pmb_sizes); i++) { 360a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt if (size < pmb_sizes[i].size) 361a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt continue; 362d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt 363a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt pmbe = pmb_alloc(vaddr, phys, pmb_flags | 364a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt pmb_sizes[i].flag, PMB_NO_ENTRY); 365a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt if (IS_ERR(pmbe)) { 366a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt pmb_unmap_entry(pmbp, mapped); 367a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt return PTR_ERR(pmbe); 368a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt } 369d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 370f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spin_lock_irqsave(&pmbe->lock, flags); 371d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt 372a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt pmbe->size = pmb_sizes[i].size; 373d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt 374a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt __set_pmb_entry(pmbe); 375d7813bc9e8e384f5a293b05c095c799d41af3668Paul Mundt 376a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt phys += pmbe->size; 377a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt vaddr += pmbe->size; 378a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt size -= pmbe->size; 379d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt 380a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt /* 381a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt * Link adjacent entries that span multiple PMB 382a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt * entries for easier tear-down. 383a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt */ 384a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt if (likely(pmbp)) { 385f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spin_lock_nested(&pmbp->lock, 386f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt SINGLE_DEPTH_NESTING); 387a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt pmbp->link = pmbe; 388f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spin_unlock(&pmbp->lock); 389a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt } 390a2767cfb1d9d97c3f861743f1ad595a80b75ec99Matt Fleming 391a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt pmbp = pmbe; 392d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 393a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt /* 394a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt * Instead of trying smaller sizes on every 395a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt * iteration (even if we succeed in allocating 396a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt * space), try using pmb_sizes[i].size again. 397a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt */ 398a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt i--; 399a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt mapped++; 400d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt 401f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spin_unlock_irqrestore(&pmbe->lock, flags); 402a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt } 403a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt } while (size >= SZ_16M); 404d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt 405281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt flush_cache_vmap(orig_addr, orig_addr + orig_size); 406281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt 4076eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt return 0; 4086eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt} 4096eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt 4106eb3c735d29e799810ce82118f9260d0044327b7Paul Mundtvoid __iomem *pmb_remap_caller(phys_addr_t phys, unsigned long size, 4116eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt pgprot_t prot, void *caller) 4126eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt{ 413281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt unsigned long vaddr; 4146eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt phys_addr_t offset, last_addr; 4156eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt phys_addr_t align_mask; 4166eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt unsigned long aligned; 4176eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt struct vm_struct *area; 4186eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt int i, ret; 4196eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt 4206eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt if (!pmb_iomapping_enabled) 4216eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt return NULL; 4226eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt 4236eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt /* 4246eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt * Small mappings need to go through the TLB. 4256eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt */ 4266eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt if (size < SZ_16M) 4276eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt return ERR_PTR(-EINVAL); 4286eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt if (!pmb_prot_valid(prot)) 4296eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt return ERR_PTR(-EINVAL); 4306eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt 4316eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) 4326eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt if (size >= pmb_sizes[i].size) 4336eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt break; 4346eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt 4356eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt last_addr = phys + size; 4366eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt align_mask = ~(pmb_sizes[i].size - 1); 4376eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt offset = phys & ~align_mask; 4386eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt phys &= align_mask; 4396eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt aligned = ALIGN(last_addr, pmb_sizes[i].size) - phys; 4406eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt 441281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt /* 442281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt * XXX: This should really start from uncached_end, but this 443281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt * causes the MMU to reset, so for now we restrict it to the 444281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt * 0xb000...0xc000 range. 445281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt */ 446281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt area = __get_vm_area_caller(aligned, VM_IOREMAP, 0xb0000000, 4476eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt P3SEG, caller); 4486eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt if (!area) 4496eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt return NULL; 4506eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt 4516eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt area->phys_addr = phys; 452281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt vaddr = (unsigned long)area->addr; 4536eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt 4546eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt ret = pmb_bolt_mapping(vaddr, phys, size, prot); 455a1042aa248e4ea7f39d5ce13f080cbf3b6c42618Paul Mundt if (unlikely(ret != 0)) 4566eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt return ERR_PTR(ret); 4576eb3c735d29e799810ce82118f9260d0044327b7Paul Mundt 458281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt return (void __iomem *)(offset + (char *)vaddr); 459d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt} 460d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt 46190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundtint pmb_unmap(void __iomem *addr) 462d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt{ 463d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt struct pmb_entry *pmbe = NULL; 46490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt unsigned long vaddr = (unsigned long __force)addr; 46590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt int i, found = 0; 466d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt 467d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt read_lock(&pmb_rwlock); 468d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 469edd7de803c79c7df117bf3f0e22ffdba1b1ef256Matt Fleming for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) { 47051becfd96287b3913b13075699433730984e2f4fPaul Mundt if (test_bit(i, pmb_map)) { 471edd7de803c79c7df117bf3f0e22ffdba1b1ef256Matt Fleming pmbe = &pmb_entry_list[i]; 47290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt if (pmbe->vpn == vaddr) { 47390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt found = 1; 474edd7de803c79c7df117bf3f0e22ffdba1b1ef256Matt Fleming break; 47590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt } 476edd7de803c79c7df117bf3f0e22ffdba1b1ef256Matt Fleming } 477edd7de803c79c7df117bf3f0e22ffdba1b1ef256Matt Fleming } 478d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 479d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt read_unlock(&pmb_rwlock); 480d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 48190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt if (found) { 48290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt pmb_unmap_entry(pmbe, NR_PMB_ENTRIES); 48390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return 0; 48490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt } 485d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt 48690e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return -EINVAL; 487d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt} 488d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 489d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundtstatic void __pmb_unmap_entry(struct pmb_entry *pmbe, int depth) 490d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt{ 491d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt do { 492d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt struct pmb_entry *pmblink = pmbe; 493d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt 494067784f6239e08a084b4d8d597e14435331eae51Matt Fleming /* 495067784f6239e08a084b4d8d597e14435331eae51Matt Fleming * We may be called before this pmb_entry has been 496067784f6239e08a084b4d8d597e14435331eae51Matt Fleming * entered into the PMB table via set_pmb_entry(), but 497067784f6239e08a084b4d8d597e14435331eae51Matt Fleming * that's OK because we've allocated a unique slot for 498067784f6239e08a084b4d8d597e14435331eae51Matt Fleming * this entry in pmb_alloc() (even if we haven't filled 499067784f6239e08a084b4d8d597e14435331eae51Matt Fleming * it yet). 500067784f6239e08a084b4d8d597e14435331eae51Matt Fleming * 501d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt * Therefore, calling __clear_pmb_entry() is safe as no 502067784f6239e08a084b4d8d597e14435331eae51Matt Fleming * other mapping can be using that slot. 503067784f6239e08a084b4d8d597e14435331eae51Matt Fleming */ 504d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt __clear_pmb_entry(pmbe); 505fc2bdefdde89b54d8fcde7bbf7d0adc0ce5cb044Matt Fleming 506281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt flush_cache_vunmap(pmbe->vpn, pmbe->vpn + pmbe->size); 507281983d6ff2674ca2e4868de628c65809d84fa4cPaul Mundt 508d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt pmbe = pmblink->link; 509d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt 510d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt pmb_free(pmblink); 511d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt } while (pmbe && --depth); 512d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt} 513d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 514d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundtstatic void pmb_unmap_entry(struct pmb_entry *pmbe, int depth) 515d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt{ 516d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt unsigned long flags; 517d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 518d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt if (unlikely(!pmbe)) 519d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt return; 520d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 521d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt write_lock_irqsave(&pmb_rwlock, flags); 522d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt __pmb_unmap_entry(pmbe, depth); 523d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt write_unlock_irqrestore(&pmb_rwlock, flags); 524d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt} 525d7cdc9e8ac82c43fdcd4fde6b5b53d2dcba7f707Paul Mundt 526d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundtstatic void __init pmb_notify(void) 52720b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming{ 528d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt int i; 52920b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming 530efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt pr_info("PMB: boot mappings:\n"); 53120b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming 532d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt read_lock(&pmb_rwlock); 533d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 534d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) { 535d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt struct pmb_entry *pmbe; 536d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 537d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt if (!test_bit(i, pmb_map)) 538d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt continue; 539d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 540d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmbe = &pmb_entry_list[i]; 541d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 542d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pr_info(" 0x%08lx -> 0x%08lx [ %4ldMB %2scached ]\n", 543d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmbe->vpn >> PAGE_SHIFT, pmbe->ppn >> PAGE_SHIFT, 544d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmbe->size >> 20, (pmbe->flags & PMB_C) ? "" : "un"); 545d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt } 546d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 547d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt read_unlock(&pmb_rwlock); 548d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt} 549d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 550d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt/* 551d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt * Sync our software copy of the PMB mappings with those in hardware. The 552d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt * mappings in the hardware PMB were either set up by the bootloader or 553d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt * very early on by the kernel. 554d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt */ 555d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundtstatic void __init pmb_synchronize(void) 556d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt{ 557d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt struct pmb_entry *pmbp = NULL; 558d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt int i, j; 559d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 5603d467676abf5f01f5ee99056273a58486968e252Matt Fleming /* 561efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt * Run through the initial boot mappings, log the established 562efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt * ones, and blow away anything that falls outside of the valid 563efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt * PPN range. Specifically, we only care about existing mappings 564efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt * that impact the cached/uncached sections. 5653d467676abf5f01f5ee99056273a58486968e252Matt Fleming * 566efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt * Note that touching these can be a bit of a minefield; the boot 567efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt * loader can establish multi-page mappings with the same caching 568efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt * attributes, so we need to ensure that we aren't modifying a 569efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt * mapping that we're presently executing from, or may execute 570efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt * from in the case of straddling page boundaries. 5713d467676abf5f01f5ee99056273a58486968e252Matt Fleming * 572efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt * In the future we will have to tidy up after the boot loader by 573efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt * jumping between the cached and uncached mappings and tearing 574efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt * down alternating mappings while executing from the other. 5753d467676abf5f01f5ee99056273a58486968e252Matt Fleming */ 57651becfd96287b3913b13075699433730984e2f4fPaul Mundt for (i = 0; i < NR_PMB_ENTRIES; i++) { 5773d467676abf5f01f5ee99056273a58486968e252Matt Fleming unsigned long addr, data; 5783d467676abf5f01f5ee99056273a58486968e252Matt Fleming unsigned long addr_val, data_val; 579efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt unsigned long ppn, vpn, flags; 580d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt unsigned long irqflags; 581d7813bc9e8e384f5a293b05c095c799d41af3668Paul Mundt unsigned int size; 582efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt struct pmb_entry *pmbe; 58320b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming 5843d467676abf5f01f5ee99056273a58486968e252Matt Fleming addr = mk_pmb_addr(i); 5853d467676abf5f01f5ee99056273a58486968e252Matt Fleming data = mk_pmb_data(i); 58620b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming 5873d467676abf5f01f5ee99056273a58486968e252Matt Fleming addr_val = __raw_readl(addr); 5883d467676abf5f01f5ee99056273a58486968e252Matt Fleming data_val = __raw_readl(data); 58920b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming 5903d467676abf5f01f5ee99056273a58486968e252Matt Fleming /* 5913d467676abf5f01f5ee99056273a58486968e252Matt Fleming * Skip over any bogus entries 5923d467676abf5f01f5ee99056273a58486968e252Matt Fleming */ 5933d467676abf5f01f5ee99056273a58486968e252Matt Fleming if (!(data_val & PMB_V) || !(addr_val & PMB_V)) 5943d467676abf5f01f5ee99056273a58486968e252Matt Fleming continue; 59520b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming 5963d467676abf5f01f5ee99056273a58486968e252Matt Fleming ppn = data_val & PMB_PFN_MASK; 5973d467676abf5f01f5ee99056273a58486968e252Matt Fleming vpn = addr_val & PMB_PFN_MASK; 598a0ab36689a36e583b6e736f1c99ac8c9aebdad59Paul Mundt 5993d467676abf5f01f5ee99056273a58486968e252Matt Fleming /* 6003d467676abf5f01f5ee99056273a58486968e252Matt Fleming * Only preserve in-range mappings. 6013d467676abf5f01f5ee99056273a58486968e252Matt Fleming */ 602efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt if (!pmb_ppn_in_range(ppn)) { 6033d467676abf5f01f5ee99056273a58486968e252Matt Fleming /* 6043d467676abf5f01f5ee99056273a58486968e252Matt Fleming * Invalidate anything out of bounds. 6053d467676abf5f01f5ee99056273a58486968e252Matt Fleming */ 6062e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt writel_uncached(addr_val & ~PMB_V, addr); 6072e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt writel_uncached(data_val & ~PMB_V, data); 608efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt continue; 6093d467676abf5f01f5ee99056273a58486968e252Matt Fleming } 610efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt 611efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt /* 612efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt * Update the caching attributes if necessary 613efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt */ 614efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt if (data_val & PMB_C) { 6150065b96775f1eff167a2c3343a41582e8fab4c6cPaul Mundt data_val &= ~PMB_CACHE_MASK; 6160065b96775f1eff167a2c3343a41582e8fab4c6cPaul Mundt data_val |= pmb_cache_flags(); 6172e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt 6182e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt writel_uncached(data_val, data); 619efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt } 620efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt 621d7813bc9e8e384f5a293b05c095c799d41af3668Paul Mundt size = data_val & PMB_SZ_MASK; 622d7813bc9e8e384f5a293b05c095c799d41af3668Paul Mundt flags = size | (data_val & PMB_CACHE_MASK); 623efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt 624efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt pmbe = pmb_alloc(vpn, ppn, flags, i); 625efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt if (IS_ERR(pmbe)) { 626efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt WARN_ON_ONCE(1); 627efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt continue; 628efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt } 629efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt 630f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spin_lock_irqsave(&pmbe->lock, irqflags); 631d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 632d7813bc9e8e384f5a293b05c095c799d41af3668Paul Mundt for (j = 0; j < ARRAY_SIZE(pmb_sizes); j++) 633d7813bc9e8e384f5a293b05c095c799d41af3668Paul Mundt if (pmb_sizes[j].flag == size) 634d7813bc9e8e384f5a293b05c095c799d41af3668Paul Mundt pmbe->size = pmb_sizes[j].size; 635d7813bc9e8e384f5a293b05c095c799d41af3668Paul Mundt 636d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt if (pmbp) { 637f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spin_lock_nested(&pmbp->lock, SINGLE_DEPTH_NESTING); 638d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt /* 639d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt * Compare the previous entry against the current one to 640d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt * see if the entries span a contiguous mapping. If so, 641d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt * setup the entry links accordingly. Compound mappings 642d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt * are later coalesced. 643d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt */ 644d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt if (pmb_can_merge(pmbp, pmbe)) 645d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt pmbp->link = pmbe; 646f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spin_unlock(&pmbp->lock); 647d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt } 648d7813bc9e8e384f5a293b05c095c799d41af3668Paul Mundt 649d7813bc9e8e384f5a293b05c095c799d41af3668Paul Mundt pmbp = pmbe; 650d7813bc9e8e384f5a293b05c095c799d41af3668Paul Mundt 651f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spin_unlock_irqrestore(&pmbe->lock, irqflags); 652d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt } 653d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt} 654d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 655d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundtstatic void __init pmb_merge(struct pmb_entry *head) 656d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt{ 657d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt unsigned long span, newsize; 658d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt struct pmb_entry *tail; 659d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt int i = 1, depth = 0; 660d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 661d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt span = newsize = head->size; 662efd54ea315f645ef318708aab5714a5f1f432d03Paul Mundt 663d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt tail = head->link; 664d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt while (tail) { 665d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt span += tail->size; 666d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 667d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt if (pmb_size_valid(span)) { 668d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt newsize = span; 669d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt depth = i; 670d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt } 671d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 672d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt /* This is the end of the line.. */ 673d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt if (!tail->link) 674d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt break; 675d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 676d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt tail = tail->link; 677d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt i++; 678a0ab36689a36e583b6e736f1c99ac8c9aebdad59Paul Mundt } 679a0ab36689a36e583b6e736f1c99ac8c9aebdad59Paul Mundt 680d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt /* 681d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt * The merged page size must be valid. 682d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt */ 683c7b03fa0bdc04e00bfbdc4cc69da144b11108f37Matt Fleming if (!depth || !pmb_size_valid(newsize)) 684d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt return; 685d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 686d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt head->flags &= ~PMB_SZ_MASK; 687d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt head->flags |= pmb_size_to_flags(newsize); 688d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 689d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt head->size = newsize; 690d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 691d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt __pmb_unmap_entry(head->link, depth); 692d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt __set_pmb_entry(head); 693a0ab36689a36e583b6e736f1c99ac8c9aebdad59Paul Mundt} 694a0ab36689a36e583b6e736f1c99ac8c9aebdad59Paul Mundt 695d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundtstatic void __init pmb_coalesce(void) 696a0ab36689a36e583b6e736f1c99ac8c9aebdad59Paul Mundt{ 697d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt unsigned long flags; 698d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt int i; 699d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 700d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt write_lock_irqsave(&pmb_rwlock, flags); 701d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 702d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) { 703d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt struct pmb_entry *pmbe; 704d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 705d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt if (!test_bit(i, pmb_map)) 706d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt continue; 707d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 708d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmbe = &pmb_entry_list[i]; 709d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 710d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt /* 711d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt * We're only interested in compound mappings 712d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt */ 713d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt if (!pmbe->link) 714d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt continue; 715d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 716d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt /* 717d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt * Nothing to do if it already uses the largest possible 718d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt * page size. 719d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt */ 720d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt if (pmbe->size == SZ_512M) 721d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt continue; 722d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 723d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmb_merge(pmbe); 724d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt } 725d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 726d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt write_unlock_irqrestore(&pmb_rwlock, flags); 727d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt} 728d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 729d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt#ifdef CONFIG_UNCACHED_MAPPING 730d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundtstatic void __init pmb_resize(void) 731d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt{ 732d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt int i; 733a0ab36689a36e583b6e736f1c99ac8c9aebdad59Paul Mundt 734a0ab36689a36e583b6e736f1c99ac8c9aebdad59Paul Mundt /* 735d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt * If the uncached mapping was constructed by the kernel, it will 736d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt * already be a reasonable size. 737a0ab36689a36e583b6e736f1c99ac8c9aebdad59Paul Mundt */ 738d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt if (uncached_size == SZ_16M) 739d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt return; 740d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 741d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt read_lock(&pmb_rwlock); 742d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 743d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) { 744d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt struct pmb_entry *pmbe; 745d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt unsigned long flags; 746d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 747d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt if (!test_bit(i, pmb_map)) 748d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt continue; 749d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 750d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmbe = &pmb_entry_list[i]; 751d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 752d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt if (pmbe->vpn != uncached_start) 753d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt continue; 754d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 755d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt /* 756d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt * Found it, now resize it. 757d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt */ 758f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spin_lock_irqsave(&pmbe->lock, flags); 759d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 760d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmbe->size = SZ_16M; 761d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmbe->flags &= ~PMB_SZ_MASK; 762d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmbe->flags |= pmb_size_to_flags(pmbe->size); 763d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 764d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt uncached_resize(pmbe->size); 765d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 766d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt __set_pmb_entry(pmbe); 767d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 768f7fcec93b619337feb9da829b8a9ab6ba86393bcPaul Mundt raw_spin_unlock_irqrestore(&pmbe->lock, flags); 769d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt } 770d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 7710e6f989ba83e6fa64e979d3488f01670b8be7959Julia Lawall read_unlock(&pmb_rwlock); 772d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt} 773d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt#endif 774d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 7754cfa8e75d6854699597e21fd570721d63f899934Paul Mundtstatic int __init early_pmb(char *p) 7764cfa8e75d6854699597e21fd570721d63f899934Paul Mundt{ 7774cfa8e75d6854699597e21fd570721d63f899934Paul Mundt if (!p) 7784cfa8e75d6854699597e21fd570721d63f899934Paul Mundt return 0; 7794cfa8e75d6854699597e21fd570721d63f899934Paul Mundt 7804cfa8e75d6854699597e21fd570721d63f899934Paul Mundt if (strstr(p, "iomap")) 7814cfa8e75d6854699597e21fd570721d63f899934Paul Mundt pmb_iomapping_enabled = 1; 7824cfa8e75d6854699597e21fd570721d63f899934Paul Mundt 7834cfa8e75d6854699597e21fd570721d63f899934Paul Mundt return 0; 7844cfa8e75d6854699597e21fd570721d63f899934Paul Mundt} 7854cfa8e75d6854699597e21fd570721d63f899934Paul Mundtearly_param("pmb", early_pmb); 7864cfa8e75d6854699597e21fd570721d63f899934Paul Mundt 787d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundtvoid __init pmb_init(void) 788d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt{ 789d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt /* Synchronize software state */ 790d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmb_synchronize(); 791d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 792d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt /* Attempt to combine compound mappings */ 793d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmb_coalesce(); 794d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 795d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt#ifdef CONFIG_UNCACHED_MAPPING 796d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt /* Resize initial mappings, if necessary */ 797d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmb_resize(); 798d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt#endif 799d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt 800d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt /* Log them */ 801d01447b3197c2c470a14666be2c640407bbbfec7Paul Mundt pmb_notify(); 8023d467676abf5f01f5ee99056273a58486968e252Matt Fleming 8032e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt writel_uncached(0, PMB_IRMCR); 804a0ab36689a36e583b6e736f1c99ac8c9aebdad59Paul Mundt 805a0ab36689a36e583b6e736f1c99ac8c9aebdad59Paul Mundt /* Flush out the TLB */ 806b5b6c7eea1124de5b110a48ac62650a690ed2419Matt Fleming local_flush_tlb_all(); 8072e450643d70b62e0192577681b227d7d5d2efa45Paul Mundt ctrl_barrier(); 80820b5014b3e5fe7b874a3f6a1dc03b0c21cb222cdMatt Fleming} 8090c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8102efa53b269ec1e9289a108e1506f53f6f1de440bPaul Mundtbool __in_29bit_mode(void) 8112efa53b269ec1e9289a108e1506f53f6f1de440bPaul Mundt{ 8122efa53b269ec1e9289a108e1506f53f6f1de440bPaul Mundt return (__raw_readl(PMB_PASCR) & PASCR_SE) == 0; 8132efa53b269ec1e9289a108e1506f53f6f1de440bPaul Mundt} 8142efa53b269ec1e9289a108e1506f53f6f1de440bPaul Mundt 8150c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundtstatic int pmb_seq_show(struct seq_file *file, void *iter) 8160c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt{ 8170c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt int i; 8180c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8190c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt seq_printf(file, "V: Valid, C: Cacheable, WT: Write-Through\n" 8200c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt "CB: Copy-Back, B: Buffered, UB: Unbuffered\n"); 8210c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt seq_printf(file, "ety vpn ppn size flags\n"); 8220c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8230c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt for (i = 0; i < NR_PMB_ENTRIES; i++) { 8240c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt unsigned long addr, data; 8250c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt unsigned int size; 8260c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt char *sz_str = NULL; 8270c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8289d56dd3b083a3bec56e9da35ce07baca81030b03Paul Mundt addr = __raw_readl(mk_pmb_addr(i)); 8299d56dd3b083a3bec56e9da35ce07baca81030b03Paul Mundt data = __raw_readl(mk_pmb_data(i)); 8300c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8310c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt size = data & PMB_SZ_MASK; 8320c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt sz_str = (size == PMB_SZ_16M) ? " 16MB": 8330c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt (size == PMB_SZ_64M) ? " 64MB": 8340c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt (size == PMB_SZ_128M) ? "128MB": 8350c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt "512MB"; 8360c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8370c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt /* 02: V 0x88 0x08 128MB C CB B */ 8380c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt seq_printf(file, "%02d: %c 0x%02lx 0x%02lx %s %c %s %s\n", 8390c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt i, ((addr & PMB_V) && (data & PMB_V)) ? 'V' : ' ', 8400c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt (addr >> 24) & 0xff, (data >> 24) & 0xff, 8410c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt sz_str, (data & PMB_C) ? 'C' : ' ', 8420c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt (data & PMB_WT) ? "WT" : "CB", 8430c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt (data & PMB_UB) ? "UB" : " B"); 8440c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt } 8450c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8460c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt return 0; 8470c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt} 8480c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8490c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundtstatic int pmb_debugfs_open(struct inode *inode, struct file *file) 8500c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt{ 8510c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt return single_open(file, pmb_seq_show, NULL); 8520c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt} 8530c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8545dfe4c964a0dd7bb3a1d64a4166835a153146207Arjan van de Venstatic const struct file_operations pmb_debugfs_fops = { 8550c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt .owner = THIS_MODULE, 8560c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt .open = pmb_debugfs_open, 8570c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt .read = seq_read, 8580c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt .llseek = seq_lseek, 85945dabf1427a0a876f733b07239ade1bdb0e06010Li Zefan .release = single_release, 8600c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt}; 8610c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8620c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundtstatic int __init pmb_debugfs_init(void) 8630c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt{ 8640c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt struct dentry *dentry; 8650c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8660c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt dentry = debugfs_create_file("pmb", S_IFREG | S_IRUGO, 8673f224f4e057ce67713f3e7a8890f2fbe12d047a5Paul Mundt arch_debugfs_dir, NULL, &pmb_debugfs_fops); 86825627c7fd71269e2658b6872eef65719ee80b9aaZhaolei if (!dentry) 86925627c7fd71269e2658b6872eef65719ee80b9aaZhaolei return -ENOMEM; 8700c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt 8710c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt return 0; 8720c7b1df69c62209db19d1279dd882b37c04c5c2fPaul Mundt} 87362c8cbbfc2367e706317f56ac21959120ae72773Pawel Mollsubsys_initcall(pmb_debugfs_init); 874a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZI 875a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZI#ifdef CONFIG_PM 876d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundtstatic void pmb_syscore_resume(void) 877a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZI{ 878d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundt struct pmb_entry *pmbe; 879edd7de803c79c7df117bf3f0e22ffdba1b1ef256Matt Fleming int i; 880a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZI 881d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundt read_lock(&pmb_rwlock); 882d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 883d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundt for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) { 884d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundt if (test_bit(i, pmb_map)) { 885d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundt pmbe = &pmb_entry_list[i]; 886d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundt set_pmb_entry(pmbe); 887edd7de803c79c7df117bf3f0e22ffdba1b1ef256Matt Fleming } 888a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZI } 889d53a0d33bc3a50ea0e8dd1680a2e8435770b162aPaul Mundt 890d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundt read_unlock(&pmb_rwlock); 891a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZI} 892a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZI 893d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundtstatic struct syscore_ops pmb_syscore_ops = { 894d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundt .resume = pmb_syscore_resume, 895a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZI}; 896a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZI 897a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZIstatic int __init pmb_sysdev_init(void) 898a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZI{ 899d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundt register_syscore_ops(&pmb_syscore_ops); 900d4cc183f7b9f639a048291e9cd95f0c255664b98Paul Mundt return 0; 901a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZI} 902a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZIsubsys_initcall(pmb_sysdev_init); 903a83c0b739f3ad1887704cfa9f1ee5ee208cf1532Francesco VIRLINZI#endif 904