110d539beSJiao Xianjun# openwifi document 22ee67178SXianjun Jiao<img src="./openwifi-detail.jpg" width="1100"> 32ee67178SXianjun Jiao 44f977aa9SJiao XianjunAbove figure shows software and hardware/FPGA modules that compose the openwifi design. The module name is equal/similar to the source code file name. Driver module source codes are in openwifi/driver/. FPGA module source codes are in openwifi-hw repository. The user space tool sdrctl source code are in openwifi/user_space/sdrctl_src/. 52ee67178SXianjun Jiao 65f436b3cSJiao Xianjun- [driver and software overall principle](#driver-and-software-overall-principle) 710d539beSJiao Xianjun- [sdrctl command](#sdrctl-command) 85f436b3cSJiao Xianjun- [rx packet flow and filtering config](#rx-packet-flow-and-filtering-config) 95f436b3cSJiao Xianjun- [tx packet flow and config](#tx-packet-flow-and-config) 102309afd4SJiao Xianjun- [debug methods](#debug-methods) 115f436b3cSJiao Xianjun 125f436b3cSJiao Xianjun## driver and software overall principle 135f436b3cSJiao Xianjun 144f977aa9SJiao Xianjun[Linux mac80211 subsystem](https://www.kernel.org/doc/html/v4.16/driver-api/80211/mac80211.html), as a part of [Linux wireless](https://wireless.wiki.kernel.org/en/developers/documentation/mac80211), defines a set of APIs ([ieee80211_ops](https://www.kernel.org/doc/html/v4.9/80211/mac80211.html#c.ieee80211_ops)) to rule the Wi-Fi chip driver behavior. SoftMAC Wi-Fi chip driver implements (subset of) those APIs. That is why Linux can support so many Wi-Fi chips of different chip vendors. 155f436b3cSJiao Xianjun 165f436b3cSJiao Xianjunopenwifi driver (sdr.c) implements following APIs of ieee80211_ops: 175f436b3cSJiao Xianjun- **tx**. It is called when upper layer has a packet to send 185f436b3cSJiao Xianjun- **start**. It is called when NIC up. (ifconfig sdr0 up) 195f436b3cSJiao Xianjun- **stop**. It is called when NIC down. (ifconfig sdr0 down) 205f436b3cSJiao Xianjun- **add_interface**. It is called when NIC is created 215f436b3cSJiao Xianjun- **remove_interface**. It is called when NIC is deleted 225f436b3cSJiao Xianjun- **config**. It is called when upper layer wants to change channel/frequency (like the scan operation) 235f436b3cSJiao Xianjun- **bss_info_changed**. It is called when upper layer believe some BSS parameters need to be changed (BSSID, TX power, beacon interval, etc) 245f436b3cSJiao Xianjun- **conf_tx**. It is called when upper layer needs to config/change some tx parameters (AIFS, CW_MIN, CW_MAX, TXOP, etc) 256a6fa9b4Sweiliu1011- **prepare_multicast**. It is called when upper layer needs to prepare multicast, currently only a empty function hook is present. 265f436b3cSJiao Xianjun- **configure_filter**. It is called when upper layer wants to config/change the [frame filtering](https://www.kernel.org/doc/html/v4.9/80211/mac80211.html#frame-filtering) rule in FPGA. 275f436b3cSJiao Xianjun- **rfkill_poll**. It is called when upper layer wants to know the RF status (ON/OFF). 285f436b3cSJiao Xianjun- **get_tsf**. It is called when upper layer wants to get 64bit FPGA timer value (TSF - Timing synchronization function) 295f436b3cSJiao Xianjun- **set_tsf**. It is called when upper layer wants to set 64bit FPGA timer value 305f436b3cSJiao Xianjun- **reset_tsf**. It is called when upper layer wants to reset 64bit FPGA timer value 315f436b3cSJiao Xianjun- **set_rts_threshold**. It is called when upper layer wants to change the threshold (packet length) for turning on RTS mechanism 325f436b3cSJiao Xianjun- **testmode_cmd**. It is called when upper layer has test command for us. [sdrctl command](#sdrctl-command) message is handled by this function. 335f436b3cSJiao Xianjun 346a6fa9b4Sweiliu1011Above APIs are called by upper layer (Linux mac80211 subsystem). When they are called, the driver (sdr.c) will do necessary job over SDR platform. If necessary, the driver will call other component drivers, like tx_intf_api/rx_intf_api/openofdm_tx_api/openofdm_rx_api/xpu_api, for help. 355f436b3cSJiao Xianjun 364f977aa9SJiao XianjunAfter receiving a packet from the air, FPGA will raise interrupt (if the frame filtering rule allows) to Linux, then the function openwifi_rx_interrupt() of openwifi driver (sdr.c) will be triggered. In that function, ieee80211_rx_irqsafe() API is used to give the packet and related information (timestamp, rssi, etc) to upper layer. 3710d539beSJiao Xianjun 386a6fa9b4Sweiliu1011The packet sending is initiated by upper layer. After the packet is sent by the driver over FPGA to the air, the upper layer will expect a sending report from the driver. Each time FPGA sends a packet, an interrupt will be raised to Linux and trigger openwifi_tx_interrupt(). This function will report the sending result (failed? succeeded? number of retransmissions, etc.) to upper layer via ieee80211_tx_status_irqsafe() API. 395f436b3cSJiao Xianjun 405f436b3cSJiao Xianjun## sdrctl command 412ee67178SXianjun Jiao 4262591d26Sweiliu1011Besides the Linux native Wi-Fi control programs, such as ifconfig/iw/iwconfig/iwlist/wpa_supplicant/hostapd/etc, openwifi offers a user space tool sdrctl to access openwifi specific functionalities, such as time sharing of the interface between two network slices, you may find more details of the slicing mechanism [here](https://doc.ilabt.imec.be/ilabt/wilab/tutorials/openwifi.html#sdr-tx-time-slicing). 4362591d26Sweiliu1011 4462591d26Sweiliu1011sdrctl is implemented as nl80211 testmode command and communicates with openwifi driver (function openwifi_testmode_cmd() in sdr.c) via Linux nl80211--cfg80211--mac80211 path 452ee67178SXianjun Jiao 465f436b3cSJiao Xianjun### get and set a parameter 472ee67178SXianjun Jiao``` 482ee67178SXianjun Jiaosdrctl dev sdr0 get para_name 492ee67178SXianjun Jiaosdrctl dev sdr0 set para_name value 502ee67178SXianjun Jiao``` 5162591d26Sweiliu1011para_name|meaning|comment 522ee67178SXianjun Jiao---------|-------|---- 5310d539beSJiao Xianjunaddr0|target MAC address of tx slice 0|32bit. for address 6c:fd:b9:4c:b1:c1, you set b94cb1c1 542ee67178SXianjun Jiaoslice_total0|tx slice 0 cycle length in us|for length 50ms, you set 49999 552ee67178SXianjun Jiaoslice_start0|tx slice 0 cycle start time in us|for start at 10ms, you set 10000 562ee67178SXianjun Jiaoslice_end0| tx slice 0 cycle end time in us|for end at 40ms, you set 39999 5710d539beSJiao Xianjunaddr1|target MAC address of tx slice 1|32bit. for address 6c:fd:b9:4c:b1:c1, you set b94cb1c1 582ee67178SXianjun Jiaoslice_total1|tx slice 1 cycle length in us|for length 50ms, you set 49999 592ee67178SXianjun Jiaoslice_start1|tx slice 1 cycle start time in us|for start at 10ms, you set 10000 602ee67178SXianjun Jiaoslice_end1| tx slice 1 cycle end time in us|for end at 40ms, you set 39999 612ee67178SXianjun Jiao 625f436b3cSJiao Xianjun### get and set a register of a module 632ee67178SXianjun Jiao``` 642ee67178SXianjun Jiaosdrctl dev sdr0 get reg module_name reg_idx 652ee67178SXianjun Jiaosdrctl dev sdr0 set reg module_name reg_idx reg_value 662ee67178SXianjun Jiao``` 67*1bbbbdc7SJiao Xianjunmodule_name refers to the name of driver functionality, can be drv_rx/drv_tx/drv_xpu. Related registers are defined in sdr.h (drv_rx_reg_val/drv_tx_reg_val/drv_xpu_reg_val) 682ee67178SXianjun Jiao 69*1bbbbdc7SJiao Xianjunmodule_name rf/rx_intf/tx_intf/rx/tx/xpu refer to RF (ad9xxx front-end) and FPGA modules (rx_intf/tx_intf/openofdm_rx/openofdm_tx/xpu). Related register addresses are defined in hw_def.h. 702ee67178SXianjun Jiao 712ee67178SXianjun Jiaomodule_name: drv_rx 7262591d26Sweiliu1011In the *comment* column, you may get a list of *decimalvalue(0xhexvalue):explanation* for a register, only use the *decimalvalue* or *hexvalue* in the sdrctl command. 732ee67178SXianjun Jiao 7462591d26Sweiliu1011reg_idx|meaning|comment 752ee67178SXianjun Jiao-------|-------|---- 762ee67178SXianjun Jiao1|rx antenna selection|0:rx1, 1:rx2. After this command, you should down and up sdr0 by ifconfig, but not reload sdr0 driver via ./wgd.sh 772ee67178SXianjun Jiao 782ee67178SXianjun Jiaomodule_name: drv_tx 792ee67178SXianjun Jiao 8062591d26Sweiliu1011reg_idx|meaning|comment 812ee67178SXianjun Jiao-------|-------|---- 822ee67178SXianjun Jiao0|override Linux rate control of tx unicast data packet|4:6M, 5:9M, 6:12M, 7:18M, 8:24M, 9:36M, 10:48M, 11:54M 832ee67178SXianjun Jiao1|tx antenna selection|0:tx1, 1:tx2. After this command, you should down and up sdr0 by ifconfig, but not reload sdr0 driver via ./wgd.sh 842ee67178SXianjun Jiao 852ee67178SXianjun Jiaomodule_name: drv_xpu 862ee67178SXianjun Jiao 8762591d26Sweiliu1011reg_idx|meaning|comment 882ee67178SXianjun Jiao-------|-------|---- 8962591d26Sweiliu1011x|x|to be defined 902ee67178SXianjun Jiao 912ee67178SXianjun Jiaomodule_name: rf 922ee67178SXianjun Jiao 9362591d26Sweiliu1011reg_idx|meaning|comment 942ee67178SXianjun Jiao-------|-------|---- 9562591d26Sweiliu1011x|x|to be defined 962ee67178SXianjun Jiao 972ee67178SXianjun Jiaomodule_name: rx_intf 982ee67178SXianjun Jiao 9962591d26Sweiliu1011reg_idx|meaning|comment 1002ee67178SXianjun Jiao-------|-------|---- 1012ee67178SXianjun Jiao2|enable/disable rx interrupt|256(0x100):disable, 0:enable 1022ee67178SXianjun Jiao 1032ee67178SXianjun Jiaomodule_name: tx_intf 1042ee67178SXianjun Jiao 10562591d26Sweiliu1011reg_idx|meaning|comment 1062ee67178SXianjun Jiao-------|-------|---- 1072ee67178SXianjun Jiao13|tx I/Q digital gain before DUC|current optimal value: 237 1082ee67178SXianjun Jiao14|enable/disable tx interrupt|196672(0x30040):disable, 64(0x40):enable 1092ee67178SXianjun Jiao 1102ee67178SXianjun Jiaomodule_name: rx 1112ee67178SXianjun Jiao 11262591d26Sweiliu1011reg_idx|meaning|comment 1132ee67178SXianjun Jiao-------|-------|---- 1142ee67178SXianjun Jiao20|history of PHY rx state|read only. If the last digit readback is always 3, it means the Viterbi decoder stops working 1152ee67178SXianjun Jiao 1162ee67178SXianjun Jiaomodule_name: tx 1172ee67178SXianjun Jiao 11862591d26Sweiliu1011reg_idx|meaning|comment 1192ee67178SXianjun Jiao-------|-------|---- 1202ee67178SXianjun Jiao1|pilot scrambler initial state|lowest 7 bits are used. 0x7E by default in openofdm_tx.c 1212ee67178SXianjun Jiao2|data scrambler initial state|lowest 7 bits are used. 0x7F by default in openofdm_tx.c 1222ee67178SXianjun Jiao 1232ee67178SXianjun Jiaomodule_name: xpu 1242ee67178SXianjun Jiao 12562591d26Sweiliu1011reg_idx|meaning|comment 1262ee67178SXianjun Jiao-------|-------|---- 1272ee67178SXianjun Jiao2|TSF timer low 32bit write|only write this register won't trigger the TSF timer reload. should use together with register for high 32bit 1282ee67178SXianjun Jiao3|TSF timer high 32bit write|falling edge of MSB will trigger the TSF timer reload, which means write '1' then '0' to MSB 1292ee67178SXianjun Jiao4|band and channel number setting|see enum openwifi_band in hw_def.h. it will be set automatically by Linux. normally you shouldn't set it 13010d539beSJiao Xianjun11|max number of retransmission in FPGA|normally number of retransmissions controlled by Linux in real-time. If you write non-zeros value to this register, it will override Linux real-time setting 1312ee67178SXianjun Jiao19|CSMA enable/disable|3758096384(0xe0000000): disable, 3:enable 1322ee67178SXianjun Jiao20|tx slice 0 cycle length in us|for length 50ms, you set 49999 1332ee67178SXianjun Jiao21|tx slice 0 cycle start time in us|for start at 10ms, you set 10000 1342ee67178SXianjun Jiao22|tx slice 0 cycle end time in us|for end at 40ms, you set 39999 1352ee67178SXianjun Jiao23|tx slice 1 cycle length in us|for length 50ms, you set 49999 1362ee67178SXianjun Jiao24|tx slice 1 cycle start time in us|for start at 10ms, you set 10000 1372ee67178SXianjun Jiao25|tx slice 1 cycle end time in us|for end at 40ms, you set 39999 1382ee67178SXianjun Jiao27|FPGA packet filter config|check openwifi_configure_filter in sdr.c. also: https://www.kernel.org/doc/html/v4.9/80211/mac80211.html#frame-filtering 1392ee67178SXianjun Jiao28|BSSID address low 32bit for BSSID filtering|normally it is set by Linux in real-time automatically 1402ee67178SXianjun Jiao29|BSSID address high 32bit for BSSID filtering|normally it is set by Linux in real-time automatically 1412ee67178SXianjun Jiao30|openwifi MAC address low 32bit| 1422ee67178SXianjun Jiao31|openwifi MAC address high 32bit|check XPU_REG_MAC_ADDR_write in sdr.c to see how we set MAC address to FPGA when NIC start 1432ee67178SXianjun Jiao58|TSF runtime value low 32bit|read only 1442ee67178SXianjun Jiao59|TSF runtime value high 32bit|read only 145c3d9cd01SJiao Xianjun63|version information|read only 1465f436b3cSJiao Xianjun 1475f436b3cSJiao Xianjun## rx packet flow and filtering config 1485f436b3cSJiao Xianjun 1494f977aa9SJiao XianjunAfter FPGA receives a packet, no matter the FCS/CRC is correct or not it will raise interrupt to Linux if the frame filtering rule allows. openwifi_rx_interrupt() function in sdr.c will be triggered to do necessary operation and give the information to upper layer (Linux mac80211 subsystem). 1505f436b3cSJiao Xianjun 15110d539beSJiao Xianjun- frame filtering 15210d539beSJiao Xianjun 1534f977aa9SJiao XianjunBecause the FPGA frame filtering configuration is done in real-time by function openwifi_configure_filter() in sdr.c, you may not have all packet type you want even if you put your sdr0 to sniffing mode. But you do have the chance to capture any types of packet by changing the filter_flag in openwifi_configure_filter() to override the frame filtering in FPGA with MONITOR_ALL. The filter_flag together with HIGH_PRIORITY_DISCARD_FLAG finally go to pkt_filter_ctl.v of xpu module in FPGA, and control how FPGA does frame filtering. 15410d539beSJiao Xianjun 15510d539beSJiao Xianjun- main rx interrupt operations in openwifi_rx_interrupt() 1564f977aa9SJiao Xianjun - get raw content from DMA buffer. When Linux receives interrupt from FPGA rx_intf module, the content has been ready in Linux DMA buffer 15710d539beSJiao Xianjun - parse extra information inserted by FPGA in the DMA buffer 15810d539beSJiao Xianjun - TSF timer value 1594f977aa9SJiao Xianjun - raw RSSI value that will be converted to actual RSSI in dBm by different correction in different bands/channels 16010d539beSJiao Xianjun - packet length and MCS 16110d539beSJiao Xianjun - FCS is valid or not 16210d539beSJiao Xianjun - send packet content and necessary extra information to upper layer via ieee80211_rx_irqsafe() 1635f436b3cSJiao Xianjun 1645f436b3cSJiao Xianjun## tx packet flow and config 1655f436b3cSJiao Xianjun 16610d539beSJiao XianjunLinux mac80211 subsystem calls openwifi_tx() to initiate a packet sending. 16710d539beSJiao Xianjun 16810d539beSJiao Xianjun- main operations in openwifi_tx() 16910d539beSJiao Xianjun - get necessary information from the packet header (struct ieee80211_hdr) for future FPGA configuration use 17010d539beSJiao Xianjun - packet length and MCS 1714f977aa9SJiao Xianjun - unicast or broadcast? does it need ACK? how many retransmissions at most are allowed to be tried by FPGA in case ACK is not received in time? 17210d539beSJiao Xianjun - which time slice in FPGA the packet should go? 17310d539beSJiao Xianjun - should RTS-CTS be used? (Send RTS and wait for CTS before actually send the data packet) 17410d539beSJiao Xianjun - should CTS-to-self be used? (Send CTS-to-self packet before sending the data packet. You can force this on by force_use_cts_protect = true;) 17510d539beSJiao Xianjun - should a sequence number be set for this packet? 1764f977aa9SJiao Xianjun - generate SIGNAL field according to length and MCS information. Insert it before the packet for the future openofdm_tx FPGA module use 1774f977aa9SJiao Xianjun - generate FPGA/PHY sequence number (priv->phy_tx_sn) for internal use (cross check between Linux and FPGA) 1784f977aa9SJiao Xianjun - config FPGA register according to the above information to make sure FPGA do correct actions according to the packet specific requirement. 17910d539beSJiao Xianjun - fire DMA transmission from Linux to one of FPGA tx queues. The packet may not be sent immediately if there are still some packets in FPGA tx queue (FPGA does the queue packet transmission according to channel and low MAC state) 18010d539beSJiao Xianjun 1814f977aa9SJiao XianjunEach time when FPGA sends a packet, an interrupt will be raised to Linux reporting the packet sending result. This interrupt handler is openwifi_tx_interrupt(). 18210d539beSJiao Xianjun 18310d539beSJiao Xianjun- main operations in openwifi_tx_interrupt() 1844f977aa9SJiao Xianjun - get necessary information/status of the packet just sent by FPGA 1854f977aa9SJiao Xianjun - packet length and sequence number to capture abnormal situation (cross checking between Linux and FPGA) 1864f977aa9SJiao Xianjun - packet sending result: packet is sent successfully (FPGA receives ACK for this packet) or not. How many retransmissions are used for the packet sending (in case FPGA doesn't receive ACK in time, FPGA will do retransmission immediately) 18710d539beSJiao Xianjun - send above information to upper layer (Linux mac80211 subsystem) via ieee80211_tx_status_irqsafe() 1882309afd4SJiao Xianjun 1892309afd4SJiao Xianjun## debug methods 1902309afd4SJiao Xianjun 1912309afd4SJiao Xianjun### dmesg 1922309afd4SJiao Xianjun 1932309afd4SJiao XianjunTo debug/see the basic driver behaviour, you could use dmesg command in Linux. openwifi driver prints normal tx/rx packet information when a packet is sent or received. The driver also prints WARNING information if it feels something abnormal happens. You can search "printk" in sdr.c to see all the printing points. 1942309afd4SJiao Xianjun 1952309afd4SJiao Xianjun- tx printing example 1962309afd4SJiao Xianjun 1972309afd4SJiao Xianjun sdr,sdr openwifi_tx: 116bytes 48M FC0208 DI002c addr1/2/3:b827ebe65f1e/66554433224c/66554433224c SC1df0 flag40000012 retry2 ack1 q0 sn1075 R/CTS 00 1M 0us wr/rd 19/19 1982309afd4SJiao Xianjun - printing from sdr driver, openwifi_tx function. 1992309afd4SJiao Xianjun - 116bytes: packet size (length field in SIGNAL) is 116 bytes. 2002309afd4SJiao Xianjun - 48M: MCS (rate field in SIGNAL) is 48Mbps. 2012309afd4SJiao Xianjun - FC0208: Frame Control field 0x0208, which means type data, subtype data, to DS 0, from DS 1 (a packet from AP to client). 2022309afd4SJiao Xianjun - DI002c: Duration/ID field 0x002c. How many us this packet will occupy the channel (including waiting for ACK). 2032309afd4SJiao Xianjun - addr1/2/3: address fields. Target MAC address b827ebe65f1e, source MAC address 66554433224c (openwifi). 2042309afd4SJiao Xianjun - SC1df0: Sequence Control field 0x1df0, which means that the driver inserts sequence number 0x1df0 to the packet under request of upper layer. 2052309afd4SJiao Xianjun - flag40000012: flags field from upper layer struct ieee80211_tx_info (first fragment? need ACK? need sequence number insertion? etc.). Here is 0x40000012. 2062309afd4SJiao Xianjun - retry2: upper layer tells us the maximum number of retransmissions for this packet is 2. 2072309afd4SJiao Xianjun - ack1: upper layer tells us this packet needs ACK. 2082309afd4SJiao Xianjun - q0: the packet goes to FPGA queue 0. 2092309afd4SJiao Xianjun - sn1075: PHY/FPGA sequence number 1075. This is different from Sequence Control asked by upper layer. This is for cross check between FPGA/interrupt and driver. 2102309afd4SJiao Xianjun - R/CTS 00: upper layer believes this packet doesn't need RTS/CTS mechanism (Because the packet size is below the RTS threshold). 2112309afd4SJiao Xianjun - 1M 0us: if RTS/CTS is asked to be used by upper layer, it should use xM rate and Xus duration. 2122309afd4SJiao Xianjun - wr/rd 19/19: the write/read index of buffer (shared buffer between the active openwifi_tx and background openwifi_tx_interrupt). 2132309afd4SJiao Xianjun 2142309afd4SJiao Xianjun- rx printing example 2152309afd4SJiao Xianjun 2162309afd4SJiao Xianjun sdr,sdr openwifi_rx_interrupt: 120bytes ht0 54M FC0108 DI002c addr1/2/3:66554433224c/b827ebe65f1e/66554433224c SCcf20 fcs1 sn117 i117 -36dBm 2172309afd4SJiao Xianjun - printing from sdr driver, openwifi_rx_interrupt function. 2182309afd4SJiao Xianjun - 120bytes: packet size (length field in SIGNAL) is 120 bytes. 2192309afd4SJiao Xianjun - ht0: this is non-ht packet. 2202309afd4SJiao Xianjun - 54M: MCS (rate field in SIGNAL) is 54Mbps. 2212309afd4SJiao Xianjun - FC0108: Frame Control field 0x0208, which means type data, subtype data, to DS 1, from DS 0 (a packet client to openwifi AP). 2222309afd4SJiao Xianjun - DI002c: Duration/ID field 0x002c. How many us this packet will occupy the channel (including waiting for ACK). 2232309afd4SJiao Xianjun - addr1/2/3: address fields. Target MAC address 66554433224c (openwifi), source MAC address b827ebe65f1e. 2242309afd4SJiao Xianjun - SCcf20: Sequence Control field 0x1df0, which means that the packet includes sequence number 0xcf20 (under request of upper layer of the peer). 2252309afd4SJiao Xianjun - fcs1: FCS/CRC is OK. 2262309afd4SJiao Xianjun - sn117: HY/FPGA sequence number 117. This is different from Sequence Control asked by upper layer. This is for cross check between FPGA/interrupt and driver. 2272309afd4SJiao Xianjun - i117: current rx packet DMA buffer index 117. 2282309afd4SJiao Xianjun - -36dBm: signal strength of this received packet. 2292309afd4SJiao Xianjun 2302309afd4SJiao Xianjun### native Linux tools 2312309afd4SJiao Xianjun 2322309afd4SJiao XianjunFor protocol, many native Linux tools you still could rely on. Such as tcpdump. 2332309afd4SJiao Xianjun 2342309afd4SJiao Xianjun### FPGA 2352309afd4SJiao Xianjun 2364f977aa9SJiao XianjunFor FPGA itself, FPGA developer could use Xilinx ILA tools to analyze FPGA signals. Spying on those state machines in xpu/tx_intf/rx_intf would be very helpful for understanding/debugging Wi-Fi low level funtionalities. 237