From 8a4259bf89d23bfd58d87e275ef6da29cea6b3c5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Jun 2009 08:40:51 +0200 Subject: ALSA: ctxfi - Fix Oops at mmapping Replace a spinlock with a mutex protecting the vm block list at mmap / munmap calls, which caused Oops like below: BUG: sleeping function called from invalid context at mm/slub.c:1599 in_atomic(): 0, irqs_disabled(): 1, pid: 32065, name: xine Pid: 32065, comm: xine Tainted: P 2.6.29.4-75.fc10.x86_64 #1 Call Trace: [] __might_sleep+0x105/0x10a [] kmem_cache_alloc+0x32/0xe2 [] ct_vm_map+0xfa/0x19e [snd_ctxfi] [] ct_map_audio_buffer+0x4c/0x76 [snd_ctxfi] [] atc_pcm_playback_prepare+0x1d7/0x2a8 [snd_ctxfi] [] ? up_read+0x9/0xb [] ? __up_read+0x7c/0x87 [] ct_pcm_playback_prepare+0x39/0x60 [snd_ctxfi] [] snd_pcm_do_prepare+0x16/0x28 [snd_pcm] [] snd_pcm_action_single+0x2d/0x5b [snd_pcm] [] snd_pcm_action_nonatomic+0x52/0x6a [snd_pcm] [] snd_pcm_common_ioctl1+0x404/0xc79 [snd_pcm] [] ? alloc_pages_current+0xb9/0xc2 [] ? new_slab+0x1a5/0x1cb [] ? vma_prio_tree_insert+0x23/0xc1 [] snd_pcm_playback_ioctl1+0x213/0x230 [snd_pcm] [] ? mmap_region+0x397/0x4c9 [] snd_pcm_playback_ioctl+0x2e/0x36 [snd_pcm] [] vfs_ioctl+0x2a/0x78 [] do_vfs_ioctl+0x462/0x4a2 [] ? default_spin_lock_flags+0x9/0xe [] ? trace_hardirqs_off_thunk+0x3a/0x6c [] sys_ioctl+0x55/0x77 [] system_call_fastpath+0x16/0x1b Signed-off-by: Takashi Iwai diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index ead104e..1a4bb35 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -119,7 +119,6 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm); static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) { - unsigned long flags; struct snd_pcm_runtime *runtime; struct ct_vm *vm; @@ -129,9 +128,7 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) runtime = apcm->substream->runtime; vm = atc->vm; - spin_lock_irqsave(&atc->vm_lock, flags); apcm->vm_block = vm->map(vm, runtime->dma_area, runtime->dma_bytes); - spin_unlock_irqrestore(&atc->vm_lock, flags); if (NULL == apcm->vm_block) return -ENOENT; @@ -141,7 +138,6 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) { - unsigned long flags; struct ct_vm *vm; if (NULL == apcm->vm_block) @@ -149,9 +145,7 @@ static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) vm = atc->vm; - spin_lock_irqsave(&atc->vm_lock, flags); vm->unmap(vm, apcm->vm_block); - spin_unlock_irqrestore(&atc->vm_lock, flags); apcm->vm_block = NULL; } @@ -161,9 +155,7 @@ static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) struct ct_vm *vm; void *kvirt_addr; unsigned long phys_addr; - unsigned long flags; - spin_lock_irqsave(&atc->vm_lock, flags); vm = atc->vm; kvirt_addr = vm->get_ptp_virt(vm, index); if (kvirt_addr == NULL) @@ -171,8 +163,6 @@ static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) else phys_addr = virt_to_phys(kvirt_addr); - spin_unlock_irqrestore(&atc->vm_lock, flags); - return phys_addr; } @@ -1562,7 +1552,6 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci, atc_set_ops(atc); spin_lock_init(&atc->atc_lock); - spin_lock_init(&atc->vm_lock); /* Find card model */ err = atc_identify_card(atc); diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index 286c993..a7b0ec2 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h @@ -101,7 +101,6 @@ struct ct_atc { unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index); spinlock_t atc_lock; - spinlock_t vm_lock; int (*pcm_playback_prepare)(struct ct_atc *atc, struct ct_atc_pcm *apcm); diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index cecf77e..363b67e 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -35,25 +35,27 @@ get_vm_block(struct ct_vm *vm, unsigned int size) struct ct_vm_block *block = NULL, *entry = NULL; struct list_head *pos = NULL; + mutex_lock(&vm->lock); list_for_each(pos, &vm->unused) { entry = list_entry(pos, struct ct_vm_block, list); if (entry->size >= size) break; /* found a block that is big enough */ } if (pos == &vm->unused) - return NULL; + goto out; if (entry->size == size) { /* Move the vm node from unused list to used list directly */ list_del(&entry->list); list_add(&entry->list, &vm->used); vm->size -= size; - return entry; + block = entry; + goto out; } block = kzalloc(sizeof(*block), GFP_KERNEL); if (NULL == block) - return NULL; + goto out; block->addr = entry->addr; block->size = size; @@ -62,6 +64,8 @@ get_vm_block(struct ct_vm *vm, unsigned int size) entry->size -= size; vm->size -= size; + out: + mutex_unlock(&vm->lock); return block; } @@ -70,6 +74,7 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block) struct ct_vm_block *entry = NULL, *pre_ent = NULL; struct list_head *pos = NULL, *pre = NULL; + mutex_lock(&vm->lock); list_del(&block->list); vm->size += block->size; @@ -106,6 +111,7 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block) pos = pre; pre = pos->prev; } + mutex_unlock(&vm->lock); } /* Map host addr (kmalloced/vmalloced) to device logical addr. */ @@ -191,6 +197,8 @@ int ct_vm_create(struct ct_vm **rvm) if (NULL == vm) return -ENOMEM; + mutex_init(&vm->lock); + /* Allocate page table pages */ for (i = 0; i < CT_PTP_NUM; i++) { vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL); diff --git a/sound/pci/ctxfi/ctvmem.h b/sound/pci/ctxfi/ctvmem.h index 4eb5bdd..618952e 100644 --- a/sound/pci/ctxfi/ctvmem.h +++ b/sound/pci/ctxfi/ctvmem.h @@ -20,7 +20,7 @@ #define CT_PTP_NUM 1 /* num of device page table pages */ -#include +#include #include struct ct_vm_block { @@ -35,6 +35,7 @@ struct ct_vm { unsigned int size; /* Available addr space in bytes */ struct list_head unused; /* List of unused blocks */ struct list_head used; /* List of used blocks */ + struct mutex lock; /* Map host addr (kmalloced/vmalloced) to device logical addr. */ struct ct_vm_block *(*map)(struct ct_vm *, void *host_addr, int size); -- cgit v0.10.2 From 822fa19b5c23746577687a0ec48eae0ec1cd22a0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Jun 2009 14:12:17 +0200 Subject: ALSA: ALSA: ctxfi - Release PCM resources at each prepare call The prepare callback can be called multiple times, thus it needs to release and acquire the resource again by itself at the second or later call. Simply add pcm_release_resources() at the beginning of each prepare callback in ctatc.c. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 1a4bb35..e14ed71 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -254,6 +254,9 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) return 0; } + /* first release old resources */ + atc->pcm_release_resources(atc, apcm); + /* Get SRC resource */ desc.multi = apcm->substream->runtime->channels; desc.msr = atc->msr; @@ -496,6 +499,9 @@ atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) int n_srcimp = 0, n_amixer = 0, n_srcc = 0, n_sum = 0; struct src_node_conf_t src_node_conf[2] = {{0} }; + /* first release old resources */ + atc->pcm_release_resources(atc, apcm); + /* The numbers of converting SRCs and SRCIMPs should be determined * by pitch value. */ @@ -767,6 +773,9 @@ static int spdif_passthru_playback_get_resources(struct ct_atc *atc, int n_amixer = apcm->substream->runtime->channels, i = 0; unsigned int pitch = 0, rsr = atc->pll_rate; + /* first release old resources */ + atc->pcm_release_resources(atc, apcm); + /* Get SRC resource */ desc.multi = apcm->substream->runtime->channels; desc.msr = 1; -- cgit v0.10.2 From 6585db943aade186d38eaab2720c18887b94c875 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Jun 2009 14:17:27 +0200 Subject: ALSA: ctxfi - Fix surround mixer names We usually pick up "Surround" mixer for the rear output, and "Side" for the extra surround. Fix the channel mapping to follow it. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c index b795076..177c46e 100644 --- a/sound/pci/ctxfi/ctmixer.c +++ b/sound/pci/ctxfi/ctmixer.c @@ -168,7 +168,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { }, [MIXER_WAVES_P] = { .ctl = 1, - .name = "Surround Playback Volume", + .name = "Side Playback Volume", }, [MIXER_WAVEC_P] = { .ctl = 1, @@ -176,7 +176,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { }, [MIXER_WAVER_P] = { .ctl = 1, - .name = "Rear Playback Volume", + .name = "Surround Playback Volume", }, [MIXER_PCM_C_S] = { @@ -213,7 +213,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { }, [MIXER_WAVES_P_S] = { .ctl = 1, - .name = "Surround Playback Switch", + .name = "Side Playback Switch", }, [MIXER_WAVEC_P_S] = { .ctl = 1, @@ -221,7 +221,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { }, [MIXER_WAVER_P_S] = { .ctl = 1, - .name = "Rear Playback Switch", + .name = "Surround Playback Switch", }, [MIXER_DIGITAL_IO_S] = { .ctl = 0, -- cgit v0.10.2 From 8372d4980fbc2e403f0dc5457441c8c6b7c04915 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Jun 2009 14:27:56 +0200 Subject: ALSA: ctxfi - Fix PCM device naming PCM names for surround streams should be also fixed as well as the mixer element names. Also, a bit clean up for PCM name setup. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index e14ed71..675dd4c 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -72,15 +72,15 @@ static struct { [FRONT] = { .create = ct_alsa_pcm_create, .destroy = NULL, .public_name = "Front/WaveIn"}, - [REAR] = { .create = ct_alsa_pcm_create, + [SURROUND] = { .create = ct_alsa_pcm_create, .destroy = NULL, - .public_name = "Rear"}, + .public_name = "Surround"}, [CLFE] = { .create = ct_alsa_pcm_create, .destroy = NULL, .public_name = "Center/LFE"}, - [SURROUND] = { .create = ct_alsa_pcm_create, + [SIDE] = { .create = ct_alsa_pcm_create, .destroy = NULL, - .public_name = "Surround"}, + .public_name = "Side"}, [IEC958] = { .create = ct_alsa_pcm_create, .destroy = NULL, .public_name = "IEC958 Non-audio"}, diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index a7b0ec2..b86d12c 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h @@ -29,9 +29,9 @@ enum CTALSADEVS { /* Types of alsa devices */ FRONT, - REAR, - CLFE, SURROUND, + CLFE, + SIDE, IEC958, MIXER, NUM_CTALSADEVS /* This should always be the last */ diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index a64cb0e..756d8b2 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -469,12 +469,10 @@ int ct_alsa_pcm_create(struct ct_atc *atc, struct snd_pcm *pcm; int err; int playback_count, capture_count; - char name[128]; - strncpy(name, device_name, sizeof(name)); playback_count = (IEC958 == device) ? 1 : 8; capture_count = (FRONT == device) ? 1 : 0; - err = snd_pcm_new(atc->card, name, device, + err = snd_pcm_new(atc->card, "ctxfi", device, playback_count, capture_count, &pcm); if (err < 0) { printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err); @@ -484,7 +482,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc, pcm->private_data = atc; pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; - strcpy(pcm->name, device_name); + strlcpy(pcm->name, device_name, sizeof(pcm->name)); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops); -- cgit v0.10.2 From d2b9b96c516d4d61663d92ab4ad4f15ca0134ef2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Jun 2009 14:39:05 +0200 Subject: ALSA: ctxfi - Fix supported PCM formats The device seems supporting only U8, S16, S24_3LE, S32. Other linear formats result in bad outputs. Also, added the support for 32bit float format, which wasn't listed in the original code. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 675dd4c..268ecc4 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -170,16 +170,15 @@ static unsigned int convert_format(snd_pcm_format_t snd_format) { switch (snd_format) { case SNDRV_PCM_FORMAT_U8: - case SNDRV_PCM_FORMAT_S8: return SRC_SF_U8; case SNDRV_PCM_FORMAT_S16_LE: - case SNDRV_PCM_FORMAT_U16_LE: return SRC_SF_S16; case SNDRV_PCM_FORMAT_S24_3LE: return SRC_SF_S24; - case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: return SRC_SF_S32; + case SNDRV_PCM_FORMAT_FLOAT_LE: + return SRC_SF_F32; default: printk(KERN_ERR "ctxfi: not recognized snd format is %d \n", snd_format); diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index 756d8b2..26d86dc 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -26,12 +26,10 @@ static struct snd_pcm_hardware ct_pcm_playback_hw = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE), + SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_FLOAT_LE), .rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000), .rate_min = 8000, @@ -52,8 +50,7 @@ static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = { SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), - .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_U16_LE), + .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_32000), @@ -77,12 +74,10 @@ static struct snd_pcm_hardware ct_pcm_capture_hw = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID), .formats = (SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE), + SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_FLOAT_LE), .rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_96000), .rate_min = 8000, -- cgit v0.10.2 From cd391e206f486955e216a61bd9ebcb0e142122e9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Jun 2009 15:04:29 +0200 Subject: ALSA: ctxfi - Remove PAGE_SIZE limitation Remove the limitation of PAGE_SIZE to be 4k by defining the own page size and macros for 4k. 8kb page size could be natively supported, but it's disabled right now for simplicity. Also, clean up using upper_32_bits() macro. Signed-off-by: Takashi Iwai diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 2d7fef5..3a7640f 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -277,7 +277,6 @@ config SND_CS5535AUDIO config SND_CTXFI tristate "Creative Sound Blaster X-Fi" - depends on X86 select SND_PCM help If you want to use soundcards based on Creative Sound Blastr X-Fi diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index 44283bd..b7b8e6f 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -1249,19 +1249,15 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info) } trnctl = 0x13; /* 32-bit, 4k-size page */ -#if BITS_PER_LONG == 64 - ptp_phys_low = info->vm_pgt_phys & ((1UL<<32)-1); - ptp_phys_high = (info->vm_pgt_phys>>32) & ((1UL<<32)-1); - trnctl |= (1<<2); -#elif BITS_PER_LONG == 32 - ptp_phys_low = info->vm_pgt_phys & (~0UL); - ptp_phys_high = 0; -#else -# error "Unknown BITS_PER_LONG!" -#endif + ptp_phys_low = (u32)info->vm_pgt_phys; + ptp_phys_high = upper_32_bits(info->vm_pgt_phys); + if (sizeof(void *) == 8) /* 64bit address */ + trnctl |= (1 << 2); +#if 0 /* Only 4k h/w pages for simplicitiy */ #if PAGE_SIZE == 8192 trnctl |= (1<<5); #endif +#endif hw_write_20kx(hw, PTPALX, ptp_phys_low); hw_write_20kx(hw, PTPAHX, ptp_phys_high); hw_write_20kx(hw, TRNCTL, trnctl); diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index 7c24c2c..3497287 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -1203,19 +1203,10 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info) } vmctl = 0x80000C0F; /* 32-bit, 4k-size page */ -#if BITS_PER_LONG == 64 - ptp_phys_low = info->vm_pgt_phys & ((1UL<<32)-1); - ptp_phys_high = (info->vm_pgt_phys>>32) & ((1UL<<32)-1); - vmctl |= (3<<8); -#elif BITS_PER_LONG == 32 - ptp_phys_low = info->vm_pgt_phys & (~0UL); - ptp_phys_high = 0; -#else -# error "Unknown BITS_PER_LONG!" -#endif -#if PAGE_SIZE == 8192 -# error "Don't support 8k-page!" -#endif + ptp_phys_low = (u32)info->vm_pgt_phys; + ptp_phys_high = upper_32_bits(info->vm_pgt_phys); + if (sizeof(void *) == 8) /* 64bit address */ + vmctl |= (3 << 8); /* Write page table physical address to all PTPAL registers */ for (i = 0; i < 64; i++) { hw_write_20kx(hw, VMEM_PTPAL+(16*i), ptp_phys_low); diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index 363b67e..74a0362 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -18,12 +18,11 @@ #include "ctvmem.h" #include #include -#include /* for PAGE_SIZE macro definition */ #include #include -#define CT_PTES_PER_PAGE (PAGE_SIZE / sizeof(void *)) -#define CT_ADDRS_PER_PAGE (CT_PTES_PER_PAGE * PAGE_SIZE) +#define CT_PTES_PER_PAGE (CT_PAGE_SIZE / sizeof(void *)) +#define CT_ADDRS_PER_PAGE (CT_PTES_PER_PAGE * CT_PAGE_SIZE) /* * * Find or create vm block based on requested @size. @@ -138,24 +137,24 @@ ct_vm_map(struct ct_vm *vm, void *host_addr, int size) return NULL; } - start_phys = (virt_to_phys(host_addr) & PAGE_MASK); - pages = (PAGE_ALIGN(virt_to_phys(host_addr) + size) - - start_phys) >> PAGE_SHIFT; + start_phys = (virt_to_phys(host_addr) & CT_PAGE_MASK); + pages = (CT_PAGE_ALIGN(virt_to_phys(host_addr) + size) + - start_phys) >> CT_PAGE_SHIFT; ptp = vm->ptp[0]; - block = get_vm_block(vm, (pages << PAGE_SHIFT)); + block = get_vm_block(vm, (pages << CT_PAGE_SHIFT)); if (block == NULL) { printk(KERN_ERR "ctxfi: No virtual memory block that is big " "enough to allocate!\n"); return NULL; } - pte_start = (block->addr >> PAGE_SHIFT); + pte_start = (block->addr >> CT_PAGE_SHIFT); for (i = 0; i < pages; i++) - ptp[pte_start+i] = start_phys + (i << PAGE_SHIFT); + ptp[pte_start+i] = start_phys + (i << CT_PAGE_SHIFT); - block->addr += (virt_to_phys(host_addr) & (~PAGE_MASK)); + block->addr += (virt_to_phys(host_addr) & (~CT_PAGE_MASK)); block->size = size; return block; @@ -164,9 +163,9 @@ ct_vm_map(struct ct_vm *vm, void *host_addr, int size) static void ct_vm_unmap(struct ct_vm *vm, struct ct_vm_block *block) { /* do unmapping */ - block->size = ((block->addr + block->size + PAGE_SIZE - 1) - & PAGE_MASK) - (block->addr & PAGE_MASK); - block->addr &= PAGE_MASK; + block->size = ((block->addr + block->size + CT_PAGE_SIZE - 1) + & CT_PAGE_MASK) - (block->addr & CT_PAGE_MASK); + block->addr &= CT_PAGE_MASK; put_vm_block(vm, block); } diff --git a/sound/pci/ctxfi/ctvmem.h b/sound/pci/ctxfi/ctvmem.h index 618952e..17d2d37 100644 --- a/sound/pci/ctxfi/ctvmem.h +++ b/sound/pci/ctxfi/ctvmem.h @@ -23,6 +23,14 @@ #include #include +/* The chip can handle the page table of 4k pages + * (emu20k1 can handle even 8k pages, but we don't use it right now) + */ +#define CT_PAGE_SIZE 4096 +#define CT_PAGE_SHIFT 12 +#define CT_PAGE_MASK (~(PAGE_SIZE - 1)) +#define CT_PAGE_ALIGN(addr) ALIGN(addr, CT_PAGE_SIZE) + struct ct_vm_block { unsigned int addr; /* starting logical addr of this block */ unsigned int size; /* size of this device virtual mem block */ -- cgit v0.10.2 From c76157d9286ed598c241c212aa5a3c6e5107bd82 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Jun 2009 15:26:19 +0200 Subject: ALSA: ctxfi - Support SG-buffers Use SG-buffers instead of contiguous pages. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 268ecc4..6849475 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -128,7 +128,7 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) runtime = apcm->substream->runtime; vm = atc->vm; - apcm->vm_block = vm->map(vm, runtime->dma_area, runtime->dma_bytes); + apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes); if (NULL == apcm->vm_block) return -ENOENT; diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index 26d86dc..52ddf19 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -442,6 +442,7 @@ static struct snd_pcm_ops ct_pcm_playback_ops = { .prepare = ct_pcm_playback_prepare, .trigger = ct_pcm_playback_trigger, .pointer = ct_pcm_playback_pointer, + .page = snd_pcm_sgbuf_ops_page, }; /* PCM operators for capture */ @@ -454,6 +455,7 @@ static struct snd_pcm_ops ct_pcm_capture_ops = { .prepare = ct_pcm_capture_prepare, .trigger = ct_pcm_capture_trigger, .pointer = ct_pcm_capture_pointer, + .page = snd_pcm_sgbuf_ops_page, }; /* Create ALSA pcm device */ @@ -485,7 +487,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc, snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops); - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(atc->pci), 128*1024, 128*1024); return 0; diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index 74a0362..b7f8e58 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #define CT_PTES_PER_PAGE (CT_PAGE_SIZE / sizeof(void *)) #define CT_ADDRS_PER_PAGE (CT_PTES_PER_PAGE * CT_PAGE_SIZE) @@ -34,6 +34,13 @@ get_vm_block(struct ct_vm *vm, unsigned int size) struct ct_vm_block *block = NULL, *entry = NULL; struct list_head *pos = NULL; + size = CT_PAGE_ALIGN(size); + if (size > vm->size) { + printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural " + "memory space available!\n"); + return NULL; + } + mutex_lock(&vm->lock); list_for_each(pos, &vm->unused) { entry = list_entry(pos, struct ct_vm_block, list); @@ -73,6 +80,8 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block) struct ct_vm_block *entry = NULL, *pre_ent = NULL; struct list_head *pos = NULL, *pre = NULL; + block->size = CT_PAGE_ALIGN(block->size); + mutex_lock(&vm->lock); list_del(&block->list); vm->size += block->size; @@ -115,57 +124,36 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block) /* Map host addr (kmalloced/vmalloced) to device logical addr. */ static struct ct_vm_block * -ct_vm_map(struct ct_vm *vm, void *host_addr, int size) +ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size) { - struct ct_vm_block *block = NULL; - unsigned long pte_start; - unsigned long i; - unsigned long pages; - unsigned long start_phys; + struct ct_vm_block *block; + unsigned int pte_start; + unsigned i, pages; unsigned long *ptp; - /* do mapping */ - if ((unsigned long)host_addr >= VMALLOC_START) { - printk(KERN_ERR "ctxfi: " - "Fail! Not support vmalloced addr now!\n"); - return NULL; - } - - if (size > vm->size) { - printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural " - "memory space available!\n"); - return NULL; - } - - start_phys = (virt_to_phys(host_addr) & CT_PAGE_MASK); - pages = (CT_PAGE_ALIGN(virt_to_phys(host_addr) + size) - - start_phys) >> CT_PAGE_SHIFT; - - ptp = vm->ptp[0]; - - block = get_vm_block(vm, (pages << CT_PAGE_SHIFT)); + block = get_vm_block(vm, size); if (block == NULL) { printk(KERN_ERR "ctxfi: No virtual memory block that is big " "enough to allocate!\n"); return NULL; } + ptp = vm->ptp[0]; pte_start = (block->addr >> CT_PAGE_SHIFT); - for (i = 0; i < pages; i++) - ptp[pte_start+i] = start_phys + (i << CT_PAGE_SHIFT); + pages = block->size >> CT_PAGE_SHIFT; + for (i = 0; i < pages; i++) { + unsigned long addr; + addr = snd_pcm_sgbuf_get_addr(substream, i << CT_PAGE_SHIFT); + ptp[pte_start + i] = addr; + } - block->addr += (virt_to_phys(host_addr) & (~CT_PAGE_MASK)); block->size = size; - return block; } static void ct_vm_unmap(struct ct_vm *vm, struct ct_vm_block *block) { /* do unmapping */ - block->size = ((block->addr + block->size + CT_PAGE_SIZE - 1) - & CT_PAGE_MASK) - (block->addr & CT_PAGE_MASK); - block->addr &= CT_PAGE_MASK; put_vm_block(vm, block); } diff --git a/sound/pci/ctxfi/ctvmem.h b/sound/pci/ctxfi/ctvmem.h index 17d2d37..01e4fd0 100644 --- a/sound/pci/ctxfi/ctvmem.h +++ b/sound/pci/ctxfi/ctvmem.h @@ -37,6 +37,8 @@ struct ct_vm_block { struct list_head list; }; +struct snd_pcm_substream; + /* Virtual memory management object for card device */ struct ct_vm { void *ptp[CT_PTP_NUM]; /* Device page table pages */ @@ -46,7 +48,8 @@ struct ct_vm { struct mutex lock; /* Map host addr (kmalloced/vmalloced) to device logical addr. */ - struct ct_vm_block *(*map)(struct ct_vm *, void *host_addr, int size); + struct ct_vm_block *(*map)(struct ct_vm *, struct snd_pcm_substream *, + int size); /* Unmap device logical addr area. */ void (*unmap)(struct ct_vm *, struct ct_vm_block *block); void *(*get_ptp_virt)(struct ct_vm *vm, int index); -- cgit v0.10.2