~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/hda/hdac_controller.c

Version: ~ [ linux-5.8 ] ~ [ linux-5.7.14 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.57 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.138 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.193 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.232 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.232 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 */
 14 static 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  */
 42 void 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 }
 86 EXPORT_SYMBOL_GPL(snd_hdac_bus_init_cmd_io);
 87 
 88 /* wait for cmd dmas till they are stopped */
 89 static 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  */
108 void 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 }
123 EXPORT_SYMBOL_GPL(snd_hdac_bus_stop_cmd_io);
124 
125 static 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  */
141 int 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 }
175 EXPORT_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  */
185 void 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 }
226 EXPORT_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  */
236 int 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->rirb.cmds[addr]) {
247                         if (res)
248                                 *res = bus->rirb.res[addr]; /* the last value */
249                         spin_unlock_irq(&bus->reg_lock);
250                         return 0;
251                 }
252                 spin_unlock_irq(&bus->reg_lock);
253                 if (time_after(jiffies, timeout))
254                         break;
255                 if (loopcounter > 3000)
256                         msleep(2); /* temporary workaround */
257                 else {
258                         udelay(10);
259                         cond_resched();
260                 }
261         }
262 
263         return -EIO;
264 }
265 EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response);
266 
267 #define HDAC_MAX_CAPS 10
268 /**
269  * snd_hdac_bus_parse_capabilities - parse capability structure
270  * @bus: the pointer to bus object
271  *
272  * Returns 0 if successful, or a negative error code.
273  */
274 int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus)
275 {
276         unsigned int cur_cap;
277         unsigned int offset;
278         unsigned int counter = 0;
279 
280         offset = snd_hdac_chip_readw(bus, LLCH);
281 
282         /* Lets walk the linked capabilities list */
283         do {
284                 cur_cap = _snd_hdac_chip_readl(bus, offset);
285 
286                 dev_dbg(bus->dev, "Capability version: 0x%x\n",
287                         (cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF);
288 
289                 dev_dbg(bus->dev, "HDA capability ID: 0x%x\n",
290                         (cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF);
291 
292                 if (cur_cap == -1) {
293                         dev_dbg(bus->dev, "Invalid capability reg read\n");
294                         break;
295                 }
296 
297                 switch ((cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF) {
298                 case AZX_ML_CAP_ID:
299                         dev_dbg(bus->dev, "Found ML capability\n");
300                         bus->mlcap = bus->remap_addr + offset;
301                         break;
302 
303                 case AZX_GTS_CAP_ID:
304                         dev_dbg(bus->dev, "Found GTS capability offset=%x\n", offset);
305                         bus->gtscap = bus->remap_addr + offset;
306                         break;
307 
308                 case AZX_PP_CAP_ID:
309                         /* PP capability found, the Audio DSP is present */
310                         dev_dbg(bus->dev, "Found PP capability offset=%x\n", offset);
311                         bus->ppcap = bus->remap_addr + offset;
312                         break;
313 
314                 case AZX_SPB_CAP_ID:
315                         /* SPIB capability found, handler function */
316                         dev_dbg(bus->dev, "Found SPB capability\n");
317                         bus->spbcap = bus->remap_addr + offset;
318                         break;
319 
320                 case AZX_DRSM_CAP_ID:
321                         /* DMA resume  capability found, handler function */
322                         dev_dbg(bus->dev, "Found DRSM capability\n");
323                         bus->drsmcap = bus->remap_addr + offset;
324                         break;
325 
326                 default:
327                         dev_err(bus->dev, "Unknown capability %d\n", cur_cap);
328                         cur_cap = 0;
329                         break;
330                 }
331 
332                 counter++;
333 
334                 if (counter > HDAC_MAX_CAPS) {
335                         dev_err(bus->dev, "We exceeded HDAC capabilities!!!\n");
336                         break;
337                 }
338 
339                 /* read the offset of next capability */
340                 offset = cur_cap & AZX_CAP_HDR_NXT_PTR_MASK;
341 
342         } while (offset);
343 
344         return 0;
345 }
346 EXPORT_SYMBOL_GPL(snd_hdac_bus_parse_capabilities);
347 
348 /*
349  * Lowlevel interface
350  */
351 
352 /**
353  * snd_hdac_bus_enter_link_reset - enter link reset
354  * @bus: HD-audio core bus
355  *
356  * Enter to the link reset state.
357  */
358 void snd_hdac_bus_enter_link_reset(struct hdac_bus *bus)
359 {
360         unsigned long timeout;
361 
362         /* reset controller */
363         snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_RESET, 0);
364 
365         timeout = jiffies + msecs_to_jiffies(100);
366         while ((snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET) &&
367                time_before(jiffies, timeout))
368                 usleep_range(500, 1000);
369 }
370 EXPORT_SYMBOL_GPL(snd_hdac_bus_enter_link_reset);
371 
372 /**
373  * snd_hdac_bus_exit_link_reset - exit link reset
374  * @bus: HD-audio core bus
375  *
376  * Exit from the link reset state.
377  */
378 void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus)
379 {
380         unsigned long timeout;
381 
382         snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET);
383 
384         timeout = jiffies + msecs_to_jiffies(100);
385         while (!snd_hdac_chip_readb(bus, GCTL) && time_before(jiffies, timeout))
386                 usleep_range(500, 1000);
387 }
388 EXPORT_SYMBOL_GPL(snd_hdac_bus_exit_link_reset);
389 
390 /* reset codec link */
391 int snd_hdac_bus_reset_link(struct hdac_bus *bus, bool full_reset)
392 {
393         if (!full_reset)
394                 goto skip_reset;
395 
396         /* clear STATESTS */
397         snd_hdac_chip_writew(bus, STATESTS, STATESTS_INT_MASK);
398 
399         /* reset controller */
400         snd_hdac_bus_enter_link_reset(bus);
401 
402         /* delay for >= 100us for codec PLL to settle per spec
403          * Rev 0.9 section 5.5.1
404          */
405         usleep_range(500, 1000);
406 
407         /* Bring controller out of reset */
408         snd_hdac_bus_exit_link_reset(bus);
409 
410         /* Brent Chartrand said to wait >= 540us for codecs to initialize */
411         usleep_range(1000, 1200);
412 
413  skip_reset:
414         /* check to see if controller is ready */
415         if (!snd_hdac_chip_readb(bus, GCTL)) {
416                 dev_dbg(bus->dev, "controller not ready!\n");
417                 return -EBUSY;
418         }
419 
420         /* detect codecs */
421         if (!bus->codec_mask) {
422                 bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
423                 dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
424         }
425 
426         return 0;
427 }
428 EXPORT_SYMBOL_GPL(snd_hdac_bus_reset_link);
429 
430 /* enable interrupts */
431 static void azx_int_enable(struct hdac_bus *bus)
432 {
433         /* enable controller CIE and GIE */
434         snd_hdac_chip_updatel(bus, INTCTL,
435                               AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN,
436                               AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN);
437 }
438 
439 /* disable interrupts */
440 static void azx_int_disable(struct hdac_bus *bus)
441 {
442         struct hdac_stream *azx_dev;
443 
444         /* disable interrupts in stream descriptor */
445         list_for_each_entry(azx_dev, &bus->stream_list, list)
446                 snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0);
447 
448         synchronize_irq(bus->irq);
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 */
458 static 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  */
481 bool 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 }
507 EXPORT_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  */
513 void 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 }
533 EXPORT_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  */
543 int 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 }
565 EXPORT_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  */
574 int 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 }
603 EXPORT_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  */
609 void 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 }
623 EXPORT_SYMBOL_GPL(snd_hdac_bus_free_stream_pages);
624 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp