xref: /dpdk/drivers/net/nfp/nfpcore/nfp_mutex.c (revision aa6b4a80a3afd5c9e3b07f6b516f44cae7505e16)
1c7e9729dSAlejandro Lucero /* SPDX-License-Identifier: BSD-3-Clause
2c7e9729dSAlejandro Lucero  * Copyright(c) 2018 Netronome Systems, Inc.
3c7e9729dSAlejandro Lucero  * All rights reserved.
4c7e9729dSAlejandro Lucero  */
5c7e9729dSAlejandro Lucero 
64b6c8db9SChaoyong He #include "nfp_mutex.h"
74b6c8db9SChaoyong He 
8c7e9729dSAlejandro Lucero #include <sched.h>
9c7e9729dSAlejandro Lucero 
1052d810dcSJames Hershaw #include "nfp_logs.h"
11055ccb33SChaoyong He #include "nfp_target.h"
12c7e9729dSAlejandro Lucero 
13c7e9729dSAlejandro Lucero /*
14c7e9729dSAlejandro Lucero  * If you need more than 65536 recursive locks, please
15c7e9729dSAlejandro Lucero  * rethink your code.
16c7e9729dSAlejandro Lucero  */
17c7e9729dSAlejandro Lucero #define MUTEX_DEPTH_MAX         0xffff
18c7e9729dSAlejandro Lucero 
19c7e9729dSAlejandro Lucero struct nfp_cpp_mutex {
20c7e9729dSAlejandro Lucero 	struct nfp_cpp *cpp;
21c7e9729dSAlejandro Lucero 	uint8_t target;
22c7e9729dSAlejandro Lucero 	uint16_t depth;
23c69debceSChaoyong He 	uint64_t address;
24c7e9729dSAlejandro Lucero 	uint32_t key;
25c69debceSChaoyong He 	uint32_t usage;
26c7e9729dSAlejandro Lucero 	struct nfp_cpp_mutex *prev, *next;
27c7e9729dSAlejandro Lucero };
28c7e9729dSAlejandro Lucero 
294b6c8db9SChaoyong He static inline uint32_t
304b6c8db9SChaoyong He nfp_mutex_locked(uint16_t interface)
314b6c8db9SChaoyong He {
324b6c8db9SChaoyong He 	return (uint32_t)interface << 16 | 0x000f;
334b6c8db9SChaoyong He }
344b6c8db9SChaoyong He 
354b6c8db9SChaoyong He static inline uint32_t
364b6c8db9SChaoyong He nfp_mutex_unlocked(uint16_t interface)
374b6c8db9SChaoyong He {
384b6c8db9SChaoyong He 	return (uint32_t)interface << 16 | 0x0000;
394b6c8db9SChaoyong He }
404b6c8db9SChaoyong He 
414b6c8db9SChaoyong He static inline uint16_t
424b6c8db9SChaoyong He nfp_mutex_owner(uint32_t val)
434b6c8db9SChaoyong He {
444b6c8db9SChaoyong He 	return (val >> 16) & 0xffff;
454b6c8db9SChaoyong He }
464b6c8db9SChaoyong He 
474b6c8db9SChaoyong He static inline bool
484b6c8db9SChaoyong He nfp_mutex_is_locked(uint32_t val)
494b6c8db9SChaoyong He {
504b6c8db9SChaoyong He 	return (val & 0xffff) == 0x000f;
514b6c8db9SChaoyong He }
524b6c8db9SChaoyong He 
534b6c8db9SChaoyong He static inline bool
544b6c8db9SChaoyong He nfp_mutex_is_unlocked(uint32_t val)
554b6c8db9SChaoyong He {
564b6c8db9SChaoyong He 	return (val & 0xffff) == 0;
574b6c8db9SChaoyong He }
584b6c8db9SChaoyong He 
59c7e9729dSAlejandro Lucero static int
604b6c8db9SChaoyong He nfp_cpp_mutex_validate(uint16_t interface,
61d108b9e9SChaoyong He 		int *target,
62c69debceSChaoyong He 		uint64_t address)
63c7e9729dSAlejandro Lucero {
644b6c8db9SChaoyong He 	/* Not permitted on invalid interfaces */
654b6c8db9SChaoyong He 	if (NFP_CPP_INTERFACE_TYPE_of(interface) == NFP_CPP_INTERFACE_TYPE_INVALID)
664b6c8db9SChaoyong He 		return -EINVAL;
674b6c8db9SChaoyong He 
68c7e9729dSAlejandro Lucero 	/* Address must be 64-bit aligned */
694aa75cadSChaoyong He 	if ((address & 7) != 0)
70b29d5df4SChaoyong He 		return -EINVAL;
71c7e9729dSAlejandro Lucero 
72c7e9729dSAlejandro Lucero 	if (*target != NFP_CPP_TARGET_MU)
73b29d5df4SChaoyong He 		return -EINVAL;
74c7e9729dSAlejandro Lucero 
75c7e9729dSAlejandro Lucero 	return 0;
76c7e9729dSAlejandro Lucero }
77c7e9729dSAlejandro Lucero 
786d03aa61SChaoyong He /**
79c7e9729dSAlejandro Lucero  * Initialize a mutex location
80c7e9729dSAlejandro Lucero  *
81c7e9729dSAlejandro Lucero  * The CPP target:address must point to a 64-bit aligned location, and
82c7e9729dSAlejandro Lucero  * will initialize 64 bits of data at the location.
83c7e9729dSAlejandro Lucero  *
84c7e9729dSAlejandro Lucero  * This creates the initial mutex state, as locked by this
85c7e9729dSAlejandro Lucero  * nfp_cpp_interface().
86c7e9729dSAlejandro Lucero  *
87c7e9729dSAlejandro Lucero  * This function should only be called when setting up
88c7e9729dSAlejandro Lucero  * the initial lock state upon boot-up of the system.
89c7e9729dSAlejandro Lucero  *
906d03aa61SChaoyong He  * @param cpp
916d03aa61SChaoyong He  *   NFP CPP handle
926d03aa61SChaoyong He  * @param target
936d03aa61SChaoyong He  *   NFP CPP target ID (ie NFP_CPP_TARGET_CLS or NFP_CPP_TARGET_MU)
946d03aa61SChaoyong He  * @param address
956d03aa61SChaoyong He  *   Offset into the address space of the NFP CPP target ID
966d03aa61SChaoyong He  * @param key
976d03aa61SChaoyong He  *   Unique 32-bit value for this mutex
98c7e9729dSAlejandro Lucero  *
996d03aa61SChaoyong He  * @return
1006d03aa61SChaoyong He  *   0 on success, or negative value on failure
101c7e9729dSAlejandro Lucero  */
102c7e9729dSAlejandro Lucero int
103d108b9e9SChaoyong He nfp_cpp_mutex_init(struct nfp_cpp *cpp,
104d108b9e9SChaoyong He 		int target,
105c69debceSChaoyong He 		uint64_t address,
106c7e9729dSAlejandro Lucero 		uint32_t key)
107c7e9729dSAlejandro Lucero {
108610bf14bSChaoyong He 	int err;
109c7e9729dSAlejandro Lucero 	uint32_t muw = NFP_CPP_ID(target, 4, 0);    /* atomic_write */
1104b6c8db9SChaoyong He 	uint16_t interface = nfp_cpp_interface(cpp);
111c7e9729dSAlejandro Lucero 
1124b6c8db9SChaoyong He 	err = nfp_cpp_mutex_validate(interface, &target, address);
113c7e9729dSAlejandro Lucero 	if (err < 0)
114c7e9729dSAlejandro Lucero 		return err;
115c7e9729dSAlejandro Lucero 
116c7e9729dSAlejandro Lucero 	err = nfp_cpp_writel(cpp, muw, address + 4, key);
117c7e9729dSAlejandro Lucero 	if (err < 0)
118c7e9729dSAlejandro Lucero 		return err;
119c7e9729dSAlejandro Lucero 
1204b6c8db9SChaoyong He 	err = nfp_cpp_writel(cpp, muw, address, nfp_mutex_locked(interface));
121c7e9729dSAlejandro Lucero 	if (err < 0)
122c7e9729dSAlejandro Lucero 		return err;
123c7e9729dSAlejandro Lucero 
124c7e9729dSAlejandro Lucero 	return 0;
125c7e9729dSAlejandro Lucero }
126c7e9729dSAlejandro Lucero 
1276d03aa61SChaoyong He /**
128c7e9729dSAlejandro Lucero  * Create a mutex handle from an address controlled by a MU Atomic engine
129c7e9729dSAlejandro Lucero  *
130c7e9729dSAlejandro Lucero  * The CPP target:address must point to a 64-bit aligned location, and
131c7e9729dSAlejandro Lucero  * reserve 64 bits of data at the location for use by the handle.
132c7e9729dSAlejandro Lucero  *
133c7e9729dSAlejandro Lucero  * Only target/address pairs that point to entities that support the
134c7e9729dSAlejandro Lucero  * MU Atomic Engine are supported.
135c7e9729dSAlejandro Lucero  *
1366d03aa61SChaoyong He  * @param cpp
1376d03aa61SChaoyong He  *   NFP CPP handle
1386d03aa61SChaoyong He  * @param target
1396d03aa61SChaoyong He  *   NFP CPP target ID (ie NFP_CPP_TARGET_CLS or NFP_CPP_TARGET_MU)
1406d03aa61SChaoyong He  * @param address
1416d03aa61SChaoyong He  *   Offset into the address space of the NFP CPP target ID
1426d03aa61SChaoyong He  * @param key
1436d03aa61SChaoyong He  *   32-bit unique key (must match the key at this location)
144c7e9729dSAlejandro Lucero  *
1456d03aa61SChaoyong He  * @return
1466d03aa61SChaoyong He  *   A non-NULL struct nfp_cpp_mutex * on success, NULL on failure.
147c7e9729dSAlejandro Lucero  */
148c7e9729dSAlejandro Lucero struct nfp_cpp_mutex *
149d108b9e9SChaoyong He nfp_cpp_mutex_alloc(struct nfp_cpp *cpp,
150d108b9e9SChaoyong He 		int target,
151c69debceSChaoyong He 		uint64_t address,
152d108b9e9SChaoyong He 		uint32_t key)
153c7e9729dSAlejandro Lucero {
154c7e9729dSAlejandro Lucero 	int err;
155c7e9729dSAlejandro Lucero 	uint32_t tmp;
156610bf14bSChaoyong He 	struct nfp_cpp_mutex *mutex;
157610bf14bSChaoyong He 	uint32_t mur = NFP_CPP_ID(target, 3, 0);    /* atomic_read */
1584b6c8db9SChaoyong He 	uint16_t interface = nfp_cpp_interface(cpp);
159c7e9729dSAlejandro Lucero 
1604b6c8db9SChaoyong He 	err = nfp_cpp_mutex_validate(interface, &target, address);
161c7e9729dSAlejandro Lucero 	if (err < 0)
162c7e9729dSAlejandro Lucero 		return NULL;
163c7e9729dSAlejandro Lucero 
164c7e9729dSAlejandro Lucero 	err = nfp_cpp_readl(cpp, mur, address + 4, &tmp);
165c7e9729dSAlejandro Lucero 	if (err < 0)
166c7e9729dSAlejandro Lucero 		return NULL;
167c7e9729dSAlejandro Lucero 
168c7e9729dSAlejandro Lucero 	if (tmp != key)
169b29d5df4SChaoyong He 		return NULL;
170c7e9729dSAlejandro Lucero 
1710352f47aSFerruh Yigit 	mutex = calloc(1, sizeof(*mutex));
172cbcbfd73SJames Hershaw 	if (mutex == NULL)
173b29d5df4SChaoyong He 		return NULL;
174c7e9729dSAlejandro Lucero 
175c7e9729dSAlejandro Lucero 	mutex->cpp = cpp;
176c7e9729dSAlejandro Lucero 	mutex->target = target;
177c7e9729dSAlejandro Lucero 	mutex->address = address;
178c7e9729dSAlejandro Lucero 	mutex->key = key;
179c7e9729dSAlejandro Lucero 	mutex->depth = 0;
180c7e9729dSAlejandro Lucero 
181c7e9729dSAlejandro Lucero 	return mutex;
182c7e9729dSAlejandro Lucero }
183c7e9729dSAlejandro Lucero 
1846d03aa61SChaoyong He /**
185c7e9729dSAlejandro Lucero  * Free a mutex handle - does not alter the lock state
186c7e9729dSAlejandro Lucero  *
1876d03aa61SChaoyong He  * @param mutex
1886d03aa61SChaoyong He  *   NFP CPP Mutex handle
189c7e9729dSAlejandro Lucero  */
190c7e9729dSAlejandro Lucero void
191c7e9729dSAlejandro Lucero nfp_cpp_mutex_free(struct nfp_cpp_mutex *mutex)
192c7e9729dSAlejandro Lucero {
193c7e9729dSAlejandro Lucero 	free(mutex);
194c7e9729dSAlejandro Lucero }
195c7e9729dSAlejandro Lucero 
1966d03aa61SChaoyong He /**
197c7e9729dSAlejandro Lucero  * Lock a mutex handle, using the NFP MU Atomic Engine
198c7e9729dSAlejandro Lucero  *
1996d03aa61SChaoyong He  * @param mutex
2006d03aa61SChaoyong He  *   NFP CPP Mutex handle
201c7e9729dSAlejandro Lucero  *
2026d03aa61SChaoyong He  * @return
2036d03aa61SChaoyong He  *   0 on success, or negative value on failure.
204c7e9729dSAlejandro Lucero  */
205c7e9729dSAlejandro Lucero int
206c7e9729dSAlejandro Lucero nfp_cpp_mutex_lock(struct nfp_cpp_mutex *mutex)
207c7e9729dSAlejandro Lucero {
208c7e9729dSAlejandro Lucero 	int err;
209c7e9729dSAlejandro Lucero 	time_t warn_at = time(NULL) + 15;
210c7e9729dSAlejandro Lucero 
211c7e9729dSAlejandro Lucero 	while ((err = nfp_cpp_mutex_trylock(mutex)) != 0) {
212b29d5df4SChaoyong He 		/* If err != -EBUSY, then the lock was damaged */
213b29d5df4SChaoyong He 		if (err < 0 && err != -EBUSY)
214c7e9729dSAlejandro Lucero 			return err;
215f842b01aSChaoyong He 
216c7e9729dSAlejandro Lucero 		if (time(NULL) >= warn_at) {
217efa766e1SChaoyong He 			PMD_DRV_LOG(WARNING, "Waiting for NFP mutex...");
218c7e9729dSAlejandro Lucero 			warn_at = time(NULL) + 60;
219c7e9729dSAlejandro Lucero 		}
220f842b01aSChaoyong He 
221c7e9729dSAlejandro Lucero 		sched_yield();
222c7e9729dSAlejandro Lucero 	}
223f842b01aSChaoyong He 
224c7e9729dSAlejandro Lucero 	return 0;
225c7e9729dSAlejandro Lucero }
226c7e9729dSAlejandro Lucero 
2276d03aa61SChaoyong He /**
228c7e9729dSAlejandro Lucero  * Unlock a mutex handle, using the NFP MU Atomic Engine
229c7e9729dSAlejandro Lucero  *
2306d03aa61SChaoyong He  * @param mutex
2316d03aa61SChaoyong He  *   NFP CPP Mutex handle
232c7e9729dSAlejandro Lucero  *
2336d03aa61SChaoyong He  * @return
2346d03aa61SChaoyong He  *   0 on success, or negative value on failure
235c7e9729dSAlejandro Lucero  */
236c7e9729dSAlejandro Lucero int
237c7e9729dSAlejandro Lucero nfp_cpp_mutex_unlock(struct nfp_cpp_mutex *mutex)
238c7e9729dSAlejandro Lucero {
239610bf14bSChaoyong He 	int err;
240610bf14bSChaoyong He 	uint32_t key;
241610bf14bSChaoyong He 	uint32_t value;
242610bf14bSChaoyong He 	struct nfp_cpp *cpp = mutex->cpp;
243610bf14bSChaoyong He 	uint16_t interface = nfp_cpp_interface(cpp);
244c7e9729dSAlejandro Lucero 	uint32_t muw = NFP_CPP_ID(mutex->target, 4, 0);    /* atomic_write */
245c7e9729dSAlejandro Lucero 	uint32_t mur = NFP_CPP_ID(mutex->target, 3, 0);    /* atomic_read */
246c7e9729dSAlejandro Lucero 
247c7e9729dSAlejandro Lucero 	if (mutex->depth > 1) {
248c7e9729dSAlejandro Lucero 		mutex->depth--;
249c7e9729dSAlejandro Lucero 		return 0;
250c7e9729dSAlejandro Lucero 	}
251c7e9729dSAlejandro Lucero 
252c7e9729dSAlejandro Lucero 	err = nfp_cpp_readl(mutex->cpp, mur, mutex->address + 4, &key);
253c7e9729dSAlejandro Lucero 	if (err < 0)
2544b6c8db9SChaoyong He 		return err;
255c7e9729dSAlejandro Lucero 
2564b6c8db9SChaoyong He 	if (key != mutex->key)
2574b6c8db9SChaoyong He 		return -EPERM;
258c7e9729dSAlejandro Lucero 
2594b6c8db9SChaoyong He 	err = nfp_cpp_readl(mutex->cpp, mur, mutex->address, &value);
260c7e9729dSAlejandro Lucero 	if (err < 0)
2614b6c8db9SChaoyong He 		return err;
2624b6c8db9SChaoyong He 
2634b6c8db9SChaoyong He 	if (value != nfp_mutex_locked(interface))
2644b6c8db9SChaoyong He 		return -EACCES;
2654b6c8db9SChaoyong He 
2664b6c8db9SChaoyong He 	err = nfp_cpp_writel(cpp, muw, mutex->address,
2674b6c8db9SChaoyong He 			nfp_mutex_unlocked(interface));
2684b6c8db9SChaoyong He 	if (err < 0)
2694b6c8db9SChaoyong He 		return err;
270c7e9729dSAlejandro Lucero 
271c7e9729dSAlejandro Lucero 	mutex->depth = 0;
272c7e9729dSAlejandro Lucero 
2734b6c8db9SChaoyong He 	return 0;
274c7e9729dSAlejandro Lucero }
275c7e9729dSAlejandro Lucero 
2766d03aa61SChaoyong He /**
277c7e9729dSAlejandro Lucero  * Attempt to lock a mutex handle, using the NFP MU Atomic Engine
278c7e9729dSAlejandro Lucero  *
279c7e9729dSAlejandro Lucero  * Valid lock states:
280c7e9729dSAlejandro Lucero  *      0x....0000      - Unlocked
281c7e9729dSAlejandro Lucero  *      0x....000f      - Locked
282c7e9729dSAlejandro Lucero  *
2836d03aa61SChaoyong He  * @param mutex
2846d03aa61SChaoyong He  *   NFP CPP Mutex handle
2856d03aa61SChaoyong He  *
2866d03aa61SChaoyong He  * @return
2876d03aa61SChaoyong He  *   0 if the lock succeeded, negative value on failure.
288c7e9729dSAlejandro Lucero  */
289c7e9729dSAlejandro Lucero int
290c7e9729dSAlejandro Lucero nfp_cpp_mutex_trylock(struct nfp_cpp_mutex *mutex)
291c7e9729dSAlejandro Lucero {
292610bf14bSChaoyong He 	int err;
293610bf14bSChaoyong He 	uint32_t key;
294610bf14bSChaoyong He 	uint32_t tmp;
295610bf14bSChaoyong He 	uint32_t value;
296610bf14bSChaoyong He 	struct nfp_cpp *cpp = mutex->cpp;
297c7e9729dSAlejandro Lucero 	uint32_t mur = NFP_CPP_ID(mutex->target, 3, 0);    /* atomic_read */
298c7e9729dSAlejandro Lucero 	uint32_t muw = NFP_CPP_ID(mutex->target, 4, 0);    /* atomic_write */
299c7e9729dSAlejandro Lucero 	uint32_t mus = NFP_CPP_ID(mutex->target, 5, 3);    /* test_set_imm */
300c7e9729dSAlejandro Lucero 
301c7e9729dSAlejandro Lucero 	if (mutex->depth > 0) {
302c7e9729dSAlejandro Lucero 		if (mutex->depth == MUTEX_DEPTH_MAX)
303b29d5df4SChaoyong He 			return -E2BIG;
304c7e9729dSAlejandro Lucero 
305c7e9729dSAlejandro Lucero 		mutex->depth++;
306c7e9729dSAlejandro Lucero 		return 0;
307c7e9729dSAlejandro Lucero 	}
308c7e9729dSAlejandro Lucero 
309c7e9729dSAlejandro Lucero 	/* Verify that the lock marker is not damaged */
310c7e9729dSAlejandro Lucero 	err = nfp_cpp_readl(cpp, mur, mutex->address + 4, &key);
311*aa6b4a80SHuaxing Zhu 	if (err < 0) {
312*aa6b4a80SHuaxing Zhu 		PMD_DRV_LOG(ERR, "Failed to read key.");
3134b6c8db9SChaoyong He 		return err;
314*aa6b4a80SHuaxing Zhu 	}
315c7e9729dSAlejandro Lucero 
316*aa6b4a80SHuaxing Zhu 	if (key != mutex->key) {
317*aa6b4a80SHuaxing Zhu 		PMD_DRV_LOG(ERR, "Key: %x is not same with the mutex: %x.",
318*aa6b4a80SHuaxing Zhu 				key, mutex->key);
3194b6c8db9SChaoyong He 		return -EPERM;
320*aa6b4a80SHuaxing Zhu 	}
321c7e9729dSAlejandro Lucero 
322c7e9729dSAlejandro Lucero 	/*
323c7e9729dSAlejandro Lucero 	 * Compare against the unlocked state, and if true,
324c7e9729dSAlejandro Lucero 	 * write the interface id into the top 16 bits, and
325c7e9729dSAlejandro Lucero 	 * mark as locked.
326c7e9729dSAlejandro Lucero 	 */
3274b6c8db9SChaoyong He 	value = nfp_mutex_locked(nfp_cpp_interface(cpp));
328c7e9729dSAlejandro Lucero 
329c7e9729dSAlejandro Lucero 	/*
330c7e9729dSAlejandro Lucero 	 * We use test_set_imm here, as it implies a read
331c7e9729dSAlejandro Lucero 	 * of the current state, and sets the bits in the
332c7e9729dSAlejandro Lucero 	 * bytemask of the command to 1s. Since the mutex
333c7e9729dSAlejandro Lucero 	 * is guaranteed to be 64-bit aligned, the bytemask
334c7e9729dSAlejandro Lucero 	 * of this 32-bit command is ensured to be 8'b00001111,
335c7e9729dSAlejandro Lucero 	 * which implies that the lower 4 bits will be set to
336c7e9729dSAlejandro Lucero 	 * ones regardless of the initial state.
337c7e9729dSAlejandro Lucero 	 *
338c7e9729dSAlejandro Lucero 	 * Since this is a 'Readback' operation, with no Pull
339c7e9729dSAlejandro Lucero 	 * data, we can treat this as a normal Push (read)
340c7e9729dSAlejandro Lucero 	 * atomic, which returns the original value.
341c7e9729dSAlejandro Lucero 	 */
342c7e9729dSAlejandro Lucero 	err = nfp_cpp_readl(cpp, mus, mutex->address, &tmp);
343*aa6b4a80SHuaxing Zhu 	if (err < 0) {
344*aa6b4a80SHuaxing Zhu 		PMD_DRV_LOG(ERR, "Failed to read tmp.");
3454b6c8db9SChaoyong He 		return err;
346*aa6b4a80SHuaxing Zhu 	}
347c7e9729dSAlejandro Lucero 
348c7e9729dSAlejandro Lucero 	/* Was it unlocked? */
3494b6c8db9SChaoyong He 	if (nfp_mutex_is_unlocked(tmp)) {
350c7e9729dSAlejandro Lucero 		/*
351c7e9729dSAlejandro Lucero 		 * The read value can only be 0x....0000 in the unlocked state.
352c7e9729dSAlejandro Lucero 		 * If there was another contending for this lock, then
353c7e9729dSAlejandro Lucero 		 * the lock state would be 0x....000f
354c7e9729dSAlejandro Lucero 		 *
3556d03aa61SChaoyong He 		 * Write our owner ID into the lock.
356c7e9729dSAlejandro Lucero 		 * While not strictly necessary, this helps with
357c7e9729dSAlejandro Lucero 		 * debug and bookkeeping.
358c7e9729dSAlejandro Lucero 		 */
359c7e9729dSAlejandro Lucero 		err = nfp_cpp_writel(cpp, muw, mutex->address, value);
360*aa6b4a80SHuaxing Zhu 		if (err < 0) {
361*aa6b4a80SHuaxing Zhu 			PMD_DRV_LOG(ERR, "Failed to write value.");
3624b6c8db9SChaoyong He 			return err;
363*aa6b4a80SHuaxing Zhu 		}
364c7e9729dSAlejandro Lucero 
365c7e9729dSAlejandro Lucero 		mutex->depth = 1;
3664b6c8db9SChaoyong He 		return 0;
367c7e9729dSAlejandro Lucero 	}
368c7e9729dSAlejandro Lucero 
369c7e9729dSAlejandro Lucero 	/* Already locked by us? Success! */
370c7e9729dSAlejandro Lucero 	if (tmp == value) {
371c7e9729dSAlejandro Lucero 		mutex->depth = 1;
3724b6c8db9SChaoyong He 		return 0;
373c7e9729dSAlejandro Lucero 	}
374c7e9729dSAlejandro Lucero 
3754b6c8db9SChaoyong He 	return nfp_mutex_is_locked(tmp) ? -EBUSY : -EINVAL;
3764b6c8db9SChaoyong He }
377c7e9729dSAlejandro Lucero 
3784b6c8db9SChaoyong He /**
3794b6c8db9SChaoyong He  * Release lock if held by local system.
3804b6c8db9SChaoyong He  * Extreme care is advised, call only when no local lock users can exist.
3814b6c8db9SChaoyong He  *
3824b6c8db9SChaoyong He  * @param cpp
3834b6c8db9SChaoyong He  *   NFP CPP handle
3844b6c8db9SChaoyong He  * @param target
3854b6c8db9SChaoyong He  *   NFP CPP target ID (ie NFP_CPP_TARGET_CLS or NFP_CPP_TARGET_MU)
3864b6c8db9SChaoyong He  * @param address
3874b6c8db9SChaoyong He  *   Offset into the address space of the NFP CPP target ID
3884b6c8db9SChaoyong He  *
3894b6c8db9SChaoyong He  * @return
3904b6c8db9SChaoyong He  *   - (0) if the lock was OK
3914b6c8db9SChaoyong He  *   - (1) if locked by us
3924b6c8db9SChaoyong He  *   - (-errno) on invalid mutex
3934b6c8db9SChaoyong He  */
3944b6c8db9SChaoyong He int
3954b6c8db9SChaoyong He nfp_cpp_mutex_reclaim(struct nfp_cpp *cpp,
3964b6c8db9SChaoyong He 		int target,
3974b6c8db9SChaoyong He 		uint64_t address)
3984b6c8db9SChaoyong He {
3994b6c8db9SChaoyong He 	int err;
4004b6c8db9SChaoyong He 	uint32_t tmp;
4014b6c8db9SChaoyong He 	uint16_t interface = nfp_cpp_interface(cpp);
4024b6c8db9SChaoyong He 	const uint32_t mur = NFP_CPP_ID(target, 3, 0);    /* atomic_read */
4034b6c8db9SChaoyong He 	const uint32_t muw = NFP_CPP_ID(target, 4, 0);    /* atomic_write */
4044b6c8db9SChaoyong He 
4054b6c8db9SChaoyong He 	err = nfp_cpp_mutex_validate(interface, &target, address);
4064b6c8db9SChaoyong He 	if (err != 0)
407c7e9729dSAlejandro Lucero 		return err;
4084b6c8db9SChaoyong He 
4094b6c8db9SChaoyong He 	/* Check lock */
4104b6c8db9SChaoyong He 	err = nfp_cpp_readl(cpp, mur, address, &tmp);
4114b6c8db9SChaoyong He 	if (err < 0)
4124b6c8db9SChaoyong He 		return err;
4134b6c8db9SChaoyong He 
4144b6c8db9SChaoyong He 	if (nfp_mutex_is_unlocked(tmp) || nfp_mutex_owner(tmp) != interface)
4154b6c8db9SChaoyong He 		return 0;
4164b6c8db9SChaoyong He 
4174b6c8db9SChaoyong He 	/* Bust the lock */
4184b6c8db9SChaoyong He 	err = nfp_cpp_writel(cpp, muw, address, nfp_mutex_unlocked(interface));
4194b6c8db9SChaoyong He 	if (err < 0)
4204b6c8db9SChaoyong He 		return err;
4214b6c8db9SChaoyong He 
4224b6c8db9SChaoyong He 	return 1;
423c7e9729dSAlejandro Lucero }
424