diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/hda_intel.c | 124 |
1 files changed, 106 insertions, 18 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index b3a618eb42cd..6ba7ac01d9f6 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -285,6 +285,7 @@ struct azx_dev { | |||
285 | u32 *posbuf; /* position buffer pointer */ | 285 | u32 *posbuf; /* position buffer pointer */ |
286 | 286 | ||
287 | unsigned int bufsize; /* size of the play buffer in bytes */ | 287 | unsigned int bufsize; /* size of the play buffer in bytes */ |
288 | unsigned int period_bytes; /* size of the period in bytes */ | ||
288 | unsigned int frags; /* number for period in the play buffer */ | 289 | unsigned int frags; /* number for period in the play buffer */ |
289 | unsigned int fifo_size; /* FIFO size */ | 290 | unsigned int fifo_size; /* FIFO size */ |
290 | 291 | ||
@@ -301,11 +302,10 @@ struct azx_dev { | |||
301 | */ | 302 | */ |
302 | unsigned char stream_tag; /* assigned stream */ | 303 | unsigned char stream_tag; /* assigned stream */ |
303 | unsigned char index; /* stream index */ | 304 | unsigned char index; /* stream index */ |
304 | /* for sanity check of position buffer */ | ||
305 | unsigned int period_intr; | ||
306 | 305 | ||
307 | unsigned int opened :1; | 306 | unsigned int opened :1; |
308 | unsigned int running :1; | 307 | unsigned int running :1; |
308 | unsigned int irq_pending: 1; | ||
309 | }; | 309 | }; |
310 | 310 | ||
311 | /* CORB/RIRB */ | 311 | /* CORB/RIRB */ |
@@ -369,6 +369,9 @@ struct azx { | |||
369 | 369 | ||
370 | /* for debugging */ | 370 | /* for debugging */ |
371 | unsigned int last_cmd; /* last issued command (to sync) */ | 371 | unsigned int last_cmd; /* last issued command (to sync) */ |
372 | |||
373 | /* for pending irqs */ | ||
374 | struct work_struct irq_pending_work; | ||
372 | }; | 375 | }; |
373 | 376 | ||
374 | /* driver types */ | 377 | /* driver types */ |
@@ -908,6 +911,8 @@ static void azx_init_pci(struct azx *chip) | |||
908 | } | 911 | } |
909 | 912 | ||
910 | 913 | ||
914 | static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev); | ||
915 | |||
911 | /* | 916 | /* |
912 | * interrupt handler | 917 | * interrupt handler |
913 | */ | 918 | */ |
@@ -930,11 +935,18 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) | |||
930 | azx_dev = &chip->azx_dev[i]; | 935 | azx_dev = &chip->azx_dev[i]; |
931 | if (status & azx_dev->sd_int_sta_mask) { | 936 | if (status & azx_dev->sd_int_sta_mask) { |
932 | azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); | 937 | azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); |
933 | if (azx_dev->substream && azx_dev->running) { | 938 | if (!azx_dev->substream || !azx_dev->running) |
934 | azx_dev->period_intr++; | 939 | continue; |
940 | /* check whether this IRQ is really acceptable */ | ||
941 | if (azx_position_ok(chip, azx_dev)) { | ||
942 | azx_dev->irq_pending = 0; | ||
935 | spin_unlock(&chip->reg_lock); | 943 | spin_unlock(&chip->reg_lock); |
936 | snd_pcm_period_elapsed(azx_dev->substream); | 944 | snd_pcm_period_elapsed(azx_dev->substream); |
937 | spin_lock(&chip->reg_lock); | 945 | spin_lock(&chip->reg_lock); |
946 | } else { | ||
947 | /* bogus IRQ, process it later */ | ||
948 | azx_dev->irq_pending = 1; | ||
949 | schedule_work(&chip->irq_pending_work); | ||
938 | } | 950 | } |
939 | } | 951 | } |
940 | } | 952 | } |
@@ -973,6 +985,7 @@ static int azx_setup_periods(struct snd_pcm_substream *substream, | |||
973 | azx_sd_writel(azx_dev, SD_BDLPU, 0); | 985 | azx_sd_writel(azx_dev, SD_BDLPU, 0); |
974 | 986 | ||
975 | period_bytes = snd_pcm_lib_period_bytes(substream); | 987 | period_bytes = snd_pcm_lib_period_bytes(substream); |
988 | azx_dev->period_bytes = period_bytes; | ||
976 | periods = azx_dev->bufsize / period_bytes; | 989 | periods = azx_dev->bufsize / period_bytes; |
977 | 990 | ||
978 | /* program the initial BDL entries */ | 991 | /* program the initial BDL entries */ |
@@ -1421,27 +1434,16 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1421 | return 0; | 1434 | return 0; |
1422 | } | 1435 | } |
1423 | 1436 | ||
1424 | static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) | 1437 | static unsigned int azx_get_position(struct azx *chip, |
1438 | struct azx_dev *azx_dev) | ||
1425 | { | 1439 | { |
1426 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
1427 | struct azx *chip = apcm->chip; | ||
1428 | struct azx_dev *azx_dev = get_azx_dev(substream); | ||
1429 | unsigned int pos; | 1440 | unsigned int pos; |
1430 | 1441 | ||
1431 | if (chip->position_fix == POS_FIX_POSBUF || | 1442 | if (chip->position_fix == POS_FIX_POSBUF || |
1432 | chip->position_fix == POS_FIX_AUTO) { | 1443 | chip->position_fix == POS_FIX_AUTO) { |
1433 | /* use the position buffer */ | 1444 | /* use the position buffer */ |
1434 | pos = le32_to_cpu(*azx_dev->posbuf); | 1445 | pos = le32_to_cpu(*azx_dev->posbuf); |
1435 | if (chip->position_fix == POS_FIX_AUTO && | ||
1436 | azx_dev->period_intr == 1 && !pos) { | ||
1437 | printk(KERN_WARNING | ||
1438 | "hda-intel: Invalid position buffer, " | ||
1439 | "using LPIB read method instead.\n"); | ||
1440 | chip->position_fix = POS_FIX_NONE; | ||
1441 | goto read_lpib; | ||
1442 | } | ||
1443 | } else { | 1446 | } else { |
1444 | read_lpib: | ||
1445 | /* read LPIB */ | 1447 | /* read LPIB */ |
1446 | pos = azx_sd_readl(azx_dev, SD_LPIB); | 1448 | pos = azx_sd_readl(azx_dev, SD_LPIB); |
1447 | if (chip->position_fix == POS_FIX_FIFO) | 1449 | if (chip->position_fix == POS_FIX_FIFO) |
@@ -1449,7 +1451,90 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) | |||
1449 | } | 1451 | } |
1450 | if (pos >= azx_dev->bufsize) | 1452 | if (pos >= azx_dev->bufsize) |
1451 | pos = 0; | 1453 | pos = 0; |
1452 | return bytes_to_frames(substream->runtime, pos); | 1454 | return pos; |
1455 | } | ||
1456 | |||
1457 | static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) | ||
1458 | { | ||
1459 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
1460 | struct azx *chip = apcm->chip; | ||
1461 | struct azx_dev *azx_dev = get_azx_dev(substream); | ||
1462 | return bytes_to_frames(substream->runtime, | ||
1463 | azx_get_position(chip, azx_dev)); | ||
1464 | } | ||
1465 | |||
1466 | /* | ||
1467 | * Check whether the current DMA position is acceptable for updating | ||
1468 | * periods. Returns non-zero if it's OK. | ||
1469 | * | ||
1470 | * Many HD-audio controllers appear pretty inaccurate about | ||
1471 | * the update-IRQ timing. The IRQ is issued before actually the | ||
1472 | * data is processed. So, we need to process it afterwords in a | ||
1473 | * workqueue. | ||
1474 | */ | ||
1475 | static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) | ||
1476 | { | ||
1477 | unsigned int pos; | ||
1478 | |||
1479 | pos = azx_get_position(chip, azx_dev); | ||
1480 | if (chip->position_fix == POS_FIX_AUTO) { | ||
1481 | if (!pos) { | ||
1482 | printk(KERN_WARNING | ||
1483 | "hda-intel: Invalid position buffer, " | ||
1484 | "using LPIB read method instead.\n"); | ||
1485 | chip->position_fix = POS_FIX_NONE; | ||
1486 | pos = azx_get_position(chip, azx_dev); | ||
1487 | } else | ||
1488 | chip->position_fix = POS_FIX_POSBUF; | ||
1489 | } | ||
1490 | |||
1491 | if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) | ||
1492 | return 0; /* NG - it's below the period boundary */ | ||
1493 | return 1; /* OK, it's fine */ | ||
1494 | } | ||
1495 | |||
1496 | /* | ||
1497 | * The work for pending PCM period updates. | ||
1498 | */ | ||
1499 | static void azx_irq_pending_work(struct work_struct *work) | ||
1500 | { | ||
1501 | struct azx *chip = container_of(work, struct azx, irq_pending_work); | ||
1502 | int i, pending; | ||
1503 | |||
1504 | for (;;) { | ||
1505 | pending = 0; | ||
1506 | spin_lock_irq(&chip->reg_lock); | ||
1507 | for (i = 0; i < chip->num_streams; i++) { | ||
1508 | struct azx_dev *azx_dev = &chip->azx_dev[i]; | ||
1509 | if (!azx_dev->irq_pending || | ||
1510 | !azx_dev->substream || | ||
1511 | !azx_dev->running) | ||
1512 | continue; | ||
1513 | if (azx_position_ok(chip, azx_dev)) { | ||
1514 | azx_dev->irq_pending = 0; | ||
1515 | spin_unlock(&chip->reg_lock); | ||
1516 | snd_pcm_period_elapsed(azx_dev->substream); | ||
1517 | spin_lock(&chip->reg_lock); | ||
1518 | } else | ||
1519 | pending++; | ||
1520 | } | ||
1521 | spin_unlock_irq(&chip->reg_lock); | ||
1522 | if (!pending) | ||
1523 | return; | ||
1524 | cond_resched(); | ||
1525 | } | ||
1526 | } | ||
1527 | |||
1528 | /* clear irq_pending flags and assure no on-going workq */ | ||
1529 | static void azx_clear_irq_pending(struct azx *chip) | ||
1530 | { | ||
1531 | int i; | ||
1532 | |||
1533 | spin_lock_irq(&chip->reg_lock); | ||
1534 | for (i = 0; i < chip->num_streams; i++) | ||
1535 | chip->azx_dev[i].irq_pending = 0; | ||
1536 | spin_unlock_irq(&chip->reg_lock); | ||
1537 | flush_scheduled_work(); | ||
1453 | } | 1538 | } |
1454 | 1539 | ||
1455 | static struct snd_pcm_ops azx_pcm_ops = { | 1540 | static struct snd_pcm_ops azx_pcm_ops = { |
@@ -1676,6 +1761,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) | |||
1676 | int i; | 1761 | int i; |
1677 | 1762 | ||
1678 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 1763 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
1764 | azx_clear_irq_pending(chip); | ||
1679 | for (i = 0; i < AZX_MAX_PCMS; i++) | 1765 | for (i = 0; i < AZX_MAX_PCMS; i++) |
1680 | snd_pcm_suspend_all(chip->pcm[i]); | 1766 | snd_pcm_suspend_all(chip->pcm[i]); |
1681 | if (chip->initialized) | 1767 | if (chip->initialized) |
@@ -1732,6 +1818,7 @@ static int azx_free(struct azx *chip) | |||
1732 | int i; | 1818 | int i; |
1733 | 1819 | ||
1734 | if (chip->initialized) { | 1820 | if (chip->initialized) { |
1821 | azx_clear_irq_pending(chip); | ||
1735 | for (i = 0; i < chip->num_streams; i++) | 1822 | for (i = 0; i < chip->num_streams; i++) |
1736 | azx_stream_stop(chip, &chip->azx_dev[i]); | 1823 | azx_stream_stop(chip, &chip->azx_dev[i]); |
1737 | azx_stop_chip(chip); | 1824 | azx_stop_chip(chip); |
@@ -1857,6 +1944,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1857 | chip->irq = -1; | 1944 | chip->irq = -1; |
1858 | chip->driver_type = driver_type; | 1945 | chip->driver_type = driver_type; |
1859 | chip->msi = enable_msi; | 1946 | chip->msi = enable_msi; |
1947 | INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); | ||
1860 | 1948 | ||
1861 | chip->position_fix = check_position_fix(chip, position_fix[dev]); | 1949 | chip->position_fix = check_position_fix(chip, position_fix[dev]); |
1862 | check_probe_mask(chip, dev); | 1950 | check_probe_mask(chip, dev); |