[6319] | 1 | /** @file wlan_mac_queue.c |
---|
| 2 | * @brief Queue Framework |
---|
| 3 | * |
---|
| 4 | * This contains code for accessing the packet queue. |
---|
| 5 | * |
---|
| 6 | * @copyright Copyright 2013-2019, Mango Communications. All rights reserved. |
---|
| 7 | * Distributed under the Mango Communications Reference Design License |
---|
| 8 | * See LICENSE.txt included in the design archive or |
---|
| 9 | * at http://mangocomm.com/802.11/license |
---|
| 10 | * |
---|
| 11 | * This file is part of the Mango 802.11 Reference Design (https://mangocomm.com/802.11) |
---|
| 12 | */ |
---|
| 13 | |
---|
| 14 | /***************************** Include Files *********************************/ |
---|
| 15 | |
---|
| 16 | #include "wlan_mac_high_sw_config.h" |
---|
| 17 | |
---|
| 18 | // Xilinx / Standard library includes |
---|
| 19 | #include "xil_types.h" |
---|
| 20 | #include "stdlib.h" |
---|
| 21 | #include "stdio.h" |
---|
| 22 | #include "wlan_platform_high.h" |
---|
| 23 | #include "string.h" |
---|
| 24 | |
---|
| 25 | // WLAN includes |
---|
| 26 | #include "wlan_mac_common.h" |
---|
| 27 | #include "wlan_mac_high.h" |
---|
| 28 | #include "wlan_mac_queue.h" |
---|
| 29 | #include "wlan_mac_dl_list.h" |
---|
| 30 | #include "wlan_mac_eth_util.h" |
---|
| 31 | #include "wlan_mac_pkt_buf_util.h" |
---|
| 32 | #include "wlan_platform_common.h" |
---|
| 33 | #include "wlan_mac_station_info.h" |
---|
| 34 | |
---|
| 35 | // WLAN Exp includes |
---|
| 36 | #include "wlan_exp_common.h" |
---|
| 37 | |
---|
| 38 | #define ADDRESS_SAFETY_CHECKS 0 |
---|
| 39 | |
---|
| 40 | |
---|
| 41 | /************************** Locally Scoped Types *************************************/ |
---|
| 42 | typedef struct _queue_t { |
---|
| 43 | dl_list list; |
---|
| 44 | u32 flags; |
---|
| 45 | function_ptr_t queue_state_change_callback; |
---|
| 46 | u32 callback_arg; |
---|
| 47 | u32 max_len; |
---|
| 48 | } _queue_t; |
---|
| 49 | |
---|
| 50 | #define _QUEUE_FLAGS_OPEN 0x00000001 |
---|
| 51 | |
---|
| 52 | /********************** Externed Global Variable Definitions *************************/ |
---|
| 53 | |
---|
| 54 | // User callback to see if the higher-level framework can send a packet to |
---|
| 55 | // the lower-level framework to be transmitted. |
---|
| 56 | extern platform_common_dev_info_t platform_common_dev_info; |
---|
| 57 | extern platform_high_dev_info_t platform_high_dev_info; |
---|
| 58 | |
---|
| 59 | /**************** Locally Scoped Global Variable Definitions *************************/ |
---|
| 60 | |
---|
| 61 | // List to hold all of the empty, free entries |
---|
| 62 | static dl_list _free_queue; |
---|
| 63 | |
---|
| 64 | // The queue_array variable is an array of lists that will be filled with queue |
---|
| 65 | // entries from the free_queue list |
---|
| 66 | // |
---|
| 67 | // NOTE: This implementation sparsely packs the queue_array array to allow fast |
---|
| 68 | // indexing at the cost of some wasted memory. |
---|
| 69 | |
---|
| 70 | static _queue_t* _queue_array; |
---|
| 71 | static u16 _num_queues; |
---|
| 72 | |
---|
| 73 | // Total number of queue entries |
---|
| 74 | static volatile u32 _total_queue_entries; |
---|
| 75 | |
---|
| 76 | /*****************************************************************************/ |
---|
| 77 | /** |
---|
| 78 | * @brief Initialize the queue framework |
---|
| 79 | * |
---|
| 80 | * The number of queue elements we can initialize is limited by the smaller of two values: |
---|
| 81 | * (1) The number of dl_entry structs we can squeeze into QUEUE_DL_ENTRY_MEM_SIZE |
---|
| 82 | * (2) The number of QUEUE_BUFFER_SIZE MPDU buffers we can squeeze into QUEUE_BUFFER_SIZE |
---|
| 83 | * |
---|
| 84 | * @param u8 dram_present - Flag to indicate if DRAM is present |
---|
| 85 | * (1 = present; other = not present) |
---|
| 86 | * |
---|
| 87 | *****************************************************************************/ |
---|
| 88 | void queue_init() { |
---|
| 89 | u32 i; |
---|
| 90 | dl_entry* dl_entry_base; |
---|
| 91 | |
---|
| 92 | // Set the total number of supported queue entries |
---|
| 93 | _total_queue_entries = WLAN_MIN((QUEUE_DL_ENTRY_MEM_SIZE / sizeof(dl_entry)), // Max dl_entry |
---|
| 94 | (QUEUE_BUFFER_SIZE / QUEUE_ELEMENT_SIZE)); // Max buffers |
---|
| 95 | |
---|
| 96 | // Initialize the queue_array |
---|
| 97 | // NOTE: queue_array is initially NULL because it will be dynamically allocated and |
---|
| 98 | // initialized. |
---|
| 99 | // |
---|
| 100 | _queue_array = NULL; |
---|
| 101 | _num_queues = 0; |
---|
| 102 | |
---|
| 103 | // Initialize the free queue |
---|
| 104 | dl_list_init(&_free_queue); |
---|
| 105 | |
---|
| 106 | // Zero all queue elements |
---|
| 107 | bzero((void*)QUEUE_BUFFER_BASE, QUEUE_BUFFER_SIZE); |
---|
| 108 | |
---|
| 109 | // Allocate the memory space into queue entries |
---|
| 110 | // |
---|
| 111 | // All queue entries are initially part of the free queue. Each queue entry consists of: |
---|
| 112 | // (1) Buffer to hold data |
---|
| 113 | // (2) dl_entry to describe the buffer |
---|
| 114 | // |
---|
| 115 | // NOTE: The code below exploits the fact that the starting state of all queue entries is |
---|
| 116 | // sequential. Therefore, it can use matrix addressing. Matrix addressing is not safe |
---|
| 117 | // once the queue is used and the insert/remove helper functions should be used instead. |
---|
| 118 | // |
---|
| 119 | dl_entry_base = (dl_entry*)(QUEUE_DL_ENTRY_MEM_BASE); |
---|
| 120 | |
---|
| 121 | for (i = 0; i < _total_queue_entries; i++) { |
---|
| 122 | // Segment the buffer in QUEUE_BUFFER_SIZE pieces |
---|
| 123 | dl_entry_base[i].data = (void*)(QUEUE_BUFFER_BASE + (i * QUEUE_ELEMENT_SIZE)); |
---|
| 124 | |
---|
| 125 | // Copy the pointer to the dl_entry into the DRAM payload. This will allow any context |
---|
| 126 | // (like Ethernet Rx) to find the dl_entry that points to a given DRAM payload |
---|
| 127 | ((pkt_queue_buffer_t*)(dl_entry_base[i].data))->pyld_queue_hdr.dle = &(dl_entry_base[i]); |
---|
| 128 | |
---|
| 129 | // Insert new dl_entry into the free queue |
---|
| 130 | dl_entry_insertEnd(&_free_queue, &(dl_entry_base[i])); |
---|
| 131 | } |
---|
| 132 | |
---|
| 133 | // Print status |
---|
| 134 | xil_printf("Allocated %d queue buffers in DRAM using %d kB\n", _total_queue_entries, |
---|
| 135 | ((_total_queue_entries * QUEUE_ELEMENT_SIZE) / 1024)); |
---|
| 136 | } |
---|
| 137 | |
---|
| 138 | /*****************************************************************************/ |
---|
| 139 | /** |
---|
| 140 | * @brief Open a queue |
---|
| 141 | * |
---|
| 142 | * This function will open a queue and return a QID that can be used by the |
---|
| 143 | * calling context to enqueue and dequeue items. |
---|
| 144 | * |
---|
| 145 | * @param function_ptr_t queue_state_change_callback - function that the framework |
---|
| 146 | * should call when the newly-opened queue transitions from empty to |
---|
| 147 | * non-empty or vice versa |
---|
| 148 | * |
---|
| 149 | * @param u32 callback_arg - argument provided to callback |
---|
| 150 | * |
---|
| 151 | * @param u32 max_len - maximum length of queue. 0 means unlimited. |
---|
| 152 | * |
---|
| 153 | * @return int -1 if error, QID otherwise |
---|
| 154 | * |
---|
| 155 | *****************************************************************************/ |
---|
| 156 | int queue_open(function_ptr_t queue_state_change_callback, u32 callback_arg, u32 max_len){ |
---|
| 157 | u32 i; |
---|
| 158 | |
---|
| 159 | // First, we will search through the existing array to see if any queues |
---|
| 160 | // have been closed and can be re-used |
---|
| 161 | |
---|
| 162 | for(i = 0; i < _num_queues; i++){ |
---|
| 163 | if( (_queue_array[i].flags & _QUEUE_FLAGS_OPEN) == 0){ |
---|
| 164 | _queue_array[i].flags |= _QUEUE_FLAGS_OPEN; |
---|
| 165 | _queue_array[i].queue_state_change_callback = queue_state_change_callback; |
---|
| 166 | _queue_array[i].callback_arg = callback_arg; |
---|
| 167 | _queue_array[i].max_len = max_len; |
---|
| 168 | return i; |
---|
| 169 | } |
---|
| 170 | } |
---|
| 171 | |
---|
| 172 | // Otherwise, we need to reallocate the array to make a new queue |
---|
| 173 | |
---|
| 174 | _queue_array = wlan_mac_high_realloc(_queue_array, ((_num_queues + 1) * sizeof(_queue_t))); |
---|
| 175 | |
---|
| 176 | if(_queue_array == NULL){ |
---|
| 177 | xil_printf("Queue error: Unable to reallocate queue array. Check heap usage\n"); |
---|
| 178 | return WLAN_FAILURE; |
---|
| 179 | } |
---|
| 180 | |
---|
| 181 | i = _num_queues; |
---|
| 182 | |
---|
| 183 | // Increment the number of queues |
---|
| 184 | _num_queues++; |
---|
| 185 | |
---|
| 186 | |
---|
| 187 | // Initialize the dl_list in the newly allocated space |
---|
| 188 | dl_list_init(&(_queue_array[i].list)); |
---|
| 189 | |
---|
| 190 | // Set queue metadata |
---|
| 191 | _queue_array[i].flags |= _QUEUE_FLAGS_OPEN; |
---|
| 192 | _queue_array[i].queue_state_change_callback = queue_state_change_callback; |
---|
| 193 | _queue_array[i].callback_arg = callback_arg; |
---|
| 194 | _queue_array[i].max_len = max_len; |
---|
| 195 | |
---|
| 196 | // Return the new QID (which is 0 indexed, so it is length-1) |
---|
| 197 | return (i); |
---|
| 198 | } |
---|
| 199 | |
---|
| 200 | /*****************************************************************************/ |
---|
| 201 | /** |
---|
| 202 | * @brief Set maximum queue length |
---|
| 203 | * |
---|
| 204 | * This function will set a new maximum queue length in the provided queue. |
---|
| 205 | * |
---|
| 206 | * @param u32 max_len - maximum length of queue |
---|
| 207 | * |
---|
| 208 | * @return int WLAN_SUCCESS or WLAN_FAILURE |
---|
| 209 | * |
---|
| 210 | *****************************************************************************/ |
---|
| 211 | int queue_set_max_len(int queue_id, u32 max_len){ |
---|
| 212 | if ((queue_id + 1) > _num_queues) { |
---|
| 213 | xil_printf("ERROR (queue_set_max_len): queue_id %d out of range\n", queue_id); |
---|
| 214 | return WLAN_FAILURE; |
---|
| 215 | } |
---|
| 216 | |
---|
| 217 | _queue_array[queue_id].max_len = max_len; |
---|
| 218 | |
---|
| 219 | return WLAN_SUCCESS; |
---|
| 220 | } |
---|
| 221 | |
---|
| 222 | /*****************************************************************************/ |
---|
| 223 | /** |
---|
| 224 | * @brief Close a queue |
---|
| 225 | * |
---|
| 226 | * This function will close the provided QID so it can be re-opened in the future. |
---|
| 227 | * This function will return an error if the queue has occupancy. It will not |
---|
| 228 | * implicitly purge the contents of the queue. |
---|
| 229 | * |
---|
| 230 | * @param int queue_id - queue selection index (returned from queue_open) |
---|
| 231 | * |
---|
| 232 | * @return int WLAN_SUCCESS or WLAN_FAILURE |
---|
| 233 | * |
---|
| 234 | *****************************************************************************/ |
---|
| 235 | int queue_close(int queue_id){ |
---|
| 236 | if ((queue_id + 1) > _num_queues) { |
---|
| 237 | xil_printf("ERROR (queue_close): queue_id %d out of range\n", queue_id); |
---|
| 238 | return WLAN_FAILURE; |
---|
| 239 | } |
---|
| 240 | |
---|
| 241 | if (_queue_array[queue_id].list.length != 0){ |
---|
| 242 | xil_printf("Queue error: Unable to close queue_id %d because\n", queue_id); |
---|
| 243 | xil_printf(" list has %d elements that would be leaked\n", _queue_array[queue_id].list.length); |
---|
| 244 | return WLAN_FAILURE; |
---|
| 245 | } |
---|
| 246 | |
---|
| 247 | // Lower the QUEUE_FLAGS_OPEN flag so this QID can be re-used in the future |
---|
| 248 | _queue_array[queue_id].flags = (_queue_array[queue_id].flags & ~_QUEUE_FLAGS_OPEN); |
---|
| 249 | |
---|
| 250 | return WLAN_SUCCESS; |
---|
| 251 | } |
---|
| 252 | |
---|
| 253 | /*****************************************************************************/ |
---|
| 254 | /** |
---|
| 255 | * @brief Check if enqueue is allowed |
---|
| 256 | * |
---|
| 257 | * @param int queue_id - queue selection index (returned from queue_open) |
---|
| 258 | * |
---|
| 259 | * @return u8 1 if allowed, 0 otherwise |
---|
| 260 | * |
---|
| 261 | *****************************************************************************/ |
---|
| 262 | u8 queue_enqueue_allowed(int queue_id){ |
---|
| 263 | if ((queue_id + 1) > _num_queues) { |
---|
| 264 | return 0; |
---|
| 265 | } |
---|
| 266 | |
---|
| 267 | if ((_queue_array[queue_id].flags & _QUEUE_FLAGS_OPEN) == 0){ |
---|
| 268 | return 0; |
---|
| 269 | } |
---|
| 270 | |
---|
| 271 | if ((queue_length(queue_id) >= _queue_array[queue_id].max_len) && (_queue_array[queue_id].max_len != 0)){ |
---|
| 272 | return 0; |
---|
| 273 | } |
---|
| 274 | |
---|
| 275 | return 1; |
---|
| 276 | } |
---|
| 277 | |
---|
| 278 | /*****************************************************************************/ |
---|
| 279 | /** |
---|
| 280 | * @brief Total number of queue entries |
---|
| 281 | * |
---|
| 282 | * This is the sum of all free and occupied queue entries |
---|
| 283 | * |
---|
| 284 | * @return u32 |
---|
| 285 | * |
---|
| 286 | *****************************************************************************/ |
---|
| 287 | u32 queue_total_size(){ |
---|
| 288 | return _total_queue_entries; |
---|
| 289 | } |
---|
| 290 | |
---|
| 291 | |
---|
| 292 | |
---|
| 293 | /*****************************************************************************/ |
---|
| 294 | /** |
---|
| 295 | * @brief Number of free queue entries |
---|
| 296 | * |
---|
| 297 | * @return u32 |
---|
| 298 | * |
---|
| 299 | *****************************************************************************/ |
---|
| 300 | u32 queue_num_free(){ |
---|
| 301 | return _free_queue.length; |
---|
| 302 | } |
---|
| 303 | |
---|
| 304 | |
---|
| 305 | |
---|
| 306 | /*****************************************************************************/ |
---|
| 307 | /** |
---|
| 308 | * @brief Number of queue entries in a given queue |
---|
| 309 | * |
---|
| 310 | * @param u16 queue_id - ID of the queue |
---|
| 311 | * |
---|
| 312 | * @return u32 |
---|
| 313 | * |
---|
| 314 | *****************************************************************************/ |
---|
| 315 | u32 queue_length(u16 queue_id){ |
---|
| 316 | if((queue_id+1) > _num_queues){ |
---|
| 317 | return 0; |
---|
| 318 | } else { |
---|
| 319 | return _queue_array[queue_id].list.length; |
---|
| 320 | } |
---|
| 321 | } |
---|
| 322 | |
---|
| 323 | /*****************************************************************************/ |
---|
| 324 | /** |
---|
| 325 | * @brief Removes all queue entries in the selected queue |
---|
| 326 | * |
---|
| 327 | * This function removes all entries from the selected queue and returns them to |
---|
| 328 | * the free pool. |
---|
| 329 | * |
---|
| 330 | * Note: if any actions need to be taken by the users of the queue prior to purging, |
---|
| 331 | * it is their responsibility to do so prior to calling this function. See |
---|
| 332 | * wlan_mac_purge_wireless_tx() as an example. |
---|
| 333 | * |
---|
| 334 | * @param u16 queue_id - ID of the queue to purge |
---|
| 335 | * |
---|
| 336 | *****************************************************************************/ |
---|
| 337 | void queue_purge(u16 queue_id){ |
---|
| 338 | u32 num_queued; |
---|
| 339 | u32 i; |
---|
| 340 | dl_entry* queue_entry; |
---|
| 341 | volatile interrupt_state_t prev_interrupt_state; |
---|
| 342 | |
---|
| 343 | num_queued = queue_length(queue_id); |
---|
| 344 | |
---|
| 345 | if (num_queued > 0) { |
---|
| 346 | #if WLAN_SW_CONFIG_ENABLE_WLAN_EXP |
---|
| 347 | wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_queue, "Purging %d packets from queue %d\n", num_queued, queue_id); |
---|
| 348 | #endif |
---|
| 349 | |
---|
| 350 | // NOTE: There is an interesting condition that can occur if an LTG is running (ie creating new TX queue |
---|
| 351 | // entries) and purge_queue is called. In this case, you have one process removing elements from the |
---|
| 352 | // queue while another process is adding elements to the queue. Therefore, purge_queue will only |
---|
| 353 | // remove a fixed number of elements from the queue (ie all queued elements at the time the function |
---|
| 354 | // is called). If purge_queue used a while loop with no checking on the number of elements removed, |
---|
| 355 | // then it could conceivably run forever. |
---|
| 356 | // |
---|
| 357 | for (i = 0; i < num_queued; i++) { |
---|
| 358 | // The queue purge is not interrupt safe |
---|
| 359 | // NOTE: Since there could be many elements in the queue, we need to toggle the interrupts |
---|
| 360 | // inside the for loop so that we do not block CPU High for an extended period of time. |
---|
| 361 | // This could result in CPU Low dropping a reception. |
---|
| 362 | // |
---|
| 363 | prev_interrupt_state = wlan_platform_intc_stop(); |
---|
| 364 | |
---|
| 365 | queue_entry = dequeue_head(queue_id); |
---|
| 366 | |
---|
| 367 | if (queue_entry){ |
---|
| 368 | queue_checkin(queue_entry); |
---|
| 369 | } |
---|
| 370 | |
---|
| 371 | // Re-enable interrupts |
---|
| 372 | wlan_platform_intc_set_state(prev_interrupt_state); |
---|
| 373 | } |
---|
| 374 | } |
---|
| 375 | } |
---|
| 376 | |
---|
| 377 | /*****************************************************************************/ |
---|
| 378 | /** |
---|
| 379 | * @brief Retrieve a packet queue buffer pointer |
---|
| 380 | * |
---|
| 381 | * Returns a pointer to a packet queue buffer at a particular index. This function |
---|
| 382 | * does not remove it from the queue. |
---|
| 383 | * |
---|
| 384 | * @param u16 queue_id - ID of the queue from which the packet will be retrieved. |
---|
| 385 | * @param u32 idx - Index into the queue. 0 represents the HEAD entry |
---|
| 386 | * |
---|
| 387 | * @return pkt_queue_buffer_t* - NULL if error, pointer to packet queue buffer otherwise |
---|
| 388 | * |
---|
| 389 | *****************************************************************************/ |
---|
| 390 | pkt_queue_buffer_t* queue_retrieve_buffer_from_index(u16 queue_id, u32 idx){ |
---|
| 391 | pkt_queue_buffer_t* ret = NULL; |
---|
| 392 | dl_entry* queue_entry; |
---|
| 393 | volatile interrupt_state_t prev_interrupt_state; |
---|
| 394 | u32 num_queued, i; |
---|
| 395 | |
---|
| 396 | if ((queue_id + 1) > _num_queues) { |
---|
| 397 | xil_printf("ERROR (queue_retrieve_buffer_from_index 1): queue_id %d out of range\n", queue_id); |
---|
| 398 | return ret; |
---|
| 399 | } |
---|
| 400 | |
---|
| 401 | if (idx > (_queue_array[queue_id].list.length - 1)) { |
---|
| 402 | xil_printf("ERROR (queue_retrieve_buffer_from_index 2): idx %d is out of range\n", idx); |
---|
| 403 | return ret; |
---|
| 404 | } |
---|
| 405 | |
---|
| 406 | prev_interrupt_state = wlan_platform_intc_stop(); |
---|
| 407 | num_queued = queue_length(queue_id); |
---|
| 408 | queue_entry = _queue_array[queue_id].list.first; |
---|
| 409 | if (num_queued > 0) { |
---|
| 410 | for (i = 0; i < num_queued; i++) { |
---|
| 411 | if(i == idx){ |
---|
| 412 | break; |
---|
| 413 | } |
---|
| 414 | queue_entry = dl_entry_next(queue_entry); |
---|
| 415 | } |
---|
| 416 | if(queue_entry) ret = (pkt_queue_buffer_t*)(queue_entry->data); |
---|
| 417 | } |
---|
| 418 | // Re-enable interrupts |
---|
| 419 | wlan_platform_intc_set_state(prev_interrupt_state); |
---|
| 420 | |
---|
| 421 | return ret; |
---|
| 422 | } |
---|
| 423 | |
---|
| 424 | /*****************************************************************************/ |
---|
| 425 | /** |
---|
| 426 | * @brief Adds a queue entry to a specified queue at the tail |
---|
| 427 | * |
---|
| 428 | * Adds the queue entry pointed to by queue_entry to the queue with ID queue_id. |
---|
| 429 | * |
---|
| 430 | * @param u16 queue_id - ID of the queue to which queue_entry is added. |
---|
| 431 | * @param dl_entry* queue_entry - Queue entry containing packet |
---|
| 432 | * |
---|
| 433 | * @return int - WLAN_SUCCESS or WLAN_FAILURE |
---|
| 434 | * |
---|
| 435 | *****************************************************************************/ |
---|
| 436 | int enqueue_tail(u16 queue_id, dl_entry* queue_entry){ |
---|
| 437 | |
---|
| 438 | #if ADDRESS_SAFETY_CHECKS |
---|
| 439 | if( ((u32)queue_entry < QUEUE_DL_ENTRY_MEM_BASE) || ((u32)queue_entry > CALC_MEM_HIGH_ADDR(QUEUE_DL_ENTRY_MEM_BASE,QUEUE_DL_ENTRY_MEM_SIZE)) ){ |
---|
| 440 | xil_printf("%s error: dl_entry @ 0x%08x out of range\n", __FUNCTION__, queue_entry); |
---|
| 441 | } |
---|
| 442 | #endif |
---|
| 443 | |
---|
| 444 | if ((queue_id + 1) > _num_queues) { |
---|
| 445 | xil_printf("Queue error: queue_id %d out of range\n", queue_id); |
---|
| 446 | return WLAN_FAILURE; |
---|
| 447 | } |
---|
| 448 | |
---|
| 449 | if ((queue_length(queue_id) >= _queue_array[queue_id].max_len) && (_queue_array[queue_id].max_len != 0)){ |
---|
| 450 | xil_printf("ERROR (enqueue_tail): queue ID %d at max occupancy (%d)\n", queue_id, _queue_array[queue_id].max_len); |
---|
| 451 | return WLAN_FAILURE; |
---|
| 452 | } |
---|
| 453 | |
---|
| 454 | interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop(); |
---|
| 455 | |
---|
| 456 | // Insert the queue entry into the dl_list representing the selected queue |
---|
| 457 | dl_entry_insertEnd(&(_queue_array[queue_id].list), (dl_entry*)queue_entry); |
---|
| 458 | |
---|
| 459 | if(_queue_array[queue_id].list.length == 1){ |
---|
| 460 | //If the queue element we just added is now the only member of this queue, we should inform |
---|
| 461 | //the top-level MAC that the queue has transitioned from empty to non-empty. |
---|
| 462 | _queue_array[queue_id].queue_state_change_callback(_queue_array[queue_id].callback_arg, 1); |
---|
| 463 | } |
---|
| 464 | |
---|
| 465 | wlan_platform_intc_set_state(curr_interrupt_state); |
---|
| 466 | |
---|
| 467 | return WLAN_SUCCESS; |
---|
| 468 | } |
---|
| 469 | |
---|
| 470 | |
---|
| 471 | /*****************************************************************************/ |
---|
| 472 | /** |
---|
| 473 | * @brief Adds a queue entry to a specified queue at the head |
---|
| 474 | * |
---|
| 475 | * Adds the queue entry pointed to by queue_entry to the queue with ID queue_id. |
---|
| 476 | * |
---|
| 477 | * @param u16 queue_id - ID of the queue to which queue_entry is added. |
---|
| 478 | * @param dl_entry* queue_entry - Queue entry containing packet |
---|
| 479 | * |
---|
| 480 | * @return int - WLAN_SUCCESS or WLAN_FAILURE |
---|
| 481 | * |
---|
| 482 | *****************************************************************************/ |
---|
| 483 | int enqueue_head(u16 queue_id, dl_entry* queue_entry){ |
---|
| 484 | |
---|
| 485 | #if ADDRESS_SAFETY_CHECKS |
---|
| 486 | if( ((u32)queue_entry < QUEUE_DL_ENTRY_MEM_BASE) || ((u32)queue_entry > CALC_MEM_HIGH_ADDR(QUEUE_DL_ENTRY_MEM_BASE,QUEUE_DL_ENTRY_MEM_SIZE)) ){ |
---|
| 487 | xil_printf("%s error: dl_entry @ 0x%08x out of range\n", __FUNCTION__, queue_entry); |
---|
| 488 | } |
---|
| 489 | #endif |
---|
| 490 | |
---|
| 491 | if ((queue_id + 1) > _num_queues) { |
---|
| 492 | xil_printf("Queue error: queue_id %d out of range\n", queue_id); |
---|
| 493 | return WLAN_FAILURE; |
---|
| 494 | } |
---|
| 495 | |
---|
| 496 | if ((queue_length(queue_id) >= _queue_array[queue_id].max_len) && (_queue_array[queue_id].max_len != 0)){ |
---|
| 497 | xil_printf("ERROR (enqueue_head): queue ID %d at max occupancy (%d)\n", queue_id, _queue_array[queue_id].max_len); |
---|
| 498 | return WLAN_FAILURE; |
---|
| 499 | } |
---|
| 500 | |
---|
| 501 | interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop(); |
---|
| 502 | |
---|
| 503 | // Insert the queue entry into the dl_list representing the selected queue |
---|
| 504 | dl_entry_insertBeginning(&(_queue_array[queue_id].list), (dl_entry*)queue_entry); |
---|
| 505 | |
---|
| 506 | if(_queue_array[queue_id].list.length == 1){ |
---|
| 507 | //If the queue element we just added is now the only member of this queue, we should inform |
---|
| 508 | //the top-level MAC that the queue has transitioned from empty to non-empty. |
---|
| 509 | _queue_array[queue_id].queue_state_change_callback(_queue_array[queue_id].callback_arg, 1); |
---|
| 510 | } |
---|
| 511 | |
---|
| 512 | wlan_platform_intc_set_state(curr_interrupt_state); |
---|
| 513 | |
---|
| 514 | return WLAN_SUCCESS; |
---|
| 515 | } |
---|
| 516 | |
---|
| 517 | |
---|
| 518 | /*****************************************************************************/ |
---|
| 519 | /** |
---|
| 520 | * @brief Removes the head entry from the specified queue |
---|
| 521 | * |
---|
| 522 | * If queue_id is not empty this function returns a queue_entry pointer |
---|
| 523 | * for the head entry in the queue. If the specified queue is empty this |
---|
| 524 | * function returns NULL. |
---|
| 525 | * |
---|
| 526 | * @param u16 queue_id - ID of the queue from which to dequeue an entry |
---|
| 527 | * |
---|
| 528 | * @return dl_entry* - Pointer to queue entry if available, |
---|
| 529 | * NULL if queue is empty |
---|
| 530 | * |
---|
| 531 | *****************************************************************************/ |
---|
| 532 | dl_entry* dequeue_head(u16 queue_id){ |
---|
| 533 | dl_entry* curr_dl_entry; |
---|
| 534 | |
---|
| 535 | interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop(); |
---|
| 536 | |
---|
| 537 | if ((queue_id + 1) > _num_queues) { |
---|
| 538 | wlan_platform_intc_set_state(curr_interrupt_state); |
---|
| 539 | return NULL; |
---|
| 540 | } else { |
---|
| 541 | if (_queue_array[queue_id].list.length == 0) { |
---|
| 542 | // Requested queue exists but is empty |
---|
| 543 | wlan_platform_intc_set_state(curr_interrupt_state); |
---|
| 544 | return NULL; |
---|
| 545 | } else { |
---|
| 546 | curr_dl_entry = (_queue_array[queue_id].list.first); |
---|
| 547 | dl_entry_remove(&_queue_array[queue_id].list, curr_dl_entry); |
---|
| 548 | |
---|
| 549 | if(_queue_array[queue_id].list.length == 0){ |
---|
| 550 | //If the queue element we just removed empties the queue, we should inform |
---|
| 551 | //the top-level MAC that the queue has transitioned from non-empty to empty. |
---|
| 552 | _queue_array[queue_id].queue_state_change_callback(_queue_array[queue_id].callback_arg, 0); |
---|
| 553 | } |
---|
| 554 | wlan_platform_intc_set_state(curr_interrupt_state); |
---|
| 555 | |
---|
| 556 | return (dl_entry *) curr_dl_entry; |
---|
| 557 | } |
---|
| 558 | } |
---|
| 559 | } |
---|
| 560 | |
---|
| 561 | /*****************************************************************************/ |
---|
| 562 | /** |
---|
| 563 | * @brief Checks out one queue entry from the free pool |
---|
| 564 | * |
---|
| 565 | * The queue framework maintains a pool of free queue entries. This function |
---|
| 566 | * removes one entry from the free pool and returns it for use by the MAC |
---|
| 567 | * application. If the free pool is empty NULL is returned. |
---|
| 568 | * |
---|
| 569 | * @return dl_entry * - Pointer to new queue entry if available, |
---|
| 570 | * NULL if free queue is empty |
---|
| 571 | * |
---|
| 572 | *****************************************************************************/ |
---|
| 573 | dl_entry* queue_checkout(){ |
---|
| 574 | interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop(); |
---|
| 575 | |
---|
| 576 | dl_entry* queue_entry; |
---|
| 577 | |
---|
| 578 | if(_free_queue.length > 0){ |
---|
| 579 | queue_entry = ((dl_entry*)(_free_queue.first)); |
---|
| 580 | dl_entry_remove(&_free_queue,_free_queue.first); |
---|
| 581 | |
---|
| 582 | // Set buffer length |
---|
| 583 | // In the current architecture, this length is fixed. |
---|
| 584 | ((pkt_queue_buffer_t*)(queue_entry->data))->pyld_queue_hdr.buffer_length = QUEUE_ELEMENT_SIZE; |
---|
| 585 | |
---|
| 586 | wlan_platform_intc_set_state(curr_interrupt_state); |
---|
| 587 | return queue_entry; |
---|
| 588 | } else { |
---|
| 589 | wlan_platform_intc_set_state(curr_interrupt_state); |
---|
| 590 | return NULL; |
---|
| 591 | } |
---|
| 592 | } |
---|
| 593 | |
---|
| 594 | |
---|
| 595 | |
---|
| 596 | /*****************************************************************************/ |
---|
| 597 | /** |
---|
| 598 | * @brief Checks in one queue entry to the free pool |
---|
| 599 | * |
---|
| 600 | * The queue framework maintains a pool of free queue entries. This function |
---|
| 601 | * returns one entry to the free pool. queue_entry must be a valid pointer to a queue |
---|
| 602 | * entry which the MAC application no longer needs. The application must not |
---|
| 603 | * use the entry pointed to by tqe after calling this function. |
---|
| 604 | * |
---|
| 605 | * @param dl_entry* queue_entry - Pointer to queue entry to be returned to free pool |
---|
| 606 | * |
---|
| 607 | *****************************************************************************/ |
---|
| 608 | void queue_checkin(dl_entry* queue_entry){ |
---|
| 609 | |
---|
| 610 | #if ADDRESS_SAFETY_CHECKS |
---|
| 611 | if( ((u32)queue_entry < QUEUE_DL_ENTRY_MEM_BASE) || ((u32)queue_entry > CALC_MEM_HIGH_ADDR(QUEUE_DL_ENTRY_MEM_BASE,QUEUE_DL_ENTRY_MEM_SIZE)) ){ |
---|
| 612 | xil_printf("%s error: dl_entry @ 0x%08x out of range\n", __FUNCTION__, queue_entry); |
---|
| 613 | } |
---|
| 614 | #endif |
---|
| 615 | |
---|
| 616 | interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop(); |
---|
| 617 | if (queue_entry != NULL) { |
---|
| 618 | dl_entry_insertEnd(&_free_queue, (dl_entry*)queue_entry); |
---|
| 619 | } |
---|
| 620 | wlan_platform_free_queue_entry_notify(); |
---|
| 621 | wlan_platform_intc_set_state(curr_interrupt_state); |
---|
| 622 | } |
---|
| 623 | |
---|
| 624 | |
---|
| 625 | |
---|
| 626 | /*****************************************************************************/ |
---|
| 627 | /** |
---|
| 628 | * @brief Checks out multiple queue entries from the free pool |
---|
| 629 | * |
---|
| 630 | * The queue framework maintains a pool of free queue entries. This function |
---|
| 631 | * attempts to check out num_queue_entry queue entries from the free pool. The number of |
---|
| 632 | * queue entries successfully checked out is returned. This may be less than |
---|
| 633 | * requested if the free pool had fewer than num_queue_entry entries available. |
---|
| 634 | * |
---|
| 635 | * @param dl_list* new_list - Pointer to dl_list to which queue entries are appended |
---|
| 636 | * @param u16 num_queue_entry - Number of queue entries requested |
---|
| 637 | * |
---|
| 638 | * @return Number of queue entries successfully checked out and appended to new_list |
---|
| 639 | * |
---|
| 640 | *****************************************************************************/ |
---|
| 641 | int queue_checkout_list(dl_list* list, u16 num_queue_entry){ |
---|
| 642 | int num_moved; |
---|
| 643 | interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop(); |
---|
| 644 | num_moved = dl_entry_move(&_free_queue, list, num_queue_entry); |
---|
| 645 | wlan_platform_intc_set_state(curr_interrupt_state); |
---|
| 646 | return num_moved; |
---|
| 647 | } |
---|
| 648 | |
---|
| 649 | |
---|
| 650 | |
---|
| 651 | /*****************************************************************************/ |
---|
| 652 | /** |
---|
| 653 | * @brief Checks in multiple queue entries into the free pool |
---|
| 654 | * |
---|
| 655 | * The queue framework maintains a pool of free queue entries. This function will |
---|
| 656 | * check in all queue entries from the provided list to the end of the free pool. |
---|
| 657 | * |
---|
| 658 | * @param dl_list * new_list - Pointer to dl_list from which queue entries will be checked in |
---|
| 659 | * |
---|
| 660 | * @return Number of queue entries successfully checked in |
---|
| 661 | * |
---|
| 662 | *****************************************************************************/ |
---|
| 663 | int queue_checkin_list(dl_list* list) { |
---|
| 664 | int num_moved; |
---|
| 665 | interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop(); |
---|
| 666 | num_moved = dl_entry_move(list, &_free_queue, list->length); |
---|
| 667 | wlan_platform_intc_set_state(curr_interrupt_state); |
---|
| 668 | wlan_platform_free_queue_entry_notify(); |
---|
| 669 | return num_moved; |
---|
| 670 | } |
---|
| 671 | |
---|
| 672 | |
---|