Page MenuHomeFreeBSD

D58064.diff
No OneTemporary

D58064.diff

diff --git a/sys/dev/sound/pcm/channel.h b/sys/dev/sound/pcm/channel.h
--- a/sys/dev/sound/pcm/channel.h
+++ b/sys/dev/sound/pcm/channel.h
@@ -434,11 +434,27 @@
* 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 secondary buffer cap scales with the channel byte rate, targeting
+ * CHN_2NDBUFTIME_MS of stream, clamped to [CHN_2NDBUFSIZE_MIN,
+ * CHN_2NDBUFSIZE_MAX]. The floor preserves historical memory use for low
+ * byte-rate streams (at the reference rate above the target is ~38 KiB,
+ * well under the floor). The ceiling bounds per-channel buffer memory;
+ * buffers are allocated at the derived size, so only streams that actually
+ * run at high byte rates approach it. It holds the full target through
+ * MADI-class streams (64ch * 32-bit * 48kHz, ~12.3 MB/s); beyond that,
+ * coverage shrinks proportionally (e.g. ~85 ms at 64ch * 32-bit * 192kHz).
*/
#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)
+/* Historical secondary buffer size; floor of the byte-rate-scaled cap. */
+#define CHN_2NDBUFSIZE_MIN (131072)
+/* Ceiling of the byte-rate-scaled secondary buffer cap. */
+#define CHN_2NDBUFSIZE_MAX (4 * 1024 * 1024)
+/* Stream time targeted by the byte-rate-scaled secondary buffer cap. */
+#define CHN_2NDBUFTIME_MS 200
+
+u_int32_t chn_2ndbufmaxsize(struct pcm_channel *);
#define CHANNEL_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, sizeof(struct kobj))
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -1661,15 +1661,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_2NDBUFSIZE_MIN);
+
+ bs = c->bufsoft;
+ maxsize = (uint64_t)bs->align * bs->spd * CHN_2NDBUFTIME_MS / 1000;
+ if (maxsize < CHN_2NDBUFSIZE_MIN)
+ maxsize = CHN_2NDBUFSIZE_MIN;
+ if (maxsize > CHN_2NDBUFSIZE_MAX)
+ maxsize = CHN_2NDBUFSIZE_MAX;
+
+ 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 +1803,16 @@
if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX ||
bps < 1 || datarate < 1 ||
!(dir == PCMDIR_PLAY || dir == PCMDIR_REC)) {
+ if (max < CHN_2NDBUFSIZE_MIN)
+ max = CHN_2NDBUFSIZE_MIN;
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 +1829,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 +1846,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 +1869,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 +1898,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);
}
@@ -1894,18 +1917,24 @@
sndbuf_xbytes(pb->blksz, pb, bs) * 2 : 0;
}
} else {
+ /*
+ * The byte-rate-scaled cap applies to the secondary buffer
+ * only; hardware buffer geometry keeps the historical cap
+ * and remains bounded by b->maxsize below.
+ */
hblkcnt = 2;
if (c->flags & CHN_F_HAS_SIZE) {
hblksz = round_blksz(sndbuf_xbytes(sblksz, bs, b),
- b->align);
+ b->align, CHN_2NDBUFSIZE_MIN);
hblkcnt = round_pow2(bs->blkcnt);
} else
chn_calclatency(c->direction, latency,
b->align, b->align * b->spd,
- CHN_2NDBUFMAXSIZE, &hblksz, &hblkcnt);
+ CHN_2NDBUFSIZE_MIN, &hblksz, &hblkcnt);
if ((hblksz << 1) > b->maxsize)
- hblksz = round_blksz(b->maxsize >> 1, b->align);
+ hblksz = round_blksz(b->maxsize >> 1, b->align,
+ CHN_2NDBUFSIZE_MIN);
while ((hblksz * hblkcnt) > b->maxsize) {
if (hblkcnt < 4)
@@ -1926,7 +1955,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 +1972,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
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -109,6 +109,33 @@
static int dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name);
#endif
+static uint32_t
+dsp_clamp_fragments(uint32_t maxfrags, uint32_t fragsz, uint32_t maxsize)
+{
+ if (maxfrags == 0)
+ maxfrags = maxsize / fragsz;
+ if (maxfrags < 2)
+ maxfrags = 2;
+ if ((uint64_t)maxfrags * fragsz > maxsize)
+ maxfrags = maxsize / fragsz;
+ return (maxfrags);
+}
+
+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)
{
@@ -1251,18 +1278,13 @@
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;
-
DEB(printf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz));
PCM_ACQUIRE_QUICK(d);
if (rdch) {
CHN_LOCK(rdch);
- ret = chn_setblocksize(rdch, maxfrags, fragsz);
+ ret = chn_setblocksize(rdch,
+ dsp_clamp_fragments(maxfrags, fragsz,
+ chn_2ndbufmaxsize(rdch)), fragsz);
r_maxfrags = rdch->bufsoft->blkcnt;
r_fragsz = rdch->bufsoft->blksz;
CHN_UNLOCK(rdch);
@@ -1272,7 +1294,9 @@
}
if (wrch && ret == 0) {
CHN_LOCK(wrch);
- ret = chn_setblocksize(wrch, maxfrags, fragsz);
+ ret = chn_setblocksize(wrch,
+ dsp_clamp_fragments(maxfrags, fragsz,
+ chn_2ndbufmaxsize(wrch)), fragsz);
maxfrags = wrch->bufsoft->blkcnt;
fragsz = wrch->bufsoft->blksz;
CHN_UNLOCK(wrch);
@@ -1661,12 +1685,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
Thu, Jul 9, 5:30 AM (7 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34877858
Default Alt Text
D58064.diff (8 KB)

Event Timeline