All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] ALSA: Prep work for PCI rescan support
@ 2021-05-18 16:51 Takashi Iwai
  2021-05-18 16:51 ` [PATCH 1/7] ALSA: core: Use READ_ONCE() / WRITE_ONCE() for power state change Takashi Iwai
                   ` (6 more replies)
  0 siblings, 7 replies; 12+ messages in thread
From: Takashi Iwai @ 2021-05-18 16:51 UTC (permalink / raw)
  To: alsa-devel; +Cc: Andrey Grodzovsky

Hi,

this is a patch set as a prep work for the future-planned PCI rescan
support(*).  The essential part is the patch to track in-flight tasks,
and the rest are cleanups and fixes in the core code.  With those
changes, the driver can perform a sort of software suspend on the
device without the hardware intervention, which is required during the
PCI BAR movement, for example.


Takashi

(*) https://lore.kernel.org/alsa-devel/e25017c6-e5e4-7a24-e793-14a2e70a434e@amd.com/

===

Takashi Iwai (7):
  ALSA: core: Use READ_ONCE() / WRITE_ONCE() for power state change
  ALSA: control: Add power state check commonly for ioctl handlers
  ALSA: control: Drop superfluous snd_power_wait() calls
  ALSA: control: Minor optimization for SNDRV_CTL_IOCTL_POWER_STATE
  ALSA: control: Track in-flight control read/write/tlv accesses
  ALSA: pcm: Block the release until the system resume finishes
  ALSA: Drop superfluous argument from snd_power_wait()

 include/sound/core.h        | 39 +++++++++++++++++++++---
 sound/core/control.c        | 41 +++++++++++++-------------
 sound/core/control_compat.c | 17 +++++------
 sound/core/init.c           | 59 ++++++++++++++++++++++++++++++++-----
 sound/core/pcm_native.c     |  6 +++-
 sound/soc/soc-core.c        |  2 +-
 sound/usb/usx2y/us122l.c    |  2 +-
 7 files changed, 121 insertions(+), 45 deletions(-)

-- 
2.26.2


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/7] ALSA: core: Use READ_ONCE() / WRITE_ONCE() for power state change
  2021-05-18 16:51 [PATCH 0/7] ALSA: Prep work for PCI rescan support Takashi Iwai
@ 2021-05-18 16:51 ` Takashi Iwai
  2021-05-18 16:51 ` [PATCH 2/7] ALSA: control: Add power state check commonly for ioctl handlers Takashi Iwai
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Takashi Iwai @ 2021-05-18 16:51 UTC (permalink / raw)
  To: alsa-devel; +Cc: Andrey Grodzovsky

We need proper barriers to handle the power state change of the card
from different CPUs.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/core.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/sound/core.h b/include/sound/core.h
index 1f9aef0adbc9..d69dfc6c4953 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -142,12 +142,12 @@ struct snd_card {
 #ifdef CONFIG_PM
 static inline unsigned int snd_power_get_state(struct snd_card *card)
 {
-	return card->power_state;
+	return READ_ONCE(card->power_state);
 }
 
 static inline void snd_power_change_state(struct snd_card *card, unsigned int state)
 {
-	card->power_state = state;
+	WRITE_ONCE(card->power_state, state);
 	wake_up(&card->power_sleep);
 }
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/7] ALSA: control: Add power state check commonly for ioctl handlers
  2021-05-18 16:51 [PATCH 0/7] ALSA: Prep work for PCI rescan support Takashi Iwai
  2021-05-18 16:51 ` [PATCH 1/7] ALSA: core: Use READ_ONCE() / WRITE_ONCE() for power state change Takashi Iwai
@ 2021-05-18 16:51 ` Takashi Iwai
  2021-05-18 18:00   ` Jaroslav Kysela
  2021-05-18 16:51 ` [PATCH 3/7] ALSA: control: Drop superfluous snd_power_wait() calls Takashi Iwai
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Takashi Iwai @ 2021-05-18 16:51 UTC (permalink / raw)
  To: alsa-devel; +Cc: Andrey Grodzovsky

The card power state check can be better put in the common ioctl
handler, as basically we want to prevent ioctls during the power off
state.  Although this situation won't happen normally any longer (*),
it'll be helpful for catching this for the future implementation like
the faked suspend that is needed for PCI rescan.

(*) Long long time ago, before the proper PM framework was introduced,
it was still possible to reach SNDRV_CTL_IOCTL_POWER ioctl during the
power off state.  This ioctl existed as a main control for the suspend
resume state in the past, but the feature was already dropped along
with the standard PM framework.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/core/control.c        | 3 +++
 sound/core/control_compat.c | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/sound/core/control.c b/sound/core/control.c
index 498e3701514a..c22c3fad0c64 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1772,6 +1772,9 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
 	card = ctl->card;
 	if (snd_BUG_ON(!card))
 		return -ENXIO;
+	err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
+	if (err < 0)
+		return err;
 	switch (cmd) {
 	case SNDRV_CTL_IOCTL_PVERSION:
 		return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index 1d708aab9c98..d5b562ff237b 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -438,6 +438,9 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
 	if (snd_BUG_ON(!ctl || !ctl->card))
 		return -ENXIO;
 
+	err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
+	if (err < 0)
+		return err;
 	switch (cmd) {
 	case SNDRV_CTL_IOCTL_PVERSION:
 	case SNDRV_CTL_IOCTL_CARD_INFO:
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/7] ALSA: control: Drop superfluous snd_power_wait() calls
  2021-05-18 16:51 [PATCH 0/7] ALSA: Prep work for PCI rescan support Takashi Iwai
  2021-05-18 16:51 ` [PATCH 1/7] ALSA: core: Use READ_ONCE() / WRITE_ONCE() for power state change Takashi Iwai
  2021-05-18 16:51 ` [PATCH 2/7] ALSA: control: Add power state check commonly for ioctl handlers Takashi Iwai
@ 2021-05-18 16:51 ` Takashi Iwai
  2021-05-18 16:51 ` [PATCH 4/7] ALSA: control: Minor optimization for SNDRV_CTL_IOCTL_POWER_STATE Takashi Iwai
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Takashi Iwai @ 2021-05-18 16:51 UTC (permalink / raw)
  To: alsa-devel; +Cc: Andrey Grodzovsky

Now the card power state is checked in the common ioctl handler, drop
the same redundant checks in each ioctl.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/core/control.c        | 11 -----------
 sound/core/control_compat.c |  9 ---------
 2 files changed, 20 deletions(-)

diff --git a/sound/core/control.c b/sound/core/control.c
index c22c3fad0c64..799d91ddccb0 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1042,9 +1042,6 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
 
 	if (copy_from_user(&info, _info, sizeof(info)))
 		return -EFAULT;
-	result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
-	if (result < 0)
-		return result;
 	result = snd_ctl_elem_info(ctl, &info);
 	if (result < 0)
 		return result;
@@ -1113,10 +1110,6 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
 	if (IS_ERR(control))
 		return PTR_ERR(control);
 
-	result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
-	if (result < 0)
-		goto error;
-
 	down_read(&card->controls_rwsem);
 	result = snd_ctl_elem_read(card, control);
 	up_read(&card->controls_rwsem);
@@ -1183,10 +1176,6 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
 		return PTR_ERR(control);
 
 	card = file->card;
-	result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
-	if (result < 0)
-		goto error;
-
 	result = snd_ctl_elem_write(card, file, control);
 	if (result < 0)
 		goto error;
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index d5b562ff237b..57b73ab57506 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -96,9 +96,6 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
 	if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
 		goto error;
 
-	err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
-	if (err < 0)
-		goto error;
 	err = snd_ctl_elem_info(ctl, data);
 	if (err < 0)
 		goto error;
@@ -298,9 +295,6 @@ static int ctl_elem_read_user(struct snd_card *card,
 	if (err < 0)
 		goto error;
 
-	err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
-	if (err < 0)
-		goto error;
 	err = snd_ctl_elem_read(card, data);
 	if (err < 0)
 		goto error;
@@ -326,9 +320,6 @@ static int ctl_elem_write_user(struct snd_ctl_file *file,
 	if (err < 0)
 		goto error;
 
-	err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
-	if (err < 0)
-		goto error;
 	err = snd_ctl_elem_write(card, file, data);
 	if (err < 0)
 		goto error;
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/7] ALSA: control: Minor optimization for SNDRV_CTL_IOCTL_POWER_STATE
  2021-05-18 16:51 [PATCH 0/7] ALSA: Prep work for PCI rescan support Takashi Iwai
                   ` (2 preceding siblings ...)
  2021-05-18 16:51 ` [PATCH 3/7] ALSA: control: Drop superfluous snd_power_wait() calls Takashi Iwai
@ 2021-05-18 16:51 ` Takashi Iwai
  2021-05-18 16:51 ` [PATCH 5/7] ALSA: control: Track in-flight control read/write/tlv accesses Takashi Iwai
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Takashi Iwai @ 2021-05-18 16:51 UTC (permalink / raw)
  To: alsa-devel; +Cc: Andrey Grodzovsky

The SNDRV_CTL_IOCTL_POWER_STATE is an obsoleted ioctl and now
practically it returns always D0.  Do some minor optimization.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/core/control.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/sound/core/control.c b/sound/core/control.c
index 799d91ddccb0..5e8b77855e5d 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1807,11 +1807,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
 	case SNDRV_CTL_IOCTL_POWER:
 		return -ENOPROTOOPT;
 	case SNDRV_CTL_IOCTL_POWER_STATE:
-#ifdef CONFIG_PM
-		return put_user(card->power_state, ip) ? -EFAULT : 0;
-#else
 		return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
-#endif
 	}
 	down_read(&snd_ioctl_rwsem);
 	list_for_each_entry(p, &snd_control_ioctls, list) {
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/7] ALSA: control: Track in-flight control read/write/tlv accesses
  2021-05-18 16:51 [PATCH 0/7] ALSA: Prep work for PCI rescan support Takashi Iwai
                   ` (3 preceding siblings ...)
  2021-05-18 16:51 ` [PATCH 4/7] ALSA: control: Minor optimization for SNDRV_CTL_IOCTL_POWER_STATE Takashi Iwai
@ 2021-05-18 16:51 ` Takashi Iwai
  2021-05-18 18:01   ` Jaroslav Kysela
  2021-05-18 16:52 ` [PATCH 6/7] ALSA: pcm: Block the release until the system resume finishes Takashi Iwai
  2021-05-18 16:52 ` [PATCH 7/7] ALSA: Drop superfluous argument from snd_power_wait() Takashi Iwai
  6 siblings, 1 reply; 12+ messages in thread
From: Takashi Iwai @ 2021-05-18 16:51 UTC (permalink / raw)
  To: alsa-devel; +Cc: Andrey Grodzovsky

Although we introduced the power state check at the entrance of the
common handler for control API (and other interfaces), there can be
still some pending tasks that already went into the ioctl handler, and
those may access the hardware even after the power state check;
currently the problem is seen typically for the kcontrol access
paths.  If a system wants to assure the free from hw access (like the
PCI rescan feature we're going to implement in future), this situation
must be avoided, and we have to sync such in-flight tasks finishing.

For that purpose, this patch introduces a few new things:
- A refcount, power_ref, and a wait queue, power_ref_sleep, to the
  card object
- A few new helpers, snd_power_ref(), snd_power_unref(),
  snd_power_ref_and_wait(), and snd_power_sync_ref()

In the code paths that call kctl info/read/write/tlv ops, we check the
power state again but at this time with the newly introduced
snd_power_ref_and_wait() instead.  This function also takes the
card.power_ref refcount for tracking this in-flight task.  Once after
the access finishes, snd_power_unref() is called to released the
refcount.  So the driver can sync via snd_power_sync_ref() assuring
that all in-flight tasks have been finished.

As of this patch, snd_power_sync_ref() is called only at
snd_card_disconnect(), but it'll be used in other places in future.

Note that atomic_t is used for power_ref intentionally instead of
refcount_t.  It's because of the design of refcount_t type; it cannot
be zero-based, and it cannot do dec_and_test() call for multiple
times.

Also, this patch changes snd_power_wait() to accept only
SNDRV_CTL_POWER_D0, which is the only value that makes sense.
In later patch, the snd_power_wait() calls will be simplified.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/core.h        | 31 ++++++++++++++++++
 sound/core/control.c        | 23 +++++++++++---
 sound/core/control_compat.c |  5 ++-
 sound/core/init.c           | 63 ++++++++++++++++++++++++++++++++-----
 4 files changed, 108 insertions(+), 14 deletions(-)

diff --git a/include/sound/core.h b/include/sound/core.h
index d69dfc6c4953..430d775b3c0e 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -128,7 +128,9 @@ struct snd_card {
 
 #ifdef CONFIG_PM
 	unsigned int power_state;	/* power state */
+	atomic_t power_ref;
 	wait_queue_head_t power_sleep;
+	wait_queue_head_t power_ref_sleep;
 #endif
 
 #if IS_ENABLED(CONFIG_SND_MIXER_OSS)
@@ -151,12 +153,41 @@ static inline void snd_power_change_state(struct snd_card *card, unsigned int st
 	wake_up(&card->power_sleep);
 }
 
+/**
+ * snd_power_ref - Take the reference count for power control
+ * @card: sound card object
+ *
+ * The power_ref reference of the card is used for managing to block
+ * the snd_power_sync_ref() operation.  This function increments the reference.
+ * The counterpart snd_power_unref() has to be called appropriately later.
+ */
+static inline void snd_power_ref(struct snd_card *card)
+{
+	atomic_inc(&card->power_ref);
+}
+
+/**
+ * snd_power_unref - Release the reference count for power control
+ * @card: sound card object
+ */
+static inline void snd_power_unref(struct snd_card *card)
+{
+	if (atomic_dec_and_test(&card->power_ref))
+		wake_up(&card->power_ref_sleep);
+}
+
 /* init.c */
 int snd_power_wait(struct snd_card *card, unsigned int power_state);
+int snd_power_ref_and_wait(struct snd_card *card);
+void snd_power_sync_ref(struct snd_card *card);
 
 #else /* ! CONFIG_PM */
 
 static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; }
+static inline void snd_power_ref(struct snd_card *card) {}
+static inline void snd_power_unref(struct snd_card *card) {}
+static inline int snd_power_ref_and_wait(struct snd_card *card) { return 0; }
+static inline void snd_power_sync_ref(struct snd_card *card) {}
 #define snd_power_get_state(card)	({ (void)(card); SNDRV_CTL_POWER_D0; })
 #define snd_power_change_state(card, state)	do { (void)(card); } while (0)
 
diff --git a/sound/core/control.c b/sound/core/control.c
index 5e8b77855e5d..37f6f2ca0543 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -995,7 +995,10 @@ static int __snd_ctl_elem_info(struct snd_card *card,
 #ifdef CONFIG_SND_DEBUG
 	info->access = 0;
 #endif
-	result = kctl->info(kctl, info);
+	result = snd_power_ref_and_wait(card);
+	if (!result)
+		result = kctl->info(kctl, info);
+	snd_power_unref(card);
 	if (result >= 0) {
 		snd_BUG_ON(info->access);
 		index_offset = snd_ctl_get_ioff(kctl, &info->id);
@@ -1085,7 +1088,10 @@ static int snd_ctl_elem_read(struct snd_card *card,
 
 	if (!snd_ctl_skip_validation(&info))
 		fill_remaining_elem_value(control, &info, pattern);
-	ret = kctl->get(kctl, control);
+	ret = snd_power_ref_and_wait(card);
+	if (!ret)
+		ret = kctl->get(kctl, control);
+	snd_power_unref(card);
 	if (ret < 0)
 		return ret;
 	if (!snd_ctl_skip_validation(&info) &&
@@ -1147,7 +1153,10 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
 	}
 
 	snd_ctl_build_ioff(&control->id, kctl, index_offset);
-	result = kctl->put(kctl, control);
+	result = snd_power_ref_and_wait(card);
+	if (!result)
+		result = kctl->put(kctl, control);
+	snd_power_unref(card);
 	if (result < 0) {
 		up_write(&card->controls_rwsem);
 		return result;
@@ -1658,7 +1667,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
 		{SNDRV_CTL_TLV_OP_CMD,   SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND},
 	};
 	struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)];
-	int i;
+	int i, ret;
 
 	/* Check support of the request for this element. */
 	for (i = 0; i < ARRAY_SIZE(pairs); ++i) {
@@ -1676,7 +1685,11 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
 	    vd->owner != NULL && vd->owner != file)
 		return -EPERM;
 
-	return kctl->tlv.c(kctl, op_flag, size, buf);
+	ret = snd_power_ref_and_wait(file->card);
+	if (!ret)
+		ret = kctl->tlv.c(kctl, op_flag, size, buf);
+	snd_power_unref(file->card);
+	return ret;
 }
 
 static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id,
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index 57b73ab57506..b9fe1ead435b 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -184,7 +184,10 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
 		return -ENOMEM;
 	}
 	info->id = *id;
-	err = kctl->info(kctl, info);
+	err = snd_power_ref_and_wait(card);
+	if (!err)
+		err = kctl->info(kctl, info);
+	snd_power_unref(card);
 	up_read(&card->controls_rwsem);
 	if (err >= 0) {
 		err = info->type;
diff --git a/sound/core/init.c b/sound/core/init.c
index ef41f5b3a240..d11636fac608 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -220,6 +220,8 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
 	mutex_init(&card->memory_mutex);
 #ifdef CONFIG_PM
 	init_waitqueue_head(&card->power_sleep);
+	init_waitqueue_head(&card->power_ref_sleep);
+	atomic_set(&card->power_ref, 0);
 #endif
 	init_waitqueue_head(&card->remove_sleep);
 	card->sync_irq = -1;
@@ -442,6 +444,7 @@ int snd_card_disconnect(struct snd_card *card)
 
 #ifdef CONFIG_PM
 	wake_up(&card->power_sleep);
+	snd_power_sync_ref(card);
 #endif
 	return 0;	
 }
@@ -1002,21 +1005,28 @@ EXPORT_SYMBOL(snd_card_file_remove);
 
 #ifdef CONFIG_PM
 /**
- *  snd_power_wait - wait until the power-state is changed.
- *  @card: soundcard structure
- *  @power_state: expected power state
+ * snd_power_ref_and_wait - wait until the card gets powered up
+ * @card: soundcard structure
+ *
+ * Take the power_ref reference count of the given card, and
+ * wait until the card gets powered up to SNDRV_CTL_POWER_D0 state.
+ * The refcount is down again while sleeping until power-up, hence this
+ * function can be used for syncing the floating control ops accesses,
+ * typically around calling control ops.
  *
- *  Waits until the power-state is changed.
+ * The caller needs to pull down the refcount via snd_power_unref() later
+ * no matter whether the error is returned from this function or not.
  *
- *  Return: Zero if successful, or a negative error code.
+ * Return: Zero if successful, or a negative error code.
  */
-int snd_power_wait(struct snd_card *card, unsigned int power_state)
+int snd_power_ref_and_wait(struct snd_card *card)
 {
 	wait_queue_entry_t wait;
 	int result = 0;
 
+	snd_power_ref(card);
 	/* fastpath */
-	if (snd_power_get_state(card) == power_state)
+	if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0)
 		return 0;
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(&card->power_sleep, &wait);
@@ -1025,13 +1035,50 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state)
 			result = -ENODEV;
 			break;
 		}
-		if (snd_power_get_state(card) == power_state)
+		if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0)
 			break;
+		snd_power_unref(card);
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(30 * HZ);
+		snd_power_ref(card);
 	}
 	remove_wait_queue(&card->power_sleep, &wait);
 	return result;
 }
+EXPORT_SYMBOL_GPL(snd_power_ref_and_wait);
+
+/**
+ * snd_power_wait - wait until the card gets powered up (old form)
+ * @card: soundcard structure
+ * @power_state: expected power state
+ *
+ * Wait until the card gets powered up to SNDRV_CTL_POWER_D0 state.
+ * @power_state must be SNDRV_CTL_POWER_D0.
+ *
+ * Return: Zero if successful, or a negative error code.
+ */
+int snd_power_wait(struct snd_card *card, unsigned int power_state)
+{
+	int ret;
+
+	if (WARN_ON(power_state != SNDRV_CTL_POWER_D0))
+		return 0;
+	ret = snd_power_ref_and_wait(card);
+	snd_power_unref(card);
+	return ret;
+}
 EXPORT_SYMBOL(snd_power_wait);
+
+/**
+ * snd_power_sync_ref - wait until the card power_ref is freed
+ * @card: sound card object
+ *
+ * This function is used to synchronize with the pending power_ref being
+ * released.
+ */
+void snd_power_sync_ref(struct snd_card *card)
+{
+	wait_event(card->power_ref_sleep, !atomic_read(&card->power_ref));
+}
+EXPORT_SYMBOL_GPL(snd_power_sync_ref);
 #endif /* CONFIG_PM */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 6/7] ALSA: pcm: Block the release until the system resume finishes
  2021-05-18 16:51 [PATCH 0/7] ALSA: Prep work for PCI rescan support Takashi Iwai
                   ` (4 preceding siblings ...)
  2021-05-18 16:51 ` [PATCH 5/7] ALSA: control: Track in-flight control read/write/tlv accesses Takashi Iwai
@ 2021-05-18 16:52 ` Takashi Iwai
  2021-05-18 16:52 ` [PATCH 7/7] ALSA: Drop superfluous argument from snd_power_wait() Takashi Iwai
  6 siblings, 0 replies; 12+ messages in thread
From: Takashi Iwai @ 2021-05-18 16:52 UTC (permalink / raw)
  To: alsa-devel; +Cc: Andrey Grodzovsky

The normal PCM operations are already blocked during the card power
off state in the PCM common ioctl handler, but the release isn't
covered.  As the PCM stream release may also access the hardware,
let's block the release until the card power turns on.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/core/pcm_native.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 8dbe86cf2e4f..3c6ba0dc2970 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2799,6 +2799,10 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
 	if (snd_BUG_ON(!substream))
 		return -ENXIO;
 	pcm = substream->pcm;
+
+	/* block until the device gets woken up as it may touch the hardware */
+	snd_power_wait(pcm->card, SNDRV_CTL_POWER_D0);
+
 	mutex_lock(&pcm->open_mutex);
 	snd_pcm_release_substream(substream);
 	kfree(pcm_file);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 7/7] ALSA: Drop superfluous argument from snd_power_wait()
  2021-05-18 16:51 [PATCH 0/7] ALSA: Prep work for PCI rescan support Takashi Iwai
                   ` (5 preceding siblings ...)
  2021-05-18 16:52 ` [PATCH 6/7] ALSA: pcm: Block the release until the system resume finishes Takashi Iwai
@ 2021-05-18 16:52 ` Takashi Iwai
  6 siblings, 0 replies; 12+ messages in thread
From: Takashi Iwai @ 2021-05-18 16:52 UTC (permalink / raw)
  To: alsa-devel; +Cc: Andrey Grodzovsky

The power_state argument of snd_power_wait() is superfluous, receiving
only SNDRV_POWER_STATE_D0.  Let's drop it in all callers for
simplicity.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/core.h        | 4 ++--
 sound/core/control.c        | 2 +-
 sound/core/control_compat.c | 2 +-
 sound/core/init.c           | 6 +-----
 sound/core/pcm_native.c     | 4 ++--
 sound/soc/soc-core.c        | 2 +-
 sound/usb/usx2y/us122l.c    | 2 +-
 7 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/include/sound/core.h b/include/sound/core.h
index 430d775b3c0e..e1192a337582 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -177,13 +177,13 @@ static inline void snd_power_unref(struct snd_card *card)
 }
 
 /* init.c */
-int snd_power_wait(struct snd_card *card, unsigned int power_state);
+int snd_power_wait(struct snd_card *card);
 int snd_power_ref_and_wait(struct snd_card *card);
 void snd_power_sync_ref(struct snd_card *card);
 
 #else /* ! CONFIG_PM */
 
-static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; }
+static inline int snd_power_wait(struct snd_card *card) { return 0; }
 static inline void snd_power_ref(struct snd_card *card) {}
 static inline void snd_power_unref(struct snd_card *card) {}
 static inline int snd_power_ref_and_wait(struct snd_card *card) { return 0; }
diff --git a/sound/core/control.c b/sound/core/control.c
index 37f6f2ca0543..c145c6011878 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1774,7 +1774,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
 	card = ctl->card;
 	if (snd_BUG_ON(!card))
 		return -ENXIO;
-	err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
+	err = snd_power_wait(card);
 	if (err < 0)
 		return err;
 	switch (cmd) {
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index b9fe1ead435b..b4554ae21e33 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -432,7 +432,7 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
 	if (snd_BUG_ON(!ctl || !ctl->card))
 		return -ENXIO;
 
-	err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
+	err = snd_power_wait(ctl->card);
 	if (err < 0)
 		return err;
 	switch (cmd) {
diff --git a/sound/core/init.c b/sound/core/init.c
index d11636fac608..7942da1085d2 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -1050,19 +1050,15 @@ EXPORT_SYMBOL_GPL(snd_power_ref_and_wait);
 /**
  * snd_power_wait - wait until the card gets powered up (old form)
  * @card: soundcard structure
- * @power_state: expected power state
  *
  * Wait until the card gets powered up to SNDRV_CTL_POWER_D0 state.
- * @power_state must be SNDRV_CTL_POWER_D0.
  *
  * Return: Zero if successful, or a negative error code.
  */
-int snd_power_wait(struct snd_card *card, unsigned int power_state)
+int snd_power_wait(struct snd_card *card)
 {
 	int ret;
 
-	if (WARN_ON(power_state != SNDRV_CTL_POWER_D0))
-		return 0;
 	ret = snd_power_ref_and_wait(card);
 	snd_power_unref(card);
 	return ret;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 3c6ba0dc2970..11acea02bc74 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2801,7 +2801,7 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
 	pcm = substream->pcm;
 
 	/* block until the device gets woken up as it may touch the hardware */
-	snd_power_wait(pcm->card, SNDRV_CTL_POWER_D0);
+	snd_power_wait(pcm->card);
 
 	mutex_lock(&pcm->open_mutex);
 	snd_pcm_release_substream(substream);
@@ -3197,7 +3197,7 @@ static int snd_pcm_common_ioctl(struct file *file,
 	if (PCM_RUNTIME_CHECK(substream))
 		return -ENXIO;
 
-	res = snd_power_wait(substream->pcm->card, SNDRV_CTL_POWER_D0);
+	res = snd_power_wait(substream->pcm->card);
 	if (res < 0)
 		return res;
 
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 1c0904acb935..ddc65c12f6f4 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -580,7 +580,7 @@ int snd_soc_suspend(struct device *dev)
 	 * Due to the resume being scheduled into a workqueue we could
 	 * suspend before that's finished - wait for it to complete.
 	 */
-	snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0);
+	snd_power_wait(card->snd_card);
 
 	/* we're going to block userspace touching us until resume completes */
 	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c
index 6e1bfe894dd5..596a1a1fea49 100644
--- a/sound/usb/usx2y/us122l.c
+++ b/sound/usb/usx2y/us122l.c
@@ -379,7 +379,7 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
 	if (cfg.period_frames < min_period_frames)
 		return -EINVAL;
 
-	snd_power_wait(hw->card, SNDRV_CTL_POWER_D0);
+	snd_power_wait(hw->card);
 
 	mutex_lock(&us122l->mutex);
 	s = us122l->sk.s;
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/7] ALSA: control: Add power state check commonly for ioctl handlers
  2021-05-18 16:51 ` [PATCH 2/7] ALSA: control: Add power state check commonly for ioctl handlers Takashi Iwai
@ 2021-05-18 18:00   ` Jaroslav Kysela
  2021-05-18 19:31     ` Takashi Iwai
  0 siblings, 1 reply; 12+ messages in thread
From: Jaroslav Kysela @ 2021-05-18 18:00 UTC (permalink / raw)
  To: Takashi Iwai, ALSA development; +Cc: Andrey Grodzovsky

Dne 18. 05. 21 v 18:51 Takashi Iwai napsal(a):
> The card power state check can be better put in the common ioctl
> handler, as basically we want to prevent ioctls during the power off
> state.  Although this situation won't happen normally any longer (*),
> it'll be helpful for catching this for the future implementation like
> the faked suspend that is needed for PCI rescan.
> 
> (*) Long long time ago, before the proper PM framework was introduced,
> it was still possible to reach SNDRV_CTL_IOCTL_POWER ioctl during the
> power off state.  This ioctl existed as a main control for the suspend
> resume state in the past, but the feature was already dropped along
> with the standard PM framework.

It seems like a function dup for the 5th patch which tracks in flight the
power state. I think that we should drop this (and reshuffle patches) or
remove this in or after the 5th patch.

					Jaroslav

> 
> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> ---
>  sound/core/control.c        | 3 +++
>  sound/core/control_compat.c | 3 +++
>  2 files changed, 6 insertions(+)
> 
> diff --git a/sound/core/control.c b/sound/core/control.c
> index 498e3701514a..c22c3fad0c64 100644
> --- a/sound/core/control.c
> +++ b/sound/core/control.c
> @@ -1772,6 +1772,9 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
>  	card = ctl->card;
>  	if (snd_BUG_ON(!card))
>  		return -ENXIO;
> +	err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
> +	if (err < 0)
> +		return err;
>  	switch (cmd) {
>  	case SNDRV_CTL_IOCTL_PVERSION:
>  		return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
> diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
> index 1d708aab9c98..d5b562ff237b 100644
> --- a/sound/core/control_compat.c
> +++ b/sound/core/control_compat.c
> @@ -438,6 +438,9 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
>  	if (snd_BUG_ON(!ctl || !ctl->card))
>  		return -ENXIO;
>  
> +	err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
> +	if (err < 0)
> +		return err;
>  	switch (cmd) {
>  	case SNDRV_CTL_IOCTL_PVERSION:
>  	case SNDRV_CTL_IOCTL_CARD_INFO:
> 


-- 
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 5/7] ALSA: control: Track in-flight control read/write/tlv accesses
  2021-05-18 16:51 ` [PATCH 5/7] ALSA: control: Track in-flight control read/write/tlv accesses Takashi Iwai
@ 2021-05-18 18:01   ` Jaroslav Kysela
  2021-05-18 18:54     ` Takashi Iwai
  0 siblings, 1 reply; 12+ messages in thread
From: Jaroslav Kysela @ 2021-05-18 18:01 UTC (permalink / raw)
  To: Takashi Iwai, alsa-devel; +Cc: Andrey Grodzovsky

Dne 18. 05. 21 v 18:51 Takashi Iwai napsal(a):

> +/**
> + * snd_power_sync_ref - wait until the card power_ref is freed
> + * @card: sound card object
> + *
> + * This function is used to synchronize with the pending power_ref being
> + * released.
> + */
> +void snd_power_sync_ref(struct snd_card *card)
> +{
> +	wait_event(card->power_ref_sleep, !atomic_read(&card->power_ref));
> +}
> +EXPORT_SYMBOL_GPL(snd_power_sync_ref);

Perhaps, this function can be inline, too?

					Jaroslav

-- 
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 5/7] ALSA: control: Track in-flight control read/write/tlv accesses
  2021-05-18 18:01   ` Jaroslav Kysela
@ 2021-05-18 18:54     ` Takashi Iwai
  0 siblings, 0 replies; 12+ messages in thread
From: Takashi Iwai @ 2021-05-18 18:54 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: Andrey Grodzovsky, alsa-devel

On Tue, 18 May 2021 20:01:33 +0200,
Jaroslav Kysela wrote:
> 
> Dne 18. 05. 21 v 18:51 Takashi Iwai napsal(a):
> 
> > +/**
> > + * snd_power_sync_ref - wait until the card power_ref is freed
> > + * @card: sound card object
> > + *
> > + * This function is used to synchronize with the pending power_ref being
> > + * released.
> > + */
> > +void snd_power_sync_ref(struct snd_card *card)
> > +{
> > +	wait_event(card->power_ref_sleep, !atomic_read(&card->power_ref));
> > +}
> > +EXPORT_SYMBOL_GPL(snd_power_sync_ref);
> 
> Perhaps, this function can be inline, too?

I thought of that, too.  Then maybe core.h needs more inclusion, but
it might be worth, yeah.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/7] ALSA: control: Add power state check commonly for ioctl handlers
  2021-05-18 18:00   ` Jaroslav Kysela
@ 2021-05-18 19:31     ` Takashi Iwai
  0 siblings, 0 replies; 12+ messages in thread
From: Takashi Iwai @ 2021-05-18 19:31 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: Andrey Grodzovsky, ALSA development

On Tue, 18 May 2021 20:00:46 +0200,
Jaroslav Kysela wrote:
> 
> Dne 18. 05. 21 v 18:51 Takashi Iwai napsal(a):
> > The card power state check can be better put in the common ioctl
> > handler, as basically we want to prevent ioctls during the power off
> > state.  Although this situation won't happen normally any longer (*),
> > it'll be helpful for catching this for the future implementation like
> > the faked suspend that is needed for PCI rescan.
> > 
> > (*) Long long time ago, before the proper PM framework was introduced,
> > it was still possible to reach SNDRV_CTL_IOCTL_POWER ioctl during the
> > power off state.  This ioctl existed as a main control for the suspend
> > resume state in the past, but the feature was already dropped along
> > with the standard PM framework.
> 
> It seems like a function dup for the 5th patch which tracks in flight the
> power state. I think that we should drop this (and reshuffle patches) or
> remove this in or after the 5th patch.

A good point.  With snd_power_ref_and_wait(), we achieve more
fine-grained protection, so those checks could be indeed dropped.
Will clean up later in the v2 patch.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2021-05-18 19:32 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-18 16:51 [PATCH 0/7] ALSA: Prep work for PCI rescan support Takashi Iwai
2021-05-18 16:51 ` [PATCH 1/7] ALSA: core: Use READ_ONCE() / WRITE_ONCE() for power state change Takashi Iwai
2021-05-18 16:51 ` [PATCH 2/7] ALSA: control: Add power state check commonly for ioctl handlers Takashi Iwai
2021-05-18 18:00   ` Jaroslav Kysela
2021-05-18 19:31     ` Takashi Iwai
2021-05-18 16:51 ` [PATCH 3/7] ALSA: control: Drop superfluous snd_power_wait() calls Takashi Iwai
2021-05-18 16:51 ` [PATCH 4/7] ALSA: control: Minor optimization for SNDRV_CTL_IOCTL_POWER_STATE Takashi Iwai
2021-05-18 16:51 ` [PATCH 5/7] ALSA: control: Track in-flight control read/write/tlv accesses Takashi Iwai
2021-05-18 18:01   ` Jaroslav Kysela
2021-05-18 18:54     ` Takashi Iwai
2021-05-18 16:52 ` [PATCH 6/7] ALSA: pcm: Block the release until the system resume finishes Takashi Iwai
2021-05-18 16:52 ` [PATCH 7/7] ALSA: Drop superfluous argument from snd_power_wait() 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.