aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2006-10-23 13:40:59 +0200
committerJaroslav Kysela <perex@suse.cz>2006-10-23 14:10:34 +0200
commit68e7fffc0f3e95063ba5bd94ee6f9b8927247297 (patch)
tree4b29ce42e3884db52e56e4e4cd7ca162954cb328
parenta5c81b648476f5b0594daeefb38bb98409da5340 (diff)
[ALSA] hda-intel - Add check of MSI availabity
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>
-rw-r--r--sound/pci/hda/hda_intel.c56
1 files changed, 39 insertions, 17 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c1771929466..0e292dc4fd8 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -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 */
@@ -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
@@ -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");
@@ -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
/*
@@ -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);
@@ -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);
@@ -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);
@@ -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;
@@ -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);