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)
int offset, count; /* siamese twins */
int off_new;
int align1;
int i;
int i, color;
if (t->num_colors) {
/* 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;
if ((align & align1) != 0)
BUG();
......@@ -40,6 +47,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
BUG();
if (len <= 0 || len > t->size)
BUG();
color &= align1;
spin_lock(&t->lock);
if (len < t->last_size)
......@@ -49,7 +57,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
count = 0;
for (;;) {
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;
offset = off_new;
if (offset >= t->size)
......@@ -121,6 +129,4 @@ void bit_map_init(struct bit_map *t, unsigned long *map, int size)
spin_lock_init(&t->lock);
t->map = map;
t->size = size;
t->last_size = 0;
t->first_free = 0;
}
......@@ -119,6 +119,13 @@ iommu_init(int iommund, struct sbus_bus *sbus)
prom_halt();
}
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",
impl, vers, iommu->page_table,
......@@ -128,7 +135,9 @@ iommu_init(int iommund, struct sbus_bus *sbus)
}
/* 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 end;
......@@ -145,6 +154,11 @@ static void iommu_viking_flush_iotlb(iopte_t *iopte, unsigned int niopte)
viking_flush_page(start);
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)
unsigned int busa, busa0;
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)
panic("iommu out");
busa0 = iommu->start + (ioptex << PAGE_SHIFT);
......@@ -172,8 +187,7 @@ static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus)
page++;
}
iommu_viking_flush_iotlb(iopte0, npages);
flush_cache_all(); // hack to fix dma errors with hypersparc
iommu_flush_iotlb(iopte0, npages);
return busa0;
}
......@@ -328,7 +342,9 @@ static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
if ((addr & ~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)
panic("iommu out");
......@@ -372,7 +388,7 @@ static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
* to handle the latter case as well.
*/
flush_cache_all();
iommu_viking_flush_iotlb(first, len >> PAGE_SHIFT);
iommu_flush_iotlb(first, len >> PAGE_SHIFT);
flush_tlb_all();
iommu_invalidate(iommu->regs);
......
......@@ -17,6 +17,7 @@ struct bit_map {
int last_off;
int last_size;
int first_free;
int num_colors;
};
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