1 /* 2 * Copyright (c) 2018 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: qdf_idr 21 * This file provides the ability to map an ID to a pointer 22 */ 23 24 /* Include files */ 25 #include <qdf_idr.h> 26 #include <qdf_module.h> 27 28 #define QDF_IDR_START 0x100 29 #define QDF_IDR_END 0 30 31 static int qdf_idr_gpf_flag(void) 32 { 33 if (in_interrupt() || irqs_disabled() || in_atomic()) 34 return GFP_ATOMIC; 35 36 return GFP_KERNEL; 37 } 38 39 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) 40 /** 41 * __qdf_idr_alloc() - Allocates an unused ID 42 * @idp: pointer to qdf idr 43 * @ptr: pointer to be associated with the new ID 44 * @start: the minimum ID 45 * @end: the maximum ID 46 * 47 * Return: new ID 48 */ 49 static inline int32_t 50 __qdf_idr_alloc(qdf_idr *idp, void *ptr, int32_t start, int32_t end) 51 { 52 int32_t id = 0; 53 54 idr_get_new(&idp->idr, ptr, &id); 55 56 return id; 57 } 58 #else 59 static inline int32_t 60 __qdf_idr_alloc(qdf_idr *idp, void *ptr, int32_t start, int32_t end) 61 { 62 return idr_alloc(&idp->idr, ptr, start, end, qdf_idr_gpf_flag()); 63 } 64 #endif 65 66 QDF_STATUS qdf_idr_create(qdf_idr *idp) 67 { 68 if (!idp) 69 return QDF_STATUS_E_INVAL; 70 71 qdf_spinlock_create(&idp->lock); 72 73 idr_init(&idp->idr); 74 75 return QDF_STATUS_SUCCESS; 76 } 77 78 qdf_export_symbol(qdf_idr_create); 79 80 QDF_STATUS qdf_idr_destroy(qdf_idr *idp) 81 { 82 if (!idp) 83 return QDF_STATUS_E_INVAL; 84 85 qdf_spinlock_destroy(&idp->lock); 86 idr_destroy(&idp->idr); 87 88 return QDF_STATUS_SUCCESS; 89 } 90 91 qdf_export_symbol(qdf_idr_destroy); 92 93 QDF_STATUS qdf_idr_alloc(qdf_idr *idp, void *ptr, int32_t *id) 94 { 95 int local_id; 96 97 if (!idp || !ptr) 98 return QDF_STATUS_E_INVAL; 99 100 qdf_spinlock_acquire(&idp->lock); 101 local_id = __qdf_idr_alloc(idp, ptr, QDF_IDR_START, QDF_IDR_END); 102 qdf_spinlock_release(&idp->lock); 103 if (local_id < QDF_IDR_START) 104 return QDF_STATUS_E_FAILURE; 105 106 *id = local_id; 107 108 return QDF_STATUS_SUCCESS; 109 } 110 111 qdf_export_symbol(qdf_idr_alloc); 112 113 QDF_STATUS qdf_idr_remove(qdf_idr *idp, int32_t id) 114 { 115 if (!idp || id < QDF_IDR_START) 116 return QDF_STATUS_E_INVAL; 117 118 qdf_spinlock_acquire(&idp->lock); 119 if (idr_find(&idp->idr, id)) 120 idr_remove(&idp->idr, id); 121 qdf_spinlock_release(&idp->lock); 122 123 return QDF_STATUS_SUCCESS; 124 } 125 126 qdf_export_symbol(qdf_idr_remove); 127 128 QDF_STATUS qdf_idr_find(qdf_idr *idp, int32_t id, void **ptr) 129 { 130 if (!ptr || (id < QDF_IDR_START)) 131 return QDF_STATUS_E_INVAL; 132 133 qdf_spinlock_acquire(&idp->lock); 134 *ptr = idr_find(&idp->idr, id); 135 qdf_spinlock_release(&idp->lock); 136 if (!ptr) 137 return QDF_STATUS_E_INVAL; 138 else 139 return QDF_STATUS_SUCCESS; 140 } 141 142 qdf_export_symbol(qdf_idr_find); 143 144