GIT eb695dbf00d572a770358305dae4de2a0680db8f git+ssh://master.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.git commit Author: Adrian McMenamin Date: Tue Jul 24 13:30:55 2007 +0900 sh: Fix Dreamcast DMA issues. The current SH DMA API is somewhat broken, not correctly matching virtual channel to the correct SH DMAC. This wasn't noticeable when using g2 DMA for the sound driver - one channel 0 is as good as any other! - but caused the pvr2 driver to fail. This patch fixes the pvr2 problem and consequently fixes the sound driver to ensure it continues to function. Signed-off by: Adrian McMenamin Signed-off-by: Paul Mundt commit 8cf1a74305688c85fc8d23ab7432a0c447ee6413 Author: Paul Mundt Date: Tue Jul 24 13:28:26 2007 +0900 sh: Add kmap_coherent()/kunmap_coherent() interface for SH-4. This wires up kmap_coherent() and kunmap_coherent() on SH-4, and moves away from the p3map_mutex and reserved P3 space, opting to use fixmaps for colouring instead. The copy_user_page()/clear_user_page() implementations are moved to this, which fixes the nasty blowups with spinlock debugging as a result of having some of these calls nested under the page table lock. Signed-off-by: Paul Mundt arch/sh/drivers/dma/dma-api.c | 7 ++-- arch/sh/mm/cache-sh4.c | 11 ------ arch/sh/mm/pg-sh4.c | 75 +++++++++++++++++++---------------------- include/asm-sh/dma.h | 1 + include/asm-sh/fixmap.h | 8 +++- sound/sh/aica.h | 2 + 6 files changed, 45 insertions(+), 59 deletions(-) diff --git a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c index cf8e119..76ed816 100644 --- a/arch/sh/drivers/dma/dma-api.c +++ b/arch/sh/drivers/dma/dma-api.c @@ -31,8 +31,8 @@ struct dma_info *get_dma_info(unsigned i * the channel is. */ list_for_each_entry(info, ®istered_dmac_list, list) { - if ((chan < info->first_channel_nr) || - (chan >= info->first_channel_nr + info->nr_channels)) + if ((chan < info->first_vchannel_nr) || + (chan >= info->first_vchannel_nr + info->nr_channels)) continue; return info; @@ -82,7 +82,7 @@ struct dma_channel *get_dma_channel(unsi for (i = 0; i < info->nr_channels; i++) { channel = &info->channels[i]; - if (channel->chan == chan) + if (channel->vchan == chan) return channel; } @@ -369,6 +369,7 @@ int register_dmac(struct dma_info *info) } total_channels = get_nr_channels(); + info->first_vchannel_nr = total_channels; for (i = 0; i < info->nr_channels; i++) { struct dma_channel *chan = &info->channels[i]; diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 981b040..5d0f73a 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -77,16 +77,8 @@ static void __init emit_cache_params(voi /* * SH-4 has virtually indexed and physically tagged cache. */ - -/* Worst case assumed to be 64k cache, direct-mapped i.e. 4 synonym bits. */ -#define MAX_P3_MUTEXES 16 - -struct mutex p3map_mutex[MAX_P3_MUTEXES]; - void __init p3_cache_init(void) { - int i; - compute_alias(¤t_cpu_data.icache); compute_alias(¤t_cpu_data.dcache); @@ -109,9 +101,6 @@ void __init p3_cache_init(void) if (ioremap_page_range(P3SEG, P3SEG + (PAGE_SIZE * 4), 0, PAGE_KERNEL)) panic("%s failed.", __FUNCTION__); - - for (i = 0; i < current_cpu_data.dcache.n_aliases; i++) - mutex_init(&p3map_mutex[i]); } /* diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c index df69da9..82b48e6 100644 --- a/arch/sh/mm/pg-sh4.c +++ b/arch/sh/mm/pg-sh4.c @@ -2,7 +2,7 @@ * arch/sh/mm/pg-sh4.c * * Copyright (C) 1999, 2000, 2002 Niibe Yutaka - * Copyright (C) 2002 - 2005 Paul Mundt + * Copyright (C) 2002 - 2007 Paul Mundt * * Released under the terms of the GNU GPL v2.0. */ @@ -11,10 +11,35 @@ #include #include #include -extern struct mutex p3map_mutex[]; - #define CACHE_ALIAS (current_cpu_data.dcache.alias_mask) +static inline void *kmap_coherent(struct page *page, unsigned long addr) +{ + enum fixed_addresses idx; + unsigned long vaddr, flags; + pte_t pte; + + inc_preempt_count(); + + idx = (addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT; + vaddr = __fix_to_virt(FIX_CMAP_END - idx); + pte = mk_pte(page, PAGE_KERNEL); + + local_irq_save(flags); + flush_tlb_one(get_asid(), vaddr); + local_irq_restore(flags); + + update_mmu_cache(NULL, vaddr, pte); + + return (void *)vaddr; +} + +static inline void kunmap_coherent(struct page *page) +{ + dec_preempt_count(); + preempt_check_resched(); +} + /* * clear_user_page * @to: P1 address @@ -27,25 +52,9 @@ void clear_user_page(void *to, unsigned if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) clear_page(to); else { - unsigned long phys_addr = PHYSADDR(to); - unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS); - pgd_t *pgd = pgd_offset_k(p3_addr); - pud_t *pud = pud_offset(pgd, p3_addr); - pmd_t *pmd = pmd_offset(pud, p3_addr); - pte_t *pte = pte_offset_kernel(pmd, p3_addr); - pte_t entry; - unsigned long flags; - - entry = pfn_pte(phys_addr >> PAGE_SHIFT, PAGE_KERNEL); - mutex_lock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); - set_pte(pte, entry); - local_irq_save(flags); - flush_tlb_one(get_asid(), p3_addr); - local_irq_restore(flags); - update_mmu_cache(NULL, p3_addr, entry); - __clear_user_page((void *)p3_addr, to); - pte_clear(&init_mm, p3_addr, pte); - mutex_unlock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); + void *vto = kmap_coherent(page, address); + __clear_user_page(vto, to); + kunmap_coherent(vto); } } @@ -63,25 +72,9 @@ void copy_user_page(void *to, void *from if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) copy_page(to, from); else { - unsigned long phys_addr = PHYSADDR(to); - unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS); - pgd_t *pgd = pgd_offset_k(p3_addr); - pud_t *pud = pud_offset(pgd, p3_addr); - pmd_t *pmd = pmd_offset(pud, p3_addr); - pte_t *pte = pte_offset_kernel(pmd, p3_addr); - pte_t entry; - unsigned long flags; - - entry = pfn_pte(phys_addr >> PAGE_SHIFT, PAGE_KERNEL); - mutex_lock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); - set_pte(pte, entry); - local_irq_save(flags); - flush_tlb_one(get_asid(), p3_addr); - local_irq_restore(flags); - update_mmu_cache(NULL, p3_addr, entry); - __copy_user_page((void *)p3_addr, from, to); - pte_clear(&init_mm, p3_addr, pte); - mutex_unlock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); + void *vfrom = kmap_coherent(page, address); + __copy_user_page(vfrom, from, to); + kunmap_coherent(vfrom); } } diff --git a/include/asm-sh/dma.h b/include/asm-sh/dma.h index 6034d4a..4c75b70 100644 --- a/include/asm-sh/dma.h +++ b/include/asm-sh/dma.h @@ -111,6 +111,7 @@ struct dma_info { struct list_head list; int first_channel_nr; + int first_vchannel_nr; }; struct dma_chan_caps { diff --git a/include/asm-sh/fixmap.h b/include/asm-sh/fixmap.h index 458e9fa..8a56617 100644 --- a/include/asm-sh/fixmap.h +++ b/include/asm-sh/fixmap.h @@ -46,6 +46,9 @@ #endif * fix-mapped? */ enum fixed_addresses { +#define FIX_N_COLOURS 16 + FIX_CMAP_BEGIN, + FIX_CMAP_END = FIX_CMAP_BEGIN + FIX_N_COLOURS, #ifdef CONFIG_HIGHMEM FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, @@ -53,8 +56,8 @@ #endif __end_of_fixed_addresses }; -extern void __set_fixmap (enum fixed_addresses idx, - unsigned long phys, pgprot_t flags); +extern void __set_fixmap(enum fixed_addresses idx, + unsigned long phys, pgprot_t flags); #define set_fixmap(idx, phys) \ __set_fixmap(idx, phys, PAGE_KERNEL) @@ -106,5 +109,4 @@ static inline unsigned long virt_to_fix( BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START); return __virt_to_fix(vaddr); } - #endif diff --git a/sound/sh/aica.h b/sound/sh/aica.h index 8c11e3d..d098baa 100644 --- a/sound/sh/aica.h +++ b/sound/sh/aica.h @@ -52,7 +52,7 @@ #define AICA_CHANNEL0_OFFSET 0x11000 #define AICA_CHANNEL1_OFFSET 0x21000 #define CHANNEL_OFFSET 0x10000 -#define AICA_DMA_CHANNEL 0 +#define AICA_DMA_CHANNEL 5 #define AICA_DMA_MODE 5 #define SND_AICA_DRIVER "AICA"