lkml.org 
[lkml]   [2021]   [Dec]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.15 005/207] ALSA: usb-audio: Check available frames for the next packet size
    Date
    From: Takashi Iwai <tiwai@suse.de>

    commit d215f63d49da9a8803af3e81acd6cad743686573 upstream.

    This is yet more preparation for the upcoming changes.

    Extend snd_usb_endpoint_next_packet_size() to check the available
    frames and return -EAGAIN if the next packet size is equal or exceeds
    the given size. This will be needed for avoiding XRUN during the low
    latency operation.

    As of this patch, avail=0 is passed, i.e. the check is skipped and no
    behavior change.

    Link: https://lore.kernel.org/r/20210929080844.11583-7-tiwai@suse.de
    Signed-off-by: Takashi Iwai <tiwai@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    sound/usb/endpoint.c | 51 ++++++++++++++++++++++++++++++++++++---------------
    sound/usb/endpoint.h | 3 ++-
    sound/usb/pcm.c | 2 +-
    3 files changed, 39 insertions(+), 17 deletions(-)

    --- a/sound/usb/endpoint.c
    +++ b/sound/usb/endpoint.c
    @@ -148,18 +148,23 @@ int snd_usb_endpoint_implicit_feedback_s
    * This won't be used for implicit feedback which takes the packet size
    * returned from the sync source
    */
    -static int slave_next_packet_size(struct snd_usb_endpoint *ep)
    +static int slave_next_packet_size(struct snd_usb_endpoint *ep,
    + unsigned int avail)
    {
    unsigned long flags;
    + unsigned int phase;
    int ret;

    if (ep->fill_max)
    return ep->maxframesize;

    spin_lock_irqsave(&ep->lock, flags);
    - ep->phase = (ep->phase & 0xffff)
    - + (ep->freqm << ep->datainterval);
    - ret = min(ep->phase >> 16, ep->maxframesize);
    + phase = (ep->phase & 0xffff) + (ep->freqm << ep->datainterval);
    + ret = min(phase >> 16, ep->maxframesize);
    + if (avail && ret >= avail)
    + ret = -EAGAIN;
    + else
    + ep->phase = phase;
    spin_unlock_irqrestore(&ep->lock, flags);

    return ret;
    @@ -169,20 +174,25 @@ static int slave_next_packet_size(struct
    * Return the number of samples to be sent in the next packet
    * for adaptive and synchronous endpoints
    */
    -static int next_packet_size(struct snd_usb_endpoint *ep)
    +static int next_packet_size(struct snd_usb_endpoint *ep, unsigned int avail)
    {
    + unsigned int sample_accum;
    int ret;

    if (ep->fill_max)
    return ep->maxframesize;

    - ep->sample_accum += ep->sample_rem;
    - if (ep->sample_accum >= ep->pps) {
    - ep->sample_accum -= ep->pps;
    + sample_accum += ep->sample_rem;
    + if (sample_accum >= ep->pps) {
    + sample_accum -= ep->pps;
    ret = ep->packsize[1];
    } else {
    ret = ep->packsize[0];
    }
    + if (avail && ret >= avail)
    + ret = -EAGAIN;
    + else
    + ep->sample_accum = sample_accum;

    return ret;
    }
    @@ -190,16 +200,27 @@ static int next_packet_size(struct snd_u
    /*
    * snd_usb_endpoint_next_packet_size: Return the number of samples to be sent
    * in the next packet
    + *
    + * If the size is equal or exceeds @avail, don't proceed but return -EAGAIN
    + * Exception: @avail = 0 for skipping the check.
    */
    int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep,
    - struct snd_urb_ctx *ctx, int idx)
    + struct snd_urb_ctx *ctx, int idx,
    + unsigned int avail)
    {
    - if (ctx->packet_size[idx])
    - return ctx->packet_size[idx];
    - else if (ep->sync_source)
    - return slave_next_packet_size(ep);
    + unsigned int packet;
    +
    + packet = ctx->packet_size[idx];
    + if (packet) {
    + if (avail && packet >= avail)
    + return -EAGAIN;
    + return packet;
    + }
    +
    + if (ep->sync_source)
    + return slave_next_packet_size(ep, avail);
    else
    - return next_packet_size(ep);
    + return next_packet_size(ep, avail);
    }

    static void call_retire_callback(struct snd_usb_endpoint *ep,
    @@ -263,7 +284,7 @@ static void prepare_silent_urb(struct sn
    unsigned int length;
    int counts;

    - counts = snd_usb_endpoint_next_packet_size(ep, ctx, i);
    + counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, 0);
    length = counts * ep->stride; /* number of silent bytes */
    offset = offs * ep->stride + extra * i;
    urb->iso_frame_desc[i].offset = offset;
    --- a/sound/usb/endpoint.h
    +++ b/sound/usb/endpoint.h
    @@ -46,6 +46,7 @@ void snd_usb_endpoint_free_all(struct sn

    int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
    int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep,
    - struct snd_urb_ctx *ctx, int idx);
    + struct snd_urb_ctx *ctx, int idx,
    + unsigned int avail);

    #endif /* __USBAUDIO_ENDPOINT_H */
    --- a/sound/usb/pcm.c
    +++ b/sound/usb/pcm.c
    @@ -1365,7 +1365,7 @@ static void prepare_playback_urb(struct
    spin_lock_irqsave(&subs->lock, flags);
    subs->frame_limit += ep->max_urb_frames;
    for (i = 0; i < ctx->packets; i++) {
    - counts = snd_usb_endpoint_next_packet_size(ep, ctx, i);
    + counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, 0);
    /* set up descriptor */
    urb->iso_frame_desc[i].offset = frames * stride;
    urb->iso_frame_desc[i].length = counts * stride;

    \
     
     \ /
      Last update: 2021-12-06 16:41    [W:2.872 / U:0.036 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site