Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: hda - Loop interrupt handling until really cleared

Currently the interrupt handler of HD-audio driver assumes that no irq
update is needed while processing the irq. But in reality, it has
been confirmed that the HW irq is issued even during the irq
handling. Since we clear the irq status at the beginning, process the
interrupt, then exits from the handler, the lately issued interrupt is
left untouched without being properly processed.

This patch changes the interrupt handler code to loop over the
check-and-process. The handler tries repeatedly as long as the IRQ
status are turned on, and either stream or CORB/RIRB is handled.

For checking the stream handling, snd_hdac_bus_handle_stream_irq()
returns a value indicating the stream indices bits. Other than that,
the change is only in the irq handler itself.

Reported-by: Libin Yang <libin.yang@linux.intel.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

+32 -22
+1 -1
include/sound/hdaudio.h
··· 343 343 void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus); 344 344 345 345 void snd_hdac_bus_update_rirb(struct hdac_bus *bus); 346 - void snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status, 346 + int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status, 347 347 void (*ack)(struct hdac_bus *, 348 348 struct hdac_stream *)); 349 349
+6 -1
sound/hda/hdac_controller.c
··· 426 426 * @bus: HD-audio core bus 427 427 * @status: INTSTS register value 428 428 * @ask: callback to be called for woken streams 429 + * 430 + * Returns the bits of handled streams, or zero if no stream is handled. 429 431 */ 430 - void snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status, 432 + int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status, 431 433 void (*ack)(struct hdac_bus *, 432 434 struct hdac_stream *)) 433 435 { 434 436 struct hdac_stream *azx_dev; 435 437 u8 sd_status; 438 + int handled = 0; 436 439 437 440 list_for_each_entry(azx_dev, &bus->stream_list, list) { 438 441 if (status & azx_dev->sd_int_sta_mask) { 439 442 sd_status = snd_hdac_stream_readb(azx_dev, SD_STS); 440 443 snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); 444 + handled |= 1 << azx_dev->index; 441 445 if (!azx_dev->substream || !azx_dev->running || 442 446 !(sd_status & SD_INT_COMPLETE)) 443 447 continue; ··· 449 445 ack(bus, azx_dev); 450 446 } 451 447 } 448 + return handled; 452 449 } 453 450 EXPORT_SYMBOL_GPL(snd_hdac_bus_handle_stream_irq); 454 451
+25 -20
sound/pci/hda/hda_controller.c
··· 930 930 struct azx *chip = dev_id; 931 931 struct hdac_bus *bus = azx_bus(chip); 932 932 u32 status; 933 + bool active, handled = false; 934 + int repeat = 0; /* count for avoiding endless loop */ 933 935 934 936 #ifdef CONFIG_PM 935 937 if (azx_has_pm_runtime(chip)) ··· 941 939 942 940 spin_lock(&bus->reg_lock); 943 941 944 - if (chip->disabled) { 945 - spin_unlock(&bus->reg_lock); 946 - return IRQ_NONE; 947 - } 942 + if (chip->disabled) 943 + goto unlock; 948 944 949 - status = azx_readl(chip, INTSTS); 950 - if (status == 0 || status == 0xffffffff) { 951 - spin_unlock(&bus->reg_lock); 952 - return IRQ_NONE; 953 - } 945 + do { 946 + status = azx_readl(chip, INTSTS); 947 + if (status == 0 || status == 0xffffffff) 948 + break; 954 949 955 - snd_hdac_bus_handle_stream_irq(bus, status, stream_update); 950 + handled = true; 951 + active = false; 952 + if (snd_hdac_bus_handle_stream_irq(bus, status, stream_update)) 953 + active = true; 956 954 957 - /* clear rirb int */ 958 - status = azx_readb(chip, RIRBSTS); 959 - if (status & RIRB_INT_MASK) { 960 - if (status & RIRB_INT_RESPONSE) { 961 - if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) 962 - udelay(80); 963 - snd_hdac_bus_update_rirb(bus); 955 + /* clear rirb int */ 956 + status = azx_readb(chip, RIRBSTS); 957 + if (status & RIRB_INT_MASK) { 958 + active = true; 959 + if (status & RIRB_INT_RESPONSE) { 960 + if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) 961 + udelay(80); 962 + snd_hdac_bus_update_rirb(bus); 963 + } 964 + azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); 964 965 } 965 - azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); 966 - } 966 + } while (active && ++repeat < 10); 967 967 968 + unlock: 968 969 spin_unlock(&bus->reg_lock); 969 970 970 - return IRQ_HANDLED; 971 + return IRQ_RETVAL(handled); 971 972 } 972 973 EXPORT_SYMBOL_GPL(azx_interrupt); 973 974