Skip to content

Conversation

@RanderWang
Copy link
Collaborator

Chao cooperates with me to develop this feature. Now it works with nocodec smart amp topology

@aiChaoSONG
Copy link
Collaborator

aiChaoSONG commented Dec 8, 2022

The IPC4 smart_amp feature is VERIFIED with topology and linux kernel patches, which I will send later.

@RanderWang
Copy link
Collaborator Author

will fix compiling issue for mutex. It is only supported by zephyr

@RanderWang RanderWang force-pushed the ipc4_smart_amp branch 3 times, most recently from 69dbc6a to 72c8f7f Compare December 9, 2022 01:50
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

locks should be taken and released symmetrically. buffer_acquire() can potentially take a lock if the buffer is shared, so buffer_unlock() should come after sa_unlock(). Also below you acquire the buffer inside sa_lock() blocks. I know, that this is just a test, so probably it cannot race, right? Still it would be better to have that consistent to not even look like we can get an AB-BA deadlock

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch! thanks! refined it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AB-BA is still here: in this function buffer-acquisition is outside of sa_lock(), and in smart_amp_trigger() it's the other way round. Maybe you could just take the sa_lock() outside of the loop here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it is a potential risk

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, let's get it correct then. It should be ok to have sa_lock() outside of buffer locking since with Zephyr they're both taking mutexes and with XTOS - spinlocks

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RanderWang can you do this in prepare() instead of bind?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ranj063 we can't do it in prepare for playback stream since the feedback buffer is shared by capture feedback stream, so it can be available only when the capture feedback stream is started.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will submit a patch later that remove bind/unbind interface and use notifier to process bind/unbind event. please check #6751 (comment)

Copy link
Member

@lgirdwood lgirdwood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of the logic is not obvious for beginners, can you create a new PR where you add more comments to the ipc4 helper in general.

Comment on lines 54 to 67
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we revisit this in a subsequent PR (as there are others doing the same) and use k_mutex_ API directly (where we will define this for xtos as a spinlock).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, thanks

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, since we are updating the PR due to other issues, let fix this one too. Please add the k_mutex() calls to xtos/include/rtos/spinlock.h (and map them to use spinlocks).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lgirdwood are we sure that this is safe? XTOS also has a real thread context, IIRC it's used for EDF tasks. Are we sure that we don't have code in SOF, that maps to an EDF task in XTOS and uses a mutex for locking? Or would it be safe to take a spinlock and potentially go to sleep in such a task?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to maintain XTOS ? or switch to zephyr completely ? if so we can do nothing for k_mutex for XTOS

Copy link
Collaborator Author

@RanderWang RanderWang Dec 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lgirdwood When I try to support k_mutex with spinlock, I find that the parameters of mutex and spinlock is different. How to save spinlock and its key ? I can't figure out a method

Spinlock;
struct k_spinlock lock;
k_spinlock_key_t key;

Mutex:
struct k_mutex lock;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RanderWang Now I get the problem. Maybe define "struct k_mutex" so that there's both struct k_spinlock and k_spinlock_key_t as members of it when you build for XTOS. So then you can implement k_mutex_lock() with k_spin_lock() and store the key in XTOS version of "struct k_mutex". Would this work?

Copy link
Member

@lgirdwood lgirdwood Dec 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RanderWang pls consider doing something like (not even build tested)

diff --git a/xtos/include/rtos/spinlock.h b/xtos/include/rtos/spinlock.h
index 410c66bb9..5a02406bb 100644
--- a/xtos/include/rtos/spinlock.h
+++ b/xtos/include/rtos/spinlock.h
@@ -160,4 +160,27 @@ k_spinlock_key_t _k_spin_lock_irq(struct k_spinlock *lock);
 void _k_spin_unlock_irq(struct k_spinlock *lock, k_spinlock_key_t key, int line);
 #define k_spin_unlock(lock, key) _k_spin_unlock_irq(lock, key, __LINE__)
 
+struct k_mutex {
+       struct k_spinlock lock;
+       k_spinlock_key_t key;
+};
+
+static inline int k_mutex_init(struct k_mutex *mutex)
+{
+       k_spinlock_init(mutex->lock);
+       return 0;
+}
+
+static int k_mutex_lock(struct k_mutex *mutex, k_timeout_t timeout)
+{
+       mutex->key = k_spin_lock(mutex->lock);
+       return 0;
+}
+
+static inline int k_mutex_unlock(struct k_mutex *mutex)
+{
+       k_spin_unlock(mutex->lock, mutex->key);
+       return 0;
+}
+
 #endif /* __XTOS_RTOS_SPINLOCK_H__ */

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kv2019i @lgirdwood thanks very much ! completely address my concern.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're already doing this in the coherent API - storing the spinlock and the key in the same persistent structure. But that made me rethink that a bit - is that actually safe, because normally you have those keys as local variables - you store your returned spinlock status (CPU interrupt state) and then you restore it from the same variable, making sure nobody else overwrites that variable in the meantime. So having that variable as persistent and available to all might sound risky - you don't want to have another context overwrite that key and then restore a wrong context. But I think it should be safe in this context because another context will only overwrite the key after it has taken the spinlock, so the spinlock protects the key too. Just something to be aware of. Alternatively we could wrap k_mutex_lock() to return a status, but I don't think we want to do that, we want to use Zephyr APIs directly.

@RanderWang RanderWang force-pushed the ipc4_smart_amp branch 2 times, most recently from ba8e289 to c0904d7 Compare December 11, 2022 13:08
@RanderWang
Copy link
Collaborator Author

add comments for unbind

@RanderWang
Copy link
Collaborator Author

update mutex support. Thanks!

@mengdonglin
Copy link
Collaborator

update mutex support. Thanks!

@lgirdwood @kv2019i @lyakh Can you help review the updated PR?

Copy link
Collaborator

@kv2019i kv2019i left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with the existing smart-amp-test module, so cannot fully review how safe the locking changes are, but the changes look ok. The conditional disconnect starts to look complex, this may need further work, but can be done in separate PRs.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is ok as a bugfix, but this kind of hints at need for reference counting type approach to be used. Otherwise this will get very complicated when we might have connections across the cores and just disabling the irq is not enough to make checks like the above atomic.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, I add it to my shopping list

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RanderWang why is this needed? ipc_comp_disconnect() will only be called when 2 connected components from separate pipelines are disconnected. You should disconnecte and unbind here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider different streams not different pipelines

Copy link
Collaborator Author

@RanderWang RanderWang Dec 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A buffer is shared between playback stream and capture stream. I meant playback stream is still working, but capture stream is stopped, and one component in capture stream will be disconnected from a component in playback stream and the shared buffer will be free. if the buffer is using by playback stream, the disconnection will result to null pointer issue

@lgirdwood
Copy link
Member

@wszypelt can you check CI, I dont think we are testing dummy smart amp today ? (unless I'm out of date with the test matrix)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RanderWang this can never happen, right? During comp_disconnect, we have disabled interrupts. So it is not possible that the buffer is dsconnected from the sink dev but it hasn't been deleted from the list and freed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in different stream case, not in the same stream.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant the buffer is not disconnected for the state check in comp_disconnect. Ignore it since I remove the logic

Use smart_amp_verify_params

Signed-off-by: Rander Wang <rander.wang@intel.com>
It uses spin lock to support mutex.

Suggested-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Suggested-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@intel.com>
@RanderWang
Copy link
Collaborator Author

RanderWang commented Dec 16, 2022

Remove pipeline state check in comp_disconnect function since we have CI issue . Currently we use mutex in unbind function so we can make sure that the buffer is not used by smart_amp when buffer is disconnected. According to Kai, reference count is better than state check. We will remove unbind interface and check the multiple stream issue again.

@RanderWang
Copy link
Collaborator Author

@lgirdwood updated, pass CI test

@RanderWang RanderWang force-pushed the ipc4_smart_amp branch 2 times, most recently from 44cb151 to ed22d6e Compare December 16, 2022 05:38
@RanderWang
Copy link
Collaborator Author

refined code style

Smart amp test module read config from ipc msg and convert ipc4 settings
to ipc3. It is a dummy module used for smart amplifier validation.

Signed-off-by: Chao Song <chao.song@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@intel.com>
@RanderWang
Copy link
Collaborator Author

update commit message to wrap at line of 75 chars

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants