source: ReferenceDesigns/w3_802.11/c/wlan_w3_high/w3_eth.c

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

1.8.0 release wlan-mac-se

File size: 9.3 KB
Line 
1#include "wlan_mac_high_sw_config.h"
2
3#include "wlan_platform_high.h"
4#include "include/w3_high.h"
5#include "include/w3_eth.h"
6#include "xparameters.h"
7#include "xintc.h"
8#include "wlan_exp_node.h"
9#include "wlan_platform_common.h"
10#include "wlan_platform_high.h"
11#include "wlan_mac_common.h"
12#include "wlan_mac_dl_list.h"
13#include "wlan_mac_high.h"
14#include "wlan_mac_eth_util.h"
15#include "wlan_mac_schedule.h"
16#include "wlan_mac_queue.h"
17#include "wlan_mac_802_11_defs.h"
18#include "wlan_axi_ethernet_intr.h"
19
20#include "xaxidma.h"
21
22#if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE
23static XAxiDma portal_eth_dma_instance;
24peripheral_args_t portal_peripheral_args;
25#endif
26
27#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP
28static XAxiDma wlan_exp_eth_dma_instance;
29peripheral_args_t wlan_exp_peripheral_args;
30#endif
31
32
33
34// Local Function Declarations -- these are not intended to be called by functions outside of this file
35#if (WLAN_SW_CONFIG_ENABLE_WLAN_EXP || WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE)
36void _eth_send_done( eth_tx_queue_buffer_t* eth_tx_queue_buffer );
37#endif
38
39/*****************************************************************************/
40/**
41 * @brief Transmits a packet over Ethernet (Portal)
42 *
43 * This function transmits a single packet via Ethernet using the axi_dma. The
44 * packet passed via pkt_ptr must be a valid Ethernet packet, complete with
45 * 14-byte Ethernet header. This function does not check for a valid header
46 * (i.e. the calling function must ensure this).
47 *
48 * The packet must be stored in a memory location accessible by the axi_dma core.
49 * The MicroBlaze DLMB is *not* accessible to the DMA. Thus packets cannot be
50 * stored in malloc'd areas (the heap is in the DLMB).  In the reference implementation
51 * all Ethernet transmissions start as wireless receptions. Thus, the Ethernet payloads
52 * are stored in the wireless Rx packet buffer, which is accessible by the DMA.
53 *
54 * Custom code which needs to send Ethernet packets can use a spare wireless Tx/Rx
55 * packet buffer, a spare Tx queue entry in DRAM or the user scratch space in DRAM
56 * to create custom Ethernet payloads.
57 *
58 * This function blocks until the Ethernet transmission completes.
59 *
60 * @param eth_tx_queue_buffer_t* eth_tx_queue_buffer - Queue buffer describing to-be-sent packet
61 *
62 * @return 0 for successful Ethernet transmission, -1 otherwise
63 */
64#if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE
65int wlan_platform_portal_eth_send( eth_tx_queue_buffer_t* eth_tx_queue_buffer ) {
66    int status;
67
68    // IMPORTANT:  If the data cache is enabled the cache must be flushed before
69    // attempting to send a packet via the ETH DMA. The DMA will read packet
70    // contents directly from RAM, bypassing any cache checking normally done by
71    // the MicroBlaze.  The data cache is disabled by default in the reference
72    // implementation.
73    //
74    // Xil_DCacheFlushRange((u32)TxPacket, MAX_PKT_LEN);
75
76
77    status = wlan_axi_eth_intr_send( &portal_peripheral_args, eth_tx_queue_buffer );
78
79    if(status & WLAN_AXI_ETH_INTR_SEND_ERR_NO_FREE_BD){
80        return WLAN_FAILURE;
81    } else {
82        return WLAN_SUCCESS;
83    }
84}
85
86int wlan_platform_portal_eth_get_mtu(){
87    return wlan_axi_eth_intr_get_mtu();
88}
89#endif //WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE
90
91#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP
92int wlan_platform_wlan_exp_eth_send( eth_tx_queue_buffer_t* eth_tx_queue_buffer ) {
93    int status;
94    status = wlan_axi_eth_intr_send( &wlan_exp_peripheral_args, eth_tx_queue_buffer );
95
96    if(status & WLAN_AXI_ETH_INTR_SEND_ERR_NO_FREE_BD){
97        return WLAN_FAILURE;
98    } else {
99        return WLAN_SUCCESS;
100    }
101}
102int wlan_platform_wlan_exp_eth_get_mtu(){
103    return wlan_axi_eth_intr_get_mtu();
104}
105#endif
106
107int w3_wlan_platform_ethernet_init() {
108
109#if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE || WLAN_SW_CONFIG_ENABLE_WLAN_EXP
110    intr_conn_params_t intr_conn_params;
111    int status;
112#endif
113
114#if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE || (WLAN_SW_CONFIG_ENABLE_WLAN_EXP && (ETH_WLAN_EXP == 0))
115    // FIXME: I'm not currently working on the single-Ethernet design, but when I do,
116    //        I need to trace through the implications of WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE = 0
117    //        and (WLAN_SW_CONFIG_ENABLE_WLAN_EXP = 1, ETH_WLAN_EXP = 0)
118
119    portal_peripheral_args.driver_instance = (void*)&portal_eth_dma_instance;
120    portal_peripheral_args.callback0 = (void*)wlan_enqueue_eth_rx;
121    portal_peripheral_args.callback1 = (void*)_eth_send_done;
122
123    // Set up ETH A
124    intr_conn_params = wlan_axi_eth_intr_init(&portal_peripheral_args,
125                                              PORTAL_ETH_DEV_ID,
126                                              PORTAL_ETH_LINK_SPEED,
127                                              PORTAL_ETH_MDIO_PHYADDR,
128                                              PORTAL_ETH_BD_MEM_BASEADDR,
129                                              PORTAL_ETH_BD_MEM_SIZE,
130                                              2,
131                                              1,
132                                              0);
133
134    if(intr_conn_params.intr_handler0 == NULL){
135        return WLAN_FAILURE;
136    }
137
138    // Connect the peripheral to the interrupt controller
139    status = wlan_platform_interrupt_connect(PORTAL_ETH_RX_INTR_ID, (wlan_intr_handler_t)intr_conn_params.intr_handler0, intr_conn_params.intr_handler_arg0);
140
141    if (status != WLAN_SUCCESS) {
142        xil_printf("ERROR: Failed to connect axi_dma interrupt: (%d)\n", status);
143        return WLAN_FAILURE;
144    }
145
146    if(intr_conn_params.intr_handler0 == NULL){
147        return WLAN_FAILURE;
148    }
149
150    // Connect the peripheral to the interrupt controller
151    status = wlan_platform_interrupt_connect(PORTAL_ETH_TX_INTR_ID, (wlan_intr_handler_t)intr_conn_params.intr_handler1, intr_conn_params.intr_handler_arg1);
152
153    if (status != WLAN_SUCCESS) {
154        xil_printf("ERROR: Failed to connect axi_dma interrupt: (%d)\n", status);
155        return WLAN_FAILURE;
156    }
157
158    wlan_platform_interrupt_enable(PORTAL_ETH_RX_INTR_ID);
159    wlan_platform_interrupt_enable(PORTAL_ETH_TX_INTR_ID);
160#endif
161
162#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP && (ETH_WLAN_EXP == 1)
163    // Set up ETH B
164    wlan_exp_peripheral_args.driver_instance = (void*)&wlan_exp_eth_dma_instance;
165    wlan_exp_peripheral_args.callback0 = (void*)wlan_exp_process_eth_rx;
166    wlan_exp_peripheral_args.callback1 = (void*)_eth_send_done;
167
168    // Some notes about the heuristics embedded in the following parameters:
169    // - 12 Tx BDs -- this will support a maximum of 6 packets during log retrieval (which uses 2 BDs per packet)
170    // - 3 Tx Coalescing -- in a backlogged scenario, we'll wait for 3 transmissions to be complete. In log retrieval, we'll
171    //   split out ring of 6 packets into 2 chunks and process Tx done interrupts one chunk at a time
172    // - 154 timer delay -- in this hardware platform, C_DLYTMR_RESOLUTION is 125 and m_axi_sg_aclk is 160 Mhz.
173    //   The unit of this parameter is therefore an integer number of 125/160 usec (or 781 ns). Conservatively, assume that C
174    //   can sustain 100Mbps of Tx throughput with standard MTUs. This is equivalent to a 1500 byte packet every 120 usec.
175    //   If more than 120 usec elapses after the last Tx done completion, we know we aren't currently attempting to backlog
176    //   transmissions so we should just fire off an interrupt and not wait for coalescing. 120 usec is 154 delay units.
177    intr_conn_params = wlan_axi_eth_intr_init(&wlan_exp_peripheral_args,
178                                              WLAN_EXP_ETH_DEV_ID,
179                                              WLAN_EXP_ETH_LINK_SPEED,
180                                              WLAN_EXP_ETH_MDIO_PHYADDR,
181                                              WLAN_EXP_ETH_BD_MEM_BASEADDR,
182                                              WLAN_EXP_ETH_BD_MEM_SIZE,
183                                              12,
184                                              3,
185                                              154);
186
187    if(intr_conn_params.intr_handler0 == NULL){
188        return WLAN_FAILURE;
189    }
190
191    // Connect the peripheral to the interrupt controller
192    status = wlan_platform_interrupt_connect(WLAN_EXP_ETH_RX_INTR_ID, (wlan_intr_handler_t)intr_conn_params.intr_handler0, intr_conn_params.intr_handler_arg0);
193
194    if (status != XST_SUCCESS) {
195        xil_printf("ERROR: Failed to connect axi_dma interrupt: (%d)\n", status);
196        return XST_FAILURE;
197    }
198
199    if(intr_conn_params.intr_handler1 == NULL){
200        return WLAN_FAILURE;
201    }
202    // Connect the peripheral to the interrupt controller
203    status = wlan_platform_interrupt_connect(WLAN_EXP_ETH_TX_INTR_ID, (wlan_intr_handler_t)intr_conn_params.intr_handler1, intr_conn_params.intr_handler_arg1);
204
205    if (status != XST_SUCCESS) {
206        xil_printf("ERROR: Failed to connect axi_dma interrupt: (%d)\n", status);
207        return XST_FAILURE;
208    }
209
210    wlan_platform_interrupt_enable(WLAN_EXP_ETH_RX_INTR_ID);
211    wlan_platform_interrupt_enable(WLAN_EXP_ETH_TX_INTR_ID);
212#endif //WLAN_SW_CONFIG_ENABLE_WLAN_EXP
213
214    return WLAN_SUCCESS;
215}
216
217void w3_wlan_platform_ethernet_free_queue_entry_notify(){
218    // We need to disable interrupts here if this function was called from a non-ISR context. Otherwise,
219    // we may get called again and interrupt ourselves from an ISR context while manipulating BDs.
220    interrupt_state_t prev_interrupt_state = wlan_platform_intc_stop();
221#if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE
222    wlan_axi_eth_intr_attach_free_rx_bd(&portal_peripheral_args);
223#endif
224
225#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP
226    wlan_axi_eth_intr_attach_free_rx_bd(&wlan_exp_peripheral_args);
227#endif //WLAN_SW_CONFIG_ENABLE_WLAN_EXP
228    wlan_platform_intc_set_state(prev_interrupt_state);
229
230}
231
232#if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE || WLAN_SW_CONFIG_ENABLE_WLAN_EXP
233void _eth_send_done( eth_tx_queue_buffer_t* eth_tx_queue_buffer ){
234    wlan_mac_high_cdma_finish_transfer();
235
236    // Free the just-sent Tx queue buffer
237    if(eth_tx_queue_buffer != NULL) queue_checkin(eth_tx_queue_buffer->pyld_queue_hdr.dle);
238}
239#endif
240
241
Note: See TracBrowser for help on using the repository browser.