Page MenuHomeFreeBSD

D58064.id181386.diff
No OneTemporary

D58064.id181386.diff

Index: sys/dev/sound/pcm/channel.h
===================================================================
--- sys/dev/sound/pcm/channel.h
+++ sys/dev/sound/pcm/channel.h
@@ -434,11 +434,25 @@
* This should be large enough to hold all pcm data between
* tsleeps in chn_{read,write} at the highest sample rate.
* (which is usually 48kHz * 16bit * stereo = 192000 bytes/sec)
+ *
+ * The default size preserves historical memory use for low byte-rate
+ * streams. High channel-count or high sample-width streams can grow their
+ * secondary ring from the actual byte rate, capped by the
+ * hw.snd.secondary_buffer_max tunable.
*/
#define CHN_2NDBUFBLKSIZE (2 * 1024)
/* The total number of blocks per secondary bufhard. */
#define CHN_2NDBUFBLKNUM (32)
/* The size of a whole secondary bufhard. */
#define CHN_2NDBUFMAXSIZE (131072)
+/* Maximum accepted value for hw.snd.secondary_buffer_max. */
+#define CHN_2NDBUFMAXSIZE_MAX (1024 * 1024)
+/*
+ * Allow up to this much stream time when deriving the secondary-buffer cap
+ * from byte rate.
+ */
+#define CHN_2NDBUFMAXMS 200
+
+u_int32_t chn_2ndbufmaxsize(struct pcm_channel *);
#define CHANNEL_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, sizeof(struct kobj))
Index: sys/dev/sound/pcm/channel.c
===================================================================
--- sys/dev/sound/pcm/channel.c
+++ sys/dev/sound/pcm/channel.c
@@ -96,6 +96,29 @@
sysctl_hw_snd_latency_profile, "I",
"buffering latency profile (0=aggressive 1=safe)");
+static int chn_2ndbuf_maxsize = CHN_2NDBUFMAXSIZE_MAX;
+
+static int
+sysctl_hw_snd_secondary_buffer_max(SYSCTL_HANDLER_ARGS)
+{
+ int err, val;
+
+ val = chn_2ndbuf_maxsize;
+ err = sysctl_handle_int(oidp, &val, 0, req);
+ if (err != 0 || req->newptr == NULL)
+ return err;
+ if (val < CHN_2NDBUFMAXSIZE || val > CHN_2NDBUFMAXSIZE_MAX)
+ err = EINVAL;
+ else
+ chn_2ndbuf_maxsize = val;
+
+ return err;
+}
+SYSCTL_PROC(_hw_snd, OID_AUTO, secondary_buffer_max,
+ CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, sizeof(int),
+ sysctl_hw_snd_secondary_buffer_max, "I",
+ "maximum auto-scaled PCM secondary buffer size in bytes");
+
static int chn_timeout = CHN_TIMEOUT;
static int
@@ -1661,15 +1684,34 @@
return ret;
}
+u_int32_t
+chn_2ndbufmaxsize(struct pcm_channel *c)
+{
+ struct snd_dbuf *bs;
+ uint64_t maxsize;
+
+ if (c == NULL || c->bufsoft == NULL)
+ return (CHN_2NDBUFMAXSIZE);
+
+ bs = c->bufsoft;
+ maxsize = (uint64_t)bs->align * bs->spd * CHN_2NDBUFMAXMS / 1000;
+ if (maxsize < CHN_2NDBUFMAXSIZE)
+ maxsize = CHN_2NDBUFMAXSIZE;
+ if (maxsize > (uint64_t)chn_2ndbuf_maxsize)
+ maxsize = chn_2ndbuf_maxsize;
+
+ return ((u_int32_t)maxsize);
+}
+
static u_int32_t
-round_blksz(u_int32_t v, int round)
+round_blksz(u_int32_t v, int round, u_int32_t maxsize)
{
u_int32_t ret, tmp;
if (round < 1)
round = 1;
- ret = min(round_pow2(v), CHN_2NDBUFMAXSIZE >> 1);
+ ret = min(round_pow2(v), maxsize >> 1);
if (ret > v && (ret >> 1) > 0 && (ret >> 1) >= ((v * 3) >> 2))
ret >>= 1;
@@ -1784,14 +1826,16 @@
if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX ||
bps < 1 || datarate < 1 ||
!(dir == PCMDIR_PLAY || dir == PCMDIR_REC)) {
+ if (max < CHN_2NDBUFMAXSIZE)
+ max = CHN_2NDBUFMAXSIZE;
if (rblksz != NULL)
- *rblksz = CHN_2NDBUFMAXSIZE >> 1;
+ *rblksz = max >> 1;
if (rblkcnt != NULL)
*rblkcnt = 2;
printf("%s(): FAILED dir=%d latency=%d bps=%d "
"datarate=%u max=%u\n",
__func__, dir, latency, bps, datarate, max);
- return CHN_2NDBUFMAXSIZE;
+ return max;
}
lprofile = chn_latency_profile;
@@ -1808,7 +1852,7 @@
datarate));
if (bufsz > max)
bufsz = max;
- blksz = round_blksz(bufsz >> blkcnt, bps);
+ blksz = round_blksz(bufsz >> blkcnt, bps, max);
if (rblksz != NULL)
*rblksz = blksz;
@@ -1825,6 +1869,7 @@
struct snd_dbuf *b, *bs, *pb;
int sblksz, sblkcnt, hblksz, hblkcnt, limit = 0, nsblksz, nsblkcnt;
int ret;
+ u_int32_t maxsize;
CHN_LOCKASSERT(c);
@@ -1847,14 +1892,15 @@
bs = c->bufsoft;
b = c->bufhard;
+ maxsize = chn_2ndbufmaxsize(c);
if (!(blksz == 0 || blkcnt == -1) &&
(blksz < 16 || blksz < bs->align || blkcnt < 2 ||
- (blksz * blkcnt) > CHN_2NDBUFMAXSIZE))
+ (uint64_t)blksz * blkcnt > maxsize))
return EINVAL;
chn_calclatency(c->direction, latency, bs->align,
- bs->align * bs->spd, CHN_2NDBUFMAXSIZE,
+ bs->align * bs->spd, maxsize,
&sblksz, &sblkcnt);
if (blksz == 0 || blkcnt == -1) {
@@ -1875,7 +1921,7 @@
* defeat the purpose of having custom control. The least
* we can do is round it to the nearest ^2 and align it.
*/
- sblksz = round_blksz(blksz, bs->align);
+ sblksz = round_blksz(blksz, bs->align, maxsize);
sblkcnt = round_pow2(blkcnt);
}
@@ -1897,7 +1943,7 @@
hblkcnt = 2;
if (c->flags & CHN_F_HAS_SIZE) {
hblksz = round_blksz(sndbuf_xbytes(sblksz, bs, b),
- b->align);
+ b->align, CHN_2NDBUFMAXSIZE);
hblkcnt = round_pow2(bs->blkcnt);
} else
chn_calclatency(c->direction, latency,
@@ -1905,7 +1951,8 @@
CHN_2NDBUFMAXSIZE, &hblksz, &hblkcnt);
if ((hblksz << 1) > b->maxsize)
- hblksz = round_blksz(b->maxsize >> 1, b->align);
+ hblksz = round_blksz(b->maxsize >> 1, b->align,
+ CHN_2NDBUFMAXSIZE);
while ((hblksz * hblkcnt) > b->maxsize) {
if (hblkcnt < 4)
@@ -1926,7 +1973,8 @@
if (!CHN_EMPTY(c, children)) {
nsblksz = round_blksz(
- sndbuf_xbytes(b->blksz, b, bs), bs->align);
+ sndbuf_xbytes(b->blksz, b, bs), bs->align,
+ maxsize);
nsblkcnt = b->blkcnt;
if (c->direction == PCMDIR_PLAY) {
do {
@@ -1942,13 +1990,13 @@
limit = sndbuf_xbytes(b->blksz, b, bs) * 2;
}
- if (limit > CHN_2NDBUFMAXSIZE)
- limit = CHN_2NDBUFMAXSIZE;
+ if ((u_int32_t)limit > maxsize)
+ limit = maxsize;
- while ((sblksz * sblkcnt) < limit)
+ while ((uint64_t)sblksz * sblkcnt < (uint64_t)limit)
sblkcnt <<= 1;
- while ((sblksz * sblkcnt) > CHN_2NDBUFMAXSIZE) {
+ while ((uint64_t)sblksz * sblkcnt > maxsize) {
if (sblkcnt < 4)
sblksz >>= 1;
else
Index: sys/dev/sound/pcm/dsp.c
===================================================================
--- sys/dev/sound/pcm/dsp.c
+++ sys/dev/sound/pcm/dsp.c
@@ -109,6 +109,21 @@
static int dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name);
#endif
+static unsigned int
+dsp_low_water(struct pcm_channel *ch, int lw)
+{
+ unsigned int max;
+
+ max = (ch->bufsoft != NULL) ? ch->bufsoft->bufsize : 1;
+ if (max < 1)
+ max = 1;
+ if (lw < 1)
+ return (1);
+ if ((unsigned int)lw > max)
+ return (max);
+ return ((unsigned int)lw);
+}
+
int
dsp_make_dev(device_t dev)
{
@@ -1245,23 +1260,27 @@
{
uint32_t fragln = (*arg_i) & 0x0000ffff;
uint32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16;
+ uint32_t req_maxfrags;
uint32_t fragsz;
uint32_t r_maxfrags, r_fragsz;
+ uint32_t maxsize;
RANGE(fragln, 4, 16);
fragsz = 1 << fragln;
-
- if (maxfrags == 0)
- maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
- if (maxfrags < 2)
- maxfrags = 2;
- if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE)
- maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
+ req_maxfrags = maxfrags;
DEB(printf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz));
PCM_ACQUIRE_QUICK(d);
if (rdch) {
CHN_LOCK(rdch);
+ maxsize = chn_2ndbufmaxsize(rdch);
+ maxfrags = req_maxfrags;
+ if (maxfrags == 0)
+ maxfrags = maxsize / fragsz;
+ if (maxfrags < 2)
+ maxfrags = 2;
+ if ((uint64_t)maxfrags * fragsz > maxsize)
+ maxfrags = maxsize / fragsz;
ret = chn_setblocksize(rdch, maxfrags, fragsz);
r_maxfrags = rdch->bufsoft->blkcnt;
r_fragsz = rdch->bufsoft->blksz;
@@ -1272,6 +1291,14 @@
}
if (wrch && ret == 0) {
CHN_LOCK(wrch);
+ maxsize = chn_2ndbufmaxsize(wrch);
+ maxfrags = req_maxfrags;
+ if (maxfrags == 0)
+ maxfrags = maxsize / fragsz;
+ if (maxfrags < 2)
+ maxfrags = 2;
+ if ((uint64_t)maxfrags * fragsz > maxsize)
+ maxfrags = maxsize / fragsz;
ret = chn_setblocksize(wrch, maxfrags, fragsz);
maxfrags = wrch->bufsoft->blkcnt;
fragsz = wrch->bufsoft->blksz;
@@ -1661,12 +1688,12 @@
*/
if (wrch != NULL) {
CHN_LOCK(wrch);
- wrch->lw = (*arg_i > 1) ? *arg_i : 1;
+ wrch->lw = dsp_low_water(wrch, *arg_i);
CHN_UNLOCK(wrch);
}
if (rdch != NULL) {
CHN_LOCK(rdch);
- rdch->lw = (*arg_i > 1) ? *arg_i : 1;
+ rdch->lw = dsp_low_water(rdch, *arg_i);
CHN_UNLOCK(rdch);
}
break;

File Metadata

Mime Type
text/plain
Expires
Mon, Jul 13, 10:31 PM (11 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35047440
Default Alt Text
D58064.id181386.diff (8 KB)

Event Timeline