source: ReferenceDesigns/w3_802.11/c/wlan_mac_high_framework/wlan_mac_high.c

Last change on this file was 6319, checked in by chunter, 5 years ago

1.8.0 release wlan-mac-se

File size: 75.4 KB
Line 
1/** @file wlan_mac_high.c
2 *  @brief Top-level WLAN MAC High Framework
3 * 
4 *  This contains the top-level code for accessing the WLAN MAC High Framework.
5 * 
6 *  @copyright Copyright 2014-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#include "wlan_mac_high_sw_config.h"
16
17// Xilinx Includes
18#include "stdlib.h"
19#include "malloc.h"
20#include "xil_exception.h"
21#include "xaxicdma.h"
22
23// WLAN Includes
24#include "wlan_mac_common.h"
25#include "wlan_platform_common.h"
26#include "wlan_platform_high.h"
27#include "wlan_mac_dl_list.h"
28#include "wlan_mac_mailbox_util.h"
29#include "wlan_mac_pkt_buf_util.h"
30#include "wlan_mac_802_11_defs.h"
31#include "wlan_mac_high.h"
32#include "wlan_mac_packet_types.h"
33#include "wlan_mac_queue.h"
34#include "wlan_mac_eth_util.h"
35#include "wlan_mac_ltg.h"
36#include "wlan_mac_entries.h"
37#include "wlan_mac_event_log.h"
38#include "wlan_mac_schedule.h"
39#include "wlan_mac_addr_filter.h"
40#include "wlan_mac_network_info.h"
41#include "wlan_mac_station_info.h"
42#include "wlan_exp_common.h"
43#include "wlan_exp_node.h"
44#include "wlan_exp_transport.h"
45#include "wlan_mac_scan.h"
46#include "wlan_mac_high_mailbox_util.h"
47
48/*********************** Global Variable Definitions *************************/
49
50// Constants
51const u8 bcast_addr[MAC_ADDR_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
52const u8 zero_addr[MAC_ADDR_LEN]  = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
53
54// HW structures
55platform_high_dev_info_t platform_high_dev_info;
56platform_common_dev_info_t platform_common_dev_info;
57wlan_mac_hw_info_t wlan_mac_hw_info;
58
59XAxiCdma cdma_inst; ///< Central DMA instance
60
61// Callback function pointers
62volatile function_ptr_t press_pb_0_callback;   ///< User callback for pressing pushbutton 0
63volatile function_ptr_t release_pb_0_callback; ///< User callback for releasing pushbutton 0
64volatile function_ptr_t press_pb_1_callback;   ///< User callback for pressing pushbutton 1
65volatile function_ptr_t release_pb_1_callback; ///< User callback for releasing pushbutton 1
66volatile function_ptr_t press_pb_2_callback;   ///< User callback for pressing pushbutton 2
67volatile function_ptr_t release_pb_2_callback; ///< User callback for releasing pushbutton 2
68
69volatile function_ptr_t uart_callback;              ///< User callback for UART reception
70volatile function_ptr_t mpdu_tx_high_done_callback; ///< User callback for lower-level message that MPDU transmission is complete
71volatile function_ptr_t mpdu_tx_low_done_callback;  ///< User callback for lower-level message that MPDU transmission is complete
72volatile function_ptr_t mpdu_rx_callback;           ///< User callback for lower-level message that MPDU reception is ready for processing
73volatile function_ptr_t tx_poll_callback;           ///< User callback when higher-level framework is ready to send a packet to low
74volatile function_ptr_t beacon_tx_done_callback;    ///< User callback for low-level message that a Beacon transmission is complete
75volatile function_ptr_t mpdu_tx_dequeue_callback;   ///< User callback for higher-level framework dequeuing a packet
76volatile function_ptr_t cpu_low_reboot_callback;    ///< User callback for CPU_LOW boot
77volatile function_ptr_t tx_queue_state_change_callback; ///< User callback for Tx queue state changes
78
79// CPU_LOW parameters that MAC High Framework tracks and is responsible for re-applying
80//  in the event of a CPU_LOW reboot.
81volatile u32 low_param_channel;
82volatile u32 low_param_dsss_en;
83volatile u8  low_param_rx_ant_mode;
84volatile s8  low_param_tx_ctrl_pow;
85volatile s8  low_param_radio_tx_pow;
86volatile u32 low_param_rx_filter;
87volatile u32 low_param_random_seed;
88
89// Node information
90volatile u8 dram_present;                 ///< Indication variable for whether DRAM SODIMM is present on this hardware
91
92// Status information
93wlan_mac_hw_info_t* hw_info;
94static volatile u32 cpu_low_status;               ///< Tracking variable for lower-level CPU status
95
96// CPU Low Register Read Buffer
97static volatile u32* cpu_low_reg_read_buffer;
98static volatile u8 cpu_low_reg_read_buffer_status;
99
100#define CPU_LOW_REG_READ_BUFFER_STATUS_READY     1
101#define CPU_LOW_REG_READ_BUFFER_STATUS_NOT_READY 0
102
103// Memory Allocation Debugging
104static volatile u32 num_malloc;                   ///< Tracking variable for number of times malloc has been called
105static volatile u32 num_free;                     ///< Tracking variable for number of times free has been called
106static volatile u32 num_realloc;                  ///< Tracking variable for number of times realloc has been called
107
108/******************************** Functions **********************************/
109
110/**
111 * @brief Initialize MAC High Framework
112 *
113 * This function initializes the MAC High Framework by setting
114 * up the hardware and other subsystems in the framework.
115 *
116 * @param None
117 * @return None
118 */
119void wlan_mac_high_init(){
120    int Status;
121    u32 i;
122    tx_frame_info_t* tx_frame_info;
123    rx_frame_info_t* rx_frame_info;
124#if WLAN_SW_CONFIG_ENABLE_LOGGING
125    u32 log_size;
126#endif //WLAN_SW_CONFIG_ENABLE_LOGGING
127    XAxiCdma_Config* cdma_cfg_ptr;
128
129    platform_high_dev_info   = wlan_platform_high_get_dev_info();
130    platform_common_dev_info = wlan_platform_common_get_dev_info();
131    wlan_mac_hw_info = wlan_platform_get_hw_info();
132
133    // Check that right shift works correctly
134    //   Issue with -Os in Xilinx SDK 14.7
135    if (wlan_mac_high_right_shift_test() != 0) {
136        wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_CPU_ERROR, WLAN_ERROR_CODE_RIGHT_SHIFT);
137    }
138
139    // Sanity check memory map of aux. BRAM and DRAM
140    //Aux. BRAM Check
141    Status = (TX_QUEUE_DL_ENTRY_MEM_HIGH < BSS_INFO_DL_ENTRY_MEM_BASE) &&
142             (BSS_INFO_DL_ENTRY_MEM_HIGH < STATION_INFO_DL_ENTRY_MEM_BASE ) &&
143             (STATION_INFO_DL_ENTRY_MEM_HIGH <= CALC_MEM_HIGH_ADDR(platform_high_dev_info.aux_bram_baseaddr, platform_high_dev_info.aux_bram_size));
144
145    if(Status != 1){
146        xil_printf("Error: Overlap detected in Aux. BRAM. Check address assignments\n");
147    }
148
149    //DRAM Check
150    Status = (TX_QUEUE_BUFFER_HIGH < BSS_INFO_BUFFER_BASE) &&
151             (BSS_INFO_BUFFER_HIGH < STATION_INFO_BUFFER_BASE) &&
152             (STATION_INFO_BUFFER_HIGH < USER_SCRATCH_BASE) &&
153             (USER_SCRATCH_HIGH < EVENT_LOG_BASE) &&
154             (EVENT_LOG_HIGH <= CALC_MEM_HIGH_ADDR(platform_high_dev_info.dram_baseaddr, platform_high_dev_info.dram_size));
155
156    if(Status != 1){
157        xil_printf("Error: Overlap detected in DRAM. Check address assignments\n");
158    }
159
160    // ***************************************************
161    // Initialize libraries
162    // ***************************************************
163
164    // Initialize mailbox
165    wlan_mac_high_init_mailbox();
166
167    // Initialize packet buffers
168    init_pkt_buf();
169
170    // Initialize the HW info structure
171    init_mac_hw_info();
172
173    hw_info = get_mac_hw_info();
174
175    xil_printf("------------------------\n");
176    xil_printf("Initializing MAC High Framework...\n");
177    xil_printf("  WLAN MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", hw_info->hw_addr_wlan[0], hw_info->hw_addr_wlan[1], hw_info->hw_addr_wlan[2],
178                                                                      hw_info->hw_addr_wlan[3], hw_info->hw_addr_wlan[4], hw_info->hw_addr_wlan[5]);
179    xil_printf("  Serial Number: %s-%05d\n", hw_info->serial_number_prefix, hw_info->serial_number);
180
181    // ***************************************************
182    // Initialize callbacks and global state variables
183    // ***************************************************
184    press_pb_0_callback             = (function_ptr_t)wlan_null_callback;
185    release_pb_0_callback           = (function_ptr_t)wlan_null_callback;
186    press_pb_1_callback             = (function_ptr_t)wlan_null_callback;
187    release_pb_1_callback           = (function_ptr_t)wlan_null_callback;
188    press_pb_2_callback             = (function_ptr_t)wlan_null_callback;
189    release_pb_2_callback           = (function_ptr_t)wlan_null_callback;
190    uart_callback                   = (function_ptr_t)wlan_null_callback;
191    mpdu_rx_callback                = (function_ptr_t)wlan_null_callback;
192    mpdu_tx_high_done_callback      = (function_ptr_t)wlan_null_callback;
193    mpdu_tx_low_done_callback       = (function_ptr_t)wlan_null_callback;
194    beacon_tx_done_callback         = (function_ptr_t)wlan_null_callback;
195    tx_poll_callback                = (function_ptr_t)wlan_null_callback;
196    mpdu_tx_dequeue_callback        = (function_ptr_t)wlan_null_callback;
197    cpu_low_reboot_callback         = (function_ptr_t)wlan_null_callback;
198    tx_queue_state_change_callback  = (function_ptr_t)wlan_null_callback;
199
200    num_malloc  = 0;
201    num_realloc = 0;
202    num_free    = 0;
203
204    low_param_channel       = 0xFFFFFFFF;
205    low_param_dsss_en       = 0xFFFFFFFF;
206    low_param_rx_ant_mode   = 0xFF;
207    low_param_tx_ctrl_pow   = -127;
208    low_param_radio_tx_pow  = -127;
209    low_param_rx_filter     = 0xFFFFFFFF;
210    low_param_random_seed   = 0xFFFFFFFF;
211
212    cpu_low_reg_read_buffer        = NULL;
213
214    // ***************************************************
215    // Initialize Transmit Packet Buffers
216    // ***************************************************
217    for(i = 0; i < NUM_TX_PKT_BUFS; i++){
218        tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, i);
219        switch(i){
220            case TX_PKT_BUF_MPDU_1:
221            case TX_PKT_BUF_MPDU_2:
222            case TX_PKT_BUF_MPDU_3:
223            case TX_PKT_BUF_MPDU_4:
224            case TX_PKT_BUF_MPDU_5:
225            case TX_PKT_BUF_MPDU_6:
226                switch(tx_frame_info->tx_pkt_buf_state){
227                    case TX_PKT_BUF_UNINITIALIZED:
228                    case TX_PKT_BUF_HIGH_CTRL:
229                        // Buffer already clean on boot or reboot
230                    case TX_PKT_BUF_DONE:
231                        // CPU High rebooted while CPU Low finished old Tx
232                        //  Ignore the packet buffer contents and clean up
233                    default:
234                        // Something went wrong if tx_pkt_buf_state is something
235                        // other than one of the tx_pkt_buf_state_t enums. We'll
236                        // attempt to resolve the problem by explicitly setting
237                        // the state.
238                        force_lock_tx_pkt_buf(i);
239                        tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
240                    break;
241                    case TX_PKT_BUF_READY:
242                    case TX_PKT_BUF_LOW_CTRL:
243                        // CPU High rebooted after submitting packet for transmission
244                        //  Will be handled by CPU Low, either because CPU Low is about
245                        //  to transmit or just rebooted and will clean up
246                    break;
247                }
248            break;
249            case TX_PKT_BUF_BEACON:
250                unlock_tx_pkt_buf(TX_PKT_BUF_BEACON);
251                tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
252            break;
253            case TX_PKT_BUF_RTS:
254            case TX_PKT_BUF_ACK_CTS:
255                unlock_tx_pkt_buf(i);
256            break;
257            default:
258            break;
259        }
260    }
261
262    // ***************************************************
263    // Initialize Receive Packet Buffers
264    // ***************************************************
265    for(i = 0; i < NUM_RX_PKT_BUFS; i++){
266        rx_frame_info = (rx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.rx_pkt_buf_baseaddr, i);
267        switch(rx_frame_info->rx_pkt_buf_state){
268            case RX_PKT_BUF_UNINITIALIZED:
269            case RX_PKT_BUF_LOW_CTRL:
270                //CPU_LOW will initialize
271            break;
272            case RX_PKT_BUF_HIGH_CTRL:
273            case RX_PKT_BUF_READY:
274                // CPU HIGH rebooted after CPU Low submitted packet for de-encap/logging
275                //  Release lock and reset state
276                //  Note: this will not cause CPU_LOW to re-lock this packet buffer.
277                //  The effects of this are subtle. CPU_LOW will see that the buffer
278                //  Is under LOW_CTRL and will assume it has a mutex lock. It will
279                //  fill the packet buffer all while the mutex is unlocked. Once the
280                //  state transitions to READY and is passed to CPU_HIGH, this ambiguous
281                //  state will be resolved.
282            default:
283                // Something went wrong if rx_pkt_buf_state is something
284                // other than one of the rx_pkt_buf_state_t enums. We'll
285                // attempt to resolve the problem by explicitly setting
286                // the state.
287                unlock_rx_pkt_buf(i);
288                rx_frame_info->rx_pkt_buf_state = RX_PKT_BUF_LOW_CTRL;
289
290            break;
291        }
292    }
293
294    // ***************************************************
295    // Initialize CDMA, GPIO, and UART drivers
296    // ***************************************************
297
298    // Initialize the central DMA (CDMA) driver
299    cdma_cfg_ptr = XAxiCdma_LookupConfig(platform_high_dev_info.cdma_dev_id);
300    Status = XAxiCdma_CfgInitialize(&cdma_inst, cdma_cfg_ptr, cdma_cfg_ptr->BaseAddress);
301    if (Status != XST_SUCCESS) {
302        wlan_printf(PL_ERROR, "ERROR: Could not initialize CDMA: %d\n", Status);
303    }
304    XAxiCdma_IntrDisable(&cdma_inst, XAXICDMA_XR_IRQ_ALL_MASK);
305
306    xil_printf("------------------------\n");
307    xil_printf("Testing DRAM...\n");
308
309    // If the CPU hangs at this point there is probably a problem with the DRAM...
310
311    if(wlan_mac_high_memory_test() != 0 ){
312        xil_printf("A working DRAM SODIMM has not been detected on this board.\n");
313        xil_printf("The 802.11 Reference Design requires at least 1GB of DRAM.\n");
314        xil_printf("This CPU will now halt.\n");
315        wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_CPU_ERROR, WLAN_ERROR_CODE_DRAM_NOT_PRESENT);
316    }
317
318    // ***************************************************
319    // Initialize various subsystems in the MAC High Framework
320    // ***************************************************
321    queue_init();
322
323#if WLAN_SW_CONFIG_ENABLE_LOGGING
324    // The event_list lives in DRAM immediately following the queue payloads.
325    if(MAX_EVENT_LOG == -1){
326        log_size = EVENT_LOG_SIZE;
327    } else {
328        log_size = WLAN_MIN(EVENT_LOG_SIZE, (u32)MAX_EVENT_LOG );
329    }
330
331    event_log_init( (void*)EVENT_LOG_BASE, log_size );
332#endif //WLAN_SW_CONFIG_ENABLE_LOGGING
333
334    network_info_init();
335    station_info_init();
336
337    station_info_t* station_info = station_info_create((u8*)bcast_addr);
338    station_info->flags |= STATION_INFO_FLAG_KEEP;
339
340#if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE
341    wlan_eth_util_init();
342#endif
343    wlan_mac_schedule_init();
344#if WLAN_SW_CONFIG_ENABLE_LTG
345    wlan_mac_ltg_sched_init();
346#endif //WLAN_SW_CONFIG_ENABLE_LTG
347    wlan_mac_addr_filter_init();
348    wlan_mac_scan_init();
349
350    //Non-blocking request for CPU_LOW to send its state. This handles the case that
351    //CPU_HIGH reboots some point after CPU_LOW had already booted.
352    wlan_mac_high_request_low_state();
353
354    wlan_mac_high_set_radio_channel(1); // Set a sane default channel. The top-level project (AP/STA/IBSS/etc) is free to change this
355
356    // Initialize Interrupts
357    wlan_mac_high_interrupt_init();
358}
359
360
361
362/**
363 * @brief Initialize MAC High Framework's Interrupts
364 *
365 * This function initializes sets up the interrupt subsystem
366 * of the MAC High Framework.
367 *
368 * @param None
369 * @return WLAN_SUCCESS or WLAN_FAILURE
370 */
371int wlan_mac_high_interrupt_init() {
372    int Result;
373
374    // ***************************************************
375    // Connect interrupt devices "owned" by wlan_mac_high
376    // ***************************************************
377
378    // ***************************************************
379    // Connect interrupt devices in other subsystems
380    // ***************************************************
381    Result = wlan_platform_high_init();
382    if (Result != WLAN_SUCCESS) {
383        wlan_printf(PL_ERROR,"Failed to set up Ethernet interrupt\n");
384        return Result;
385    }
386
387    Result = setup_mailbox_interrupt();
388    if (Result != WLAN_SUCCESS) {
389        wlan_printf(PL_ERROR, "Failed to set up wlan_lib mailbox interrupt\n");
390        return WLAN_FAILURE;
391    }
392
393    // ***************************************************
394    // Enable MicroBlaze exceptions
395    // ***************************************************
396    Xil_ExceptionInit();
397    Xil_ExceptionEnable();
398
399    // Finish setting up any subsystems that were waiting on interrupts to be configured
400    network_info_init_finish();
401
402
403    return WLAN_SUCCESS;
404}
405
406void wlan_mac_high_uart_rx_callback(u8 rxByte){
407    uart_callback(rxByte);
408}
409
410void wlan_mac_high_userio_inputs_callback(u32 userio_state, userio_input_mask_t userio_delta){
411    switch(userio_delta){
412        case USERIO_INPUT_MASK_PB_0:
413            if(userio_state){
414                press_pb_0_callback();
415            } else {
416                release_pb_0_callback();
417            }
418        break;
419        case USERIO_INPUT_MASK_PB_1:
420            if(userio_state){
421                press_pb_1_callback();
422            } else {
423                release_pb_1_callback();
424            }
425        break;
426        case USERIO_INPUT_MASK_PB_2:
427            if(userio_state){
428                press_pb_2_callback();
429            } else {
430                release_pb_2_callback();
431            }
432        break;
433        default:
434        //Not implemented
435        break;
436    }
437}
438
439
440void wlan_mac_high_sw_intr_callback(u32 intr_state){
441
442#if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE
443    if(intr_state & SW_INTR_ID_PORTAL_ETH_RX){
444        wlan_poll_eth_rx_queue();
445    }
446    if(intr_state & SW_INTR_ID_PORTAL_ETH_TX){
447        wlan_poll_eth_tx_queue();
448    }
449#endif
450
451#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP
452    if(intr_state & SW_INTR_ID_WLAN_EXP_ETH_TX){
453        wlan_exp_handle_tx_queue();
454    }
455#endif
456}
457
458
459void wlan_mac_high_set_press_pb_0_callback(function_ptr_t callback){
460    press_pb_0_callback = callback;
461}
462void wlan_mac_high_set_release_pb_0_callback(function_ptr_t callback){
463    release_pb_0_callback = callback;
464}
465void wlan_mac_high_set_press_pb_1_callback(function_ptr_t callback){
466    press_pb_1_callback = callback;
467}
468void wlan_mac_high_set_release_pb_1_callback(function_ptr_t callback){
469    release_pb_1_callback = callback;
470}
471void wlan_mac_high_set_press_pb_2_callback(function_ptr_t callback){
472    press_pb_2_callback = callback;
473}
474void wlan_mac_high_set_release_pb_2_callback(function_ptr_t callback){
475    release_pb_2_callback = callback;
476}
477
478
479/**
480 * @brief Set UART Reception Callback
481 *
482 * Tells the framework which function should be called when
483 * a byte is received from UART.
484 *
485 * @param function_ptr_t callback
486 *  - Pointer to callback function
487 * @return None
488 *
489 */
490void wlan_mac_high_set_uart_rx_callback(function_ptr_t callback){
491    uart_callback = callback;
492}
493
494/**
495 * @brief Set MPDU Transmission Complete Callback (High-level)
496 *
497 * Tells the framework which function should be called when
498 * the lower-level CPU confirms that a high-level MPDU transmission has
499 * completed.
500 *
501 * @param function_ptr_t callback
502 *  - Pointer to callback function
503 * @return None
504 *
505 * @note This callback is not executed for individual retransmissions.
506 * It is instead only executed after a chain of retransmissions is complete
507 * either through the reception of an ACK or the number of retransmissions
508 * reaching the maximum number of retries specified by the MPDU's
509 * tx_frame_info metadata.
510 *
511 */
512void wlan_mac_high_set_mpdu_tx_high_done_callback(function_ptr_t callback){
513    mpdu_tx_high_done_callback = callback;
514}
515
516/**
517 * @brief Set MPDU Transmission Complete Callback (Low-level)
518 *
519 * Tells the framework which function should be called when
520 * the lower-level CPU confirms that a low-level MPDU transmission has
521 * completed.
522 *
523 * @param function_ptr_t callback
524 *  - Pointer to callback function
525 * @return None
526 *
527 */
528void wlan_mac_high_set_mpdu_tx_low_done_callback(function_ptr_t callback){
529    mpdu_tx_low_done_callback = callback;
530}
531
532
533void wlan_mac_high_set_beacon_tx_done_callback(function_ptr_t callback){
534    beacon_tx_done_callback = callback;
535}
536
537
538/**
539 * @brief Set MPDU Reception Callback
540 *
541 * Tells the framework which function should be called when
542 * the lower-level CPU receives a valid MPDU frame.
543 *
544 * @param function_ptr_t callback
545 *  - Pointer to callback function
546 * @return None
547 *
548 */
549void wlan_mac_high_set_mpdu_rx_callback(function_ptr_t callback){
550    mpdu_rx_callback = callback;
551}
552
553
554
555/**
556 * @brief Set Poll Tx Queue Callback
557 *
558 * Tells the framework which function should be called whenever
559 * the framework knows that CPU_LOW is ready to send a new packet.
560 *
561 * @param function_ptr_t callback
562 *  - Pointer to callback function
563 * @return None
564 *
565 */
566void wlan_mac_high_set_poll_tx_queues_callback(function_ptr_t callback){
567    tx_poll_callback = callback;
568}
569
570
571/**
572 * @brief Set MPDU Dequeue Callback
573 *
574 * Tells the framework which function should be called when
575 * a packet is dequeued and about to be passed to the
576 * lower-level CPU.
577 *
578 * @param function_ptr_t callback
579 *  - Pointer to callback function
580 * @return None
581 *
582 */
583void wlan_mac_high_set_mpdu_dequeue_callback(function_ptr_t callback){
584    mpdu_tx_dequeue_callback = callback;
585}
586
587
588/**
589 * @brief Set CPU_LOW Reboot Callback
590 *
591 * Tells the framework which function should be called when
592 * CPU_LOW boots or reboots. This allows a high-level application
593 * to restore any parameters it previously set in CPU_LOW
594 *
595 * @param function_ptr_t callback
596 *  - Pointer to callback function
597 * @return None
598 *
599 */
600void wlan_mac_high_set_cpu_low_reboot_callback(function_ptr_t callback){
601    cpu_low_reboot_callback = callback;
602}
603
604/**
605 * @brief Set Tx queue state change callback
606 *
607 * Tells the framework which function should be called when
608 * the Tx queue for a network member changes state.
609 *
610 * @param function_ptr_t callback
611 *  - Pointer to callback function
612 * @return None
613 *
614 */
615void wlan_mac_high_set_tx_queue_state_change_callback(function_ptr_t callback){
616    tx_queue_state_change_callback = callback;
617}
618
619
620/**
621 * @brief Display Memory Allocation Information
622 *
623 * This function is a wrapper around a call to mallinfo(). It prints
624 * the information returned by mallinfo() to aid in the debugging of
625 * memory leaks and other dynamic memory allocation issues.
626 *
627 * @param None
628 * @return None
629 *
630 */
631void wlan_mac_high_display_mallinfo(){
632    struct mallinfo mi;
633    mi = mallinfo();
634
635    xil_printf("\n");
636    xil_printf("--- Malloc Info ---\n");
637    xil_printf("Summary:\n");
638    xil_printf("   num_malloc:              %d\n", num_malloc);
639    xil_printf("   num_realloc:             %d\n", num_realloc);
640    xil_printf("   num_free:                %d\n", num_free);
641    xil_printf("   num_malloc-num_free:     %d\n", (int)num_malloc - (int)num_free);
642    xil_printf("   System:                  %d bytes\n", mi.arena);
643    xil_printf("   Total Allocated Space:   %d bytes\n", mi.uordblks);
644    xil_printf("   Total Free Space:        %d bytes\n", mi.fordblks);
645#if 0
646    xil_printf("Details:\n");
647    xil_printf("   arena:                   %d\n", mi.arena);
648    xil_printf("   ordblks:                 %d\n", mi.ordblks);
649    xil_printf("   smblks:                  %d\n", mi.smblks);
650    xil_printf("   hblks:                   %d\n", mi.hblks);
651    xil_printf("   hblkhd:                  %d\n", mi.hblkhd);
652    xil_printf("   usmblks:                 %d\n", mi.usmblks);
653    xil_printf("   fsmblks:                 %d\n", mi.fsmblks);
654    xil_printf("   uordblks:                %d\n", mi.uordblks);
655    xil_printf("   fordblks:                %d\n", mi.fordblks);
656    xil_printf("   keepcost:                %d\n", mi.keepcost);
657#endif
658}
659
660
661
662/**
663 * @brief Dynamically Allocate Memory
664 *
665 * This function wraps malloc() and uses its same API.
666 *
667 * @param u32 size
668 *  - Number of bytes that should be allocated
669 * @return void*
670 *  - Memory address of allocation if the allocation was successful
671 *  - NULL if the allocation was unsuccessful
672 *
673 * @note The purpose of this function is to funnel all memory allocations through one place in
674 * code to enable easier debugging of memory leaks when they occur. This function also updates
675 * a variable maintained by the framework to track the number of memory allocations and prints
676 * this value, along with the other data from wlan_mac_high_display_mallinfo() in the event that
677 * malloc() fails to allocate the requested size.
678 *
679 */
680void* wlan_mac_high_malloc(u32 size){
681    void* return_value;
682    return_value = malloc(size);
683
684    if(return_value == NULL){
685        xil_printf("malloc error. Try increasing heap size in linker script.\n");
686        wlan_mac_high_display_mallinfo();
687    } else {
688#if 0
689        xil_printf("MALLOC - 0x%08x    %d\n", return_value, size);
690#endif
691        num_malloc++;
692    }
693    return return_value;
694}
695
696
697
698/**
699 * @brief Dynamically Allocate and Initialize Memory
700 *
701 * This function wraps wlan_mac_high_malloc() and uses its same API. If successfully allocated,
702 * this function will explicitly zero-initialize the allocated memory.
703 *
704 * @param u32 size
705 *  - Number of bytes that should be allocated
706 * @return void*
707 *  - Memory address of allocation if the allocation was successful
708 *  - NULL if the allocation was unsuccessful
709 *
710 * @see wlan_mac_high_malloc()
711 *
712 */
713void* wlan_mac_high_calloc(u32 size){
714    //This is just a simple wrapper around calloc to aid in debugging memory leak issues
715    void* return_value;
716    return_value = wlan_mac_high_malloc(size);
717
718    if(return_value == NULL){
719    } else {
720        memset(return_value, 0 , size);
721    }
722    return return_value;
723}
724
725
726
727/**
728 * @brief Dynamically Reallocate Memory
729 *
730 * This function wraps realloc() and uses its same API.
731 *
732 * @param void* addr
733 *  - Address of dynamically allocated array that should be reallocated
734 * @param u32 size
735 *  - Number of bytes that should be allocated
736 * @return void*
737 *  - Memory address of allocation if the allocation was successful
738 *  - NULL if the allocation was unsuccessful
739 *
740 * @note The purpose of this function is to funnel all memory allocations through one place in
741 * code to enable easier debugging of memory leaks when they occur. This function also updates
742 * a variable maintained by the framework to track the number of memory allocations and prints
743 * this value, along with the other data from wlan_mac_high_display_mallinfo() in the event that
744 * realloc() fails to allocate the requested size.
745 *
746 */
747void* wlan_mac_high_realloc(void* addr, u32 size){
748    void* return_value;
749    return_value = realloc(addr, size);
750
751    if(return_value == NULL){
752        xil_printf("realloc error. Try increasing heap size in linker script.\n");
753        wlan_mac_high_display_mallinfo();
754    } else {
755#if 0
756        xil_printf("REALLOC - 0x%08x    %d\n", return_value, size);
757#endif
758        num_realloc++;
759    }
760
761    return return_value;
762}
763
764
765
766/**
767 * @brief Free Dynamically Allocated Memory
768 *
769 * This function wraps free() and uses its same API.
770 *
771 * @param void* addr
772 *  - Address of dynamically allocated array that should be freed
773 * @return None
774 *
775 * @note The purpose of this function is to funnel all memory freeing through one place in
776 * code to enable easier debugging of memory leaks when they occur. This function also updates
777 * a variable maintained by the framework to track the number of memory frees.
778 *
779 */
780void wlan_mac_high_free(void* addr){
781#if 0
782    xil_printf("FREE - 0x%08x\n", addr);
783#endif
784    free(addr);
785    num_free++;
786}
787
788
789
790/**
791 * @brief Test DDR3 SODIMM Memory Module
792 *
793 * This function tests the integrity of the DDR3 SODIMM module attached to the hardware
794 * by performing various write and read tests. Note, this function will destory contents
795 * in DRAM, so it should only be called immediately after booting.
796 *
797 * @param None
798 * @return int
799 *  - WLAN_SUCCESS for memory test pass
800 *  - WLAN_FAILURE for memory test fail
801 */
802int wlan_mac_high_memory_test() {
803
804    volatile u8 i,j;
805
806    volatile u8  test_u8;
807    volatile u16 test_u16;
808    volatile u32 test_u32;
809    volatile u64 test_u64;
810
811    volatile u8  readback_u8;
812    volatile u16 readback_u16;
813    volatile u32 readback_u32;
814    volatile u64 readback_u64;
815
816    volatile void* memory_ptr;
817
818    for(i=0; i<6; i++) {
819        // Jump by 100MB steps
820        memory_ptr = (void*)((u8*)platform_high_dev_info.dram_baseaddr + (i*100*1024*1024));
821
822        // Test all types at multiple byte offsets to verify unaligned accesses succeed
823        for(j=0; j<3; j++) {
824            test_u8 = rand()&0xFF;
825            test_u16 = rand()&0xFFFF;
826            test_u32 = rand()&0xFFFFFFFF;
827            test_u64 = (((u64)rand()&0xFFFFFFFF)<<32) + ((u64)rand()&0xFFFFFFFF);
828
829            *((u8*)memory_ptr) = test_u8;
830            readback_u8 = *((u8*)memory_ptr);
831
832            if(readback_u8!= test_u8){
833                xil_printf("0x%08x: %2x = %2x\n", memory_ptr, readback_u8, test_u8);
834                xil_printf("DRAM Failure: Addr: 0x%08x -- Unable to verify write of u8\n",memory_ptr);
835                return WLAN_FAILURE;
836            }
837            *((u16*)memory_ptr) = test_u16;
838            readback_u16 = *((u16*)memory_ptr);
839
840            if(readback_u16 != test_u16){
841                xil_printf("0x%08x: %4x = %4x\n", memory_ptr, readback_u16, test_u16);
842                xil_printf("DRAM Failure: Addr: 0x%08x -- Unable to verify write of u16\n",memory_ptr);
843                return WLAN_FAILURE;
844            }
845            *((u32*)memory_ptr) = test_u32;
846            readback_u32 = *((u32*)memory_ptr);
847
848            if(readback_u32 != test_u32){
849                xil_printf("0x%08x: %8x = %8x\n", memory_ptr, readback_u32, test_u32);
850                xil_printf("DRAM Failure: Addr: 0x%08x -- Unable to verify write of u32\n",memory_ptr);
851                return WLAN_FAILURE;
852            }
853
854// Disabling u64 test for now - we've observed Zynq ARM is unable to do unaligned
855//  64-bit DRAM read/write, even when 8/16/32-bit unaligned accesses succeed
856// FIXME: figure out why ARM fails when MB succeeds using the same memory controller and interface
857#ifdef __MICROBLAZE__
858            *((u64*)memory_ptr) = test_u64;
859            readback_u64 = *((u64*)memory_ptr);
860
861            if(readback_u64!= test_u64){
862                xil_printf("DRAM Failure: Addr: 0x%08x -- Unable to verify write of u64\n",memory_ptr);
863                return WLAN_FAILURE;
864            }
865#endif
866            memory_ptr++;
867        }
868    }
869
870    return WLAN_SUCCESS;
871}
872
873
874
875/**
876 * @brief Test Right Shift Operator
877 *
878 * This function tests the compiler right shift operator.  This is due to a bug in
879 * the Xilinx 14.7 toolchain when the '-Os' flag is used during compilation.  Please
880 * see:  http://warpproject.org/forums/viewtopic.php?id=2472 for more information.
881 *
882 * @param None
883 * @return int
884 *  - WLAN_SUCCESS for right shift test pass
885 *  - WLAN_FAILURE for right shift test fail
886 */
887int wlan_mac_high_right_shift_test(){
888    u8 val_3, val_2, val_1, val_0;
889
890    volatile u32 test_val   = 0xFEDCBA98;
891    volatile u8* test_array = (u8 *)&test_val;
892
893    val_3 = (u8)((test_val & 0xFF000000) >> 24);
894    val_2 = (u8)((test_val & 0x00FF0000) >> 16);
895    val_1 = (u8)((test_val & 0x0000FF00) >>  8);
896    val_0 = (u8)((test_val & 0x000000FF) >>  0);
897
898    if ((val_3 != test_array[3]) || (val_2 != test_array[2]) || (val_1 != test_array[1]) || (val_0 != test_array[0])) {
899        xil_printf("Right shift operator is not operating correctly in this toolchain.\n");
900        xil_printf("Please use Xilinx 14.4 or an optimization level other than '-Os'\n");
901        xil_printf("See http://warpproject.org/forums/viewtopic.php?id=2472 for more info.\n");
902        return WLAN_FAILURE;
903    }
904
905    return WLAN_SUCCESS;
906}
907
908
909
910/**
911 * @brief Start Central DMA Transfer
912 *
913 * This function wraps the XAxiCdma call for a CDMA memory transfer and mimics the well-known
914 * API of memcpy(). This function does not block once the transfer is started.
915 *
916 * @param void* dest
917 *  - Pointer to destination address where bytes should be copied
918 * @param void* src
919 *  - Pointer to source address from where bytes should be copied
920 * @param u32 size
921 *  - Number of bytes that should be copied
922 * @return int
923 *  - WLAN_SUCCESS for success of submission
924 *  - WLAN_FAILURE for submission failure
925 *
926 *   @note This function will block until any existing CDMA transfer is complete. It is therefore
927 *   safe to call this function successively as each call will wait on the preceeding call.
928 *
929 */
930
931int wlan_mac_high_cdma_start_transfer(void* dest, void* src, u32 size){
932    //This is a wrapper function around the central DMA simple transfer call. It's arguments
933    //are intended to be similar to memcpy. Note: This function does not block on the transfer.
934    int return_value;
935    interrupt_state_t prev_interrupt_state;
936
937    prev_interrupt_state = wlan_platform_intc_stop();
938
939    if( size == 0 ){
940        xil_printf("CDMA Error: size argument must be > 0\n");
941        xil_printf("0x%08x -> 0x%08x: %d\n", src, dest, size);
942        return WLAN_FAILURE;
943    }
944
945    wlan_mac_high_cdma_finish_transfer();
946    return_value = XAxiCdma_SimpleTransfer(&cdma_inst, (u32)src, (u32)dest, size, NULL, NULL);
947
948    if(return_value != 0){
949        xil_printf("CDMA Error: code %d, (0x%08x,0x%08x,%d)\n", return_value, dest,src,size);
950    }
951
952    if(return_value == XST_SUCCESS){
953        return_value = WLAN_SUCCESS;
954    } else {
955        return_value = WLAN_FAILURE;
956    }
957
958    wlan_platform_intc_set_state(prev_interrupt_state);
959
960    return return_value;
961}
962
963
964
965/**
966 * @brief Finish Central DMA Transfer
967 *
968 * This function will block until an ongoing CDMA transfer is complete.
969 * If there is no CDMA transfer underway when this function is called, it
970 * returns immediately.
971 *
972 * @param None
973 * @return None
974 *
975 */
976void wlan_mac_high_cdma_finish_transfer(){
977    while(XAxiCdma_IsBusy(&cdma_inst)) {}
978    return;
979}
980
981
982
983/**
984 * @brief Transmit MPDU
985 *
986 * This function passes off an MPDU to the lower-level processor for transmission.
987 *
988 */
989void wlan_mac_high_mpdu_transmit(tx_80211_queue_buffer_t* tx_queue_buffer, int tx_pkt_buf) {
990    wlan_ipc_msg_t ipc_msg_to_low;
991    tx_frame_info_t* tx_frame_info;
992    mac_header_80211* header;
993
994    u8 frame_control_1;
995    tx_params_t default_tx_params;
996    u8 is_multicast;
997    station_info_t* station_info_ptr;
998    u8* copy_destination;
999
1000    station_info_ptr = tx_queue_buffer->station_info;
1001    tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf);
1002
1003    header = (mac_header_80211*)(tx_queue_buffer->pkt);
1004    is_multicast = wlan_addr_mcast(header->address_1);
1005
1006    // Call user code to notify it of dequeue
1007    mpdu_tx_dequeue_callback(tx_queue_buffer);
1008
1009    copy_destination = (u8*)(((u8*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf)) + sizeof(tx_frame_info_t) + PHY_TX_PKT_BUF_PHY_HDR_SIZE);
1010
1011    // Copy section C1 with CDMA
1012    if(tx_queue_buffer->seg1_len > 0){
1013        wlan_mac_high_cdma_start_transfer(  copy_destination + tx_queue_buffer->seg0_len,
1014                                            tx_queue_buffer->pkt + tx_queue_buffer->seg1_offset,
1015                                            tx_queue_buffer->seg1_len );
1016    }
1017    if(tx_queue_buffer->seg1_len > 0){
1018        // Copy section C0 with memcpy
1019        memcpy( copy_destination,
1020                tx_queue_buffer->pkt,
1021                tx_queue_buffer->seg0_len );
1022    } else {
1023        // Copy section C0 with CDMA
1024        wlan_mac_high_cdma_start_transfer( copy_destination,
1025                                           tx_queue_buffer->pkt,
1026                                           tx_queue_buffer->seg0_len );
1027    }
1028
1029    tx_frame_info->length = tx_queue_buffer->length;
1030    tx_frame_info->queue_info = tx_queue_buffer->tx_queue_details;
1031    tx_frame_info->flags = 0;
1032
1033    if(tx_queue_buffer->flags & TX_80211_QUEUE_BUFFER_FLAGS_FILL_TIMESTAMP) tx_frame_info->flags |= TX_FRAME_INFO_FLAGS_FILL_TIMESTAMP;
1034    if(tx_queue_buffer->flags & TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION) tx_frame_info->flags |= TX_FRAME_INFO_FLAGS_FILL_DURATION;
1035    if(tx_queue_buffer->flags & TX_80211_QUEUE_BUFFER_FLAGS_FILL_UNIQ_SEQ) tx_frame_info->flags |= TX_FRAME_INFO_FLAGS_FILL_UNIQ_SEQ;
1036
1037    if((!is_multicast) & (!(tx_queue_buffer->flags & TX_80211_QUEUE_BUFFER_FLAGS_BYPASS_RECOVERY))){
1038        tx_frame_info->flags |= TX_FRAME_INFO_FLAGS_REQ_TO;  //TODO: Since TA can be anything in full generality,
1039    }                                                        // should we only raise this flag if TA = self? I'd
1040                                                             // prefer not to add a 6-byte comparison here if we
1041                                                             // can avoid it.
1042
1043    tx_frame_info->unique_seq = 0; // Unique_seq will be filled in by CPU_LOW
1044
1045    if( tx_queue_buffer->flags & TX_80211_QUEUE_BUFFER_FLAGS_TYPE_CTS ){
1046        tx_frame_info->tx_details_type = TX_DETAILS_CTS;
1047    } else if( tx_queue_buffer->flags & TX_80211_QUEUE_BUFFER_FLAGS_TYPE_ACK ) {
1048        tx_frame_info->tx_details_type = TX_DETAILS_ACK;
1049    } else {
1050        // Note: this will be overwritten as TX_DETAILS_RTS_ONLY or TX_DETAILS_RTS_MPDU in the PHY report
1051        // if RTS/CTS enabled and the length of this packet is sufficiently large
1052        tx_frame_info->tx_details_type = TX_DETAILS_MPDU;
1053    }
1054
1055    // Pull first byte from the payload of the packet so we can determine whether
1056    // it is a management or data type
1057    frame_control_1 = header->frame_control_1; //Note: header points to DRAM. We aren't relying on the bytes in the Tx packet buffer
1058                                               //that are currently being copied because that would be a race
1059
1060    if(station_info_ptr == NULL){
1061        // If there is no station_info tied to this enqueued packet, something must have gone wrong earlier
1062        // (e.g. there wasn't room in aux. BRAM to create another station_info_t). We should retrieve
1063        // default Tx parameters from the framework.
1064        if(is_multicast){
1065            if( (frame_control_1 & MAC_FRAME_CTRL1_MASK_TYPE) == MAC_FRAME_CTRL1_TYPE_MGMT){
1066                default_tx_params = wlan_mac_get_default_tx_params(mcast_mgmt);
1067            } else {
1068                default_tx_params = wlan_mac_get_default_tx_params(mcast_data);
1069            }
1070        } else {
1071            if( (frame_control_1 & MAC_FRAME_CTRL1_MASK_TYPE) == MAC_FRAME_CTRL1_TYPE_MGMT){
1072                default_tx_params = wlan_mac_get_default_tx_params(unicast_mgmt);
1073            } else {
1074                default_tx_params = wlan_mac_get_default_tx_params(unicast_data);
1075            }
1076        }
1077
1078        memcpy(&(tx_frame_info->params), &default_tx_params, sizeof(tx_params_t));
1079
1080    } else {
1081        if( (frame_control_1 & MAC_FRAME_CTRL1_MASK_TYPE) == MAC_FRAME_CTRL1_TYPE_MGMT){
1082            memcpy(&(tx_frame_info->params), &(station_info_ptr->tx_params_mgmt), sizeof(tx_params_t));
1083        } else {
1084            memcpy(&(tx_frame_info->params), &(station_info_ptr->tx_params_data), sizeof(tx_params_t));
1085        }
1086        //Sanitize tx_params based on HT capability of STA
1087        wlan_mac_sanitize_tx_params(station_info_ptr, &(tx_frame_info->params));
1088    }
1089
1090    // Wait for transfer to finish
1091    wlan_mac_high_cdma_finish_transfer();
1092
1093    ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_TX_PKT_BUF_READY);
1094    ipc_msg_to_low.arg0              = tx_pkt_buf;
1095    ipc_msg_to_low.num_payload_words = 0;
1096
1097    // Set the packet buffer state to READY
1098    tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_READY;
1099
1100    // Note: at this point in the code, the packet buffer state has been modified to TX_PKT_BUF_READY,
1101    // yet we have not sent the IPC_MBOX_TX_PKT_BUF_READY message. If we happen to reboot here,
1102    // this packet buffer will be abandoned and won't be cleaned up in the boot process. This is a narrow
1103    // race in practice, but step-by-step debugging can accentuate the risk since there can be an arbitrary
1104    // amount of time spent in this window.
1105
1106    if(unlock_tx_pkt_buf(tx_pkt_buf) == PKT_BUF_MUTEX_FAIL_NOT_LOCK_OWNER){
1107        // The unlock failed because CPU_LOW currently has the mutex lock. We will not
1108        // submit a READY message for this packet. Instead, we'll drop it and revert
1109        // the state of the packet buffer to TX_PKT_BUF_HIGH_CTRL. CPU_LOW will unlock the
1110        // packet buffer when it is done transmitting from it or if it reboots. At that
1111        // point, we will clean up and be able to use this packet buffer again for future
1112        // transmissions.
1113        wlan_printf(PL_ERROR, "Error: unable to unlock tx pkt_buf %d\n",tx_pkt_buf);
1114        tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
1115    } else {
1116        // We successfully unlocked the packet buffer or we failed to unlock it because
1117        // it was already unlocked. In either case, we can submit this READY message.
1118        write_mailbox_msg(&ipc_msg_to_low);
1119    }
1120}
1121
1122/**
1123 * @brief WLAN MAC IPC processing function for CPU High
1124 *
1125 * Process IPC message from CPU low
1126 *
1127 * @param  wlan_ipc_msg* msg
1128 *     - Pointer to the IPC message
1129 * @param  u32* ipc_msg_from_low_payload
1130 *     - Pointer to the payload of the IPC message
1131 * @return None
1132 */
1133void wlan_mac_high_process_ipc_msg(wlan_ipc_msg_t* msg, u32* ipc_msg_from_low_payload) {
1134    u8 rx_pkt_buf;
1135    u8 tx_pkt_buf;
1136    rx_frame_info_t* rx_frame_info;
1137    tx_frame_info_t* tx_frame_info;
1138
1139    // Determine what type of message this is
1140    switch(IPC_MBOX_MSG_ID_TO_MSG(msg->msg_id)) {
1141
1142        //---------------------------------------------------------------------
1143        case IPC_MBOX_TX_BEACON_DONE:{
1144            wlan_mac_low_tx_details_t* tx_low_details;
1145            tx_low_entry* tx_low_event_log_entry = NULL;
1146            station_info_t* station_info;
1147
1148            tx_pkt_buf = msg->arg0;
1149            if(tx_pkt_buf == TX_PKT_BUF_BEACON){
1150                if(lock_tx_pkt_buf(tx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS){
1151                    xil_printf("Error: CPU_LOW had lock on Beacon packet buffer during IPC_MBOX_TX_BEACON_DONE\n");
1152                } else {
1153                    tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf);
1154                    tx_low_details = (wlan_mac_low_tx_details_t*)(msg->payload_ptr);
1155
1156                    tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
1157
1158                    //We will pass this completed transmission off to the Station Info subsystem
1159                    station_info_posttx_process((void*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf)));
1160
1161#if WLAN_SW_CONFIG_ENABLE_LOGGING
1162                    // Log the TX low
1163                    tx_low_event_log_entry = wlan_exp_log_create_tx_low_entry(tx_frame_info, tx_low_details);
1164#endif
1165
1166                    beacon_tx_done_callback( tx_frame_info, tx_low_details, tx_low_event_log_entry );
1167
1168                    // Apply latest broadcast management tx_params in case that they have changed
1169                    station_info = station_info_create((u8*)bcast_addr);
1170                    tx_frame_info->params = station_info->tx_params_mgmt;
1171
1172                    tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_READY;
1173                    if(unlock_tx_pkt_buf(tx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS){
1174                        xil_printf("Error: Unable to unlock Beacon packet buffer during IPC_MBOX_TX_BEACON_DONE\n");
1175                        return;
1176                    }
1177                }
1178            } else {
1179                xil_printf("Error: IPC_MBOX_TX_BEACON_DONE with invalid pkt buf index %d\n ", tx_pkt_buf);
1180            }
1181        }
1182        break;
1183
1184        //---------------------------------------------------------------------
1185        case IPC_MBOX_RX_PKT_BUF_READY: {
1186            // CPU Low has received an MPDU addressed to this node or to the broadcast address
1187
1188            station_info_t* station_info;
1189#pragma GCC diagnostic push
1190#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
1191            // Depending on the state of WLAN_SW_CONFIG_ENABLE_TXRX_COUNTS, this variable
1192            // may be assigned but never used. We'll suppress the warning if it shows up.
1193            u32 mpdu_rx_process_flags;
1194#pragma GCC diagnostic pop
1195
1196            rx_common_entry* rx_event_log_entry = NULL;
1197
1198            rx_pkt_buf = msg->arg0;
1199            if(rx_pkt_buf < NUM_RX_PKT_BUFS){
1200                rx_frame_info = (rx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.rx_pkt_buf_baseaddr, rx_pkt_buf);
1201
1202                switch(rx_frame_info->rx_pkt_buf_state){
1203                   case RX_PKT_BUF_READY:
1204                       // Normal Rx process - buffer contains packet ready for de-encap and logging
1205                       // Attempt to lock the indicated Rx pkt buf (CPU Low must unlock it before sending this msg)
1206                        if(lock_rx_pkt_buf(rx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS){
1207                            wlan_printf(PL_ERROR, "Error: unable to lock pkt_buf %d\n", rx_pkt_buf);
1208                        } else {
1209
1210                            rx_frame_info->rx_pkt_buf_state = RX_PKT_BUF_HIGH_CTRL;
1211
1212                            //Before calling the user's callback, we'll pass this reception off to the BSS info subsystem so it can scrape for BSS metadata
1213                            network_info_rx_process((void*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.rx_pkt_buf_baseaddr, rx_pkt_buf)));
1214
1215                            //We will also pass this reception off to the Station Info subsystem
1216                            station_info = station_info_postrx_process((void*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.rx_pkt_buf_baseaddr, rx_pkt_buf)));
1217
1218#if WLAN_SW_CONFIG_ENABLE_LOGGING
1219                            //Log this RX event
1220                            rx_event_log_entry = wlan_exp_log_create_rx_entry(rx_frame_info);
1221#endif
1222
1223                            // Call the RX callback function to process the received packet
1224                            mpdu_rx_process_flags = mpdu_rx_callback((void*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.rx_pkt_buf_baseaddr, rx_pkt_buf)), station_info, rx_event_log_entry);
1225
1226                            station_info_rx_process_hostname( (void*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.rx_pkt_buf_baseaddr, rx_pkt_buf)), station_info );
1227
1228#if WLAN_SW_CONFIG_ENABLE_TXRX_COUNTS
1229                            if( (mpdu_rx_process_flags & MAC_RX_CALLBACK_RETURN_FLAG_NO_COUNTS) == 0 ){
1230                                if(mpdu_rx_process_flags & MAC_RX_CALLBACK_RETURN_FLAG_DUP){
1231                                    station_info_rx_process_counts((void*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.rx_pkt_buf_baseaddr, rx_pkt_buf)), station_info, RX_PROCESS_COUNTS_OPTION_FLAG_IS_DUPLICATE);
1232                                } else {
1233                                    station_info_rx_process_counts((void*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.rx_pkt_buf_baseaddr, rx_pkt_buf)), station_info, 0);
1234                                }
1235                            }
1236#endif
1237                            if(unlock_rx_pkt_buf(rx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS){
1238                                wlan_printf(PL_ERROR, "Error: unable to unlock rx pkt_buf %d\n", rx_pkt_buf);
1239                            }
1240
1241                            // Free up the rx_pkt_buf
1242                            rx_frame_info->rx_pkt_buf_state = RX_PKT_BUF_LOW_CTRL;
1243                        }
1244                   break;
1245                   default:
1246                   case RX_PKT_BUF_HIGH_CTRL:
1247                       //  Don't de-encap - just clean up and return
1248                       rx_frame_info->rx_pkt_buf_state = RX_PKT_BUF_LOW_CTRL;
1249                   case RX_PKT_BUF_UNINITIALIZED:
1250                   case RX_PKT_BUF_LOW_CTRL:
1251                       if(unlock_rx_pkt_buf(rx_pkt_buf) == PKT_BUF_MUTEX_SUCCESS){
1252                            wlan_printf(PL_ERROR, "Error: state mismatch; CPU_HIGH owned the lock on rx pkt_buf %d\n", rx_pkt_buf);
1253                       }
1254                   break;
1255                }
1256            } else {
1257                xil_printf("Error: IPC_MBOX_RX_MPDU_READY with invalid pkt buf index %d\n ", rx_pkt_buf);
1258            }
1259
1260        } break;
1261
1262        //---------------------------------------------------------------------
1263        case IPC_MBOX_PHY_TX_REPORT: {
1264            wlan_mac_low_tx_details_t* tx_low_details;
1265            tx_low_entry* tx_low_event_log_entry = NULL;
1266            station_info_t* station_info;
1267
1268            tx_pkt_buf = msg->arg0;
1269            if(tx_pkt_buf < NUM_TX_PKT_BUFS){
1270                tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf);
1271                tx_low_details = (wlan_mac_low_tx_details_t*)(msg->payload_ptr);
1272#if WLAN_SW_CONFIG_ENABLE_LOGGING
1273                tx_low_event_log_entry = wlan_exp_log_create_tx_low_entry(tx_frame_info, tx_low_details);
1274#endif //WLAN_SW_CONFIG_ENABLE_LOGGING
1275                station_info = station_info_txreport_process((void*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf)), tx_low_details);
1276                mpdu_tx_low_done_callback(tx_frame_info, station_info, tx_low_details, tx_low_event_log_entry);
1277            }
1278        }
1279        break;
1280
1281        //---------------------------------------------------------------------
1282        case IPC_MBOX_TX_PKT_BUF_DONE: {
1283            // CPU Low has finished the Tx process for the previously submitted-accepted frame
1284            //     CPU High should do any necessary post-processing, then recycle the packet buffer
1285            //
1286
1287            tx_high_entry* tx_high_event_log_entry = NULL;
1288            station_info_t* station_info;
1289
1290            tx_pkt_buf = msg->arg0;
1291            if(tx_pkt_buf < NUM_TX_PKT_BUFS){
1292                tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf);
1293                switch(tx_frame_info->tx_pkt_buf_state){
1294                    case TX_PKT_BUF_DONE:
1295                        // Expected state after CPU Low finishes Tx
1296                        //  Run normal post-tx processing
1297                        // Lock this packet buffer
1298                        if(lock_tx_pkt_buf(tx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS){
1299                            xil_printf("Error: DONE Lock Tx Pkt Buf State Mismatch\n");
1300                            tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
1301                            return;
1302                        }
1303
1304                        //We can now attempt to dequeue any pending transmissions before we fully process
1305                        //this done message.
1306                        tx_poll_callback();
1307
1308                        //We will pass this completed transmission off to the Station Info subsystem
1309                        station_info = station_info_posttx_process((void*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf)));
1310
1311#if WLAN_SW_CONFIG_ENABLE_LOGGING
1312                        // Log the high-level transmission and call the application callback
1313                        tx_high_event_log_entry = wlan_exp_log_create_tx_high_entry(tx_frame_info);
1314#endif //WLAN_SW_CONFIG_ENABLE_LOGGING
1315                        mpdu_tx_high_done_callback(tx_frame_info, station_info, tx_high_event_log_entry);
1316
1317                        tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
1318                    break;
1319                    // Something has gone wrong - TX_DONE message disagrees
1320                    //  with state of Tx pkt buf
1321                    case TX_PKT_BUF_UNINITIALIZED:
1322                    case TX_PKT_BUF_HIGH_CTRL:
1323                        // CPU High probably rebooted, initialized Tx pkt buffers
1324                        //  then got TX_DONE message from pre-reboot
1325                        // Ignore the contents, force-lock the buffer, and
1326                        //  leave it TX_PKT_BUF_HIGH_CTRL, will be used by future ping-pong rotation
1327                        force_lock_tx_pkt_buf(tx_pkt_buf);
1328                        tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
1329                    case TX_PKT_BUF_READY:
1330                    case TX_PKT_BUF_LOW_CTRL:
1331                        //CPU Low will clean up
1332                        // Unlikely CPU High holds lock, but unlock just in case
1333                        unlock_tx_pkt_buf(tx_pkt_buf);
1334                    break;
1335                }
1336            } else {
1337                xil_printf("Error: IPC_MBOX_TX_PKT_BUF_DONE with invalid pkt buf index %d\n ", tx_pkt_buf);
1338            }
1339
1340        } break;
1341
1342
1343        //---------------------------------------------------------------------
1344        case IPC_MBOX_CPU_STATUS:
1345            // CPU low's status
1346            //
1347
1348            // cpu_low_status isn't needed to process this IPC message since there is an explicit
1349            // reason provided in the arg0 field of the message. However, we'll copy the information
1350            // into the global in case any future process wants record of it.
1351            cpu_low_status = ipc_msg_from_low_payload[0];
1352
1353            switch( msg->arg0 ){
1354                case CPU_STATUS_REASON_EXCEPTION:
1355                    wlan_printf(PL_ERROR, "ERROR:  An unrecoverable exception has occurred in CPU_LOW, halting...\n");
1356                    wlan_printf(PL_ERROR, "    Reason code: %d\n", ipc_msg_from_low_payload[1]);
1357                    wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_CPU_ERROR, WLAN_ERROR_CPU_STOP);
1358                break;
1359
1360                case CPU_STATUS_REASON_BOOTED:
1361
1362                    // Notify the high-level project that CPU_LOW has rebooted
1363                    cpu_low_reboot_callback(ipc_msg_from_low_payload[1]);
1364
1365                    // Set any of low parameters that have been modified and
1366                    //  the MAC High Framework is responsible for tracking
1367                    if(low_param_channel != 0xFFFFFFFF)     wlan_mac_high_set_radio_channel(low_param_channel);
1368                    if(low_param_dsss_en != 0xFFFFFFFF)     wlan_mac_high_set_dsss(low_param_dsss_en);
1369                    if(low_param_rx_ant_mode != 0xFF)       wlan_mac_high_set_rx_ant_mode(low_param_rx_ant_mode);
1370                    if(low_param_tx_ctrl_pow != -127)       wlan_mac_high_set_tx_ctrl_power(low_param_tx_ctrl_pow);
1371                    if(low_param_radio_tx_pow != -127)      wlan_mac_high_set_radio_tx_power(low_param_radio_tx_pow);
1372                    if(low_param_rx_filter != 0xFFFFFFFF)   wlan_mac_high_set_rx_filter_mode(low_param_rx_filter);
1373                    if(low_param_random_seed != 0xFFFFFFFF) wlan_mac_high_set_srand(low_param_random_seed);
1374
1375                    // Attempt to dequeue and fill any available Tx packet buffers
1376                    tx_poll_callback();
1377                break;
1378
1379                case CPU_STATUS_REASON_RESPONSE:
1380                    // Set the CPU_LOW wlan_exp type
1381#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP
1382                    {
1383                        compilation_details_t* compilation_details = (compilation_details_t*)(&ipc_msg_from_low_payload[2]);
1384                        wlan_exp_node_set_type_low(ipc_msg_from_low_payload[1], compilation_details->compilation_date, compilation_details->compilation_time);
1385                    }
1386#endif
1387                default:
1388
1389                break;
1390            }
1391        break;
1392
1393
1394        //---------------------------------------------------------------------
1395        case IPC_MBOX_MEM_READ_WRITE:
1396            // Memory Read / Write message
1397            //   - Allows CPU High to read / write arbitrary memory locations in CPU low
1398            //
1399            if(cpu_low_reg_read_buffer != NULL){
1400                memcpy( (u8*)cpu_low_reg_read_buffer, (u8*)ipc_msg_from_low_payload, (msg->num_payload_words) * sizeof(u32));
1401                cpu_low_reg_read_buffer_status = CPU_LOW_REG_READ_BUFFER_STATUS_READY;
1402
1403            } else {
1404                wlan_printf(PL_ERROR, "ERROR: Received low-level register buffer from CPU_LOW and was not expecting it.\n");
1405            }
1406        break;
1407
1408
1409        //---------------------------------------------------------------------
1410        case IPC_MBOX_LOW_PARAM:
1411            // CPU Low Parameter IPC message
1412            //   - Processes any CPU Low Parameter IPC messages sent to CPU High
1413            //   - This is an error condition.  CPU High should never expect this IPC message
1414            //
1415            // NOTE:  This is due to the fact that IPC messages in CPU low can take an infinitely long amount of
1416            //     to return given that the sending and receiving of wireless data takes precedent.  Therefore,
1417            //     it is not good to try to return values from CPU low since there is no guarantee when the values
1418            //     will be available.
1419            //
1420            wlan_printf(PL_ERROR, "ERROR: Received low-level parameter buffer from CPU_LOW and was not expecting it.\n");
1421        break;
1422
1423
1424        //---------------------------------------------------------------------
1425        default:
1426            wlan_printf(PL_ERROR, "ERROR: Unknown IPC message type %d\n", IPC_MBOX_MSG_ID_TO_MSG(msg->msg_id));
1427        break;
1428    }
1429}
1430
1431
1432
1433/**
1434 * @brief Set Random Seed
1435 *
1436 * Send an IPC message to CPU Low to set the Random Seed
1437 *
1438 * @param  u32 seed
1439 *     - Random number generator seed
1440 * @return None
1441 */
1442void wlan_mac_high_set_srand(u32 seed) {
1443
1444    wlan_ipc_msg_t ipc_msg_to_low;
1445    u32 ipc_msg_to_low_payload = seed;
1446
1447    //Set tracking global
1448    low_param_random_seed = seed;
1449
1450    // Send message to CPU Low
1451    ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_LOW_RANDOM_SEED);
1452    ipc_msg_to_low.num_payload_words = 1;
1453    ipc_msg_to_low.payload_ptr       = &(ipc_msg_to_low_payload);
1454
1455    write_mailbox_msg(&ipc_msg_to_low);
1456}
1457
1458
1459/**
1460 * @brief Convert BSS Channel Specification to Radio Channel
1461 *
1462 * Converts a BSS channel specification to a radio channel
1463 * for use in wlan_mac_high_set_radio_channel. When extended
1464 * to support HT40, this function will grow more complex.
1465 *
1466 * @param  chan_spec_t* chan_spec
1467 *     - Pointer to BSS Channel Specification
1468 * @return None
1469 */
1470u8 wlan_mac_high_bss_channel_spec_to_radio_chan(chan_spec_t chan_spec) {
1471    return chan_spec.chan_pri;
1472}
1473
1474/**
1475 * @brief Set Radio Channel
1476 *
1477 * Send an IPC message to CPU Low to set the MAC Channel
1478 *
1479 * @param  u32 mac_channel
1480 *     - 802.11 Channel to set
1481 * @return None
1482 */
1483void wlan_mac_high_set_radio_channel(u32 mac_channel) {
1484
1485    wlan_ipc_msg_t ipc_msg_to_low;
1486    u32 ipc_msg_to_low_payload = mac_channel;
1487
1488    if(wlan_verify_channel(mac_channel) == WLAN_SUCCESS){
1489        //Set tracking global
1490        low_param_channel = mac_channel;
1491
1492        // Send message to CPU Low
1493        ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_CONFIG_CHANNEL);
1494        ipc_msg_to_low.num_payload_words = 1;
1495        ipc_msg_to_low.payload_ptr       = &(ipc_msg_to_low_payload);
1496
1497        write_mailbox_msg(&ipc_msg_to_low);
1498    } else {
1499        xil_printf("Channel %d not allowed\n", mac_channel);
1500    }
1501}
1502
1503void wlan_mac_high_enable_mcast_buffering(u8 enable){
1504    wlan_ipc_msg_t ipc_msg_to_low;
1505
1506    // Send message to CPU Low
1507    ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_MCAST_BUFFER_ENABLE);
1508    ipc_msg_to_low.num_payload_words = 0;
1509    ipc_msg_to_low.arg0              = enable;
1510
1511    write_mailbox_msg(&ipc_msg_to_low);
1512}
1513
1514void wlan_mac_high_config_txrx_beacon(beacon_txrx_config_t* beacon_txrx_config){
1515    wlan_ipc_msg_t ipc_msg_to_low;
1516
1517    // Send message to CPU Low
1518    ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_TXRX_BEACON_CONFIG);
1519    ipc_msg_to_low.num_payload_words = sizeof(beacon_txrx_config_t)/sizeof(u32);
1520    ipc_msg_to_low.payload_ptr       = (u32*)beacon_txrx_config;
1521
1522    write_mailbox_msg(&ipc_msg_to_low);
1523
1524}
1525
1526/**
1527 * @brief Set Rx Antenna Mode
1528 *
1529 * Send an IPC message to CPU Low to set the Rx antenna mode.
1530 *
1531 * @param  u8 ant_mode
1532 *     - Antenna mode selection
1533 * @return None
1534 */
1535void wlan_mac_high_set_rx_ant_mode(u8 ant_mode) {
1536    wlan_ipc_msg_t ipc_msg_to_low;
1537    u32 ipc_msg_to_low_payload = (u32)ant_mode;
1538
1539    //Sanity check input
1540    switch(ant_mode){
1541        case RX_ANTMODE_SISO_ANTA:
1542        case RX_ANTMODE_SISO_ANTB:
1543        case RX_ANTMODE_SISO_ANTC:
1544        case RX_ANTMODE_SISO_ANTD:
1545        case RX_ANTMODE_SISO_SELDIV_2ANT:
1546            //Set tracking global
1547            low_param_rx_ant_mode = ant_mode;
1548        break;
1549        default:
1550            xil_printf("Error: unsupported antenna mode %x\n", ant_mode);
1551            return;
1552        break;
1553    }
1554
1555    // Send message to CPU Low
1556    ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_CONFIG_RX_ANT_MODE);
1557    ipc_msg_to_low.num_payload_words = 1;
1558    ipc_msg_to_low.payload_ptr       = &(ipc_msg_to_low_payload);
1559
1560    write_mailbox_msg(&ipc_msg_to_low);
1561}
1562
1563
1564
1565/**
1566 * @brief Set Tx Control Packet Power
1567 *
1568 * Send an IPC message to CPU Low to set the Tx control packet power
1569 *
1570 * @param  s8 pow
1571 *     - Tx control packet power in dBm
1572 * @return None
1573 */
1574void wlan_mac_high_set_tx_ctrl_power(s8 pow) {
1575
1576    wlan_ipc_msg_t ipc_msg_to_low;
1577    u32 ipc_msg_to_low_payload = (u32)pow;
1578
1579    //Set tracking global
1580    low_param_tx_ctrl_pow = pow;
1581
1582    // Send message to CPU Low
1583    ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_CONFIG_TX_CTRL_POW);
1584    ipc_msg_to_low.num_payload_words = 1;
1585    ipc_msg_to_low.payload_ptr       = &(ipc_msg_to_low_payload);
1586
1587    write_mailbox_msg(&ipc_msg_to_low);
1588}
1589
1590/**
1591 * @brief Set Tx Control Packet Power
1592 *
1593 * Send an IPC message to CPU Low to set the radio's Tx power; applies to
1594 * platforms which do not support per-packet Tx power control
1595 *
1596 * @param  s8 pow
1597 *     - Tx power in dBm
1598 * @return None
1599 */
1600void wlan_mac_high_set_radio_tx_power(s8 pow) {
1601    wlan_ipc_msg_t ipc_msg_to_low;
1602    u32 ipc_msg_to_low_payload = (u32)pow;
1603
1604    //Set tracking global
1605    low_param_radio_tx_pow = pow;
1606
1607    // Send message to CPU Low
1608    ipc_msg_to_low.msg_id = IPC_MBOX_MSG_ID(IPC_MBOX_SET_RADIO_TX_POWER);
1609    ipc_msg_to_low.num_payload_words = 1;
1610    ipc_msg_to_low.payload_ptr       = &(ipc_msg_to_low_payload);
1611
1612    write_mailbox_msg(&ipc_msg_to_low);
1613}
1614
1615
1616
1617/**
1618 * @brief Set Rx Filter
1619 *
1620 * Send an IPC message to CPU Low to set the filter for receptions. This will
1621 * allow or disallow different packets from being passed up to CPU_High
1622 *
1623 * @param    filter_mode
1624 *              - RX_FILTER_FCS_GOOD
1625 *              - RX_FILTER_FCS_ALL
1626 *              - RX_FILTER_ADDR_STANDARD   (unicast to me or multicast)
1627 *              - RX_FILTER_ADDR_ALL_MPDU   (all MPDU frames to any address)
1628 *              - RX_FILTER_ADDR_ALL        (all observed frames, including control)
1629 *
1630 * @note    FCS and ADDR filter selections must be bit-wise ORed together. For example,
1631 *     wlan_mac_high_set_rx_filter_mode(RX_FILTER_FCS_ALL | RX_FILTER_ADDR_ALL)
1632 *
1633 * @return  None
1634 */
1635void wlan_mac_high_set_rx_filter_mode(u32 filter_mode) {
1636
1637    wlan_ipc_msg_t ipc_msg_to_low;
1638    u32 ipc_msg_to_low_payload = (u32)filter_mode;
1639
1640    //Set tracking global
1641    low_param_rx_filter = filter_mode;
1642
1643    // Send message to CPU Low
1644    ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_CONFIG_RX_FILTER);
1645    ipc_msg_to_low.num_payload_words = 1;
1646    ipc_msg_to_low.payload_ptr       = &(ipc_msg_to_low_payload);
1647
1648    write_mailbox_msg(&ipc_msg_to_low);
1649}
1650
1651
1652
1653/**
1654 * @brief Write a memory location in CPU low
1655 *
1656 * Send an IPC message to CPU Low to write the given data
1657 *
1658 * @param   u32 num_words    - Number of words in the message payload
1659 * @param   u32* payload    - Pointer to the message payload
1660 *
1661 * @return  int              - WLAN_SUCCESS or WLAN_FAILURE
1662 */
1663int wlan_mac_high_write_low_mem(u32 num_words, u32* payload) {
1664    wlan_ipc_msg_t ipc_msg_to_low;
1665
1666    if (num_words > MAILBOX_MSG_MAX_NUM_WORDS) {
1667        xil_printf("ERROR: attempted to send LOW_PARAM IPC message with oversize payload! (%d > %d)\n", num_words, MAILBOX_MSG_MAX_NUM_WORDS);
1668        return WLAN_FAILURE;
1669    }
1670
1671    // Send message to CPU Low
1672    ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_MEM_READ_WRITE);
1673    ipc_msg_to_low.num_payload_words = num_words;
1674    ipc_msg_to_low.arg0              = IPC_REG_WRITE_MODE;
1675    ipc_msg_to_low.payload_ptr       = payload;
1676
1677    write_mailbox_msg(&ipc_msg_to_low);
1678
1679    return WLAN_SUCCESS;
1680}
1681
1682
1683
1684/**
1685 * @brief Read a memory location in CPU low
1686 *
1687 * Send an IPC message to CPU Low to read the given data
1688 *
1689 * @param   u32 num_words    - Number of words to read from CPU low
1690 * @param   u32 baseaddr     - Base address of the data to read from CPU low
1691 * @param   u32* payload    - Pointer to the buffer to be populated with data
1692 *
1693 * @return  int              - WLAN_SUCCESS or WLAN_FAILURE
1694 */
1695int wlan_mac_high_read_low_mem(u32 num_words, u32 baseaddr, u32* payload) {
1696
1697    u64 start_timestamp;
1698    wlan_ipc_msg_t ipc_msg_to_low;
1699    ipc_reg_read_write_t ipc_msg_to_low_payload;
1700
1701    if(wlan_platform_intc_get_state() == INTERRUPTS_ENABLED) {
1702        // Send message to CPU Low
1703        ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_MEM_READ_WRITE);
1704        ipc_msg_to_low.num_payload_words = sizeof(ipc_reg_read_write_t) / sizeof(u32);
1705        ipc_msg_to_low.arg0              = IPC_REG_READ_MODE;
1706        ipc_msg_to_low.payload_ptr       = (u32*)(&(ipc_msg_to_low_payload));
1707
1708        ipc_msg_to_low_payload.baseaddr  = baseaddr;
1709        ipc_msg_to_low_payload.num_words = num_words;
1710
1711        // Set the read buffer to the payload pointer
1712        cpu_low_reg_read_buffer          = payload;
1713        cpu_low_reg_read_buffer_status   = CPU_LOW_REG_READ_BUFFER_STATUS_NOT_READY;
1714
1715        write_mailbox_msg(&ipc_msg_to_low);
1716
1717        // Get start time
1718        start_timestamp = get_system_time_usec();
1719
1720        // Wait for CPU low to finish the read or timeout to occur
1721        while(cpu_low_reg_read_buffer_status != CPU_LOW_REG_READ_BUFFER_STATUS_READY){
1722            if ((get_system_time_usec() - start_timestamp) > WLAN_EXP_CPU_LOW_DATA_REQ_TIMEOUT) {
1723                xil_printf("Error: Reading CPU_LOW memory timed out\n");
1724
1725                // Reset the read buffer
1726                cpu_low_reg_read_buffer  = NULL;
1727
1728                return WLAN_FAILURE;
1729            }
1730        }
1731
1732        // Reset the read buffer
1733        cpu_low_reg_read_buffer          = NULL;
1734
1735    } else {
1736        xil_printf("ERROR (wlan_mac_high_read_low_mem): cannot read low memory when interrupts are disabled\n");
1737        return WLAN_FAILURE;
1738    }
1739
1740    return WLAN_SUCCESS;
1741}
1742
1743
1744
1745/**
1746 * @brief Write a parameter in CPU low
1747 *
1748 * Send an IPC message to CPU Low to write the given parameter
1749 *
1750 * @param   u32 num_words    - Number of words in the message payload
1751 * @param   u32 * payload    - Pointer to the message payload (includes parameter ID)
1752 *
1753 * @return  int              - WLAN_SUCCESS or WLAN_FAILURE
1754 */
1755int wlan_mac_high_write_low_param(u32 num_words, u32* payload) {
1756    wlan_ipc_msg_t ipc_msg_to_low;
1757
1758    if (num_words > MAILBOX_MSG_MAX_NUM_WORDS) {
1759        xil_printf("ERROR: attempted to send LOW_PARAM IPC message with oversize payload! (%d > %d)\n", num_words, MAILBOX_MSG_MAX_NUM_WORDS);
1760        return WLAN_FAILURE;
1761    }
1762
1763    // Send message to CPU Low
1764    ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_LOW_PARAM);
1765    ipc_msg_to_low.num_payload_words = num_words;
1766    ipc_msg_to_low.arg0              = IPC_REG_WRITE_MODE;
1767    ipc_msg_to_low.payload_ptr       = payload;
1768
1769    write_mailbox_msg(&ipc_msg_to_low);
1770
1771    return WLAN_SUCCESS;
1772}
1773
1774
1775
1776/**
1777 * @brief Enable/Disable DSSS
1778 *
1779 * Send an IPC message to CPU Low to set the DSSS value
1780 *
1781 * @param  u32 dsss_value
1782 *     - DSSS Enable/Disable value
1783 * @return None
1784 */
1785void wlan_mac_high_set_dsss(u32 dsss_value) {
1786
1787    wlan_ipc_msg_t ipc_msg_to_low;
1788    u32 ipc_msg_to_low_payload = dsss_value;
1789
1790    //Set tracking global
1791    low_param_dsss_en = dsss_value;
1792
1793    // Send message to CPU Low
1794    ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_CONFIG_DSSS_EN);
1795    ipc_msg_to_low.num_payload_words = 1;
1796    ipc_msg_to_low.payload_ptr       = &(ipc_msg_to_low_payload);
1797
1798    write_mailbox_msg(&ipc_msg_to_low);
1799}
1800
1801
1802
1803/**
1804 * @brief Get CPU low's state
1805 *
1806 * Send an IPC message to CPU Low to get its state
1807 *
1808 * @param  None
1809 * @return None
1810 */
1811void wlan_mac_high_request_low_state(){
1812    wlan_ipc_msg_t ipc_msg_to_low;
1813
1814    // Send message to CPU Low
1815    ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_CPU_STATUS);
1816    ipc_msg_to_low.num_payload_words = 0;
1817    ipc_msg_to_low.arg0              = (u8)CPU_STATUS_REASON_BOOTED;
1818
1819    write_mailbox_msg(&ipc_msg_to_low);
1820}
1821
1822
1823/**
1824* @brief Check that CPU low is initialized
1825*
1826* @param  None
1827* @return int
1828*     - 0 if CPU low is not initialized
1829*     - 1 if CPU low is initialized
1830*/
1831int wlan_mac_high_is_cpu_low_initialized(){
1832    wlan_mac_high_ipc_rx();
1833    return ( (cpu_low_status & CPU_STATUS_INITIALIZED) != 0 );
1834}
1835
1836/**
1837 * @brief Check the number of available tx packet buffers for an available group
1838 *
1839 * @param  pkt_buf_group_t pkt_buf_group
1840 * @return int
1841 *     - number of tx packet buffers that can be filled
1842 */
1843inline u8 wlan_mac_num_tx_pkt_buf_available(pkt_buf_group_t pkt_buf_group) {
1844
1845    u8 i, num_empty, num_low_owned;
1846    tx_frame_info_t* tx_frame_info;
1847
1848    num_empty = 0;
1849    num_low_owned = 0;
1850
1851    for( i = 0; i < NUM_TX_PKT_BUF_MPDU; i++ ) {
1852        tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, i);
1853
1854        if( tx_frame_info->tx_pkt_buf_state == TX_PKT_BUF_HIGH_CTRL ) {
1855            num_empty++;
1856        }
1857
1858        if( (tx_frame_info->queue_info.pkt_buf_group == pkt_buf_group) &&
1859            ( (tx_frame_info->tx_pkt_buf_state == TX_PKT_BUF_READY) ||
1860              (tx_frame_info->tx_pkt_buf_state == TX_PKT_BUF_LOW_CTRL))) {
1861            num_low_owned++;
1862        }
1863    }
1864
1865    // The first requirement for being allowed to dequeue is that there is at least one empty packet buffer.
1866
1867    // The second requirement for being allowed to dequeue is that no more than one packet buffer is currently
1868    // in the TX_PKT_BUF_READY or TX_PKT_BUF_LOW_CTRL for pkt_buf_group of PKT_BUF_GROUP_GENERAL and no more than two
1869    // for PKT_BUF_GROUP_DTIM_MCAST
1870
1871    if(num_empty == 0) {
1872        return 0;
1873    }
1874
1875    if(pkt_buf_group==PKT_BUF_GROUP_GENERAL) {
1876        if(num_low_owned > 2) {
1877            // Should never happen - clip to 2 to restore sanity from here on
1878            xil_printf("WARNING: wlan_mac_num_tx_pkt_buf_available found %d GENERAL buffers owned by low!\n", num_low_owned);
1879            num_low_owned = 2;
1880        }
1881
1882        // Return 1 (if one buffer is already filled) or 2 (if both can be filled)
1883        return WLAN_MIN(num_empty, (2 - num_low_owned));
1884
1885    } else if(pkt_buf_group==PKT_BUF_GROUP_DTIM_MCAST) {
1886        if(num_low_owned > 3) {
1887            // Should never happen - clip to 3 to restore sanity from here on
1888            xil_printf("WARNING: wlan_mac_num_tx_pkt_buf_available found %d DTIM_MCAST buffers owned by low!\n", num_low_owned);
1889            num_low_owned = 3;
1890        }
1891
1892        // Return 3 if all buffers are available, otherwise 1 or 2
1893        return WLAN_MIN(num_empty, (3 - num_low_owned));
1894
1895    } else {
1896        // Invalid packet buffer group
1897        return 0;
1898    }
1899
1900}
1901
1902
1903
1904/**
1905 * @brief Return the index of the next free transmit packet buffer
1906 *
1907 * @param  None
1908 * @return int
1909 *     - packet buffer index of free, now-locked packet buffer
1910 *     - -1 if there are no free Tx packet buffers
1911 */
1912int wlan_mac_high_get_empty_tx_packet_buffer(){
1913
1914    //TODO: Debate: This function assumes that it is currently safe to take control
1915    // of an empty Tx packet buffer. In other words, it is the responsibility of the
1916    // the calling function to ensure that wlan_mac_is_tx_pkt_buf_available() == 1.
1917    // For extra safety, we could call wlan_mac_is_tx_pkt_buf_available() here at the
1918    // expensive of another search through the three packet buffers.
1919
1920    u8 i;
1921    int pkt_buf_sel = -1;
1922
1923    for( i = 0; i < NUM_TX_PKT_BUF_MPDU; i++ ){
1924        if( ((tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, i))->tx_pkt_buf_state == TX_PKT_BUF_HIGH_CTRL ){
1925            pkt_buf_sel = i;
1926            break;
1927        }
1928    }
1929    return pkt_buf_sel;
1930}
1931
1932/**
1933 * @brief Determine if Packet is LTG
1934 * This function inspects the payload of the packet provided as an argument
1935 * and searches for the LTG-specific LLC header. If it finds such a header,
1936 * it returns a 1.
1937 *
1938 * @param  None
1939 * @return u8
1940 *     - 1 if LTG
1941 *     - 0 if not LTG
1942 */
1943u8 wlan_mac_high_is_pkt_ltg(void* mac_payload, u16 length){
1944
1945    mac_header_80211* hdr_80211;
1946    llc_header_t* llc_hdr;
1947
1948    hdr_80211 = (mac_header_80211*)((void*)mac_payload);
1949
1950    if((hdr_80211->frame_control_1 & 0xF) == MAC_FRAME_CTRL1_TYPE_DATA) {
1951
1952        //Check if this is an encrypted packet. If it is, we can't trust any of the MPDU
1953        //payload bytes for further classification
1954        if(hdr_80211->frame_control_2 & MAC_FRAME_CTRL2_FLAG_PROTECTED){
1955            return 0;
1956        }
1957
1958        llc_hdr = (llc_header_t*)((u8*)mac_payload + sizeof(mac_header_80211));
1959
1960        if(length < (sizeof(mac_header_80211) + sizeof(llc_header_t) + WLAN_PHY_FCS_NBYTES)){
1961            // This was a DATA packet, but it wasn't long enough to have an LLC header.
1962            return 0;
1963
1964        } else {
1965            if(llc_hdr->type == LLC_TYPE_WLAN_LTG){
1966                return 1;
1967            }
1968        }
1969    }
1970
1971    return 0;
1972}
1973
1974
1975
1976/**
1977 * @brief Configure Beacon Transmissions
1978 *
1979 * This function will create a beacon and inform CPU_LOW to transmit it periodically.
1980 *
1981 */
1982
1983int wlan_mac_high_configure_beacon_tx_template(u8* addr1,
1984                                               u8* addr2,
1985                                               u8* addr3,
1986                                               network_info_t* network_info,
1987                                               tx_params_t* tx_params_ptr,
1988                                               u8 flags) {
1989    u16 tx_length;
1990
1991    tx_frame_info_t*  tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, TX_PKT_BUF_BEACON);
1992    if(lock_tx_pkt_buf(TX_PKT_BUF_BEACON) != PKT_BUF_MUTEX_SUCCESS){
1993        xil_printf("Error: CPU_LOW had lock on Beacon packet buffer during initial configuration\n");
1994        return WLAN_FAILURE;
1995    }
1996
1997    // Fill in the data
1998    tx_length = wlan_create_beacon_frame( (u8*)(tx_frame_info)+PHY_TX_PKT_BUF_MPDU_OFFSET,
1999                                           addr1,
2000                                           addr2,
2001                                           addr3,
2002                                           network_info);
2003
2004    bzero(tx_frame_info, sizeof(tx_frame_info_t));
2005
2006    // Set up frame info data
2007    tx_frame_info->queue_info.enqueue_timestamp = get_mac_time_usec();
2008    tx_frame_info->length = tx_length;
2009    tx_frame_info->flags = flags;
2010    tx_frame_info->queue_info.id = 0xFF;
2011    tx_frame_info->queue_info.pkt_buf_group = PKT_BUF_GROUP_OTHER;
2012    tx_frame_info->queue_info.occupancy = 0;
2013
2014
2015    // Unique_seq will be filled in by CPU_LOW
2016    tx_frame_info->unique_seq = 0;
2017
2018    memcpy(&(tx_frame_info->params), tx_params_ptr, sizeof(tx_params_t));
2019
2020    tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_READY;
2021    if(unlock_tx_pkt_buf(TX_PKT_BUF_BEACON) != PKT_BUF_MUTEX_SUCCESS){
2022        xil_printf("Error: Unable to unlock Beacon packet buffer during initial configuration\n");
2023        return WLAN_FAILURE;
2024    }
2025
2026    return WLAN_SUCCESS;
2027}
2028
2029
2030
2031/**
2032 * @brief Update Beacon TX parameters
2033 *
2034 * This function will update the beacon template in the packet buffer with the
2035 * new TX parameters.
2036 *
2037 * This function should be used inside a while loop in order to make sure that
2038 * the update is successful:
2039 *     while (wlan_mac_high_update_beacon_tx_params(&default_multicast_mgmt_tx_params) != 0) {}
2040 *
2041 * @param  tx_params_ptr     - Pointer to tx_params_t structure with new parameters
2042 * @return status            - WLAN_SUCCESS or WLAN_FAILURE
2043 */
2044int wlan_mac_high_update_beacon_tx_params(tx_params_t* tx_params_ptr) {
2045    tx_frame_info_t*  tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, TX_PKT_BUF_BEACON);
2046
2047    if (lock_tx_pkt_buf(TX_PKT_BUF_BEACON) != PKT_BUF_MUTEX_SUCCESS) {
2048        xil_printf("Error: CPU_LOW had lock on Beacon packet buffer during initial configuration\n");
2049        return WLAN_FAILURE;
2050    }
2051
2052    memcpy(&(tx_frame_info->params), tx_params_ptr, sizeof(tx_params_t));
2053
2054    if (unlock_tx_pkt_buf(TX_PKT_BUF_BEACON) != PKT_BUF_MUTEX_SUCCESS) {
2055        xil_printf("Error: Unable to unlock Beacon packet buffer during initial configuration\n");
2056        return WLAN_FAILURE;
2057    }
2058
2059    return WLAN_SUCCESS;
2060}
2061
2062void wlan_mac_sanitize_tx_params(station_info_t* station_info, tx_params_t* tx_params){
2063
2064     // Adjust MCS and PHY_MODE based upon STATION_INFO_CAPABILITIES_HT_CAPABLE flag
2065     // Requested HT MCS: 0 1 2 3 4 5 6 7
2066     // Actual NONHT MCS: 0 2 3 4 5 6 7 7
2067
2068    if (station_info->capabilities & STATION_INFO_CAPABILITIES_HT_CAPABLE) {
2069        // Station is capable of HTMF waveforms -- no need to modify tx_params_ret
2070    } else {
2071        if (tx_params->phy.phy_mode == PHY_MODE_HTMF) {
2072            // Requested rate was HT, adjust the MCS corresponding to the table above
2073            tx_params->phy.phy_mode = PHY_MODE_NONHT;
2074            if ((tx_params->phy.mcs == 0) || (tx_params->phy.mcs == 7)) {
2075                // Do nothing - HT MCS[0,7] map to NONHT[0,7]
2076            } else {
2077                tx_params->phy.mcs = tx_params->phy.mcs + 1;
2078            }
2079        } else {
2080            // Requested rate was non-HT, so do not adjust MCS
2081        }
2082    }
2083    return;
2084}
2085
2086inline void wlan_mac_poll(){
2087    // Poll the platform in case any I/O is not interrupt-based
2088    wlan_platform_high_poll();
2089
2090#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP
2091    // Poll received, filtered UDP frames for wlan_exp
2092    wlan_exp_transport_poll();
2093#endif
2094}
2095
2096int wlan_mac_enqueue_wireless_tx(u16 queue_id, dl_entry* queue_entry){
2097    int status;
2098
2099    if (queue_enqueue_allowed(queue_id) == 0){
2100        xil_printf("ERROR (wlan_mac_enqueue_wireless_tx): queue_id %d enqueue rejected\n", queue_id);
2101        return WLAN_FAILURE;
2102    }
2103
2104    // Update the occupancy of the tx queue for the tx_queue_element
2105    //     NOTE:  This is the best place to record this value since it will catch all cases.  However,
2106    //         when populating the tx_frame_info, be careful to not overwrite this value.  Also, the
2107    //         occupancy value includes itself.
2108    //
2109    ((tx_80211_queue_buffer_t*)(queue_entry->data))->tx_queue_details.enqueue_timestamp = get_mac_time_usec();
2110    ((tx_80211_queue_buffer_t*)(queue_entry->data))->tx_queue_details.occupancy = queue_length(queue_id)+1;//include this entry, which has not been added yet
2111    ((tx_80211_queue_buffer_t*)(queue_entry->data))->tx_queue_details.id = queue_id;
2112
2113    //Increment the num_linked_queue_buffer field in the attached station_info_t. This will prevent
2114    // the framework from removing the station_info_t out from underneath us while this
2115    // packet is enqueued.
2116    ((tx_80211_queue_buffer_t*)(queue_entry->data))->station_info->num_linked_queue_buffer++;
2117
2118    status = queue_enqueue(queue_id, queue_entry);
2119
2120    // Poll the TX queues to see if anything needs to be transmitted
2121    tx_poll_callback();
2122
2123    return status;
2124}
2125
2126void wlan_mac_transmit_wireless(dl_entry* queue_entry){
2127    tx_80211_queue_buffer_t* tx_queue_buffer;
2128    int tx_pkt_buf = -1;
2129    tx_pkt_buf = wlan_mac_high_get_empty_tx_packet_buffer();
2130
2131    if (queue_entry == NULL) return;
2132
2133    if( tx_pkt_buf != -1 ){
2134        // Transmit the queue_entry
2135        //     NOTE:  This copies all the contents of the queue element to the
2136        //         packet buffer so that the queue element can be safely returned
2137        //         to the free pool
2138
2139
2140        tx_queue_buffer = (tx_80211_queue_buffer_t*)(queue_entry->data);
2141
2142        // TODO: flush data cache here if caching is enabled - otherwise
2143        //  the CMDA from DRAM will read stale DRAM contents
2144        //  This is not the only place in our code that requires data cache flush/invalidation
2145        // Xil_DCacheFlushRange((unsigned int)tx_queue_buffer, 4096);
2146        wlan_mac_high_mpdu_transmit(tx_queue_buffer, tx_pkt_buf);
2147
2148        //FIXME: there were two num_linked_queue_buffer decrements - one commented out as of this FIXME, leaving this
2149        // here in case it's related to the ongoing deauthenticate_station/wlan_mac_enqueue_wireless_tx bug search
2150
2151        // Decrement the number of linked queue buffers in the station_info_t so the framework's
2152        // cleanup process can remove it later
2153        //tx_queue_buffer->station_info->num_linked_queue_buffer--;
2154
2155        // Decrement the num_linked_queue_buffer field in the attached station_info_t. If this was the
2156        // last queued packet for this station, this will allow the framework to recycle this
2157        // station_info_t if it also has not been flagged as something to keep.
2158        ((tx_80211_queue_buffer_t*)(queue_entry->data))->station_info->num_linked_queue_buffer--;
2159    } else {
2160        xil_printf("Error in transmit_checkin(): no free Tx packet buffers. Packet was freed without being sent\n");
2161    }
2162
2163    // Check in the queue entry because it is no longer being used
2164    queue_checkin(queue_entry);
2165}
2166
2167void wlan_mac_purge_wireless_tx(u16 queue_id){
2168    tx_80211_queue_buffer_t* tx_queue_buffer;
2169    u32 num_queued;
2170    u32 i;
2171
2172    volatile interrupt_state_t prev_interrupt_state;
2173
2174    num_queued = queue_length(queue_id);
2175
2176    prev_interrupt_state = wlan_platform_intc_stop();
2177    if (num_queued > 0) {
2178        for (i = 0; i < num_queued; i++) {
2179            tx_queue_buffer = (tx_80211_queue_buffer_t*)queue_retrieve_buffer_from_index(queue_id, i);
2180            tx_queue_buffer->station_info->num_linked_queue_buffer--;
2181        }
2182    }
2183    queue_purge(queue_id);
2184    // Re-enable interrupts
2185    wlan_platform_intc_set_state(prev_interrupt_state);
2186
2187    return;
2188}
2189
2190
Note: See TracBrowser for help on using the repository browser.