source: ReferenceDesigns/w3_802.11/c/wlan_mac_low_framework/wlan_mac_low.c

Last change on this file was 6228, checked in by chunter, 3 days ago

added require_pkt_det to LOW_PARAM_OFDM_PKT_DET_THRESH implementation

File size: 57.4 KB
Line 
1/** @file wlan_mac_low.c
2 *  @brief Low-level WLAN MAC High Framework
3 *
4 *  This contains the low-level code for accessing the WLAN MAC Low Framework.
5 *
6 *  @copyright Copyright 2014-2018, 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/***************************** Include Files *********************************/
14
15// Xilinx / Standard library includes
16#include <xil_io.h>
17#include <xio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <xstatus.h>
21
22// WLAN includes
23#include "xparameters.h"
24#include "wlan_platform_common.h"
25#include "wlan_platform_low.h"
26#include "wlan_mac_mailbox_util.h"
27#include "wlan_mac_802_11_defs.h"
28#include "wlan_phy_util.h"
29#include "wlan_mac_low.h"
30#include "wlan_mac_common.h"
31#include "wlan_mac_pkt_buf_util.h"
32
33
34// WLAN Exp includes
35#include "wlan_exp.h"
36
37
38/*************************** Constant Definitions ****************************/
39
40#define DBG_PRINT  0
41
42
43/*********************** Global Variable Definitions *************************/
44
45/*************************** Functions Prototypes ****************************/
46
47
48/*************************** Variable Definitions ****************************/
49static volatile phy_samp_rate_t gl_phy_samp_rate; ///< Current PHY sampling rate
50static volatile u32 mac_param_chan; ///< Current channel of the lower-level MAC
51static volatile u8 mac_param_band; ///< Current band of the lower-level MAC
52static volatile u8 mac_param_dsss_en; ///< Enable / Disable DSSS when possible
53static volatile s8 mac_param_ctrl_tx_pow; ///< Current transmit power (dBm) for control packets
54static volatile u32 mac_param_rx_filter; ///< Current filter applied to packet receptions
55static volatile u8 rx_pkt_buf; ///< Current receive buffer of the lower-level MAC
56
57static u32 cpu_low_status; ///< Status flags that are reported to upper-level MAC
58static u32 cpu_low_type; ///< wlan_exp CPU_LOW type that is reported to upper-level MAC
59static compilation_details_t cpu_low_compilation_details;
60
61// Common Platform Device Info
62platform_common_dev_info_t platform_common_dev_info;
63
64static wlan_ipc_msg_t ipc_msg_from_high; ///< Buffer for incoming IPC messages
65static u32 ipc_msg_from_high_payload[MAILBOX_MSG_MAX_NUM_WORDS]; ///< Buffer for payload of incoming IPC messages
66
67// Callback function pointers
68static function_ptr_t frame_rx_callback;
69static function_ptr_t beacon_txrx_config_callback;
70static function_ptr_t mcast_buffer_enable_callback;
71static function_ptr_t mactime_change_callback;
72static function_ptr_t sample_rate_change_callback;
73static function_ptr_t handle_tx_pkt_buf_ready;
74static function_ptr_t ipc_low_param_callback;
75
76// Unique transmit sequence number
77static volatile u64 unique_seq;
78
79// Constant LUTs for MCS
80static const u16 mcs_to_n_dbps_nonht_lut[] = {24, 36, 48, 72, 96, 144, 192, 216};
81static const u16 mcs_to_n_dbps_htmf_lut[] = {26, 52, 78, 104, 156, 208, 234, 260};
82
83/******************************** Functions **********************************/
84
85
86/*****************************************************************************/
87/**
88 * @brief Initialize MAC Low Framework
89 *
90 * This function initializes the MAC Low Framework by setting
91 * up the hardware and other subsystems in the framework.
92 *
93 * @param   type                - Lower-level MAC type
94 * @param   compilation_details - compilation_details_t struct from low-level application
95 * @return  int                 - Initialization status (0 = success)
96 */
97int wlan_mac_low_init(u32 type, compilation_details_t compilation_details){
98    u32 status;
99    rx_frame_info_t* rx_frame_info;
100    tx_frame_info_t* tx_frame_info;
101    u32 i;
102
103    /**********************************************************************************
104     * Initialize the low platform first - this must happen before the low application
105     *  attempts to use any hardware resources
106     **********************************************************************************/
107    status = wlan_platform_common_init();
108    if(status != 0) {
109        xil_printf("Error in wlan_platform_common_init()! Exiting\n");
110        return -1;
111    }
112    status = wlan_platform_low_init();
113
114    if(status != 0) {
115        xil_printf("Error in wlan_platform_low_init()! Exiting\n");
116        return -1;
117    }
118    /**********************************************************************************/
119
120    // Get the device info
121    platform_common_dev_info = wlan_platform_common_get_dev_info();
122
123    /**********************************************************************************
124     * Initialize the MAC and PHY cores - this must happen before the low application
125     *  attempts any wireless Tx/Rx operations
126     * These calls will reset the MAC and PHY cores, safely interrupting any ongoing
127     *  Tx/Rx events and clearing old MAC state that may remain from a previous boot
128     **********************************************************************************/
129    wlan_phy_init();
130
131    // Set a default physical CS threshold of -62dBm (18.3.10.6)
132    wlan_platform_set_phy_cs_thresh(-62);
133
134    wlan_mac_hw_init();
135
136
137    mac_param_dsss_en = 1;
138    mac_param_band = CHAN_BAND_24GHz;
139    mac_param_ctrl_tx_pow = 10;
140    cpu_low_status = 0;
141    cpu_low_type = type;
142    cpu_low_compilation_details = compilation_details;
143
144    unique_seq = 0;
145
146    //Set the TU Target to the max value
147    wlan_mac_set_tu_target(0xFFFFFFFFFFFFFFFFULL);
148
149    mac_param_rx_filter      = (RX_FILTER_FCS_ALL | RX_FILTER_HDR_ALL);
150
151    frame_rx_callback            = (function_ptr_t) wlan_null_callback;
152    ipc_low_param_callback       = (function_ptr_t) wlan_null_callback;
153    beacon_txrx_config_callback  = (function_ptr_t) wlan_null_callback;
154    mcast_buffer_enable_callback = (function_ptr_t) wlan_null_callback;
155    mactime_change_callback      = (function_ptr_t) wlan_null_callback;
156    sample_rate_change_callback  = (function_ptr_t) wlan_null_callback;
157    handle_tx_pkt_buf_ready      = (function_ptr_t) wlan_null_callback;
158
159    // Initialize mailbox
160    init_mailbox();
161
162    // Initialize packet buffers
163    init_pkt_buf();
164
165    // ***************************************************
166    // Initialize Transmit Packet Buffers
167    // ***************************************************
168    for(i = 0; i < NUM_TX_PKT_BUFS; i++){
169        tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, i);
170        switch(i){
171            case TX_PKT_BUF_MPDU_1:
172            case TX_PKT_BUF_MPDU_2:
173            case TX_PKT_BUF_MPDU_3:
174                switch(tx_frame_info->tx_pkt_buf_state){
175                    case TX_PKT_BUF_UNINITIALIZED:
176                    case TX_PKT_BUF_HIGH_CTRL:
177                        // CPU High will initialize
178                        break;
179                    break;
180                    case TX_PKT_BUF_READY:
181                    case TX_PKT_BUF_DONE:
182                        // CPU Low rebooted after finishing old Tx
183                        // No way to know if CPU Low sent TX_DONE(p) message - must reset p.state here
184                        //  Two potential races:
185                        //   -CPU High just rebooted and will also attempt setting p.state=TX_PKT_BUF_HIGH_CTRL
186                        //      No problem if both CPUs set state to TX_PKT_BUF_HIGH_CTRL
187                        //   -CPU High did not reboot and will attempt tx_done_handler(p)
188                        //      If p.state=TX_PKT_BUF_HIGH_CTRL when tx_done_handler(p) runs, CPU High will fail gracefully
189                        //      If p.state set to TX_PKT_BUF_HIGH_CTRL during tx_done_handler(p), CPU High will succeed normally
190                    case TX_PKT_BUF_LOW_CTRL:
191                        // CPU Low rebooted after CPU High submitted packet for Tx
192                        //  Release lock and reset state
193                        //  CPU High will find this TX_PKT_BUF_HIGH_CTRL buffer in next ping/pong update
194                    default:
195                        // Something went wrong if tx_pkt_buf_state is something
196                        // other than one of the tx_pkt_buf_state_t enums. We'll
197                        // attempt to resolve the problem by explicitly setting
198                        // the state.
199                        tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
200                        unlock_tx_pkt_buf(i);
201                    break;
202                }
203            break;
204            case TX_PKT_BUF_BEACON:
205                unlock_tx_pkt_buf(i);
206            break;
207            case TX_PKT_BUF_RTS:
208            case TX_PKT_BUF_ACK_CTS:
209                force_lock_tx_pkt_buf(i);
210                tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_LOW_CTRL;
211            default:
212            break;
213        }
214    }
215    // ***************************************************
216    // Initialize Receive Packet Buffers
217    // ***************************************************
218    for(i = 0; i < NUM_RX_PKT_BUFS; i++){
219        rx_frame_info = (rx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.rx_pkt_buf_baseaddr, i);
220        switch(rx_frame_info->rx_pkt_buf_state){
221           case RX_PKT_BUF_UNINITIALIZED:
222           case RX_PKT_BUF_LOW_CTRL:
223           default:
224                // Something went wrong if rx_pkt_buf_state is something
225                // other than one of the rx_pkt_buf_state_t enums. We'll
226                // attempt to resolve the problem by explicitly setting
227                // the state.
228               force_lock_rx_pkt_buf(i);
229               rx_frame_info->rx_pkt_buf_state = RX_PKT_BUF_LOW_CTRL;
230           break;
231           case RX_PKT_BUF_HIGH_CTRL:
232           case RX_PKT_BUF_READY:
233               // CPU Low rebooted after submitting packet for de-encapsulation/logging
234               //  Will be handled by CPU High, either because CPU High is about
235               //  to de-encapsulate/log p or just rebooted and will clean up
236           break;
237        }
238    }
239
240    // Create IPC message to receive into
241    ipc_msg_from_high.payload_ptr = &(ipc_msg_from_high_payload[0]);
242
243    // Point the PHY to an empty Rx Pkt Buffer
244    wlan_mac_low_lock_empty_rx_pkt_buf();
245
246    // Move the PHY's starting address into the packet buffers by PHY_XX_PKT_BUF_PHY_HDR_OFFSET.
247    // This accounts for the metadata located at the front of every packet buffer (Xx_mpdu_info)
248    wlan_phy_rx_pkt_buf_phy_hdr_offset(PHY_RX_PKT_BUF_PHY_HDR_OFFSET);
249    wlan_phy_tx_pkt_buf_phy_hdr_offset(PHY_TX_PKT_BUF_PHY_HDR_OFFSET);
250
251
252    // Unpause MAC Tx Controllers
253    wlan_mac_pause_tx_ctrl_A(0);
254    wlan_mac_pause_tx_ctrl_C(0);
255    wlan_mac_pause_tx_ctrl_D(0);
256
257    // Initialize the HW info structure
258    init_mac_hw_info();
259
260    // Set the NAV ignore addr to this HW address
261    wlan_mac_low_set_nav_check_addr(get_mac_hw_addr_wlan());
262
263    return 0;
264}
265
266
267
268/*****************************************************************************/
269/**
270 * @brief Finish Initializing MAC Low Framework
271 *
272 * This function finishes the initialization and notifies the upper-level
273 * MAC that it has finished booting.
274 *
275 * @param   None
276 * @return  None
277 */
278void wlan_mac_low_init_finish(){
279
280    //Set the default PHY sample rate to 20 MSps
281    set_phy_samp_rate(PHY_20M);
282
283    // Update the CPU Low status
284    cpu_low_status |= CPU_STATUS_INITIALIZED;
285
286    wlan_mac_low_send_status(CPU_STATUS_REASON_BOOTED);
287
288}
289
290void wlan_mac_low_send_status(u8 cpu_status_reason){
291    wlan_ipc_msg_t ipc_msg_to_high;
292    u32 ipc_msg_to_high_payload[2+(sizeof(compilation_details_t)/sizeof(u32))];
293
294    // Send a message to other processor to say that this processor is initialized and ready
295    ipc_msg_to_high.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_CPU_STATUS);
296    ipc_msg_to_high.arg0              = cpu_status_reason;
297    ipc_msg_to_high.num_payload_words = 2+(sizeof(compilation_details_t)/sizeof(u32));
298    ipc_msg_to_high.payload_ptr       = &(ipc_msg_to_high_payload[0]);
299    ipc_msg_to_high_payload[0]        = cpu_low_status;
300    ipc_msg_to_high_payload[1]        = cpu_low_type;
301    memcpy((u8*)&(ipc_msg_to_high_payload[2]), (u8*)&cpu_low_compilation_details, sizeof(compilation_details_t));
302
303    write_mailbox_msg(&ipc_msg_to_high);
304}
305
306
307/*****************************************************************************/
308/**
309 * @brief Set the PHY Sampling Rate
310 *
311 * This function should be called to switch the PHY sampling rate between
312 * 10/20/40 MSps.
313 *
314 * @param   phy_samp_rate_t phy_samp_rate
315 * @return  None
316 */
317void set_phy_samp_rate(phy_samp_rate_t phy_samp_rate) {
318
319    // Check sample rate argument
320    //     - Must be in [PHY_10M, PHY_20M, PHY_40M]
321    if (!((phy_samp_rate == PHY_10M) || (phy_samp_rate == PHY_20M) || (phy_samp_rate == PHY_40M))) {
322        return;
323    }
324
325    // Set global sample rate variable
326    gl_phy_samp_rate = phy_samp_rate;
327
328    // Call the platform's set_samp_rate first
329    wlan_platform_low_set_samp_rate(phy_samp_rate);
330
331    // DSSS Rx only supported at 20Msps
332    switch(phy_samp_rate){
333        case PHY_10M:
334        case PHY_40M:
335            // Always disable DSSS when PHY sample rate is not 20 MSps
336            wlan_phy_DSSS_rx_disable();
337        break;
338        case PHY_20M:
339            // Enable DSSS if global variable indicates it should be enabled and RF band allows it
340            if ((mac_param_dsss_en) && (mac_param_band == CHAN_BAND_24GHz)) {
341                wlan_phy_DSSS_rx_enable();
342            }
343        break;
344    }
345
346    // Call user callback so it can deal with any changes that need to happen due to a change in sampling rate
347    sample_rate_change_callback(gl_phy_samp_rate);
348
349}
350
351/*****************************************************************************/
352/**
353 * @brief Initialize the DCF Hardware Core
354 *
355 * This function initializes the DCF hardware core.
356 *
357 * @param   None
358 * @return  None
359 */
360void wlan_mac_hw_init(){
361
362    // Reset the MAC core - this clears any stale state in the Tx controllers, NAV counter, backoff counters, etc.
363    wlan_mac_reset(1);
364
365    // Enable blocking of the Rx PHY following good-FCS receptions and bad-FCS receptions
366    //     BLOCK_RX_ON_VALID_RXEND will block the Rx PHY on all RX_END events following valid RX_START events
367    //     This allows the wlan_exp framework to count and log bad FCS receptions
368    //
369    REG_SET_BITS(WLAN_MAC_REG_CONTROL, WLAN_MAC_CTRL_MASK_BLOCK_RX_ON_TX);
370
371    // Enable the NAV counter
372    REG_CLEAR_BITS(WLAN_MAC_REG_CONTROL, (WLAN_MAC_CTRL_MASK_DISABLE_NAV));
373
374    // Set sane defaults for MAC timing values. These will be overwritten by
375    // low-level applications that need to specify these times (e.g. the DCF)
376    wlan_mac_set_slot(9*10);
377    wlan_mac_set_DIFS(28*10);
378    wlan_mac_set_TxDIFS((28*10) - (TX_PHY_DLY_100NSEC));
379    wlan_mac_postTx_timer1_en(0);
380    wlan_mac_postRx_timer2_en(0);
381    wlan_mac_set_NAV_adj(0*10);
382    wlan_mac_set_EIFS(88*10);
383
384    // Set the TU target to 2^32-1 (max value) and hold TU_LATCH in reset
385    //  MAC Low application should re-enabled if needed
386    wlan_mac_set_tu_target(0xFFFFFFFF);
387    wlan_mac_reset_tu_target_latch(1);
388
389    // Clear any stale Rx events
390    wlan_mac_hw_clear_rx_started();
391
392    // Clear the reset
393    wlan_mac_reset(0);
394
395    return;
396}
397
398
399
400/*****************************************************************************/
401/**
402 * @brief Send Exception to Upper-Level MAC
403 *
404 * This function generates an IPC message for the upper-level MAC
405 * to tell it that something has gone wrong
406 *
407 * @param u32 reason
408 *  - reason code for the exception
409 * @return None
410 */
411inline void wlan_mac_low_send_exception(u32 reason){
412    wlan_ipc_msg_t ipc_msg_to_high;
413    u32 ipc_msg_to_high_payload[2];
414
415    // Update CPU Low status
416    cpu_low_status |= CPU_STATUS_EXCEPTION;
417
418    // Send an exception to CPU_HIGH along with a reason
419    ipc_msg_to_high.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_CPU_STATUS);
420    ipc_msg_to_high.arg0              = (u8)CPU_STATUS_REASON_EXCEPTION;
421    ipc_msg_to_high.num_payload_words = 2;
422    ipc_msg_to_high.payload_ptr       = &(ipc_msg_to_high_payload[0]);
423    ipc_msg_to_high_payload[0]        = cpu_low_status;
424    ipc_msg_to_high_payload[1]        = reason;
425
426    write_mailbox_msg(&ipc_msg_to_high);
427
428    // Set the Hex display with the reason code and flash the LEDs
429    wlan_platform_low_userio_disp_status(USERIO_DISP_STATUS_CPU_ERROR,reason);
430}
431
432/*****************************************************************************/
433/**
434 * @brief Poll the Receive Frame Start
435 *
436 * This function will poll the hardware to see if the PHY is currently receiving or
437 * has finished receiving a packet.  This will then dispatch the current RX packet
438 * buffer and PHY details to the frame_rx_callback(). The callback is responsible for
439 * updating the current Rx packet buffer, typically required if the received packet
440 * is passed to CPU High for further processing.
441 *
442 * @param   None
443 * @return  u32              - Status (See MAC Polling defines in wlan_mac_low.h)
444 */
445inline u32 wlan_mac_low_poll_frame_rx(){
446    phy_rx_details_t phy_details;
447    u8 active_rx_ant;
448
449    volatile u32 mac_hw_status;
450    volatile u32 phy_hdr_params;
451
452    void* pkt_buf_addr = (void *) CALC_PKT_BUF_ADDR(platform_common_dev_info.rx_pkt_buf_baseaddr, rx_pkt_buf);
453    rx_frame_info_t* rx_frame_info = (rx_frame_info_t *) pkt_buf_addr;
454
455    int i = 0;
456
457    u32 return_status = 0;
458
459    // Read the MAC/PHY status
460    mac_hw_status = wlan_mac_get_status();
461
462    // Check if PHY has started a new reception
463    if(mac_hw_status & WLAN_MAC_STATUS_MASK_RX_PHY_STARTED) {
464
465        // Fill in rx_frame_info_t metadata
466        active_rx_ant = (wlan_phy_rx_get_active_rx_ant());
467
468        rx_frame_info->flags          = 0;
469        rx_frame_info->channel        = wlan_mac_low_get_active_channel();
470        rx_frame_info->phy_samp_rate  = (u8)wlan_mac_low_get_phy_samp_rate();
471        rx_frame_info->timestamp      = wlan_mac_low_get_rx_start_timestamp();
472        rx_frame_info->timestamp_frac = wlan_mac_low_get_rx_start_timestamp_frac();
473        rx_frame_info->ant_mode       = active_rx_ant;
474        rx_frame_info->rx_gain_index  = wlan_platform_get_rx_pkt_gain(active_rx_ant);
475        rx_frame_info->rx_power       = wlan_platform_get_rx_pkt_pwr(active_rx_ant);
476
477
478        // Check whether this is an OFDM or DSSS Rx
479        if(wlan_mac_get_rx_phy_sel() == WLAN_MAC_PHY_RX_PHY_HDR_PHY_SEL_DSSS) {
480            // DSSS Rx - PHY Rx length is already valid, other params unused for DSSS
481            phy_details.phy_mode = PHY_MODE_DSSS;
482
483            // Strip off extra pre-MAC-header bytes used in DSSS frames; this adjustment allows the next
484            //     function to treat OFDM and DSSS payloads the same
485            phy_details.length   = wlan_mac_get_rx_phy_length() - 5;
486            phy_details.mcs      = wlan_mac_get_rx_phy_mcs();
487
488            rx_frame_info->cfo_est        = 0;;
489            rx_frame_info->phy_details    = phy_details;
490
491
492            // Call the user callback to handle this Rx, capture return value
493            return_status |= FRAME_RX_RET_STATUS_RECEIVED_PKT;
494            return_status |= frame_rx_callback(rx_pkt_buf, &phy_details);
495
496        } else {
497            // OFDM Rx - must wait for valid PHY header
498            // Order of operations is critical here
499            //  1) Read status first
500            //  2) Read PHY header register second
501            //  3) Check for complete PHY header - continue if complete
502            //  4) Else check for early PHY reset - quit if reset
503
504            while (1) {
505                mac_hw_status = wlan_mac_get_status();
506                phy_hdr_params = wlan_mac_get_rx_phy_hdr_params();
507
508                if(i++ > 1000000) {
509                    xil_printf("Stuck in OFDM Rx PHY hdr check!\n");
510                    xil_printf(" MAC HW Status: 0x%08x\n", wlan_mac_get_status());
511                    xil_printf(" Rx Hdr Params: 0x%08x\n", wlan_mac_get_rx_phy_hdr_params());
512                    xil_printf(" Rx PHY Status: 0x%08x\n", Xil_In32(WLAN_RX_STATUS));
513                }
514
515                if(phy_hdr_params & WLAN_MAC_PHY_RX_PHY_HDR_READY) {
516                    // Rx PHY received enough bytes to decode PHY header
517                    //  Exit loop and check PHY header params
518                    break;
519                }
520                if((mac_hw_status & WLAN_MAC_STATUS_MASK_RX_PHY_ACTIVE) == 0) {
521                    // Rx PHY went idle before asserting RX_PHY_HDR_READY
522                    //  This only happens if the PHY is reset externally, possible if MAC starts a Tx during Rx
523                    //  Only option is to reset RX_STARTED and wait for next Rx
524
525                    // There is a 1-cycle race in this case, because RX_END asserts 1 cycle before RX_PHY_HDR_READY in the
526                    //  case of an invalid HT-SIG. The invalid HT-SIG generates an RX_END_ERROR which causes
527                    //  RX_END to assert. The simple workaround used below is to re-read phy_hdr_params one last time
528                    //  before concluding that the Rx PHY was reset unexpectedly
529                    break;
530                }
531            }
532
533            //  Re-read phy_hdr_params to resolve 1-cycle ambiguity in case of HT-SIG error
534            phy_hdr_params = wlan_mac_get_rx_phy_hdr_params();
535
536            // Decide how to handle this waveform
537            if(phy_hdr_params & WLAN_MAC_PHY_RX_PHY_HDR_READY) {
538                // Received PHY header - decide whether to call MAC callback
539                if( (phy_hdr_params & WLAN_MAC_PHY_RX_PHY_HDR_MASK_UNSUPPORTED) ||
540                    (wlan_mac_get_rx_phy_mode() > 0x2) ) {
541                    // Valid HT-SIG but unsupported waveform
542                    //  Rx PHY will hold ACTIVE until last samp but will not write payload
543                    //  HT-SIG fields (MCS, length) can be safely read here if desired
544                    // Or detected VHT waveform (not supported), did not attempt decoding VHT-SIG
545                    //xil_printf("Quitting - WLAN_MAC_PHY_RX_PHY_HDR_MASK_UNSUPPORTED (MCS = %d, Length = %d)", wlan_mac_get_rx_phy_mcs(), wlan_mac_get_rx_phy_length());
546
547                } else if(phy_hdr_params & WLAN_MAC_PHY_RX_PHY_HDR_MASK_RX_ERROR) {
548                    // Invalid HT-SIG (CRC error, invalid RESERVED or TAIL bits, invalid LENGTH, etc)
549                    //  Rx PHY has already released ACTIVE and will not write payload
550                    //  HT-SIG fields (MCS, length) should not be trusted in this case
551                    //xil_printf("Quitting - WLAN_MAC_PHY_RX_PHY_HDR_MASK_RX_ERROR");
552
553                } else {
554                    // NONHT waveform or HTMF waveform with supported HT-SIG - PHY will write payload
555                    //  Call lower MAC Rx callback
556                    //  Callback can safely return anytime (before or after RX_END)
557
558                    phy_details.phy_mode = wlan_mac_get_rx_phy_mode();
559                    phy_details.length   = wlan_mac_get_rx_phy_length();
560                    phy_details.mcs      = wlan_mac_get_rx_phy_mcs();
561
562                    rx_frame_info->cfo_est        = wlan_phy_rx_get_cfo_est();
563                    rx_frame_info->phy_details    = phy_details;
564
565                    return_status |= FRAME_RX_RET_STATUS_RECEIVED_PKT;
566                    return_status |= frame_rx_callback(rx_pkt_buf, &phy_details);
567                }
568            } else {
569                // PHY went idle before PHY_HDR_DONE, probably due to external reset
570                //  The Rx PHY can be reset from software (only used in wlan_phy_init()) or hardware.
571                //  The hardware reset is asserted by the MAC core during Tx. Asserting Tx during Rx is
572                //  impossible with the normal DCF code, as packet det is treated as a busy medium. With a
573                //  custom MAC implementation that allows Tx during Rx this code block will catch the
574                //  unexpected reset events.
575
576                // PHY header cannot be trusted in this case - do nothing and return
577
578            }//END if(PHY_HDR_DONE)
579        } //END if(OFDM Rx)
580
581        // Clear the MAC status register RX_STARTED bit unless the MAC application requested it stay asserted
582        //  By this point the framework and MAC are typically done with the current waveform, however it was handled.
583        //  The MAC application can request the RX_STARTED latch stay asserted by returning the FRAME_RX_RET_SKIP_RX_STARTED_RESET flag
584        //  In this case the application *must* clear the latch directly whenever it completes its Rx processing
585        if((return_status & FRAME_RX_RET_SKIP_RX_STARTED_RESET) == 0) wlan_mac_hw_clear_rx_started();
586
587    } //END if(PHY_RX_STARTED)
588
589    return return_status;
590}
591
592/*****************************************************************************/
593/**
594 * @brief Poll for IPC Receptions
595 *
596 * This function is a non-blocking poll for IPC receptions from the upper-level MAC.
597 *
598 * @param   None
599 * @return  int             - 0 when mailbox was empty, 1 when one message was processed
600 */
601inline int wlan_mac_low_poll_ipc_rx(){
602    // Poll mailbox read msg
603    if (read_mailbox_msg(&ipc_msg_from_high) == IPC_MBOX_SUCCESS) {
604        wlan_mac_low_process_ipc_msg(&ipc_msg_from_high);
605        return 1;
606    }
607    return 0;
608}
609
610
611/*****************************************************************************/
612/**
613 * @brief Process IPC Reception
614 *
615 * This is an internal function to the WLAN MAC Low framework to process
616 * received IPC messages and call the appropriate callback.
617 *
618 * @param   None
619 * @return  None
620 */
621void wlan_mac_low_process_ipc_msg(wlan_ipc_msg_t * msg){
622    wlan_ipc_msg_t ipc_msg_to_high;
623
624    switch(IPC_MBOX_MSG_ID_TO_MSG(msg->msg_id)){
625        //---------------------------------------------------------------------
626        case IPC_MBOX_TX_PKT_BUF_READY: {
627            u8 tx_pkt_buf;
628            tx_pkt_buf = msg->arg0;
629
630            if(tx_pkt_buf < NUM_TX_PKT_BUFS){
631
632                // Lock and change state of packet buffer
633                wlan_mac_low_lock_tx_pkt_buf(tx_pkt_buf);
634
635                // Message is an indication that a Tx Pkt Buf needs processing
636                handle_tx_pkt_buf_ready(tx_pkt_buf);
637                // TODO: check return status and inform CPU_HIGH of error?
638
639            }
640        }
641        break;
642
643        //---------------------------------------------------------------------
644        case IPC_MBOX_SET_MAC_TIME:
645            switch(msg->arg0){
646                default:
647                case 0:
648                    //Payload is an absolute MAC time that must be applied
649                    set_mac_time_usec( *(u64*)(msg->payload_ptr) );
650                    mactime_change_callback( (*(s64*)(msg->payload_ptr))-((s64)get_mac_time_usec()) );
651                break;
652                case 1:
653                    //Payload is a MAC time delta that must be applied
654                    apply_mac_time_delta_usec( *(s64*)(msg->payload_ptr));
655                    mactime_change_callback( *(s64*)(msg->payload_ptr));
656                break;
657            }
658        break;
659
660        //---------------------------------------------------------------------
661        case IPC_MBOX_TXRX_BEACON_CONFIG: {
662            beacon_txrx_config_callback(msg->payload_ptr);
663        }
664        break;
665
666        //---------------------------------------------------------------------
667        case IPC_MBOX_CPU_STATUS: {
668            if(msg->arg0 == (u8)CPU_STATUS_REASON_BOOTED){
669                // If CPU_HIGH just booted, we should re-inform it of our CPU status
670                wlan_mac_low_send_status(CPU_STATUS_REASON_RESPONSE);
671            }
672        }
673        break;
674
675        //---------------------------------------------------------------------
676        case IPC_MBOX_MEM_READ_WRITE: {
677            switch(msg->arg0){
678                case IPC_REG_WRITE_MODE: {
679
680                    u32* payload_to_write = (u32*)((u8*)ipc_msg_from_high_payload + sizeof(ipc_reg_read_write_t));
681
682                    // IMPORTANT: this memcpy assumes the payload provided by CPU high is ready as-is
683                    //     Any byte swapping (i.e. for payloads that arrive over Ethernet) *must* be performed
684                    //     before the payload is passed to this function
685
686                    // Implement memcpy with only 32-bit writes, avoids byte-select issues in Sysgen AXI slaves
687                    int word_idx;
688                    u32 num_words = ((ipc_reg_read_write_t*)ipc_msg_from_high_payload)->num_words;
689                    u32 start_addr = (((ipc_reg_read_write_t*)ipc_msg_from_high_payload)->baseaddr) & 0xFFFFFFFC; //force 2LSB=0
690
691                    for(word_idx = 0; word_idx < num_words; word_idx++) {
692                        // Increment target address by 4 bytes per iteration
693                        // payload_to_write already a u32 pointer, so use count-by-1 array index to access u32 words
694                        Xil_Out32((start_addr + word_idx*4), payload_to_write[word_idx]);
695                    }
696                }
697                break;
698
699                case IPC_REG_READ_MODE: {
700
701                    /*
702                    xil_printf("\nCPU Low Read:\n");
703                    xil_printf(" Addr: 0x%08x\n", (u32*)((ipc_reg_read_write_t*)ipc_msg_from_high_payload)->baseaddr);
704                    xil_printf(" N Wrds: %d\n", ((ipc_reg_read_write_t*)ipc_msg_from_high_payload)->num_words);
705
706                    xil_printf("Mem[0x%08x] = 0x%08x\n",
707                            (u32*)((ipc_reg_read_write_t*)ipc_msg_from_high_payload)->baseaddr,
708                            Xil_In32((u32*)((ipc_reg_read_write_t*)ipc_msg_from_high_payload)->baseaddr));
709                    */
710                    ipc_msg_to_high.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_MEM_READ_WRITE);
711                    ipc_msg_to_high.num_payload_words = ((ipc_reg_read_write_t*)ipc_msg_from_high_payload)->num_words;
712                    ipc_msg_to_high.payload_ptr       = (u32*)((ipc_reg_read_write_t*)ipc_msg_from_high_payload)->baseaddr;
713
714                    write_mailbox_msg(&ipc_msg_to_high);
715                }
716                break;
717            }
718        }
719        break;
720
721        //---------------------------------------------------------------------------------------
722        case IPC_MBOX_LOW_PARAM: {
723            switch(msg->arg0){
724                case IPC_REG_WRITE_MODE: {
725                    switch(ipc_msg_from_high_payload[0]){
726
727                        case LOW_PARAM_PHY_SAMPLE_RATE: {
728                            set_phy_samp_rate(ipc_msg_from_high_payload[1]);
729                        }
730                        break;
731
732                        case LOW_PARAM_DSSS_PKT_DET_THRESH: {
733                            // Two u32 values:
734                            //  payload[1]: Correlation threshold
735                            //  payload[2]: Energy threshold
736
737                            xil_printf("DSSS Pkt Det Thresh: (%d, %d, %d)\n", ipc_msg_from_high_payload[1], ipc_msg_from_high_payload[2], ipc_msg_from_high_payload[3]);
738
739                            //wlan_phy_rx_pktDet_autoCorr_dsss_cfg(corr_thresh, energy_thresh)
740                            //  corr_thresh: UFix8_6
741                            //  energy_thresh: UFix10_0
742                            wlan_phy_rx_pktDet_autoCorr_dsss_cfg(ipc_msg_from_high_payload[1], ipc_msg_from_high_payload[2]);
743
744                            if(ipc_msg_from_high_payload[3] == 1){
745                                //Require packet detection before DSSS Rx
746                                REG_SET_BITS(WLAN_RX_REG_CFG, (WLAN_RX_REG_CFG_DSSS_RX_REQ_PKT_DET));
747                            } else {
748                                //Do not require packet detection before DSSS Rx
749                                REG_CLEAR_BITS(WLAN_RX_REG_CFG, (WLAN_RX_REG_CFG_DSSS_RX_REQ_PKT_DET));
750                            }
751                        }
752                        break;
753
754                        case LOW_PARAM_OFDM_PKT_DET_THRESH: {
755                            // Two u32 values:
756                            //  payload[1]: Correlation threshold
757                            //  payload[2]: Energy threshold
758                            //  payload[3]: Minimum duration
759
760                            xil_printf("OFDM Pkt Det Config: corr_thesh=%d, energy_thresh=%d, min_dur=%d, post_wait=%d, require_pkt_det = %d\n", ipc_msg_from_high_payload[1], ipc_msg_from_high_payload[2], ipc_msg_from_high_payload[3], ipc_msg_from_high_payload[4], ipc_msg_from_high_payload[5]);
761
762                            //wlan_phy_rx_pktDet_autoCorr_ofdm_cfg(corr_thresh, energy_thresh, min_dur, post_wait)
763                            //  corr_thresh: UFix8_7
764                            //  energy_thresh: UFix16_15
765                            //  min_dur: UFix4_0
766                            //  post-det-reset: UFix4_0
767                            wlan_phy_rx_pktDet_autoCorr_ofdm_cfg(ipc_msg_from_high_payload[1], ipc_msg_from_high_payload[2], ipc_msg_from_high_payload[3], ipc_msg_from_high_payload[4]);
768
769                            if(ipc_msg_from_high_payload[5] == 1){
770                                //Require packet detection before DSSS Rx
771                                REG_SET_BITS(WLAN_RX_REG_CFG, (WLAN_RX_REG_CFG_OFDM_RX_REQ_PKT_DET));
772                            } else {
773                                //Do not require packet detection before DSSS Rx
774                                REG_CLEAR_BITS(WLAN_RX_REG_CFG, (WLAN_RX_REG_CFG_OFDM_RX_REQ_PKT_DET));
775                            }
776                        }
777                        break;
778
779                        case LOW_PARAM_OFDM_RX_EN: {
780                            // One u32 value:
781                            // payload[1]: Zero=Disable OFDM Rx, Non-zero: Enable OFDM Rx
782
783                            xil_printf("OFDM_RX_EN: ");
784                            if(ipc_msg_from_high_payload[1]) {
785                                xil_printf("Enabling OFDM Rx\n");
786                                REG_CLEAR_BITS(WLAN_RX_REG_CFG, WLAN_RX_REG_CFG_DISABLE_OFDM_RX);
787                            } else {
788                                xil_printf("Disabling OFDM Rx\n");
789                                REG_SET_BITS(WLAN_RX_REG_CFG, WLAN_RX_REG_CFG_DISABLE_OFDM_RX);
790                            }
791                        }
792                        break;
793
794                        default: {
795                            // Low framework doesn't recognize this low param ID - call the application
796                            //  and platform handlers to process with this param write
797                            ipc_low_param_callback(IPC_REG_WRITE_MODE, ipc_msg_from_high_payload);
798                            wlan_platform_low_param_handler(IPC_REG_WRITE_MODE, ipc_msg_from_high_payload);
799                        }
800                        break;
801                    }
802                }
803                break;
804
805                case IPC_REG_READ_MODE: {
806                    // Read Mode is not supported
807                    //
808                    // NOTE:  This is due to the fact that IPC messages in CPU low can take an infinitely long amount of
809                    //     to return given that the sending and receiving of wireless data takes precedent.  Therefore,
810                    //     it is not good to try to return values from CPU low since there is no guarantee when the values
811                    //     will be available.
812                    //
813                    u32 ret_val = 0;
814
815                    ipc_msg_to_high.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_LOW_PARAM);
816                    ipc_msg_to_high.num_payload_words = 0;
817                    ipc_msg_to_high.payload_ptr       = (u32 *)&ret_val;
818
819                    write_mailbox_msg(&ipc_msg_to_high);
820                }
821                break;
822            }
823        }
824        break;
825
826        //---------------------------------------------------------------------
827        case IPC_MBOX_MCAST_BUFFER_ENABLE: {
828            mcast_buffer_enable_callback(msg->arg0);
829        }
830        break;
831
832        //---------------------------------------------------------------------
833        case IPC_MBOX_CONFIG_CHANNEL: {
834            wlan_mac_low_set_radio_channel(ipc_msg_from_high_payload[0]);
835        }
836        break;
837
838        //---------------------------------------------------------------------
839        case IPC_MBOX_LOW_RANDOM_SEED: {
840            srand(ipc_msg_from_high_payload[0]);
841        }
842        break;
843
844        //---------------------------------------------------------------------
845        case IPC_MBOX_CONFIG_TX_CTRL_POW: {
846            mac_param_ctrl_tx_pow = (s8)ipc_msg_from_high_payload[0];
847        }
848        break;
849
850        //---------------------------------------------------------------------
851        case IPC_MBOX_CONFIG_RX_FILTER: {
852            u32 filter_mode_hi = (u32)ipc_msg_from_high_payload[0];
853            u32 filter_mode_lo = 0;
854
855            if((filter_mode_hi & RX_FILTER_FCS_MASK) == RX_FILTER_FCS_NOCHANGE){
856                filter_mode_lo |= (mac_param_rx_filter & RX_FILTER_FCS_MASK);
857            } else {
858                filter_mode_lo |= (filter_mode_hi & RX_FILTER_FCS_MASK);
859            }
860
861            if((filter_mode_hi & RX_FILTER_HDR_NOCHANGE) == RX_FILTER_HDR_NOCHANGE){
862                filter_mode_lo |= (mac_param_rx_filter & RX_FILTER_HDR_NOCHANGE);
863            } else {
864                filter_mode_lo |= (filter_mode_hi & RX_FILTER_HDR_NOCHANGE);
865            }
866
867            mac_param_rx_filter = filter_mode_lo;
868        }
869        break;
870
871        //---------------------------------------------------------------------
872        case IPC_MBOX_CONFIG_RX_ANT_MODE: {
873            wlan_rx_config_ant_mode(ipc_msg_from_high_payload[0]);
874        }
875        break;
876
877        //---------------------------------------------------------------------
878        case IPC_MBOX_CONFIG_DSSS_EN: {
879            if (ipc_msg_from_high_payload[0] == 1) {
880                // xil_printf("Enabling DSSS\n");
881                wlan_mac_low_DSSS_rx_enable();
882            } else {
883                // xil_printf("Disabling DSSS\n");
884                wlan_mac_low_DSSS_rx_disable();
885            }
886        }
887        break;
888
889        //---------------------------------------------------------------------
890        case IPC_MBOX_SET_RADIO_TX_POWER: {
891            s8 pwr = (s8)ipc_msg_from_high_payload[0];
892            wlan_platform_set_radio_tx_power(pwr);
893        }
894        break;
895
896
897    }
898}
899
900inline u32 wlan_mac_low_lock_tx_pkt_buf(u16 tx_pkt_buf){
901    u32 is_locked, owner;
902    u32 iter = 0;
903    tx_frame_info_t* tx_frame_info;
904
905    tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf);
906
907    if( tx_frame_info->flags & TX_FRAME_INFO_FLAGS_WAIT_FOR_LOCK ){
908        // This packet buffer has been flagged to ensure that CPU_LOW will wait until a mutex lock
909        // is achieved before proceeding (as opposed to aborting and raising an error). The implicit
910        // contract in this flag is that CPU_HIGH will only briefly lock the packet buffer while updating
911        // its contents.
912        if(tx_frame_info->tx_pkt_buf_state == TX_PKT_BUF_DONE){
913            return PREPARE_FRAME_TRANSMIT_ERROR_UNEXPECTED_PKT_BUF_STATE;
914        }
915
916        while(lock_tx_pkt_buf(tx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS){
917            // This frame was flagged with
918            if(iter > 1000000) {
919                xil_printf("ERROR (wlan_mac_low_lock_tx_pkt_buf): stuck waiting for CPU High to unlock Tx pkt buf %d\n", tx_pkt_buf);
920            }
921            else {
922                iter++;
923            }
924        }
925
926        if(tx_frame_info->tx_pkt_buf_state != TX_PKT_BUF_READY){
927            return PREPARE_FRAME_TRANSMIT_ERROR_UNEXPECTED_PKT_BUF_STATE;
928        }
929
930    } else {
931        // This packet buffer should be lockable and there is no need for CPU_LOW to wait on a mutex
932        // lock if it is not. In that case, CPU_LOW should print an error and quit this function.
933
934        if(tx_frame_info->tx_pkt_buf_state != TX_PKT_BUF_READY){
935            if(tx_frame_info->tx_pkt_buf_state == TX_PKT_BUF_LOW_CTRL ){
936                // CPU Low responsible for any LOW_CTRL buffers
937                //  Don't transmit - just clean up and return
938                tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
939            }
940            //  CPU High will handle it eventually
941            //  Ensure CPU Low doesn't own lock then return
942            unlock_tx_pkt_buf(tx_pkt_buf);
943            return PREPARE_FRAME_TRANSMIT_ERROR_UNEXPECTED_PKT_BUF_STATE;
944        }
945
946        // Attempt to lock the packet buffer. If this fails, we will not wait for it to succeed. Something
947        // has gone wrong and we should print an error.
948        if(lock_tx_pkt_buf(tx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS){
949            wlan_printf(PL_ERROR, "Error: unable to lock TX pkt_buf %d\n", tx_pkt_buf);
950            get_tx_pkt_buf_status(tx_pkt_buf, &is_locked, &owner);
951            wlan_printf(PL_ERROR, "    TX pkt_buf %d status: isLocked = %d, owner = %d\n", tx_pkt_buf, is_locked, owner);
952            tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
953            return PREPARE_FRAME_TRANSMIT_ERROR_LOCK_FAIL;
954        }
955    }
956    // By this point in the function, we have verified that the packet buffer was in an expected state
957    // and have successfully locked the mutex.
958
959    tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_LOW_CTRL;
960    return 0;
961}
962
963/*****************************************************************************/
964/**
965 * @brief Set the radio channel
966 *
967 * This function will set the radio channel for CPU LOW
968 *
969 * @param   channel     - Radio channel
970 * @return  None
971 *
972 */
973int wlan_mac_low_set_radio_channel(u32 channel){
974
975    if (wlan_verify_channel(channel) == XST_SUCCESS) {
976    mac_param_chan = channel;
977
978        if(mac_param_chan <= 14){
979            mac_param_band = CHAN_BAND_24GHz;
980
981            // Enable DSSS if global variable indicates it should be enabled and PHY sample rate allows it
982            if ((mac_param_dsss_en) && (gl_phy_samp_rate == PHY_20M)) {
983                wlan_phy_DSSS_rx_enable();
984            }
985        } else {
986            mac_param_band = CHAN_BAND_5GHz;
987
988            // Always disable DSSS when in the 5 GHZ band
989            wlan_phy_DSSS_rx_disable();
990        }
991
992        wlan_mac_reset_NAV_counter();
993
994        return wlan_platform_low_set_radio_channel(channel);
995
996    } else {
997        xil_printf("Invalid channel selection %d\n", channel);
998        return -1;
999    }
1000}
1001
1002
1003
1004/*****************************************************************************/
1005/**
1006 * @brief Enable / Disable DSSS RX
1007 *
1008 * DSSS RX must be disabled when in the 5 GHz band or when the PHY sample rate
1009 * is not 20 MSps.  However, the low framework will maintain what the state
1010 * should be when in the 2.4 GHz band and the PHY sample rate is 20 MSps
1011 *
1012 * @param   None
1013 * @return  None
1014 *
1015 */
1016void wlan_mac_low_DSSS_rx_enable() {
1017    mac_param_dsss_en = 1;
1018
1019    // Only enable DSSS if in 2.4 GHz band and phy sample rate is 20
1020    if ((mac_param_band == CHAN_BAND_24GHz) && (gl_phy_samp_rate == PHY_20M)) {
1021        wlan_phy_DSSS_rx_enable();
1022    }
1023}
1024
1025
1026void wlan_mac_low_DSSS_rx_disable() {
1027    mac_param_dsss_en = 0;
1028    wlan_phy_DSSS_rx_disable();
1029}
1030
1031int wlan_mac_low_finish_frame_transmit(u16 tx_pkt_buf){
1032    // This function should only be called on a packet buffer whose state is
1033    // TX_PKT_BUF_LOW_CTRL and is currently locked by CPU_LOW
1034    int return_value = 0;
1035    tx_frame_info_t* tx_frame_info;
1036    u32 is_locked, owner;
1037    wlan_ipc_msg_t ipc_msg_to_high;
1038
1039
1040    if(tx_pkt_buf >= NUM_TX_PKT_BUFS){
1041        xil_printf("Error: Tx Pkt Buf index exceeds NUM_TX_PKT_BUFS\n");
1042        return_value = -1;
1043        return return_value;
1044    }
1045
1046    tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf);
1047
1048    switch(tx_frame_info->tx_pkt_buf_state){
1049        case TX_PKT_BUF_LOW_CTRL:
1050            get_tx_pkt_buf_status(tx_pkt_buf, &is_locked, &owner);
1051
1052            if( (is_locked == 0) || (owner != XPAR_CPU_ID)){
1053                wlan_printf(PL_ERROR, "TX pkt_buf %d is not locked by CPU_LOW\n", tx_pkt_buf);
1054
1055                get_tx_pkt_buf_status(tx_pkt_buf, &is_locked, &owner);
1056                tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
1057
1058                return_value = -1;
1059
1060            } else {
1061                //Record the time when we completed this MPDU
1062                tx_frame_info->timestamp_done = get_mac_time_usec();
1063
1064                tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_DONE;
1065
1066                // Note: at this point in the code, the packet buffer state has been modified to TX_PKT_BUF_DONE,
1067                // yet we have not sent the IPC_MBOX_TX_PKT_BUF_DONE message. If we happen to reboot here,
1068                // this packet buffer will be abandoned and won't be cleaned up in the boot process. This is a narrow
1069                // race in practice, but step-by-step debugging can accentuate the risk since there can be an arbitrary
1070                // amount of time spent in this window.
1071
1072                //Revert the state of the packet buffer and return control to CPU High
1073                if(unlock_tx_pkt_buf(tx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS){
1074                    wlan_printf(PL_ERROR, "Error: unable to unlock TX pkt_buf %d\n", tx_pkt_buf);
1075                    wlan_mac_low_send_exception(WLAN_ERROR_CODE_CPU_LOW_TX_MUTEX);
1076                    tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
1077                } else {
1078                    ipc_msg_to_high.msg_id =  IPC_MBOX_MSG_ID(IPC_MBOX_TX_PKT_BUF_DONE);
1079
1080                    ipc_msg_to_high.num_payload_words = 0;
1081                    ipc_msg_to_high.payload_ptr = NULL;
1082
1083                    ipc_msg_to_high.arg0 = tx_pkt_buf;
1084
1085                    write_mailbox_msg(&ipc_msg_to_high);
1086                }
1087            }
1088        break;
1089        // ---- Something went wrong - packet buffer in unexpected state ----
1090        default:
1091        case TX_PKT_BUF_READY:
1092            // CPU Low responsible for any LOW_CTRL buffers
1093            //  Don't transmit - just clean up and return
1094            tx_frame_info->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
1095        case TX_PKT_BUF_UNINITIALIZED:
1096        case TX_PKT_BUF_DONE:
1097        case TX_PKT_BUF_HIGH_CTRL:
1098            //  CPU High will handle it eventually
1099            //  Ensure CPU Low doesn't own lock then return
1100            unlock_tx_pkt_buf(tx_pkt_buf);
1101        break;
1102    }
1103    return return_value;
1104}
1105
1106int wlan_mac_low_prepare_frame_transmit(u16 tx_pkt_buf){
1107    tx_frame_info_t* tx_frame_info;
1108    mac_header_80211* tx_80211_header;
1109    ltg_packet_id_t* pkt_id;
1110    if(tx_pkt_buf >= NUM_TX_PKT_BUFS){
1111        xil_printf("Error: Tx Pkt Buf index exceeds NUM_TX_PKT_BUFS\n");
1112        return PREPARE_FRAME_TRANSMIT_ERROR_INVALID_PKT_BUF;
1113    }
1114
1115    tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf);
1116
1117    tx_frame_info->timestamp_accept = get_mac_time_usec();
1118
1119    // Get pointer to start of MAC header in packet buffer
1120    tx_80211_header = (mac_header_80211*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, tx_pkt_buf)+PHY_TX_PKT_BUF_MPDU_OFFSET);
1121
1122    // Mark this packet buffer as prepared
1123    tx_frame_info->flags |= TX_FRAME_INFO_FLAGS_PKT_BUF_PREPARED;
1124
1125    // Insert sequence number here
1126    tx_80211_header->sequence_control = ((tx_80211_header->sequence_control) & 0xF) | ( (unique_seq&0xFFF)<<4 );
1127
1128    // Insert unique sequence into tx_frame_info
1129    tx_frame_info->unique_seq = unique_seq;
1130
1131    if((tx_frame_info->flags) & TX_FRAME_INFO_FLAGS_FILL_UNIQ_SEQ){
1132        // Fill unique sequence number into LTG payload
1133        pkt_id = (ltg_packet_id_t*)((u8*)tx_80211_header + sizeof(mac_header_80211));
1134        pkt_id->unique_seq = unique_seq;
1135    }
1136
1137    //Increment the global unique sequence number
1138    unique_seq++;
1139    return 0;
1140}
1141
1142void wlan_mac_low_send_low_tx_details(u8 pkt_buf, wlan_mac_low_tx_details_t* low_tx_details){
1143    wlan_ipc_msg_t ipc_msg_to_high;
1144
1145    ipc_msg_to_high.payload_ptr = (u32*)low_tx_details;
1146    ipc_msg_to_high.arg0 = pkt_buf;
1147    ipc_msg_to_high.num_payload_words = (sizeof(wlan_mac_low_tx_details_t) / sizeof(u32));
1148
1149    ipc_msg_to_high.msg_id =  IPC_MBOX_MSG_ID(IPC_MBOX_PHY_TX_REPORT);
1150    write_mailbox_msg(&ipc_msg_to_high);
1151    return;
1152}
1153
1154
1155
1156/*****************************************************************************/
1157/**
1158 * @brief Notify upper-level MAC of frame reception
1159 *
1160 * Sends an IPC message to the upper-level MAC to notify it that a frame has been
1161 * received and is ready to be processed
1162 *
1163 * @param   None
1164 * @return  None
1165 *
1166 * @note This function assumes it is called in the same context where rx_pkt_buf is still valid.
1167 */
1168void wlan_mac_low_frame_ipc_send(){
1169    wlan_ipc_msg_t ipc_msg_to_high;
1170
1171    ipc_msg_to_high.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_RX_PKT_BUF_READY);
1172    ipc_msg_to_high.num_payload_words = 0;
1173    ipc_msg_to_high.arg0              = rx_pkt_buf;
1174
1175    write_mailbox_msg(&ipc_msg_to_high);
1176}
1177
1178
1179
1180/*****************************************************************************/
1181/**
1182 * @brief Set Frame Reception Callback
1183 *
1184 * Tells the framework which function should be called when the PHY begins processing a frame reception
1185 *
1186 * @param   callback         - Pointer to callback function
1187 * @return  None
1188 */
1189inline void wlan_mac_low_set_frame_rx_callback(function_ptr_t callback){
1190    frame_rx_callback = callback;
1191}
1192
1193inline void wlan_mac_low_set_sample_rate_change_callback(function_ptr_t callback){
1194    sample_rate_change_callback = callback;
1195}
1196
1197inline void wlan_mac_low_set_handle_tx_pkt_buf_ready(function_ptr_t callback){
1198    handle_tx_pkt_buf_ready = callback;
1199}
1200
1201inline void wlan_mac_low_set_beacon_txrx_config_callback(function_ptr_t callback){
1202    beacon_txrx_config_callback = callback;
1203}
1204
1205inline void wlan_mac_low_set_mcast_buffer_enable_callback(function_ptr_t callback){
1206    mcast_buffer_enable_callback = callback;
1207}
1208
1209inline void wlan_mac_low_set_mactime_change_callback(function_ptr_t callback){
1210    mactime_change_callback = callback;
1211}
1212
1213/*****************************************************************************/
1214/**
1215 * @brief Set IPC_MBOX_LOW_PARAM Callback
1216 *
1217 * Tells the framework which function should be called when an ipc message is received for
1218 * the IPC_MBOX_LOW_PARAM command.
1219 *
1220 * @param   callback         - Pointer to callback function
1221 * @return  None
1222 */
1223void wlan_mac_low_set_ipc_low_param_callback(function_ptr_t callback){
1224    ipc_low_param_callback = callback;
1225}
1226
1227
1228
1229/*****************************************************************************/
1230/**
1231 * @brief Various Getter Methods
1232 *
1233 * These functions will get parameters from the low framework.
1234 *
1235 * @param   None
1236 * @return  (see individual function)
1237 */
1238inline u32 wlan_mac_low_get_active_channel(){
1239    return mac_param_chan;
1240}
1241
1242
1243inline s8 wlan_mac_low_get_current_ctrl_tx_pow(){
1244    return mac_param_ctrl_tx_pow;
1245}
1246
1247
1248inline u32 wlan_mac_low_get_current_rx_filter(){
1249    return mac_param_rx_filter;
1250}
1251
1252
1253inline phy_samp_rate_t wlan_mac_low_get_phy_samp_rate() {
1254    return gl_phy_samp_rate;
1255}
1256
1257
1258
1259/*****************************************************************************/
1260/**
1261 * @brief Get the Rx Start Microsecond Timestamp
1262 *
1263 * This function returns the Rx start timestamp of the system
1264 *
1265 * @param   None
1266 * @return  u64              - microsecond timestamp
1267 */
1268inline u64 wlan_mac_low_get_rx_start_timestamp() {
1269    u32 timestamp_high_u32;
1270    u32 timestamp_low_u32;
1271    u64 timestamp_u64;
1272
1273    // RX_START timestamp is captured once per reception - no race condition between 32-bit reads
1274    timestamp_high_u32 = Xil_In32(WLAN_MAC_REG_RX_TIMESTAMP_MSB);
1275    timestamp_low_u32 = Xil_In32(WLAN_MAC_REG_RX_TIMESTAMP_LSB);
1276    timestamp_u64 = (((u64)timestamp_high_u32)<<32) + ((u64)timestamp_low_u32);
1277
1278    return timestamp_u64;
1279}
1280
1281
1282
1283/*****************************************************************************/
1284/**
1285 * @brief Get the Tx Start Microsecond Timestamp
1286 *
1287 * This function returns the Tx start timestamp of the system
1288 *
1289 * @param   None
1290 * @return  u64              - microsecond timestamp
1291 */
1292inline u64 wlan_mac_low_get_tx_start_timestamp() {
1293    u32 timestamp_high_u32;
1294    u32 timestamp_low_u32;
1295    u64 timestamp_u64;
1296
1297    // TX_START timestamp is captured once per transmission - no race condition between 32-bit reads
1298    timestamp_high_u32 = Xil_In32(WLAN_MAC_REG_TX_TIMESTAMP_MSB);
1299    timestamp_low_u32 = Xil_In32(WLAN_MAC_REG_TX_TIMESTAMP_LSB);
1300    timestamp_u64 = (((u64)timestamp_high_u32)<<32) + ((u64)timestamp_low_u32);
1301
1302    return timestamp_u64;
1303}
1304
1305
1306/*****************************************************************************/
1307/**
1308 * @brief Sets the node's MAC address in the MAC core's NAV logic
1309 *
1310 * @param   addr - pointer to 6-byte MAC address
1311 * @return  None
1312 */
1313void wlan_mac_low_set_nav_check_addr(u8* addr) {
1314    Xil_Out32(WLAN_MAC_REG_NAV_CHECK_ADDR_1, *((u32*)&(addr[0])) );
1315    Xil_Out32(WLAN_MAC_REG_NAV_CHECK_ADDR_2, *((u32*)&(addr[4])) );
1316}
1317
1318/*****************************************************************************/
1319/**
1320 * @brief Search for and Lock Empty Packet Buffer (Blocking)
1321 *
1322 * This is a blocking function for finding and locking an empty rx packet buffer. The low framework
1323 * calls this function after passing a new wireless reception up to CPU High for processing. CPU High
1324 * must unlock Rx packet buffers after processing the received packet. This function loops over all Rx
1325 * packet buffers until it finds one that has been unlocked by CPU High.
1326 *
1327 * By design this function prints a message if it fails to unlock the oldest packet buffer. When this
1328 * occurs it indicates that CPU Low has outrun CPU High, a situation that leads to dropped wireless
1329 * receptions with high probability. The node recovers gracefully from this condition and will
1330 * continue processing new Rx events after CPU High catches up. But seeing this message in the UART
1331 * for CPU Low is a strong indicator the CPU High code is not keeping up with wireless receptions.
1332 *
1333 * @param   None
1334 * @return  None
1335 *
1336 * @note    This function assumes it is called in the same context where rx_pkt_buf is still valid.
1337 */
1338inline void wlan_mac_low_lock_empty_rx_pkt_buf(){
1339    // This function blocks until it safely finds a packet buffer for the PHY RX to store a future reception
1340    rx_frame_info_t* rx_frame_info;
1341    u32 i = 1;
1342
1343    while(1) {
1344        //rx_pkt_buf is the global shared by all contexts which deal with wireless Rx
1345        // Rx packet buffers are used in order. Thus incrementing rx_pkt_buf should
1346        // select the "oldest" packet buffer, the one that is most likely to have already
1347        // been processed and released by CPU High
1348        rx_pkt_buf = (rx_pkt_buf+1) % NUM_RX_PKT_BUFS;
1349        rx_frame_info    = (rx_frame_info_t*) CALC_PKT_BUF_ADDR(platform_common_dev_info.rx_pkt_buf_baseaddr, rx_pkt_buf);
1350
1351        if((rx_frame_info->rx_pkt_buf_state) == RX_PKT_BUF_LOW_CTRL){
1352
1353            if(lock_rx_pkt_buf(rx_pkt_buf) == PKT_BUF_MUTEX_SUCCESS){
1354            // By default Rx pkt buffers are not zeroed out, to save the performance penalty of bzero'ing 2KB
1355            //     However zeroing out the pkt buffer can be helpful when debugging Rx MAC/PHY behaviors
1356            // bzero((void *)(RX_PKT_BUF_TO_ADDR(rx_pkt_buf)), 2048);
1357
1358            // Set the OFDM and DSSS PHYs to use the same Rx pkt buffer
1359            wlan_phy_rx_pkt_buf_ofdm(rx_pkt_buf);
1360            wlan_phy_rx_pkt_buf_dsss(rx_pkt_buf);
1361
1362            if (i > 1) { xil_printf("found in %d iterations.\n", i); }
1363
1364            return;
1365            } else {
1366                xil_printf("Error: unable to lock Rx pkt_buf %d despite RX_PKT_BUF_LOW_CTRL\n", rx_pkt_buf);
1367                unlock_rx_pkt_buf(rx_pkt_buf);
1368        }
1369        }
1370
1371        if (i == 1) { xil_printf("Searching for empty packet buff ... "); }
1372        i++;
1373    }
1374}
1375
1376
1377/*****************************************************************************/
1378/**
1379 * @brief Finish PHY Reception
1380 *
1381 * This function polls the MAC status register until the Rx PHY goes idle. The
1382 * return value indicates whether the just-completed reception was good
1383 * (no Rx errors and matching checksum) or bad
1384 *
1385 * @param   None
1386 * @return  u32              - FCS status (RX_MPDU_STATE_FCS_GOOD or RX_MPDU_STATE_FCS_BAD)
1387 */
1388inline u32 wlan_mac_hw_rx_finish() {
1389    u32 mac_hw_status;
1390    int i = 0;
1391
1392    // Wait for the packet to finish - Rx PHY is "active" if the demod/decoding pipeline is
1393    //  still writing bytes to the packet buffer. The FCS result is not known until the last
1394    //  payload byte has been written. The RX_PHY_ACTIVE bit might de-assert before this happens
1395    //  for some lengths/rates/bandwidths. This allows RX_END to start the SIFS timer at the right
1396    //  time independent of payload-specific PHY latencies.
1397    do{
1398        mac_hw_status = wlan_mac_get_status();
1399        if(i++>1000000) {
1400            xil_printf("Stuck in wlan_mac_hw_rx_finish!\n", mac_hw_status);
1401            xil_printf(" MAC HW Status: 0x%08x\n", wlan_mac_get_status());
1402            xil_printf(" Rx Hdr Params: 0x%08x\n", wlan_mac_get_rx_phy_hdr_params());
1403            xil_printf(" Rx PHY Status: 0x%08x\n", Xil_In32(WLAN_RX_STATUS));
1404            xil_printf(" Last Rx Data : 0x%08x\n", Xil_In32(WLAN_MAC_REG_LATEST_RX_BYTE));
1405        }
1406        // Exit this loop when either:
1407        //  -The Rx PHY has finished received AND has finished writing its payload
1408        //  -The Rx PHY got reset mid-Rx and will not be writing a payload
1409        } while( (mac_hw_status & (WLAN_MAC_STATUS_MASK_RX_PHY_ACTIVE | WLAN_MAC_STATUS_MASK_RX_PHY_WRITING_PAYLOAD))
1410                 && ((mac_hw_status & WLAN_MAC_STATUS_MASK_RX_END_ERROR) == 0));
1411
1412    // Check RX_END_ERROR and FCS
1413    if( (mac_hw_status & WLAN_MAC_STATUS_MASK_RX_FCS_GOOD) &&
1414       ((mac_hw_status & WLAN_MAC_STATUS_MASK_RX_END_ERROR) == 0)) {
1415        return 1;
1416
1417    } else {
1418        return 0;
1419
1420    }
1421}
1422
1423
1424
1425/*****************************************************************************/
1426/**
1427 * @brief Force reset backoff counter in MAC hardware
1428 */
1429inline void wlan_mac_reset_backoff_counter() {
1430    Xil_Out32(WLAN_MAC_REG_CONTROL, Xil_In32(WLAN_MAC_REG_CONTROL) | WLAN_MAC_CTRL_MASK_RESET_A_BACKOFF);
1431    Xil_Out32(WLAN_MAC_REG_CONTROL, Xil_In32(WLAN_MAC_REG_CONTROL) & ~WLAN_MAC_CTRL_MASK_RESET_A_BACKOFF);
1432}
1433
1434
1435
1436/*****************************************************************************/
1437/**
1438 * @brief Force reset NAV counter in MAC hardware
1439 */
1440inline void wlan_mac_reset_NAV_counter() {
1441    Xil_Out32(WLAN_MAC_REG_CONTROL, Xil_In32(WLAN_MAC_REG_CONTROL) | WLAN_MAC_CTRL_MASK_RESET_NAV);
1442    Xil_Out32(WLAN_MAC_REG_CONTROL, Xil_In32(WLAN_MAC_REG_CONTROL) & ~WLAN_MAC_CTRL_MASK_RESET_NAV);
1443}
1444
1445
1446
1447/*****************************************************************************/
1448/**
1449 * @brief Convert MCS to number of data bits per symbol
1450 */
1451inline u16 wlan_mac_low_mcs_to_n_dbps(u8 mcs, u8 phy_mode) {
1452    if(phy_mode == PHY_MODE_NONHT && mcs < (sizeof(mcs_to_n_dbps_nonht_lut)/sizeof(mcs_to_n_dbps_nonht_lut[0]))) {
1453        return mcs_to_n_dbps_nonht_lut[mcs];
1454    } else if(phy_mode == PHY_MODE_HTMF && mcs < (sizeof(mcs_to_n_dbps_htmf_lut)/sizeof(mcs_to_n_dbps_htmf_lut[0]))) {
1455        return mcs_to_n_dbps_htmf_lut[mcs];
1456    } else {
1457        xil_printf("ERROR (wlan_mac_low_mcs_to_n_dbps): Invalid PHY_MODE (%d) or MCS (%d)\n", phy_mode, mcs);
1458        return 1; // N_DBPS used as denominator, so better not return 0
1459    }
1460}
1461
1462
1463
1464/*****************************************************************************/
1465/**
1466 * @brief Convert MCS to Control Response MCS
1467 */
1468inline u8 wlan_mac_low_mcs_to_ctrl_resp_mcs(u8 mcs, u8 phy_mode){
1469    // Returns the fastest NON-HT half-rate MCS lower than the provided MCS and no larger that 24Mbps.
1470    //  Valid return values are [0, 2, 4]
1471    u8 return_value = 0;
1472
1473    if(phy_mode == PHY_MODE_NONHT){
1474        return_value = mcs;
1475        if(return_value > 4){ return_value = 4; }
1476        if(return_value % 2){ return_value--;   }
1477    } else if(phy_mode == PHY_MODE_HTMF) {
1478        switch(mcs){
1479            default:
1480            case 0:
1481                return_value = 0;
1482            break;
1483            case 1:
1484                return_value = 2;
1485            break;
1486            case 2:
1487                return_value = 2;
1488            break;
1489            case 3:
1490            case 4:
1491            case 5:
1492            case 6:
1493            case 7:
1494                return_value = 4;
1495            break;
1496        }
1497    }
1498    return return_value;
1499}
1500
1501inline void wlan_mac_hw_clear_rx_started() {
1502    wlan_mac_reset_rx_started(1);
1503    wlan_mac_reset_rx_started(0);
1504
1505    return;
1506}
1507
1508void wlan_mac_set_tu_target(u64 tu_target) {
1509    Xil_Out32(WLAN_MAC_REG_TU_TARGET_MSB, ((u32)(tu_target >> 32)));
1510    Xil_Out32(WLAN_MAC_REG_TU_TARGET_LSB, ((u32)(tu_target & 0xFFFFFFFF)));
1511}
1512
Note: See TracBrowser for help on using the repository browser.