All of lore.kernel.org
 help / color / mirror / Atom feed
* [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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.