diff options
author | Jaroslav Kysela <perex@perex.cz> | 2010-02-02 13:58:25 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2010-02-04 15:48:00 -0500 |
commit | 21956b61f594f7924d98240da74bc81c28601fa9 (patch) | |
tree | 0514becc673bcd8b952af728700af5cdfef15e0d /sound | |
parent | c68db7175f4dcb3d5789bb50bea6376fb81f87fe (diff) |
ALSA: ctxfi - fix PTP address initialization
After hours of debugging, I finally found the reason why some source
and runtime combination does not work. The PTP (page table pages)
address must be aligned. I am not sure how much, but alignment to
PAGE_SIZE is sufficient. Also, use ALSA's page allocation routines
to ensure proper virtual -> physical address translation.
Cc: <stable@kernel.org>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/ctxfi/ctatc.c | 15 | ||||
-rw-r--r-- | sound/pci/ctxfi/ctvmem.c | 38 | ||||
-rw-r--r-- | sound/pci/ctxfi/ctvmem.h | 8 |
3 files changed, 25 insertions, 36 deletions
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index cb65bd0dd35b..459c1f62783b 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c | |||
@@ -166,18 +166,7 @@ static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) | |||
166 | 166 | ||
167 | static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) | 167 | static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) |
168 | { | 168 | { |
169 | struct ct_vm *vm; | 169 | return atc->vm->get_ptp_phys(atc->vm, index); |
170 | void *kvirt_addr; | ||
171 | unsigned long phys_addr; | ||
172 | |||
173 | vm = atc->vm; | ||
174 | kvirt_addr = vm->get_ptp_virt(vm, index); | ||
175 | if (kvirt_addr == NULL) | ||
176 | phys_addr = (~0UL); | ||
177 | else | ||
178 | phys_addr = virt_to_phys(kvirt_addr); | ||
179 | |||
180 | return phys_addr; | ||
181 | } | 170 | } |
182 | 171 | ||
183 | static unsigned int convert_format(snd_pcm_format_t snd_format) | 172 | static unsigned int convert_format(snd_pcm_format_t snd_format) |
@@ -1669,7 +1658,7 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, | |||
1669 | } | 1658 | } |
1670 | 1659 | ||
1671 | /* Set up device virtual memory management object */ | 1660 | /* Set up device virtual memory management object */ |
1672 | err = ct_vm_create(&atc->vm); | 1661 | err = ct_vm_create(&atc->vm, pci); |
1673 | if (err < 0) | 1662 | if (err < 0) |
1674 | goto error1; | 1663 | goto error1; |
1675 | 1664 | ||
diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index 6b78752e9503..65da6e466f80 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c | |||
@@ -138,7 +138,7 @@ ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size) | |||
138 | return NULL; | 138 | return NULL; |
139 | } | 139 | } |
140 | 140 | ||
141 | ptp = vm->ptp[0]; | 141 | ptp = (unsigned long *)vm->ptp[0].area; |
142 | pte_start = (block->addr >> CT_PAGE_SHIFT); | 142 | pte_start = (block->addr >> CT_PAGE_SHIFT); |
143 | pages = block->size >> CT_PAGE_SHIFT; | 143 | pages = block->size >> CT_PAGE_SHIFT; |
144 | for (i = 0; i < pages; i++) { | 144 | for (i = 0; i < pages; i++) { |
@@ -158,25 +158,25 @@ static void ct_vm_unmap(struct ct_vm *vm, struct ct_vm_block *block) | |||
158 | } | 158 | } |
159 | 159 | ||
160 | /* * | 160 | /* * |
161 | * return the host (kmalloced) addr of the @index-th device | 161 | * return the host physical addr of the @index-th device |
162 | * page talbe page on success, or NULL on failure. | 162 | * page table page on success, or ~0UL on failure. |
163 | * The first returned NULL indicates the termination. | 163 | * The first returned ~0UL indicates the termination. |
164 | * */ | 164 | * */ |
165 | static void * | 165 | static dma_addr_t |
166 | ct_get_ptp_virt(struct ct_vm *vm, int index) | 166 | ct_get_ptp_phys(struct ct_vm *vm, int index) |
167 | { | 167 | { |
168 | void *addr; | 168 | dma_addr_t addr; |
169 | 169 | ||
170 | addr = (index >= CT_PTP_NUM) ? NULL : vm->ptp[index]; | 170 | addr = (index >= CT_PTP_NUM) ? ~0UL : vm->ptp[index].addr; |
171 | 171 | ||
172 | return addr; | 172 | return addr; |
173 | } | 173 | } |
174 | 174 | ||
175 | int ct_vm_create(struct ct_vm **rvm) | 175 | int ct_vm_create(struct ct_vm **rvm, struct pci_dev *pci) |
176 | { | 176 | { |
177 | struct ct_vm *vm; | 177 | struct ct_vm *vm; |
178 | struct ct_vm_block *block; | 178 | struct ct_vm_block *block; |
179 | int i; | 179 | int i, err = 0; |
180 | 180 | ||
181 | *rvm = NULL; | 181 | *rvm = NULL; |
182 | 182 | ||
@@ -188,23 +188,21 @@ int ct_vm_create(struct ct_vm **rvm) | |||
188 | 188 | ||
189 | /* Allocate page table pages */ | 189 | /* Allocate page table pages */ |
190 | for (i = 0; i < CT_PTP_NUM; i++) { | 190 | for (i = 0; i < CT_PTP_NUM; i++) { |
191 | vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL); | 191 | err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, |
192 | if (!vm->ptp[i]) | 192 | snd_dma_pci_data(pci), |
193 | PAGE_SIZE, &vm->ptp[i]); | ||
194 | if (err < 0) | ||
193 | break; | 195 | break; |
194 | } | 196 | } |
195 | if (!i) { | 197 | if (err < 0) { |
196 | /* no page table pages are allocated */ | 198 | /* no page table pages are allocated */ |
197 | kfree(vm); | 199 | ct_vm_destroy(vm); |
198 | return -ENOMEM; | 200 | return -ENOMEM; |
199 | } | 201 | } |
200 | vm->size = CT_ADDRS_PER_PAGE * i; | 202 | vm->size = CT_ADDRS_PER_PAGE * i; |
201 | /* Initialise remaining ptps */ | ||
202 | for (; i < CT_PTP_NUM; i++) | ||
203 | vm->ptp[i] = NULL; | ||
204 | |||
205 | vm->map = ct_vm_map; | 203 | vm->map = ct_vm_map; |
206 | vm->unmap = ct_vm_unmap; | 204 | vm->unmap = ct_vm_unmap; |
207 | vm->get_ptp_virt = ct_get_ptp_virt; | 205 | vm->get_ptp_phys = ct_get_ptp_phys; |
208 | INIT_LIST_HEAD(&vm->unused); | 206 | INIT_LIST_HEAD(&vm->unused); |
209 | INIT_LIST_HEAD(&vm->used); | 207 | INIT_LIST_HEAD(&vm->used); |
210 | block = kzalloc(sizeof(*block), GFP_KERNEL); | 208 | block = kzalloc(sizeof(*block), GFP_KERNEL); |
@@ -242,7 +240,7 @@ void ct_vm_destroy(struct ct_vm *vm) | |||
242 | 240 | ||
243 | /* free allocated page table pages */ | 241 | /* free allocated page table pages */ |
244 | for (i = 0; i < CT_PTP_NUM; i++) | 242 | for (i = 0; i < CT_PTP_NUM; i++) |
245 | kfree(vm->ptp[i]); | 243 | snd_dma_free_pages(&vm->ptp[i]); |
246 | 244 | ||
247 | vm->size = 0; | 245 | vm->size = 0; |
248 | 246 | ||
diff --git a/sound/pci/ctxfi/ctvmem.h b/sound/pci/ctxfi/ctvmem.h index 01e4fd0386a3..b23adfca4de6 100644 --- a/sound/pci/ctxfi/ctvmem.h +++ b/sound/pci/ctxfi/ctvmem.h | |||
@@ -22,6 +22,8 @@ | |||
22 | 22 | ||
23 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | #include <linux/pci.h> | ||
26 | #include <sound/memalloc.h> | ||
25 | 27 | ||
26 | /* The chip can handle the page table of 4k pages | 28 | /* The chip can handle the page table of 4k pages |
27 | * (emu20k1 can handle even 8k pages, but we don't use it right now) | 29 | * (emu20k1 can handle even 8k pages, but we don't use it right now) |
@@ -41,7 +43,7 @@ struct snd_pcm_substream; | |||
41 | 43 | ||
42 | /* Virtual memory management object for card device */ | 44 | /* Virtual memory management object for card device */ |
43 | struct ct_vm { | 45 | struct ct_vm { |
44 | void *ptp[CT_PTP_NUM]; /* Device page table pages */ | 46 | struct snd_dma_buffer ptp[CT_PTP_NUM]; /* Device page table pages */ |
45 | unsigned int size; /* Available addr space in bytes */ | 47 | unsigned int size; /* Available addr space in bytes */ |
46 | struct list_head unused; /* List of unused blocks */ | 48 | struct list_head unused; /* List of unused blocks */ |
47 | struct list_head used; /* List of used blocks */ | 49 | struct list_head used; /* List of used blocks */ |
@@ -52,10 +54,10 @@ struct ct_vm { | |||
52 | int size); | 54 | int size); |
53 | /* Unmap device logical addr area. */ | 55 | /* Unmap device logical addr area. */ |
54 | void (*unmap)(struct ct_vm *, struct ct_vm_block *block); | 56 | void (*unmap)(struct ct_vm *, struct ct_vm_block *block); |
55 | void *(*get_ptp_virt)(struct ct_vm *vm, int index); | 57 | dma_addr_t (*get_ptp_phys)(struct ct_vm *vm, int index); |
56 | }; | 58 | }; |
57 | 59 | ||
58 | int ct_vm_create(struct ct_vm **rvm); | 60 | int ct_vm_create(struct ct_vm **rvm, struct pci_dev *pci); |
59 | void ct_vm_destroy(struct ct_vm *vm); | 61 | void ct_vm_destroy(struct ct_vm *vm); |
60 | 62 | ||
61 | #endif /* CTVMEM_H */ | 63 | #endif /* CTVMEM_H */ |