/** * hwspin_lock_request() - request an hwspinlock * * This function should be called by users of the hwspinlock device, * in order to dynamically assign them an unused hwspinlock. * Usually the user of this lock will then have to communicate the lock's id * to the remote core before it can be used for synchronization (to get the * id of a given hwlock, use hwspin_lock_get_id()). * * Should be called from a process context (might sleep) * * Returns the address of the assigned hwspinlock, or NULL on error */ struct hwspinlock *hwspin_lock_request(void) { struct hwspinlock *hwlock; int ret; mutex_lock(&hwspinlock_tree_lock); /* look for an unused lock */ ret = radix_tree_gang_lookup_tag(&hwspinlock_tree, (void **)&hwlock, 0, 1, HWSPINLOCK_UNUSED); if (ret == 0) { pr_warn("a free hwspinlock is not available\n"); hwlock = NULL; goto out; } /* sanity check that should never fail */ WARN_ON(ret > 1); /* mark as used and power up */ ret = __hwspin_lock_request(hwlock); if (ret < 0) hwlock = NULL; out: mutex_unlock(&hwspinlock_tree_lock); return hwlock; }
/** * hwspin_lock_request_specific() - request for a specific hwspinlock * @id: index of the specific hwspinlock that is requested * * This function should be called by users of the hwspinlock module, * in order to assign them a specific hwspinlock. * Usually early board code will be calling this function in order to * reserve specific hwspinlock ids for predefined purposes. * * Should be called from a process context (might sleep) * * Returns the address of the assigned hwspinlock, or NULL on error */ struct hwspinlock *hwspin_lock_request_specific(unsigned int id) { struct hwspinlock *hwlock; int ret; mutex_lock(&hwspinlock_tree_lock); /* make sure this hwspinlock exists */ hwlock = radix_tree_lookup(&hwspinlock_tree, id); if (!hwlock) { pr_warn("hwspinlock %u does not exist\n", id); goto out; } /* sanity check (this shouldn't happen) */ WARN_ON(hwlock_to_id(hwlock) != id); /* make sure this hwspinlock is unused */ ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); if (ret == 0) { pr_warn("hwspinlock %u is already in use\n", id); hwlock = NULL; goto out; } /* mark as used and power up */ ret = __hwspin_lock_request(hwlock); if (ret < 0) hwlock = NULL; out: mutex_unlock(&hwspinlock_tree_lock); return hwlock; }
/** * hwspin_lock_request() - request an hwspinlock * @lock_type: User to decide to use mutex or spinlocks * 1 to use mutex & 0 to use spinlock. If mutex is used, hwspinlock APIs can * be called from context that sleeps but cannot be called from interrupt * context. If spinlock is used the APIs can be called from any context but * the calling context cannot sleep. * * This function should be called by users of the hwspinlock device, * in order to dynamically assign them an unused hwspinlock. * Usually the user of this lock will then have to communicate the lock's id * to the remote core before it can be used for synchronization (to get the * id of a given hwlock, use hwspin_lock_get_id()). * * Should be called from a process context (might sleep) * * Returns the address of the assigned hwspinlock, or NULL on error */ struct hwspinlock *hwspin_lock_request(enum lock_type l) { struct hwspinlock *hwlock; int ret; mutex_lock(&hwspinlock_tree_lock); /* look for an unused lock */ ret = radix_tree_gang_lookup_tag(&hwspinlock_tree, (void **)&hwlock, 0, 1, HWSPINLOCK_UNUSED); if (ret == 0) { pr_warn("a free hwspinlock is not available\n"); hwlock = NULL; goto out; } /* sanity check that should never fail */ WARN_ON(ret > 1); /* mark as used and power up */ ret = __hwspin_lock_request(hwlock); if (ret < 0) { hwlock = NULL; } else { if (l == USE_MUTEX_LOCK) mutex_init(&hwlock->sw_l.mlock); else spin_lock_init(&hwlock->sw_l.slock); hwlock->tlock = l; } out: mutex_unlock(&hwspinlock_tree_lock); return hwlock; }