.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * HD-audio controller helpers |
---|
3 | 4 | */ |
---|
.. | .. |
---|
8 | 9 | #include <sound/core.h> |
---|
9 | 10 | #include <sound/hdaudio.h> |
---|
10 | 11 | #include <sound/hda_register.h> |
---|
| 12 | +#include "local.h" |
---|
11 | 13 | |
---|
12 | 14 | /* clear CORB read pointer properly */ |
---|
13 | 15 | static void azx_clear_corbrp(struct hdac_bus *bus) |
---|
.. | .. |
---|
78 | 80 | snd_hdac_chip_writew(bus, RINTCNT, 1); |
---|
79 | 81 | /* enable rirb dma and response irq */ |
---|
80 | 82 | snd_hdac_chip_writeb(bus, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN); |
---|
| 83 | + /* Accept unsolicited responses */ |
---|
| 84 | + snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); |
---|
81 | 85 | spin_unlock_irq(&bus->reg_lock); |
---|
82 | 86 | } |
---|
83 | 87 | EXPORT_SYMBOL_GPL(snd_hdac_bus_init_cmd_io); |
---|
.. | .. |
---|
178 | 182 | * @bus: HD-audio core bus |
---|
179 | 183 | * |
---|
180 | 184 | * Usually called from interrupt handler. |
---|
| 185 | + * The caller needs bus->reg_lock spinlock before calling this. |
---|
181 | 186 | */ |
---|
182 | 187 | void snd_hdac_bus_update_rirb(struct hdac_bus *bus) |
---|
183 | 188 | { |
---|
.. | .. |
---|
213 | 218 | else if (bus->rirb.cmds[addr]) { |
---|
214 | 219 | bus->rirb.res[addr] = res; |
---|
215 | 220 | bus->rirb.cmds[addr]--; |
---|
| 221 | + if (!bus->rirb.cmds[addr] && |
---|
| 222 | + waitqueue_active(&bus->rirb_wq)) |
---|
| 223 | + wake_up(&bus->rirb_wq); |
---|
216 | 224 | } else { |
---|
217 | 225 | dev_err_ratelimited(bus->dev, |
---|
218 | 226 | "spurious response %#x:%#x, last cmd=%#08x\n", |
---|
.. | .. |
---|
235 | 243 | { |
---|
236 | 244 | unsigned long timeout; |
---|
237 | 245 | unsigned long loopcounter; |
---|
| 246 | + wait_queue_entry_t wait; |
---|
| 247 | + bool warned = false; |
---|
238 | 248 | |
---|
| 249 | + init_wait_entry(&wait, 0); |
---|
239 | 250 | timeout = jiffies + msecs_to_jiffies(1000); |
---|
240 | 251 | |
---|
241 | 252 | for (loopcounter = 0;; loopcounter++) { |
---|
242 | 253 | spin_lock_irq(&bus->reg_lock); |
---|
| 254 | + if (!bus->polling_mode) |
---|
| 255 | + prepare_to_wait(&bus->rirb_wq, &wait, |
---|
| 256 | + TASK_UNINTERRUPTIBLE); |
---|
| 257 | + if (bus->polling_mode) |
---|
| 258 | + snd_hdac_bus_update_rirb(bus); |
---|
243 | 259 | if (!bus->rirb.cmds[addr]) { |
---|
244 | 260 | if (res) |
---|
245 | 261 | *res = bus->rirb.res[addr]; /* the last value */ |
---|
| 262 | + if (!bus->polling_mode) |
---|
| 263 | + finish_wait(&bus->rirb_wq, &wait); |
---|
246 | 264 | spin_unlock_irq(&bus->reg_lock); |
---|
247 | 265 | return 0; |
---|
248 | 266 | } |
---|
249 | 267 | spin_unlock_irq(&bus->reg_lock); |
---|
250 | 268 | if (time_after(jiffies, timeout)) |
---|
251 | 269 | break; |
---|
252 | | - if (loopcounter > 3000) |
---|
| 270 | +#define LOOP_COUNT_MAX 3000 |
---|
| 271 | + if (!bus->polling_mode) { |
---|
| 272 | + schedule_timeout(msecs_to_jiffies(2)); |
---|
| 273 | + } else if (bus->needs_damn_long_delay || |
---|
| 274 | + loopcounter > LOOP_COUNT_MAX) { |
---|
| 275 | + if (loopcounter > LOOP_COUNT_MAX && !warned) { |
---|
| 276 | + dev_dbg_ratelimited(bus->dev, |
---|
| 277 | + "too slow response, last cmd=%#08x\n", |
---|
| 278 | + bus->last_cmd[addr]); |
---|
| 279 | + warned = true; |
---|
| 280 | + } |
---|
253 | 281 | msleep(2); /* temporary workaround */ |
---|
254 | | - else { |
---|
| 282 | + } else { |
---|
255 | 283 | udelay(10); |
---|
256 | 284 | cond_resched(); |
---|
257 | 285 | } |
---|
258 | 286 | } |
---|
| 287 | + |
---|
| 288 | + if (!bus->polling_mode) |
---|
| 289 | + finish_wait(&bus->rirb_wq, &wait); |
---|
259 | 290 | |
---|
260 | 291 | return -EIO; |
---|
261 | 292 | } |
---|
.. | .. |
---|
376 | 407 | { |
---|
377 | 408 | unsigned long timeout; |
---|
378 | 409 | |
---|
379 | | - snd_hdac_chip_updateb(bus, GCTL, 0, AZX_GCTL_RESET); |
---|
| 410 | + snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET); |
---|
380 | 411 | |
---|
381 | 412 | timeout = jiffies + msecs_to_jiffies(100); |
---|
382 | 413 | while (!snd_hdac_chip_readb(bus, GCTL) && time_before(jiffies, timeout)) |
---|
.. | .. |
---|
415 | 446 | return -EBUSY; |
---|
416 | 447 | } |
---|
417 | 448 | |
---|
418 | | - /* Accept unsolicited responses */ |
---|
419 | | - snd_hdac_chip_updatel(bus, GCTL, 0, AZX_GCTL_UNSOL); |
---|
420 | | - |
---|
421 | 449 | /* detect codecs */ |
---|
422 | 450 | if (!bus->codec_mask) { |
---|
423 | 451 | bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS); |
---|
.. | .. |
---|
432 | 460 | static void azx_int_enable(struct hdac_bus *bus) |
---|
433 | 461 | { |
---|
434 | 462 | /* enable controller CIE and GIE */ |
---|
435 | | - snd_hdac_chip_updatel(bus, INTCTL, 0, AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN); |
---|
| 463 | + snd_hdac_chip_updatel(bus, INTCTL, |
---|
| 464 | + AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN, |
---|
| 465 | + AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN); |
---|
436 | 466 | } |
---|
437 | 467 | |
---|
438 | 468 | /* disable interrupts */ |
---|
.. | .. |
---|
499 | 529 | } |
---|
500 | 530 | |
---|
501 | 531 | bus->chip_init = true; |
---|
| 532 | + |
---|
502 | 533 | return true; |
---|
503 | 534 | } |
---|
504 | 535 | EXPORT_SYMBOL_GPL(snd_hdac_bus_init_chip); |
---|
.. | .. |
---|
533 | 564 | * snd_hdac_bus_handle_stream_irq - interrupt handler for streams |
---|
534 | 565 | * @bus: HD-audio core bus |
---|
535 | 566 | * @status: INTSTS register value |
---|
536 | | - * @ask: callback to be called for woken streams |
---|
| 567 | + * @ack: callback to be called for woken streams |
---|
537 | 568 | * |
---|
538 | 569 | * Returns the bits of handled streams, or zero if no stream is handled. |
---|
539 | 570 | */ |
---|
.. | .. |
---|
572 | 603 | { |
---|
573 | 604 | struct hdac_stream *s; |
---|
574 | 605 | int num_streams = 0; |
---|
| 606 | + int dma_type = bus->dma_type ? bus->dma_type : SNDRV_DMA_TYPE_DEV; |
---|
575 | 607 | int err; |
---|
576 | 608 | |
---|
577 | 609 | list_for_each_entry(s, &bus->stream_list, list) { |
---|
578 | 610 | /* allocate memory for the BDL for each stream */ |
---|
579 | | - err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, |
---|
580 | | - BDL_SIZE, &s->bdl); |
---|
| 611 | + err = snd_dma_alloc_pages(dma_type, bus->dev, |
---|
| 612 | + BDL_SIZE, &s->bdl); |
---|
581 | 613 | num_streams++; |
---|
582 | 614 | if (err < 0) |
---|
583 | 615 | return -ENOMEM; |
---|
.. | .. |
---|
586 | 618 | if (WARN_ON(!num_streams)) |
---|
587 | 619 | return -EINVAL; |
---|
588 | 620 | /* allocate memory for the position buffer */ |
---|
589 | | - err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, |
---|
590 | | - num_streams * 8, &bus->posbuf); |
---|
| 621 | + err = snd_dma_alloc_pages(dma_type, bus->dev, |
---|
| 622 | + num_streams * 8, &bus->posbuf); |
---|
591 | 623 | if (err < 0) |
---|
592 | 624 | return -ENOMEM; |
---|
593 | 625 | list_for_each_entry(s, &bus->stream_list, list) |
---|
594 | 626 | s->posbuf = (__le32 *)(bus->posbuf.area + s->index * 8); |
---|
595 | 627 | |
---|
596 | 628 | /* single page (at least 4096 bytes) must suffice for both ringbuffes */ |
---|
597 | | - return bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, |
---|
598 | | - PAGE_SIZE, &bus->rb); |
---|
| 629 | + return snd_dma_alloc_pages(dma_type, bus->dev, PAGE_SIZE, &bus->rb); |
---|
599 | 630 | } |
---|
600 | 631 | EXPORT_SYMBOL_GPL(snd_hdac_bus_alloc_stream_pages); |
---|
601 | 632 | |
---|
.. | .. |
---|
609 | 640 | |
---|
610 | 641 | list_for_each_entry(s, &bus->stream_list, list) { |
---|
611 | 642 | if (s->bdl.area) |
---|
612 | | - bus->io_ops->dma_free_pages(bus, &s->bdl); |
---|
| 643 | + snd_dma_free_pages(&s->bdl); |
---|
613 | 644 | } |
---|
614 | 645 | |
---|
615 | 646 | if (bus->rb.area) |
---|
616 | | - bus->io_ops->dma_free_pages(bus, &bus->rb); |
---|
| 647 | + snd_dma_free_pages(&bus->rb); |
---|
617 | 648 | if (bus->posbuf.area) |
---|
618 | | - bus->io_ops->dma_free_pages(bus, &bus->posbuf); |
---|
| 649 | + snd_dma_free_pages(&bus->posbuf); |
---|
619 | 650 | } |
---|
620 | 651 | EXPORT_SYMBOL_GPL(snd_hdac_bus_free_stream_pages); |
---|