ALSA: hda: Use waitqueue for RIRB in HDA-core helper, too
authorTakashi Iwai <tiwai@suse.de>
Thu, 12 Dec 2019 19:11:00 +0000 (20:11 +0100)
committerTakashi Iwai <tiwai@suse.de>
Fri, 13 Dec 2019 13:36:44 +0000 (14:36 +0100)
This patch implements the same logic that was done for the legacy
HD-audio controller driver by the commit 88452da92ba2 ("ALSA: hda: Use
standard waitqueue for RIRB wakeup") to the HDA-core helper code,
too.  This makes snd_hdac_bus_get_response() waiting for the response
with bus->rirb_wq instead of polling when bus->polling is false.
It'll save both CPU time and response latency.

Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20191212191101.19517-2-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/hda/hdac_controller.c

index cd1c3b2..61950b8 100644 (file)
@@ -241,30 +241,42 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
 {
        unsigned long timeout;
        unsigned long loopcounter;
 {
        unsigned long timeout;
        unsigned long loopcounter;
+       wait_queue_entry_t wait;
 
 
+       init_wait_entry(&wait, 0);
        timeout = jiffies + msecs_to_jiffies(1000);
 
        for (loopcounter = 0;; loopcounter++) {
                spin_lock_irq(&bus->reg_lock);
        timeout = jiffies + msecs_to_jiffies(1000);
 
        for (loopcounter = 0;; loopcounter++) {
                spin_lock_irq(&bus->reg_lock);
+               if (!bus->polling_mode)
+                       prepare_to_wait(&bus->rirb_wq, &wait,
+                                       TASK_UNINTERRUPTIBLE);
                if (bus->polling_mode)
                        snd_hdac_bus_update_rirb(bus);
                if (!bus->rirb.cmds[addr]) {
                        if (res)
                                *res = bus->rirb.res[addr]; /* the last value */
                if (bus->polling_mode)
                        snd_hdac_bus_update_rirb(bus);
                if (!bus->rirb.cmds[addr]) {
                        if (res)
                                *res = bus->rirb.res[addr]; /* the last value */
+                       if (!bus->polling_mode)
+                               finish_wait(&bus->rirb_wq, &wait);
                        spin_unlock_irq(&bus->reg_lock);
                        return 0;
                }
                spin_unlock_irq(&bus->reg_lock);
                if (time_after(jiffies, timeout))
                        break;
                        spin_unlock_irq(&bus->reg_lock);
                        return 0;
                }
                spin_unlock_irq(&bus->reg_lock);
                if (time_after(jiffies, timeout))
                        break;
-               if (loopcounter > 3000)
+               if (!bus->polling_mode) {
+                       schedule_timeout(msecs_to_jiffies(2));
+               } else if (loopcounter > 3000) {
                        msleep(2); /* temporary workaround */
                        msleep(2); /* temporary workaround */
-               else {
+               else {
                        udelay(10);
                        cond_resched();
                }
        }
 
                        udelay(10);
                        cond_resched();
                }
        }
 
+       if (!bus->polling_mode)
+               finish_wait(&bus->rirb_wq, &wait);
+
        return -EIO;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response);
        return -EIO;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response);