Skip to content

Commit

Permalink
[ALSA] hda-intel - Add check of MSI availabity
Browse files Browse the repository at this point in the history
Check the availability of MSI and turn off MSI automatically when it's
not available on the hardware.  MSI seems broken on some hardwares
but the kernel doesn't know exactly, thus we have to turn the MSI
feature off on the sound driver manually.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
  • Loading branch information
Takashi Iwai authored and Jaroslav Kysela committed Oct 23, 2006
1 parent a5c81b6 commit 68e7fff
Showing 1 changed file with 39 additions and 17 deletions.
56 changes: 39 additions & 17 deletions sound/pci/hda/hda_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ struct azx {
unsigned int initialized :1;
unsigned int single_cmd :1;
unsigned int polling_mode :1;
unsigned int msi :1;
};

/* driver types */
Expand Down Expand Up @@ -397,6 +398,7 @@ static char *driver_short_names[] __devinitdata = {
*/
#define upper_32bit(addr) (sizeof(addr) > 4 ? (u32)((addr) >> 32) : (u32)0)

static int azx_acquire_irq(struct azx *chip, int do_disconnect);

/*
* Interface for HD codec
Expand Down Expand Up @@ -536,6 +538,18 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
schedule_timeout_interruptible(1);
} while (time_after_eq(timeout, jiffies));

if (chip->msi) {
snd_printk(KERN_WARNING "hda_intel: No response from codec, "
"disabling MSI...\n");
free_irq(chip->irq, chip);
chip->irq = -1;
pci_disable_msi(chip->pci);
chip->msi = 0;
if (azx_acquire_irq(chip, 1) < 0)
return -1;
goto again;
}

if (!chip->polling_mode) {
snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, "
"switching to polling mode...\n");
Expand Down Expand Up @@ -1364,6 +1378,20 @@ static int __devinit azx_init_stream(struct azx *chip)
return 0;
}

static int azx_acquire_irq(struct azx *chip, int do_disconnect)
{
if (request_irq(chip->pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED,
"HDA Intel", chip)) {
printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "
"disabling device\n", chip->pci->irq);
if (do_disconnect)
snd_card_disconnect(chip->card);
return -1;
}
chip->irq = chip->pci->irq;
return 0;
}


#ifdef CONFIG_PM
/*
Expand All @@ -1385,7 +1413,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
free_irq(chip->irq, chip);
chip->irq = -1;
}
if (!disable_msi)
if (chip->msi)
pci_disable_msi(chip->pci);
pci_disable_device(pci);
pci_save_state(pci);
Expand All @@ -1407,16 +1435,11 @@ static int azx_resume(struct pci_dev *pci)
return -EIO;
}
pci_set_master(pci);
if (!disable_msi)
pci_enable_msi(pci);
if (request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED,
"HDA Intel", chip)) {
printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "
"disabling device\n", pci->irq);
snd_card_disconnect(card);
if (chip->msi)
if (pci_enable_msi(pci) < 0)
chip->msi = 0;
if (azx_acquire_irq(chip, 1) < 0)
return -EIO;
}
chip->irq = pci->irq;
azx_init_chip(chip);
snd_hda_resume(chip->bus);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
Expand Down Expand Up @@ -1452,7 +1475,7 @@ static int azx_free(struct azx *chip)
synchronize_irq(chip->irq);
free_irq(chip->irq, (void*)chip);
}
if (!disable_msi)
if (chip->msi)
pci_disable_msi(chip->pci);
if (chip->remap_addr)
iounmap(chip->remap_addr);
Expand Down Expand Up @@ -1508,6 +1531,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
chip->pci = pci;
chip->irq = -1;
chip->driver_type = driver_type;
chip->msi = !disable_msi;

chip->position_fix = position_fix;
chip->single_cmd = single_cmd;
Expand Down Expand Up @@ -1537,16 +1561,14 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
goto errout;
}

if (!disable_msi)
pci_enable_msi(pci);
if (chip->msi)
if (pci_enable_msi(pci) < 0)
chip->msi = 0;

if (request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED,
"HDA Intel", (void*)chip)) {
snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
if (azx_acquire_irq(chip, 0) < 0) {
err = -EBUSY;
goto errout;
}
chip->irq = pci->irq;

pci_set_master(pci);
synchronize_irq(chip->irq);
Expand Down

0 comments on commit 68e7fff

Please sign in to comment.