Merge branch 'for-5.0' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[platform/kernel/linux-rpi.git] / sound / soc / codecs / wm_adsp.c
index d15cf6e..b93fdc8 100644 (file)
 #define adsp_dbg(_dsp, fmt, ...) \
        dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
 
+#define compr_err(_obj, fmt, ...) \
+       adsp_err(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
+                ##__VA_ARGS__)
+#define compr_dbg(_obj, fmt, ...) \
+       adsp_dbg(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
+                ##__VA_ARGS__)
+
 #define ADSP1_CONTROL_1                   0x00
 #define ADSP1_CONTROL_2                   0x02
 #define ADSP1_CONTROL_3                   0x03
@@ -310,6 +317,12 @@ struct wm_adsp_alg_xm_struct {
        __be64 smoothed_power;
 };
 
+struct wm_adsp_host_buf_coeff_v1 {
+       __be32 host_buf_ptr;            /* Host buffer pointer */
+       __be32 versions;                /* Version numbers */
+       __be32 name[4];                 /* The buffer name */
+};
+
 struct wm_adsp_buffer {
        __be32 buf1_base;               /* Base addr of first buffer area */
        __be32 buf1_size;               /* Size of buf1 area in DSP words */
@@ -334,6 +347,7 @@ struct wm_adsp_buffer {
 struct wm_adsp_compr;
 
 struct wm_adsp_compr_buf {
+       struct list_head list;
        struct wm_adsp *dsp;
        struct wm_adsp_compr *compr;
 
@@ -344,9 +358,13 @@ struct wm_adsp_compr_buf {
        u32 irq_count;
        int read_index;
        int avail;
+       int host_buf_mem_type;
+
+       char *name;
 };
 
 struct wm_adsp_compr {
+       struct list_head list;
        struct wm_adsp *dsp;
        struct wm_adsp_compr_buf *buf;
 
@@ -357,6 +375,8 @@ struct wm_adsp_compr {
        unsigned int copied_total;
 
        unsigned int sample_rate;
+
+       const char *name;
 };
 
 #define WM_ADSP_DATA_WORD_SIZE         3
@@ -374,6 +394,11 @@ struct wm_adsp_compr {
 #define ALG_XM_FIELD(field) \
        (offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32))
 
+#define HOST_BUF_COEFF_SUPPORTED_COMPAT_VER    1
+
+#define HOST_BUF_COEFF_COMPAT_VER_MASK         0xFF00
+#define HOST_BUF_COEFF_COMPAT_VER_SHIFT                8
+
 static int wm_adsp_buffer_init(struct wm_adsp *dsp);
 static int wm_adsp_buffer_free(struct wm_adsp *dsp);
 
@@ -707,7 +732,7 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&dsp[e->shift_l].pwr_lock);
 
-       if (dsp[e->shift_l].booted || dsp[e->shift_l].compr)
+       if (dsp[e->shift_l].booted || !list_empty(&dsp[e->shift_l].compr_list))
                ret = -EBUSY;
        else
                dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0];
@@ -2429,6 +2454,8 @@ static int wm_adsp_common_init(struct wm_adsp *dsp)
 
        INIT_LIST_HEAD(&dsp->alg_regions);
        INIT_LIST_HEAD(&dsp->ctl_list);
+       INIT_LIST_HEAD(&dsp->compr_list);
+       INIT_LIST_HEAD(&dsp->buffer_list);
 
        mutex_init(&dsp->pwr_lock);
 
@@ -2971,14 +2998,19 @@ static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
 
 static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
 {
-       /*
-        * Note this will be more complex once each DSP can support multiple
-        * streams
-        */
-       if (!compr->dsp->buffer)
+       struct wm_adsp_compr_buf *buf = NULL, *tmp;
+
+       list_for_each_entry(tmp, &compr->dsp->buffer_list, list) {
+               if (!tmp->name || !strcmp(compr->name, tmp->name)) {
+                       buf = tmp;
+                       break;
+               }
+       }
+
+       if (!buf)
                return -EINVAL;
 
-       compr->buf = compr->dsp->buffer;
+       compr->buf = buf;
        compr->buf->compr = compr;
 
        return 0;
@@ -3001,28 +3033,33 @@ static void wm_adsp_compr_detach(struct wm_adsp_compr *compr)
 
 int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
 {
-       struct wm_adsp_compr *compr;
+       struct wm_adsp_compr *compr, *tmp;
+       struct snd_soc_pcm_runtime *rtd = stream->private_data;
        int ret = 0;
 
        mutex_lock(&dsp->pwr_lock);
 
        if (wm_adsp_fw[dsp->fw].num_caps == 0) {
-               adsp_err(dsp, "Firmware does not support compressed API\n");
+               adsp_err(dsp, "%s: Firmware does not support compressed API\n",
+                        rtd->codec_dai->name);
                ret = -ENXIO;
                goto out;
        }
 
        if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
-               adsp_err(dsp, "Firmware does not support stream direction\n");
+               adsp_err(dsp, "%s: Firmware does not support stream direction\n",
+                        rtd->codec_dai->name);
                ret = -EINVAL;
                goto out;
        }
 
-       if (dsp->compr) {
-               /* It is expect this limitation will be removed in future */
-               adsp_err(dsp, "Only a single stream supported per DSP\n");
-               ret = -EBUSY;
-               goto out;
+       list_for_each_entry(tmp, &dsp->compr_list, list) {
+               if (!strcmp(tmp->name, rtd->codec_dai->name)) {
+                       adsp_err(dsp, "%s: Only a single stream supported per dai\n",
+                                rtd->codec_dai->name);
+                       ret = -EBUSY;
+                       goto out;
+               }
        }
 
        compr = kzalloc(sizeof(*compr), GFP_KERNEL);
@@ -3033,8 +3070,9 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
 
        compr->dsp = dsp;
        compr->stream = stream;
+       compr->name = rtd->codec_dai->name;
 
-       dsp->compr = compr;
+       list_add_tail(&compr->list, &dsp->compr_list);
 
        stream->runtime->private_data = compr;
 
@@ -3053,7 +3091,7 @@ int wm_adsp_compr_free(struct snd_compr_stream *stream)
        mutex_lock(&dsp->pwr_lock);
 
        wm_adsp_compr_detach(compr);
-       dsp->compr = NULL;
+       list_del(&compr->list);
 
        kfree(compr->raw_buf);
        kfree(compr);
@@ -3078,9 +3116,9 @@ static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
            params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS ||
            params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS ||
            params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) {
-               adsp_err(dsp, "Invalid buffer fragsize=%d fragments=%d\n",
-                        params->buffer.fragment_size,
-                        params->buffer.fragments);
+               compr_err(compr, "Invalid buffer fragsize=%d fragments=%d\n",
+                         params->buffer.fragment_size,
+                         params->buffer.fragments);
 
                return -EINVAL;
        }
@@ -3108,9 +3146,9 @@ static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
                                return 0;
        }
 
-       adsp_err(dsp, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
-                params->codec.id, params->codec.ch_in, params->codec.ch_out,
-                params->codec.sample_rate, params->codec.format);
+       compr_err(compr, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
+                 params->codec.id, params->codec.ch_in, params->codec.ch_out,
+                 params->codec.sample_rate, params->codec.format);
        return -EINVAL;
 }
 
@@ -3132,8 +3170,8 @@ int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
 
        compr->size = params->buffer;
 
-       adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n",
-                compr->size.fragment_size, compr->size.fragments);
+       compr_dbg(compr, "fragment_size=%d fragments=%d\n",
+                 compr->size.fragment_size, compr->size.fragments);
 
        size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
        compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
@@ -3219,24 +3257,106 @@ static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type,
 static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
                                      unsigned int field_offset, u32 *data)
 {
-       return wm_adsp_read_data_word(buf->dsp, WMFW_ADSP2_XM,
+       return wm_adsp_read_data_word(buf->dsp, buf->host_buf_mem_type,
                                      buf->host_buf_ptr + field_offset, data);
 }
 
 static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
                                       unsigned int field_offset, u32 data)
 {
-       return wm_adsp_write_data_word(buf->dsp, WMFW_ADSP2_XM,
+       return wm_adsp_write_data_word(buf->dsp, buf->host_buf_mem_type,
                                       buf->host_buf_ptr + field_offset, data);
 }
 
-static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf)
+static void wm_adsp_remove_padding(u32 *buf, int nwords, int data_word_size)
+{
+       u8 *pack_in = (u8 *)buf;
+       u8 *pack_out = (u8 *)buf;
+       int i, j;
+
+       /* Remove the padding bytes from the data read from the DSP */
+       for (i = 0; i < nwords; i++) {
+               for (j = 0; j < data_word_size; j++)
+                       *pack_out++ = *pack_in++;
+
+               pack_in += sizeof(*buf) - data_word_size;
+       }
+}
+
+static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
+{
+       const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
+       struct wm_adsp_buffer_region *region;
+       u32 offset = 0;
+       int i, ret;
+
+       buf->regions = kcalloc(caps->num_regions, sizeof(*buf->regions),
+                              GFP_KERNEL);
+       if (!buf->regions)
+               return -ENOMEM;
+
+       for (i = 0; i < caps->num_regions; ++i) {
+               region = &buf->regions[i];
+
+               region->offset = offset;
+               region->mem_type = caps->region_defs[i].mem_type;
+
+               ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
+                                         &region->base_addr);
+               if (ret < 0)
+                       return ret;
+
+               ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
+                                         &offset);
+               if (ret < 0)
+                       return ret;
+
+               region->cumulative_size = offset;
+
+               compr_dbg(buf,
+                         "region=%d type=%d base=%08x off=%08x size=%08x\n",
+                         i, region->mem_type, region->base_addr,
+                         region->offset, region->cumulative_size);
+       }
+
+       return 0;
+}
+
+static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf)
+{
+       buf->irq_count = 0xFFFFFFFF;
+       buf->read_index = -1;
+       buf->avail = 0;
+}
+
+static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp)
+{
+       struct wm_adsp_compr_buf *buf;
+
+       buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->dsp = dsp;
+
+       wm_adsp_buffer_clear(buf);
+
+       list_add_tail(&buf->list, &dsp->buffer_list);
+
+       return buf;
+}
+
+static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
 {
        struct wm_adsp_alg_region *alg_region;
-       struct wm_adsp *dsp = buf->dsp;
+       struct wm_adsp_compr_buf *buf;
        u32 xmalg, addr, magic;
        int i, ret;
 
+       buf = wm_adsp_buffer_alloc(dsp);
+       if (!buf)
+               return -ENOMEM;
+
        alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
        xmalg = sizeof(struct wm_adsp_system_config_xm_hdr) / sizeof(__be32);
 
@@ -3246,7 +3366,7 @@ static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf)
                return ret;
 
        if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
-               return -EINVAL;
+               return -ENODEV;
 
        addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
        for (i = 0; i < 5; ++i) {
@@ -3264,48 +3384,30 @@ static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf)
        if (!buf->host_buf_ptr)
                return -EIO;
 
-       adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr);
+       buf->host_buf_mem_type = WMFW_ADSP2_XM;
 
-       return 0;
-}
-
-static struct wm_coeff_ctl *
-wm_adsp_find_host_buffer_ctrl(struct wm_adsp_compr_buf *buf)
-{
-       struct wm_adsp *dsp = buf->dsp;
-       struct wm_coeff_ctl *ctl;
-
-       list_for_each_entry(ctl, &dsp->ctl_list, list) {
-               if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
-                       continue;
-
-               if (!ctl->enabled)
-                       continue;
+       ret = wm_adsp_buffer_populate(buf);
+       if (ret < 0)
+               return ret;
 
-               return ctl;
-       }
+       compr_dbg(buf, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr);
 
-       return NULL;
+       return 0;
 }
 
-static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
+static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
 {
-       struct wm_adsp *dsp = buf->dsp;
-       struct wm_coeff_ctl *ctl;
-       unsigned int reg;
-       u32 val;
-       int i, ret;
-
-       ctl = wm_adsp_find_host_buffer_ctrl(buf);
-       if (!ctl)
-               return wm_adsp_legacy_host_buf_addr(buf);
+       struct wm_adsp_host_buf_coeff_v1 coeff_v1;
+       struct wm_adsp_compr_buf *buf;
+       unsigned int val, reg;
+       int ret, i;
 
        ret = wm_coeff_base_reg(ctl, &reg);
        if (ret)
                return ret;
 
        for (i = 0; i < 5; ++i) {
-               ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
+               ret = regmap_raw_read(ctl->dsp->regmap, reg, &val, sizeof(val));
                if (ret < 0)
                        return ret;
 
@@ -3315,108 +3417,113 @@ static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
                usleep_range(1000, 2000);
        }
 
-       if (!val)
+       if (!val) {
+               adsp_err(ctl->dsp, "Failed to acquire host buffer\n");
                return -EIO;
+       }
+
+       buf = wm_adsp_buffer_alloc(ctl->dsp);
+       if (!buf)
+               return -ENOMEM;
 
+       buf->host_buf_mem_type = ctl->alg_region.type;
        buf->host_buf_ptr = be32_to_cpu(val);
-       adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr);
 
-       return 0;
-}
+       ret = wm_adsp_buffer_populate(buf);
+       if (ret < 0)
+               return ret;
 
-static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
-{
-       const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
-       struct wm_adsp_buffer_region *region;
-       u32 offset = 0;
-       int i, ret;
+       /*
+        * v0 host_buffer coefficients didn't have versioning, so if the
+        * control is one word, assume version 0.
+        */
+       if (ctl->len == 4) {
+               compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr);
+               return 0;
+       }
 
-       for (i = 0; i < caps->num_regions; ++i) {
-               region = &buf->regions[i];
+       ret = regmap_raw_read(ctl->dsp->regmap, reg, &coeff_v1,
+                             sizeof(coeff_v1));
+       if (ret < 0)
+               return ret;
 
-               region->offset = offset;
-               region->mem_type = caps->region_defs[i].mem_type;
+       coeff_v1.versions = be32_to_cpu(coeff_v1.versions);
+       val = coeff_v1.versions & HOST_BUF_COEFF_COMPAT_VER_MASK;
+       val >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
 
-               ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
-                                         &region->base_addr);
-               if (ret < 0)
-                       return ret;
+       if (val > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) {
+               adsp_err(ctl->dsp,
+                        "Host buffer coeff ver %u > supported version %u\n",
+                        val, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
+               return -EINVAL;
+       }
 
-               ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
-                                         &offset);
-               if (ret < 0)
-                       return ret;
+       for (i = 0; i < ARRAY_SIZE(coeff_v1.name); i++)
+               coeff_v1.name[i] = be32_to_cpu(coeff_v1.name[i]);
 
-               region->cumulative_size = offset;
+       wm_adsp_remove_padding((u32 *)&coeff_v1.name,
+                              ARRAY_SIZE(coeff_v1.name),
+                              WM_ADSP_DATA_WORD_SIZE);
 
-               adsp_dbg(buf->dsp,
-                        "region=%d type=%d base=%08x off=%08x size=%08x\n",
-                        i, region->mem_type, region->base_addr,
-                        region->offset, region->cumulative_size);
-       }
+       buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part,
+                             (char *)&coeff_v1.name);
 
-       return 0;
-}
+       compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n",
+                 buf->host_buf_ptr, val);
 
-static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf)
-{
-       buf->irq_count = 0xFFFFFFFF;
-       buf->read_index = -1;
-       buf->avail = 0;
+       return val;
 }
 
 static int wm_adsp_buffer_init(struct wm_adsp *dsp)
 {
-       struct wm_adsp_compr_buf *buf;
+       struct wm_coeff_ctl *ctl;
        int ret;
 
-       buf = kzalloc(sizeof(*buf), GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       buf->dsp = dsp;
-
-       wm_adsp_buffer_clear(buf);
+       list_for_each_entry(ctl, &dsp->ctl_list, list) {
+               if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
+                       continue;
 
-       ret = wm_adsp_buffer_locate(buf);
-       if (ret < 0) {
-               adsp_err(dsp, "Failed to acquire host buffer: %d\n", ret);
-               goto err_buffer;
-       }
+               if (!ctl->enabled)
+                       continue;
 
-       buf->regions = kcalloc(wm_adsp_fw[dsp->fw].caps->num_regions,
-                              sizeof(*buf->regions), GFP_KERNEL);
-       if (!buf->regions) {
-               ret = -ENOMEM;
-               goto err_buffer;
+               ret = wm_adsp_buffer_parse_coeff(ctl);
+               if (ret < 0) {
+                       adsp_err(dsp, "Failed to parse coeff: %d\n", ret);
+                       goto error;
+               } else if (ret == 0) {
+                       /* Only one buffer supported for version 0 */
+                       return 0;
+               }
        }
 
-       ret = wm_adsp_buffer_populate(buf);
-       if (ret < 0) {
-               adsp_err(dsp, "Failed to populate host buffer: %d\n", ret);
-               goto err_regions;
+       if (list_empty(&dsp->buffer_list)) {
+               /* Fall back to legacy support */
+               ret = wm_adsp_buffer_parse_legacy(dsp);
+               if (ret) {
+                       adsp_err(dsp, "Failed to parse legacy: %d\n", ret);
+                       goto error;
+               }
        }
 
-       dsp->buffer = buf;
-
        return 0;
 
-err_regions:
-       kfree(buf->regions);
-err_buffer:
-       kfree(buf);
+error:
+       wm_adsp_buffer_free(dsp);
        return ret;
 }
 
 static int wm_adsp_buffer_free(struct wm_adsp *dsp)
 {
-       if (dsp->buffer) {
-               wm_adsp_compr_detach(dsp->buffer->compr);
+       struct wm_adsp_compr_buf *buf, *tmp;
 
-               kfree(dsp->buffer->regions);
-               kfree(dsp->buffer);
+       list_for_each_entry_safe(buf, tmp, &dsp->buffer_list, list) {
+               if (buf->compr)
+                       wm_adsp_compr_detach(buf->compr);
 
-               dsp->buffer = NULL;
+               kfree(buf->name);
+               kfree(buf->regions);
+               list_del(&buf->list);
+               kfree(buf);
        }
 
        return 0;
@@ -3445,7 +3552,7 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd)
        struct wm_adsp *dsp = compr->dsp;
        int ret = 0;
 
-       adsp_dbg(dsp, "Trigger: %d\n", cmd);
+       compr_dbg(compr, "Trigger: %d\n", cmd);
 
        mutex_lock(&dsp->pwr_lock);
 
@@ -3454,8 +3561,8 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd)
                if (!wm_adsp_compr_attached(compr)) {
                        ret = wm_adsp_compr_attach(compr);
                        if (ret < 0) {
-                               adsp_err(dsp, "Failed to link buffer and stream: %d\n",
-                                        ret);
+                               compr_err(compr, "Failed to link buffer and stream: %d\n",
+                                         ret);
                                break;
                        }
                }
@@ -3471,8 +3578,8 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd)
                                           HOST_BUFFER_FIELD(high_water_mark),
                                           wm_adsp_compr_frag_words(compr));
                if (ret < 0) {
-                       adsp_err(dsp, "Failed to set high water mark: %d\n",
-                                ret);
+                       compr_err(compr, "Failed to set high water mark: %d\n",
+                                 ret);
                        break;
                }
                break;
@@ -3513,7 +3620,7 @@ static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
                read_index = sign_extend32(next_read_index, 23);
 
                if (read_index < 0) {
-                       adsp_dbg(buf->dsp, "Avail check on unstarted stream\n");
+                       compr_dbg(buf, "Avail check on unstarted stream\n");
                        return 0;
                }
 
@@ -3531,8 +3638,8 @@ static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
        if (avail < 0)
                avail += wm_adsp_buffer_size(buf);
 
-       adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
-                buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE);
+       compr_dbg(buf, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
+                 buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE);
 
        buf->avail = avail;
 
@@ -3547,39 +3654,40 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
 
        mutex_lock(&dsp->pwr_lock);
 
-       buf = dsp->buffer;
-       compr = dsp->compr;
-
-       if (!buf) {
+       if (list_empty(&dsp->buffer_list)) {
                ret = -ENODEV;
                goto out;
        }
 
        adsp_dbg(dsp, "Handling buffer IRQ\n");
 
-       ret = wm_adsp_buffer_get_error(buf);
-       if (ret < 0)
-               goto out_notify; /* Wake poll to report error */
+       list_for_each_entry(buf, &dsp->buffer_list, list) {
+               compr = buf->compr;
 
-       ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
-                                 &buf->irq_count);
-       if (ret < 0) {
-               adsp_err(dsp, "Failed to get irq_count: %d\n", ret);
-               goto out;
-       }
+               ret = wm_adsp_buffer_get_error(buf);
+               if (ret < 0)
+                       goto out_notify; /* Wake poll to report error */
 
-       ret = wm_adsp_buffer_update_avail(buf);
-       if (ret < 0) {
-               adsp_err(dsp, "Error reading avail: %d\n", ret);
-               goto out;
-       }
+               ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
+                                         &buf->irq_count);
+               if (ret < 0) {
+                       compr_err(buf, "Failed to get irq_count: %d\n", ret);
+                       goto out;
+               }
 
-       if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2)
-               ret = WM_ADSP_COMPR_VOICE_TRIGGER;
+               ret = wm_adsp_buffer_update_avail(buf);
+               if (ret < 0) {
+                       compr_err(buf, "Error reading avail: %d\n", ret);
+                       goto out;
+               }
+
+               if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2)
+                       ret = WM_ADSP_COMPR_VOICE_TRIGGER;
 
 out_notify:
-       if (compr && compr->stream)
-               snd_compr_fragment_elapsed(compr->stream);
+               if (compr && compr->stream)
+                       snd_compr_fragment_elapsed(compr->stream);
+       }
 
 out:
        mutex_unlock(&dsp->pwr_lock);
@@ -3593,8 +3701,7 @@ static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
        if (buf->irq_count & 0x01)
                return 0;
 
-       adsp_dbg(buf->dsp, "Enable IRQ(0x%x) for next fragment\n",
-                buf->irq_count);
+       compr_dbg(buf, "Enable IRQ(0x%x) for next fragment\n", buf->irq_count);
 
        buf->irq_count |= 0x01;
 
@@ -3610,7 +3717,7 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
        struct wm_adsp_compr_buf *buf;
        int ret = 0;
 
-       adsp_dbg(dsp, "Pointer request\n");
+       compr_dbg(compr, "Pointer request\n");
 
        mutex_lock(&dsp->pwr_lock);
 
@@ -3625,7 +3732,7 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
        if (buf->avail < wm_adsp_compr_frag_words(compr)) {
                ret = wm_adsp_buffer_update_avail(buf);
                if (ret < 0) {
-                       adsp_err(dsp, "Error reading avail: %d\n", ret);
+                       compr_err(compr, "Error reading avail: %d\n", ret);
                        goto out;
                }
 
@@ -3644,9 +3751,8 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
 
                        ret = wm_adsp_buffer_reenable_irq(buf);
                        if (ret < 0) {
-                               adsp_err(dsp,
-                                        "Failed to re-enable buffer IRQ: %d\n",
-                                        ret);
+                               compr_err(compr, "Failed to re-enable buffer IRQ: %d\n",
+                                         ret);
                                goto out;
                        }
                }
@@ -3666,11 +3772,9 @@ EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
 static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
 {
        struct wm_adsp_compr_buf *buf = compr->buf;
-       u8 *pack_in = (u8 *)compr->raw_buf;
-       u8 *pack_out = (u8 *)compr->raw_buf;
        unsigned int adsp_addr;
        int mem_type, nwords, max_read;
-       int i, j, ret;
+       int i, ret;
 
        /* Calculate read parameters */
        for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
@@ -3702,13 +3806,7 @@ static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
        if (ret < 0)
                return ret;
 
-       /* Remove the padding bytes from the data read from the DSP */
-       for (i = 0; i < nwords; i++) {
-               for (j = 0; j < WM_ADSP_DATA_WORD_SIZE; j++)
-                       *pack_out++ = *pack_in++;
-
-               pack_in += sizeof(*(compr->raw_buf)) - WM_ADSP_DATA_WORD_SIZE;
-       }
+       wm_adsp_remove_padding(compr->raw_buf, nwords, WM_ADSP_DATA_WORD_SIZE);
 
        /* update read index to account for words read */
        buf->read_index += nwords;
@@ -3729,11 +3827,10 @@ static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
 static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
                              char __user *buf, size_t count)
 {
-       struct wm_adsp *dsp = compr->dsp;
        int ntotal = 0;
        int nwords, nbytes;
 
-       adsp_dbg(dsp, "Requested read of %zu bytes\n", count);
+       compr_dbg(compr, "Requested read of %zu bytes\n", count);
 
        if (!compr->buf || compr->buf->error) {
                snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
@@ -3745,17 +3842,18 @@ static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
        do {
                nwords = wm_adsp_buffer_capture_block(compr, count);
                if (nwords < 0) {
-                       adsp_err(dsp, "Failed to capture block: %d\n", nwords);
+                       compr_err(compr, "Failed to capture block: %d\n",
+                                 nwords);
                        return nwords;
                }
 
                nbytes = nwords * WM_ADSP_DATA_WORD_SIZE;
 
-               adsp_dbg(dsp, "Read %d bytes\n", nbytes);
+               compr_dbg(compr, "Read %d bytes\n", nbytes);
 
                if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
-                       adsp_err(dsp, "Failed to copy data to user: %d, %d\n",
-                                ntotal, nbytes);
+                       compr_err(compr, "Failed to copy data to user: %d, %d\n",
+                                 ntotal, nbytes);
                        return -EFAULT;
                }