2002-09-29 18:47:19

by Jaroslav Kysela

[permalink] [raw]
Subject: [PATCH] ALSA update [6/10] - 2002/07/20

You can import this changeset into BK by piping this whole message to:
'| bk receive [path to repository]' or apply the patch as usual.

===================================================================


[email protected], 2002-09-25 17:57:54+02:00, [email protected]
ALSA update 2002/07/20 :
- added vfree_nocheck()
- PCM midlevel & EMU10K1 - added support for SG buffer
- CS4236 - added new ISA PnP ID
- HDSP - fixed rate rules (OSS emulation works)


include/sound/core.h | 2
include/sound/emu10k1.h | 3
include/sound/pcm.h | 4
include/sound/pcm_sgbuf.h | 60 +++++++
include/sound/sndmagic.h | 1
include/sound/version.h | 2
sound/core/Makefile | 5
sound/core/control.c | 1
sound/core/pcm_lib.c | 21 ++
sound/core/pcm_native.c | 9 -
sound/core/pcm_sgbuf.c | 321 +++++++++++++++++++++++++++++++++++++++
sound/core/rtctimer.c | 1
sound/core/sound.c | 2
sound/isa/cs423x/cs4236.c | 2
sound/pci/Config.help | 4
sound/pci/Config.in | 2
sound/pci/emu10k1/emupcm.c | 18 +-
sound/pci/emu10k1/memory.c | 20 +-
sound/pci/rme9652/hdsp.c | 20 --
sound/pci/via686.c | 366 +++++++++++++++++++--------------------------
20 files changed, 621 insertions(+), 243 deletions(-)


diff -Nru a/include/sound/core.h b/include/sound/core.h
--- a/include/sound/core.h Sun Sep 29 20:21:38 2002
+++ b/include/sound/core.h Sun Sep 29 20:21:38 2002
@@ -243,8 +243,10 @@
#define kfree_nocheck(obj) snd_wrapper_kfree(obj)
#define vmalloc(size) snd_hidden_vmalloc(size)
#define vfree(obj) snd_hidden_vfree(obj)
+#define vfree_nocheck(obj) snd_wrapper_vfree(obj)
#else
#define kfree_nocheck(obj) kfree(obj)
+#define vfree_nocheck(obj) vfree(obj)
#endif
void *snd_kcalloc(size_t size, int flags);
char *snd_kmalloc_strdup(const char *string, int flags);
diff -Nru a/include/sound/emu10k1.h b/include/sound/emu10k1.h
--- a/include/sound/emu10k1.h Sun Sep 29 20:21:38 2002
+++ b/include/sound/emu10k1.h Sun Sep 29 20:21:38 2002
@@ -26,6 +26,7 @@
#ifdef __KERNEL__

#include "pcm.h"
+#include "pcm_sgbuf.h"
#include "rawmidi.h"
#include "hwdep.h"
#include "ac97_codec.h"
@@ -1043,7 +1044,7 @@
unsigned char snd_emu10k1_sum_vol_attn(unsigned int value);

/* memory allocation */
-snd_util_memblk_t *snd_emu10k1_alloc_pages(emu10k1_t *emu, dma_addr_t addr, unsigned long size);
+snd_util_memblk_t *snd_emu10k1_alloc_pages(emu10k1_t *emu, struct snd_sg_buf *sgbuf);
int snd_emu10k1_free_pages(emu10k1_t *emu, snd_util_memblk_t *blk);
snd_util_memblk_t *snd_emu10k1_synth_alloc(emu10k1_t *emu, unsigned int size);
int snd_emu10k1_synth_free(emu10k1_t *emu, snd_util_memblk_t *blk);
diff -Nru a/include/sound/pcm.h b/include/sound/pcm.h
--- a/include/sound/pcm.h Sun Sep 29 20:21:38 2002
+++ b/include/sound/pcm.h Sun Sep 29 20:21:38 2002
@@ -96,6 +96,7 @@
void *buf, snd_pcm_uframes_t count);
int (*silence)(snd_pcm_substream_t *substream, int channel,
snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
+ void *(*page)(snd_pcm_substream_t *substream, unsigned long offset);
} snd_pcm_ops_t;

/*
@@ -771,6 +772,9 @@
unsigned int cond,
snd_pcm_hw_param_t var,
unsigned long step);
+int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime,
+ unsigned int cond,
+ snd_pcm_hw_param_t var);
int snd_pcm_hw_rule_add(snd_pcm_runtime_t *runtime,
unsigned int cond,
int var,
diff -Nru a/include/sound/pcm_sgbuf.h b/include/sound/pcm_sgbuf.h
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/include/sound/pcm_sgbuf.h Sun Sep 29 20:21:38 2002
@@ -0,0 +1,60 @@
+#ifndef __SOUND_PCM_SGBUF_H
+#define __SOUND_PCM_SGBUF_H
+
+/*
+ * Scatter-Gather PCM access
+ *
+ * Copyright (c) by Takashi Iwai <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+struct snd_sg_page {
+ void *buf;
+ dma_addr_t addr;
+};
+
+struct snd_sg_buf {
+ int size; /* allocated byte size (= runtime->dma_bytes) */
+ int pages; /* allocated pages */
+ int tblsize; /* allocated table size */
+ struct snd_sg_page *table;
+ struct pci_dev *pci;
+};
+
+typedef struct snd_sg_buf snd_pcm_sgbuf_t; /* for magic cast */
+
+/*
+ * return the pages matching with the given byte size
+ */
+static inline unsigned int snd_pcm_sgbuf_pages(size_t size)
+{
+ return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+}
+
+
+int snd_pcm_sgbuf_init(snd_pcm_substream_t *substream, struct pci_dev *pci, int tblsize);
+int snd_pcm_sgbuf_delete(snd_pcm_substream_t *substream);
+int snd_pcm_sgbuf_alloc(snd_pcm_substream_t *substream, size_t size);
+int snd_pcm_sgbuf_free(snd_pcm_substream_t *substream);
+
+int snd_pcm_sgbuf_ops_copy_playback(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
+int snd_pcm_sgbuf_ops_copy_capture(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
+int snd_pcm_sgbuf_ops_silence(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, snd_pcm_uframes_t count);
+void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
+
+
+#endif /* __SOUND_PCM_SGBUF_H */
diff -Nru a/include/sound/sndmagic.h b/include/sound/sndmagic.h
--- a/include/sound/sndmagic.h Sun Sep 29 20:21:38 2002
+++ b/include/sound/sndmagic.h Sun Sep 29 20:21:38 2002
@@ -61,6 +61,7 @@
#define snd_pcm_proc_private_t_magic 0xa15a0104
#define snd_pcm_oss_file_t_magic 0xa15a0105
#define snd_mixer_oss_t_magic 0xa15a0106
+#define snd_pcm_sgbuf_t_magic 0xa15a0107

#define snd_info_private_data_t_magic 0xa15a0201
#define snd_ctl_file_t_magic 0xa15a0301
diff -Nru a/include/sound/version.h b/include/sound/version.h
--- a/include/sound/version.h Sun Sep 29 20:21:38 2002
+++ b/include/sound/version.h Sun Sep 29 20:21:38 2002
@@ -1,3 +1,3 @@
/* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc2"
-#define CONFIG_SND_DATE " (Wed Jul 17 10:56:41 2002 UTC)"
+#define CONFIG_SND_DATE " (Sat Jul 20 07:16:41 2002 UTC)"
diff -Nru a/sound/core/Makefile b/sound/core/Makefile
--- a/sound/core/Makefile Sun Sep 29 20:21:38 2002
+++ b/sound/core/Makefile Sun Sep 29 20:21:38 2002
@@ -3,7 +3,8 @@
# Copyright (c) 1999,2001 by Jaroslav Kysela <[email protected]>
#

-export-objs := sound.o pcm.o pcm_lib.o rawmidi.o timer.o hwdep.o
+export-objs := sound.o pcm.o pcm_lib.o rawmidi.o timer.o hwdep.o \
+ pcm_sgbuf.o

snd-objs := sound.o init.o isadma.o memory.o info.o control.o misc.o \
device.o wrappers.o
@@ -12,7 +13,7 @@
endif

snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
- pcm_memory.o
+ pcm_memory.o pcm_sgbuf.o

snd-rawmidi-objs := rawmidi.o
snd-timer-objs := timer.o
diff -Nru a/sound/core/control.c b/sound/core/control.c
--- a/sound/core/control.c Sun Sep 29 20:21:38 2002
+++ b/sound/core/control.c Sun Sep 29 20:21:38 2002
@@ -21,6 +21,7 @@

#define __NO_VERSION__
#include <sound/driver.h>
+#include <linux/threads.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
diff -Nru a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
--- a/sound/core/pcm_lib.c Sun Sep 29 20:21:38 2002
+++ b/sound/core/pcm_lib.c Sun Sep 29 20:21:38 2002
@@ -960,6 +960,26 @@
var, -1);
}

+static int snd_pcm_hw_rule_pow2(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule)
+{
+ static int pow2_sizes[] = {
+ 1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7,
+ 1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
+ 1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
+ 1<<24, 1<<25, 1<<26, 1<<27, 1<<28, 1<<29, 1<<30
+ };
+ return snd_interval_list(hw_param_interval(params, rule->var),
+ sizeof(pow2_sizes)/sizeof(int), pow2_sizes, 0);
+}
+
+int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime,
+ unsigned int cond,
+ snd_pcm_hw_param_t var)
+{
+ return snd_pcm_hw_rule_add(runtime, cond, var,
+ snd_pcm_hw_rule_pow2, NULL,
+ var, -1);
+}

/* To use the same code we have in alsa-lib */
#define snd_pcm_t snd_pcm_substream_t
@@ -2364,6 +2384,7 @@
EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
+EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
EXPORT_SYMBOL(snd_pcm_hw_rule_add);
EXPORT_SYMBOL(snd_pcm_set_ops);
EXPORT_SYMBOL(snd_pcm_set_sync);
diff -Nru a/sound/core/pcm_native.c b/sound/core/pcm_native.c
--- a/sound/core/pcm_native.c Sun Sep 29 20:21:38 2002
+++ b/sound/core/pcm_native.c Sun Sep 29 20:21:38 2002
@@ -2631,6 +2631,7 @@
snd_pcm_runtime_t *runtime;
unsigned long offset;
struct page * page;
+ void *vaddr;
size_t dma_bytes;

if (substream == NULL)
@@ -2646,7 +2647,13 @@
dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
if (offset > dma_bytes - PAGE_SIZE)
return NOPAGE_SIGBUS;
- page = virt_to_page(runtime->dma_area + offset);
+ if (substream->ops->page) {
+ vaddr = substream->ops->page(substream, offset);
+ if (! vaddr)
+ return NOPAGE_OOM;
+ } else
+ vaddr = runtime->dma_area + offset;
+ page = virt_to_page(vaddr);
get_page(page);
#ifndef LINUX_2_2
return page;
diff -Nru a/sound/core/pcm_sgbuf.c b/sound/core/pcm_sgbuf.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/sound/core/pcm_sgbuf.c Sun Sep 29 20:21:38 2002
@@ -0,0 +1,321 @@
+/*
+ * Scatter-Gather PCM access
+ *
+ * Copyright (c) by Takashi Iwai <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_sgbuf.h>
+
+
+/* table entries are align to 32 */
+#define SGBUF_TBL_ALIGN 32
+#define sgbuf_align_table(tbl) ((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN)
+
+/*
+ * shrink to the given pages.
+ * free the unused pages
+ */
+static void sgbuf_shrink(struct snd_sg_buf *sgbuf, int pages)
+{
+ snd_assert(sgbuf, return);
+ if (! sgbuf->table)
+ return;
+ while (sgbuf->pages > pages) {
+ sgbuf->pages--;
+ snd_free_pci_pages(sgbuf->pci, PAGE_SIZE,
+ sgbuf->table[sgbuf->pages].buf,
+ sgbuf->table[sgbuf->pages].addr);
+ }
+}
+
+/*
+ * initialize the sg buffer
+ * assigned to substream->dma_private.
+ * initialize the table with the given size.
+ */
+int snd_pcm_sgbuf_init(snd_pcm_substream_t *substream, struct pci_dev *pci, int tblsize)
+{
+ struct snd_sg_buf *sgbuf;
+
+ tblsize = sgbuf_align_table(tblsize);
+ sgbuf = snd_magic_kcalloc(snd_pcm_sgbuf_t, 0, GFP_KERNEL);
+ if (! sgbuf)
+ return -ENOMEM;
+ substream->dma_private = sgbuf;
+ sgbuf->pci = pci;
+ sgbuf->pages = 0;
+ sgbuf->tblsize = tblsize;
+ sgbuf->table = kmalloc(sizeof(struct snd_sg_page) * tblsize, GFP_KERNEL);
+ if (! sgbuf->table) {
+ snd_pcm_sgbuf_free(substream);
+ return -ENOMEM;
+ }
+ memset(sgbuf->table, 0, sizeof(struct snd_sg_page) * tblsize);
+ return 0;
+}
+
+/*
+ * release all pages and free the sgbuf instance
+ */
+int snd_pcm_sgbuf_delete(snd_pcm_substream_t *substream)
+{
+ struct snd_sg_buf *sgbuf;
+
+ sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+ sgbuf_shrink(sgbuf, 0);
+ if (sgbuf->table)
+ kfree(sgbuf->table);
+ snd_magic_kfree(sgbuf);
+ substream->dma_private = NULL;
+ return 0;
+}
+
+/*
+ * allocate sg buffer table with the given byte size.
+ * if the buffer table already exists, try to resize it.
+ * call this from hw_params callback.
+ */
+int snd_pcm_sgbuf_alloc(snd_pcm_substream_t *substream, size_t size)
+{
+ struct snd_sg_buf *sgbuf;
+ unsigned int pages;
+ unsigned int tblsize;
+ int changed = 0;
+
+ sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+ pages = snd_pcm_sgbuf_pages(size);
+ tblsize = sgbuf_align_table(pages);
+ if (pages < sgbuf->pages) {
+ /* release unsed pages */
+ sgbuf_shrink(sgbuf, pages);
+ substream->runtime->dma_bytes = size;
+ return 1; /* changed */
+ } else if (pages > sgbuf->tblsize) {
+ /* bigger than existing one. reallocate the table. */
+ struct snd_sg_page *table;
+ table = kmalloc(sizeof(*table) * tblsize, GFP_KERNEL);
+ if (! table)
+ return -ENOMEM;
+ memcpy(table, sgbuf->table, sizeof(*table) * sgbuf->tblsize);
+ kfree(sgbuf->table);
+ sgbuf->table = table;
+ sgbuf->tblsize = tblsize;
+ }
+ /* allocate each page */
+ while (sgbuf->pages < pages) {
+ void *ptr;
+ dma_addr_t addr;
+ ptr = snd_malloc_pci_pages(sgbuf->pci, PAGE_SIZE, &addr);
+ if (! ptr)
+ return -ENOMEM;
+ sgbuf->table[sgbuf->pages].buf = ptr;
+ sgbuf->table[sgbuf->pages].addr = addr;
+ sgbuf->pages++;
+ changed = 1;
+ }
+ sgbuf->size = size;
+ substream->runtime->dma_bytes = size;
+ return changed;
+}
+
+/*
+ * free the sg buffer
+ * the table is kept.
+ * call this from hw_free callback.
+ */
+int snd_pcm_sgbuf_free(snd_pcm_substream_t *substream)
+{
+ struct snd_sg_buf *sgbuf;
+
+ sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+ sgbuf_shrink(sgbuf, 0);
+ return 0;
+}
+
+/*
+ * get the page pointer on the given offset
+ * used as the page callback of pcm ops
+ */
+void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
+{
+ struct snd_sg_buf *sgbuf;
+ unsigned int idx;
+
+ sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return NULL);
+ idx = offset >> PAGE_SHIFT;
+ if (idx >= sgbuf->pages)
+ return 0;
+ return sgbuf->table[idx].buf;
+}
+
+/*
+ * do copy_from_user to the sg buffer
+ */
+static int copy_from_user_sg_buf(snd_pcm_substream_t *substream,
+ char *buf, size_t hwoff, ssize_t bytes)
+{
+ int len;
+ char *addr;
+ size_t p = (hwoff >> PAGE_SHIFT) << PAGE_SHIFT;
+ hwoff -= p;
+ len = PAGE_SIZE - hwoff;
+ for (;;) {
+ addr = snd_pcm_sgbuf_ops_page(substream, p);
+ if (! addr)
+ return -EFAULT;
+ if (len > bytes)
+ len = bytes;
+ if (copy_from_user(addr + hwoff, buf, len))
+ return -EFAULT;
+ bytes -= len;
+ if (bytes <= 0)
+ break;
+ buf += len;
+ p += PAGE_SIZE;
+ len = PAGE_SIZE;
+ hwoff = 0;
+ }
+ return 0;
+}
+
+/*
+ * do copy_to_user from the sg buffer
+ */
+static int copy_to_user_sg_buf(snd_pcm_substream_t *substream,
+ char *buf, size_t hwoff, ssize_t bytes)
+{
+ int len;
+ char *addr;
+ size_t p = (hwoff >> PAGE_SHIFT) << PAGE_SHIFT;
+ hwoff -= p;
+ len = PAGE_SIZE - hwoff;
+ for (;;) {
+ addr = snd_pcm_sgbuf_ops_page(substream, p);
+ if (! addr)
+ return -EFAULT;
+ if (len > bytes)
+ len = bytes;
+ if (copy_to_user(buf, addr + hwoff, len))
+ return -EFAULT;
+ bytes -= len;
+ if (bytes <= 0)
+ break;
+ buf += len;
+ p += PAGE_SIZE;
+ len = PAGE_SIZE;
+ hwoff = 0;
+ }
+ return 0;
+}
+
+/*
+ * set silence on the sg buffer
+ */
+static int set_silence_sg_buf(snd_pcm_substream_t *substream,
+ size_t hwoff, ssize_t samples)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int len, page_len;
+ char *addr;
+ size_t p = (hwoff >> PAGE_SHIFT) << PAGE_SHIFT;
+ hwoff -= p;
+ len = bytes_to_samples(substream->runtime, PAGE_SIZE - hwoff);
+ page_len = bytes_to_samples(substream->runtime, PAGE_SIZE);
+ for (;;) {
+ addr = snd_pcm_sgbuf_ops_page(substream, p);
+ if (! addr)
+ return -EFAULT;
+ if (len > samples)
+ len = samples;
+ snd_pcm_format_set_silence(runtime->format, addr + hwoff, len);
+ samples -= len;
+ if (samples <= 0)
+ break;
+ p += PAGE_SIZE;
+ len = page_len;
+ hwoff = 0;
+ }
+ return 0;
+}
+
+/*
+ * copy callback for playback pcm ops
+ */
+int snd_pcm_sgbuf_ops_copy_playback(snd_pcm_substream_t *substream, int channel,
+ snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ if (channel < 0) {
+ return copy_from_user_sg_buf(substream, buf, frames_to_bytes(runtime, hwoff), frames_to_bytes(runtime, count));
+ } else {
+ size_t dma_csize = runtime->dma_bytes / runtime->channels;
+ size_t c_ofs = (channel * dma_csize) + samples_to_bytes(runtime, hwoff);
+ return copy_from_user_sg_buf(substream, buf, c_ofs, samples_to_bytes(runtime, count));
+ }
+}
+
+/*
+ * copy callback for capture pcm ops
+ */
+int snd_pcm_sgbuf_ops_copy_capture(snd_pcm_substream_t *substream, int channel,
+ snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ if (channel < 0) {
+ return copy_to_user_sg_buf(substream, buf, frames_to_bytes(runtime, hwoff), frames_to_bytes(runtime, count));
+ } else {
+ size_t dma_csize = runtime->dma_bytes / runtime->channels;
+ size_t c_ofs = (channel * dma_csize) + samples_to_bytes(runtime, hwoff);
+ return copy_to_user_sg_buf(substream, buf, c_ofs, samples_to_bytes(runtime, count));
+ }
+}
+
+/*
+ * silence callback for pcm ops
+ */
+int snd_pcm_sgbuf_ops_silence(snd_pcm_substream_t *substream, int channel,
+ snd_pcm_uframes_t hwoff, snd_pcm_uframes_t count)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ if (channel < 0) {
+ return set_silence_sg_buf(substream, frames_to_bytes(runtime, hwoff),
+ frames_to_bytes(runtime, count));
+ } else {
+ size_t dma_csize = runtime->dma_bytes / runtime->channels;
+ size_t c_ofs = (channel * dma_csize) + samples_to_bytes(runtime, hwoff);
+ return set_silence_sg_buf(substream, c_ofs, samples_to_bytes(runtime, count));
+ }
+}
+
+
+/*
+ * Exported symbols
+ */
+EXPORT_SYMBOL(snd_pcm_sgbuf_init);
+EXPORT_SYMBOL(snd_pcm_sgbuf_delete);
+EXPORT_SYMBOL(snd_pcm_sgbuf_alloc);
+EXPORT_SYMBOL(snd_pcm_sgbuf_free);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_copy_playback);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_copy_capture);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_silence);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
diff -Nru a/sound/core/rtctimer.c b/sound/core/rtctimer.c
--- a/sound/core/rtctimer.c Sun Sep 29 20:21:38 2002
+++ b/sound/core/rtctimer.c Sun Sep 29 20:21:38 2002
@@ -23,6 +23,7 @@
#include <sound/driver.h>
#include <linux/init.h>
#include <linux/time.h>
+#include <linux/threads.h>
#include <linux/interrupt.h>
#include <sound/core.h>
#include <sound/timer.h>
diff -Nru a/sound/core/sound.c b/sound/core/sound.c
--- a/sound/core/sound.c Sun Sep 29 20:21:38 2002
+++ b/sound/core/sound.c Sun Sep 29 20:21:38 2002
@@ -501,6 +501,8 @@
#ifdef CONFIG_SND_DEBUG_MEMORY
EXPORT_SYMBOL(snd_wrapper_kmalloc);
EXPORT_SYMBOL(snd_wrapper_kfree);
+EXPORT_SYMBOL(snd_wrapper_vmalloc);
+EXPORT_SYMBOL(snd_wrapper_vfree);
#endif
#ifdef HACK_PCI_ALLOC_CONSISTENT
EXPORT_SYMBOL(snd_pci_hack_alloc_consistent);
diff -Nru a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
--- a/sound/isa/cs423x/cs4236.c Sun Sep 29 20:21:38 2002
+++ b/sound/isa/cs423x/cs4236.c Sun Sep 29 20:21:38 2002
@@ -227,6 +227,8 @@
ISAPNP_CS4232('C','S','C',0x4336,0x0000,0x0010,0x0003),
/* Typhoon Soundsystem PnP - CS4236B */
ISAPNP_CS4232('C','S','C',0x4536,0x0000,0x0010,0x0003),
+ /* Crystal CX4235-XQ3 EP - CS4235 */
+ ISAPNP_CS4232('C','S','C',0x4625,0x0100,0x0110,0x0103),
/* TerraTec AudioSystem EWS64XL - CS4236B */
ISAPNP_CS4232('C','S','C',0xa836,0xa800,0xa810,0xa803),
/* TerraTec AudioSystem EWS64XL - CS4236B */
diff -Nru a/sound/pci/Config.help b/sound/pci/Config.help
--- a/sound/pci/Config.help Sun Sep 29 20:21:38 2002
+++ b/sound/pci/Config.help Sun Sep 29 20:21:38 2002
@@ -7,6 +7,10 @@

CONFIG_SND_CS46XX_ACCEPT_VALID
Say 'Y' to allow sample resolution for mmap() transfers.
+ Note: This can be also specified via module option snd_mmap_valid.
+
+CONFIG_SND_CS4281
+ Say 'Y' or 'M' to include support for Cirrus Logic CS4281.

CONFIG_SND_EMU10K1
Say 'Y' or 'M' to include support for Sound Blaster PCI 512, Live!,
diff -Nru a/sound/pci/Config.in b/sound/pci/Config.in
--- a/sound/pci/Config.in Sun Sep 29 20:21:38 2002
+++ b/sound/pci/Config.in Sun Sep 29 20:21:38 2002
@@ -8,7 +8,7 @@
if [ "$CONFIG_SND_CS46XX" != "n" ]; then
bool ' Cirrus Logic (Sound Fusion) MMAP support for OSS' CONFIG_SND_CS46XX_ACCEPT_VALID
fi
-dep_tristate 'Cirrus Logic (Sound Fusion) CS4281' CONFIG_SND_CS4281 $CONFIG_SND
+dep_tristate 'Cirrus Logic CS4281' CONFIG_SND_CS4281 $CONFIG_SND
dep_tristate 'EMU10K1 (SB Live!, E-mu APS)' CONFIG_SND_EMU10K1 $CONFIG_SND
dep_tristate 'Korg 1212 IO' CONFIG_SND_KORG1212 $CONFIG_SND
dep_tristate 'NeoMagic NM256AV/ZX' CONFIG_SND_NM256 $CONFIG_SND
diff -Nru a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
--- a/sound/pci/emu10k1/emupcm.c Sun Sep 29 20:21:38 2002
+++ b/sound/pci/emu10k1/emupcm.c Sun Sep 29 20:21:38 2002
@@ -32,6 +32,7 @@
#include <linux/init.h>
#include <sound/core.h>
#include <sound/emu10k1.h>
+#include <sound/pcm_sgbuf.h>

#define chip_t emu10k1_t

@@ -358,13 +359,13 @@

if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0)
return err;
- if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
+ if ((err = snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params))) < 0)
return err;
if (err > 0) { /* change */
snd_util_memblk_t *memblk;
if (epcm->memblk != NULL)
snd_emu10k1_free_pages(emu, epcm->memblk);
- memblk = snd_emu10k1_alloc_pages(emu, runtime->dma_addr, runtime->dma_bytes);
+ memblk = snd_emu10k1_alloc_pages(emu, (struct snd_sg_buf *)substream->dma_private);
if ((epcm->memblk = memblk) == NULL || ((emu10k1_memblk_t *)memblk)->mapped_page < 0) {
epcm->start_addr = 0;
return -ENOMEM;
@@ -400,7 +401,7 @@
epcm->memblk = NULL;
epcm->start_addr = 0;
}
- snd_pcm_lib_free_pages(substream);
+ snd_pcm_sgbuf_free(substream);
return 0;
}

@@ -778,6 +779,10 @@
runtime->private_data = epcm;
runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_playback;
+ if ((err = snd_pcm_sgbuf_init(substream, emu->pci, 32)) < 0) {
+ snd_magic_kfree(epcm);
+ return err;
+ }
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) {
snd_magic_kfree(epcm);
return err;
@@ -804,6 +809,7 @@
emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[substream->number];

mix->epcm = NULL;
+ snd_pcm_sgbuf_delete(substream);
snd_emu10k1_pcm_mixer_notify(emu->card, mix, 0);
return 0;
}
@@ -942,6 +948,9 @@
prepare: snd_emu10k1_playback_prepare,
trigger: snd_emu10k1_playback_trigger,
pointer: snd_emu10k1_playback_pointer,
+ copy: snd_pcm_sgbuf_ops_copy_playback,
+ silence: snd_pcm_sgbuf_ops_silence,
+ page: snd_pcm_sgbuf_ops_page,
};

static snd_pcm_ops_t snd_emu10k1_capture_ops = {
@@ -959,7 +968,6 @@
{
emu10k1_t *emu = snd_magic_cast(emu10k1_t, pcm->private_data, return);
emu->pcm = NULL;
- snd_pcm_lib_preallocate_free_for_all(pcm);
}

int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
@@ -983,8 +991,6 @@
pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
strcpy(pcm->name, "EMU10K1");
emu->pcm = pcm;
-
- snd_pcm_lib_preallocate_pci_pages_for_all(emu->pci, pcm, 64*1024, 128*1024);

if (rpcm)
*rpcm = pcm;
diff -Nru a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
--- a/sound/pci/emu10k1/memory.c Sun Sep 29 20:21:38 2002
+++ b/sound/pci/emu10k1/memory.c Sun Sep 29 20:21:38 2002
@@ -289,22 +289,19 @@
* page allocation for DMA
*/
snd_util_memblk_t *
-snd_emu10k1_alloc_pages(emu10k1_t *emu, dma_addr_t addr, unsigned long size)
+snd_emu10k1_alloc_pages(emu10k1_t *emu, struct snd_sg_buf *sgbuf)
{
snd_util_memhdr_t *hdr;
emu10k1_memblk_t *blk;
- int page, err;
+ int page, err, idx;

snd_assert(emu, return NULL);
- snd_assert(size > 0 && size < MAXPAGES * EMUPAGESIZE, return NULL);
+ snd_assert(sgbuf->size > 0 && sgbuf->size < MAXPAGES * EMUPAGESIZE, return NULL);
hdr = emu->memhdr;
snd_assert(hdr, return NULL);

- if (!is_valid_page(addr))
- return NULL;
-
down(&hdr->block_mutex);
- blk = search_empty(emu, size);
+ blk = search_empty(emu, sgbuf->size);
if (blk == NULL) {
up(&hdr->block_mutex);
return NULL;
@@ -312,10 +309,15 @@
/* fill buffer addresses but pointers are not stored so that
* snd_free_pci_pages() is not called in in synth_free()
*/
- for (page = blk->first_page; page <= blk->last_page; page++) {
+ idx = 0;
+ for (page = blk->first_page; page <= blk->last_page; page++, idx++) {
+ dma_addr_t addr = sgbuf->table[idx].addr;
+ if (! is_valid_page(addr)) {
+ up(&hdr->block_mutex);
+ return NULL;
+ }
emu->page_addr_table[page] = addr;
emu->page_ptr_table[page] = NULL;
- addr += PAGE_SIZE;
}

/* set PTB entries */
diff -Nru a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
--- a/sound/pci/rme9652/hdsp.c Sun Sep 29 20:21:38 2002
+++ b/sound/pci/rme9652/hdsp.c Sun Sep 29 20:21:38 2002
@@ -482,7 +482,6 @@
if (hdsp_fifo_wait(hdsp, 127, HDSP_LONG_WAIT)) {
return -1;
}
-
hdsp_write (hdsp, HDSP_fifoData, ad);
hdsp->mixer_matrix[addr] = data;

@@ -854,10 +853,7 @@
}

if (clear_timer && hmidi->istimer && --hmidi->istimer <= 0) {
- printk ("removing timer because there is nothing to do\n");
- if (del_timer(&hmidi->timer)) {
- printk ("not removed\n");
- }
+ del_timer(&hmidi->timer);
}
}

@@ -956,16 +952,12 @@
hmidi->timer.function = snd_hdsp_midi_output_timer;
hmidi->timer.data = (unsigned long) hmidi;
hmidi->timer.expires = 1 + jiffies;
- printk ("add timer from output trigger\n");
add_timer(&hmidi->timer);
hmidi->istimer++;
}
} else {
if (hmidi->istimer && --hmidi->istimer <= 0) {
- printk ("remove timer in trigger off\n");
- if (del_timer (&hmidi->timer)) {
- printk ("not removed\n");
- }
+ del_timer (&hmidi->timer);
}
}
spin_unlock_irqrestore (&hmidi->lock, flags);
@@ -2560,7 +2552,7 @@
SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_DOUBLE),
formats: SNDRV_PCM_FMTBIT_S32_LE,
- rates: (SNDRV_PCM_RATE_32000 |
+ rates: (SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_64000 |
@@ -2635,7 +2627,7 @@
integer: 1,
};
return snd_interval_refine(c, &t);
- } else if (r->max < 88200) {
+ } else if (r->max < 64000) {
snd_interval_t t = {
min: hdsp->ss_channels,
max: hdsp->ss_channels,
@@ -2654,14 +2646,14 @@
snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
if (c->min >= hdsp->ss_channels) {
snd_interval_t t = {
- min: 44100,
+ min: 32000,
max: 48000,
integer: 1,
};
return snd_interval_refine(r, &t);
} else if (c->max <= hdsp->ds_channels) {
snd_interval_t t = {
- min: 88200,
+ min: 64000,
max: 96000,
integer: 1,
};
diff -Nru a/sound/pci/via686.c b/sound/pci/via686.c
--- a/sound/pci/via686.c Sun Sep 29 20:21:38 2002
+++ b/sound/pci/via686.c Sun Sep 29 20:21:38 2002
@@ -28,6 +28,8 @@
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
+#include <sound/pcm_sgbuf.h>
+#include <sound/pcm_params.h>
#include <sound/info.h>
#include <sound/ac97_codec.h>
#include <sound/mpu401.h>
@@ -135,29 +137,92 @@
#define VIA_REG_AC97_DATA_MASK 0xffff
#define VIA_REG_SGD_SHADOW 0x84 /* dword */

-/*
- *
- */
-
-#define VIA_MAX_FRAGS 32
+#define VIA_TBL_BIT_FLAG 0x40000000
+#define VIA_TBL_BIT_EOL 0x80000000

/*
- *
+ * pcm stream
*/

typedef struct {
unsigned long reg_offset;
- unsigned int *table;
- dma_addr_t table_addr;
snd_pcm_substream_t *substream;
- dma_addr_t physbuf;
+ int running;
unsigned int size;
unsigned int fragsize;
unsigned int frags;
unsigned int lastptr;
unsigned int lastcount;
+ unsigned int page_per_frag;
+ unsigned int curidx;
+ unsigned int tbl_entries; /* number of descriptor table entries */
+ unsigned int tbl_size; /* size of a table entry */
+ u32 *table; /* physical address + flag */
+ dma_addr_t table_addr;
} viadev_t;

+
+static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
+ struct pci_dev *pci)
+{
+ int i, pages, size;
+ struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+
+ if (dev->table) {
+ pages = snd_pcm_sgbuf_pages(dev->tbl_entries * 8);
+ snd_free_pci_pages(pci, pages << PAGE_SHIFT, dev->table, dev->table_addr);
+ dev->table = NULL;
+ }
+
+ /* allocate buffer descriptor lists */
+ if (dev->fragsize < PAGE_SIZE) {
+ dev->tbl_size = dev->fragsize;
+ dev->tbl_entries = dev->frags;
+ dev->page_per_frag = 1;
+ } else {
+ dev->tbl_size = PAGE_SIZE;
+ dev->tbl_entries = sgbuf->pages;
+ dev->page_per_frag = dev->fragsize >> PAGE_SHIFT;
+ }
+ /* the start of each lists must be aligned to 8 bytes,
+ * but the kernel pages are much bigger, so we don't care
+ */
+ pages = snd_pcm_sgbuf_pages(dev->tbl_entries * 8);
+ dev->table = (u32*)snd_malloc_pci_pages(pci, pages << PAGE_SHIFT, &dev->table_addr);
+ if (! dev->table)
+ return -ENOMEM;
+
+ if (dev->tbl_size < PAGE_SIZE) {
+ for (i = 0; i < dev->tbl_entries; i++)
+ dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[0].addr + dev->fragsize * i);
+ } else {
+ for (i = 0; i < dev->tbl_entries; i++)
+ dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[i].addr);
+ }
+ size = dev->size;
+ for (i = 0; i < dev->tbl_entries - 1; i++) {
+ dev->table[(i << 1) + 1] = cpu_to_le32(VIA_TBL_BIT_FLAG | dev->tbl_size);
+ size -= dev->tbl_size;
+ }
+ dev->table[(dev->tbl_entries << 1) - 1] = cpu_to_le32(VIA_TBL_BIT_EOL | size);
+
+ return 0;
+}
+
+
+static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
+ struct pci_dev *pci)
+{
+ if (dev->table) {
+ snd_free_pci_pages(pci, snd_pcm_sgbuf_pages(dev->tbl_entries * 8) << PAGE_SHIFT, dev->table, dev->table_addr);
+ dev->table = NULL;
+ }
+}
+
+
+/*
+ */
+
typedef struct _snd_via686a via686a_t;
#define chip_t via686a_t

@@ -178,7 +243,7 @@
snd_pcm_t *pcm_fm;
viadev_t playback;
viadev_t capture;
- viadev_t playback_fm;
+ /*viadev_t playback_fm;*/

snd_rawmidi_t *rmidi;

@@ -188,9 +253,6 @@

spinlock_t reg_lock;
snd_info_entry_t *proc_entry;
-
- void *tables;
- dma_addr_t tables_addr;
};

static struct pci_device_id snd_via686a_ids[] __devinitdata = {
@@ -336,15 +398,19 @@
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
val = VIA_REG_CTRL_START;
+ viadev->running = 1;
break;
case SNDRV_PCM_TRIGGER_STOP:
val = VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET;
+ viadev->running = 0;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
val = VIA_REG_CTRL_PAUSE;
+ viadev->running = 1;
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
val = 0;
+ viadev->running = 0;
break;
default:
return -EINVAL;
@@ -355,44 +421,43 @@
return 0;
}

-static void snd_via686a_setup_periods(via686a_t *chip, viadev_t *viadev,
+
+static int snd_via686a_setup_periods(via686a_t *chip, viadev_t *viadev,
snd_pcm_substream_t *substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
- int idx, frags;
- unsigned int *table = viadev->table;
unsigned long port = chip->port + viadev->reg_offset;
+ int v, err;

- viadev->physbuf = runtime->dma_addr;
viadev->size = snd_pcm_lib_buffer_bytes(substream);
viadev->fragsize = snd_pcm_lib_period_bytes(substream);
viadev->frags = runtime->periods;
viadev->lastptr = ~0;
viadev->lastcount = ~0;
+ viadev->curidx = 0;
+
+ /* the period size must be in power of 2 */
+ v = ld2(viadev->fragsize);
+ if (viadev->fragsize != (1 << v)) {
+ snd_printd(KERN_ERR "invalid fragment size %d\n", viadev->fragsize);
+ return -EINVAL;
+ }

snd_via686a_channel_reset(chip, viadev);
- outl(viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
+
+ err = build_via_table(viadev, substream, chip->pci);
+ if (err < 0)
+ return err;
+
+ runtime->dma_bytes = viadev->size;
+ outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
outb(VIA_REG_TYPE_AUTOSTART |
(runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA_REG_TYPE_16BIT : 0) |
(runtime->channels > 1 ? VIA_REG_TYPE_STEREO : 0) |
((viadev->reg_offset & 0x10) == 0 ? VIA_REG_TYPE_INT_LSAMPLE : 0) |
VIA_REG_TYPE_INT_EOL |
VIA_REG_TYPE_INT_FLAG, port + VIA_REG_OFFSET_TYPE);
- if (viadev->size == viadev->fragsize) {
- table[0] = cpu_to_le32(viadev->physbuf);
- table[1] = cpu_to_le32(0xc0000000 | /* EOL + flag */
- viadev->fragsize);
- } else {
- frags = viadev->size / viadev->fragsize;
- for (idx = 0; idx < frags - 1; idx++) {
- table[(idx << 1) + 0] = cpu_to_le32(viadev->physbuf + (idx * viadev->fragsize));
- table[(idx << 1) + 1] = cpu_to_le32(0x40000000 | /* flag */
- viadev->fragsize);
- }
- table[((frags-1) << 1) + 0] = cpu_to_le32(viadev->physbuf + ((frags-1) * viadev->fragsize));
- table[((frags-1) << 1) + 1] = cpu_to_le32(0x80000000 | /* EOL */
- viadev->fragsize);
- }
+ return 0;
}

/*
@@ -401,8 +466,16 @@

static inline void snd_via686a_update(via686a_t *chip, viadev_t *viadev)
{
- snd_pcm_period_elapsed(viadev->substream);
outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset);
+ if (viadev->substream && viadev->running) {
+ viadev->curidx++;
+ if (viadev->curidx >= viadev->page_per_frag) {
+ viadev->curidx = 0;
+ spin_unlock(&chip->reg_lock);
+ snd_pcm_period_elapsed(viadev->substream);
+ spin_lock(&chip->reg_lock);
+ }
+ }
}

static void snd_via686a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -410,8 +483,10 @@
via686a_t *chip = snd_magic_cast(via686a_t, dev_id, return);
unsigned int status;

+ spin_lock(&chip->reg_lock);
status = inl(VIAREG(chip, SGD_SHADOW));
if ((status & 0x00000077) == 0) {
+ spin_unlock(&chip->reg_lock);
if (chip->rmidi != NULL) {
snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
}
@@ -419,10 +494,11 @@
}
if (inb(VIAREG(chip, PLAYBACK_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via686a_update(chip, &chip->playback);
- if (inb(VIAREG(chip, FM_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
- snd_via686a_update(chip, &chip->playback_fm);
if (inb(VIAREG(chip, CAPTURE_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via686a_update(chip, &chip->capture);
+ /*if (inb(VIAREG(chip, FM_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
+ snd_via686a_update(chip, &chip->playback_fm);*/
+ spin_unlock(&chip->reg_lock);
}

/*
@@ -448,12 +524,12 @@
static int snd_via686a_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params)
{
- return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+ return snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
}

static int snd_via686a_hw_free(snd_pcm_substream_t * substream)
{
- return snd_pcm_lib_free_pages(substream);
+ return 0;
}

static int snd_via686a_playback_prepare(snd_pcm_substream_t * substream)
@@ -462,8 +538,7 @@
snd_pcm_runtime_t *runtime = substream->runtime;

snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
- snd_via686a_setup_periods(chip, &chip->playback, substream);
- return 0;
+ return snd_via686a_setup_periods(chip, &chip->playback, substream);
}

static int snd_via686a_capture_prepare(snd_pcm_substream_t * substream)
@@ -472,8 +547,7 @@
snd_pcm_runtime_t *runtime = substream->runtime;

snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
- snd_via686a_setup_periods(chip, &chip->capture, substream);
- return 0;
+ return snd_via686a_setup_periods(chip, &chip->capture, substream);
}

static inline unsigned int snd_via686a_cur_ptr(via686a_t *chip, viadev_t *viadev)
@@ -486,9 +560,14 @@
ptr += 8;
if (!(inb(VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset) & VIA_REG_STAT_ACTIVE))
return 0;
- val = (((unsigned int)(ptr - viadev->table_addr) / 8) - 1) % viadev->frags;
- val *= viadev->fragsize;
- val += viadev->fragsize - count;
+ snd_assert(viadev->tbl_entries, return 0);
+ /* get index */
+ if (ptr <= (unsigned int)viadev->table_addr)
+ val = 0;
+ else
+ val = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries;
+ val *= viadev->tbl_size;
+ val += viadev->tbl_size - count;
viadev->lastptr = ptr;
viadev->lastcount = count;
// printk("pointer: ptr = 0x%x (%i), count = 0x%x, val = 0x%x\n", ptr, count, val);
@@ -522,8 +601,8 @@
buffer_bytes_max: 128 * 1024,
period_bytes_min: 32,
period_bytes_max: 128 * 1024,
- periods_min: 1,
- periods_max: VIA_MAX_FRAGS,
+ periods_min: 2,
+ periods_max: 1024,
fifo_size: 0,
};

@@ -541,8 +620,8 @@
buffer_bytes_max: 128 * 1024,
period_bytes_min: 32,
period_bytes_max: 128 * 1024,
- periods_min: 1,
- periods_max: VIA_MAX_FRAGS,
+ periods_min: 2,
+ periods_max: 1024,
fifo_size: 0,
};

@@ -555,10 +634,20 @@
chip->playback.substream = substream;
runtime->hw = snd_via686a_playback;
runtime->hw.rates = chip->ac97->rates_front_dac;
+ if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
+ return err;
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
+ if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
+ return err;
+#if 0
+ /* applying the following constraint together with the power-of-2 rule
+ * above may result in too narrow space.
+ * this one is not strictly necessary, so let's disable it.
+ */
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
+#endif
return 0;
}

@@ -571,10 +660,16 @@
chip->capture.substream = substream;
runtime->hw = snd_via686a_capture;
runtime->hw.rates = chip->ac97->rates_adc;
+ if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
+ return err;
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
+ if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
+ return err;
+#if 0
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
+#endif
return 0;
}

@@ -582,6 +677,8 @@
{
via686a_t *chip = snd_pcm_substream_chip(substream);

+ clean_via_table(&chip->playback, substream, chip->pci);
+ snd_pcm_sgbuf_delete(substream);
chip->playback.substream = NULL;
/* disable DAC power */
snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0200, 0x0200);
@@ -592,6 +689,8 @@
{
via686a_t *chip = snd_pcm_substream_chip(substream);

+ clean_via_table(&chip->capture, substream, chip->pci);
+ snd_pcm_sgbuf_delete(substream);
chip->capture.substream = NULL;
/* disable ADC power */
snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0100, 0x0100);
@@ -607,6 +706,9 @@
prepare: snd_via686a_playback_prepare,
trigger: snd_via686a_playback_trigger,
pointer: snd_via686a_playback_pointer,
+ copy: snd_pcm_sgbuf_ops_copy_playback,
+ silence: snd_pcm_sgbuf_ops_silence,
+ page: snd_pcm_sgbuf_ops_page,
};

static snd_pcm_ops_t snd_via686a_capture_ops = {
@@ -618,13 +720,15 @@
prepare: snd_via686a_capture_prepare,
trigger: snd_via686a_capture_trigger,
pointer: snd_via686a_capture_pointer,
+ copy: snd_pcm_sgbuf_ops_copy_capture,
+ silence: snd_pcm_sgbuf_ops_silence,
+ page: snd_pcm_sgbuf_ops_page,
};

static void snd_via686a_pcm_free(snd_pcm_t *pcm)
{
via686a_t *chip = snd_magic_cast(via686a_t, pcm->private_data, return);
chip->pcm = NULL;
- snd_pcm_lib_preallocate_free_for_all(pcm);
}

static int __devinit snd_via686a_pcm(via686a_t *chip, int device, snd_pcm_t ** rpcm)
@@ -647,146 +751,11 @@
strcpy(pcm->name, "VIA 82C686A");
chip->pcm = pcm;

- snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 128*1024);
-
if (rpcm)
*rpcm = NULL;
return 0;
}

-#if 0
-
-/*
- * PCM code - FM channel
- */
-
-static int snd_via686a_playback_fm_ioctl(snd_pcm_substream_t * substream,
- unsigned int cmd,
- void *arg)
-{
- return snd_pcm_lib_ioctl(substream, cmd, arg);
-}
-
-static int snd_via686a_playback_fm_trigger(snd_pcm_substream_t * substream,
- int cmd)
-{
- via686a_t *chip = snd_pcm_substream_chip(substream);
-
- return snd_via686a_trigger(chip, &chip->playback_fm, cmd);
-}
-
-static int snd_via686a_playback_fm_prepare(snd_pcm_substream_t * substream)
-{
- via686a_t *chip = snd_pcm_substream_chip(substream);
- snd_pcm_runtime_t *runtime = substream->runtime;
-
- snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
- snd_via686a_setup_periods(chip, &chip->playback_fm, substream);
- return 0;
-}
-
-static snd_pcm_uframes_t snd_via686a_playback_fm_pointer(snd_pcm_substream_t * substream)
-{
- via686a_t *chip = snd_pcm_substream_chip(substream);
- return bytes_to_frames(substream->runtime, snd_via686a_cur_ptr(chip, &chip->playback_fm));
-}
-
-static snd_pcm_hardware_t snd_via686a_playback_fm =
-{
- info: (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE),
- formats: SNDRV_PCM_FMTBIT_S16_LE,
- rates: SNDRV_PCM_RATE_KNOT,
- rate_min: 24000,
- rate_max: 24000,
- channels_min: 2,
- channels_max: 2,
- buffer_bytes_max: 128 * 1024,
- period_bytes_min: 32,
- period_bytes_max: 128 * 1024,
- periods_min: 1,
- periods_max: VIA_MAX_FRAGS,
- fifo_size: 0,
-};
-
-static int snd_via686a_playback_fm_open(snd_pcm_substream_t * substream)
-{
- via686a_t *chip = snd_pcm_substream_chip(substream);
- snd_pcm_runtime_t *runtime = substream->runtime;
- int err;
-
- if ((runtime->dma_area = snd_malloc_pci_pages_fallback(chip->pci, chip->dma_fm_size, &runtime->dma_addr, &runtime->dma_bytes)) == NULL)
- return -ENOMEM;
- chip->playback_fm.substream = substream;
- runtime->hw = snd_via686a_playback_fm;
-#if 0
- runtime->hw.rates = chip->ac97->rates_front_dac;
- if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
- runtime->hw.min_rate = 48000;
-#endif
- if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
- return err;
- return 0;
-}
-
-static int snd_via686a_playback_fm_close(snd_pcm_substream_t * substream)
-{
- via686a_t *chip = snd_pcm_substream_chip(substream);
- snd_pcm_runtime_t *runtime = substream->runtime;
-
- chip->playback_fm.substream = NULL;
- snd_free_pci_pages(chip->pci, runtime->dma_bytes, runtime->dma_area, runtime->dma_addr);
- /* disable DAC power */
- snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0200, 0x0200);
- return 0;
-}
-
-static snd_pcm_ops_t snd_via686a_playback_fm_ops = {
- open: snd_via686a_playback_fm_open,
- close: snd_via686a_playback_fm_close,
- ioctl: snd_pcm_lib_ioctl,
- prepare: snd_via686a_playback_fm_prepare,
- trigger: snd_via686a_playback_fm_trigger,
- pointer: snd_via686a_playback_fm_pointer,
-};
-
-static void snd_via686a_pcm_fm_free(void *private_data)
-{
- via686a_t *chip = snd_magic_cast(via686a_t, private_data, return);
- chip->pcm_fm = NULL;
- snd_pcm_lib_preallocate_pci_free_for_all(ensoniq->pci, pcm);
-}
-
-static int __devinit snd_via686a_pcm_fm(via686a_t *chip, int device, snd_pcm_t ** rpcm)
-{
- snd_pcm_t *pcm;
- int err;
-
- if (rpcm)
- *rpcm = NULL;
- err = snd_pcm_new(chip->card, "VIA 82C686A - FM DAC", device, 1, 0, &pcm);
- if (err < 0)
- return err;
-
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via686a_playback_fm_ops);
-
- pcm->private_data = chip;
- pcm->private_free = snd_via686a_pcm_fm_free;
- pcm->info_flags = 0;
- strcpy(pcm->name, "VIA 82C686A - FM DAC");
-
- snd_pcm_add_buffer_bytes_controls(pcm);
- snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024);
-
- chip->pcm_fm = pcm;
- if (rpcm)
- *rpcm = NULL;
- return 0;
-}
-
-#endif

/*
* Mixer part
@@ -979,7 +948,7 @@
/* disable interrupts */
snd_via686a_channel_reset(chip, &chip->playback);
snd_via686a_channel_reset(chip, &chip->capture);
- snd_via686a_channel_reset(chip, &chip->playback_fm);
+ /*snd_via686a_channel_reset(chip, &chip->playback_fm);*/
return 0;
}

@@ -990,13 +959,10 @@
/* disable interrupts */
snd_via686a_channel_reset(chip, &chip->playback);
snd_via686a_channel_reset(chip, &chip->capture);
- snd_via686a_channel_reset(chip, &chip->playback_fm);
+ /*snd_via686a_channel_reset(chip, &chip->playback_fm);*/
/* --- */
+ synchronize_irq(chip->irq);
__end_hw:
- if(chip->irq >= 0)
- synchronize_irq(chip->irq);
- if (chip->tables)
- snd_free_pci_pages(chip->pci, 3 * sizeof(unsigned int) * VIA_MAX_FRAGS * 2, chip->tables, chip->tables_addr);
if (chip->res_port) {
release_resource(chip->res_port);
kfree_nocheck(chip->res_port);
@@ -1061,23 +1027,7 @@
/* initialize offsets */
chip->playback.reg_offset = VIA_REG_PLAYBACK_STATUS;
chip->capture.reg_offset = VIA_REG_CAPTURE_STATUS;
- chip->playback_fm.reg_offset = VIA_REG_FM_STATUS;
-
- /* allocate buffer descriptor lists */
- /* the start of each lists must be aligned to 8 bytes */
- chip->tables = (unsigned int *)snd_malloc_pci_pages(pci, 3 * sizeof(unsigned int) * VIA_MAX_FRAGS * 2, &chip->tables_addr);
- if (chip->tables == NULL) {
- snd_via686a_free(chip);
- return -ENOMEM;
- }
- /* tables must be aligned to 8 bytes, but the kernel pages
- are much bigger, so we don't care */
- chip->playback.table = chip->tables;
- chip->playback.table_addr = chip->tables_addr;
- chip->capture.table = chip->playback.table + VIA_MAX_FRAGS * 2;
- chip->capture.table_addr = chip->playback.table_addr + sizeof(unsigned int) * VIA_MAX_FRAGS * 2;
- chip->playback_fm.table = chip->capture.table + VIA_MAX_FRAGS * 2;
- chip->playback_fm.table_addr = chip->capture.table_addr + sizeof(unsigned int) * VIA_MAX_FRAGS * 2;
+ /*chip->playback_fm.reg_offset = VIA_REG_FM_STATUS;*/

if ((err = snd_via686a_chip_init(chip)) < 0) {
snd_via686a_free(chip);

===================================================================


This BitKeeper patch contains the following changesets:
1.605.2.17
## Wrapped with gzip_uu ##


begin 664 bkpatch2473
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
M][email protected]%"$056<8Q?;VZ`UOO."&=;\U!(@M!J-1K6!D?WS7HLGMDD.M&A(
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
C%5/[RMK:#^(,@?&"OC0;S,>_6%!Q:.W7U_X&5>+/!N:&````
`
end

-----
Jaroslav Kysela <[email protected]>
Linux Kernel Sound Maintainer
ALSA Project http://www.alsa-project.org
SuSE Linux http://www.suse.com


2002-09-29 19:04:31

by Arjan van de Ven

[permalink] [raw]
Subject: Re: [PATCH] ALSA update [6/10] - 2002/07/20

On Sun, 2002-09-29 at 20:51, Jaroslav Kysela wrote:
> + sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);

hummmm magic casts?? why ?

> + ptr = snd_malloc_pci_pages(sgbuf->pci, PAGE_SIZE, &addr);

what is wrong with the PCI DMA API that makes ALSA wants a private
interface/implementation ?

> EXPORT_SYMBOL(snd_wrapper_kmalloc);
> EXPORT_SYMBOL(snd_wrapper_kfree);
> +EXPORT_SYMBOL(snd_wrapper_vmalloc);
> +EXPORT_SYMBOL(snd_wrapper_vfree);

why do you need a wrapper for vfree?




Attachments:
signature.asc (189.00 B)
This is a digitally signed message part

2002-09-29 19:24:15

by Jaroslav Kysela

[permalink] [raw]
Subject: Re: [PATCH] ALSA update [6/10] - 2002/07/20

On 29 Sep 2002, Arjan van de Ven wrote:

> On Sun, 2002-09-29 at 20:51, Jaroslav Kysela wrote:
> > + sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
>
> hummmm magic casts?? why ?

We are trying to check if 'void *' pointers in structures are used
correctly. It's our tool for debugging.

> > + ptr = snd_malloc_pci_pages(sgbuf->pci, PAGE_SIZE, &addr);
>
> what is wrong with the PCI DMA API that makes ALSA wants a private
> interface/implementation ?

These lines (i386 arch):

if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
gfp |= GFP_DMA;
ret = (void *)__get_free_pages(gfp, get_order(size));

Note that some of soundcards have various PCI DMA transfer limits
(dma_mask is not set to use full 32-bits). In this case, restricting this
hardware to allocate these buffers in first 16MB is not a very good idea.
Thus, we have own hacks to allocate memory in whole hardware area.

> > EXPORT_SYMBOL(snd_wrapper_kmalloc);
> > EXPORT_SYMBOL(snd_wrapper_kfree);
> > +EXPORT_SYMBOL(snd_wrapper_vmalloc);
> > +EXPORT_SYMBOL(snd_wrapper_vfree);
>
> why do you need a wrapper for vfree?

Debugging. We enumerate all allocations, so we can check for memory leaks.
I'm happy to say, that our code is very well debugged in this regard.

Jaroslav

-----
Jaroslav Kysela <[email protected]>
Linux Kernel Sound Maintainer
ALSA Project http://www.alsa-project.org
SuSE Linux http://www.suse.com

2002-09-29 19:48:06

by Jeff Garzik

[permalink] [raw]
Subject: Re: [PATCH] ALSA update [6/10] - 2002/07/20

Jaroslav Kysela wrote:
> On 29 Sep 2002, Arjan van de Ven wrote:
>>what is wrong with the PCI DMA API that makes ALSA wants a private
>>interface/implementation ?
>
>
> These lines (i386 arch):
>
> if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
> gfp |= GFP_DMA;
> ret = (void *)__get_free_pages(gfp, get_order(size));
>
> Note that some of soundcards have various PCI DMA transfer limits
> (dma_mask is not set to use full 32-bits). In this case, restricting this
> hardware to allocate these buffers in first 16MB is not a very good idea.
> Thus, we have own hacks to allocate memory in whole hardware area.

It sounds like it would be reasonable to fix the ia32 arch code, would
it not?


> Debugging. We enumerate all allocations, so we can check for memory leaks.
> I'm happy to say, that our code is very well debugged in this regard.

So are the net drivers, but without wrappers :)

2002-09-29 20:30:44

by Jaroslav Kysela

[permalink] [raw]
Subject: Re: [PATCH] ALSA update [6/10] - 2002/07/20

On Sun, 29 Sep 2002, Jeff Garzik wrote:

> Jaroslav Kysela wrote:
> > On 29 Sep 2002, Arjan van de Ven wrote:
> >>what is wrong with the PCI DMA API that makes ALSA wants a private
> >>interface/implementation ?
> >
> >
> > These lines (i386 arch):
> >
> > if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
> > gfp |= GFP_DMA;
> > ret = (void *)__get_free_pages(gfp, get_order(size));
> >
> > Note that some of soundcards have various PCI DMA transfer limits
> > (dma_mask is not set to use full 32-bits). In this case, restricting this
> > hardware to allocate these buffers in first 16MB is not a very good idea.
> > Thus, we have own hacks to allocate memory in whole hardware area.
>
> It sounds like it would be reasonable to fix the ia32 arch code, would
> it not?

We have simple method in our hack:

- try to allocate memory anywhere
- try to allocate memory with GFP DMA if first step fails

Here is updated pci-dma.c code for comments:

===== pci-dma.c 1.8 vs edited =====
--- 1.8/arch/i386/kernel/pci-dma.c Thu May 9 19:24:12 2002
+++ edited/pci-dma.c Sun Sep 29 22:26:46 2002
@@ -19,14 +19,24 @@
void *ret;
int gfp = GFP_ATOMIC;

- if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
+ if (hwdev == NULL || (u32)hwdev->dma_mask <= 0x00ffffff)
gfp |= GFP_DMA;
ret = (void *)__get_free_pages(gfp, get_order(size));

- if (ret != NULL) {
- memset(ret, 0, size);
- *dma_handle = virt_to_phys(ret);
+ if (ret == NULL)
+ return NULL;
+
+ /* try to allocate area in first 16MB memory */
+ if ((gfp & GFP_DMA) == 0 && (u32)hwdev->dma_mask != 0xffffffff &&
+ ((virt_to_phys(ret) + size - 1) & ~(u32)hwdev->dma_mask) != 0) {
+ free_pages(ret, get_order(size));
+ ret = (void *)__get_free_pages(gfp | GFP_DMA, get_order(size));
+ if (ret == NULL)
+ return NULL;
}
+
+ memset(ret, 0, size);
+ *dma_handle = virt_to_phys(ret);
return ret;
}

Jaroslav

-----
Jaroslav Kysela <[email protected]>
Linux Kernel Sound Maintainer
ALSA Project http://www.alsa-project.org
SuSE Linux http://www.suse.com

2002-09-29 21:07:49

by Alan

[permalink] [raw]
Subject: Re: [PATCH] ALSA update [6/10] - 2002/07/20

On Sun, 2002-09-29 at 21:34, Jaroslav Kysela wrote:
> - if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
> + if (hwdev == NULL || (u32)hwdev->dma_mask <= 0x00ffffff)
> gfp |= GFP_DMA;

This is wrong. You just broke ISA DMA handling, and also blocking of
devices with sub ISA requirements


2002-09-30 00:24:31

by David Miller

[permalink] [raw]
Subject: Re: [PATCH] ALSA update [6/10] - 2002/07/20

From: Arjan van de Ven <[email protected]>
Date: 29 Sep 2002 21:12:23 +0200

what is wrong with the PCI DMA API that makes ALSA wants a private
interface/implementation ?

It makes the layers not have to know what the BUS is, and this can all
be deleted when everything goes through a generic struct device and
assosciated OPS.

I think ALSA is definitely doing the right thing here.

2002-09-30 00:54:35

by David Miller

[permalink] [raw]
Subject: Re: [PATCH] ALSA update [6/10] - 2002/07/20

From: Jaroslav Kysela <[email protected]>
Date: Sun, 29 Sep 2002 22:34:51 +0200 (CEST)

- if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
+ if (hwdev == NULL || (u32)hwdev->dma_mask <= 0x00ffffff)
gfp |= GFP_DMA;

So alan, why is this really broken?

EISA/ISA DMA is defined as using a hwdev of NULL or requiring
<16MB address, he is preserving GFP_DMA in those cases.

The only problem I have with the patch is that it probably isn't
that hard to let the page allocator take some MASK arg (defaults
to all 1's) to implement this in 2.5.x

2002-09-30 12:43:02

by Alan

[permalink] [raw]
Subject: Re: [PATCH] ALSA update [6/10] - 2002/07/20

On Mon, 2002-09-30 at 01:53, David S. Miller wrote:
> From: Jaroslav Kysela <[email protected]>
> Date: Sun, 29 Sep 2002 22:34:51 +0200 (CEST)
>
> - if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
> + if (hwdev == NULL || (u32)hwdev->dma_mask <= 0x00ffffff)
> gfp |= GFP_DMA;
>
> So alan, why is this really broken?
>
> EISA/ISA DMA is defined as using a hwdev of NULL or requiring
> <16MB address, he is preserving GFP_DMA in those cases.

Firstly the DMA mask on x86 can't be below 24bits, we don't support
allocation from a smaller zone. Secondly what about PCI for 25-31bits -
there we do need to force gfp_dma to have any chance of getting the
right pages

Giving the page allocator a mask argument does sound a lot nicer

2002-09-30 16:12:50

by Jaroslav Kysela

[permalink] [raw]
Subject: Re: [PATCH] ALSA update [6/10] - 2002/07/20

On 30 Sep 2002, Alan Cox wrote:

> On Mon, 2002-09-30 at 01:53, David S. Miller wrote:
> > From: Jaroslav Kysela <[email protected]>
> > Date: Sun, 29 Sep 2002 22:34:51 +0200 (CEST)
> >
> > - if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
> > + if (hwdev == NULL || (u32)hwdev->dma_mask <= 0x00ffffff)
> > gfp |= GFP_DMA;
> >
> > So alan, why is this really broken?
> >
> > EISA/ISA DMA is defined as using a hwdev of NULL or requiring
> > <16MB address, he is preserving GFP_DMA in those cases.
>
> Firstly the DMA mask on x86 can't be below 24bits, we don't support
> allocation from a smaller zone. Secondly what about PCI for 25-31bits -
> there we do need to force gfp_dma to have any chance of getting the
> right pages

Not really. The test in original code - if the page is in right area - was
bellow first allocation. Sure, it's dirty hack.

> Giving the page allocator a mask argument does sound a lot nicer

Right, my aim was to point to a bug. Let's go to create proper DMA
allocation for broken hardware. I still wonder why hardware vendors are
lazy to support full bus addressing. Perhaps, saving few coins per
chip make them happy.

Jaroslav

-----
Jaroslav Kysela <[email protected]>
Linux Kernel Sound Maintainer
ALSA Project http://www.alsa-project.org
SuSE Linux http://www.suse.com

2002-09-30 20:34:43

by David Miller

[permalink] [raw]
Subject: Re: [PATCH] ALSA update [6/10] - 2002/07/20

From: Alan Cox <[email protected]>
Date: 30 Sep 2002 13:54:11 +0100

On Mon, 2002-09-30 at 01:53, David S. Miller wrote:
> EISA/ISA DMA is defined as using a hwdev of NULL or requiring
> <16MB address, he is preserving GFP_DMA in those cases.

Firstly the DMA mask on x86 can't be below 24bits, we don't support
allocation from a smaller zone.

Understood.

Secondly what about PCI for 25-31bits -
there we do need to force gfp_dma to have any chance of getting the
right pages

Look at what his code does after the GFP_DMA setting, it goes
a non-GFP_DMA setting, and if the 25-31 bits case is not satisfied
it backs down to GFP_DMA.

Giving the page allocator a mask argument does sound a lot nicer

It's pretty simple to implement too since we do have page_to_phys.