1 /* 2 * queue.c 3 * 4 * Copyright(c) 1998 - 2010 Texas Instruments. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name Texas Instruments nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 35 36 /** \file queue.c 37 * \brief This module provides generic queueing services, including enqueue, dequeue 38 * and requeue of any object that contains TQueNodeHdr in its structure. 39 * 40 * \see queue.h 41 */ 42 43 44 45 #define __FILE_ID__ FILE_ID_130 46 #include "report.h" 47 #include "queue.h" 48 49 50 /* Queue structure */ 51 typedef struct 52 { 53 TQueNodeHdr tHead; /* The queue first node */ 54 TI_UINT32 uCount; /* Current number of nodes in queue */ 55 TI_UINT32 uLimit; /* Upper limit of nodes in queue */ 56 TI_UINT32 uMaxCount; /* Maximum uCount value (for debug) */ 57 TI_UINT32 uOverflow; /* Number of overflow occurences - couldn't insert node (for debug) */ 58 TI_UINT32 uNodeHeaderOffset; /* Offset of NodeHeader field from the entry of the queued item */ 59 TI_HANDLE hOs; 60 TI_HANDLE hReport; 61 } TQueue; 62 63 64 65 /* 66 * INTERNAL FUNCTIONS 67 * =============================== 68 */ 69 70 71 /* 72 * InsertNode(): Insert new node between pPrev and pNext 73 */ 74 static INLINE void InsertNode( TQueNodeHdr *pNode, TQueNodeHdr *pPrev, TQueNodeHdr *pNext) 75 { 76 pNext->pPrev = pNode; 77 pNode->pNext = pNext; 78 pNode->pPrev = pPrev; 79 pPrev->pNext = pNode; 80 } 81 82 /* 83 * RemoveNode(): Remove node from between pPrev and pNext 84 */ 85 static INLINE void RemoveNode( TQueNodeHdr *pPrev, TQueNodeHdr *pNext) 86 { 87 pNext->pPrev = pPrev; 88 pPrev->pNext = pNext; 89 } 90 91 /* 92 * AddToHead(): Add node to queue head (last in queue) 93 */ 94 static INLINE void AddToHead( TQueNodeHdr *pNode, TQueNodeHdr *pListHead) 95 { 96 InsertNode (pNode, pListHead, pListHead->pNext); 97 } 98 99 /* 100 * AddToTail(): Add node to queue tail (first in queue) 101 */ 102 static INLINE void AddToTail( TQueNodeHdr *pNode, TQueNodeHdr *pListHead) 103 { 104 InsertNode( pNode, pListHead->pPrev, pListHead ); 105 } 106 107 /* 108 * DelFromTail(): Delete node from queue tail (first in queue) 109 */ 110 static INLINE void DelFromTail (TQueNodeHdr *pNode) 111 { 112 RemoveNode (pNode->pPrev, pNode->pNext); 113 } 114 115 116 117 /* 118 * EXTERNAL FUNCTIONS 119 * =============================== 120 */ 121 122 123 /** 124 * \fn que_Create 125 * \brief Create a queue. 126 * 127 * Allocate and init a queue object. 128 * 129 * \note 130 * \param hOs - Handle to Os Abstraction Layer 131 * \param hReport - Handle to report module 132 * \param uLimit - Maximum items to store in queue 133 * \param uNodeHeaderOffset - Offset of NodeHeader field from the entry of the queued item. 134 * \return Handle to the allocated queue 135 * \sa que_Destroy 136 */ 137 TI_HANDLE que_Create (TI_HANDLE hOs, TI_HANDLE hReport, TI_UINT32 uLimit, TI_UINT32 uNodeHeaderOffset) 138 { 139 TQueue *pQue; 140 141 /* allocate queue module */ 142 pQue = os_memoryAlloc (hOs, sizeof(TQueue)); 143 144 if (!pQue) 145 { 146 WLAN_OS_REPORT (("Error allocating the Queue Module\n")); 147 return NULL; 148 } 149 150 os_memoryZero (hOs, pQue, sizeof(TQueue)); 151 152 /* Intialize the queue header */ 153 pQue->tHead.pNext = pQue->tHead.pPrev = &pQue->tHead; 154 155 /* Set the Queue parameters */ 156 pQue->hOs = hOs; 157 pQue->hReport = hReport; 158 pQue->uLimit = uLimit; 159 pQue->uNodeHeaderOffset = uNodeHeaderOffset; 160 161 return (TI_HANDLE)pQue; 162 } 163 164 165 /** 166 * \fn que_Destroy 167 * \brief Destroy the queue. 168 * 169 * Free the queue memory. 170 * 171 * \note The queue's owner should first free the queued items! 172 * \param hQue - The queue object 173 * \return TI_OK on success or TI_NOK on failure 174 * \sa que_Create 175 */ 176 TI_STATUS que_Destroy (TI_HANDLE hQue) 177 { 178 TQueue *pQue = (TQueue *)hQue; 179 180 if (pQue) 181 { 182 /* Alert if the queue is unloaded before it was cleared from items */ 183 if (pQue->uCount) 184 { 185 TRACE0(pQue->hReport, REPORT_SEVERITY_WARNING, "que_Destroy() Queue Not Empty!!"); 186 } 187 /* free Queue object */ 188 os_memoryFree (pQue->hOs, pQue, sizeof(TQueue)); 189 } 190 191 return TI_OK; 192 } 193 194 195 /** 196 * \fn que_Init 197 * \brief Init required handles 198 * 199 * Init required handles. 200 * 201 * \note 202 * \param hQue - The queue object 203 * \param hOs - Handle to Os Abstraction Layer 204 * \param hReport - Handle to report module 205 * \return TI_OK on success or TI_NOK on failure 206 * \sa 207 */ 208 TI_STATUS que_Init (TI_HANDLE hQue, TI_HANDLE hOs, TI_HANDLE hReport) 209 { 210 TQueue *pQue = (TQueue *)hQue; 211 212 pQue->hOs = hOs; 213 pQue->hReport = hReport; 214 215 return TI_OK; 216 } 217 218 219 /** 220 * \fn que_Enqueue 221 * \brief Enqueue an item 222 * 223 * Enqueue an item at the queue's head (last in queue). 224 * 225 * \note 226 * \param hQue - The queue object 227 * \param hItem - Handle to queued item 228 * \return TI_OK if item was queued, or TI_NOK if not queued due to overflow 229 * \sa que_Dequeue, que_Requeue 230 */ 231 TI_STATUS que_Enqueue (TI_HANDLE hQue, TI_HANDLE hItem) 232 { 233 TQueue *pQue = (TQueue *)hQue; 234 TQueNodeHdr *pQueNodeHdr; /* the Node-Header in the given item */ 235 236 if (pQue) 237 { 238 /* Check queue limit */ 239 if(pQue->uCount < pQue->uLimit) 240 { 241 /* Find NodeHeader in the given item */ 242 pQueNodeHdr = (TQueNodeHdr *)((TI_UINT8*)hItem + pQue->uNodeHeaderOffset); 243 244 /* Verify that pNext is NULL --> Sanity check that this item is not already linked to a queue */ 245 if (pQueNodeHdr->pNext) 246 { 247 /* Not an error since we have a case where a timer may expire twice in a row (in TxDataQueue) */ 248 TRACE0(pQue->hReport, REPORT_SEVERITY_WARNING, "que_Enqueue(): Trying to enqueue an item that is already enqueued!!"); 249 return TI_NOK; 250 } 251 252 /* Enqueue item and increment items counter */ 253 AddToHead (pQueNodeHdr, &pQue->tHead); 254 pQue->uCount++; 255 256 #ifdef TI_DBG 257 if (pQue->uCount > pQue->uMaxCount) 258 { 259 pQue->uMaxCount = pQue->uCount; 260 } 261 TRACE0(pQue->hReport, REPORT_SEVERITY_INFORMATION , "que_Enqueue(): Enqueued Successfully\n"); 262 #endif 263 264 return TI_OK; 265 } 266 267 /* 268 * Queue is overflowed, return TI_NOK. 269 */ 270 #ifdef TI_DBG 271 pQue->uOverflow++; 272 TRACE0(pQue->hReport, REPORT_SEVERITY_WARNING , "que_Enqueue(): Queue Overflow\n"); 273 #endif 274 } 275 return TI_NOK; 276 } 277 278 279 /** 280 * \fn que_Dequeue 281 * \brief Dequeue an item 282 * 283 * Dequeue an item from the queue's tail (first in queue). 284 * 285 * \note 286 * \param hQue - The queue object 287 * \return pointer to dequeued item or NULL if queue is empty 288 * \sa que_Enqueue, que_Requeue 289 */ 290 TI_HANDLE que_Dequeue (TI_HANDLE hQue) 291 { 292 TQueue *pQue = (TQueue *)hQue; 293 TI_HANDLE hItem; 294 295 if (pQue) 296 { 297 if (pQue->uCount) 298 { 299 /* Queue is not empty, take packet from the queue tail */ 300 301 /* find pointer to the node entry */ 302 hItem = (TI_HANDLE)((TI_UINT8*)pQue->tHead.pPrev - pQue->uNodeHeaderOffset); 303 304 DelFromTail (pQue->tHead.pPrev); /* remove node from the queue */ 305 pQue->uCount--; 306 307 #ifdef TI_DBG 308 /* Clear the pNext so we can do a sanity check when enqueuing this structre in the future */ 309 ((TQueNodeHdr *)((TI_UINT8*)hItem + pQue->uNodeHeaderOffset))->pNext = NULL; 310 #endif 311 312 return (hItem); 313 } 314 } 315 316 /* Queue is empty */ 317 TRACE0(pQue->hReport, REPORT_SEVERITY_INFORMATION , "que_Dequeue(): Queue is empty\n"); 318 return NULL; 319 } 320 321 322 /** 323 * \fn que_Requeue 324 * \brief Requeue an item 325 * 326 * Requeue an item at the queue's tail (first in queue). 327 * 328 * \note 329 * \param hQue - The queue object 330 * \param hItem - Handle to queued item 331 * \return TI_OK if item was queued, or TI_NOK if not queued due to overflow 332 * \sa que_Enqueue, que_Dequeue 333 */ 334 TI_STATUS que_Requeue (TI_HANDLE hQue, TI_HANDLE hItem) 335 { 336 TQueue *pQue = (TQueue *)hQue; 337 TQueNodeHdr *pQueNodeHdr; /* the NodeHeader in the given item */ 338 339 /* 340 * If queue's limits not exceeded add the packet to queue's tail and return TI_OK 341 */ 342 if (pQue->uCount < pQue->uLimit) 343 { 344 /* Find NodeHeader in the given item */ 345 pQueNodeHdr = (TQueNodeHdr *)((TI_UINT8*)hItem + pQue->uNodeHeaderOffset); 346 347 /* Verify that pNext is NULL --> Sanity check that this item is not already linked to a queue */ 348 if (pQueNodeHdr->pNext) 349 { 350 TRACE0(pQue->hReport, REPORT_SEVERITY_ERROR, "que_Requeue(): Trying to Requeue an item that is already enqueued!!"); 351 return TI_NOK; 352 } 353 354 /* Enqueue item and increment items counter */ 355 AddToTail (pQueNodeHdr, &pQue->tHead); 356 pQue->uCount++; 357 358 #ifdef TI_DBG 359 if (pQue->uCount > pQue->uMaxCount) 360 pQue->uMaxCount = pQue->uCount; 361 TRACE0(pQue->hReport, REPORT_SEVERITY_INFORMATION , "que_Requeue(): Requeued successfully\n"); 362 #endif 363 364 return TI_OK; 365 } 366 367 368 /* 369 * Queue is overflowed, return TI_NOK. 370 * Note: This is not expected in the current design, since Tx packet may be requeued 371 * only right after it was dequeued in the same context so the queue can't be full. 372 */ 373 #ifdef TI_DBG 374 pQue->uOverflow++; 375 TRACE0(pQue->hReport, REPORT_SEVERITY_ERROR , "que_Requeue(): Queue Overflow\n"); 376 #endif 377 378 return TI_NOK; 379 } 380 381 382 /** 383 * \fn que_Size 384 * \brief Return queue size 385 * 386 * Return number of items in queue. 387 * 388 * \note 389 * \param hQue - The queue object 390 * \return TI_UINT32 - the items count 391 * \sa 392 */ 393 TI_UINT32 que_Size (TI_HANDLE hQue) 394 { 395 TQueue *pQue = (TQueue *)hQue; 396 397 return (pQue->uCount); 398 } 399 400 401 /** 402 * \fn que_Print 403 * \brief Print queue status 404 * 405 * Print the queue's parameters (not the content). 406 * 407 * \note 408 * \param hQue - The queue object 409 * \return void 410 * \sa 411 */ 412 413 #ifdef TI_DBG 414 415 void que_Print(TI_HANDLE hQue) 416 { 417 #ifdef REPORT_LOG 418 TQueue *pQue = (TQueue *)hQue; 419 420 WLAN_OS_REPORT(("que_Print: Count=%u MaxCount=%u Limit=%u Overflow=%u NodeHeaderOffset=%u Next=0x%x Prev=0x%x\n", 421 pQue->uCount, pQue->uMaxCount, pQue->uLimit, pQue->uOverflow, 422 pQue->uNodeHeaderOffset, pQue->tHead.pNext, pQue->tHead.pPrev)); 423 #endif 424 } 425 426 #endif /* TI_DBG */ 427