Commit bd05dbd3 authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/ctxfi-fix' into topic/ctxfi

parents 67fbf880 c76157d9
...@@ -277,7 +277,6 @@ config SND_CS5535AUDIO ...@@ -277,7 +277,6 @@ config SND_CS5535AUDIO
config SND_CTXFI config SND_CTXFI
tristate "Creative Sound Blaster X-Fi" tristate "Creative Sound Blaster X-Fi"
depends on X86
select SND_PCM select SND_PCM
help help
If you want to use soundcards based on Creative Sound Blastr X-Fi If you want to use soundcards based on Creative Sound Blastr X-Fi
......
...@@ -72,15 +72,15 @@ static struct { ...@@ -72,15 +72,15 @@ static struct {
[FRONT] = { .create = ct_alsa_pcm_create, [FRONT] = { .create = ct_alsa_pcm_create,
.destroy = NULL, .destroy = NULL,
.public_name = "Front/WaveIn"}, .public_name = "Front/WaveIn"},
[REAR] = { .create = ct_alsa_pcm_create, [SURROUND] = { .create = ct_alsa_pcm_create,
.destroy = NULL, .destroy = NULL,
.public_name = "Rear"}, .public_name = "Surround"},
[CLFE] = { .create = ct_alsa_pcm_create, [CLFE] = { .create = ct_alsa_pcm_create,
.destroy = NULL, .destroy = NULL,
.public_name = "Center/LFE"}, .public_name = "Center/LFE"},
[SURROUND] = { .create = ct_alsa_pcm_create, [SIDE] = { .create = ct_alsa_pcm_create,
.destroy = NULL, .destroy = NULL,
.public_name = "Surround"}, .public_name = "Side"},
[IEC958] = { .create = ct_alsa_pcm_create, [IEC958] = { .create = ct_alsa_pcm_create,
.destroy = NULL, .destroy = NULL,
.public_name = "IEC958 Non-audio"}, .public_name = "IEC958 Non-audio"},
...@@ -119,7 +119,6 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm); ...@@ -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) static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
{ {
unsigned long flags;
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
struct ct_vm *vm; struct ct_vm *vm;
...@@ -129,9 +128,7 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) ...@@ -129,9 +128,7 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
runtime = apcm->substream->runtime; runtime = apcm->substream->runtime;
vm = atc->vm; vm = atc->vm;
spin_lock_irqsave(&atc->vm_lock, flags); apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes);
apcm->vm_block = vm->map(vm, runtime->dma_area, runtime->dma_bytes);
spin_unlock_irqrestore(&atc->vm_lock, flags);
if (NULL == apcm->vm_block) if (NULL == apcm->vm_block)
return -ENOENT; return -ENOENT;
...@@ -141,7 +138,6 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) ...@@ -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) static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
{ {
unsigned long flags;
struct ct_vm *vm; struct ct_vm *vm;
if (NULL == apcm->vm_block) if (NULL == apcm->vm_block)
...@@ -149,9 +145,7 @@ static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) ...@@ -149,9 +145,7 @@ static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
vm = atc->vm; vm = atc->vm;
spin_lock_irqsave(&atc->vm_lock, flags);
vm->unmap(vm, apcm->vm_block); vm->unmap(vm, apcm->vm_block);
spin_unlock_irqrestore(&atc->vm_lock, flags);
apcm->vm_block = NULL; apcm->vm_block = NULL;
} }
...@@ -161,9 +155,7 @@ static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) ...@@ -161,9 +155,7 @@ static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index)
struct ct_vm *vm; struct ct_vm *vm;
void *kvirt_addr; void *kvirt_addr;
unsigned long phys_addr; unsigned long phys_addr;
unsigned long flags;
spin_lock_irqsave(&atc->vm_lock, flags);
vm = atc->vm; vm = atc->vm;
kvirt_addr = vm->get_ptp_virt(vm, index); kvirt_addr = vm->get_ptp_virt(vm, index);
if (kvirt_addr == NULL) if (kvirt_addr == NULL)
...@@ -171,8 +163,6 @@ static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) ...@@ -171,8 +163,6 @@ static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index)
else else
phys_addr = virt_to_phys(kvirt_addr); phys_addr = virt_to_phys(kvirt_addr);
spin_unlock_irqrestore(&atc->vm_lock, flags);
return phys_addr; return phys_addr;
} }
...@@ -180,16 +170,15 @@ static unsigned int convert_format(snd_pcm_format_t snd_format) ...@@ -180,16 +170,15 @@ static unsigned int convert_format(snd_pcm_format_t snd_format)
{ {
switch (snd_format) { switch (snd_format) {
case SNDRV_PCM_FORMAT_U8: case SNDRV_PCM_FORMAT_U8:
case SNDRV_PCM_FORMAT_S8:
return SRC_SF_U8; return SRC_SF_U8;
case SNDRV_PCM_FORMAT_S16_LE: case SNDRV_PCM_FORMAT_S16_LE:
case SNDRV_PCM_FORMAT_U16_LE:
return SRC_SF_S16; return SRC_SF_S16;
case SNDRV_PCM_FORMAT_S24_3LE: case SNDRV_PCM_FORMAT_S24_3LE:
return SRC_SF_S24; return SRC_SF_S24;
case SNDRV_PCM_FORMAT_S24_LE:
case SNDRV_PCM_FORMAT_S32_LE: case SNDRV_PCM_FORMAT_S32_LE:
return SRC_SF_S32; return SRC_SF_S32;
case SNDRV_PCM_FORMAT_FLOAT_LE:
return SRC_SF_F32;
default: default:
printk(KERN_ERR "ctxfi: not recognized snd format is %d \n", printk(KERN_ERR "ctxfi: not recognized snd format is %d \n",
snd_format); snd_format);
...@@ -264,6 +253,9 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) ...@@ -264,6 +253,9 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
return 0; return 0;
} }
/* first release old resources */
atc->pcm_release_resources(atc, apcm);
/* Get SRC resource */ /* Get SRC resource */
desc.multi = apcm->substream->runtime->channels; desc.multi = apcm->substream->runtime->channels;
desc.msr = atc->msr; desc.msr = atc->msr;
...@@ -506,6 +498,9 @@ atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) ...@@ -506,6 +498,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; int n_srcimp = 0, n_amixer = 0, n_srcc = 0, n_sum = 0;
struct src_node_conf_t src_node_conf[2] = {{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 /* The numbers of converting SRCs and SRCIMPs should be determined
* by pitch value. */ * by pitch value. */
...@@ -777,6 +772,9 @@ static int spdif_passthru_playback_get_resources(struct ct_atc *atc, ...@@ -777,6 +772,9 @@ static int spdif_passthru_playback_get_resources(struct ct_atc *atc,
int n_amixer = apcm->substream->runtime->channels, i = 0; int n_amixer = apcm->substream->runtime->channels, i = 0;
unsigned int pitch = 0, rsr = atc->pll_rate; unsigned int pitch = 0, rsr = atc->pll_rate;
/* first release old resources */
atc->pcm_release_resources(atc, apcm);
/* Get SRC resource */ /* Get SRC resource */
desc.multi = apcm->substream->runtime->channels; desc.multi = apcm->substream->runtime->channels;
desc.msr = 1; desc.msr = 1;
...@@ -1562,7 +1560,6 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci, ...@@ -1562,7 +1560,6 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci,
atc_set_ops(atc); atc_set_ops(atc);
spin_lock_init(&atc->atc_lock); spin_lock_init(&atc->atc_lock);
spin_lock_init(&atc->vm_lock);
/* Find card model */ /* Find card model */
err = atc_identify_card(atc); err = atc_identify_card(atc);
......
...@@ -29,9 +29,9 @@ ...@@ -29,9 +29,9 @@
enum CTALSADEVS { /* Types of alsa devices */ enum CTALSADEVS { /* Types of alsa devices */
FRONT, FRONT,
REAR,
CLFE,
SURROUND, SURROUND,
CLFE,
SIDE,
IEC958, IEC958,
MIXER, MIXER,
NUM_CTALSADEVS /* This should always be the last */ NUM_CTALSADEVS /* This should always be the last */
...@@ -101,7 +101,6 @@ struct ct_atc { ...@@ -101,7 +101,6 @@ struct ct_atc {
unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index); unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index);
spinlock_t atc_lock; spinlock_t atc_lock;
spinlock_t vm_lock;
int (*pcm_playback_prepare)(struct ct_atc *atc, int (*pcm_playback_prepare)(struct ct_atc *atc,
struct ct_atc_pcm *apcm); struct ct_atc_pcm *apcm);
......
...@@ -1249,18 +1249,14 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info) ...@@ -1249,18 +1249,14 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
} }
trnctl = 0x13; /* 32-bit, 4k-size page */ trnctl = 0x13; /* 32-bit, 4k-size page */
#if BITS_PER_LONG == 64 ptp_phys_low = (u32)info->vm_pgt_phys;
ptp_phys_low = info->vm_pgt_phys & ((1UL<<32)-1); ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
ptp_phys_high = (info->vm_pgt_phys>>32) & ((1UL<<32)-1); if (sizeof(void *) == 8) /* 64bit address */
trnctl |= (1<<2); trnctl |= (1 << 2);
#elif BITS_PER_LONG == 32 #if 0 /* Only 4k h/w pages for simplicitiy */
ptp_phys_low = info->vm_pgt_phys & (~0UL);
ptp_phys_high = 0;
#else
# error "Unknown BITS_PER_LONG!"
#endif
#if PAGE_SIZE == 8192 #if PAGE_SIZE == 8192
trnctl |= (1<<5); trnctl |= (1<<5);
#endif
#endif #endif
hw_write_20kx(hw, PTPALX, ptp_phys_low); hw_write_20kx(hw, PTPALX, ptp_phys_low);
hw_write_20kx(hw, PTPAHX, ptp_phys_high); hw_write_20kx(hw, PTPAHX, ptp_phys_high);
......
...@@ -1203,19 +1203,10 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info) ...@@ -1203,19 +1203,10 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
} }
vmctl = 0x80000C0F; /* 32-bit, 4k-size page */ vmctl = 0x80000C0F; /* 32-bit, 4k-size page */
#if BITS_PER_LONG == 64 ptp_phys_low = (u32)info->vm_pgt_phys;
ptp_phys_low = info->vm_pgt_phys & ((1UL<<32)-1); ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
ptp_phys_high = (info->vm_pgt_phys>>32) & ((1UL<<32)-1); if (sizeof(void *) == 8) /* 64bit address */
vmctl |= (3<<8); 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
/* Write page table physical address to all PTPAL registers */ /* Write page table physical address to all PTPAL registers */
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++) {
hw_write_20kx(hw, VMEM_PTPAL+(16*i), ptp_phys_low); hw_write_20kx(hw, VMEM_PTPAL+(16*i), ptp_phys_low);
......
...@@ -168,7 +168,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { ...@@ -168,7 +168,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
}, },
[MIXER_WAVES_P] = { [MIXER_WAVES_P] = {
.ctl = 1, .ctl = 1,
.name = "Surround Playback Volume", .name = "Side Playback Volume",
}, },
[MIXER_WAVEC_P] = { [MIXER_WAVEC_P] = {
.ctl = 1, .ctl = 1,
...@@ -176,7 +176,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { ...@@ -176,7 +176,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
}, },
[MIXER_WAVER_P] = { [MIXER_WAVER_P] = {
.ctl = 1, .ctl = 1,
.name = "Rear Playback Volume", .name = "Surround Playback Volume",
}, },
[MIXER_PCM_C_S] = { [MIXER_PCM_C_S] = {
...@@ -213,7 +213,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { ...@@ -213,7 +213,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
}, },
[MIXER_WAVES_P_S] = { [MIXER_WAVES_P_S] = {
.ctl = 1, .ctl = 1,
.name = "Surround Playback Switch", .name = "Side Playback Switch",
}, },
[MIXER_WAVEC_P_S] = { [MIXER_WAVEC_P_S] = {
.ctl = 1, .ctl = 1,
...@@ -221,7 +221,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { ...@@ -221,7 +221,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
}, },
[MIXER_WAVER_P_S] = { [MIXER_WAVER_P_S] = {
.ctl = 1, .ctl = 1,
.name = "Rear Playback Switch", .name = "Surround Playback Switch",
}, },
[MIXER_DIGITAL_IO_S] = { [MIXER_DIGITAL_IO_S] = {
.ctl = 0, .ctl = 0,
......
...@@ -26,12 +26,10 @@ static struct snd_pcm_hardware ct_pcm_playback_hw = { ...@@ -26,12 +26,10 @@ static struct snd_pcm_hardware ct_pcm_playback_hw = {
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE), SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_U8 | .formats = (SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_U16_LE |
SNDRV_PCM_FMTBIT_S24_3LE | 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 | .rates = (SNDRV_PCM_RATE_CONTINUOUS |
SNDRV_PCM_RATE_8000_192000), SNDRV_PCM_RATE_8000_192000),
.rate_min = 8000, .rate_min = 8000,
...@@ -52,8 +50,7 @@ static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = { ...@@ -52,8 +50,7 @@ static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = {
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE), SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE | .formats = SNDRV_PCM_FMTBIT_S16_LE,
SNDRV_PCM_FMTBIT_U16_LE),
.rates = (SNDRV_PCM_RATE_48000 | .rates = (SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_32000), SNDRV_PCM_RATE_32000),
...@@ -77,12 +74,10 @@ static struct snd_pcm_hardware ct_pcm_capture_hw = { ...@@ -77,12 +74,10 @@ static struct snd_pcm_hardware ct_pcm_capture_hw = {
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_MMAP_VALID), SNDRV_PCM_INFO_MMAP_VALID),
.formats = (SNDRV_PCM_FMTBIT_U8 | .formats = (SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_U16_LE |
SNDRV_PCM_FMTBIT_S24_3LE | 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 | .rates = (SNDRV_PCM_RATE_CONTINUOUS |
SNDRV_PCM_RATE_8000_96000), SNDRV_PCM_RATE_8000_96000),
.rate_min = 8000, .rate_min = 8000,
...@@ -447,6 +442,7 @@ static struct snd_pcm_ops ct_pcm_playback_ops = { ...@@ -447,6 +442,7 @@ static struct snd_pcm_ops ct_pcm_playback_ops = {
.prepare = ct_pcm_playback_prepare, .prepare = ct_pcm_playback_prepare,
.trigger = ct_pcm_playback_trigger, .trigger = ct_pcm_playback_trigger,
.pointer = ct_pcm_playback_pointer, .pointer = ct_pcm_playback_pointer,
.page = snd_pcm_sgbuf_ops_page,
}; };
/* PCM operators for capture */ /* PCM operators for capture */
...@@ -459,6 +455,7 @@ static struct snd_pcm_ops ct_pcm_capture_ops = { ...@@ -459,6 +455,7 @@ static struct snd_pcm_ops ct_pcm_capture_ops = {
.prepare = ct_pcm_capture_prepare, .prepare = ct_pcm_capture_prepare,
.trigger = ct_pcm_capture_trigger, .trigger = ct_pcm_capture_trigger,
.pointer = ct_pcm_capture_pointer, .pointer = ct_pcm_capture_pointer,
.page = snd_pcm_sgbuf_ops_page,
}; };
/* Create ALSA pcm device */ /* Create ALSA pcm device */
...@@ -469,12 +466,10 @@ int ct_alsa_pcm_create(struct ct_atc *atc, ...@@ -469,12 +466,10 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
struct snd_pcm *pcm; struct snd_pcm *pcm;
int err; int err;
int playback_count, capture_count; int playback_count, capture_count;
char name[128];
strncpy(name, device_name, sizeof(name));
playback_count = (IEC958 == device) ? 1 : 8; playback_count = (IEC958 == device) ? 1 : 8;
capture_count = (FRONT == device) ? 1 : 0; 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); playback_count, capture_count, &pcm);
if (err < 0) { if (err < 0) {
printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err); printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err);
...@@ -484,7 +479,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc, ...@@ -484,7 +479,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
pcm->private_data = atc; pcm->private_data = atc;
pcm->info_flags = 0; pcm->info_flags = 0;
pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; 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); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops);
...@@ -492,7 +487,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc, ...@@ -492,7 +487,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
snd_pcm_set_ops(pcm, snd_pcm_set_ops(pcm,
SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops); 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); snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
return 0; return 0;
......
...@@ -18,12 +18,11 @@ ...@@ -18,12 +18,11 @@
#include "ctvmem.h" #include "ctvmem.h"
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/page.h> /* for PAGE_SIZE macro definition */
#include <linux/io.h> #include <linux/io.h>
#include <asm/pgtable.h> #include <sound/pcm.h>
#define CT_PTES_PER_PAGE (PAGE_SIZE / sizeof(void *)) #define CT_PTES_PER_PAGE (CT_PAGE_SIZE / sizeof(void *))
#define CT_ADDRS_PER_PAGE (CT_PTES_PER_PAGE * PAGE_SIZE) #define CT_ADDRS_PER_PAGE (CT_PTES_PER_PAGE * CT_PAGE_SIZE)
/* * /* *
* Find or create vm block based on requested @size. * Find or create vm block based on requested @size.
...@@ -35,25 +34,34 @@ get_vm_block(struct ct_vm *vm, unsigned int size) ...@@ -35,25 +34,34 @@ get_vm_block(struct ct_vm *vm, unsigned int size)
struct ct_vm_block *block = NULL, *entry = NULL; struct ct_vm_block *block = NULL, *entry = NULL;
struct list_head *pos = 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) { list_for_each(pos, &vm->unused) {
entry = list_entry(pos, struct ct_vm_block, list); entry = list_entry(pos, struct ct_vm_block, list);
if (entry->size >= size) if (entry->size >= size)
break; /* found a block that is big enough */ break; /* found a block that is big enough */
} }
if (pos == &vm->unused) if (pos == &vm->unused)
return NULL; goto out;
if (entry->size == size) { if (entry->size == size) {
/* Move the vm node from unused list to used list directly */ /* Move the vm node from unused list to used list directly */
list_del(&entry->list); list_del(&entry->list);
list_add(&entry->list, &vm->used); list_add(&entry->list, &vm->used);
vm->size -= size; vm->size -= size;
return entry; block = entry;
goto out;
} }
block = kzalloc(sizeof(*block), GFP_KERNEL); block = kzalloc(sizeof(*block), GFP_KERNEL);
if (NULL == block) if (NULL == block)
return NULL; goto out;
block->addr = entry->addr; block->addr = entry->addr;
block->size = size; block->size = size;
...@@ -62,6 +70,8 @@ get_vm_block(struct ct_vm *vm, unsigned int size) ...@@ -62,6 +70,8 @@ get_vm_block(struct ct_vm *vm, unsigned int size)
entry->size -= size; entry->size -= size;
vm->size -= size; vm->size -= size;
out:
mutex_unlock(&vm->lock);
return block; return block;
} }
...@@ -70,6 +80,9 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block) ...@@ -70,6 +80,9 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block)
struct ct_vm_block *entry = NULL, *pre_ent = NULL; struct ct_vm_block *entry = NULL, *pre_ent = NULL;
struct list_head *pos = NULL, *pre = NULL; struct list_head *pos = NULL, *pre = NULL;
block->size = CT_PAGE_ALIGN(block->size);
mutex_lock(&vm->lock);
list_del(&block->list); list_del(&block->list);
vm->size += block->size; vm->size += block->size;
...@@ -106,61 +119,41 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block) ...@@ -106,61 +119,41 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block)
pos = pre; pos = pre;
pre = pos->prev; pre = pos->prev;
} }
mutex_unlock(&vm->lock);
} }
/* Map host addr (kmalloced/vmalloced) to device logical addr. */ /* Map host addr (kmalloced/vmalloced) to device logical addr. */
static struct ct_vm_block * 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; struct ct_vm_block *block;
unsigned long pte_start; unsigned int pte_start;
unsigned long i; unsigned i, pages;
unsigned long pages;
unsigned long start_phys;
unsigned long *ptp; unsigned long *ptp;
/* do mapping */ block = get_vm_block(vm, size);
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) & PAGE_MASK);
pages = (PAGE_ALIGN(virt_to_phys(host_addr) + size)
- start_phys) >> PAGE_SHIFT;
ptp = vm->ptp[0];
block = get_vm_block(vm, (pages << PAGE_SHIFT));
if (block == NULL) { if (block == NULL) {
printk(KERN_ERR "ctxfi: No virtual memory block that is big " printk(KERN_ERR "ctxfi: No virtual memory block that is big "
"enough to allocate!\n"); "enough to allocate!\n");
return NULL; return NULL;
} }
pte_start = (block->addr >> PAGE_SHIFT); ptp = vm->ptp[0];
for (i = 0; i < pages; i++) pte_start = (block->addr >> CT_PAGE_SHIFT);
ptp[pte_start+i] = start_phys + (i << 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) & (~PAGE_MASK));
block->size = size; block->size = size;
return block; return block;
} }
static void ct_vm_unmap(struct ct_vm *vm, struct ct_vm_block *block) static void ct_vm_unmap(struct ct_vm *vm, struct ct_vm_block *block)
{ {
/* do unmapping */ /* do unmapping */
block->size = ((block->addr + block->size + PAGE_SIZE - 1)
& PAGE_MASK) - (block->addr & PAGE_MASK);
block->addr &= PAGE_MASK;
put_vm_block(vm, block); put_vm_block(vm, block);
} }
...@@ -191,6 +184,8 @@ int ct_vm_create(struct ct_vm **rvm) ...@@ -191,6 +184,8 @@ int ct_vm_create(struct ct_vm **rvm)
if (NULL == vm) if (NULL == vm)
return -ENOMEM; return -ENOMEM;
mutex_init(&vm->lock);
/* Allocate page table pages */ /* Allocate page table pages */
for (i = 0; i < CT_PTP_NUM; i++) { for (i = 0; i < CT_PTP_NUM; i++) {
vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL); vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL);
......
...@@ -20,24 +20,36 @@ ...@@ -20,24 +20,36 @@
#define CT_PTP_NUM 1 /* num of device page table pages */ #define CT_PTP_NUM 1 /* num of device page table pages */
#include <linux/spinlock.h> #include <linux/mutex.h>
#include <linux/list.h> #include <linux/list.h>
/* 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 { struct ct_vm_block {
unsigned int addr; /* starting logical addr of this block */ unsigned int addr; /* starting logical addr of this block */
unsigned int size; /* size of this device virtual mem block */ unsigned int size; /* size of this device virtual mem block */
struct list_head list; struct list_head list;
}; };
struct snd_pcm_substream;
/* Virtual memory management object for card device */ /* Virtual memory management object for card device */
struct ct_vm { struct ct_vm {
void *ptp[CT_PTP_NUM]; /* Device page table pages */ void *ptp[CT_PTP_NUM]; /* Device page table pages */
unsigned int size; /* Available addr space in bytes */ unsigned int size; /* Available addr space in bytes */
struct list_head unused; /* List of unused blocks */ struct list_head unused; /* List of unused blocks */
struct list_head used; /* List of used blocks */ struct list_head used; /* List of used blocks */
struct mutex lock;
/* Map host addr (kmalloced/vmalloced) to device logical addr. */ /* 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. */ /* Unmap device logical addr area. */
void (*unmap)(struct ct_vm *, struct ct_vm_block *block); void (*unmap)(struct ct_vm *, struct ct_vm_block *block);
void *(*get_ptp_virt)(struct ct_vm *vm, int index); void *(*get_ptp_virt)(struct ct_vm *vm, int index);
......
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