Commit 0f86e14f authored by William Lee Irwin III's avatar William Lee Irwin III Committed by Linus Torvalds

[PATCH] sparc32: fix hypersparc dvma

DVMA is having aliasing problems. Bob originally sent in the following
description:

At some point in the past, Bob Breuer wrote:
> Here's the preliminary patch.  This time around, both the hme
> and esp drivers are working for me.  This replaces my previous
> patch and is against the vanilla 2.6.9 kernel.  I've tried to
> reduce the amount of unnecessary cache flushing, therefore this
> will need some testing on non-hypersparc cpus also.  It needs
> some cleanup yet, and will be rediffed against a later kernel.
> I'm looking for comments and feedback.

This patch represents one of those subsequent rediffings.
Signed-off-by: default avatarBob Breuer <breuerr@mc.net>
Acked-by: default avatarWilliam Irwin <wli@holomorphy.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 8b83153e
...@@ -29,10 +29,17 @@ int bit_map_string_get(struct bit_map *t, int len, int align) ...@@ -29,10 +29,17 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
int offset, count; /* siamese twins */ int offset, count; /* siamese twins */
int off_new; int off_new;
int align1; int align1;
int i; int i, color;
if (align == 0) if (t->num_colors) {
align = 1; /* align is overloaded to be the page color */
color = align;
align = t->num_colors;
} else {
color = 0;
if (align == 0)
align = 1;
}
align1 = align - 1; align1 = align - 1;
if ((align & align1) != 0) if ((align & align1) != 0)
BUG(); BUG();
...@@ -40,6 +47,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align) ...@@ -40,6 +47,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
BUG(); BUG();
if (len <= 0 || len > t->size) if (len <= 0 || len > t->size)
BUG(); BUG();
color &= align1;
spin_lock(&t->lock); spin_lock(&t->lock);
if (len < t->last_size) if (len < t->last_size)
...@@ -49,7 +57,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align) ...@@ -49,7 +57,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
count = 0; count = 0;
for (;;) { for (;;) {
off_new = find_next_zero_bit(t->map, t->size, offset); off_new = find_next_zero_bit(t->map, t->size, offset);
off_new = (off_new + align1) & ~align1; off_new = ((off_new + align1) & ~align1) + color;
count += off_new - offset; count += off_new - offset;
offset = off_new; offset = off_new;
if (offset >= t->size) if (offset >= t->size)
...@@ -121,6 +129,4 @@ void bit_map_init(struct bit_map *t, unsigned long *map, int size) ...@@ -121,6 +129,4 @@ void bit_map_init(struct bit_map *t, unsigned long *map, int size)
spin_lock_init(&t->lock); spin_lock_init(&t->lock);
t->map = map; t->map = map;
t->size = size; t->size = size;
t->last_size = 0;
t->first_free = 0;
} }
...@@ -119,6 +119,13 @@ iommu_init(int iommund, struct sbus_bus *sbus) ...@@ -119,6 +119,13 @@ iommu_init(int iommund, struct sbus_bus *sbus)
prom_halt(); prom_halt();
} }
bit_map_init(&iommu->usemap, bitmap, IOMMU_NPTES); bit_map_init(&iommu->usemap, bitmap, IOMMU_NPTES);
/* To be coherent on HyperSparc, the page color of DVMA
* and physical addresses must match.
*/
if (srmmu_modtype == HyperSparc)
iommu->usemap.num_colors = vac_cache_size >> PAGE_SHIFT;
else
iommu->usemap.num_colors = 1;
printk("IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n", printk("IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n",
impl, vers, iommu->page_table, impl, vers, iommu->page_table,
...@@ -128,7 +135,9 @@ iommu_init(int iommund, struct sbus_bus *sbus) ...@@ -128,7 +135,9 @@ iommu_init(int iommund, struct sbus_bus *sbus)
} }
/* This begs to be btfixup-ed by srmmu. */ /* This begs to be btfixup-ed by srmmu. */
static void iommu_viking_flush_iotlb(iopte_t *iopte, unsigned int niopte) /* Flush the iotlb entries to ram. */
/* This could be better if we didn't have to flush whole pages. */
static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte)
{ {
unsigned long start; unsigned long start;
unsigned long end; unsigned long end;
...@@ -145,6 +154,11 @@ static void iommu_viking_flush_iotlb(iopte_t *iopte, unsigned int niopte) ...@@ -145,6 +154,11 @@ static void iommu_viking_flush_iotlb(iopte_t *iopte, unsigned int niopte)
viking_flush_page(start); viking_flush_page(start);
start += PAGE_SIZE; start += PAGE_SIZE;
} }
} else {
while(start < end) {
__flush_page_to_ram(start);
start += PAGE_SIZE;
}
} }
} }
...@@ -156,7 +170,8 @@ static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus) ...@@ -156,7 +170,8 @@ static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus)
unsigned int busa, busa0; unsigned int busa, busa0;
int i; int i;
ioptex = bit_map_string_get(&iommu->usemap, npages, 1); /* page color = pfn of page */
ioptex = bit_map_string_get(&iommu->usemap, npages, page_to_pfn(page));
if (ioptex < 0) if (ioptex < 0)
panic("iommu out"); panic("iommu out");
busa0 = iommu->start + (ioptex << PAGE_SHIFT); busa0 = iommu->start + (ioptex << PAGE_SHIFT);
...@@ -172,8 +187,7 @@ static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus) ...@@ -172,8 +187,7 @@ static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus)
page++; page++;
} }
iommu_viking_flush_iotlb(iopte0, npages); iommu_flush_iotlb(iopte0, npages);
flush_cache_all(); // hack to fix dma errors with hypersparc
return busa0; return busa0;
} }
...@@ -328,7 +342,9 @@ static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va, ...@@ -328,7 +342,9 @@ static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
if ((addr & ~PAGE_MASK) != 0) BUG(); if ((addr & ~PAGE_MASK) != 0) BUG();
if ((len & ~PAGE_MASK) != 0) BUG(); if ((len & ~PAGE_MASK) != 0) BUG();
ioptex = bit_map_string_get(&iommu->usemap, len >> PAGE_SHIFT, 1); /* page color = physical address */
ioptex = bit_map_string_get(&iommu->usemap, len >> PAGE_SHIFT,
addr >> PAGE_SHIFT);
if (ioptex < 0) if (ioptex < 0)
panic("iommu out"); panic("iommu out");
...@@ -372,7 +388,7 @@ static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va, ...@@ -372,7 +388,7 @@ static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
* to handle the latter case as well. * to handle the latter case as well.
*/ */
flush_cache_all(); flush_cache_all();
iommu_viking_flush_iotlb(first, len >> PAGE_SHIFT); iommu_flush_iotlb(first, len >> PAGE_SHIFT);
flush_tlb_all(); flush_tlb_all();
iommu_invalidate(iommu->regs); iommu_invalidate(iommu->regs);
......
...@@ -17,6 +17,7 @@ struct bit_map { ...@@ -17,6 +17,7 @@ struct bit_map {
int last_off; int last_off;
int last_size; int last_size;
int first_free; int first_free;
int num_colors;
}; };
extern int bit_map_string_get(struct bit_map *t, int len, int align); extern int bit_map_string_get(struct bit_map *t, int len, int align);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment