diff options
| author | Wu Fengguang <fengguang.wu@intel.com> | 2009-08-01 06:45:16 -0400 | 
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2009-08-03 02:26:13 -0400 | 
| commit | deadff1665491afce124a8ff83f00f784161f660 (patch) | |
| tree | b0de54cef8d75623f5839651331b31018e1ea217 | |
| parent | ce577e8cf5ddb4216553c9d563a9835d6de70ffa (diff) | |
ALSA: hda: track CIRB/CORB command/response states for each codec
Recently we hit a bug in our dev board, whose HDMI codec#3 may emit
redundant/spurious responses, which were then taken as responses to
command for another onboard Realtek codec#2, and mess up both codecs.
Extend the azx_rb.cmds and azx_rb.res to array and track each codec's
commands/responses separately. This helps keep good codec safe from
broken ones.
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | sound/pci/hda/hda_codec.c | 2 | ||||
| -rw-r--r-- | sound/pci/hda/hda_codec.h | 2 | ||||
| -rw-r--r-- | sound/pci/hda/hda_intel.c | 76 | 
3 files changed, 56 insertions, 24 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 88480c0c58a0..c7df01b72cac 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c  | |||
| @@ -174,7 +174,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, | |||
| 174 | mutex_lock(&bus->cmd_mutex); | 174 | mutex_lock(&bus->cmd_mutex); | 
| 175 | err = bus->ops.command(bus, cmd); | 175 | err = bus->ops.command(bus, cmd); | 
| 176 | if (!err && res) | 176 | if (!err && res) | 
| 177 | *res = bus->ops.get_response(bus); | 177 | *res = bus->ops.get_response(bus, codec->addr); | 
| 178 | mutex_unlock(&bus->cmd_mutex); | 178 | mutex_unlock(&bus->cmd_mutex); | 
| 179 | snd_hda_power_down(codec); | 179 | snd_hda_power_down(codec); | 
| 180 | if (res && *res == -1 && bus->rirb_error) { | 180 | if (res && *res == -1 && bus->rirb_error) { | 
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index cad79efaabc9..1b75f28ed092 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h  | |||
| @@ -568,7 +568,7 @@ struct hda_bus_ops { | |||
| 568 | /* send a single command */ | 568 | /* send a single command */ | 
| 569 | int (*command)(struct hda_bus *bus, unsigned int cmd); | 569 | int (*command)(struct hda_bus *bus, unsigned int cmd); | 
| 570 | /* get a response from the last command */ | 570 | /* get a response from the last command */ | 
| 571 | unsigned int (*get_response)(struct hda_bus *bus); | 571 | unsigned int (*get_response)(struct hda_bus *bus, unsigned int addr); | 
| 572 | /* free the private data */ | 572 | /* free the private data */ | 
| 573 | void (*private_free)(struct hda_bus *); | 573 | void (*private_free)(struct hda_bus *); | 
| 574 | /* attach a PCM stream */ | 574 | /* attach a PCM stream */ | 
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 77c1b840ca8b..19e67a1b6026 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c  | |||
| @@ -253,7 +253,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
| 253 | 253 | ||
| 254 | /* STATESTS int mask: S3,SD2,SD1,SD0 */ | 254 | /* STATESTS int mask: S3,SD2,SD1,SD0 */ | 
| 255 | #define AZX_MAX_CODECS 4 | 255 | #define AZX_MAX_CODECS 4 | 
| 256 | #define STATESTS_INT_MASK 0x0f | 256 | #define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1) | 
| 257 | 257 | ||
| 258 | /* SD_CTL bits */ | 258 | /* SD_CTL bits */ | 
| 259 | #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ | 259 | #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ | 
| @@ -361,8 +361,8 @@ struct azx_rb { | |||
| 361 | dma_addr_t addr; /* physical address of CORB/RIRB buffer */ | 361 | dma_addr_t addr; /* physical address of CORB/RIRB buffer */ | 
| 362 | /* for RIRB */ | 362 | /* for RIRB */ | 
| 363 | unsigned short rp, wp; /* read/write pointers */ | 363 | unsigned short rp, wp; /* read/write pointers */ | 
| 364 | int cmds; /* number of pending requests */ | 364 | int cmds[AZX_MAX_CODECS]; /* number of pending requests */ | 
| 365 | u32 res; /* last read value */ | 365 | u32 res[AZX_MAX_CODECS]; /* last read value */ | 
| 366 | }; | 366 | }; | 
| 367 | 367 | ||
| 368 | struct azx { | 368 | struct azx { | 
| @@ -531,7 +531,8 @@ static void azx_init_cmd_io(struct azx *chip) | |||
| 531 | /* RIRB set up */ | 531 | /* RIRB set up */ | 
| 532 | chip->rirb.addr = chip->rb.addr + 2048; | 532 | chip->rirb.addr = chip->rb.addr + 2048; | 
| 533 | chip->rirb.buf = (u32 *)(chip->rb.area + 2048); | 533 | chip->rirb.buf = (u32 *)(chip->rb.area + 2048); | 
| 534 | chip->rirb.wp = chip->rirb.rp = chip->rirb.cmds = 0; | 534 | chip->rirb.wp = chip->rirb.rp = 0; | 
| 535 | memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds)); | ||
| 535 | azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); | 536 | azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); | 
| 536 | azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); | 537 | azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); | 
| 537 | 538 | ||
| @@ -552,10 +553,35 @@ static void azx_free_cmd_io(struct azx *chip) | |||
| 552 | azx_writeb(chip, CORBCTL, 0); | 553 | azx_writeb(chip, CORBCTL, 0); | 
| 553 | } | 554 | } | 
| 554 | 555 | ||
| 556 | static unsigned int azx_command_addr(u32 cmd) | ||
| 557 | { | ||
| 558 | unsigned int addr = cmd >> 28; | ||
| 559 | |||
| 560 | if (addr >= AZX_MAX_CODECS) { | ||
| 561 | snd_BUG(); | ||
| 562 | addr = 0; | ||
| 563 | } | ||
| 564 | |||
| 565 | return addr; | ||
| 566 | } | ||
| 567 | |||
| 568 | static unsigned int azx_response_addr(u32 res) | ||
| 569 | { | ||
| 570 | unsigned int addr = res & 0xf; | ||
| 571 | |||
| 572 | if (addr >= AZX_MAX_CODECS) { | ||
| 573 | snd_BUG(); | ||
| 574 | addr = 0; | ||
| 575 | } | ||
| 576 | |||
| 577 | return addr; | ||
| 578 | } | ||
| 579 | |||
| 555 | /* send a command */ | 580 | /* send a command */ | 
| 556 | static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) | 581 | static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) | 
| 557 | { | 582 | { | 
| 558 | struct azx *chip = bus->private_data; | 583 | struct azx *chip = bus->private_data; | 
| 584 | unsigned int addr = azx_command_addr(val); | ||
| 559 | unsigned int wp; | 585 | unsigned int wp; | 
| 560 | 586 | ||
| 561 | /* add command to corb */ | 587 | /* add command to corb */ | 
| @@ -564,7 +590,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) | |||
| 564 | wp %= ICH6_MAX_CORB_ENTRIES; | 590 | wp %= ICH6_MAX_CORB_ENTRIES; | 
| 565 | 591 | ||
| 566 | spin_lock_irq(&chip->reg_lock); | 592 | spin_lock_irq(&chip->reg_lock); | 
| 567 | chip->rirb.cmds++; | 593 | chip->rirb.cmds[addr]++; | 
| 568 | chip->corb.buf[wp] = cpu_to_le32(val); | 594 | chip->corb.buf[wp] = cpu_to_le32(val); | 
| 569 | azx_writel(chip, CORBWP, wp); | 595 | azx_writel(chip, CORBWP, wp); | 
| 570 | spin_unlock_irq(&chip->reg_lock); | 596 | spin_unlock_irq(&chip->reg_lock); | 
| @@ -578,13 +604,14 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) | |||
| 578 | static void azx_update_rirb(struct azx *chip) | 604 | static void azx_update_rirb(struct azx *chip) | 
| 579 | { | 605 | { | 
| 580 | unsigned int rp, wp; | 606 | unsigned int rp, wp; | 
| 607 | unsigned int addr; | ||
| 581 | u32 res, res_ex; | 608 | u32 res, res_ex; | 
| 582 | 609 | ||
| 583 | wp = azx_readb(chip, RIRBWP); | 610 | wp = azx_readb(chip, RIRBWP); | 
| 584 | if (wp == chip->rirb.wp) | 611 | if (wp == chip->rirb.wp) | 
| 585 | return; | 612 | return; | 
| 586 | chip->rirb.wp = wp; | 613 | chip->rirb.wp = wp; | 
| 587 | 614 | ||
| 588 | while (chip->rirb.rp != wp) { | 615 | while (chip->rirb.rp != wp) { | 
| 589 | chip->rirb.rp++; | 616 | chip->rirb.rp++; | 
| 590 | chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES; | 617 | chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES; | 
| @@ -592,18 +619,20 @@ static void azx_update_rirb(struct azx *chip) | |||
| 592 | rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ | 619 | rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ | 
| 593 | res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); | 620 | res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); | 
| 594 | res = le32_to_cpu(chip->rirb.buf[rp]); | 621 | res = le32_to_cpu(chip->rirb.buf[rp]); | 
| 622 | addr = azx_response_addr(res_ex); | ||
| 595 | if (res_ex & ICH6_RIRB_EX_UNSOL_EV) | 623 | if (res_ex & ICH6_RIRB_EX_UNSOL_EV) | 
| 596 | snd_hda_queue_unsol_event(chip->bus, res, res_ex); | 624 | snd_hda_queue_unsol_event(chip->bus, res, res_ex); | 
| 597 | else if (chip->rirb.cmds) { | 625 | else if (chip->rirb.cmds[addr]) { | 
| 598 | chip->rirb.res = res; | 626 | chip->rirb.res[addr] = res; | 
| 599 | smp_wmb(); | 627 | smp_wmb(); | 
| 600 | chip->rirb.cmds--; | 628 | chip->rirb.cmds[addr]--; | 
| 601 | } | 629 | } | 
| 602 | } | 630 | } | 
| 603 | } | 631 | } | 
| 604 | 632 | ||
| 605 | /* receive a response */ | 633 | /* receive a response */ | 
| 606 | static unsigned int azx_rirb_get_response(struct hda_bus *bus) | 634 | static unsigned int azx_rirb_get_response(struct hda_bus *bus, | 
| 635 | unsigned int addr) | ||
| 607 | { | 636 | { | 
| 608 | struct azx *chip = bus->private_data; | 637 | struct azx *chip = bus->private_data; | 
| 609 | unsigned long timeout; | 638 | unsigned long timeout; | 
| @@ -616,10 +645,10 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) | |||
| 616 | azx_update_rirb(chip); | 645 | azx_update_rirb(chip); | 
| 617 | spin_unlock_irq(&chip->reg_lock); | 646 | spin_unlock_irq(&chip->reg_lock); | 
| 618 | } | 647 | } | 
| 619 | if (!chip->rirb.cmds) { | 648 | if (!chip->rirb.cmds[addr]) { | 
| 620 | smp_rmb(); | 649 | smp_rmb(); | 
| 621 | bus->rirb_error = 0; | 650 | bus->rirb_error = 0; | 
| 622 | return chip->rirb.res; /* the last value */ | 651 | return chip->rirb.res[addr]; /* the last value */ | 
| 623 | } | 652 | } | 
| 624 | if (time_after(jiffies, timeout)) | 653 | if (time_after(jiffies, timeout)) | 
| 625 | break; | 654 | break; | 
| @@ -692,7 +721,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) | |||
| 692 | */ | 721 | */ | 
| 693 | 722 | ||
| 694 | /* receive a response */ | 723 | /* receive a response */ | 
| 695 | static int azx_single_wait_for_response(struct azx *chip) | 724 | static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) | 
| 696 | { | 725 | { | 
| 697 | int timeout = 50; | 726 | int timeout = 50; | 
| 698 | 727 | ||
| @@ -700,7 +729,7 @@ static int azx_single_wait_for_response(struct azx *chip) | |||
| 700 | /* check IRV busy bit */ | 729 | /* check IRV busy bit */ | 
| 701 | if (azx_readw(chip, IRS) & ICH6_IRS_VALID) { | 730 | if (azx_readw(chip, IRS) & ICH6_IRS_VALID) { | 
| 702 | /* reuse rirb.res as the response return value */ | 731 | /* reuse rirb.res as the response return value */ | 
| 703 | chip->rirb.res = azx_readl(chip, IR); | 732 | chip->rirb.res[addr] = azx_readl(chip, IR); | 
| 704 | return 0; | 733 | return 0; | 
| 705 | } | 734 | } | 
| 706 | udelay(1); | 735 | udelay(1); | 
| @@ -708,7 +737,7 @@ static int azx_single_wait_for_response(struct azx *chip) | |||
| 708 | if (printk_ratelimit()) | 737 | if (printk_ratelimit()) | 
| 709 | snd_printd(SFX "get_response timeout: IRS=0x%x\n", | 738 | snd_printd(SFX "get_response timeout: IRS=0x%x\n", | 
| 710 | azx_readw(chip, IRS)); | 739 | azx_readw(chip, IRS)); | 
| 711 | chip->rirb.res = -1; | 740 | chip->rirb.res[addr] = -1; | 
| 712 | return -EIO; | 741 | return -EIO; | 
| 713 | } | 742 | } | 
| 714 | 743 | ||
| @@ -716,6 +745,7 @@ static int azx_single_wait_for_response(struct azx *chip) | |||
| 716 | static int azx_single_send_cmd(struct hda_bus *bus, u32 val) | 745 | static int azx_single_send_cmd(struct hda_bus *bus, u32 val) | 
| 717 | { | 746 | { | 
| 718 | struct azx *chip = bus->private_data; | 747 | struct azx *chip = bus->private_data; | 
| 748 | unsigned int addr = azx_command_addr(val); | ||
| 719 | int timeout = 50; | 749 | int timeout = 50; | 
| 720 | 750 | ||
| 721 | bus->rirb_error = 0; | 751 | bus->rirb_error = 0; | 
| @@ -728,7 +758,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) | |||
| 728 | azx_writel(chip, IC, val); | 758 | azx_writel(chip, IC, val); | 
| 729 | azx_writew(chip, IRS, azx_readw(chip, IRS) | | 759 | azx_writew(chip, IRS, azx_readw(chip, IRS) | | 
| 730 | ICH6_IRS_BUSY); | 760 | ICH6_IRS_BUSY); | 
| 731 | return azx_single_wait_for_response(chip); | 761 | return azx_single_wait_for_response(chip, addr); | 
| 732 | } | 762 | } | 
| 733 | udelay(1); | 763 | udelay(1); | 
| 734 | } | 764 | } | 
| @@ -739,10 +769,11 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) | |||
| 739 | } | 769 | } | 
| 740 | 770 | ||
| 741 | /* receive a response */ | 771 | /* receive a response */ | 
| 742 | static unsigned int azx_single_get_response(struct hda_bus *bus) | 772 | static unsigned int azx_single_get_response(struct hda_bus *bus, | 
| 773 | unsigned int addr) | ||
| 743 | { | 774 | { | 
| 744 | struct azx *chip = bus->private_data; | 775 | struct azx *chip = bus->private_data; | 
| 745 | return chip->rirb.res; | 776 | return chip->rirb.res[addr]; | 
| 746 | } | 777 | } | 
| 747 | 778 | ||
| 748 | /* | 779 | /* | 
| @@ -765,13 +796,14 @@ static int azx_send_cmd(struct hda_bus *bus, unsigned int val) | |||
| 765 | } | 796 | } | 
| 766 | 797 | ||
| 767 | /* get a response */ | 798 | /* get a response */ | 
| 768 | static unsigned int azx_get_response(struct hda_bus *bus) | 799 | static unsigned int azx_get_response(struct hda_bus *bus, | 
| 800 | unsigned int addr) | ||
| 769 | { | 801 | { | 
| 770 | struct azx *chip = bus->private_data; | 802 | struct azx *chip = bus->private_data; | 
| 771 | if (chip->single_cmd) | 803 | if (chip->single_cmd) | 
| 772 | return azx_single_get_response(bus); | 804 | return azx_single_get_response(bus, addr); | 
| 773 | else | 805 | else | 
| 774 | return azx_rirb_get_response(bus); | 806 | return azx_rirb_get_response(bus, addr); | 
| 775 | } | 807 | } | 
| 776 | 808 | ||
| 777 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 809 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 
| @@ -1245,7 +1277,7 @@ static int probe_codec(struct azx *chip, int addr) | |||
| 1245 | 1277 | ||
| 1246 | chip->probing = 1; | 1278 | chip->probing = 1; | 
| 1247 | azx_send_cmd(chip->bus, cmd); | 1279 | azx_send_cmd(chip->bus, cmd); | 
| 1248 | res = azx_get_response(chip->bus); | 1280 | res = azx_get_response(chip->bus, addr); | 
| 1249 | chip->probing = 0; | 1281 | chip->probing = 0; | 
| 1250 | if (res == -1) | 1282 | if (res == -1) | 
| 1251 | return -EIO; | 1283 | return -EIO; | 
