linux/sound/hda/hdac_controller.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * HD-audio controller helpers
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/delay.h>
   8#include <linux/export.h>
   9#include <sound/core.h>
  10#include <sound/hdaudio.h>
  11#include <sound/hda_register.h>
  12
  13/* clear CORB read pointer properly */
  14static void azx_clear_corbrp(struct hdac_bus *bus)
  15{
  16        int timeout;
  17
  18        for (timeout = 1000; timeout > 0; timeout--) {
  19                if (snd_hdac_chip_readw(bus, CORBRP) & AZX_CORBRP_RST)
  20                        break;
  21                udelay(1);
  22        }
  23        if (timeout <= 0)
  24                dev_err(bus->dev, "CORB reset timeout#1, CORBRP = %d\n",
  25                        snd_hdac_chip_readw(bus, CORBRP));
  26
  27        snd_hdac_chip_writew(bus, CORBRP, 0);
  28        for (timeout = 1000; timeout > 0; timeout--) {
  29                if (snd_hdac_chip_readw(bus, CORBRP) == 0)
  30                        break;
  31                udelay(1);
  32        }
  33        if (timeout <= 0)
  34                dev_err(bus->dev, "CORB reset timeout#2, CORBRP = %d\n",
  35                        snd_hdac_chip_readw(bus, CORBRP));
  36}
  37
  38/**
  39 * snd_hdac_bus_init_cmd_io - set up CORB/RIRB buffers
  40 * @bus: HD-audio core bus
  41 */
  42void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
  43{
  44        WARN_ON_ONCE(!bus->rb.area);
  45
  46        spin_lock_irq(&bus->reg_lock);
  47        /* CORB set up */
  48        bus->corb.addr = bus->rb.addr;
  49        bus->corb.buf = (__le32 *)bus->rb.area;
  50        snd_hdac_chip_writel(bus, CORBLBASE, (u32)bus->corb.addr);
  51        snd_hdac_chip_writel(bus, CORBUBASE, upper_32_bits(bus->corb.addr));
  52
  53        /* set the corb size to 256 entries (ULI requires explicitly) */
  54        snd_hdac_chip_writeb(bus, CORBSIZE, 0x02);
  55        /* set the corb write pointer to 0 */
  56        snd_hdac_chip_writew(bus, CORBWP, 0);
  57
  58        /* reset the corb hw read pointer */
  59        snd_hdac_chip_writew(bus, CORBRP, AZX_CORBRP_RST);
  60        if (!bus->corbrp_self_clear)
  61                azx_clear_corbrp(bus);
  62
  63        /* enable corb dma */
  64        snd_hdac_chip_writeb(bus, CORBCTL, AZX_CORBCTL_RUN);
  65
  66        /* RIRB set up */
  67        bus->rirb.addr = bus->rb.addr + 2048;
  68        bus->rirb.buf = (__le32 *)(bus->rb.area + 2048);
  69        bus->rirb.wp = bus->rirb.rp = 0;
  70        memset(bus->rirb.cmds, 0, sizeof(bus->rirb.cmds));
  71        snd_hdac_chip_writel(bus, RIRBLBASE, (u32)bus->rirb.addr);
  72        snd_hdac_chip_writel(bus, RIRBUBASE, upper_32_bits(bus->rirb.addr));
  73
  74        /* set the rirb size to 256 entries (ULI requires explicitly) */
  75        snd_hdac_chip_writeb(bus, RIRBSIZE, 0x02);
  76        /* reset the rirb hw write pointer */
  77        snd_hdac_chip_writew(bus, RIRBWP, AZX_RIRBWP_RST);
  78        /* set N=1, get RIRB response interrupt for new entry */
  79        snd_hdac_chip_writew(bus, RINTCNT, 1);
  80        /* enable rirb dma and response irq */
  81        snd_hdac_chip_writeb(bus, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
  82        /* Accept unsolicited responses */
  83        snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
  84        spin_unlock_irq(&bus->reg_lock);
  85}
  86EXPORT_SYMBOL_GPL(snd_hdac_bus_init_cmd_io);
  87
  88/* wait for cmd dmas till they are stopped */
  89static void hdac_wait_for_cmd_dmas(struct hdac_bus *bus)
  90{
  91        unsigned long timeout;
  92
  93        timeout = jiffies + msecs_to_jiffies(100);
  94        while ((snd_hdac_chip_readb(bus, RIRBCTL) & AZX_RBCTL_DMA_EN)
  95                && time_before(jiffies, timeout))
  96                udelay(10);
  97
  98        timeout = jiffies + msecs_to_jiffies(100);
  99        while ((snd_hdac_chip_readb(bus, CORBCTL) & AZX_CORBCTL_RUN)
 100                && time_before(jiffies, timeout))
 101                udelay(10);
 102}
 103
 104/**
 105 * snd_hdac_bus_stop_cmd_io - clean up CORB/RIRB buffers
 106 * @bus: HD-audio core bus
 107 */
 108void snd_hdac_bus_stop_cmd_io(struct hdac_bus *bus)
 109{
 110        spin_lock_irq(&bus->reg_lock);
 111        /* disable ringbuffer DMAs */
 112        snd_hdac_chip_writeb(bus, RIRBCTL, 0);
 113        snd_hdac_chip_writeb(bus, CORBCTL, 0);
 114        spin_unlock_irq(&bus->reg_lock);
 115
 116        hdac_wait_for_cmd_dmas(bus);
 117
 118        spin_lock_irq(&bus->reg_lock);
 119        /* disable unsolicited responses */
 120        snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, 0);
 121        spin_unlock_irq(&bus->reg_lock);
 122}
 123EXPORT_SYMBOL_GPL(snd_hdac_bus_stop_cmd_io);
 124
 125static unsigned int azx_command_addr(u32 cmd)
 126{
 127        unsigned int addr = cmd >> 28;
 128
 129        if (snd_BUG_ON(addr >= HDA_MAX_CODECS))
 130                addr = 0;
 131        return addr;
 132}
 133
 134/**
 135 * snd_hdac_bus_send_cmd - send a command verb via CORB
 136 * @bus: HD-audio core bus
 137 * @val: encoded verb value to send
 138 *
 139 * Returns zero for success or a negative error code.
 140 */
 141int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val)
 142{
 143        unsigned int addr = azx_command_addr(val);
 144        unsigned int wp, rp;
 145
 146        spin_lock_irq(&bus->reg_lock);
 147
 148        bus->last_cmd[azx_command_addr(val)] = val;
 149
 150        /* add command to corb */
 151        wp = snd_hdac_chip_readw(bus, CORBWP);
 152        if (wp == 0xffff) {
 153                /* something wrong, controller likely turned to D3 */
 154                spin_unlock_irq(&bus->reg_lock);
 155                return -EIO;
 156        }
 157        wp++;
 158        wp %= AZX_MAX_CORB_ENTRIES;
 159
 160        rp = snd_hdac_chip_readw(bus, CORBRP);
 161        if (wp == rp) {
 162                /* oops, it's full */
 163                spin_unlock_irq(&bus->reg_lock);
 164                return -EAGAIN;
 165        }
 166
 167        bus->rirb.cmds[addr]++;
 168        bus->corb.buf[wp] = cpu_to_le32(val);
 169        snd_hdac_chip_writew(bus, CORBWP, wp);
 170
 171        spin_unlock_irq(&bus->reg_lock);
 172
 173        return 0;
 174}
 175EXPORT_SYMBOL_GPL(snd_hdac_bus_send_cmd);
 176
 177#define AZX_RIRB_EX_UNSOL_EV    (1<<4)
 178
 179/**
 180 * snd_hdac_bus_update_rirb - retrieve RIRB entries
 181 * @bus: HD-audio core bus
 182 *
 183 * Usually called from interrupt handler.
 184 */
 185void snd_hdac_bus_update_rirb(struct hdac_bus *bus)
 186{
 187        unsigned int rp, wp;
 188        unsigned int addr;
 189        u32 res, res_ex;
 190
 191        wp = snd_hdac_chip_readw(bus, RIRBWP);
 192        if (wp == 0xffff) {
 193                /* something wrong, controller likely turned to D3 */
 194                return;
 195        }
 196
 197        if (wp == bus->rirb.wp)
 198                return;
 199        bus->rirb.wp = wp;
 200
 201        while (bus->rirb.rp != wp) {
 202                bus->rirb.rp++;
 203                bus->rirb.rp %= AZX_MAX_RIRB_ENTRIES;
 204
 205                rp = bus->rirb.rp << 1; /* an RIRB entry is 8-bytes */
 206                res_ex = le32_to_cpu(bus->rirb.buf[rp + 1]);
 207                res = le32_to_cpu(bus->rirb.buf[rp]);
 208                addr = res_ex & 0xf;
 209                if (addr >= HDA_MAX_CODECS) {
 210                        dev_err(bus->dev,
 211                                "spurious response %#x:%#x, rp = %d, wp = %d",
 212                                res, res_ex, bus->rirb.rp, wp);
 213                        snd_BUG();
 214                } else if (res_ex & AZX_RIRB_EX_UNSOL_EV)
 215                        snd_hdac_bus_queue_event(bus, res, res_ex);
 216                else if (bus->rirb.cmds[addr]) {
 217                        bus->rirb.res[addr] = res;
 218                        bus->rirb.cmds[addr]--;
 219                } else {
 220                        dev_err_ratelimited(bus->dev,
 221                                "spurious response %#x:%#x, last cmd=%#08x\n",
 222                                res, res_ex, bus->last_cmd[addr]);
 223                }
 224        }
 225}
 226EXPORT_SYMBOL_GPL(snd_hdac_bus_update_rirb);
 227
 228/**
 229 * snd_hdac_bus_get_response - receive a response via RIRB
 230 * @bus: HD-audio core bus
 231 * @addr: codec address
 232 * @res: pointer to store the value, NULL when not needed
 233 *
 234 * Returns zero if a value is read, or a negative error code.
 235 */
 236int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
 237                              unsigned int *res)
 238{
 239        unsigned long timeout;
 240        unsigned long loopcounter;
 241
 242        timeout = jiffies + msecs_to_jiffies(1000);
 243
 244        for (loopcounter = 0;; loopcounter++) {
 245                spin_lock_irq(&bus->reg_lock);
 246                if (bus->polling_mode)
 247                        snd_hdac_bus_update_rirb(bus);
 248                if (!bus->rirb.cmds[addr]) {
 249                        if (res)
 250                                *res = bus->rirb.res[addr]; /* the last value */
 251                        spin_unlock_irq(&bus->reg_lock);
 252                        return 0;
 253                }
 254                spin_unlock_irq(&bus->reg_lock);
 255                if (time_after(jiffies, timeout))
 256                        break;
 257                if (loopcounter > 3000)
 258                        msleep(2); /* temporary workaround */
 259                else {
 260                        udelay(10);
 261                        cond_resched();
 262                }
 263        }
 264
 265        return -EIO;
 266}
 267EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response);
 268
 269#define HDAC_MAX_CAPS 10
 270/**
 271 * snd_hdac_bus_parse_capabilities - parse capability structure
 272 * @bus: the pointer to bus object
 273 *
 274 * Returns 0 if successful, or a negative error code.
 275 */
 276int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus)
 277{
 278        unsigned int cur_cap;
 279        unsigned int offset;
 280        unsigned int counter = 0;
 281
 282        offset = snd_hdac_chip_readw(bus, LLCH);
 283
 284        /* Lets walk the linked capabilities list */
 285        do {
 286                cur_cap = _snd_hdac_chip_readl(bus, offset);
 287
 288                dev_dbg(bus->dev, "Capability version: 0x%x\n",
 289                        (cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF);
 290
 291                dev_dbg(bus->dev, "HDA capability ID: 0x%x\n",
 292                        (cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF);
 293
 294                if (cur_cap == -1) {
 295                        dev_dbg(bus->dev, "Invalid capability reg read\n");
 296                        break;
 297                }
 298
 299                switch ((cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF) {
 300                case AZX_ML_CAP_ID:
 301                        dev_dbg(bus->dev, "Found ML capability\n");
 302                        bus->mlcap = bus->remap_addr + offset;
 303                        break;
 304
 305                case AZX_GTS_CAP_ID:
 306                        dev_dbg(bus->dev, "Found GTS capability offset=%x\n", offset);
 307                        bus->gtscap = bus->remap_addr + offset;
 308                        break;
 309
 310                case AZX_PP_CAP_ID:
 311                        /* PP capability found, the Audio DSP is present */
 312                        dev_dbg(bus->dev, "Found PP capability offset=%x\n", offset);
 313                        bus->ppcap = bus->remap_addr + offset;
 314                        break;
 315
 316                case AZX_SPB_CAP_ID:
 317                        /* SPIB capability found, handler function */
 318                        dev_dbg(bus->dev, "Found SPB capability\n");
 319                        bus->spbcap = bus->remap_addr + offset;
 320                        break;
 321
 322                case AZX_DRSM_CAP_ID:
 323                        /* DMA resume  capability found, handler function */
 324                        dev_dbg(bus->dev, "Found DRSM capability\n");
 325                        bus->drsmcap = bus->remap_addr + offset;
 326                        break;
 327
 328                default:
 329                        dev_err(bus->dev, "Unknown capability %d\n", cur_cap);
 330                        cur_cap = 0;
 331                        break;
 332                }
 333
 334                counter++;
 335
 336                if (counter > HDAC_MAX_CAPS) {
 337                        dev_err(bus->dev, "We exceeded HDAC capabilities!!!\n");
 338                        break;
 339                }
 340
 341                /* read the offset of next capability */
 342                offset = cur_cap & AZX_CAP_HDR_NXT_PTR_MASK;
 343
 344        } while (offset);
 345
 346        return 0;
 347}
 348EXPORT_SYMBOL_GPL(snd_hdac_bus_parse_capabilities);
 349
 350/*
 351 * Lowlevel interface
 352 */
 353
 354/**
 355 * snd_hdac_bus_enter_link_reset - enter link reset
 356 * @bus: HD-audio core bus
 357 *
 358 * Enter to the link reset state.
 359 */
 360void snd_hdac_bus_enter_link_reset(struct hdac_bus *bus)
 361{
 362        unsigned long timeout;
 363
 364        /* reset controller */
 365        snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_RESET, 0);
 366
 367        timeout = jiffies + msecs_to_jiffies(100);
 368        while ((snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET) &&
 369               time_before(jiffies, timeout))
 370                usleep_range(500, 1000);
 371}
 372EXPORT_SYMBOL_GPL(snd_hdac_bus_enter_link_reset);
 373
 374/**
 375 * snd_hdac_bus_exit_link_reset - exit link reset
 376 * @bus: HD-audio core bus
 377 *
 378 * Exit from the link reset state.
 379 */
 380void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus)
 381{
 382        unsigned long timeout;
 383
 384        snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET);
 385
 386        timeout = jiffies + msecs_to_jiffies(100);
 387        while (!snd_hdac_chip_readb(bus, GCTL) && time_before(jiffies, timeout))
 388                usleep_range(500, 1000);
 389}
 390EXPORT_SYMBOL_GPL(snd_hdac_bus_exit_link_reset);
 391
 392/* reset codec link */
 393int snd_hdac_bus_reset_link(struct hdac_bus *bus, bool full_reset)
 394{
 395        if (!full_reset)
 396                goto skip_reset;
 397
 398        /* clear STATESTS */
 399        snd_hdac_chip_writew(bus, STATESTS, STATESTS_INT_MASK);
 400
 401        /* reset controller */
 402        snd_hdac_bus_enter_link_reset(bus);
 403
 404        /* delay for >= 100us for codec PLL to settle per spec
 405         * Rev 0.9 section 5.5.1
 406         */
 407        usleep_range(500, 1000);
 408
 409        /* Bring controller out of reset */
 410        snd_hdac_bus_exit_link_reset(bus);
 411
 412        /* Brent Chartrand said to wait >= 540us for codecs to initialize */
 413        usleep_range(1000, 1200);
 414
 415 skip_reset:
 416        /* check to see if controller is ready */
 417        if (!snd_hdac_chip_readb(bus, GCTL)) {
 418                dev_dbg(bus->dev, "controller not ready!\n");
 419                return -EBUSY;
 420        }
 421
 422        /* detect codecs */
 423        if (!bus->codec_mask) {
 424                bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
 425                dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
 426        }
 427
 428        return 0;
 429}
 430EXPORT_SYMBOL_GPL(snd_hdac_bus_reset_link);
 431
 432/* enable interrupts */
 433static void azx_int_enable(struct hdac_bus *bus)
 434{
 435        /* enable controller CIE and GIE */
 436        snd_hdac_chip_updatel(bus, INTCTL,
 437                              AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN,
 438                              AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN);
 439}
 440
 441/* disable interrupts */
 442static void azx_int_disable(struct hdac_bus *bus)
 443{
 444        struct hdac_stream *azx_dev;
 445
 446        /* disable interrupts in stream descriptor */
 447        list_for_each_entry(azx_dev, &bus->stream_list, list)
 448                snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0);
 449
 450        /* disable SIE for all streams */
 451        snd_hdac_chip_writeb(bus, INTCTL, 0);
 452
 453        /* disable controller CIE and GIE */
 454        snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN, 0);
 455}
 456
 457/* clear interrupts */
 458static void azx_int_clear(struct hdac_bus *bus)
 459{
 460        struct hdac_stream *azx_dev;
 461
 462        /* clear stream status */
 463        list_for_each_entry(azx_dev, &bus->stream_list, list)
 464                snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK);
 465
 466        /* clear STATESTS */
 467        snd_hdac_chip_writew(bus, STATESTS, STATESTS_INT_MASK);
 468
 469        /* clear rirb status */
 470        snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
 471
 472        /* clear int status */
 473        snd_hdac_chip_writel(bus, INTSTS, AZX_INT_CTRL_EN | AZX_INT_ALL_STREAM);
 474}
 475
 476/**
 477 * snd_hdac_bus_init_chip - reset and start the controller registers
 478 * @bus: HD-audio core bus
 479 * @full_reset: Do full reset
 480 */
 481bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset)
 482{
 483        if (bus->chip_init)
 484                return false;
 485
 486        /* reset controller */
 487        snd_hdac_bus_reset_link(bus, full_reset);
 488
 489        /* clear interrupts */
 490        azx_int_clear(bus);
 491
 492        /* initialize the codec command I/O */
 493        snd_hdac_bus_init_cmd_io(bus);
 494
 495        /* enable interrupts after CORB/RIRB buffers are initialized above */
 496        azx_int_enable(bus);
 497
 498        /* program the position buffer */
 499        if (bus->use_posbuf && bus->posbuf.addr) {
 500                snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr);
 501                snd_hdac_chip_writel(bus, DPUBASE, upper_32_bits(bus->posbuf.addr));
 502        }
 503
 504        bus->chip_init = true;
 505        return true;
 506}
 507EXPORT_SYMBOL_GPL(snd_hdac_bus_init_chip);
 508
 509/**
 510 * snd_hdac_bus_stop_chip - disable the whole IRQ and I/Os
 511 * @bus: HD-audio core bus
 512 */
 513void snd_hdac_bus_stop_chip(struct hdac_bus *bus)
 514{
 515        if (!bus->chip_init)
 516                return;
 517
 518        /* disable interrupts */
 519        azx_int_disable(bus);
 520        azx_int_clear(bus);
 521
 522        /* disable CORB/RIRB */
 523        snd_hdac_bus_stop_cmd_io(bus);
 524
 525        /* disable position buffer */
 526        if (bus->posbuf.addr) {
 527                snd_hdac_chip_writel(bus, DPLBASE, 0);
 528                snd_hdac_chip_writel(bus, DPUBASE, 0);
 529        }
 530
 531        bus->chip_init = false;
 532}
 533EXPORT_SYMBOL_GPL(snd_hdac_bus_stop_chip);
 534
 535/**
 536 * snd_hdac_bus_handle_stream_irq - interrupt handler for streams
 537 * @bus: HD-audio core bus
 538 * @status: INTSTS register value
 539 * @ask: callback to be called for woken streams
 540 *
 541 * Returns the bits of handled streams, or zero if no stream is handled.
 542 */
 543int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
 544                                    void (*ack)(struct hdac_bus *,
 545                                                struct hdac_stream *))
 546{
 547        struct hdac_stream *azx_dev;
 548        u8 sd_status;
 549        int handled = 0;
 550
 551        list_for_each_entry(azx_dev, &bus->stream_list, list) {
 552                if (status & azx_dev->sd_int_sta_mask) {
 553                        sd_status = snd_hdac_stream_readb(azx_dev, SD_STS);
 554                        snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK);
 555                        handled |= 1 << azx_dev->index;
 556                        if (!azx_dev->substream || !azx_dev->running ||
 557                            !(sd_status & SD_INT_COMPLETE))
 558                                continue;
 559                        if (ack)
 560                                ack(bus, azx_dev);
 561                }
 562        }
 563        return handled;
 564}
 565EXPORT_SYMBOL_GPL(snd_hdac_bus_handle_stream_irq);
 566
 567/**
 568 * snd_hdac_bus_alloc_stream_pages - allocate BDL and other buffers
 569 * @bus: HD-audio core bus
 570 *
 571 * Call this after assigning the all streams.
 572 * Returns zero for success, or a negative error code.
 573 */
 574int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus)
 575{
 576        struct hdac_stream *s;
 577        int num_streams = 0;
 578        int err;
 579
 580        list_for_each_entry(s, &bus->stream_list, list) {
 581                /* allocate memory for the BDL for each stream */
 582                err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV,
 583                                                   BDL_SIZE, &s->bdl);
 584                num_streams++;
 585                if (err < 0)
 586                        return -ENOMEM;
 587        }
 588
 589        if (WARN_ON(!num_streams))
 590                return -EINVAL;
 591        /* allocate memory for the position buffer */
 592        err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV,
 593                                           num_streams * 8, &bus->posbuf);
 594        if (err < 0)
 595                return -ENOMEM;
 596        list_for_each_entry(s, &bus->stream_list, list)
 597                s->posbuf = (__le32 *)(bus->posbuf.area + s->index * 8);
 598
 599        /* single page (at least 4096 bytes) must suffice for both ringbuffes */
 600        return bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV,
 601                                            PAGE_SIZE, &bus->rb);
 602}
 603EXPORT_SYMBOL_GPL(snd_hdac_bus_alloc_stream_pages);
 604
 605/**
 606 * snd_hdac_bus_free_stream_pages - release BDL and other buffers
 607 * @bus: HD-audio core bus
 608 */
 609void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus)
 610{
 611        struct hdac_stream *s;
 612
 613        list_for_each_entry(s, &bus->stream_list, list) {
 614                if (s->bdl.area)
 615                        bus->io_ops->dma_free_pages(bus, &s->bdl);
 616        }
 617
 618        if (bus->rb.area)
 619                bus->io_ops->dma_free_pages(bus, &bus->rb);
 620        if (bus->posbuf.area)
 621                bus->io_ops->dma_free_pages(bus, &bus->posbuf);
 622}
 623EXPORT_SYMBOL_GPL(snd_hdac_bus_free_stream_pages);
 624