@@ -64,6 +64,8 @@ config SPARC32
select HAVE_UID16
select HAVE_PAGE_SIZE_4KB
select LOCK_MM_AND_FIND_VMA
+ select MMU_GATHER_RCU_TABLE_FREE
+ select HAVE_ARCH_TLB_REMOVE_TABLE
select OLD_SIGACTION
select ZONE_DMA
@@ -48,7 +48,9 @@ static inline void free_pmd_fast(pmd_t * pmd)
}
#define pmd_free(mm, pmd) free_pmd_fast(pmd)
-#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd)
+
+#define __pmd_free_tlb(tlb, pmd, addr) \
+ tlb_remove_table((tlb), (void *)((unsigned long)(pmd) | 1UL))
#define pmd_populate(mm, pmd, pte) pmd_set(pmd, pte)
@@ -72,6 +74,7 @@ static inline void free_pte_fast(pte_t *pte)
#define pte_free_kernel(mm, pte) free_pte_fast(pte)
void pte_free(struct mm_struct * mm, pgtable_t pte);
-#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
+void __tlb_remove_table(void *table);
+#define __pte_free_tlb(tlb, pte, addr) tlb_remove_table((tlb), (void *)(pte))
#endif /* _SPARC_PGALLOC_H */
@@ -22,8 +22,6 @@
* @align: requested alignment
*
* Returns offset in the map or -1 if out of space.
- *
- * Not safe to call from an interrupt (uses spin_lock).
*/
int bit_map_string_get(struct bit_map *t, int len, int align)
{
@@ -31,6 +29,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
int off_new;
int align1;
int i, color;
+ unsigned long flags;
if (t->num_colors) {
/* align is overloaded to be the page color */
@@ -50,7 +49,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
BUG();
color &= align1;
- spin_lock(&t->lock);
+ spin_lock_irqsave(&t->lock, flags);
if (len < t->last_size)
offset = t->first_free;
else
@@ -64,7 +63,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
if (offset >= t->size)
offset = 0;
if (count + len > t->size) {
- spin_unlock(&t->lock);
+ spin_unlock_irqrestore(&t->lock, flags);
/* P3 */ printk(KERN_ERR
"bitmap out: size %d used %d off %d len %d align %d count %d\n",
t->size, t->used, offset, len, align, count);
@@ -90,7 +89,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
t->last_off = 0;
t->used += len;
t->last_size = len;
- spin_unlock(&t->lock);
+ spin_unlock_irqrestore(&t->lock, flags);
return offset;
}
}
@@ -103,10 +102,11 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
void bit_map_clear(struct bit_map *t, int offset, int len)
{
int i;
+ unsigned long flags;
if (t->used < len)
BUG(); /* Much too late to do any good, but alas... */
- spin_lock(&t->lock);
+ spin_lock_irqsave(&t->lock, flags);
for (i = 0; i < len; i++) {
if (test_bit(offset + i, t->map) == 0)
BUG();
@@ -115,7 +115,7 @@ void bit_map_clear(struct bit_map *t, int offset, int len)
if (offset < t->first_free)
t->first_free = offset;
t->used -= len;
- spin_unlock(&t->lock);
+ spin_unlock_irqrestore(&t->lock, flags);
}
void bit_map_init(struct bit_map *t, unsigned long *map, int size)
@@ -340,38 +340,60 @@ pgd_t *get_pgd_fast(void)
* Alignments up to the page size are the same for physical and virtual
* addresses of the nocache area.
*/
+
+static DEFINE_SPINLOCK(pte_page_lock);
+
pgtable_t pte_alloc_one(struct mm_struct *mm)
{
+ unsigned long flags;
pte_t *ptep;
struct page *page;
if (!(ptep = pte_alloc_one_kernel(mm)))
return NULL;
page = pfn_to_page(__nocache_pa((unsigned long)ptep) >> PAGE_SHIFT);
- spin_lock(&mm->page_table_lock);
+ spin_lock_irqsave(&pte_page_lock, flags);
if (page_ref_inc_return(page) == 2 &&
!pagetable_pte_ctor(mm, page_ptdesc(page))) {
page_ref_dec(page);
ptep = NULL;
}
- spin_unlock(&mm->page_table_lock);
+ spin_unlock_irqrestore(&pte_page_lock, flags);
return ptep;
}
-void pte_free(struct mm_struct *mm, pgtable_t ptep)
+static void __pte_free(pgtable_t ptep)
{
struct page *page;
+ unsigned long flags;
page = pfn_to_page(__nocache_pa((unsigned long)ptep) >> PAGE_SHIFT);
- spin_lock(&mm->page_table_lock);
+ spin_lock_irqsave(&pte_page_lock, flags);
if (page_ref_dec_return(page) == 1)
pagetable_dtor(page_ptdesc(page));
- spin_unlock(&mm->page_table_lock);
+ spin_unlock_irqrestore(&pte_page_lock, flags);
srmmu_free_nocache(ptep, SRMMU_PTE_TABLE_SIZE);
}
+void pte_free(struct mm_struct *mm, pgtable_t ptep)
+{
+ __pte_free(ptep);
+}
+
+void __tlb_remove_table(void *table)
+{
+ const unsigned long encoded = (unsigned long)table;
+ const unsigned long addr = encoded & ~1UL;
+ const bool is_pmd = encoded & 1;
+
+ if (is_pmd)
+ free_pmd_fast((pmd_t *)addr);
+ else
+ __pte_free((pgtable_t)addr);
+}
+
/* context handling - a dynamically sized pool is used */
#define NO_CONTEXT -1