diff --git a/qdf/inc/qdf_idr.h b/qdf/inc/qdf_idr.h new file mode 100644 index 0000000000..7ad63aca89 --- /dev/null +++ b/qdf/inc/qdf_idr.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: qdf_idr(ID Allocation) + * QCA driver framework (QDF) ID allocation APIs + */ + +#if !defined(__QDF_IDR_H) +#define __QDF_IDR_H + +/* Include Files */ +#include +#include +#include + +/** + * qdf_idr - platform idr object + */ +typedef __qdf_idr qdf_idr; + +/** + * qdf_idr_create() - idr initialization function + * @idp: pointer to qdf idr + * + * Return: QDF status + */ +QDF_STATUS qdf_idr_create(qdf_idr *idp); + +/** + * qdf_idr_destroy() - idr deinitialization function + * @idp: pointer to qdf idr + * + * Return: QDF status + */ +QDF_STATUS qdf_idr_destroy(qdf_idr *idp); + +/** + * qdf_idr_alloc() - Allocates an unused ID + * @idp: pointer to qdf idr + * @ptr: pointer to be associated with the new ID + * @id: pointer to return new ID + * + * Return: QDF status + */ +QDF_STATUS qdf_idr_alloc(qdf_idr *idp, void *ptr, int32_t *id); + +/** + * qdf_idr_remove() - Removes this ID from the IDR. + * @idp: pointer to qdf idr + * @id: ID to be remove + * + * Return: QDF status + */ +QDF_STATUS qdf_idr_remove(qdf_idr *idp, int32_t id); + +/** + * qdf_idr_find() - find the user pointer from the IDR by id. + * @idp: pointer to qdf idr + * @id: ID to be remove + * @ptr: pointer to return user pointer for given ID + * + * Return: QDF status + */ +QDF_STATUS qdf_idr_find(qdf_idr *idp, int32_t id, void **ptr); + +#endif /* __QDF_IDR_H */ diff --git a/qdf/linux/src/i_qdf_idr.h b/qdf/linux/src/i_qdf_idr.h new file mode 100644 index 0000000000..57b56c0311 --- /dev/null +++ b/qdf/linux/src/i_qdf_idr.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: i_qdf_idr.h (ID Allocation) + * Linux-specific definitions for QDF ID Allocation API's + */ + +#if !defined(__I_QDF_IDR_H) +#define __I_QDF_IDR_H + +#include +#include + +/** + * struct __qdf_idr_s + * @lock: qdf spinlock + * @idr: idr handler + */ +struct __qdf_idr_s { + qdf_spinlock_t lock; + struct idr idr; +}; + +typedef struct __qdf_idr_s __qdf_idr; + +#endif /* __I_QDF_IDR_H */ diff --git a/qdf/linux/src/qdf_idr.c b/qdf/linux/src/qdf_idr.c new file mode 100644 index 0000000000..e6c2b7f343 --- /dev/null +++ b/qdf/linux/src/qdf_idr.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: qdf_idr + * This file provides the ability to map an ID to a pointer + */ + +/* Include files */ +#include +#include + +#define QDF_IDR_START 0x100 +#define QDF_IDR_END 0 + +static int qdf_idr_gpf_flag(void) +{ + if (in_interrupt() || irqs_disabled() || in_atomic()) + return GFP_ATOMIC; + + return GFP_KERNEL; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) +/** + * __qdf_idr_alloc() - Allocates an unused ID + * @idp: pointer to qdf idr + * @ptr: pointer to be associated with the new ID + * @start: the minimum ID + * @end: the maximum ID + * + * Return: new ID + */ +static inline int32_t +__qdf_idr_alloc(qdf_idr *idp, void *ptr, int32_t start, int32_t end) +{ + int32_t id = 0; + + idr_get_new(&idp->idr, ptr, &id); + + return id; +} +#else +static inline int32_t +__qdf_idr_alloc(qdf_idr *idp, void *ptr, int32_t start, int32_t end) +{ + return idr_alloc(&idp->idr, ptr, start, end, qdf_idr_gpf_flag()); +} +#endif + +QDF_STATUS qdf_idr_create(qdf_idr *idp) +{ + if (!idp) + return QDF_STATUS_E_INVAL; + + qdf_spinlock_create(&idp->lock); + + idr_init(&idp->idr); + + return QDF_STATUS_SUCCESS; +} + +qdf_export_symbol(qdf_idr_create); + +QDF_STATUS qdf_idr_destroy(qdf_idr *idp) +{ + if (!idp) + return QDF_STATUS_E_INVAL; + + qdf_spinlock_destroy(&idp->lock); + idr_destroy(&idp->idr); + + return QDF_STATUS_SUCCESS; +} + +qdf_export_symbol(qdf_idr_destroy); + +QDF_STATUS qdf_idr_alloc(qdf_idr *idp, void *ptr, int32_t *id) +{ + int local_id; + + if (!idp || !ptr) + return QDF_STATUS_E_INVAL; + + qdf_spinlock_acquire(&idp->lock); + local_id = __qdf_idr_alloc(idp, ptr, QDF_IDR_START, QDF_IDR_END); + qdf_spinlock_release(&idp->lock); + if (local_id < QDF_IDR_START) + return QDF_STATUS_E_FAILURE; + + *id = local_id; + + return QDF_STATUS_SUCCESS; +} + +qdf_export_symbol(qdf_idr_alloc); + +QDF_STATUS qdf_idr_remove(qdf_idr *idp, int32_t id) +{ + if (!idp || id < QDF_IDR_START) + return QDF_STATUS_E_INVAL; + + qdf_spinlock_acquire(&idp->lock); + idr_remove(&idp->idr, id); + qdf_spinlock_release(&idp->lock); + + return QDF_STATUS_SUCCESS; +} + +qdf_export_symbol(qdf_idr_remove); + +QDF_STATUS qdf_idr_find(qdf_idr *idp, int32_t id, void **ptr) +{ + if (!ptr || (id < QDF_IDR_START)) + return QDF_STATUS_E_INVAL; + + qdf_spinlock_acquire(&idp->lock); + *ptr = idr_find(&idp->idr, id); + qdf_spinlock_release(&idp->lock); + if (!ptr) + return QDF_STATUS_E_INVAL; + else + return QDF_STATUS_SUCCESS; +} + +qdf_export_symbol(qdf_idr_find); +