diff options
author | Manuel Lauss <manuel.lauss@googlemail.com> | 2010-01-26 14:39:33 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2010-02-01 14:30:25 -0500 |
commit | 22f4bb68b301f4ab896e9b3b0431fdde962242d2 (patch) | |
tree | 62767bbd1ad7d11dbbeea3482b7902f08ea178ce /arch/mips | |
parent | be8cde8b24c9dca1e54598690115eee5b1476519 (diff) |
MIPS: Alchemy: Fix dbdma ring destruction memory debugcheck.
DBDMA descriptors need to be located at 32-byte aligned addresses;
however kmalloc in conjunction with the SLAB allocator and
CONFIG_DEBUG_SLUB enabled doesn't deliver any. The dbdma code works
around that by allocating a larger area and realigning the start
address within it.
When freeing a channel however this adjustment is not taken into
account which results in an oops:
Kernel bug detected[#1]:
[...]
Call Trace:
[<80186010>] cache_free_debugcheck+0x284/0x318
[<801869d8>] kfree+0xe8/0x2a0
[<8010b31c>] au1xxx_dbdma_chan_free+0x2c/0x7c
[<80388dc8>] au1x_pcm_dbdma_free+0x34/0x4c
[<80388fa8>] au1xpsc_pcm_close+0x28/0x38
[<80383cb8>] soc_codec_close+0x14c/0x1cc
[<8036dbb4>] snd_pcm_release_substream+0x60/0xac
[<8036dc40>] snd_pcm_release+0x40/0xa0
[<8018c7a8>] __fput+0x11c/0x228
[<80188f60>] filp_close+0x7c/0x98
[<80189018>] sys_close+0x9c/0xe4
[<801022a0>] stack_done+0x20/0x3c
Fix this by recording the address delivered by kmalloc() and using
it as parameter to kfree().
This fix is only necessary with the SLAB allocator and CONFIG_DEBUG_SLAB
enabled; non-debug SLAB, SLUB do return nicely aligned addresses,
debug-enabled SLUB currently panics early in the boot process.
Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
To: Linux-MIPS <linux-mips@linux-mips.org>
Cc: Manuel Lauss <manuel.lauss@gmail.com>
Patchwork: http://patchwork.linux-mips.org/patch/878/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/alchemy/common/dbdma.c | 7 | ||||
-rw-r--r-- | arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h | 1 |
2 files changed, 6 insertions, 2 deletions
diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c index 5c68569344c1..f9201ca2295b 100644 --- a/arch/mips/alchemy/common/dbdma.c +++ b/arch/mips/alchemy/common/dbdma.c | |||
@@ -412,8 +412,11 @@ u32 au1xxx_dbdma_ring_alloc(u32 chanid, int entries) | |||
412 | if (desc_base == 0) | 412 | if (desc_base == 0) |
413 | return 0; | 413 | return 0; |
414 | 414 | ||
415 | ctp->cdb_membase = desc_base; | ||
415 | desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t)); | 416 | desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t)); |
416 | } | 417 | } else |
418 | ctp->cdb_membase = desc_base; | ||
419 | |||
417 | dp = (au1x_ddma_desc_t *)desc_base; | 420 | dp = (au1x_ddma_desc_t *)desc_base; |
418 | 421 | ||
419 | /* Keep track of the base descriptor. */ | 422 | /* Keep track of the base descriptor. */ |
@@ -831,7 +834,7 @@ void au1xxx_dbdma_chan_free(u32 chanid) | |||
831 | 834 | ||
832 | au1xxx_dbdma_stop(chanid); | 835 | au1xxx_dbdma_stop(chanid); |
833 | 836 | ||
834 | kfree((void *)ctp->chan_desc_base); | 837 | kfree((void *)ctp->cdb_membase); |
835 | 838 | ||
836 | stp->dev_flags &= ~DEV_FLAGS_INUSE; | 839 | stp->dev_flags &= ~DEV_FLAGS_INUSE; |
837 | dtp->dev_flags &= ~DEV_FLAGS_INUSE; | 840 | dtp->dev_flags &= ~DEV_FLAGS_INUSE; |
diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h index 06f68f43800a..d206000fbfe2 100644 --- a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h +++ b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h | |||
@@ -305,6 +305,7 @@ typedef struct dbdma_chan_config { | |||
305 | dbdev_tab_t *chan_dest; | 305 | dbdev_tab_t *chan_dest; |
306 | au1x_dma_chan_t *chan_ptr; | 306 | au1x_dma_chan_t *chan_ptr; |
307 | au1x_ddma_desc_t *chan_desc_base; | 307 | au1x_ddma_desc_t *chan_desc_base; |
308 | u32 cdb_membase; /* kmalloc base of above */ | ||
308 | au1x_ddma_desc_t *get_ptr, *put_ptr, *cur_ptr; | 309 | au1x_ddma_desc_t *get_ptr, *put_ptr, *cur_ptr; |
309 | void *chan_callparam; | 310 | void *chan_callparam; |
310 | void (*chan_callback)(int, void *); | 311 | void (*chan_callback)(int, void *); |