* [RFC][PATCH] hda: track CIRB/CORB command/response states for each codec
@ 2009-08-01 10:45 Wu Fengguang
2009-08-01 10:46 ` [PATCH] hda: take cmd_mutex in probe_codec() Wu Fengguang
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Wu Fengguang @ 2009-08-01 10:45 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel, Jaroslav Kysela
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>
---
sound/pci/hda/hda_codec.c | 2
sound/pci/hda/hda_codec.h | 2
sound/pci/hda/hda_intel.c | 76 +++++++++++++++++++++++++-----------
3 files changed, 56 insertions(+), 24 deletions(-)
--- sound-2.6.orig/sound/pci/hda/hda_codec.c
+++ sound-2.6/sound/pci/hda/hda_codec.c
@@ -185,7 +185,7 @@ static int codec_exec_verb(struct hda_co
mutex_lock(&bus->cmd_mutex);
err = bus->ops.command(bus, cmd);
if (!err && res)
- *res = bus->ops.get_response(bus);
+ *res = bus->ops.get_response(bus, codec->addr);
mutex_unlock(&bus->cmd_mutex);
snd_hda_power_down(codec);
if (res && *res == -1 && bus->rirb_error) {
--- sound-2.6.orig/sound/pci/hda/hda_codec.h
+++ sound-2.6/sound/pci/hda/hda_codec.h
@@ -568,7 +568,7 @@ struct hda_bus_ops {
/* send a single command */
int (*command)(struct hda_bus *bus, unsigned int cmd);
/* get a response from the last command */
- unsigned int (*get_response)(struct hda_bus *bus);
+ unsigned int (*get_response)(struct hda_bus *bus, unsigned int addr);
/* free the private data */
void (*private_free)(struct hda_bus *);
/* attach a PCM stream */
--- sound-2.6.orig/sound/pci/hda/hda_intel.c
+++ sound-2.6/sound/pci/hda/hda_intel.c
@@ -260,7 +260,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO
/* STATESTS int mask: S3,SD2,SD1,SD0 */
#define AZX_MAX_CODECS 4
-#define STATESTS_INT_MASK 0x0f
+#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1)
/* SD_CTL bits */
#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
@@ -368,8 +368,8 @@ struct azx_rb {
dma_addr_t addr; /* physical address of CORB/RIRB buffer */
/* for RIRB */
unsigned short rp, wp; /* read/write pointers */
- int cmds; /* number of pending requests */
- u32 res; /* last read value */
+ int cmds[AZX_MAX_CODECS]; /* number of pending requests */
+ u32 res[AZX_MAX_CODECS]; /* last read value */
};
struct azx {
@@ -538,7 +538,8 @@ static void azx_init_cmd_io(struct azx *
/* RIRB set up */
chip->rirb.addr = chip->rb.addr + 2048;
chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
- chip->rirb.wp = chip->rirb.rp = chip->rirb.cmds = 0;
+ chip->rirb.wp = chip->rirb.rp = 0;
+ memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds));
azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
@@ -559,10 +560,35 @@ static void azx_free_cmd_io(struct azx *
azx_writeb(chip, CORBCTL, 0);
}
+static unsigned int azx_command_addr(u32 cmd)
+{
+ unsigned int addr = cmd >> 28;
+
+ if (addr >= AZX_MAX_CODECS) {
+ snd_BUG();
+ addr = 0;
+ }
+
+ return addr;
+}
+
+static unsigned int azx_response_addr(u32 res)
+{
+ unsigned int addr = res & 0xf;
+
+ if (addr >= AZX_MAX_CODECS) {
+ snd_BUG();
+ addr = 0;
+ }
+
+ return addr;
+}
+
/* send a command */
static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
{
struct azx *chip = bus->private_data;
+ unsigned int addr = azx_command_addr(val);
unsigned int wp;
/* add command to corb */
@@ -571,7 +597,7 @@ static int azx_corb_send_cmd(struct hda_
wp %= ICH6_MAX_CORB_ENTRIES;
spin_lock_irq(&chip->reg_lock);
- chip->rirb.cmds++;
+ chip->rirb.cmds[addr]++;
chip->corb.buf[wp] = cpu_to_le32(val);
azx_writel(chip, CORBWP, wp);
spin_unlock_irq(&chip->reg_lock);
@@ -585,13 +611,14 @@ static int azx_corb_send_cmd(struct hda_
static void azx_update_rirb(struct azx *chip)
{
unsigned int rp, wp;
+ unsigned int addr;
u32 res, res_ex;
wp = azx_readb(chip, RIRBWP);
if (wp == chip->rirb.wp)
return;
chip->rirb.wp = wp;
-
+
while (chip->rirb.rp != wp) {
chip->rirb.rp++;
chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES;
@@ -599,18 +626,20 @@ static void azx_update_rirb(struct azx *
rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */
res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
res = le32_to_cpu(chip->rirb.buf[rp]);
+ addr = azx_response_addr(res_ex);
if (res_ex & ICH6_RIRB_EX_UNSOL_EV)
snd_hda_queue_unsol_event(chip->bus, res, res_ex);
- else if (chip->rirb.cmds) {
- chip->rirb.res = res;
+ else if (chip->rirb.cmds[addr]) {
+ chip->rirb.res[addr] = res;
smp_wmb();
- chip->rirb.cmds--;
+ chip->rirb.cmds[addr]--;
}
}
}
/* receive a response */
-static unsigned int azx_rirb_get_response(struct hda_bus *bus)
+static unsigned int azx_rirb_get_response(struct hda_bus *bus,
+ unsigned int addr)
{
struct azx *chip = bus->private_data;
unsigned long timeout;
@@ -623,10 +652,10 @@ static unsigned int azx_rirb_get_respons
azx_update_rirb(chip);
spin_unlock_irq(&chip->reg_lock);
}
- if (!chip->rirb.cmds) {
+ if (!chip->rirb.cmds[addr]) {
smp_rmb();
bus->rirb_error = 0;
- return chip->rirb.res; /* the last value */
+ return chip->rirb.res[addr]; /* the last value */
}
if (time_after(jiffies, timeout))
break;
@@ -699,7 +728,7 @@ static unsigned int azx_rirb_get_respons
*/
/* receive a response */
-static int azx_single_wait_for_response(struct azx *chip)
+static int azx_single_wait_for_response(struct azx *chip, unsigned int addr)
{
int timeout = 50;
@@ -707,7 +736,7 @@ static int azx_single_wait_for_response(
/* check IRV busy bit */
if (azx_readw(chip, IRS) & ICH6_IRS_VALID) {
/* reuse rirb.res as the response return value */
- chip->rirb.res = azx_readl(chip, IR);
+ chip->rirb.res[addr] = azx_readl(chip, IR);
return 0;
}
udelay(1);
@@ -715,7 +744,7 @@ static int azx_single_wait_for_response(
if (printk_ratelimit())
snd_printd(SFX "get_response timeout: IRS=0x%x\n",
azx_readw(chip, IRS));
- chip->rirb.res = -1;
+ chip->rirb.res[addr] = -1;
return -EIO;
}
@@ -723,6 +752,7 @@ static int azx_single_wait_for_response(
static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
{
struct azx *chip = bus->private_data;
+ unsigned int addr = azx_command_addr(val);
int timeout = 50;
bus->rirb_error = 0;
@@ -735,7 +765,7 @@ static int azx_single_send_cmd(struct hd
azx_writel(chip, IC, val);
azx_writew(chip, IRS, azx_readw(chip, IRS) |
ICH6_IRS_BUSY);
- return azx_single_wait_for_response(chip);
+ return azx_single_wait_for_response(chip, addr);
}
udelay(1);
}
@@ -746,10 +776,11 @@ static int azx_single_send_cmd(struct hd
}
/* receive a response */
-static unsigned int azx_single_get_response(struct hda_bus *bus)
+static unsigned int azx_single_get_response(struct hda_bus *bus,
+ unsigned int addr)
{
struct azx *chip = bus->private_data;
- return chip->rirb.res;
+ return chip->rirb.res[addr];
}
/*
@@ -772,13 +803,14 @@ static int azx_send_cmd(struct hda_bus *
}
/* get a response */
-static unsigned int azx_get_response(struct hda_bus *bus)
+static unsigned int azx_get_response(struct hda_bus *bus,
+ unsigned int addr)
{
struct azx *chip = bus->private_data;
if (chip->single_cmd)
- return azx_single_get_response(bus);
+ return azx_single_get_response(bus, addr);
else
- return azx_rirb_get_response(bus);
+ return azx_rirb_get_response(bus, addr);
}
#ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -1252,7 +1284,7 @@ static int probe_codec(struct azx *chip,
chip->probing = 1;
azx_send_cmd(chip->bus, cmd);
- res = azx_get_response(chip->bus);
+ res = azx_get_response(chip->bus, addr);
chip->probing = 0;
if (res == -1)
return -EIO;
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH] hda: take cmd_mutex in probe_codec()
2009-08-01 10:45 [RFC][PATCH] hda: track CIRB/CORB command/response states for each codec Wu Fengguang
@ 2009-08-01 10:46 ` Wu Fengguang
2009-08-01 10:47 ` [PATCH] hda: take reg_lock in azx_init_cmd_io/azx_free_cmd_io Wu Fengguang
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Wu Fengguang @ 2009-08-01 10:46 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel, Jaroslav Kysela
Now that each codec will have its own module, it is possible
for the user to load one codec while another one is running.
So cmd_mutex would be a safe addition to probe_codec().
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
---
sound/pci/hda/hda_intel.c | 2 ++
1 file changed, 2 insertions(+)
--- sound-2.6.orig/sound/pci/hda/hda_intel.c
+++ sound-2.6/sound/pci/hda/hda_intel.c
@@ -1282,10 +1282,12 @@ static int probe_codec(struct azx *chip,
(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
unsigned int res;
+ mutex_lock(&chip->bus->cmd_mutex);
chip->probing = 1;
azx_send_cmd(chip->bus, cmd);
res = azx_get_response(chip->bus, addr);
chip->probing = 0;
+ mutex_unlock(&chip->bus->cmd_mutex);
if (res == -1)
return -EIO;
snd_printdd(SFX "codec #%d probed OK\n", addr);
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH] hda: take reg_lock in azx_init_cmd_io/azx_free_cmd_io
2009-08-01 10:45 [RFC][PATCH] hda: track CIRB/CORB command/response states for each codec Wu Fengguang
2009-08-01 10:46 ` [PATCH] hda: take cmd_mutex in probe_codec() Wu Fengguang
@ 2009-08-01 10:47 ` Wu Fengguang
2009-08-01 10:48 ` [PATCH] hda: read CORBWP inside reg_lock Wu Fengguang
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Wu Fengguang @ 2009-08-01 10:47 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel, Jaroslav Kysela
Just for safety. azx_init_cmd_io() and azx_free_cmd_io() may be
called when switching to single command mode.
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
---
sound/pci/hda/hda_intel.c | 4 ++++
1 file changed, 4 insertions(+)
--- sound-2.6.orig/sound/pci/hda/hda_intel.c
+++ sound-2.6/sound/pci/hda/hda_intel.c
@@ -520,6 +520,7 @@ static int azx_alloc_cmd_io(struct azx *
static void azx_init_cmd_io(struct azx *chip)
{
+ spin_lock_irq(&chip->reg_lock);
/* CORB set up */
chip->corb.addr = chip->rb.addr;
chip->corb.buf = (u32 *)chip->rb.area;
@@ -551,13 +552,16 @@ static void azx_init_cmd_io(struct azx *
azx_writew(chip, RINTCNT, 1);
/* enable rirb dma and response irq */
azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
+ spin_unlock_irq(&chip->reg_lock);
}
static void azx_free_cmd_io(struct azx *chip)
{
+ spin_lock_irq(&chip->reg_lock);
/* disable ringbuffer DMAs */
azx_writeb(chip, RIRBCTL, 0);
azx_writeb(chip, CORBCTL, 0);
+ spin_unlock_irq(&chip->reg_lock);
}
static unsigned int azx_command_addr(u32 cmd)
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH] hda: read CORBWP inside reg_lock
2009-08-01 10:45 [RFC][PATCH] hda: track CIRB/CORB command/response states for each codec Wu Fengguang
2009-08-01 10:46 ` [PATCH] hda: take cmd_mutex in probe_codec() Wu Fengguang
2009-08-01 10:47 ` [PATCH] hda: take reg_lock in azx_init_cmd_io/azx_free_cmd_io Wu Fengguang
@ 2009-08-01 10:48 ` Wu Fengguang
2009-08-01 11:17 ` [PATCH] hda: remember last command for each codec Wu Fengguang
2009-08-03 6:50 ` [RFC][PATCH] hda: track CIRB/CORB command/response states for each codec Takashi Iwai
4 siblings, 0 replies; 7+ messages in thread
From: Wu Fengguang @ 2009-08-01 10:48 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel, Jaroslav Kysela
This converts the last CORBWP access outside of reg_lock.
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
---
sound/pci/hda/hda_intel.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- sound-2.6.orig/sound/pci/hda/hda_intel.c
+++ sound-2.6/sound/pci/hda/hda_intel.c
@@ -595,15 +595,17 @@ static int azx_corb_send_cmd(struct hda_
unsigned int addr = azx_command_addr(val);
unsigned int wp;
+ spin_lock_irq(&chip->reg_lock);
+
/* add command to corb */
wp = azx_readb(chip, CORBWP);
wp++;
wp %= ICH6_MAX_CORB_ENTRIES;
- spin_lock_irq(&chip->reg_lock);
chip->rirb.cmds[addr]++;
chip->corb.buf[wp] = cpu_to_le32(val);
azx_writel(chip, CORBWP, wp);
+
spin_unlock_irq(&chip->reg_lock);
return 0;
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH] hda: remember last command for each codec
2009-08-01 10:45 [RFC][PATCH] hda: track CIRB/CORB command/response states for each codec Wu Fengguang
` (2 preceding siblings ...)
2009-08-01 10:48 ` [PATCH] hda: read CORBWP inside reg_lock Wu Fengguang
@ 2009-08-01 11:17 ` Wu Fengguang
2009-08-01 11:18 ` [PATCH] hda: warn on spurious response Wu Fengguang
2009-08-03 6:50 ` [RFC][PATCH] hda: track CIRB/CORB command/response states for each codec Takashi Iwai
4 siblings, 1 reply; 7+ messages in thread
From: Wu Fengguang @ 2009-08-01 11:17 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel, Jaroslav Kysela
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
---
sound/pci/hda/hda_intel.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
--- sound-2.6.orig/sound/pci/hda/hda_intel.c
+++ sound-2.6/sound/pci/hda/hda_intel.c
@@ -425,7 +425,7 @@ struct azx {
unsigned int probing :1; /* codec probing phase */
/* for debugging */
- unsigned int last_cmd; /* last issued command (to sync) */
+ unsigned int last_cmd[AZX_MAX_CODECS];
/* for pending irqs */
struct work_struct irq_pending_work;
@@ -675,7 +675,8 @@ static unsigned int azx_rirb_get_respons
if (chip->msi) {
snd_printk(KERN_WARNING SFX "No response from codec, "
- "disabling MSI: last cmd=0x%08x\n", chip->last_cmd);
+ "disabling MSI: last cmd=0x%08x\n",
+ chip->last_cmd[addr]);
free_irq(chip->irq, chip);
chip->irq = -1;
pci_disable_msi(chip->pci);
@@ -690,7 +691,7 @@ static unsigned int azx_rirb_get_respons
if (!chip->polling_mode) {
snd_printk(KERN_WARNING SFX "azx_get_response timeout, "
"switching to polling mode: last cmd=0x%08x\n",
- chip->last_cmd);
+ chip->last_cmd[addr]);
chip->polling_mode = 1;
goto again;
}
@@ -714,7 +715,7 @@ static unsigned int azx_rirb_get_respons
snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
"switching to single_cmd mode: last cmd=0x%08x\n",
- chip->last_cmd);
+ chip->last_cmd[addr]);
chip->single_cmd = 1;
bus->response_reset = 0;
/* re-initialize CORB/RIRB */
@@ -801,7 +802,7 @@ static int azx_send_cmd(struct hda_bus *
{
struct azx *chip = bus->private_data;
- chip->last_cmd = val;
+ chip->last_cmd[azx_command_addr(val)] = val;
if (chip->single_cmd)
return azx_single_send_cmd(bus, val);
else
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH] hda: warn on spurious response
2009-08-01 11:17 ` [PATCH] hda: remember last command for each codec Wu Fengguang
@ 2009-08-01 11:18 ` Wu Fengguang
0 siblings, 0 replies; 7+ messages in thread
From: Wu Fengguang @ 2009-08-01 11:18 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel, Jaroslav Kysela
To help disclose hardware bugs.
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
---
sound/pci/hda/hda_intel.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
--- sound-2.6.orig/sound/pci/hda/hda_intel.c
+++ sound-2.6/sound/pci/hda/hda_intel.c
@@ -639,7 +639,11 @@ static void azx_update_rirb(struct azx *
chip->rirb.res[addr] = res;
smp_wmb();
chip->rirb.cmds[addr]--;
- }
+ } else
+ snd_printk(KERN_ERR SFX "spurious response %#x:%#x, "
+ "last cmd=%#08x\n",
+ res, res_ex,
+ chip->last_cmd[addr]);
}
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC][PATCH] hda: track CIRB/CORB command/response states for each codec
2009-08-01 10:45 [RFC][PATCH] hda: track CIRB/CORB command/response states for each codec Wu Fengguang
` (3 preceding siblings ...)
2009-08-01 11:17 ` [PATCH] hda: remember last command for each codec Wu Fengguang
@ 2009-08-03 6:50 ` Takashi Iwai
4 siblings, 0 replies; 7+ messages in thread
From: Takashi Iwai @ 2009-08-03 6:50 UTC (permalink / raw)
To: Wu Fengguang; +Cc: alsa-devel, Jaroslav Kysela
At Sat, 1 Aug 2009 18:45:16 +0800,
Wu Fengguang wrote:
>
> 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>
Good catch. I applied this series to fix/hda branch to be included
in the next pull request.
thanks,
Takashi
> ---
> sound/pci/hda/hda_codec.c | 2
> sound/pci/hda/hda_codec.h | 2
> sound/pci/hda/hda_intel.c | 76 +++++++++++++++++++++++++-----------
> 3 files changed, 56 insertions(+), 24 deletions(-)
>
> --- sound-2.6.orig/sound/pci/hda/hda_codec.c
> +++ sound-2.6/sound/pci/hda/hda_codec.c
> @@ -185,7 +185,7 @@ static int codec_exec_verb(struct hda_co
> mutex_lock(&bus->cmd_mutex);
> err = bus->ops.command(bus, cmd);
> if (!err && res)
> - *res = bus->ops.get_response(bus);
> + *res = bus->ops.get_response(bus, codec->addr);
> mutex_unlock(&bus->cmd_mutex);
> snd_hda_power_down(codec);
> if (res && *res == -1 && bus->rirb_error) {
> --- sound-2.6.orig/sound/pci/hda/hda_codec.h
> +++ sound-2.6/sound/pci/hda/hda_codec.h
> @@ -568,7 +568,7 @@ struct hda_bus_ops {
> /* send a single command */
> int (*command)(struct hda_bus *bus, unsigned int cmd);
> /* get a response from the last command */
> - unsigned int (*get_response)(struct hda_bus *bus);
> + unsigned int (*get_response)(struct hda_bus *bus, unsigned int addr);
> /* free the private data */
> void (*private_free)(struct hda_bus *);
> /* attach a PCM stream */
> --- sound-2.6.orig/sound/pci/hda/hda_intel.c
> +++ sound-2.6/sound/pci/hda/hda_intel.c
> @@ -260,7 +260,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO
>
> /* STATESTS int mask: S3,SD2,SD1,SD0 */
> #define AZX_MAX_CODECS 4
> -#define STATESTS_INT_MASK 0x0f
> +#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1)
>
> /* SD_CTL bits */
> #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
> @@ -368,8 +368,8 @@ struct azx_rb {
> dma_addr_t addr; /* physical address of CORB/RIRB buffer */
> /* for RIRB */
> unsigned short rp, wp; /* read/write pointers */
> - int cmds; /* number of pending requests */
> - u32 res; /* last read value */
> + int cmds[AZX_MAX_CODECS]; /* number of pending requests */
> + u32 res[AZX_MAX_CODECS]; /* last read value */
> };
>
> struct azx {
> @@ -538,7 +538,8 @@ static void azx_init_cmd_io(struct azx *
> /* RIRB set up */
> chip->rirb.addr = chip->rb.addr + 2048;
> chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
> - chip->rirb.wp = chip->rirb.rp = chip->rirb.cmds = 0;
> + chip->rirb.wp = chip->rirb.rp = 0;
> + memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds));
> azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
> azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
>
> @@ -559,10 +560,35 @@ static void azx_free_cmd_io(struct azx *
> azx_writeb(chip, CORBCTL, 0);
> }
>
> +static unsigned int azx_command_addr(u32 cmd)
> +{
> + unsigned int addr = cmd >> 28;
> +
> + if (addr >= AZX_MAX_CODECS) {
> + snd_BUG();
> + addr = 0;
> + }
> +
> + return addr;
> +}
> +
> +static unsigned int azx_response_addr(u32 res)
> +{
> + unsigned int addr = res & 0xf;
> +
> + if (addr >= AZX_MAX_CODECS) {
> + snd_BUG();
> + addr = 0;
> + }
> +
> + return addr;
> +}
> +
> /* send a command */
> static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
> {
> struct azx *chip = bus->private_data;
> + unsigned int addr = azx_command_addr(val);
> unsigned int wp;
>
> /* add command to corb */
> @@ -571,7 +597,7 @@ static int azx_corb_send_cmd(struct hda_
> wp %= ICH6_MAX_CORB_ENTRIES;
>
> spin_lock_irq(&chip->reg_lock);
> - chip->rirb.cmds++;
> + chip->rirb.cmds[addr]++;
> chip->corb.buf[wp] = cpu_to_le32(val);
> azx_writel(chip, CORBWP, wp);
> spin_unlock_irq(&chip->reg_lock);
> @@ -585,13 +611,14 @@ static int azx_corb_send_cmd(struct hda_
> static void azx_update_rirb(struct azx *chip)
> {
> unsigned int rp, wp;
> + unsigned int addr;
> u32 res, res_ex;
>
> wp = azx_readb(chip, RIRBWP);
> if (wp == chip->rirb.wp)
> return;
> chip->rirb.wp = wp;
> -
> +
> while (chip->rirb.rp != wp) {
> chip->rirb.rp++;
> chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES;
> @@ -599,18 +626,20 @@ static void azx_update_rirb(struct azx *
> rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */
> res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
> res = le32_to_cpu(chip->rirb.buf[rp]);
> + addr = azx_response_addr(res_ex);
> if (res_ex & ICH6_RIRB_EX_UNSOL_EV)
> snd_hda_queue_unsol_event(chip->bus, res, res_ex);
> - else if (chip->rirb.cmds) {
> - chip->rirb.res = res;
> + else if (chip->rirb.cmds[addr]) {
> + chip->rirb.res[addr] = res;
> smp_wmb();
> - chip->rirb.cmds--;
> + chip->rirb.cmds[addr]--;
> }
> }
> }
>
> /* receive a response */
> -static unsigned int azx_rirb_get_response(struct hda_bus *bus)
> +static unsigned int azx_rirb_get_response(struct hda_bus *bus,
> + unsigned int addr)
> {
> struct azx *chip = bus->private_data;
> unsigned long timeout;
> @@ -623,10 +652,10 @@ static unsigned int azx_rirb_get_respons
> azx_update_rirb(chip);
> spin_unlock_irq(&chip->reg_lock);
> }
> - if (!chip->rirb.cmds) {
> + if (!chip->rirb.cmds[addr]) {
> smp_rmb();
> bus->rirb_error = 0;
> - return chip->rirb.res; /* the last value */
> + return chip->rirb.res[addr]; /* the last value */
> }
> if (time_after(jiffies, timeout))
> break;
> @@ -699,7 +728,7 @@ static unsigned int azx_rirb_get_respons
> */
>
> /* receive a response */
> -static int azx_single_wait_for_response(struct azx *chip)
> +static int azx_single_wait_for_response(struct azx *chip, unsigned int addr)
> {
> int timeout = 50;
>
> @@ -707,7 +736,7 @@ static int azx_single_wait_for_response(
> /* check IRV busy bit */
> if (azx_readw(chip, IRS) & ICH6_IRS_VALID) {
> /* reuse rirb.res as the response return value */
> - chip->rirb.res = azx_readl(chip, IR);
> + chip->rirb.res[addr] = azx_readl(chip, IR);
> return 0;
> }
> udelay(1);
> @@ -715,7 +744,7 @@ static int azx_single_wait_for_response(
> if (printk_ratelimit())
> snd_printd(SFX "get_response timeout: IRS=0x%x\n",
> azx_readw(chip, IRS));
> - chip->rirb.res = -1;
> + chip->rirb.res[addr] = -1;
> return -EIO;
> }
>
> @@ -723,6 +752,7 @@ static int azx_single_wait_for_response(
> static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
> {
> struct azx *chip = bus->private_data;
> + unsigned int addr = azx_command_addr(val);
> int timeout = 50;
>
> bus->rirb_error = 0;
> @@ -735,7 +765,7 @@ static int azx_single_send_cmd(struct hd
> azx_writel(chip, IC, val);
> azx_writew(chip, IRS, azx_readw(chip, IRS) |
> ICH6_IRS_BUSY);
> - return azx_single_wait_for_response(chip);
> + return azx_single_wait_for_response(chip, addr);
> }
> udelay(1);
> }
> @@ -746,10 +776,11 @@ static int azx_single_send_cmd(struct hd
> }
>
> /* receive a response */
> -static unsigned int azx_single_get_response(struct hda_bus *bus)
> +static unsigned int azx_single_get_response(struct hda_bus *bus,
> + unsigned int addr)
> {
> struct azx *chip = bus->private_data;
> - return chip->rirb.res;
> + return chip->rirb.res[addr];
> }
>
> /*
> @@ -772,13 +803,14 @@ static int azx_send_cmd(struct hda_bus *
> }
>
> /* get a response */
> -static unsigned int azx_get_response(struct hda_bus *bus)
> +static unsigned int azx_get_response(struct hda_bus *bus,
> + unsigned int addr)
> {
> struct azx *chip = bus->private_data;
> if (chip->single_cmd)
> - return azx_single_get_response(bus);
> + return azx_single_get_response(bus, addr);
> else
> - return azx_rirb_get_response(bus);
> + return azx_rirb_get_response(bus, addr);
> }
>
> #ifdef CONFIG_SND_HDA_POWER_SAVE
> @@ -1252,7 +1284,7 @@ static int probe_codec(struct azx *chip,
>
> chip->probing = 1;
> azx_send_cmd(chip->bus, cmd);
> - res = azx_get_response(chip->bus);
> + res = azx_get_response(chip->bus, addr);
> chip->probing = 0;
> if (res == -1)
> return -EIO;
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2009-08-03 6:50 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-01 10:45 [RFC][PATCH] hda: track CIRB/CORB command/response states for each codec Wu Fengguang
2009-08-01 10:46 ` [PATCH] hda: take cmd_mutex in probe_codec() Wu Fengguang
2009-08-01 10:47 ` [PATCH] hda: take reg_lock in azx_init_cmd_io/azx_free_cmd_io Wu Fengguang
2009-08-01 10:48 ` [PATCH] hda: read CORBWP inside reg_lock Wu Fengguang
2009-08-01 11:17 ` [PATCH] hda: remember last command for each codec Wu Fengguang
2009-08-01 11:18 ` [PATCH] hda: warn on spurious response Wu Fengguang
2009-08-03 6:50 ` [RFC][PATCH] hda: track CIRB/CORB command/response states for each codec Takashi Iwai
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox