├── .gitignore ├── OpenWRT_Makefile ├── README ├── click ├── .gitignore ├── Makefile ├── README ├── TODO ├── build │ └── .gitignore ├── configs │ ├── ath9k-downstream.slickh │ ├── ath9k-upstream.slickh │ ├── generic-master.slickh │ ├── generic-station.slickh │ ├── master.slick │ ├── shared.slickh │ ├── station-1.slick │ ├── station-2.slick │ ├── station-3.slick │ ├── station-4.slick │ ├── test-demux.slick │ ├── test-encap.slick │ ├── test-gate.slick │ ├── test-sched.slick │ ├── tun-downstream.slickh │ └── tun-upstream.slickh ├── dist │ └── .gitignore └── elements │ ├── Frame.cc │ ├── Frame.hh │ ├── JaldiClick.hh │ ├── JaldiDecap.cc │ ├── JaldiDecap.hh │ ├── JaldiEncap.cc │ ├── JaldiEncap.hh │ ├── JaldiFakeDriver.cc │ ├── JaldiFakeDriver.hh │ ├── JaldiFakeDriverPrecise.cc │ ├── JaldiFakeDriverPrecise.hh │ ├── JaldiGate.cc │ ├── JaldiGate.hh │ ├── JaldiPrint.cc │ ├── JaldiPrint.hh │ ├── JaldiQueue.cc │ ├── JaldiQueue.hh │ ├── JaldiScheduler.cc │ ├── JaldiScheduler.hh │ ├── JaldiVoIPDemux.cc │ ├── JaldiVoIPDemux.hh │ ├── Makefile.in │ └── configure.ac ├── kerneldriver ├── Kconfig ├── Makefile ├── ahb.c ├── debug.c ├── debug.h ├── eeprom.c ├── eeprom.h ├── eeprom_def.c ├── hw.c ├── hw.h ├── init.c ├── initvals.h ├── jaldi.h ├── mac.h ├── main.c ├── pci.c ├── phy.c ├── phy.h └── reg.h ├── openwrt-feed └── jaldi-click │ └── Makefile └── shared ├── Frame.cc └── Frame.hh /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /OpenWRT_Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for TIER-specific kernel modules 3 | # 4 | 5 | include $(TOPDIR)/rules.mk 6 | include $(INCLUDE_DIR)/kernel.mk 7 | 8 | PKG_NAME:=jaldi 9 | 10 | PKG_VERSION:=2010-07-20 11 | PKG_RELEASE:=1 12 | 13 | #PKG_SOURCE:=jaldi.tar.bz2 14 | PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/jaldi 15 | #PKG_CAT:=bzcat 16 | 17 | include $(INCLUDE_DIR)/package.mk 18 | 19 | WMENU:=Wireless Drivers 20 | 21 | define KernelPackage/jaldi 22 | TITLE:=JaldiMAC driver for Atheros wireless devices 23 | DEPENDS+= @PCI_SUPPORT 24 | SUBMENU:=$(WMENU) 25 | VERSION:=$(LINUX_VERSION)+$(PKG_VERSION) 26 | FILES:= \ 27 | $(PKG_BUILD_DIR)/jaldi.$(LINUX_KMOD_SUFFIX) 28 | AUTOLOAD:=$(call AutoLoad,27,jaldi) 29 | MENU:=1 30 | endef 31 | 32 | MAKE_OPTS:= \ 33 | CROSS_COMPILE="$(KERNEL_CROSS)" \ 34 | ARCH="$(LINUX_KARCH)" \ 35 | KLIB_BUILD="$(LINUX_DIR)" \ 36 | KLIB=$(TARGET_MODULES_DIR) 37 | 38 | 39 | define Build/Prepare 40 | rm -rf $(PKG_BUILD_DIR) 41 | cp -pr /home/shaddi/Code/jaldi-openwrt/jaldi/jaldi/kerneldriver $(KERNEL_BUILD_DIR)/jaldi 42 | #rm -rf $(PKG_BUILD_DIR)/.git $(PKG_BUILD_DIR)/OpenWRT_Makefile 43 | endef 44 | 45 | define Build/Compile/kmod 46 | rm -rf $(PKG_BUILD_DIR)/modules 47 | $(MAKE) -C "$(PKG_BUILD_DIR)" $(MAKE_OPTS) 48 | endef 49 | 50 | define Build/Compile 51 | $(call Build/Compile/kmod) 52 | endef 53 | 54 | $(eval $(call KernelPackage,jaldi)) 55 | 56 | 57 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is the jaldimac kernel driver. Not currently functional, but more 2 | documentation will be added once the driver is in a working state. 3 | 4 | Getting JaldiMAC to compile under OpenWRT 5 | ========================================= 6 | This assumes you are able to build OpenWRT from source already. I've only 7 | tested with Backfire, and I make no guarantees that it will work with anything 8 | but my specific buildroot (but it probably will). 9 | 10 | First, create a directory called "jaldi" under backfire/packages. Rename 11 | OpeNWRT_Makefile to Makefile and drop it in here. You need to modify this file 12 | to reflect the location of wherever you have the source for JaldiMAC located on 13 | your machine. Edit line 41 (under Build/Prepare) to point to this. In the 14 | future, this will all be automated in keeping with the spirit of the OpenWRT 15 | build system, but for now copying the source into the build_dir on every build 16 | makes development a bit easier. 17 | 18 | After this you should be good to go. Go into 'make menuconfig' and select the 19 | kmod-jaldi package under Kernel Modules > Wireless Drivers. Compile it as 20 | normal. 21 | 22 | If you're hacking on jaldi and want to just rebuild the jaldi package and 23 | create an updated image to flash onto your device, just run 'make 24 | package/jaldi-{clean,compile,install} ; make target/install' (assuming you've 25 | selected the kmod-jaldi package to begin with, of course). 26 | -------------------------------------------------------------------------------- /click/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore all generated files 2 | build/* 3 | dist/* 4 | -------------------------------------------------------------------------------- /click/Makefile: -------------------------------------------------------------------------------- 1 | # ======================================== 2 | # Configuration 3 | # ======================================== 4 | 5 | TESTS=test-encap test-demux test-gate test-sched 6 | CONFIGURATIONS=master station-1 station-2 station-3 station-4 $(TESTS) 7 | ELEMENTS_CONFIGURATION=--enable-userlevel 8 | CHECK?=no 9 | 10 | # ======================================== 11 | # Internal and derived variables 12 | # ======================================== 13 | 14 | CONFIGDIR=configs 15 | ELEMENTDIR=elements 16 | BUILDDIR=build 17 | DISTDIR=dist 18 | CONFIGURATION_FILES=$(addprefix $(BUILDDIR)/,$(addsuffix .click,$(CONFIGURATIONS))) 19 | CONFIGURATION_DOT=$(addprefix $(BUILDDIR)/,$(addsuffix .dot,$(CONFIGURATIONS))) 20 | CONFIGURATION_GRAPH=$(addprefix $(DISTDIR)/,$(addsuffix .pdf,$(CONFIGURATIONS))) 21 | PACKAGES=$(addprefix $(DISTDIR)/,$(addsuffix .clickpkg,$(CONFIGURATIONS))) 22 | JALDI_PACKAGE_BINARY=$(ELEMENTDIR)/jaldi.uo 23 | JALDI_ELEMENT_MAP=$(ELEMENTDIR)/elementmap-jaldi.xml 24 | 25 | # ======================================== 26 | # Metarules 27 | # ======================================== 28 | 29 | .PHONY: all dist packages pretty configurations elements clean 30 | .SILENT: 31 | 32 | # ======================================== 33 | # Targets 34 | # ======================================== 35 | 36 | all: dist 37 | 38 | dist: packages pretty 39 | 40 | packages: $(PACKAGES) 41 | 42 | pretty: $(CONFIGURATION_DOT) $(CONFIGURATION_GRAPH) 43 | 44 | configurations: $(CONFIGURATION_FILES) 45 | 46 | elements: $(JALDI_PACKAGE_BINARY) $(JALDI_ELEMENT_MAP) 47 | 48 | clean: 49 | cd $(BUILDDIR); rm -f * 50 | cd $(DISTDIR); rm -f * 51 | cd $(ELEMENTDIR) && (make clean 2> /dev/null || true) 52 | cd $(ELEMENTDIR) && rm -f Makefile configure config.status config.log 53 | cd $(ELEMENTDIR) && rm -rf autom4te.cache 54 | 55 | # ======================================== 56 | # Internal targets 57 | # ======================================== 58 | 59 | %.click: ../$(CONFIGDIR)/%.slick 60 | gcc -E -x c $< -o $@ 61 | 62 | %.dot: %.clickpkg 63 | click-pretty --dot $< > $@ 64 | 65 | %.pdf: %.dot 66 | dot -Tpdf -o$@ $< 67 | 68 | %.clickpkg: ../$(BUILDDIR)/%.click configurations elements 69 | cp $< $(BUILDDIR)/config 70 | ar rcs $@ $(BUILDDIR)/config $(JALDI_PACKAGE_BINARY) $(JALDI_ELEMENT_MAP) 71 | #click -q $@ || (rm -f $@ && rm -f $< && false) 72 | ifeq ($(CHECK),no) 73 | else 74 | click -q $@ || (echo "Click configuration failed sanity check; if the problem is real, remember to run 'make clean' before running 'make' again.\n" && true) 75 | endif 76 | 77 | $(ELEMENTDIR)/Makefile: 78 | cd $(ELEMENTDIR) && autoconf && ./configure $(ELEMENTS_CONFIGURATION) 79 | 80 | $(JALDI_PACKAGE_BINARY): $(ELEMENTDIR)/Makefile 81 | cd $(ELEMENTDIR) && make 82 | 83 | $(JALDI_ELEMENT_MAP): 84 | click-mkelemmap $(ELEMENTDIR)/*.hh > $@ 85 | -------------------------------------------------------------------------------- /click/README: -------------------------------------------------------------------------------- 1 | These are the Click elements and Click configurations that make up the JaldiMAC 2 | implementation. 3 | 4 | For this to build, the following must already be installed: 5 | 6 | - GNU build tools (gcc, autotools, make, etc.) 7 | - The Click modular router 8 | - Graphviz 9 | 10 | To build, type "make". To remove the generated files from a previous build, 11 | type "make clean". The "dist" directory will contain the useful build products; 12 | for each master and station, there are: 13 | 14 | - "clickpkg" files: these are actually ar archives, and can be loaded just as 15 | if they were a standalone configuration by the Click tools; they contain all 16 | of the custom JaldiMAC elements in addition to a Click configuration matching 17 | the name of the package. 18 | - "pdf" files: these are visualizations of each Click configuration, generated 19 | by click-pretty and dot. 20 | -------------------------------------------------------------------------------- /click/TODO: -------------------------------------------------------------------------------- 1 | - Add support for bulk ACKs - or, indeed, any ACKs at all! 2 | - Make a drop front variant of JaldiQueue for use with VoIP flows. 3 | - Make JaldiScheduler create the layout online instead of being an offline algorithm; this will enable better VoIP performance. (The current arrangement of inserting VoIP packets from upstream into the downstream transmissions dynamically in the fake driver is only a temporary hack.) 4 | - Complete this TODO list. =) 5 | -------------------------------------------------------------------------------- /click/build/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaddi/jaldimac/5d545828645248447846cf4f97a534cbe603a85a/click/build/.gitignore -------------------------------------------------------------------------------- /click/configs/ath9k-downstream.slickh: -------------------------------------------------------------------------------- 1 | // JaldiMAC Click configuration for downstream traffic from an ath9k monitor device 2 | 3 | // Defines $DOWNSTREAM_SOURCE and $DOWNSTREAM_SINK for ath9k monitor-mode devices. 4 | 5 | // ====================================================== 6 | // Component Graph 7 | // ====================================================== 8 | 9 | elementclass FromMonitor 10 | { 11 | FromDevice(mon0) 12 | -> RadiotapDecap() -> Strip(2) // we're using a custom radiotap header, so we need to strip 2 more bytes 13 | -> WifiDecap() 14 | -> Strip(14) // strip ethernet 15 | -> output 16 | } 17 | 18 | elementclass Injectorizer { 19 | input 20 | -> EtherEncap(0x9000, a1:a1:ff:a1:ff:ff, ff:ff:ff:0f:ff:ff) // note the address we put here doesn't matter: everyone gets everything 'cause they're all in monitor mode! probably should set them to something distinctive for debugging purposes 21 | -> WifiEncap(0x00, 0:0:0:0:0:0) // same applies here 22 | -> Unstrip(18) 23 | -> StoreData(0, DATA \<00 00 10 00 08 0c 08 00 3c 14 20 80 0c 24 | 00 03 00>) // radiotap header: same for all stations. may need to be updated later, but I think it's set to the way we want it (5180Mhz, MCS 3) 25 | -> output 26 | } 27 | 28 | elementclass ToMonitor 29 | { 30 | input -> Injectorizer -> Align(4, 0) -> ToDevice(mon0) 31 | } 32 | 33 | fromMonitor :: FromMonitor 34 | toMonitor :: ToMonitor 35 | 36 | #define $DOWNSTREAM_SOURCE fromMonitor 37 | #define $DOWNSTREAM_SINK toMonitor 38 | -------------------------------------------------------------------------------- /click/configs/ath9k-upstream.slickh: -------------------------------------------------------------------------------- 1 | // JaldiMAC Click configuration for upstream traffic from an ath9k monitor device 2 | 3 | // Defines $UPSTREAM_SOURCE and $UPSTREAM_SINK for ath9k monitor-mode devices. 4 | 5 | // ====================================================== 6 | // Component Graph 7 | // ====================================================== 8 | 9 | elementclass FromMonitor 10 | { 11 | FromDevice(mon0) 12 | -> RadiotapDecap() -> Strip(2) // we're using a custom radiotap header, so we need to strip 2 more bytes 13 | -> WifiDecap() 14 | -> Strip(14) // strip ethernet 15 | -> output 16 | } 17 | 18 | elementclass Injectorizer { 19 | input 20 | -> EtherEncap(0x9000, a1:a1:ff:a1:ff:ff, ff:ff:ff:0f:ff:ff) // note the address we put here doesn't matter: everyone gets everything 'cause they're all in monitor mode! probably should set them to something distinctive for debugging purposes 21 | -> WifiEncap(0x00, 0:0:0:0:0:0) // same applies here 22 | -> Unstrip(18) 23 | -> StoreData(0, DATA \<00 00 10 00 08 0c 08 00 3c 14 20 80 0c 24 | 00 03 00>) // radiotap header: same for all stations. may need to be updated later, but I think it's set to the way we want it (5180Mhz, MCS 3) 25 | -> output 26 | } 27 | 28 | elementclass ToMonitor 29 | { 30 | input -> Injectorizer -> Align(4, 0) -> ToDevice(mon0) 31 | } 32 | 33 | fromMonitor :: FromMonitor 34 | toMonitor :: ToMonitor 35 | 36 | #define $UPSTREAM_SOURCE fromMonitor 37 | #define $UPSTREAM_SINK toMonitor 38 | -------------------------------------------------------------------------------- /click/configs/generic-master.slickh: -------------------------------------------------------------------------------- 1 | // JaldiMAC Click configuration for the master 2 | 3 | // Before this file is included, $UPSTREAM_SOURCE, $UPSTREAM_SINK, 4 | // $DOWNSTREAM_SOURCE, and $DOWNSTREAM_SINK must be defined. 5 | 6 | // ====================================================== 7 | // Configuration 8 | // ====================================================== 9 | 10 | // Click port names 11 | #define $STATION_1_BULK 2 12 | #define $STATION_2_BULK 3 13 | #define $STATION_3_BULK 4 14 | #define $STATION_4_BULK 5 15 | 16 | // ====================================================== 17 | // Components 18 | // ====================================================== 19 | 20 | // Include shared components 21 | #include "shared.slickh" 22 | 23 | // Classifier 24 | elementclass MasterIPClassifier 25 | { 26 | // For now the number of stations is fixed to 4. 27 | ic :: IPClassifier(ip dscp 1, // Station 1 bulk 28 | ip dscp 2, // Station 1 VoIP 29 | ip dscp 3, // Station 2 bulk 30 | ip dscp 4, // Station 2 VoIP 31 | ip dscp 5, // Station 3 bulk 32 | ip dscp 6, // Station 3 VoIP 33 | ip dscp 7, // Station 4 bulk 34 | ip dscp 8, // Station 4 VoIP 35 | -) 36 | 37 | input -> ic 38 | ic[0] -> JaldiEncap(BULK_FRAME, $MASTER_ID, $STATION_1_ID) -> [$STATION_1_BULK]output 39 | ic[1] -> JaldiEncap(VOIP_FRAME, $MASTER_ID, $STATION_1_ID) -> [$ALL_VOIP]output 40 | ic[2] -> JaldiEncap(BULK_FRAME, $MASTER_ID, $STATION_2_ID) -> [$STATION_2_BULK]output 41 | ic[3] -> JaldiEncap(VOIP_FRAME, $MASTER_ID, $STATION_2_ID) -> [$ALL_VOIP]output 42 | ic[4] -> JaldiEncap(BULK_FRAME, $MASTER_ID, $STATION_3_ID) -> [$STATION_3_BULK]output 43 | ic[5] -> JaldiEncap(VOIP_FRAME, $MASTER_ID, $STATION_3_ID) -> [$ALL_VOIP]output 44 | ic[6] -> JaldiEncap(BULK_FRAME, $MASTER_ID, $STATION_4_ID) -> [$STATION_4_BULK]output 45 | ic[7] -> JaldiEncap(VOIP_FRAME, $MASTER_ID, $STATION_4_ID) -> [$ALL_VOIP]output 46 | ic[8] -> [$OUT]output 47 | } 48 | 49 | ipClassifier :: MasterIPClassifier 50 | 51 | // Encapsulation / decapsulation 52 | jaldiDecap :: JaldiDecap($MASTER_ID) 53 | 54 | // Scheduler and driver components 55 | scheduler :: JaldiScheduler 56 | driver :: JaldiFakeDriverPrecise 57 | 58 | // ====================================================== 59 | // Component Graph 60 | // ====================================================== 61 | 62 | // Handle incoming upstream traffic 63 | $UPSTREAM_SOURCE -> CheckIPHeader -> ipClassifier 64 | ipClassifier[$OUT] -> $UPSTREAM_SINK 65 | ipClassifier[$ALL_VOIP] -> JaldiQueue(2000) -> [$DRIVER_UPSTREAM_VOIP]driver 66 | ipClassifier[$STATION_1_BULK] -> JaldiQueue(2000) -> [$STATION_1_BULK]scheduler 67 | ipClassifier[$STATION_2_BULK] -> JaldiQueue(2000) -> [$STATION_2_BULK]scheduler 68 | ipClassifier[$STATION_3_BULK] -> JaldiQueue(2000) -> [$STATION_3_BULK]scheduler 69 | ipClassifier[$STATION_4_BULK] -> JaldiQueue(2000) -> [$STATION_4_BULK]scheduler 70 | 71 | // Handle incoming downstream traffic 72 | $DOWNSTREAM_SOURCE -> [$DRIVER_FROM_DOWNSTREAM]driver 73 | driver[$DRIVER_FROM_DOWNSTREAM] -> jaldiDecap 74 | jaldiDecap[$CONTROL] -> [$CONTROL]scheduler 75 | jaldiDecap[$DATA] -> ipClassifier 76 | 77 | // Plumbing for scheduler and driver 78 | InfiniteSource(DATA \<00>, LIMIT 1, BURST 1) -> JaldiEncap(ROUND_COMPLETE_MESSAGE, $DRIVER_ID, $MASTER_ID) -> [$ALT_CONTROL]scheduler 79 | scheduler -> JaldiQueue(2000) -> [$DRIVER_FROM_SCHEDULER]driver 80 | driver[$DRIVER_TO_DOWNSTREAM] -> JaldiQueue(2000) -> $DOWNSTREAM_SINK 81 | -------------------------------------------------------------------------------- /click/configs/generic-station.slickh: -------------------------------------------------------------------------------- 1 | // JaldiMAC Click configuration for the stations 2 | 3 | // ====================================================== 4 | // Components 5 | // ====================================================== 6 | 7 | // Include shared components 8 | #include "shared.slickh" 9 | 10 | // Classifiers 11 | elementclass StationIPClassifier 12 | { 13 | ic :: IPClassifier(ip dscp 2, // Station 1 VoIP 14 | ip dscp 4, // Station 2 VoIP 15 | ip dscp 6, // Station 3 VoIP 16 | ip dscp 8, // Station 4 VoIP 17 | -) // Everything else (bulk) 18 | 19 | input -> ic 20 | ic[0] -> [$ALL_VOIP]output 21 | ic[1] -> [$ALL_VOIP]output 22 | ic[2] -> [$ALL_VOIP]output 23 | ic[3] -> [$ALL_VOIP]output 24 | ic[4] -> [$OUT]output 25 | } 26 | 27 | ipClassifier :: StationIPClassifier 28 | voipDemux :: JaldiVoIPDemux(3) 29 | 30 | // Encapsulation / decapsulation 31 | elementclass ToJaldiAndQueue 32 | { 33 | $type, $size | 34 | input -> JaldiEncap($type, $STATION_ID, $MASTER_ID) 35 | -> JaldiQueue($size) -> output 36 | } 37 | 38 | jaldiDecap :: JaldiDecap($STATION_ID) 39 | 40 | // Gate 41 | gate :: JaldiGate($STATION_ID) 42 | 43 | // ====================================================== 44 | // Component Graph 45 | // ====================================================== 46 | 47 | // Handle incoming downstream traffic 48 | $DOWNSTREAM_SOURCE -> CheckIPHeader -> ipClassifier 49 | 50 | ipClassifier[$OUT] -> ToJaldiAndQueue(BULK_FRAME, 2000) -> [$BULK]gate 51 | ipClassifier[$ALL_VOIP] -> voipDemux 52 | 53 | // FIXME: Should really use a drop-front queue 54 | voipDemux[$VOIP_OUT_1] -> ToJaldiAndQueue(VOIP_FRAME, 10) -> [$VOIP_IN_1]gate 55 | voipDemux[$VOIP_OUT_2] -> ToJaldiAndQueue(VOIP_FRAME, 10) -> [$VOIP_IN_2]gate 56 | voipDemux[$VOIP_OUT_3] -> ToJaldiAndQueue(VOIP_FRAME, 10) -> [$VOIP_IN_3]gate 57 | voipDemux[$VOIP_OUT_4] -> ToJaldiAndQueue(VOIP_FRAME, 10) -> [$VOIP_IN_4]gate 58 | voipDemux[$VOIP_OUT_OVERFLOW] -> ToJaldiAndQueue(VOIP_FRAME, 10) -> [$VOIP_IN_OVERFLOW]gate 59 | 60 | gate -> JaldiQueue(2000) -> $UPSTREAM_SINK 61 | 62 | // Handle incoming upstream traffic 63 | $UPSTREAM_SOURCE -> jaldiDecap 64 | 65 | jaldiDecap[$DATA] -> $DOWNSTREAM_SINK 66 | jaldiDecap[$CONTROL] -> [$CONTROL]gate 67 | -------------------------------------------------------------------------------- /click/configs/master.slick: -------------------------------------------------------------------------------- 1 | // Master configuration 2 | #define $HOST_IP 10.3.3.2 3 | #define $HOST_IP_NETMASK 10.3.3.2/24 4 | #define $STATION_ID $MASTER_ID 5 | 6 | // Station configuration 7 | #define $STATION_1_IP 192.168.0.2 8 | #define $STATION_2_IP 192.168.0.3 9 | #define $STATION_3_IP 192.168.0.4 10 | #define $STATION_4_IP 192.168.0.5 11 | 12 | // Devices 13 | #include "tun-upstream.slickh" 14 | #include "ath9k-downstream.slickh" 15 | 16 | // Implementation 17 | #include "generic-master.slickh" 18 | -------------------------------------------------------------------------------- /click/configs/shared.slickh: -------------------------------------------------------------------------------- 1 | // Shared definitions for Jaldimac click configurations 2 | 3 | // $HOST_IP, $HOST_IP_NETMASK, and $STATION_ID must already be defined when 4 | // this file is included! 5 | // Examples: 6 | // #define $HOST_IP 10.0.0.1 7 | // #define $HOST_IP_NETMASK 10.0.0.1/24 8 | // #define $STATION_ID 1 9 | 10 | // ====================================================== 11 | // Required packages 12 | // ====================================================== 13 | require(package jaldi) 14 | 15 | // ====================================================== 16 | // Constants 17 | // ====================================================== 18 | 19 | // General network configuration 20 | #define $BULK_MTU 1500 21 | 22 | // Jaldi station IDs 23 | #define $DRIVER_ID 0 24 | #define $BROADCAST_ID 0 25 | #define $MASTER_ID 1 26 | #define $STATION_1_ID 2 27 | #define $STATION_2_ID 3 28 | #define $STATION_3_ID 4 29 | #define $STATION_4_ID 5 30 | 31 | // Click port names - this really needs to be redone but no time right now 32 | #define $CONTROL 0 33 | #define $BULK 1 34 | #define $VOIP 2 35 | 36 | #define $VOIP_IN_1 2 37 | #define $VOIP_IN_2 3 38 | #define $VOIP_IN_3 4 39 | #define $VOIP_IN_4 5 40 | #define $VOIP_IN_OVERFLOW 6 41 | 42 | #define $VOIP_OUT_1 0 43 | #define $VOIP_OUT_2 1 44 | #define $VOIP_OUT_3 2 45 | #define $VOIP_OUT_4 3 46 | #define $VOIP_OUT_OVERFLOW 4 47 | #define $VOIP_OUT_BAD 5 48 | 49 | #define $ALL_VOIP 1 50 | 51 | #define $ALT_CONTROL 1 52 | 53 | #define $DATA 1 54 | 55 | #define $OUT 0 56 | 57 | #define $ARP_REPLY 0 58 | #define $ARP_QUERY 1 59 | #define $IP 2 60 | #define $OTHER 3 61 | 62 | #define $INTERNAL 0 63 | #define $HOST 1 64 | 65 | #define $DRIVER_FROM_DOWNSTREAM 0 66 | #define $DRIVER_FROM_SCHEDULER 1 67 | #define $DRIVER_UPSTREAM_VOIP 2 68 | #define $DRIVER_TO_DOWNSTREAM 1 69 | 70 | // ====================================================== 71 | // Components 72 | // ====================================================== 73 | 74 | // Since we've switched to using tun interfaces we don't need to deal with 75 | // Ethernet, but for now we can keep these elementclasses around in case they 76 | // become useful again. 77 | /* 78 | elementclass EthernetToIP 79 | { 80 | input -> Strip(14) // Remove Ethernet header 81 | -> CheckIPHeader // Check for legality and annotate 82 | -> output 83 | } 84 | 85 | elementclass IPToEthernet 86 | { 87 | aq :: ARPQuerier($HOST_IP, $HOST_MAC 88 | input[$DATA] -> DecIPTTL -> ipf :: IPFragmenter($MTU) 89 | ipf -> [$DATA]aq -> output // Frames and ARP queries go to output 90 | input[$ARP_REPLY] -> [$ARP_REPLY]aq // ARP responses come in via input[$ARP-REPLY] 91 | } 92 | 93 | elementclass EthernetClassifier 94 | { 95 | c :: Classifier(12/0806 20/0001, // ARP queries 96 | 12/0806 20/0002, // ARP responses 97 | 12/0800, // IP packets 98 | -); // Other 99 | 100 | // This is defined in a verbose manner to clearly denote 101 | // the names associated with each port. 102 | input -> c 103 | c[$ARP_QUERY] -> [$ARP_QUERY]output 104 | c[$ARP_REPLY] -> [$ARP_REPLY]output 105 | c[$IP] -> [$IP]output 106 | c[$OTHER] -> [$OTHER]output 107 | } 108 | 109 | // Proxy ARP 110 | elementclass ProxyARP 111 | { 112 | input -> ARPResponder($PROXY_ARP_NETWORK $HOST_MAC) -> output 113 | } 114 | */ 115 | -------------------------------------------------------------------------------- /click/configs/station-1.slick: -------------------------------------------------------------------------------- 1 | // Station configuration 2 | #define $HOST_IP 10.3.3.3 3 | #define $HOST_IP_NETMASK 10.3.3.3/24 4 | #define $STATION_ID 1 5 | 6 | // Devices 7 | #include "tun-downstream.slickh" 8 | #include "ath9k-upstream.slickh" 9 | 10 | // Implementation 11 | #include "generic-station.slickh" 12 | -------------------------------------------------------------------------------- /click/configs/station-2.slick: -------------------------------------------------------------------------------- 1 | // Station configuration 2 | #define $HOST_IP 10.3.3.4 3 | #define $HOST_IP_NETMASK 10.3.3.4/24 4 | #define $STATION_ID 2 5 | 6 | // Devices 7 | #include "tun-downstream.slickh" 8 | #include "ath9k-upstream.slickh" 9 | 10 | // Implementation 11 | #include "generic-station.slickh" 12 | -------------------------------------------------------------------------------- /click/configs/station-3.slick: -------------------------------------------------------------------------------- 1 | // Station configuration 2 | #define $HOST_IP 10.3.3.5 3 | #define $HOST_IP_NETMASK 10.3.3.5/24 4 | #define $STATION_ID 3 5 | 6 | // Devices 7 | #include "tun-downstream.slickh" 8 | #include "ath9k-upstream.slickh" 9 | 10 | // Implementation 11 | #include "generic-station.slickh" 12 | -------------------------------------------------------------------------------- /click/configs/station-4.slick: -------------------------------------------------------------------------------- 1 | // Station configuration 2 | #define $HOST_IP 10.3.3.6 3 | #define $HOST_IP_NETMASK 10.3.3.6/24 4 | #define $STATION_ID 4 5 | 6 | // Devices 7 | #include "tun-downstream.slickh" 8 | #include "ath9k-upstream.slickh" 9 | 10 | // Implementation 11 | #include "generic-station.slickh" 12 | -------------------------------------------------------------------------------- /click/configs/test-demux.slick: -------------------------------------------------------------------------------- 1 | #include "shared.slickh" 2 | 3 | voipDemux :: JaldiVoIPDemux(3) 4 | 5 | InfiniteSource(DATA \<450000 54 000040004001b45e c0a80201 c0a802f9 080084710547000d 9694d7a500000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000>, LIMIT 1, BURST 1, STOP true) 6 | -> CheckIPHeader 7 | -> Print 8 | -> voipDemux 9 | 10 | voipDemux[$VOIP_OUT_1] -> Print(Output1) -> Discard 11 | voipDemux[$VOIP_OUT_2] -> Print(Output2) -> Discard 12 | voipDemux[$VOIP_OUT_3] -> Print(Output3) -> Discard 13 | voipDemux[$VOIP_OUT_4] -> Print(Output4) -> Discard 14 | voipDemux[$VOIP_OUT_OVERFLOW] -> Print(OverflowOutput) -> Discard 15 | voipDemux[$VOIP_OUT_BAD] -> Print(BadOutput) -> Discard 16 | -------------------------------------------------------------------------------- /click/configs/test-encap.slick: -------------------------------------------------------------------------------- 1 | #include "shared.slickh" 2 | 3 | jd :: JaldiDecap 4 | 5 | InfiniteSource(DATA \<0000>, LIMIT 1, BURST 1, STOP true) 6 | -> Print 7 | -> JaldiEncap(BULK_FRAME, $DRIVER_ID, $MASTER_ID) 8 | -> JaldiPrint(true) 9 | -> jd 10 | 11 | jd[0] -> Print(Control, 1600) -> Discard 12 | 13 | jd[1] -> Print(IP, 1600) -> Discard 14 | 15 | jd[2] -> Print(Bad, 1600) -> Discard 16 | -------------------------------------------------------------------------------- /click/configs/test-gate.slick: -------------------------------------------------------------------------------- 1 | #include "shared.slickh" 2 | 3 | voipDemux :: JaldiVoIPDemux(3) 4 | jaldiGate :: JaldiGate(2) 5 | 6 | InfiniteSource(DATA \<00>, LIMIT 100, BURST 1, STOP true) 7 | -> UDPIPEncap(192.168.0.1, 5555, 192.168.0.2, 6666) 8 | -> CheckIPHeader 9 | -> Print 10 | -> voipDemux 11 | 12 | voipDemux[$VOIP_OUT_1] -> Print(Output1) -> JaldiEncap(VOIP_FRAME, 2, 1) -> JaldiQueue(10) -> [2]jaldiGate 13 | voipDemux[$VOIP_OUT_2] -> Print(Output2) -> JaldiEncap(VOIP_FRAME, 2, 1) -> JaldiQueue(10) -> [3]jaldiGate 14 | voipDemux[$VOIP_OUT_3] -> Print(Output3) -> JaldiEncap(VOIP_FRAME, 2, 1) -> JaldiQueue(10) -> [4]jaldiGate 15 | voipDemux[$VOIP_OUT_4] -> Print(Output4) -> JaldiEncap(VOIP_FRAME, 2, 1) -> JaldiQueue(10) -> [5]jaldiGate 16 | voipDemux[$VOIP_OUT_OVERFLOW] -> Print(OverflowOutput) -> JaldiEncap(VOIP_FRAME, 2, 1) -> JaldiQueue(10) -> [6]jaldiGate 17 | voipDemux[$VOIP_OUT_BAD] -> Print(BadOutput) -> Discard 18 | 19 | InfiniteSource(DATA \<00>, LIMIT 100, BURST 1, STOP false) 20 | -> IPEncap(6, 192.168.0.1, 192.168.0.2) 21 | -> CheckIPHeader 22 | -> Print 23 | -> JaldiEncap(BULK_FRAME, 2, 1) 24 | -> JaldiQueue(2000) 25 | -> [1]jaldiGate 26 | 27 | 28 | /* 29 | InfiniteSource(DATA \, LIMIT 100, BURST 1, STOP false) 30 | -> JaldiEncap(TRANSMIT_SLOT, 1, 2) 31 | -> JaldiPrint 32 | -> [0]jaldiGate 33 | */ 34 | 35 | /* 36 | InfiniteSource(DATA \, LIMIT 100, BURST 1, STOP false) 37 | -> JaldiEncap(CONTENTION_SLOT, 1, 2) 38 | -> JaldiPrint 39 | -> [0]jaldiGate 40 | */ 41 | 42 | InfiniteSource(DATA \, LIMIT 100, BURST 1, STOP false) 43 | -> JaldiEncap(VOIP_SLOT, 1, 2) 44 | -> JaldiPrint 45 | -> [0]jaldiGate 46 | 47 | jaldiGate -> JaldiPrint -> Discard 48 | -------------------------------------------------------------------------------- /click/configs/test-sched.slick: -------------------------------------------------------------------------------- 1 | #include "shared.slickh" 2 | 3 | sched :: JaldiScheduler 4 | 5 | elementclass BulkGen 6 | { 7 | InfiniteSource(DATA \<00>, LIMIT 1, BURST 1, STOP false) 8 | -> IPEncap(6, 192.168.0.1, 192.168.0.2) 9 | -> CheckIPHeader 10 | -> JaldiEncap(BULK_FRAME, 1, 2) 11 | -> output 12 | } 13 | 14 | elementclass RCMGen 15 | { 16 | $limit | 17 | InfiniteSource(DATA \<00>, LIMIT $limit, BURST 1, STOP false) 18 | -> JaldiEncap(ROUND_COMPLETE_MESSAGE, 0, 1) 19 | -> JaldiPrint 20 | -> output 21 | } 22 | 23 | RCMGen(0) -> [0]sched 24 | RCMGen(1) -> [1]sched 25 | BulkGen -> Print(Bulk1) -> JaldiQueue(2000) -> [2]sched 26 | BulkGen -> Print(Bulk2) -> JaldiQueue(2000) -> [3]sched 27 | BulkGen -> Print(Bulk3) -> JaldiQueue(2000) -> [4]sched 28 | BulkGen -> Print(Bulk4) -> JaldiQueue(2000) -> [5]sched 29 | 30 | sched -> JaldiPrint -> Discard 31 | -------------------------------------------------------------------------------- /click/configs/tun-downstream.slickh: -------------------------------------------------------------------------------- 1 | // JaldiMAC Click configuration for downstream traffic from a tun device 2 | 3 | // Defines $DOWNSTREAM_SOURCE and $DOWNSTREAM_SINK for tun devices. 4 | // $HOST_IP_NETMASK must be defined before this file is included. 5 | 6 | // ====================================================== 7 | // Component Graph 8 | // ====================================================== 9 | 10 | AddressInfo(tun0 $HOST_IP_NETMASK) 11 | tunDevice :: KernelTun(tun0) 12 | 13 | #define $DOWNSTREAM_SOURCE tunDevice 14 | #define $DOWNSTREAM_SINK tunDevice 15 | -------------------------------------------------------------------------------- /click/configs/tun-upstream.slickh: -------------------------------------------------------------------------------- 1 | // JaldiMAC Click configuration for upstream traffic from a tun device 2 | 3 | // Defines $UPSTREAM_SOURCE and $UPSTREAM_SINK for tun devices. 4 | // $HOST_IP_NETMASK must be defined before this file is included. 5 | 6 | // ====================================================== 7 | // Component Graph 8 | // ====================================================== 9 | 10 | AddressInfo(tun0 $HOST_IP_NETMASK) 11 | tunDevice :: KernelTun(tun0) 12 | 13 | #define $UPSTREAM_SOURCE tunDevice 14 | #define $UPSTREAM_SINK tunDevice 15 | -------------------------------------------------------------------------------- /click/dist/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaddi/jaldimac/5d545828645248447846cf4f97a534cbe603a85a/click/dist/.gitignore -------------------------------------------------------------------------------- /click/elements/Frame.cc: -------------------------------------------------------------------------------- 1 | ../../shared/Frame.cc -------------------------------------------------------------------------------- /click/elements/Frame.hh: -------------------------------------------------------------------------------- 1 | ../../shared/Frame.hh -------------------------------------------------------------------------------- /click/elements/JaldiClick.hh: -------------------------------------------------------------------------------- 1 | #ifndef JALDI_CLICK_HH 2 | #define JALDI_CLICK_HH 3 | 4 | #include 5 | #include "Frame.hh" 6 | 7 | template 8 | WritablePacket* make_jaldi_frame(uint8_t src_id, PayloadType*& payload_out) 9 | { 10 | WritablePacket* wp = Packet::make(jaldimac::Frame::empty_frame_size + sizeof(PayloadType)); 11 | jaldimac::Frame* f = (jaldimac::Frame*) wp->data(); 12 | f->initialize(); 13 | f->type = FrameType; 14 | f->src_id = src_id; 15 | f->dest_id = DestId; 16 | f->length = jaldimac::Frame::empty_frame_size + sizeof(PayloadType); 17 | payload_out = (PayloadType*) f->payload; 18 | return wp; 19 | } 20 | 21 | template 22 | WritablePacket* make_jaldi_frame_dyn_dest(uint8_t src_id, uint8_t dest_id, PayloadType*& payload_out) 23 | { 24 | WritablePacket* wp = Packet::make(jaldimac::Frame::empty_frame_size + sizeof(PayloadType)); 25 | jaldimac::Frame* f = (jaldimac::Frame*) wp->data(); 26 | f->initialize(); 27 | f->type = FrameType; 28 | f->src_id = src_id; 29 | f->dest_id = dest_id; 30 | f->length = jaldimac::Frame::empty_frame_size + sizeof(PayloadType); 31 | payload_out = (PayloadType*) f->payload; 32 | return wp; 33 | } 34 | 35 | 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /click/elements/JaldiDecap.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * JaldiDecap.{cc,hh} -- decapsulates Jaldi frame 3 | */ 4 | 5 | #include 6 | #include "JaldiDecap.hh" 7 | #include 8 | #include 9 | #include 10 | #include "Frame.hh" 11 | 12 | using namespace jaldimac; 13 | 14 | CLICK_DECLS 15 | 16 | JaldiDecap::JaldiDecap() 17 | { 18 | } 19 | 20 | JaldiDecap::~JaldiDecap() 21 | { 22 | } 23 | 24 | int JaldiDecap::configure(Vector& conf, ErrorHandler* errh) 25 | { 26 | // Parse configuration parameters 27 | if (cp_va_kparse(conf, this, errh, 28 | "DEST", cpkP+cpkC, &should_filter_by_dest, cpByte, &dest_id, 29 | cpEnd) < 0) 30 | return -1; 31 | else 32 | return 0; 33 | } 34 | 35 | void JaldiDecap::push(int, Packet* p) 36 | { 37 | // Treat the packet as a Frame 38 | const Frame* f = (const Frame*) p->data(); 39 | 40 | // Filter by dest_id if requested 41 | if (should_filter_by_dest && !(f->dest_id == BROADCAST_ID || f->dest_id == dest_id)) 42 | checked_output_push(out_port_bad, p); 43 | 44 | // Classify the packet (Control, Data, or Bad)? 45 | switch (f->type) 46 | { 47 | case BULK_FRAME: 48 | case VOIP_FRAME: 49 | // Strip Jaldi header and footer 50 | p->pull(Frame::header_size); 51 | p->take(Frame::footer_size); 52 | output(out_port_data).push(p); 53 | break; 54 | 55 | case REQUEST_FRAME: 56 | case CONTENTION_SLOT: 57 | case VOIP_SLOT: 58 | case TRANSMIT_SLOT: 59 | case BITRATE_MESSAGE: 60 | case ROUND_COMPLETE_MESSAGE: 61 | case DELAY_MESSAGE: 62 | output(out_port_control).push(p); 63 | break; 64 | 65 | default: 66 | checked_output_push(out_port_bad, p); 67 | break; 68 | } 69 | } 70 | 71 | CLICK_ENDDECLS 72 | ELEMENT_REQUIRES(Frame) 73 | EXPORT_ELEMENT(JaldiDecap) 74 | -------------------------------------------------------------------------------- /click/elements/JaldiDecap.hh: -------------------------------------------------------------------------------- 1 | #ifndef CLICK_JALDIDECAP_HH 2 | #define CLICK_JALDIDECAP_HH 3 | #include 4 | CLICK_DECLS 5 | 6 | /* 7 | =c 8 | 9 | JaldiDecap(DEST) 10 | 11 | =s jaldi 12 | 13 | decapsulates packets which are wrapped in a Jaldi header 14 | 15 | =d 16 | 17 | Decapsulates Jaldi frames into IP packets. Jaldi control messages, for which 18 | decapsulation is not meaningful, are placed on output 0. IP packets are placed 19 | on output 1. Jaldi frames which could not be decapsulated for whatever reason 20 | (for example, they have an invalid type, or they failed the CRC check) are 21 | placed on output 2 if that output is connected. 22 | 23 | DEST an optional parameter which specifies the destination station id we are 24 | interested in. If DEST is not supplied, JaldiDecap will decapsulate all incoming 25 | Jaldi frames. If DEST is supplied, JaldiDecap will only decapsulate incoming 26 | Jaldi frames which are either destined for station DEST, or are destined for 27 | station 0 (broadcast). Frames which are not decapsulated because of these rules 28 | are placed on output 2 if that output is connected. 29 | 30 | This element is push only. 31 | 32 | =a 33 | 34 | JaldiEncap */ 35 | 36 | class JaldiDecap : public Element { public: 37 | 38 | JaldiDecap(); 39 | ~JaldiDecap(); 40 | 41 | const char* class_name() const { return "JaldiDecap"; } 42 | const char* port_count() const { return "1/2-3"; } 43 | const char* processing() const { return PUSH; } 44 | const char* flow_code() const { return COMPLETE_FLOW; } 45 | 46 | int configure(Vector&, ErrorHandler*); 47 | bool can_live_reconfigure() const { return true; } 48 | 49 | void push(int, Packet*); 50 | 51 | private: 52 | static const int in_port = 0; 53 | static const int out_port_control = 0; 54 | static const int out_port_data = 1; 55 | static const int out_port_bad = 2; 56 | 57 | bool should_filter_by_dest; 58 | uint8_t dest_id; 59 | }; 60 | 61 | CLICK_ENDDECLS 62 | #endif 63 | -------------------------------------------------------------------------------- /click/elements/JaldiEncap.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * JaldiEncap.{cc,hh} -- encapsulates packet in Jaldi header 3 | */ 4 | 5 | #define __STDC_LIMIT_MACROS 6 | #include 7 | #include 8 | #include "JaldiEncap.hh" 9 | #include 10 | #include 11 | #include 12 | #include "Frame.hh" 13 | 14 | using namespace jaldimac; 15 | 16 | CLICK_DECLS 17 | 18 | JaldiEncap::JaldiEncap() 19 | { 20 | } 21 | 22 | JaldiEncap::~JaldiEncap() 23 | { 24 | } 25 | 26 | int JaldiEncap::configure(Vector& conf, ErrorHandler* errh) 27 | { 28 | String name_of_type; 29 | 30 | // Parse configuration parameters 31 | if (cp_va_kparse(conf, this, errh, 32 | "TYPE", cpkP+cpkM, cpString, &name_of_type, 33 | "SRC", cpkP+cpkM, cpByte, &src_id, 34 | "DEST", cpkP+cpkM, cpByte, &dest_id, 35 | cpEnd) < 0) 36 | return -1; 37 | 38 | // Convert TYPE field from a string to the appropriate code 39 | if (name_of_type.equals("BULK_FRAME", -1)) 40 | type = BULK_FRAME; 41 | else if (name_of_type.equals("VOIP_FRAME", -1)) 42 | type = VOIP_FRAME; 43 | else if (name_of_type.equals("REQUEST_FRAME", -1)) 44 | type = REQUEST_FRAME; 45 | else if (name_of_type.equals("CONTENTION_SLOT", -1)) 46 | type = CONTENTION_SLOT; 47 | else if (name_of_type.equals("VOIP_SLOT", -1)) 48 | type = VOIP_SLOT; 49 | else if (name_of_type.equals("TRANSMIT_SLOT", -1)) 50 | type = TRANSMIT_SLOT; 51 | else if (name_of_type.equals("BITRATE_MESSAGE", -1)) 52 | type = BITRATE_MESSAGE; 53 | else if (name_of_type.equals("ROUND_COMPLETE_MESSAGE", -1)) 54 | type = ROUND_COMPLETE_MESSAGE; 55 | else if (name_of_type.equals("DELAY_MESSAGE", -1)) 56 | type = DELAY_MESSAGE; 57 | else 58 | { 59 | errh->error("invalid Jaldi frame type: %s", name_of_type.c_str()); 60 | return -1; 61 | } 62 | 63 | // Initialize the sequence number to 0 64 | seq = 0; 65 | 66 | return 0; 67 | } 68 | 69 | void JaldiEncap::take_state(Element* old, ErrorHandler*) 70 | { 71 | JaldiEncap* oldJE = (JaldiEncap*) old->cast("JaldiEncap"); 72 | 73 | if (oldJE) 74 | seq = oldJE->seq; 75 | } 76 | 77 | Packet* JaldiEncap::action(Packet* p) 78 | { 79 | // Remember the "real" length of this packet 80 | uint32_t length = p->length(); 81 | 82 | // If the packet's too long, kill it 83 | if (length > UINT32_MAX) 84 | { 85 | checked_output_push(out_port_bad, p); 86 | return NULL; 87 | } 88 | 89 | // Add space for Jaldi frame header and footer to packet 90 | WritablePacket* p0 = p->push(Frame::header_size); 91 | WritablePacket* p1 = p0->put(Frame::footer_size); 92 | 93 | // Create header 94 | Frame* f = (Frame*) p1->data(); 95 | f->initialize(); 96 | f->dest_id = dest_id; 97 | f->src_id = src_id; 98 | f->type = type; 99 | f->length = Frame::empty_frame_size + length; 100 | f->seq = seq++; 101 | 102 | // Return the final encapsulated packet 103 | return p1; 104 | } 105 | 106 | void JaldiEncap::push(int, Packet* p) 107 | { 108 | if (Packet* q = action(p)) 109 | output(out_port).push(q); 110 | } 111 | 112 | Packet* JaldiEncap::pull(int) 113 | { 114 | if (Packet *p = input(in_port).pull()) 115 | return action(p); 116 | else 117 | return NULL; 118 | } 119 | 120 | CLICK_ENDDECLS 121 | ELEMENT_REQUIRES(Frame) 122 | EXPORT_ELEMENT(JaldiEncap) 123 | -------------------------------------------------------------------------------- /click/elements/JaldiEncap.hh: -------------------------------------------------------------------------------- 1 | #ifndef CLICK_JALDIENCAP_HH 2 | #define CLICK_JALDIENCAP_HH 3 | #include 4 | CLICK_DECLS 5 | 6 | /* 7 | =c 8 | 9 | JaldiEncap(TYPE, SRC, DEST) 10 | 11 | =s jaldi 12 | 13 | encapsulates packets in Jaldi header 14 | 15 | =d 16 | 17 | Encapsulates each packet in the Jaldi header specified by its arguments. 18 | 19 | TYPE may be one of: BULK_FRAME, VOIP_FRAME, REQUEST_FRAME, CONTENTION_SLOT, 20 | VOIP_SLOT, TRANSMIT_SLOT, ROUND_COMPLETE_MESSAGE, DELAY_MESSAGE, or 21 | BITRATE_MESSAGE. 22 | 23 | SRC is the station identifier of the sending station. 24 | 25 | DEST is the station identifier of the station the Jaldi frame is intended for. 26 | 27 | Successfully encapsulated packets are sent to the first output (output 0). 28 | Certain erroneous packets may be dropped by JaldiEncap - in particular, packets 29 | which have a size larger than the limit of the Jaldi frame length field will be 30 | dropped. If the second output (output 1) is connected, such packets will be 31 | sent there instead of being dropped. Although the first input and first 32 | output are agnostic, the second output is always push. 33 | 34 | =e 35 | 36 | Encapsulate packets in a Jaldi header with type BULK_FRAME, 37 | destination station 2: 38 | 39 | JaldiEncap(BULK_FRAME, 2) 40 | 41 | =a 42 | 43 | JaldiDecap */ 44 | 45 | class JaldiEncap : public Element { public: 46 | 47 | JaldiEncap(); 48 | ~JaldiEncap(); 49 | 50 | const char* class_name() const { return "JaldiEncap"; } 51 | const char* port_count() const { return "1/1-2"; } 52 | const char* processing() const { return PROCESSING_A_AH; } 53 | const char* flow_code() const { return COMPLETE_FLOW; } 54 | 55 | int configure(Vector&, ErrorHandler*); 56 | bool can_live_reconfigure() const { return true; } 57 | void take_state(Element*, ErrorHandler*); 58 | 59 | Packet* action(Packet* p); 60 | void push(int, Packet*); 61 | Packet* pull(int); 62 | 63 | private: 64 | static const int in_port = 0; 65 | static const int out_port = 0; 66 | static const int out_port_bad = 1; 67 | 68 | uint8_t src_id; 69 | uint8_t dest_id; 70 | uint8_t type; 71 | uint32_t seq; 72 | 73 | }; 74 | 75 | CLICK_ENDDECLS 76 | #endif 77 | -------------------------------------------------------------------------------- /click/elements/JaldiFakeDriver.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * JaldiFakeDriver.{cc,hh} -- simulates the behavior of the JaldiMAC kernel driver for use with other drivers 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "JaldiClick.hh" 13 | #include "JaldiQueue.hh" 14 | #include "JaldiFakeDriver.hh" 15 | 16 | using namespace jaldimac; 17 | 18 | CLICK_DECLS 19 | 20 | JaldiFakeDriver::JaldiFakeDriver() : timer(this), max_frames_per_trigger(1), 21 | voip_queue_connected(false), 22 | scheduled_queue(NULL), voip_queue(NULL) 23 | { 24 | } 25 | 26 | JaldiFakeDriver::~JaldiFakeDriver() 27 | { 28 | } 29 | 30 | int JaldiFakeDriver::configure(Vector& conf, ErrorHandler* errh) 31 | { 32 | // Parse configuration parameters 33 | if (cp_va_kparse(conf, this, errh, 34 | "FRAMES", cpkP+cpkM, cpUnsigned, &max_frames_per_trigger, 35 | cpEnd) < 0) 36 | return -1; 37 | 38 | // Record input port configuration 39 | if (ninputs() == 2) 40 | voip_queue_connected = false; 41 | 42 | return 0; 43 | } 44 | 45 | int JaldiFakeDriver::initialize(ErrorHandler* errh) 46 | { 47 | // Find the nearest upstream scheduled frame queue 48 | ElementCastTracker filter(router(), "JaldiQueue"); 49 | 50 | if (router()->visit_upstream(this, in_port_scheduled, &filter) < 0 || filter.size() == 0) 51 | return errh->error("couldn't find an upstream scheduled frame JaldiQueue on input port %<%d%> using flow-based router context", in_port_scheduled); 52 | 53 | if (! (scheduled_queue = (JaldiQueue*) filter[0]->cast("JaldiQueue"))) 54 | return errh->error("scheduled frame queue %<%s%> on input port %<%d%> is not a valid JaldiQueue (cast failed)", filter[0]->name().c_str(), in_port_scheduled); 55 | 56 | if (voip_queue_connected) 57 | { 58 | // Find the nearest upstream VoIP queue 59 | filter.clear(); 60 | 61 | if (router()->visit_upstream(this, in_port_upstream_voip, &filter) < 0 || filter.size() == 0) 62 | return errh->error("couldn't find an upstream VoIP JaldiQueue on input port %<%d%> using flow-based router context", in_port_upstream_voip); 63 | 64 | if (! (voip_queue = (JaldiQueue*) filter[0]->cast("JaldiQueue"))) 65 | return errh->error("VoIP queue %<%s%> on input port %<%d%> is not a valid JaldiQueue (cast failed)", filter[0]->name().c_str(), in_port_upstream_voip); 66 | } 67 | 68 | // Initialize timer 69 | timer.initialize(this); 70 | timer.schedule_now(); 71 | 72 | // Success! 73 | return 0; 74 | } 75 | 76 | void JaldiFakeDriver::push(int, Packet* p) 77 | { 78 | // Got a message from downstream (the stations); push it to the master. 79 | output(out_port_to_master).push(p); 80 | } 81 | 82 | void JaldiFakeDriver::run_timer(Timer*) 83 | { 84 | // Pull scheduled frames 85 | unsigned pulled_frames = 0; 86 | while (pulled_frames < max_frames_per_trigger) 87 | { 88 | Packet* p = input(in_port_scheduled).pull(); 89 | ++pulled_frames; 90 | 91 | if (p == NULL) 92 | break; 93 | 94 | // Got a Jaldi frame from the scheduler; decode it to decide what to do. 95 | const Frame* f = (const Frame*) p->data(); 96 | 97 | switch (f->type) 98 | { 99 | case BULK_FRAME: 100 | case VOIP_FRAME: 101 | case REQUEST_FRAME: 102 | { 103 | // Transmit a VoIP frame from upstream if one is waiting. 104 | if (voip_queue_connected) 105 | { 106 | Packet* vp = input(in_port_upstream_voip).pull(); 107 | 108 | if (vp) 109 | { 110 | ++pulled_frames; 111 | output(out_port_to_stations).push(vp); 112 | } 113 | } 114 | 115 | // Transmit the scheduled frame. 116 | output(out_port_to_stations).push(p); 117 | 118 | break; 119 | } 120 | 121 | case CONTENTION_SLOT: 122 | { 123 | // Convert duration to milliseconds. 124 | const ContentionSlotPayload* csp = (const ContentionSlotPayload*) f->payload; 125 | uint32_t duration_ms = csp->duration_us / 1000; 126 | 127 | if (duration_ms < 1) 128 | duration_ms = 1; 129 | 130 | // Let the master know that the round is complete. 131 | RoundCompleteMessagePayload* rcmp; 132 | WritablePacket* rcp = make_jaldi_frame(DRIVER_ID, rcmp); 133 | output(out_port_to_master).push(rcp); 134 | 135 | // Announce the contention slot. 136 | output(out_port_to_stations).push(p); 137 | 138 | // Wait until it's over. (as best we can with this timer resolution) 139 | timer.reschedule_after_msec(duration_ms); 140 | 141 | return; 142 | } 143 | 144 | case VOIP_SLOT: 145 | { 146 | // Convert duration to milliseconds. 147 | const VoIPSlotPayload* vsp = (const VoIPSlotPayload*) f->payload; 148 | uint32_t duration_ms = vsp->duration_us / 1000; 149 | 150 | if (duration_ms < 1) 151 | duration_ms = 1; 152 | 153 | // Announce the VoIP slot. 154 | output(out_port_to_stations).push(p); 155 | 156 | // Wait until it's over. (as best we can with this timer resolution) 157 | timer.reschedule_after_msec(duration_ms); 158 | 159 | return; 160 | } 161 | 162 | case TRANSMIT_SLOT: 163 | { 164 | // Convert duration to milliseconds. 165 | const TransmitSlotPayload* tsp = (const TransmitSlotPayload*) f->payload; 166 | uint32_t duration_ms = tsp->duration_us / 1000; 167 | 168 | if (duration_ms < 1) 169 | duration_ms = 1; 170 | 171 | // Announce the transmit slot. 172 | output(out_port_to_stations).push(p); 173 | 174 | // Wait until it's over. (as best we can with this timer resolution) 175 | timer.reschedule_after_msec(duration_ms); 176 | 177 | return; 178 | } 179 | 180 | case BITRATE_MESSAGE: 181 | { 182 | // This isn't implemented. 183 | click_chatter("%s: BITRATE_MESSAGE is unsupported\n", declaration().c_str()); 184 | p->kill(); 185 | break; 186 | } 187 | 188 | case ROUND_COMPLETE_MESSAGE: 189 | { 190 | // This isn't meant to be broadcast. 191 | p->kill(); 192 | break; 193 | } 194 | 195 | case DELAY_MESSAGE: 196 | { 197 | // Convert duration to milliseconds. 198 | const DelayMessagePayload* tsp = (const DelayMessagePayload*) f->payload; 199 | uint32_t duration_ms = tsp->duration_us / 1000; 200 | 201 | if (duration_ms < 1) 202 | duration_ms = 1; 203 | 204 | // Delays aren't meant to be broadcast, so kill this frame. 205 | p->kill(); 206 | 207 | // Wait until it's over. (as best we can with this timer resolution) 208 | timer.reschedule_after_msec(duration_ms); 209 | 210 | return; 211 | } 212 | 213 | default: 214 | { 215 | // Bad stuff; dump it out the optional output 216 | checked_output_push(out_port_bad, p); 217 | break; 218 | } 219 | } 220 | } 221 | 222 | // We've pulled all of the frames we're allowed to until the timer is 223 | // triggered again, so reschedule and return. 224 | timer.reschedule_after_msec(timer_period_ms); 225 | } 226 | 227 | CLICK_ENDDECLS 228 | ELEMENT_REQUIRES(Frame) 229 | EXPORT_ELEMENT(JaldiFakeDriver) 230 | -------------------------------------------------------------------------------- /click/elements/JaldiFakeDriver.hh: -------------------------------------------------------------------------------- 1 | #ifndef CLICK_JALDIFAKEDRIVER_HH 2 | #define CLICK_JALDIFAKEDRIVER_HH 3 | #include 4 | #include 5 | CLICK_DECLS 6 | 7 | /* 8 | =c 9 | 10 | JaldiFakeDriver(FRAMES) 11 | 12 | =s jaldi 13 | 14 | simulates the behavior of the JaldiMAC kernel driver for use with other drivers 15 | 16 | =d 17 | 18 | JaldiFakeDriver sits between the JaldiScheduler and a non-JaldiMAC kernel 19 | driver that does not support the notifications and timers that the JaldiMAC 20 | kernel driver makes available. It simulates these behaviors in Click. 21 | 22 | Because of a recent design change, JaldiFakeDriver also has an additional 23 | responsibility - it dynamically inserts VoIP frames destined for the stations 24 | from upstream into its output. This may have the effect of making the resulting 25 | round longer than the nominal maximum round size, or slightly changing the 26 | distance between VoIP slots, but under normal traffic conditions these effects 27 | should be minimal, and this is the best way we have to simulate real dynamic 28 | scheduling of VoIP from upstream under the deadline constraints we have. 29 | 30 | FRAMES is the maximum number of frames that JaldiFakeDriver will process each 31 | time it is trigger. This should be set large enough that we get reasonable 32 | performance (since JaldiFakeDriver only runs once per millisecond) but small 33 | enough that other timers and periodic events get a chance to run. 34 | 35 | JaldiFakeDriver's first input (push) receives traffic from downstream (the 36 | stations) and passes it along on its first output (push) unchanged. Input 1 37 | (pull) receives the output of a JaldiScheduler element. Input 2 (pull) receives 38 | upstream VoIP traffic if it is connected. Everything arriving on all inputs 39 | should be encapsulated in Jaldi frames, and both pull inputs should be 40 | connected to a JaldiQueue. 41 | 42 | There are two push outputs; the first is for traffic from downstream (the 43 | stations) to the master, and the second is for scheduled traffic being sent to 44 | the stations. A third push output may be connected to receive erroneous 45 | packets. 46 | 47 | =a 48 | 49 | JaldiScheduler, JaldiFakeDriverPrecise */ 50 | 51 | class JaldiQueue; 52 | 53 | class JaldiFakeDriver : public Element { public: 54 | 55 | JaldiFakeDriver(); 56 | ~JaldiFakeDriver(); 57 | 58 | const char* class_name() const { return "JaldiFakeDriver"; } 59 | const char* port_count() const { return "2-3/2-3"; } 60 | const char* processing() const { return "hl/h"; } 61 | const char* flow_code() const { return COMPLETE_FLOW; } 62 | 63 | int configure(Vector&, ErrorHandler*); 64 | int initialize(ErrorHandler*); 65 | bool can_live_reconfigure() const { return true; } 66 | 67 | void push(int, Packet*); 68 | void run_timer(Timer*); 69 | 70 | private: 71 | static const int in_port_from_stations = 0; 72 | static const int in_port_scheduled = 1; 73 | static const int in_port_upstream_voip = 2; 74 | static const int out_port_to_master = 0; 75 | static const int out_port_to_stations = 1; 76 | static const int out_port_bad = 1; 77 | 78 | static const uint32_t timer_period_ms = 1; 79 | 80 | Timer timer; 81 | unsigned max_frames_per_trigger; 82 | bool voip_queue_connected; 83 | JaldiQueue* scheduled_queue; 84 | JaldiQueue* voip_queue; 85 | }; 86 | 87 | CLICK_ENDDECLS 88 | #endif 89 | -------------------------------------------------------------------------------- /click/elements/JaldiFakeDriverPrecise.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * JaldiFakeDriverPrecise.{cc,hh} -- simulates the behavior of the JaldiMAC kernel driver for use with other drivers 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "JaldiClick.hh" 14 | #include "JaldiQueue.hh" 15 | #include "JaldiFakeDriverPrecise.hh" 16 | 17 | using namespace jaldimac; 18 | 19 | CLICK_DECLS 20 | 21 | JaldiFakeDriverPrecise::JaldiFakeDriverPrecise() : task(this), 22 | voip_queue_connected(false), 23 | scheduled_queue(NULL), 24 | voip_queue(NULL), 25 | sleeping(false) 26 | { 27 | } 28 | 29 | JaldiFakeDriverPrecise::~JaldiFakeDriverPrecise() 30 | { 31 | } 32 | 33 | int JaldiFakeDriverPrecise::configure(Vector&, ErrorHandler*) 34 | { 35 | // Record input port configuration 36 | if (ninputs() == 2) 37 | voip_queue_connected = false; 38 | 39 | return 0; 40 | } 41 | 42 | int JaldiFakeDriverPrecise::initialize(ErrorHandler* errh) 43 | { 44 | // Find the nearest upstream scheduled frame queue 45 | ElementCastTracker filter(router(), "JaldiQueue"); 46 | 47 | if (router()->visit_upstream(this, in_port_scheduled, &filter) < 0 || filter.size() == 0) 48 | return errh->error("couldn't find an upstream scheduled frame JaldiQueue on input port %<%d%> using flow-based router context", in_port_scheduled); 49 | 50 | if (! (scheduled_queue = (JaldiQueue*) filter[0]->cast("JaldiQueue"))) 51 | return errh->error("scheduled frame queue %<%s%> on input port %<%d%> is not a valid JaldiQueue (cast failed)", filter[0]->name().c_str(), in_port_scheduled); 52 | 53 | if (voip_queue_connected) 54 | { 55 | // Find the nearest upstream VoIP queue 56 | filter.clear(); 57 | 58 | if (router()->visit_upstream(this, in_port_upstream_voip, &filter) < 0 || filter.size() == 0) 59 | return errh->error("couldn't find an upstream VoIP JaldiQueue on input port %<%d%> using flow-based router context", in_port_upstream_voip); 60 | 61 | if (! (voip_queue = (JaldiQueue*) filter[0]->cast("JaldiQueue"))) 62 | return errh->error("VoIP queue %<%s%> on input port %<%d%> is not a valid JaldiQueue (cast failed)", filter[0]->name().c_str(), in_port_upstream_voip); 63 | } 64 | 65 | // Initialize state 66 | sleeping = false; 67 | 68 | // Initialize task 69 | ScheduleInfo::initialize_task(this, &task, true, errh); 70 | 71 | // Success! 72 | return 0; 73 | } 74 | 75 | void JaldiFakeDriverPrecise::take_state(Element* old, ErrorHandler*) 76 | { 77 | JaldiFakeDriverPrecise* oldJFDP = (JaldiFakeDriverPrecise*) old->cast("JaldiFakeDriverPrecise"); 78 | 79 | if (oldJFDP) 80 | { 81 | sleeping = oldJFDP->sleeping; 82 | sleep_until.tv_sec = oldJFDP->sleep_until.tv_sec; 83 | sleep_until.tv_usec = oldJFDP->sleep_until.tv_usec; 84 | } 85 | } 86 | 87 | void JaldiFakeDriverPrecise::push(int, Packet* p) 88 | { 89 | // Got a message from downstream (the stations); push it to the master. 90 | output(out_port_to_master).push(p); 91 | } 92 | 93 | void JaldiFakeDriverPrecise::sleep_for_us(uint32_t us) 94 | { 95 | // Get current time. 96 | gettimeofday(&sleep_until, NULL); 97 | 98 | // Advance. 99 | sleep_until.tv_usec += us; 100 | 101 | // Normalize. 102 | while (sleep_until.tv_usec > 1000000) 103 | { 104 | ++sleep_until.tv_sec; 105 | sleep_until.tv_usec -= 1000000; 106 | } 107 | } 108 | 109 | bool JaldiFakeDriverPrecise::run_task(Task*) 110 | { 111 | // Sleep if needed. 112 | if (sleeping) 113 | { 114 | timeval now; 115 | gettimeofday(&now, NULL); 116 | 117 | if (now.tv_sec < sleep_until.tv_sec || (now.tv_sec == sleep_until.tv_sec && now.tv_usec < sleep_until.tv_usec)) 118 | return false; // Keep sleeping. 119 | else 120 | sleeping = false; 121 | } 122 | 123 | // Pull scheduled frames 124 | unsigned pulled_frames = 0; 125 | while (pulled_frames < max_frames_per_trigger) 126 | { 127 | Packet* p = input(in_port_scheduled).pull(); 128 | ++pulled_frames; 129 | 130 | if (p == NULL) 131 | break; 132 | 133 | // Got a Jaldi frame from the scheduler; decode it to decide what to do. 134 | const Frame* f = (const Frame*) p->data(); 135 | 136 | switch (f->type) 137 | { 138 | case BULK_FRAME: 139 | case VOIP_FRAME: 140 | case REQUEST_FRAME: 141 | { 142 | // Transmit a VoIP frame from upstream if one is waiting. 143 | if (voip_queue_connected) 144 | { 145 | Packet* vp = input(in_port_upstream_voip).pull(); 146 | 147 | if (vp) 148 | { 149 | ++pulled_frames; 150 | output(out_port_to_stations).push(vp); 151 | } 152 | } 153 | 154 | // Transmit the scheduled frame. 155 | output(out_port_to_stations).push(p); 156 | 157 | break; 158 | } 159 | 160 | case CONTENTION_SLOT: 161 | { 162 | const ContentionSlotPayload* csp = (const ContentionSlotPayload*) f->payload; 163 | // Let the master know that the round is complete. 164 | RoundCompleteMessagePayload* rcmp; 165 | WritablePacket* rcp = make_jaldi_frame(DRIVER_ID, rcmp); 166 | output(out_port_to_master).push(rcp); 167 | 168 | // Announce the contention slot. 169 | output(out_port_to_stations).push(p); 170 | 171 | // Wait until it's over. 172 | sleep_for_us(csp->duration_us); 173 | 174 | break; 175 | } 176 | 177 | case VOIP_SLOT: 178 | { 179 | const VoIPSlotPayload* vsp = (const VoIPSlotPayload*) f->payload; 180 | 181 | // Announce the VoIP slot. 182 | output(out_port_to_stations).push(p); 183 | 184 | // Wait until it's over. 185 | sleep_for_us(vsp->duration_us); 186 | 187 | break; 188 | } 189 | 190 | case TRANSMIT_SLOT: 191 | { 192 | const TransmitSlotPayload* tsp = (const TransmitSlotPayload*) f->payload; 193 | 194 | // Announce the transmit slot. 195 | output(out_port_to_stations).push(p); 196 | 197 | // Wait until it's over. 198 | sleep_for_us(tsp->duration_us); 199 | 200 | break; 201 | } 202 | 203 | case BITRATE_MESSAGE: 204 | { 205 | // This isn't implemented. 206 | click_chatter("%s: BITRATE_MESSAGE is unsupported\n", declaration().c_str()); 207 | p->kill(); 208 | break; 209 | } 210 | 211 | case ROUND_COMPLETE_MESSAGE: 212 | { 213 | // This isn't meant to be broadcast. 214 | p->kill(); 215 | break; 216 | } 217 | 218 | case DELAY_MESSAGE: 219 | { 220 | const DelayMessagePayload* tsp = (const DelayMessagePayload*) f->payload; 221 | 222 | // Delays aren't meant to be broadcast, so kill this frame. 223 | p->kill(); 224 | 225 | // Wait until it's over. 226 | sleep_for_us(tsp->duration_us); 227 | 228 | break; 229 | } 230 | 231 | default: 232 | { 233 | // Bad stuff; dump it out the optional output 234 | checked_output_push(out_port_bad, p); 235 | break; 236 | } 237 | } 238 | } 239 | 240 | // We've pulled all of the frames we're allowed to until the timer is 241 | // triggered again, so reschedule and return. 242 | task.fast_reschedule(); 243 | return true; 244 | } 245 | 246 | CLICK_ENDDECLS 247 | ELEMENT_REQUIRES(Frame) 248 | EXPORT_ELEMENT(JaldiFakeDriverPrecise) 249 | -------------------------------------------------------------------------------- /click/elements/JaldiFakeDriverPrecise.hh: -------------------------------------------------------------------------------- 1 | #ifndef CLICK_JALDIFAKEDRIVERPRECISE_HH 2 | #define CLICK_JALDIFAKEDRIVERPRECISE_HH 3 | #include 4 | #include 5 | CLICK_DECLS 6 | 7 | /* 8 | =c 9 | 10 | JaldiFakeDriverPrecise 11 | 12 | =s jaldi 13 | 14 | simulates the behavior of the JaldiMAC kernel driver for use with other drivers 15 | 16 | =d 17 | 18 | JaldiFakeDriverPrecise sits between the JaldiScheduler and a non-JaldiMAC kernel 19 | driver that does not support the notifications and timers that the JaldiMAC 20 | kernel driver makes available. It simulates these behaviors in Click. 21 | 22 | JaldiFakeDriverPrecise is different from JaldiFakeDriver in that it uses a higher 23 | resolution timing method. The downside of this method is that it relies on busy 24 | waiting, so JaldiFakeDriverPrecise will take all available CPU time for itself. 25 | However, JaldiFakeDriverPrecise should do a much better job of getting correct 26 | timing and sending packets at high speed than JaldiFakeDriver. 27 | 28 | Because of a recent design change, JaldiFakeDriverPrecise also has an additional 29 | responsibility - it dynamically inserts VoIP frames destined for the stations 30 | from upstream into its output. This may have the effect of making the resulting 31 | round longer than the nominal maximum round size, or slightly changing the 32 | distance between VoIP slots, but under normal traffic conditions these effects 33 | should be minimal, and this is the best way we have to simulate real dynamic 34 | scheduling of VoIP from upstream under the deadline constraints we have. 35 | 36 | JaldiFakeDriverPrecise's first input (push) receives traffic from downstream (the 37 | stations) and passes it along on its first output (push) unchanged. Input 1 38 | (pull) receives the output of a JaldiScheduler element. Input 2 (pull) receives 39 | upstream VoIP traffic if it is connected. Everything arriving on all inputs 40 | should be encapsulated in Jaldi frames, and both pull inputs should be 41 | connected to a JaldiQueue. 42 | 43 | There are two push outputs; the first is for traffic from downstream (the 44 | stations) to the master, and the second is for scheduled traffic being sent to 45 | the stations. A third push output may be connected to receive erroneous 46 | packets. 47 | 48 | =a 49 | 50 | JaldiScheduler, JaldiFakeDriver */ 51 | 52 | class JaldiQueue; 53 | 54 | class JaldiFakeDriverPrecise : public Element { public: 55 | 56 | JaldiFakeDriverPrecise(); 57 | ~JaldiFakeDriverPrecise(); 58 | 59 | const char* class_name() const { return "JaldiFakeDriverPrecise"; } 60 | const char* port_count() const { return "2-3/2-3"; } 61 | const char* processing() const { return "hl/h"; } 62 | const char* flow_code() const { return COMPLETE_FLOW; } 63 | 64 | int configure(Vector&, ErrorHandler*); 65 | int initialize(ErrorHandler*); 66 | bool can_live_reconfigure() const { return true; } 67 | void take_state(Element*, ErrorHandler*); 68 | 69 | void push(int, Packet*); 70 | bool run_task(Task*); 71 | 72 | private: 73 | void sleep_for_us(uint32_t us); 74 | 75 | static const int in_port_from_stations = 0; 76 | static const int in_port_scheduled = 1; 77 | static const int in_port_upstream_voip = 2; 78 | static const int out_port_to_master = 0; 79 | static const int out_port_to_stations = 1; 80 | static const int out_port_bad = 1; 81 | 82 | static const unsigned max_frames_per_trigger = 1; 83 | 84 | Task task; 85 | bool voip_queue_connected; 86 | JaldiQueue* scheduled_queue; 87 | JaldiQueue* voip_queue; 88 | bool sleeping; 89 | timeval sleep_until; 90 | }; 91 | 92 | CLICK_ENDDECLS 93 | #endif 94 | -------------------------------------------------------------------------------- /click/elements/JaldiGate.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * JaldiGate.{cc,hh} -- sends packets to master at appropriate times based upon control packets 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "JaldiClick.hh" 13 | #include "JaldiQueue.hh" 14 | #include "JaldiGate.hh" 15 | 16 | using namespace jaldimac; 17 | 18 | CLICK_DECLS 19 | 20 | JaldiGate::JaldiGate() : bulk_queue(NULL), voip_overflow_queue(NULL), 21 | outstanding_requests(false), bulk_requested_bytes(0), 22 | voip_requested_flows(0), station_id(0) 23 | { 24 | } 25 | 26 | JaldiGate::~JaldiGate() 27 | { 28 | } 29 | 30 | int JaldiGate::configure(Vector& conf, ErrorHandler* errh) 31 | { 32 | // Parse configuration parameters 33 | if (cp_va_kparse(conf, this, errh, 34 | "ID", cpkP+cpkM, cpByte, &station_id, 35 | cpEnd) < 0) 36 | return -1; 37 | 38 | // Check that we have the right number of input ports 39 | if (ninputs() != FLOWS_PER_VOIP_SLOT + 3) 40 | return errh->error("wrong number of input ports; need %<%d%>", FLOWS_PER_VOIP_SLOT + 3); 41 | 42 | // Looks good! 43 | return 0; 44 | } 45 | 46 | int JaldiGate::initialize(ErrorHandler* errh) 47 | { 48 | // Seed PRNG 49 | srand(time(NULL)); 50 | 51 | // Find the nearest upstream bulk queue 52 | ElementCastTracker filter(router(), "JaldiQueue"); 53 | 54 | if (router()->visit_upstream(this, in_port_bulk, &filter) < 0 || filter.size() == 0) 55 | return errh->error("couldn't find an upstream bulk JaldiQueue on input port %<%d%> using flow-based router context", in_port_bulk); 56 | 57 | if (! (bulk_queue = (JaldiQueue*) filter[0]->cast("JaldiQueue"))) 58 | return errh->error("bulk queue %<%s%> on input port %<%d%> is not a valid JaldiQueue (cast failed)", filter[0]->name().c_str(), in_port_bulk); 59 | 60 | // Find the nearest upstream VoIP queues 61 | for (unsigned voip_port = 0 ; voip_port < FLOWS_PER_VOIP_SLOT ; ++voip_port) 62 | { 63 | filter.clear(); 64 | 65 | if (router()->visit_upstream(this, in_port_voip_first + voip_port, &filter) < 0 || filter.size() == 0) 66 | return errh->error("couldn't find an upstream VoIP JaldiQueue on input port %<%d%> using flow-based router context", in_port_voip_first + voip_port); 67 | 68 | if (! (voip_queues[voip_port] = (JaldiQueue*) filter[0]->cast("JaldiQueue"))) 69 | return errh->error("VoIP queue %<%s%> on input port %<%d%> is not a valid JaldiQueue (cast failed)", filter[0]->name().c_str(), in_port_voip_first + voip_port); 70 | } 71 | 72 | // Find the nearest upstream VoIP overflow queue 73 | filter.clear(); 74 | 75 | if (router()->visit_upstream(this, in_port_voip_overflow, &filter) < 0 || filter.size() == 0) 76 | return errh->error("couldn't find an upstream VoIP overflow JaldiQueue on input port %<%d%> using flow-based router context", in_port_voip_overflow); 77 | 78 | if (! (voip_overflow_queue = (JaldiQueue*) filter[0]->cast("JaldiQueue"))) 79 | return errh->error("VoIP queue %<%s%> on input port %<%d%> is not a valid JaldiQueue (cast failed)", filter[0]->name().c_str(), in_port_voip_overflow); 80 | 81 | 82 | // Success! 83 | return 0; 84 | } 85 | 86 | void JaldiGate::take_state(Element* old, ErrorHandler*) 87 | { 88 | JaldiGate* oldJG = (JaldiGate*) old->cast("JaldiGate"); 89 | 90 | if (oldJG) 91 | { 92 | outstanding_requests = oldJG->outstanding_requests; 93 | bulk_requested_bytes = oldJG->bulk_requested_bytes; 94 | voip_requested_flows = oldJG->voip_requested_flows; 95 | station_id = oldJG->station_id; 96 | } 97 | } 98 | 99 | WritablePacket* JaldiGate::make_request_frame() 100 | { 101 | // Verify that a request is needed 102 | unsigned bulk_new_bytes = bulk_queue->total_length() - bulk_requested_bytes; 103 | unsigned voip_new_flows = 0; 104 | 105 | for (int voip_queue = 0 ; voip_queue < int(FLOWS_PER_VOIP_SLOT) ; ++voip_queue) 106 | { 107 | if (! voip_queues[voip_queue]->empty()) 108 | voip_new_flows += 1; 109 | } 110 | 111 | voip_new_flows -= voip_requested_flows; 112 | 113 | if (bulk_new_bytes == 0 && voip_new_flows == 0) 114 | return NULL; // Nothing to request! 115 | 116 | // Construct a request frame 117 | RequestFramePayload* rfp; 118 | WritablePacket* rp = make_jaldi_frame(station_id, rfp); 119 | rfp->bulk_request_bytes = bulk_new_bytes; 120 | rfp->voip_request_flows = voip_new_flows; 121 | 122 | // Update state 123 | outstanding_requests = true; 124 | bulk_requested_bytes += bulk_new_bytes; 125 | voip_requested_flows += voip_new_flows; 126 | 127 | // Return constructed packet 128 | return rp; 129 | } 130 | 131 | void JaldiGate::push(int, Packet* p) 132 | { 133 | // We've received some kind of control traffic; take action based on the 134 | // specific type and parameters. 135 | const Frame* f = (const Frame*) p->data(); 136 | 137 | if (! (f->dest_id == BROADCAST_ID || f->dest_id == station_id)) 138 | { 139 | // Not for us! Dump it out the optional output port 140 | checked_output_push(out_port_bad, p); 141 | return; 142 | } 143 | 144 | switch (f->type) 145 | { 146 | case CONTENTION_SLOT: 147 | { 148 | WritablePacket* rp; 149 | 150 | // Reset requested VoIP flows since they don't carry over between rounds 151 | voip_requested_flows = 0; 152 | 153 | // Send requests if we need to and we won't get a chance later 154 | if (outstanding_requests) 155 | outstanding_requests = false; // We'll get another chance 156 | else if ((rp = make_request_frame()) != NULL) 157 | { 158 | // We need to send a request! 159 | 160 | // If possible, create a delay message with a random delay 161 | // within the contention slot 162 | const ContentionSlotPayload* payload = (const ContentionSlotPayload*) f->payload; 163 | uint32_t requested_duration_us = rp->length() / BITRATE__BYTES_PER_US + 1; 164 | 165 | if (requested_duration_us < payload->duration_us) 166 | { 167 | // Construct and send a delay message frame 168 | DelayMessagePayload* dmp; 169 | WritablePacket* dp = make_jaldi_frame(station_id, dmp); 170 | dmp->duration_us = rand() % (payload->duration_us - requested_duration_us + 1); 171 | output(out_port).push(dp); 172 | } 173 | 174 | // Send the request 175 | output(out_port).push(rp); 176 | } 177 | 178 | p->kill(); 179 | 180 | break; 181 | } 182 | 183 | case VOIP_SLOT: 184 | { 185 | WritablePacket* rp; 186 | 187 | // Send a VoIP packet if the master has given us a chance to do so 188 | 189 | const VoIPSlotPayload* payload = (const VoIPSlotPayload*) f->payload; 190 | 191 | bool already_requested = false; 192 | int cur_voip_queue = in_port_voip_first; 193 | for (unsigned i = 0 ; i < FLOWS_PER_VOIP_SLOT ; ++i) 194 | { 195 | if (payload->stations[i] == station_id) 196 | { 197 | if (! already_requested && (rp = make_request_frame()) != NULL) 198 | { 199 | // Send a request frame 200 | output(out_port).push(rp); 201 | already_requested = true; 202 | } 203 | 204 | // Send one of our VoIP packets 205 | while (cur_voip_queue < in_port_voip_overflow) 206 | { 207 | Packet* vp = input(cur_voip_queue++).pull(); 208 | 209 | if (vp) 210 | { 211 | output(out_port).push(vp); 212 | break; 213 | } 214 | } 215 | } 216 | else 217 | { 218 | // Construct a delay message frame for the driver 219 | DelayMessagePayload* dmp; 220 | WritablePacket* dp = make_jaldi_frame(station_id, dmp); 221 | dmp->duration_us = VOIP_SLOT_SIZE__BYTES / BITRATE__BYTES_PER_US + 1; 222 | 223 | // Send it 224 | output(out_port).push(dp); 225 | } 226 | } 227 | 228 | p->kill(); 229 | 230 | break; 231 | } 232 | 233 | case TRANSMIT_SLOT: 234 | { 235 | WritablePacket* rp; 236 | uint32_t next_frame_duration_us; 237 | 238 | // If we have requests or bulk data, send them 239 | 240 | const TransmitSlotPayload* payload = (const TransmitSlotPayload*) f->payload; 241 | uint32_t duration_us = payload->duration_us; 242 | 243 | if ((rp = make_request_frame()) != NULL) 244 | { 245 | // Send a request frame 246 | output(out_port).push(rp); 247 | duration_us -= rp->length() / BITRATE__BYTES_PER_US + 1; 248 | } 249 | 250 | // Send VoIP frames that we will not receive a VoIP slot for 251 | if (payload->voip_granted_flows < voip_requested_flows) 252 | { 253 | uint8_t skip_flows = payload->voip_granted_flows; 254 | unsigned cur_voip_queue = 0; 255 | 256 | // Send one of our VoIP packets 257 | while (cur_voip_queue < FLOWS_PER_VOIP_SLOT) 258 | { 259 | // Skip over any empty voip queues 260 | if (voip_queues[cur_voip_queue]->empty()) 261 | { 262 | ++cur_voip_queue; 263 | continue; 264 | } 265 | 266 | // Skip over queues that will be handled by a VoIP slot 267 | if (skip_flows > 0) 268 | { 269 | ++cur_voip_queue; 270 | --skip_flows; 271 | continue; 272 | } 273 | 274 | // Skip over queues that we don't have time to send 275 | if ((next_frame_duration_us = voip_queues[cur_voip_queue]->head_length() / BITRATE__BYTES_PER_US + 1) < duration_us) 276 | { 277 | ++cur_voip_queue; 278 | continue; 279 | } 280 | 281 | // OK, it's safe to send a packet from this queue! 282 | Packet* vp = input(in_port_voip_first + cur_voip_queue++).pull(); 283 | output(out_port).push(vp); 284 | 285 | // Update remaining duration 286 | duration_us -= next_frame_duration_us; 287 | } 288 | } 289 | 290 | // Send overflow VoIP frames 291 | while (! voip_overflow_queue->empty() && (next_frame_duration_us = voip_overflow_queue->head_length() / BITRATE__BYTES_PER_US + 1) < duration_us) 292 | { 293 | // Pull the next frame and send it 294 | Packet* vp = input(in_port_voip_overflow).pull(); 295 | output(out_port).push(vp); 296 | 297 | // Update remaining duration 298 | duration_us -= next_frame_duration_us; 299 | } 300 | 301 | // Send bulk frames 302 | while (! bulk_queue->empty() && (next_frame_duration_us = bulk_queue->head_length() / BITRATE__BYTES_PER_US + 1) < duration_us) 303 | { 304 | // Pull the next frame, update stats, and send it 305 | Packet* bp = input(in_port_bulk).pull(); 306 | bulk_requested_bytes -= bp->length(); 307 | output(out_port).push(bp); 308 | 309 | // Update remaining duration 310 | duration_us -= next_frame_duration_us; 311 | } 312 | 313 | p->kill(); 314 | 315 | break; 316 | } 317 | 318 | default: 319 | { 320 | // Bad stuff; dump it out the optional output 321 | checked_output_push(out_port_bad, p); 322 | break; 323 | } 324 | } 325 | } 326 | 327 | CLICK_ENDDECLS 328 | ELEMENT_REQUIRES(Frame) 329 | EXPORT_ELEMENT(JaldiGate) 330 | -------------------------------------------------------------------------------- /click/elements/JaldiGate.hh: -------------------------------------------------------------------------------- 1 | #ifndef CLICK_JALDIGATE_HH 2 | #define CLICK_JALDIGATE_HH 3 | #include 4 | #include "Frame.hh" 5 | CLICK_DECLS 6 | 7 | /* 8 | =c 9 | 10 | JaldiGate(ID) 11 | 12 | =s jaldi 13 | 14 | sends Jaldi frames in response to control messages 15 | 16 | =d 17 | 18 | JaldiGate observes incoming control messages and sends data queued on its 19 | inputs to its output when requested by the master. It's also responsible for 20 | sending requests to the master when more data is queued than can be sent in the 21 | current round. JaldiGate is, in some sense, the equivalent of JaldiScheduler 22 | for stations. 23 | 24 | ID is the station ID of this station. 25 | 26 | JaldiGate has at least 3 inputs. Input 0 (push) is for control traffic and 27 | input 1 (pull) is for bulk traffic. Inputs 2 and above (pull) are for VoIP 28 | traffic; there should be as many VoIP inputs as there are flows that may fit in 29 | a VoIP slot, plus one for any excess VoIP flows that will have to be sent with 30 | bulk data. Everything arriving on the inputs should be encapsulated in Jaldi 31 | frames, and all pull inputs should be connected to JaldiQueues. 32 | 33 | There is one push output (though a second push output may be connected to 34 | receive erroneous packets). 35 | 36 | =a 37 | 38 | JaldiGate */ 39 | 40 | class JaldiQueue; 41 | 42 | class JaldiGate : public Element { public: 43 | 44 | JaldiGate(); 45 | ~JaldiGate(); 46 | 47 | const char* class_name() const { return "JaldiGate"; } 48 | const char* port_count() const { return "3-/1-2"; } 49 | const char* processing() const { return "hl/h"; } 50 | const char* flow_code() const { return COMPLETE_FLOW; } 51 | 52 | int configure(Vector&, ErrorHandler*); 53 | int initialize(ErrorHandler*); 54 | bool can_live_reconfigure() const { return true; } 55 | void take_state(Element*, ErrorHandler*); 56 | 57 | WritablePacket* make_request_frame(); 58 | 59 | void push(int, Packet*); 60 | 61 | private: 62 | static const int in_port_control = 0; 63 | static const int in_port_bulk = 1; 64 | static const int in_port_voip_first = 2; 65 | static const int in_port_voip_overflow = in_port_voip_first + jaldimac::FLOWS_PER_VOIP_SLOT; 66 | static const int out_port = 0; 67 | static const int out_port_bad = 1; 68 | 69 | JaldiQueue* bulk_queue; 70 | JaldiQueue* voip_queues[jaldimac::FLOWS_PER_VOIP_SLOT]; 71 | JaldiQueue* voip_overflow_queue; 72 | bool outstanding_requests; 73 | uint32_t bulk_requested_bytes; 74 | uint8_t voip_requested_flows; 75 | uint8_t station_id; 76 | }; 77 | 78 | CLICK_ENDDECLS 79 | #endif 80 | -------------------------------------------------------------------------------- /click/elements/JaldiPrint.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * JaldiPrint.{cc,hh} -- prints Jaldi frames 3 | */ 4 | 5 | #define __STDC_LIMIT_MACROS 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "JaldiPrint.hh" 14 | 15 | using namespace jaldimac; 16 | using namespace std; 17 | 18 | CLICK_DECLS 19 | 20 | JaldiPrint::JaldiPrint() 21 | { 22 | } 23 | 24 | JaldiPrint::~JaldiPrint() 25 | { 26 | } 27 | 28 | int JaldiPrint::configure(Vector& conf, ErrorHandler* errh) 29 | { 30 | bool contents_supplied = false; 31 | 32 | // Parse configuration parameters 33 | if (cp_va_kparse(conf, this, errh, 34 | "CONTENTS", cpkP+cpkC, &contents_supplied, cpBool, &show_contents, 35 | cpEnd) < 0) 36 | return -1; 37 | 38 | if (! contents_supplied) 39 | show_contents = false; 40 | 41 | return 0; 42 | } 43 | 44 | void JaldiPrint::show_raw_payload(const Frame* f) 45 | { 46 | if (show_contents) 47 | { 48 | char buffer[5000]; 49 | char* buf = buffer; 50 | unsigned length = min(f->payload_length(), (const uint32_t) 2000); 51 | const uint8_t* payload = f->payload; 52 | 53 | for (unsigned i = 0 ; i < length ; ++i) 54 | { 55 | if (i && (i % 4) == 0) 56 | *buf++ = ' '; 57 | 58 | sprintf(buf, "%02x", *payload++ & 0xff); 59 | buf += 2; 60 | } 61 | 62 | *buf = '\0'; 63 | 64 | click_chatter("Payload: %s", buffer); 65 | } 66 | } 67 | 68 | Packet* JaldiPrint::action(Packet* p) 69 | { 70 | // Treat the packet as a Frame 71 | const Frame* f = (const Frame*) p->data(); 72 | 73 | // Print header 74 | click_chatter("==========================="); 75 | 76 | click_chatter("Preamble: %c%c%c%u Source: %u Dest: %u", 77 | f->preamble[0], f->preamble[1], f->preamble[2], 78 | unsigned(f->preamble[3]), f->src_id, f->dest_id); 79 | 80 | click_chatter("Tag: %u Length: %u Payload Length: %u Sequence #: %u", 81 | unsigned(f->tag), unsigned(f->length), 82 | unsigned(f->payload_length()), unsigned(f->seq)); 83 | 84 | switch (f->type) 85 | { 86 | case BULK_FRAME: 87 | { 88 | click_chatter("Type: BULK_FRAME"); 89 | show_raw_payload(f); 90 | break; 91 | } 92 | 93 | case VOIP_FRAME: 94 | { 95 | click_chatter("Type: VOIP_FRAME"); 96 | show_raw_payload(f); 97 | break; 98 | } 99 | 100 | case REQUEST_FRAME: 101 | { 102 | const RequestFramePayload* rfp = (const RequestFramePayload*) f->payload; 103 | click_chatter("Type: REQUEST_FRAME Bulk request (bytes): %u VoIP request (flows): %u", 104 | rfp->bulk_request_bytes, unsigned(rfp->voip_request_flows)); 105 | 106 | show_raw_payload(f); 107 | break; 108 | } 109 | 110 | case CONTENTION_SLOT: 111 | { 112 | const ContentionSlotPayload* csp = (const ContentionSlotPayload*) f->payload; 113 | click_chatter("Type: CONTENTION_SLOT Duration (us): %u", 114 | csp->duration_us); 115 | 116 | show_raw_payload(f); 117 | break; 118 | } 119 | 120 | case VOIP_SLOT: 121 | { 122 | // FIXME: Don't hardcode the number of flows per VoIP slot 123 | const VoIPSlotPayload* vsp = (const VoIPSlotPayload*) f->payload; 124 | click_chatter("Type: VOIP_SLOT Duration (us): %u Stations: %u %u %u %u", 125 | vsp->duration_us, unsigned(vsp->stations[0]), 126 | unsigned(vsp->stations[1]), unsigned(vsp->stations[2]), 127 | unsigned(vsp->stations[3])); 128 | 129 | show_raw_payload(f); 130 | break; 131 | } 132 | 133 | case TRANSMIT_SLOT: 134 | { 135 | const TransmitSlotPayload* tsp = (const TransmitSlotPayload*) f->payload; 136 | click_chatter("Type: TRANSMIT_SLOT Duration (us): %u Granted VoIP flows: %u", 137 | tsp->duration_us, unsigned(tsp->voip_granted_flows)); 138 | 139 | show_raw_payload(f); 140 | break; 141 | } 142 | 143 | case BITRATE_MESSAGE: 144 | { 145 | const BitrateMessagePayload* bmp = (const BitrateMessagePayload*) f->payload; 146 | click_chatter("Type: BITRATE_MESSAGE Bitrate: %u", bmp->bitrate); 147 | 148 | show_raw_payload(f); 149 | break; 150 | } 151 | 152 | case ROUND_COMPLETE_MESSAGE: 153 | { 154 | click_chatter("Type: ROUND_COMPLETE_MESSAGE"); 155 | 156 | show_raw_payload(f); 157 | break; 158 | } 159 | 160 | 161 | case DELAY_MESSAGE: 162 | { 163 | const DelayMessagePayload* dmp = (const DelayMessagePayload*) f->payload; 164 | click_chatter("Type: DELAY_MESSAGE Duration (us): %u", 165 | dmp->duration_us); 166 | 167 | show_raw_payload(f); 168 | break; 169 | } 170 | 171 | default: 172 | click_chatter("Type: <<>>\n"); break; 173 | } 174 | 175 | click_chatter("==========================="); 176 | 177 | return p; 178 | } 179 | 180 | void JaldiPrint::push(int, Packet* p) 181 | { 182 | if (Packet* q = action(p)) 183 | output(out_port).push(q); 184 | } 185 | 186 | Packet* JaldiPrint::pull(int) 187 | { 188 | if (Packet *p = input(in_port).pull()) 189 | return action(p); 190 | else 191 | return NULL; 192 | } 193 | 194 | CLICK_ENDDECLS 195 | ELEMENT_REQUIRES(Frame) 196 | EXPORT_ELEMENT(JaldiPrint) 197 | -------------------------------------------------------------------------------- /click/elements/JaldiPrint.hh: -------------------------------------------------------------------------------- 1 | #ifndef CLICK_JALDIPRINT_HH 2 | #define CLICK_JALDIPRINT_HH 3 | #include 4 | #include "Frame.hh" 5 | CLICK_DECLS 6 | 7 | /* 8 | =c 9 | 10 | JaldiPrint(CONTENTS) 11 | 12 | =s jaldi 13 | 14 | prints Jaldi frames 15 | 16 | =d 17 | 18 | Prints Jaldi frames received on its only (agnostic) input and then 19 | sends them out through its only (agnostic) output. 20 | 21 | CONTENTS determines if the payload of the frame will be printed. 22 | If not present, defaults to false. 23 | 24 | =a 25 | 26 | JaldiEncap, JaldiDecap */ 27 | 28 | class JaldiPrint : public Element { public: 29 | 30 | JaldiPrint(); 31 | ~JaldiPrint(); 32 | 33 | const char* class_name() const { return "JaldiPrint"; } 34 | const char* port_count() const { return "1/1"; } 35 | const char* processing() const { return AGNOSTIC; } 36 | const char* flow_code() const { return COMPLETE_FLOW; } 37 | 38 | int configure(Vector&, ErrorHandler*); 39 | bool can_live_reconfigure() const { return true; } 40 | 41 | void show_raw_payload(const jaldimac::Frame*); 42 | Packet* action(Packet* p); 43 | void push(int, Packet*); 44 | Packet* pull(int); 45 | 46 | private: 47 | static const int in_port = 0; 48 | static const int out_port = 0; 49 | 50 | bool show_contents; 51 | }; 52 | 53 | CLICK_ENDDECLS 54 | #endif 55 | -------------------------------------------------------------------------------- /click/elements/JaldiQueue.cc: -------------------------------------------------------------------------------- 1 | // -*- c-basic-offset: 4 -*- 2 | /* 3 | * simplequeue.{cc,hh} -- queue element 4 | * Eddie Kohler 5 | * 6 | * Copyright (c) 1999-2000 Massachusetts Institute of Technology 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a 9 | * copy of this software and associated documentation files (the "Software"), 10 | * to deal in the Software without restriction, subject to the conditions 11 | * listed in the Click LICENSE file. These conditions include: you must 12 | * preserve this copyright notice, and you cannot mention the copyright 13 | * holders in advertising related to the Software without their permission. 14 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 15 | * notice is a summary of the Click LICENSE file; the license in that file is 16 | * legally binding. 17 | */ 18 | 19 | #include 20 | #include "JaldiQueue.hh" 21 | #include 22 | #include 23 | CLICK_DECLS 24 | 25 | JaldiQueue::JaldiQueue() 26 | : _q(0) 27 | { 28 | } 29 | 30 | JaldiQueue::~JaldiQueue() 31 | { 32 | } 33 | 34 | void * 35 | JaldiQueue::cast(const char *n) 36 | { 37 | if (strcmp(n, "Storage") == 0) 38 | return (Storage *)this; 39 | else if (strcmp(n, "JaldiQueue") == 0 40 | || strcmp(n, "Queue") == 0) 41 | return (Element *)this; 42 | else 43 | return 0; 44 | } 45 | 46 | int 47 | JaldiQueue::configure(Vector &conf, ErrorHandler *errh) 48 | { 49 | int new_capacity = 1000; 50 | if (cp_va_kparse(conf, this, errh, 51 | "CAPACITY", cpkP, cpUnsigned, &new_capacity, 52 | cpEnd) < 0) 53 | return -1; 54 | _capacity = new_capacity; 55 | return 0; 56 | } 57 | 58 | int 59 | JaldiQueue::initialize(ErrorHandler *errh) 60 | { 61 | assert(!_q && _head == 0 && _tail == 0); 62 | _q = (Packet **) CLICK_LALLOC(sizeof(Packet *) * (_capacity + 1)); 63 | if (_q == 0) 64 | return errh->error("out of memory"); 65 | _drops = 0; 66 | _highwater_length = 0; 67 | return 0; 68 | } 69 | 70 | int 71 | JaldiQueue::live_reconfigure(Vector &conf, ErrorHandler *errh) 72 | { 73 | // change the maximum queue length at runtime 74 | int old_capacity = _capacity; 75 | // NB: do not call children! 76 | if (JaldiQueue::configure(conf, errh) < 0) 77 | return -1; 78 | if (_capacity == old_capacity || !_q) 79 | return 0; 80 | int new_capacity = _capacity; 81 | _capacity = old_capacity; 82 | 83 | Packet **new_q = (Packet **) CLICK_LALLOC(sizeof(Packet *) * (new_capacity + 1)); 84 | if (new_q == 0) 85 | return errh->error("out of memory"); 86 | 87 | int i, j; 88 | for (i = _head, j = 0; i != _tail && j != new_capacity; i = next_i(i)) 89 | new_q[j++] = _q[i]; 90 | for (; i != _tail; i = next_i(i)) 91 | _q[i]->kill(); 92 | 93 | CLICK_LFREE(_q, sizeof(Packet *) * (_capacity + 1)); 94 | _q = new_q; 95 | _head = 0; 96 | _tail = j; 97 | _capacity = new_capacity; 98 | return 0; 99 | } 100 | 101 | void 102 | JaldiQueue::take_state(Element *e, ErrorHandler *errh) 103 | { 104 | JaldiQueue *q = (JaldiQueue *)e->cast("JaldiQueue"); 105 | if (!q) 106 | return; 107 | 108 | if (_tail != _head || _head != 0) { 109 | errh->error("already have packets enqueued, can%,t take state"); 110 | return; 111 | } 112 | 113 | _head = 0; 114 | int i = 0, j = q->_head; 115 | while (i < _capacity && j != q->_tail) { 116 | _q[i] = q->_q[j]; 117 | i++; 118 | j = q->next_i(j); 119 | } 120 | _tail = i; 121 | _highwater_length = size(); 122 | 123 | if (j != q->_tail) 124 | errh->warning("some packets lost (old length %d, new capacity %d)", 125 | q->size(), _capacity); 126 | while (j != q->_tail) { 127 | q->_q[j]->kill(); 128 | j = q->next_i(j); 129 | } 130 | q->set_head(0); 131 | q->set_tail(0); 132 | } 133 | 134 | void 135 | JaldiQueue::cleanup(CleanupStage) 136 | { 137 | for (int i = _head; i != _tail; i = next_i(i)) 138 | _q[i]->kill(); 139 | CLICK_LFREE(_q, sizeof(Packet *) * (_capacity + 1)); 140 | _q = 0; 141 | } 142 | 143 | void 144 | JaldiQueue::push(int, Packet *p) 145 | { 146 | // If you change this code, also change NotifierQueue::push() 147 | // and FullNoteQueue::push(). 148 | int h = _head, t = _tail, nt = next_i(t); 149 | 150 | // should this stuff be in JaldiQueue::enq? 151 | if (nt != h) { 152 | _q[t] = p; 153 | packet_memory_barrier(_q[t], _tail); 154 | _tail = nt; 155 | 156 | int s = size(h, nt); 157 | if (s > _highwater_length) 158 | _highwater_length = s; 159 | 160 | } else { 161 | // if (!(_drops % 100)) 162 | if (_drops == 0 && _capacity > 0) 163 | click_chatter("%{element}: overflow", this); 164 | _drops++; 165 | checked_output_push(1, p); 166 | } 167 | } 168 | 169 | Packet * 170 | JaldiQueue::pull(int) 171 | { 172 | return deq(); 173 | } 174 | 175 | #if 0 176 | Vector 177 | JaldiQueue::yank(bool (filter)(const Packet *, void *), void *thunk) 178 | { 179 | // remove all packets from the queue that match filter(); return in 180 | // a vector. caller is responsible for managing the yank()-ed 181 | // packets from now on, i.e. deallocating them. 182 | Vector v; 183 | 184 | int next_slot = _head; 185 | for (int i = _head; i != _tail; i = next_i(i)) { 186 | if (filter(_q[i], thunk)) 187 | v.push_back(_q[i]); 188 | else { 189 | _q[next_slot] = _q[i]; 190 | next_slot = next_i(next_slot); 191 | } 192 | } 193 | _tail = next_slot; 194 | 195 | return v; 196 | } 197 | #endif 198 | 199 | 200 | String 201 | JaldiQueue::read_handler(Element *e, void *thunk) 202 | { 203 | JaldiQueue *q = static_cast(e); 204 | int which = reinterpret_cast(thunk); 205 | switch (which) { 206 | case 0: 207 | return String(q->size()); 208 | case 1: 209 | return String(q->highwater_length()); 210 | case 2: 211 | return String(q->capacity()); 212 | case 3: 213 | return String(q->_drops); 214 | default: 215 | return ""; 216 | } 217 | } 218 | 219 | void 220 | JaldiQueue::reset() 221 | { 222 | while (Packet *p = pull(0)) 223 | checked_output_push(1, p); 224 | } 225 | 226 | int 227 | JaldiQueue::write_handler(const String &, Element *e, void *thunk, ErrorHandler *errh) 228 | { 229 | JaldiQueue *q = static_cast(e); 230 | int which = reinterpret_cast(thunk); 231 | switch (which) { 232 | case 0: 233 | q->_drops = 0; 234 | q->_highwater_length = q->size(); 235 | return 0; 236 | case 1: 237 | q->reset(); 238 | return 0; 239 | default: 240 | return errh->error("internal error"); 241 | } 242 | } 243 | 244 | void 245 | JaldiQueue::add_handlers() 246 | { 247 | add_read_handler("length", read_handler, (void *)0); 248 | add_read_handler("highwater_length", read_handler, (void *)1); 249 | add_read_handler("capacity", read_handler, (void *)2, Handler::CALM); 250 | add_read_handler("drops", read_handler, (void *)3); 251 | add_write_handler("capacity", reconfigure_keyword_handler, "0 CAPACITY"); 252 | add_write_handler("reset_counts", write_handler, (void *)0, Handler::BUTTON | Handler::NONEXCLUSIVE); 253 | add_write_handler("reset", write_handler, (void *)1, Handler::BUTTON); 254 | } 255 | 256 | CLICK_ENDDECLS 257 | ELEMENT_PROVIDES(Storage) 258 | EXPORT_ELEMENT(JaldiQueue) 259 | -------------------------------------------------------------------------------- /click/elements/JaldiQueue.hh: -------------------------------------------------------------------------------- 1 | #ifndef CLICK_JALDIQUEUE_HH 2 | #define CLICK_JALDIQUEUE_HH 3 | #include 4 | #include 5 | CLICK_DECLS 6 | 7 | /* 8 | =c 9 | 10 | JaldiQueue 11 | JaldiQueue(CAPACITY) 12 | 13 | =s jaldi 14 | 15 | stores packets in a FIFO queue 16 | 17 | =d 18 | 19 | Stores incoming packets in a first-in-first-out queue. 20 | Drops incoming packets if the queue already holds CAPACITY packets. 21 | The default for CAPACITY is 1000. 22 | 23 | B JaldiQueue is designed to be used in an 24 | environment with at most one concurrent pusher and at most one concurrent 25 | puller. Thus, at most one thread pushes to the JaldiQueue at a time and at 26 | most one thread pulls from the JaldiQueue at a time. Different threads can 27 | push to and pull from the JaldiQueue concurrently, however. See 28 | ThreadSafeQueue for a queue that can support multiple concurrent pushers and 29 | pullers. 30 | 31 | JaldiQueue is a variation of SimpleQueue from the Click distribution that 32 | includes internal changes required for other Jaldi elements, such as JaldiGate, 33 | to work. From the level of the Click configuration language, there is no 34 | difference between JaldiQueue and SimpleQueue. 35 | 36 | =n 37 | 38 | The Queue and NotifierQueue elements act like JaldiQueue, but additionally 39 | notify interested parties when they change state (from nonempty to empty or 40 | vice versa, and/or from nonfull to full or vice versa). 41 | 42 | =h length read-only 43 | 44 | Returns the current number of packets in the queue. 45 | 46 | =h highwater_length read-only 47 | 48 | Returns the maximum number of packets that have ever been in the queue at once. 49 | 50 | =h capacity read/write 51 | 52 | Returns or sets the queue's capacity. 53 | 54 | =h drops read-only 55 | 56 | Returns the number of packets dropped by the queue so far. Dropped packets 57 | are emitted on output 1 if output 1 exists. 58 | 59 | =h reset_counts write-only 60 | 61 | When written, resets the C and C counters. 62 | 63 | =h reset write-only 64 | 65 | When written, drops all packets in the queue. 66 | 67 | =a Queue, NotifierQueue, MixedQueue, RED, FrontDropQueue, ThreadSafeQueue */ 68 | 69 | class JaldiQueue : public Element, public Storage { public: 70 | 71 | JaldiQueue(); 72 | ~JaldiQueue(); 73 | 74 | int drops() const { return _drops; } 75 | int highwater_length() const { return _highwater_length; } 76 | 77 | inline bool enq(Packet*); 78 | inline void lifo_enq(Packet*); 79 | inline Packet* deq(); 80 | inline unsigned total_length(); 81 | inline unsigned head_length(); 82 | 83 | // to be used with care 84 | Packet* packet(int i) const { return _q[i]; } 85 | void reset(); // NB: does not do notification 86 | 87 | template Packet* yank1(Filter); 88 | template Packet* yank1_peek(Filter); 89 | template int yank(Filter, Vector &); 90 | 91 | const char *class_name() const { return "JaldiQueue"; } 92 | const char *port_count() const { return PORTS_1_1X2; } 93 | const char *processing() const { return "h/lh"; } 94 | void* cast(const char*); 95 | 96 | int configure(Vector&, ErrorHandler*); 97 | int initialize(ErrorHandler*); 98 | void cleanup(CleanupStage); 99 | bool can_live_reconfigure() const { return true; } 100 | int live_reconfigure(Vector&, ErrorHandler*); 101 | void take_state(Element*, ErrorHandler*); 102 | void add_handlers(); 103 | 104 | void push(int port, Packet*); 105 | Packet* pull(int port); 106 | 107 | protected: 108 | 109 | Packet* volatile * _q; 110 | volatile int _drops; 111 | int _highwater_length; 112 | 113 | friend class MixedQueue; 114 | friend class TokenQueue; 115 | friend class InOrderQueue; 116 | friend class ECNQueue; 117 | 118 | static String read_handler(Element*, void*); 119 | static int write_handler(const String&, Element*, void*, ErrorHandler*); 120 | 121 | }; 122 | 123 | 124 | inline bool 125 | JaldiQueue::enq(Packet *p) 126 | { 127 | assert(p); 128 | int h = _head, t = _tail, nt = next_i(t); 129 | if (nt != h) { 130 | _q[t] = p; 131 | packet_memory_barrier(_q[t], _tail); 132 | _tail = nt; 133 | int s = size(h, nt); 134 | if (s > _highwater_length) 135 | _highwater_length = s; 136 | return true; 137 | } else { 138 | p->kill(); 139 | _drops++; 140 | return false; 141 | } 142 | } 143 | 144 | inline void 145 | JaldiQueue::lifo_enq(Packet *p) 146 | { 147 | // XXX NB: significantly more dangerous in a multithreaded environment 148 | // than plain (FIFO) enq(). 149 | assert(p); 150 | int h = _head, t = _tail, ph = prev_i(h); 151 | if (ph == t) { 152 | t = prev_i(t); 153 | _q[t]->kill(); 154 | _tail = t; 155 | } 156 | _q[ph] = p; 157 | packet_memory_barrier(_q[ph], _head); 158 | _head = ph; 159 | } 160 | 161 | inline Packet * 162 | JaldiQueue::deq() 163 | { 164 | int h = _head, t = _tail; 165 | if (h != t) { 166 | Packet *p = _q[h]; 167 | packet_memory_barrier(_q[h], _head); 168 | _head = next_i(h); 169 | assert(p); 170 | return p; 171 | } else 172 | return 0; 173 | } 174 | 175 | // Report the total length, in bytes, of every packet in the queue. 176 | inline unsigned 177 | JaldiQueue::total_length() 178 | { 179 | unsigned size = 0; 180 | 181 | for (int trav = _head; trav != _tail; trav = next_i(trav)) 182 | size += _q[trav]->length(); 183 | 184 | return size; 185 | } 186 | 187 | // Report the length, in bytes, of the packet at the head of the queue. 188 | // Unsafe if the queue is empty, so check first! 189 | inline unsigned 190 | JaldiQueue::head_length() 191 | { 192 | return _q[_head]->length(); 193 | } 194 | 195 | template 196 | Packet * 197 | JaldiQueue::yank1(Filter filter) 198 | /* Remove from the queue and return the first packet that matches 199 | 'filter(Packet *)'. The returned packet must be deallocated by the 200 | caller. */ 201 | { 202 | for (int trav = _head; trav != _tail; trav = next_i(trav)) 203 | if (filter(_q[trav])) { 204 | Packet *p = _q[trav]; 205 | int prev = prev_i(trav); 206 | while (trav != _head) { 207 | _q[trav] = _q[prev]; 208 | trav = prev; 209 | prev = prev_i(prev); 210 | } 211 | _head = next_i(_head); 212 | return p; 213 | } 214 | return 0; 215 | } 216 | 217 | template 218 | Packet * 219 | JaldiQueue::yank1_peek(Filter filter) 220 | /* return the first packet that matches 221 | 'filter(Packet *)'. The returned packet must *NOT* be deallocated by the 222 | caller. */ 223 | { 224 | for (int trav = _head; trav != _tail; trav = next_i(trav)) 225 | if (filter(_q[trav])) { 226 | Packet *p = _q[trav]; 227 | return p; 228 | } 229 | return 0; 230 | } 231 | 232 | template 233 | int 234 | JaldiQueue::yank(Filter filter, Vector &yank_vec) 235 | /* Removes from the queue and adds to 'yank_vec' all packets in the queue 236 | that match 'filter(Packet *)'. Packets are added to 'yank_vec' in LIFO 237 | order, so 'yank_vec.back()' will equal the first packet in the queue 238 | that matched 'filter()'. Caller should deallocate any packets returned 239 | in 'yank_vec'. Returns the number of packets yanked. */ 240 | { 241 | int write_ptr = _tail; 242 | int nyanked = 0; 243 | for (int trav = _tail; trav != _head; ) { 244 | trav = prev_i(trav); 245 | if (filter(_q[trav])) { 246 | yank_vec.push_back(_q[trav]); 247 | nyanked++; 248 | } else { 249 | write_ptr = prev_i(write_ptr); 250 | _q[write_ptr] = _q[trav]; 251 | } 252 | } 253 | _head = write_ptr; 254 | return nyanked; 255 | } 256 | 257 | CLICK_ENDDECLS 258 | #endif 259 | -------------------------------------------------------------------------------- /click/elements/JaldiScheduler.hh: -------------------------------------------------------------------------------- 1 | #ifndef CLICK_JALDISCHEDULER_HH 2 | #define CLICK_JALDISCHEDULER_HH 3 | #include 4 | #include "Frame.hh" 5 | CLICK_DECLS 6 | 7 | /* 8 | =c 9 | 10 | JaldiScheduler(CSONLYRATELIMIT) 11 | 12 | =s jaldi 13 | 14 | constructs a Jaldi round layout from incoming packets and requests 15 | 16 | =d 17 | 18 | JaldiScheduler constructs a Jaldi round layout (expressed in the form of a 19 | sequence of Jaldi frames that direct the driver, which actually implements the 20 | requested behavior) from incoming packets from the Internet and incoming 21 | requests from stations. 22 | 23 | In a complete JaldiMAC implementation, JaldiScheduler would have a STATIONS 24 | parameter indicating the number of stations it must serve, and it would 25 | calculate port numbers dynamically from that. For now, STATIONS is hardcoded. 26 | 27 | Input 0 (push) is for control Jaldi frames, coming from either stations (e.g. 28 | REQUEST_FRAME) or from the driver. (e.g. ROUND_COMPLETE_MESSAGE) Input 1 (push) 29 | is a second input for control Jaldi frames for use by other elements; in 30 | particular, this input is intended to be used by an InfiniteSource or similar 31 | to jumpstart the scheduling process by sending a single initial 32 | ROUND_COMPLETE_MESSAGE. Inputs 2 thru STATIONS + 1 (pull) are for bulk Jaldi 33 | frames destined for each station. VoIP traffic destined for the stations is 34 | not handled by the scheduler at all; instead, it is inserted dynamically (by 35 | another element) as soon as the traffic arrives. JaldiScheduler has one push 36 | output (though a second push output may be connected to receive erroneous 37 | packets). Everything arriving on the inputs should be encapsulated in Jaldi 38 | frames. 39 | 40 | The CSONLYRATELIMIT parameter, if specified, indicates the minimum time between 41 | contention-slot-only rounds in microseconds. (i.e., rounds which contain 42 | neither data from upstream nor requests from the stations) If this parameter is 43 | not specified, a reasonable default is chosen. 44 | 45 | =a 46 | 47 | JaldiGate */ 48 | 49 | class JaldiQueue; 50 | 51 | class JaldiScheduler : public Element { public: 52 | 53 | JaldiScheduler(); 54 | ~JaldiScheduler(); 55 | 56 | const char* class_name() const { return "JaldiScheduler"; } 57 | const char* port_count() const { return "2-/1-2"; } 58 | const char* processing() const { return "hhl/h"; } 59 | const char* flow_code() const { return COMPLETE_FLOW; } 60 | 61 | int configure(Vector&, ErrorHandler*); 62 | int initialize(ErrorHandler*); 63 | bool can_live_reconfigure() const { return true; } 64 | void take_state(Element*, ErrorHandler*); 65 | 66 | void run_timer(Timer*); 67 | void push(int, Packet*); 68 | 69 | private: 70 | void received_round_complete_message(); 71 | bool have_data_or_requests(); 72 | void count_upstream(); 73 | bool try_to_allocate_voip_request(unsigned, unsigned&); 74 | void allocate_voip_to_no_one(unsigned); 75 | void compute_fair_allocation(); 76 | void generate_layout(); 77 | 78 | static const int in_port_control = 0; 79 | static const int in_port_control_secondary = 1; 80 | static const int in_port_bulk_first = 2; 81 | static const int out_port = 0; 82 | static const int out_port_bad = 1; 83 | 84 | JaldiQueue* bulk_queues[jaldimac::STATION_COUNT]; 85 | 86 | uint32_t bulk_requested_bytes[jaldimac::STATION_COUNT]; 87 | uint8_t voip_requested_flows[jaldimac::STATION_COUNT]; 88 | uint32_t bulk_upstream_bytes[jaldimac::STATION_COUNT]; 89 | 90 | bool granted_voip; 91 | uint8_t voip_granted_by_station[jaldimac::STATION_COUNT]; 92 | jaldimac::VoIPSlotPayload voip_granted; 93 | uint32_t bulk_granted_bytes[jaldimac::STATION_COUNT]; 94 | uint32_t bulk_granted_upstream_bytes[jaldimac::STATION_COUNT]; 95 | 96 | uint32_t rate_limit_distance_us; 97 | timeval rate_limit_until; 98 | Timer timer; 99 | }; 100 | 101 | CLICK_ENDDECLS 102 | #endif 103 | -------------------------------------------------------------------------------- /click/elements/JaldiVoIPDemux.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * JaldiVoIPDemux.{cc,hh} -- demultiplexes VoIP flows 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "Frame.hh" 13 | #include "JaldiVoIPDemux.hh" 14 | 15 | using namespace jaldimac; 16 | 17 | CLICK_DECLS 18 | 19 | JaldiVoIPDemux::JaldiVoIPDemux() : timeout_s(3) 20 | { 21 | } 22 | 23 | JaldiVoIPDemux::~JaldiVoIPDemux() 24 | { 25 | } 26 | 27 | int JaldiVoIPDemux::configure(Vector& conf, ErrorHandler* errh) 28 | { 29 | // Parse configuration parameters 30 | if (cp_va_kparse(conf, this, errh, 31 | "TIMEOUT", cpkP+cpkM, cpUnsigned, &timeout_s, 32 | cpEnd) < 0) 33 | return -1; 34 | 35 | // Check that we have the right number of output ports 36 | if (noutputs() < int(FLOWS_PER_VOIP_SLOT + 1) || noutputs() > int(FLOWS_PER_VOIP_SLOT + 2)) 37 | return errh->error("wrong number of output ports; need either %<%d%> or %<%d%>", FLOWS_PER_VOIP_SLOT + 1, FLOWS_PER_VOIP_SLOT + 2); 38 | 39 | // Looks good! 40 | return 0; 41 | } 42 | 43 | void JaldiVoIPDemux::push(int, Packet* p) 44 | { 45 | time_t current_time = time(NULL); 46 | 47 | // Get destination IP and port of this packet 48 | if (! p->has_network_header()) 49 | { 50 | checked_output_push(out_port_bad, p); 51 | return; 52 | } 53 | 54 | const in_addr dest_ip = p->ip_header()->ip_dst; 55 | 56 | if (! p->ip_header()->ip_p == IP_PROTO_UDP) 57 | { 58 | checked_output_push(out_port_bad, p); 59 | return; 60 | } 61 | 62 | uint16_t dest_port = p->udp_header()->uh_dport; 63 | 64 | // Check for an output port already assigned to this 2-tuple 65 | for (unsigned i = 0 ; i < FLOWS_PER_VOIP_SLOT ; ++i) 66 | { 67 | if (output_ip[i] == dest_ip && output_port[i] == dest_port) 68 | { 69 | output_last_seen[i] = current_time; 70 | output(i).push(p); 71 | return; 72 | } 73 | } 74 | 75 | // Try to find an expired output port to reclaim 76 | for (unsigned i = 0 ; i < FLOWS_PER_VOIP_SLOT ; ++i) 77 | { 78 | if (difftime(current_time, output_last_seen[i]) > timeout_s) 79 | { 80 | output_ip[i] = dest_ip; 81 | output_port[i] = dest_port; 82 | output_last_seen[i] = current_time; 83 | output(i).push(p); 84 | return; 85 | } 86 | } 87 | 88 | // All output ports are claimed! We have to send it out the overflow port 89 | output(out_port_voip_overflow); 90 | } 91 | 92 | CLICK_ENDDECLS 93 | ELEMENT_REQUIRES(Frame) 94 | EXPORT_ELEMENT(JaldiVoIPDemux) 95 | -------------------------------------------------------------------------------- /click/elements/JaldiVoIPDemux.hh: -------------------------------------------------------------------------------- 1 | #ifndef CLICK_JALDIVOIPDEMUX_HH 2 | #define CLICK_JALDIVOIPDEMUX_HH 3 | #include 4 | #include "Frame.hh" 5 | CLICK_DECLS 6 | 7 | /* 8 | =c 9 | 10 | JaldiVoIPDemux(TIMEOUT) 11 | 12 | =s jaldi 13 | 14 | demultiplexes VoIP flows 15 | 16 | =d 17 | 18 | JaldiVoIPDemux demultiplexes a stream of incoming VoIP packets into individual 19 | flows. It identifies flows using a combination of destination IP address and 20 | port. It only tracks a limited number of flows at a time; additional flows are 21 | all directed to an "overflow" output. Since flows may start and stop at any 22 | time, JaldiVoIPDemux will forget about flows it has not received a packet for 23 | in TIMEOUT seconds, freeing the corresponding output to be used by another 24 | flow. 25 | 26 | The first and only input, which is push, receives IP packets which are presumed 27 | to have been classified as VoIP by an upstream classifier. 28 | 29 | The outputs are all push. The number of outputs is equal to the number of flows 30 | that can fit into a VoIP slot, plus an extra overflow output and an optional 31 | additoinal port for bad packets. Though it is not required, it makes sense that 32 | each output would be connected to a short, drop-front queue. (Since stale VoIP 33 | packets are essentially useless.) 34 | 35 | =a 36 | 37 | JaldiEncap, JaldiDecap, JaldiGate */ 38 | 39 | struct in_addr; 40 | 41 | class JaldiVoIPDemux : public Element { public: 42 | 43 | JaldiVoIPDemux(); 44 | ~JaldiVoIPDemux(); 45 | 46 | const char* class_name() const { return "JaldiVoIPDemux"; } 47 | const char* port_count() const { return "1/1-"; } 48 | const char* processing() const { return PUSH; } 49 | const char* flow_code() const { return COMPLETE_FLOW; } 50 | 51 | int configure(Vector&, ErrorHandler*); 52 | bool can_live_reconfigure() const { return true; } 53 | 54 | void push(int, Packet*); 55 | 56 | private: 57 | static const int in_port = 0; 58 | static const int out_port_voip_overflow = jaldimac::FLOWS_PER_VOIP_SLOT; 59 | static const int out_port_bad = jaldimac::FLOWS_PER_VOIP_SLOT + 1; 60 | 61 | uint32_t timeout_s; 62 | in_addr output_ip[jaldimac::FLOWS_PER_VOIP_SLOT]; 63 | uint16_t output_port[jaldimac::FLOWS_PER_VOIP_SLOT]; 64 | time_t output_last_seen[jaldimac::FLOWS_PER_VOIP_SLOT]; 65 | }; 66 | 67 | CLICK_ENDDECLS 68 | #endif 69 | -------------------------------------------------------------------------------- /click/elements/Makefile.in: -------------------------------------------------------------------------------- 1 | SHELL = @SHELL@ 2 | 3 | 4 | # THESE VARIABLES MAY CHANGE BETWEEN PACKAGES 5 | 6 | # Set 'package' to the name of your package. 7 | package := @CLICKPACKAGENAME@ 8 | 9 | # Set these variables appropriately. 10 | top_builddir := . 11 | subdir := . 12 | 13 | # Require Click prefix settings. 14 | # Generally, you will provide a '--with-click=CLICKPREFIX' option, and set: 15 | include @clickdatadir@/config.mk 16 | 17 | # Set 'MAKE_UPACKAGE', 'MAKE_KPACKAGE', and 'MAKE_BPACKAGE' to '0' or '1' 18 | # to determine whether to build userlevel, linuxmodule, and bsdmodule 19 | # packages, respectively. 20 | MAKE_UPACKAGE = @BUILD_USERLEVEL@ 21 | MAKE_KPACKAGE = @BUILD_LINUXMODULE@ 22 | MAKE_BPACKAGE = @BUILD_BSDMODULE@ 23 | 24 | # Set 'STRIP_UPACKAGE' to 'strip -g' to strip debugging symbols from the 25 | # userlevel package before installing. 26 | #STRIP_UPACKAGE = $(STRIP) -g 27 | 28 | # Set these variables as required. 29 | DEFS = @DEFS@ $(CLICKDEFS) 30 | INCLUDES = -I. -I$(top_builddir) -I$(srcdir) $(CLICKINCLUDES) 31 | 32 | # Set this variable to force 'click-elem2package' to include a header, 33 | # such as your package's '', if necessary. 34 | #ELEM2PACKAGE_INCLUDES = -i'' 35 | 36 | # END OF VARIABLES THAT MAY CHANGE BETWEEN PACKAGES 37 | 38 | 39 | # Everything below here will probably stay unchanged 40 | 41 | srcdir = @srcdir@ 42 | top_srcdir = @top_srcdir@ 43 | 44 | ifeq ($(CLICK_PACKAGE_MAKING),) 45 | prefix = @prefix@ 46 | exec_prefix = @exec_prefix@ 47 | bindir = @bindir@ 48 | sbindir = @sbindir@ 49 | libdir = @libdir@ 50 | mandir = @mandir@ 51 | datarootdir = @datarootdir@ 52 | datadir = @datadir@ 53 | endif 54 | 55 | include $(clickdatadir)/pkg-Makefile 56 | -------------------------------------------------------------------------------- /click/elements/configure.ac: -------------------------------------------------------------------------------- 1 | dnl -*- mode: shell-script -*- 2 | dnl 'configure.ac' file for the JaldiMAC Click package. 3 | dnl Process this file with autoconf to produce a configure script. 4 | dnl 5 | dnl Permission is hereby granted, free of charge, to any person obtaining a 6 | dnl copy of this software and associated documentation files (the "Software"), 7 | dnl to deal in the Software without restriction, subject to the conditions 8 | dnl listed in the Click LICENSE file. These conditions include: you must 9 | dnl preserve this copyright notice, and you cannot mention the copyright 10 | dnl holders in advertising related to the Software without their permission. 11 | dnl The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 12 | dnl notice is a summary of the Click LICENSE file; the license in that file is 13 | dnl legally binding. 14 | 15 | dnl 16 | dnl the usual 'configure.ac' boilerplate 17 | dnl 18 | 19 | AC_INIT(click-jaldimac, 1.0.0) 20 | AC_SUBST(ac_configure_args) 21 | 22 | CLICKPACKAGENAME=jaldi 23 | AC_SUBST(CLICKPACKAGENAME) 24 | 25 | 26 | dnl 27 | dnl locate Click install directory 28 | dnl 29 | 30 | AC_ARG_WITH(click, [ --with-click[[=DIR]] Click install path is DIR [[PREFIX]]], 31 | [clickprefix=$withval; if test -z "$withval" -o "$withval" = yes; then clickprefix=$prefix; fi], 32 | clickprefix=NONE) 33 | 34 | dnl Preset $prefix and $exec_prefix. 35 | test "x$prefix" = xNONE && prefix=$ac_default_prefix 36 | test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' 37 | test "x$clickprefix" != xNONE -a "x$prefix" = xNONE && prefix="$clickprefix" 38 | test "x$clickprefix" = xNONE && clickprefix="$prefix" 39 | 40 | clickdatadir="${clickprefix}/share/click" 41 | 42 | if test ! -r $clickdatadir/config.mk; then 43 | AC_MSG_ERROR([ 44 | ============================================== 45 | 46 | '$clickdatadir/config.mk' not found. 47 | Are you sure '$clickprefix' is a Click install directory? 48 | 49 | ==============================================]) 50 | fi 51 | 52 | . $clickdatadir/config.mk 53 | 54 | AC_SUBST(clickprefix) 55 | AC_SUBST(clickbindir) 56 | AC_SUBST(clicksbindir) 57 | AC_SUBST(clickdatadir) 58 | 59 | 60 | dnl 61 | dnl build userlevel? Linux module? FreeBSD module? 62 | dnl 63 | 64 | onezero () { 65 | { [[ "$1" = yes ]] && echo 1; } || echo 0 66 | } 67 | 68 | AC_ARG_ENABLE(userlevel, [ --enable-userlevel enable user-level driver], 69 | [BUILD_USERLEVEL=`onezero $enableval`], 70 | [BUILD_USERLEVEL=$CLICK_HAVE_USERLEVEL_DRIVER]) 71 | AC_ARG_ENABLE(linuxmodule, [ --enable-linuxmodule enable Linux kernel driver], 72 | [BUILD_LINUXMODULE=`onezero $enableval`], 73 | [BUILD_LINUXMODULE=$CLICK_HAVE_LINUXMODULE_DRIVER]) 74 | AC_ARG_ENABLE(bsdmodule, [ --enable-bsdmodule enable FreeBSD kernel driver 75 | [[Default drivers are those Click supports.]]], 76 | [BUILD_BSDMODULE=`onezero $enableval`], 77 | [BUILD_BSDMODULE=$CLICK_HAVE_BSDMODULE_DRIVER]) 78 | 79 | AC_SUBST(BUILD_USERLEVEL) 80 | AC_SUBST(BUILD_LINUXMODULE) 81 | AC_SUBST(BUILD_BSDMODULE) 82 | 83 | 84 | dnl 85 | dnl Output 86 | dnl 87 | 88 | AC_OUTPUT(Makefile) 89 | -------------------------------------------------------------------------------- /kerneldriver/Kconfig: -------------------------------------------------------------------------------- 1 | config JALDI 2 | tristate "Atheros 802.11n wireless cards support" 3 | depends on PCI 4 | ---help--- 5 | This is the Jaldi module. 6 | -------------------------------------------------------------------------------- /kerneldriver/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := jaldi.o 2 | jaldi-objs := \ 3 | main.o \ 4 | ahb.o \ 5 | pci.o \ 6 | phy.o \ 7 | eeprom.o \ 8 | eeprom_def.o \ 9 | init.o \ 10 | hw.o \ 11 | debug.o 12 | 13 | PWD := $(shell pwd) 14 | 15 | default: 16 | $(MAKE) -C $(KLIB_BUILD) M=$(PWD) modules 17 | -------------------------------------------------------------------------------- /kerneldriver/ahb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "jaldi.h" 5 | 6 | static void jaldi_ahb_read_cachesize(struct jaldi_softc *sc, int *csz) { 7 | *csz = L1_CACHE_BYTES >> 2; 8 | } 9 | 10 | 11 | static bool jaldi_ahb_eeprom_read(struct jaldi_softc *sc, u32 off, u16 *data) 12 | { 13 | jaldi_print(JALDI_DEBUG,"Entering '%s'\n", __FUNCTION__); 14 | struct platform_device *pdev = to_platform_device(sc->dev); 15 | struct ath9k_platform_data *pdata; // making use of linux/ath9k_platform 16 | 17 | pdata = (struct ath9k_platform_data *) pdev->dev.platform_data; 18 | if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { 19 | jaldi_print(JALDI_FATAL, 20 | "%s: flash read failed, offset %08x " 21 | "is out of range\n", 22 | __func__, off); 23 | return false; 24 | } 25 | 26 | *data = pdata->eeprom_data[off]; 27 | return true; 28 | } 29 | 30 | static struct jaldi_bus_ops jaldi_ahb_bus_ops = { 31 | .type = JALDI_AHB, 32 | .read_cachesize = jaldi_ahb_read_cachesize, 33 | .eeprom_read = jaldi_ahb_eeprom_read, 34 | }; 35 | 36 | static int jaldi_ahb_probe(struct platform_device *pdev) { 37 | void __iomem *mem; 38 | struct jaldi_softc *sc; 39 | struct net_device *jaldi_dev; 40 | struct resource *res; 41 | int irq; 42 | int ret = 0; 43 | struct jaldi_hw *hw; 44 | //char hw_name[64]; 45 | 46 | jaldi_print(JALDI_DEBUG,"Entering '%s'\n", __FUNCTION__); 47 | if (!pdev->dev.platform_data) { 48 | dev_err(&pdev->dev, "no platform data specified\n"); 49 | ret = -EINVAL; 50 | goto err_out; 51 | } 52 | 53 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 54 | if (res == NULL) { 55 | dev_err(&pdev->dev, "no memory resource found\n"); 56 | ret = -ENXIO; 57 | goto err_out; 58 | } 59 | 60 | mem = ioremap_nocache(res->start, res->end - res->start + 1); 61 | if (mem == NULL) { 62 | dev_err(&pdev->dev, "ioremap failed\n"); 63 | ret = -ENOMEM; 64 | goto err_out; 65 | } 66 | 67 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 68 | if (res == NULL) { 69 | dev_err(&pdev->dev, "no IRQ resource found\n"); 70 | ret = -ENXIO; 71 | goto err_iounmap; 72 | } 73 | 74 | irq = res->start; 75 | 76 | /* allocate and register net_dev, also allocs softc */ 77 | jaldi_dev = jaldi_init_netdev(); 78 | 79 | if (jaldi_dev < 0) { 80 | jaldi_print(JALDI_FATAL, "could not init netdev\n"); 81 | goto err_iounmap; 82 | } 83 | 84 | sc = netdev_priv(jaldi_dev); 85 | 86 | if (!sc) { 87 | dev_err(&pdev->dev, "no memory for jaldi_softc\n"); 88 | ret = -ENOMEM; 89 | goto err_no_softc; 90 | } 91 | 92 | platform_set_drvdata(pdev,sc); 93 | sc->dev = &pdev->dev; 94 | sc->mem = mem; 95 | sc->irq = irq; 96 | 97 | // irq not ready, this is cleared during init (ath9k_start?) 98 | sc->sc_flags |= SC_OP_INVALID; 99 | 100 | ret = request_irq(irq, jaldi_isr, IRQF_SHARED, "jaldi", sc); 101 | if (ret) { 102 | dev_err(&pdev->dev, "request_irq failed\n"); 103 | goto err_free_hw; 104 | } 105 | 106 | ret = jaldi_init_device(AR5416_AR9100_DEVID, sc, 0x0, &jaldi_ahb_bus_ops); 107 | if (ret) { 108 | dev_err(&pdev->dev, "failed to initialize device\n"); 109 | goto err_irq; 110 | } 111 | 112 | hw = sc->hw; // pointer to jaldi_hw struct 113 | //jaldi_hw_name(hw, hw_name, sizeof(hw_name)); // TODO 114 | //printk(KERN_INFO "jaldi: %s mem=0x%1x, irq=%d\n", hw_name, (unsigned long)mem, irq); 115 | 116 | 117 | /* alright let's do this */ 118 | ret = jaldi_start_netdev(sc); 119 | if (ret) { 120 | jaldi_print(JALDI_FATAL, "Failed to register netdev\n"); 121 | goto err_start; 122 | } 123 | 124 | return 0; 125 | 126 | err_start: 127 | jaldi_deinit_device(sc); 128 | err_irq: 129 | free_irq(irq, sc); 130 | err_free_hw: 131 | platform_set_drvdata(pdev, NULL); 132 | err_no_softc: 133 | free_netdev(jaldi_dev); 134 | err_iounmap: 135 | iounmap(mem); 136 | err_out: 137 | return ret; 138 | }; 139 | 140 | static int jaldi_ahb_remove(struct platform_device *pdev) { 141 | jaldi_print(JALDI_DEBUG,"Entering '%s'\n", __FUNCTION__); 142 | struct jaldi_softc *sc = platform_get_drvdata(pdev); 143 | 144 | if (sc) { 145 | void __iomem *mem = sc->mem; 146 | 147 | unregister_netdev(sc->net_dev); 148 | 149 | jaldi_deinit_device(sc); 150 | free_irq(sc->irq, sc); 151 | 152 | free_netdev(sc->net_dev); 153 | 154 | iounmap(mem); 155 | platform_set_drvdata(pdev,NULL); 156 | } 157 | 158 | return 0; 159 | } 160 | 161 | // standard linux platform_driver stuff 162 | static struct platform_driver jaldi_ahb_driver = { 163 | .probe = jaldi_ahb_probe, 164 | .remove = jaldi_ahb_remove, 165 | .driver = { 166 | .name = "jaldi", 167 | .owner = THIS_MODULE, 168 | }, 169 | }; 170 | 171 | int jaldi_ahb_init(void) { 172 | jaldi_print(JALDI_DEBUG,"Entering '%s'\n", __FUNCTION__); 173 | return platform_driver_register(&jaldi_ahb_driver); 174 | } 175 | 176 | void jaldi_ahb_exit(void) { 177 | jaldi_print(JALDI_DEBUG,"Entering '%s'\n", __FUNCTION__); 178 | platform_driver_unregister(&jaldi_ahb_driver); 179 | } 180 | -------------------------------------------------------------------------------- /kerneldriver/debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Jaldi debugging 3 | */ 4 | 5 | #include "jaldi.h" 6 | 7 | void jaldi_print(int level, const char *fmt, ...) 8 | { 9 | va_list args; 10 | 11 | if (JALDI_DEBUG_ON && level <= JALDI_DEBUG_LEVEL) { 12 | va_start(args, fmt); 13 | printk(KERN_EMERG "jaldi [%d]: ", level); 14 | vprintk(fmt, args); 15 | va_end(args); 16 | } 17 | } 18 | 19 | void jaldi_print_skb(struct sk_buff *skb) 20 | { 21 | int i; 22 | char str[3500]; 23 | char *pStr = str; 24 | 25 | for (i=0; i < skb->len && pStr < str+3900; i++) { 26 | sprintf(pStr,"%02x", skb->data[i]); 27 | pStr+=2; 28 | 29 | if( (i+1)%8 == 0){ 30 | sprintf(pStr," "); 31 | pStr++; 32 | } 33 | 34 | if( (i+1)%32 == 0){ 35 | sprintf(pStr,"\n"); 36 | pStr++; 37 | } 38 | } 39 | 40 | jaldi_print(JALDI_DEBUG, "%s\n", str); 41 | } 42 | 43 | static int jaldi_debugfs_open(struct inode *inode, struct file *file) 44 | { 45 | file->private_data = inode->i_private; 46 | return 0; 47 | } 48 | 49 | static ssize_t read_file_profile(struct file *file, char __user *user_buf, 50 | size_t count, loff_t *ppos) 51 | { 52 | struct jaldi_softc *sc = file->private_data; 53 | char *buf; 54 | unsigned int len = 0, size = 8192; 55 | ssize_t retval = 0; 56 | int i,j; 57 | 58 | buf = kzalloc(size, GFP_KERNEL); 59 | if (buf == NULL) 60 | return -ENOMEM; 61 | for(i=0; i < 2048 && i < sc->debug.actual_tx_idx-1; i++) { 62 | // printk(KERN_EMERG "loop da loop i:%d idx:%d\n", i, sc->debug.actual_tx_idx); 63 | len += snprintf(buf + len, size - len, "%s %d: %lld\n", 64 | "Actual TX Start", i, sc->debug.actual_tx_times[i]); 65 | } 66 | 67 | for(i=0; i < 2048 && i < sc->debug.intended_tx_idx-1; i++) { 68 | len += snprintf(buf + len, size - len, "%s %d: %lld\n", 69 | "Intended TX Start", i, sc->debug.intended_tx_times[i]); 70 | } 71 | if (len > size) 72 | len = size; 73 | 74 | retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); 75 | kfree(buf); 76 | 77 | return retval; 78 | } 79 | 80 | static const struct file_operations fops_profiling = { 81 | .read = read_file_profile, 82 | .open = jaldi_debugfs_open, 83 | .owner = THIS_MODULE 84 | }; 85 | 86 | int jaldi_init_debug(struct jaldi_hw *hw) 87 | { 88 | struct jaldi_softc *sc = hw->sc; 89 | 90 | if (!jaldi_debugfs_root) 91 | return -ENOENT; 92 | 93 | memset(&sc->debug, 0, sizeof(struct jaldi_debug)); 94 | OHAI; 95 | sc->debug.debugfs = debugfs_create_dir("jaldi", 96 | jaldi_debugfs_root); 97 | OHAI; 98 | if (!sc->debug.debugfs) 99 | return -ENOMEM; 100 | 101 | OHAI; 102 | if (!debugfs_create_file("profile", S_IRUSR, 103 | sc->debug.debugfs, sc, &fops_profiling)) 104 | goto err; 105 | OHAI; 106 | 107 | sc->debug.regidx = 0; 108 | return 0; 109 | err: 110 | jaldi_exit_debug(hw); 111 | return -ENOMEM; 112 | } 113 | 114 | void jaldi_exit_debug(struct jaldi_hw *hw) 115 | { 116 | struct jaldi_softc *sc = (struct jaldi_softc *) hw->sc; 117 | 118 | debugfs_remove_recursive(sc->debug.debugfs); 119 | } 120 | EXPORT_SYMBOL(jaldi_exit_debug); 121 | 122 | int jaldi_debug_create_root(void) 123 | { 124 | jaldi_debugfs_root = debugfs_create_dir("jaldi", NULL); 125 | if (!jaldi_debugfs_root) 126 | return -ENOENT; 127 | 128 | return 0; 129 | } 130 | 131 | void jaldi_debug_remove_root(void) 132 | { 133 | debugfs_remove(jaldi_debugfs_root); 134 | jaldi_print(JALDI_INFO, "removed debugfs\n"); 135 | jaldi_debugfs_root = NULL; 136 | } 137 | -------------------------------------------------------------------------------- /kerneldriver/debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Jaldi Debugging 3 | * 4 | * Originally based on ath's debug. 5 | */ 6 | 7 | #ifndef JALDI_DEBUG_H 8 | #define JALDI_DEBUG_H 9 | 10 | #include 11 | #include "jaldi.h" 12 | 13 | #define JALDI_DEBUG_ON 1 14 | #define WHERESTR "[file %s, line %d]: " 15 | #define WHEREARG __FILE__, __LINE__ 16 | #define DBG_START_MSG jaldi_print(JALDI_DEBUG,"---> Entering '%s' [file %s, line %d]\n", __FUNCTION__, WHEREARG) 17 | #define DBG_END_MSG jaldi_print(JALDI_DEBUG,"<--- Exiting '%s' [file %s, line %d]\n", __FUNCTION__, WHEREARG) 18 | #define OHAI jaldi_print(JALDI_DEBUG,"OHAI! %s [file %s, line %d]\n", __FUNCTION__, WHEREARG) 19 | 20 | enum JALDI_DEBUG_LEVEL { 21 | JALDI_FATAL = 0, 22 | JALDI_WARN = 1, 23 | JALDI_ALERT = 2, 24 | JALDI_INFO = 3, 25 | JALDI_DEBUG = 4, 26 | }; 27 | 28 | struct jaldi_debug { 29 | struct dentry *debugfs; 30 | u32 regidx; 31 | struct timespec ts; 32 | int actual_tx_idx; 33 | int intended_tx_idx; 34 | s64 actual_tx_times[2048]; 35 | s64 intended_tx_times[2048]; 36 | }; 37 | 38 | 39 | static struct dentry *jaldi_debugfs_root; 40 | 41 | int jaldi_init_debug(struct jaldi_hw *hw); 42 | void jaldi_exit_debug(struct jaldi_hw *hw); 43 | int jaldi_debug_create_root(void); 44 | void jaldi_debug_remove_root(void); 45 | 46 | void jaldi_print_skb(struct sk_buff *skb); 47 | 48 | void jaldi_print(int level, const char *fmt, ...) 49 | __attribute__ ((format (printf, 2, 3))); 50 | 51 | #define JALDI_DEBUG_LEVEL JALDI_FATAL 52 | 53 | #endif /* JALDI_DEBUG_H */ 54 | -------------------------------------------------------------------------------- /kerneldriver/eeprom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "jaldi.h" 18 | 19 | static inline u16 jaldi_hw_fbin2freq(u8 fbin, bool is2GHz) 20 | { 21 | if (fbin == AR5416_BCHAN_UNUSED) 22 | return fbin; 23 | 24 | return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); 25 | } 26 | 27 | void jaldi_hw_analog_shift_regwrite(struct jaldi_hw *hw, u32 reg, u32 val) 28 | { 29 | REG_WRITE(hw, reg, val); 30 | 31 | if (hw->analog_shiftreg) 32 | udelay(100); 33 | } 34 | 35 | void jaldi_hw_analog_shift_rmw(struct jaldi_hw *hw, u32 reg, u32 mask, 36 | u32 shift, u32 val) 37 | { 38 | u32 regVal; 39 | 40 | regVal = REG_READ(hw, reg) & ~mask; 41 | regVal |= (val << shift) & mask; 42 | 43 | REG_WRITE(hw, reg, regVal); 44 | 45 | if (hw->analog_shiftreg) 46 | udelay(100); 47 | } 48 | 49 | int16_t jaldi_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, 50 | int16_t targetLeft, int16_t targetRight) 51 | { 52 | int16_t rv; 53 | 54 | if (srcRight == srcLeft) { 55 | rv = targetLeft; 56 | } else { 57 | rv = (int16_t) (((target - srcLeft) * targetRight + 58 | (srcRight - target) * targetLeft) / 59 | (srcRight - srcLeft)); 60 | } 61 | return rv; 62 | } 63 | 64 | bool jaldi_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, 65 | u16 *indexL, u16 *indexR) 66 | { 67 | u16 i; 68 | 69 | if (target <= pList[0]) { 70 | *indexL = *indexR = 0; 71 | return true; 72 | } 73 | if (target >= pList[listSize - 1]) { 74 | *indexL = *indexR = (u16) (listSize - 1); 75 | return true; 76 | } 77 | 78 | for (i = 0; i < listSize - 1; i++) { 79 | if (pList[i] == target) { 80 | *indexL = *indexR = i; 81 | return true; 82 | } 83 | if (target < pList[i + 1]) { 84 | *indexL = i; 85 | *indexR = (u16) (i + 1); 86 | return false; 87 | } 88 | } 89 | return false; 90 | } 91 | 92 | bool jaldi_hw_nvram_read(struct jaldi_hw *hw, u32 off, u16 *data) 93 | { 94 | bool res = hw->bus_ops->eeprom_read(hw->sc, off, data); 95 | // jaldi_print(JALDI_DEBUG, "nvram_read mem: %lx offset: %8x, data: %4x\n", (unsigned long)hw->sc->hw->sc->mem, off, *data); 96 | return res; 97 | } 98 | 99 | void jaldi_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, 100 | u8 *pVpdList, u16 numIntercepts, 101 | u8 *pRetVpdList) 102 | { 103 | u16 i, k; 104 | u8 currPwr = pwrMin; 105 | u16 idxL = 0, idxR = 0; 106 | 107 | for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { 108 | jaldi_hw_get_lower_upper_index(currPwr, pPwrList, 109 | numIntercepts, &(idxL), 110 | &(idxR)); 111 | if (idxR < 1) 112 | idxR = 1; 113 | if (idxL == numIntercepts - 1) 114 | idxL = (u16) (numIntercepts - 2); 115 | if (pPwrList[idxL] == pPwrList[idxR]) 116 | k = pVpdList[idxL]; 117 | else 118 | k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + 119 | (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / 120 | (pPwrList[idxR] - pPwrList[idxL])); 121 | pRetVpdList[i] = (u8) k; 122 | currPwr += 2; 123 | } 124 | } 125 | 126 | void jaldi_hw_get_legacy_target_powers(struct jaldi_hw *hw, 127 | struct jaldi_channel *chan, 128 | struct cal_target_power_leg *powInfo, 129 | u16 numChannels, 130 | struct cal_target_power_leg *pNewPower, 131 | u16 numRates, bool isExtTarget) 132 | { 133 | struct chan_centers centers; 134 | u16 clo, chi; 135 | int i; 136 | int matchIndex = -1, lowIndex = -1; 137 | u16 freq; 138 | 139 | jaldi_hw_get_channel_centers(chan, ¢ers); 140 | freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; 141 | 142 | if (freq <= jaldi_hw_fbin2freq(powInfo[0].bChannel, 143 | IS_CHAN_2GHZ(chan))) { 144 | matchIndex = 0; 145 | } else { 146 | for (i = 0; (i < numChannels) && 147 | (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { 148 | if (freq == jaldi_hw_fbin2freq(powInfo[i].bChannel, 149 | IS_CHAN_2GHZ(chan))) { 150 | matchIndex = i; 151 | break; 152 | } else if (freq < jaldi_hw_fbin2freq(powInfo[i].bChannel, 153 | IS_CHAN_2GHZ(chan)) && i > 0 && 154 | freq > jaldi_hw_fbin2freq(powInfo[i - 1].bChannel, 155 | IS_CHAN_2GHZ(chan))) { 156 | lowIndex = i - 1; 157 | break; 158 | } 159 | } 160 | if ((matchIndex == -1) && (lowIndex == -1)) 161 | matchIndex = i - 1; 162 | } 163 | 164 | if (matchIndex != -1) { 165 | *pNewPower = powInfo[matchIndex]; 166 | } else { 167 | clo = jaldi_hw_fbin2freq(powInfo[lowIndex].bChannel, 168 | IS_CHAN_2GHZ(chan)); 169 | chi = jaldi_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, 170 | IS_CHAN_2GHZ(chan)); 171 | 172 | for (i = 0; i < numRates; i++) { 173 | pNewPower->tPow2x[i] = 174 | (u8)jaldi_hw_interpolate(freq, clo, chi, 175 | powInfo[lowIndex].tPow2x[i], 176 | powInfo[lowIndex + 1].tPow2x[i]); 177 | } 178 | } 179 | } 180 | 181 | void jaldi_hw_get_target_powers(struct jaldi_hw *hw, 182 | struct jaldi_channel *chan, 183 | struct cal_target_power_ht *powInfo, 184 | u16 numChannels, 185 | struct cal_target_power_ht *pNewPower, 186 | u16 numRates, bool isHt40Target) 187 | { 188 | struct chan_centers centers; 189 | u16 clo, chi; 190 | int i; 191 | int matchIndex = -1, lowIndex = -1; 192 | u16 freq; 193 | 194 | jaldi_hw_get_channel_centers(chan, ¢ers); 195 | freq = isHt40Target ? centers.synth_center : centers.ctl_center; 196 | 197 | if (freq <= jaldi_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { 198 | matchIndex = 0; 199 | } else { 200 | for (i = 0; (i < numChannels) && 201 | (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { 202 | if (freq == jaldi_hw_fbin2freq(powInfo[i].bChannel, 203 | IS_CHAN_2GHZ(chan))) { 204 | matchIndex = i; 205 | break; 206 | } else 207 | if (freq < jaldi_hw_fbin2freq(powInfo[i].bChannel, 208 | IS_CHAN_2GHZ(chan)) && i > 0 && 209 | freq > jaldi_hw_fbin2freq(powInfo[i - 1].bChannel, 210 | IS_CHAN_2GHZ(chan))) { 211 | lowIndex = i - 1; 212 | break; 213 | } 214 | } 215 | if ((matchIndex == -1) && (lowIndex == -1)) 216 | matchIndex = i - 1; 217 | } 218 | 219 | if (matchIndex != -1) { 220 | *pNewPower = powInfo[matchIndex]; 221 | } else { 222 | clo = jaldi_hw_fbin2freq(powInfo[lowIndex].bChannel, 223 | IS_CHAN_2GHZ(chan)); 224 | chi = jaldi_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, 225 | IS_CHAN_2GHZ(chan)); 226 | 227 | for (i = 0; i < numRates; i++) { 228 | pNewPower->tPow2x[i] = (u8)jaldi_hw_interpolate(freq, 229 | clo, chi, 230 | powInfo[lowIndex].tPow2x[i], 231 | powInfo[lowIndex + 1].tPow2x[i]); 232 | } 233 | } 234 | } 235 | 236 | u16 jaldi_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, 237 | bool is2GHz, int num_band_edges) 238 | { 239 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; 240 | int i; 241 | 242 | for (i = 0; (i < num_band_edges) && 243 | (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { 244 | if (freq == jaldi_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { 245 | twiceMaxEdgePower = pRdEdgesPower[i].tPower; 246 | break; 247 | } else if ((i > 0) && 248 | (freq < jaldi_hw_fbin2freq(pRdEdgesPower[i].bChannel, 249 | is2GHz))) { 250 | if (jaldi_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, 251 | is2GHz) < freq && 252 | pRdEdgesPower[i - 1].flag) { 253 | twiceMaxEdgePower = 254 | pRdEdgesPower[i - 1].tPower; 255 | } 256 | break; 257 | } 258 | } 259 | 260 | return twiceMaxEdgePower; 261 | } 262 | 263 | int jaldi_hw_eeprom_init(struct jaldi_hw *hw) 264 | { 265 | int status; 266 | 267 | if (AR_SREV_9300_20_OR_LATER(hw)) { 268 | jaldi_print(JALDI_DEBUG, "eeprom ar9300\n"); 269 | // hw->eep_ops = &eep_ar9300_ops; 270 | } else if (AR_SREV_9287(hw)) { 271 | jaldi_print(JALDI_DEBUG, "eeprom ar9287\n"); 272 | // hw->eep_ops = &eep_ar9287_ops; 273 | } else if (AR_SREV_9285(hw) || AR_SREV_9271(hw)) { 274 | jaldi_print(JALDI_DEBUG, "eeprom 4k\n"); 275 | // hw->eep_ops = &eep_4k_ops; 276 | } else { 277 | jaldi_print(JALDI_DEBUG, "eeprom def\n"); 278 | hw->eep_ops = &eep_def_ops; 279 | } 280 | 281 | if (!hw->eep_ops->fill_eeprom(hw)) 282 | return -EIO; 283 | 284 | status = hw->eep_ops->check_eeprom(hw); 285 | 286 | return status; 287 | } 288 | -------------------------------------------------------------------------------- /kerneldriver/hw.h: -------------------------------------------------------------------------------- 1 | /* deals with hw; bare-bones implementation of ath9k_hw 2 | * 3 | * TODO: 4 | * - Bus operations (init/deinit) 5 | * - Firmware loading? 6 | * - PHY (channels, power, interface for manipulating hardware) 7 | */ 8 | 9 | #ifndef HW_H 10 | #define HW_H 11 | 12 | #include "reg.h" 13 | #include "eeprom.h" 14 | #include "phy.h" 15 | #include "mac.h" 16 | 17 | 18 | #define ATHEROS_VENDOR_ID 0x168c 19 | 20 | #define AR5416_DEVID_PCI 0x0023 21 | #define AR5416_DEVID_PCIE 0x0024 22 | #define AR9160_DEVID_PCI 0x0027 23 | #define AR9280_DEVID_PCI 0x0029 24 | #define AR9280_DEVID_PCIE 0x002a 25 | #define AR9285_DEVID_PCIE 0x002b 26 | #define AR2427_DEVID_PCIE 0x002c 27 | #define AR9287_DEVID_PCI 0x002d 28 | #define AR9287_DEVID_PCIE 0x002e 29 | #define AR9300_DEVID_PCIE 0x0030 30 | 31 | #define AR5416_AR9100_DEVID 0x000b 32 | 33 | #define AR_SUBVENDOR_ID_NOG 0x0e11 34 | #define AR_SUBVENDOR_ID_NEW_A 0x7065 35 | #define AR5416_MAGIC 0x19641014 36 | 37 | #define DEFAULT_CACHELINE 32 38 | 39 | #define JALDI_AMPDU_LIMIT_MAX (64 * 1024 - 1) /* Not doing frame agg... */ 40 | #define JALDI_DEFAULT_NOISE_FLOOR -95 41 | #define JALDI_RSSI_BAD -128 42 | #define JALDI_WAIT_TIMEOUT 100000 /* (us) */ 43 | #define JALDI_TIME_QUANTUM 10 44 | #define POWER_UP_TIME 10000 45 | #define SPUR_RSSI_THRESH 40 46 | 47 | #define MAX_RATE_POWER 63 48 | 49 | #define JALDI_CLOCK_RATE_CCK 22 50 | #define JALDI_CLOCK_RATE_5GHZ_OFDM 40 51 | #define JALDI_CLOCK_RATE_2GHZ_OFDM 44 52 | #define JALDI_CLOCK_FAST_RATE_5GHZ_OFDM 44 53 | 54 | 55 | /* Register operation macros */ 56 | #define REG_WRITE(_hw, _reg, _val) \ 57 | (_hw)->reg_ops->write((_hw), (_val), (_reg)) 58 | 59 | #define REG_READ(_hw, _reg) \ 60 | (_hw)->reg_ops->read((_hw), (_reg)) 61 | 62 | #define ENABLE_REGWRITE_BUFFER(_hw) \ 63 | do { \ 64 | if (AR_SREV_9271(_hw)) \ 65 | (_hw)->reg_ops->enable_write_buffer((_hw)); \ 66 | } while (0) 67 | 68 | #define DISABLE_REGWRITE_BUFFER(_hw) \ 69 | do { \ 70 | if (AR_SREV_9271(_hw)) \ 71 | (_hw)->reg_ops->disable_write_buffer((_hw)); \ 72 | } while (0) 73 | 74 | #define REGWRITE_BUFFER_FLUSH(_hw) \ 75 | do { \ 76 | if (AR_SREV_9271(_hw)) \ 77 | (_hw)->reg_ops->write_flush((_hw)); \ 78 | } while (0) 79 | 80 | /* Shift and mask (and vice versa) 81 | * "_f##_S" appends an "_S" to the passed field name; reg.h contains shift 82 | * amounts for each field. */ 83 | #define SM(_v, _f) (((_v) << _f##_S) & _f) 84 | #define MS(_v, _f) (((_v) & _f) >> _f##_S) 85 | 86 | /* RMW: "Read modify write" */ 87 | #define REG_RMW(_a, _r, _set, _clr) \ 88 | REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set)) 89 | #define REG_RMW_FIELD(_a, _r, _f, _v) \ 90 | REG_WRITE(_a, _r, \ 91 | (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f)) 92 | #define REG_READ_FIELD(_a, _r, _f) \ 93 | (((REG_READ(_a, _r) & _f) >> _f##_S)) 94 | #define REG_SET_BIT(_a, _r, _f) \ 95 | REG_WRITE(_a, _r, REG_READ(_a, _r) | _f) 96 | #define REG_CLR_BIT(_a, _r, _f) \ 97 | REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f) 98 | 99 | #define DO_DELAY(x) do { \ 100 | if ((++(x) % 64) == 0) \ 101 | udelay(1); \ 102 | } while (0) 103 | 104 | #define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ 105 | int r; \ 106 | for (r = 0; r < ((iniarray)->ia_rows); r++) { \ 107 | REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ 108 | INI_RA((iniarray), r, (column))); \ 109 | DO_DELAY(regWr); \ 110 | } \ 111 | } while (0) 112 | 113 | // it's unclear what these do: document TODO 114 | #define SM(_v, _f) (((_v) << _f##_S) & _f) 115 | #define MS(_v, _f) (((_v) & _f) >> _f##_S) 116 | /* End register r/w macros */ 117 | 118 | 119 | #define CHANNEL_CCK 0x00020 120 | #define CHANNEL_OFDM 0x00040 121 | #define CHANNEL_2GHZ 0x00080 122 | #define CHANNEL_5GHZ 0x00100 123 | #define CHANNEL_PASSIVE 0x00200 124 | #define CHANNEL_DYN 0x00400 125 | #define CHANNEL_HALF 0x04000 126 | #define CHANNEL_QUARTER 0x08000 127 | #define CHANNEL_HT20 0x10000 128 | #define CHANNEL_HT40PLUS 0x20000 129 | #define CHANNEL_HT40MINUS 0x40000 130 | 131 | #define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) 132 | #define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) 133 | #define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) 134 | #define CHANNEL_G_HT20 (CHANNEL_2GHZ|CHANNEL_HT20) 135 | #define CHANNEL_A_HT20 (CHANNEL_5GHZ|CHANNEL_HT20) 136 | #define CHANNEL_G_HT40PLUS (CHANNEL_2GHZ|CHANNEL_HT40PLUS) 137 | #define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS) 138 | #define CHANNEL_A_HT40PLUS (CHANNEL_5GHZ|CHANNEL_HT40PLUS) 139 | #define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS) 140 | #define CHANNEL_ALL \ 141 | (CHANNEL_OFDM| \ 142 | CHANNEL_CCK| \ 143 | CHANNEL_2GHZ | \ 144 | CHANNEL_5GHZ | \ 145 | CHANNEL_HT20 | \ 146 | CHANNEL_HT40PLUS | \ 147 | CHANNEL_HT40MINUS) 148 | 149 | #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \ 150 | (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \ 151 | (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \ 152 | (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS)) 153 | #define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0) 154 | #define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) 155 | #define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) 156 | #define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0) 157 | #define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) 158 | #define IS_CHAN_A_FAST_CLOCK(_hw, _c) \ 159 | ((((_c)->channelFlags & CHANNEL_5GHZ) != 0) && \ 160 | ((_hw)->caps.hw_caps & JALDI_HW_CAP_FASTCLOCK)) 161 | 162 | /* Macros for checking chanmode */ 163 | #define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) 164 | #define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) 165 | #define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B) 166 | #define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_HT20)) 167 | #define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_HT40PLUS) || \ 168 | ((_c)->chanmode == CHANNEL_HT40MINUS)) 169 | #define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c))) 170 | 171 | #define BASE_ACTIVATE_DELAY 100 172 | #define RTC_PLL_SETTLE_DELAY 100 173 | #define INIT_CONFIG_STATUS 0x00000000 174 | #define INIT_RSSI_THR 0x00000700 175 | 176 | #define JALDI_HW_RX_HP_QDEPTH 16 177 | #define JALDI_HW_RX_LP_QDEPTH 128 178 | 179 | #define SPUR_DISABLE 0 180 | #define SPUR_ENABLE_IOCTL 1 181 | #define SPUR_ENABLE_EEPROM 2 182 | #define AR_EEPROM_MODAL_SPURS 5 183 | #define AR_SPUR_5413_1 1640 184 | #define AR_SPUR_5413_2 1200 185 | #define AR_NO_SPUR 0x8000 186 | #define AR_BASE_FREQ_2GHZ 2300 187 | #define AR_BASE_FREQ_5GHZ 4900 188 | #define AR_SPUR_FEEQ_BOUND_HT40 19 189 | #define AR_SPUR_FEEQ_BOUND_HT20 10 190 | 191 | /* tx fifo thresholds 192 | * Single stream device AR9285 and AR9271 require 2 KB 193 | * to work around a hardware issue, all other devices 194 | * have can use the max 4 KB limit. 195 | */ 196 | #define MIN_TX_FIFO_THRESHOLD 0x1 /* 64 byte increments */ 197 | #define MAX_TX_FIFO_THRESHOLD ((4096 / 64) - 1) /* 4KB */ 198 | 199 | /* calibration */ 200 | #define NUM_NF_READINGS 6 201 | 202 | enum jaldi_pkt_type; 203 | struct jaldi_softc; 204 | 205 | // closely based upon ath9k_hw_version (a9k/hw.h) 206 | struct jaldi_hw_version { 207 | u32 magic; 208 | u32 devid; 209 | u16 subvendorid; 210 | u32 macVersion; 211 | u16 macRev; 212 | u16 phyRev; 213 | u16 analog5GhzRev; 214 | u16 analog2GhzRev; // don't think this is needed for us... 215 | u16 subsysid; 216 | }; 217 | 218 | #define HT40_CHANNEL_CENTER_SHIFT 10 219 | // channel mode flags -- from ath9k, many not needed here 220 | #define CHANNEL_CW_INT 0x00002 221 | 222 | enum jaldi_intr_type { 223 | JALDI_INT_RX = 0x00000001, 224 | JALDI_INT_RXDESC = 0x00000002, 225 | JALDI_INT_RXHP = 0x00000001, 226 | JALDI_INT_RXLP = 0x00000002, 227 | JALDI_INT_RXNOFRM = 0x00000008, 228 | JALDI_INT_RXEOL = 0x00000010, 229 | JALDI_INT_RXORN = 0x00000020, 230 | JALDI_INT_TX = 0x00000040, 231 | JALDI_INT_TXDESC = 0x00000080, 232 | JALDI_INT_TIM_TIMER = 0x00000100, 233 | JALDI_INT_BB_WATCHDOG = 0x00000400, 234 | JALDI_INT_TXURN = 0x00000800, 235 | JALDI_INT_MIB = 0x00001000, 236 | JALDI_INT_RXPHY = 0x00004000, 237 | JALDI_INT_RXKCM = 0x00008000, 238 | JALDI_INT_SWBA = 0x00010000, 239 | JALDI_INT_BMISS = 0x00040000, 240 | JALDI_INT_BNR = 0x00100000, 241 | JALDI_INT_TIM = 0x00200000, 242 | JALDI_INT_DTIM = 0x00400000, 243 | JALDI_INT_DTIMSYNC = 0x00800000, 244 | JALDI_INT_GPIO = 0x01000000, 245 | JALDI_INT_CABEND = 0x02000000, 246 | JALDI_INT_TSFOOR = 0x04000000, 247 | JALDI_INT_GENTIMER = 0x08000000, 248 | JALDI_INT_CST = 0x10000000, 249 | JALDI_INT_GTT = 0x20000000, 250 | JALDI_INT_FATAL = 0x40000000, 251 | JALDI_INT_GLOBAL = 0x80000000, 252 | JALDI_INT_BMISC = JALDI_INT_TIM | 253 | JALDI_INT_DTIM | 254 | JALDI_INT_DTIMSYNC | 255 | JALDI_INT_TSFOOR | 256 | JALDI_INT_CABEND, 257 | JALDI_INT_COMMON = JALDI_INT_RXNOFRM | 258 | JALDI_INT_RXDESC | 259 | JALDI_INT_RXEOL | 260 | JALDI_INT_RXORN | 261 | JALDI_INT_TXURN | 262 | JALDI_INT_TXDESC | 263 | JALDI_INT_MIB | 264 | JALDI_INT_RXPHY | 265 | JALDI_INT_RXKCM | 266 | JALDI_INT_SWBA | 267 | JALDI_INT_BMISS | 268 | JALDI_INT_GPIO, 269 | JALDI_INT_NOCARD = 0xffffffff 270 | }; 271 | 272 | struct jaldi_channel { 273 | u16 channel; // MHz 274 | u16 center_freq; // MHz 275 | u16 hw_value; // HW-specific channel value (see hw.h, others). Used to index. 276 | u16 max_power; 277 | u32 channelFlags; // TODO: not needed? 278 | u32 chanmode; // 20MHz vs 40Mhz 279 | /* TODO: Noise calibration data per channel may go here, as in a9k */ 280 | }; 281 | 282 | // a convenient way to refer to the freq we're on 283 | struct chan_centers { 284 | u16 synth_center; 285 | u16 ctl_center; 286 | u16 ext_center; 287 | }; 288 | 289 | enum jaldi_power_mode { 290 | JALDI_PM_AWAKE = 0, 291 | JALDI_PM_FULL_SLEEP, 292 | JALDI_PM_NETWORK_SLEEP, 293 | JALDI_PM_UNDEFINED, 294 | }; 295 | 296 | enum ser_reg_mode { 297 | SER_REG_MODE_OFF = 0, 298 | SER_REG_MODE_ON = 1, 299 | SER_REG_MODE_AUTO = 2, 300 | }; 301 | 302 | enum jaldi_reset_type { 303 | JALDI_RESET_POWER_ON, 304 | JALDI_RESET_WARM, 305 | JALDI_RESET_COLD, 306 | }; 307 | 308 | enum jaldi_opmode { 309 | JALDI_UNSPECIFIED, 310 | JALDI_MASTER, 311 | JALDI_CLIENT, 312 | }; 313 | 314 | struct jaldi_bitrate { 315 | u16 bitrate; 316 | u16 hw_value; 317 | }; 318 | 319 | enum jaldi_device_state { 320 | JALDI_HW_UNAVAILABLE, 321 | JALDI_HW_INITIALIZED, 322 | }; 323 | 324 | enum jaldi_bus_type { 325 | JALDI_PCI, 326 | JALDI_AHB, 327 | JALDI_USB, 328 | }; 329 | 330 | /* For hardware jaldimac supports, we only use the 11NA modes. The rest have 331 | * been left for the sake of completeness. */ 332 | enum wireless_mode { 333 | JALDI_MODE_11A = 0, 334 | JALDI_MODE_11G, 335 | JALDI_MODE_11NA_HT20, 336 | JALDI_MODE_11NG_HT20, 337 | JALDI_MODE_11NA_HT40PLUS, 338 | JALDI_MODE_11NA_HT40MINUS, 339 | JALDI_MODE_11NG_HT40PLUS, 340 | JALDI_MODE_11NG_HT40MINUS, 341 | JALDI_MODE_MAX, 342 | }; 343 | 344 | /* NB: This is a direct copy of ath9k_hw_caps to avoid modifying low-level 345 | * code as much as possible. 346 | * 347 | * VEOL seems to be deprecated in ath9k; 80211 beacons are now generated in 348 | * software instead. Nonetheless, we keep track of the hw capability here. */ 349 | enum jaldi_hw_caps { 350 | JALDI_HW_CAP_MIC_AESCCM = BIT(0), 351 | JALDI_HW_CAP_MIC_CKIP = BIT(1), 352 | JALDI_HW_CAP_MIC_TKIP = BIT(2), 353 | JALDI_HW_CAP_CIPHER_AESCCM = BIT(3), 354 | JALDI_HW_CAP_CIPHER_CKIP = BIT(4), 355 | JALDI_HW_CAP_CIPHER_TKIP = BIT(5), 356 | JALDI_HW_CAP_VEOL = BIT(6), /* Virt end-of-list (hw-generated beacons) */ 357 | JALDI_HW_CAP_BSSIDMASK = BIT(7), 358 | JALDI_HW_CAP_MCAST_KEYSEARCH = BIT(8), 359 | JALDI_HW_CAP_HT = BIT(9), 360 | JALDI_HW_CAP_GTT = BIT(10), /* Global transmit timeout */ 361 | JALDI_HW_CAP_FASTCC = BIT(11), /* Fast channel change */ 362 | JALDI_HW_CAP_RFSILENT = BIT(12), 363 | JALDI_HW_CAP_CST = BIT(13), 364 | JALDI_HW_CAP_ENHANCEDPM = BIT(14), 365 | JALDI_HW_CAP_AUTOSLEEP = BIT(15), 366 | JALDI_HW_CAP_4KB_SPLITTRANS = BIT(16), 367 | JALDI_HW_CAP_EDMA = BIT(17), 368 | JALDI_HW_CAP_RAC_SUPPORTED = BIT(18), 369 | JALDI_HW_CAP_LDPC = BIT(19), 370 | JALDI_HW_CAP_FASTCLOCK = BIT(20), 371 | JALDI_HW_CAP_SGI_20 = BIT(21), 372 | }; 373 | 374 | struct jaldi_hw_capabilities { 375 | u32 hw_caps; /* JALDI_HW_CAP_* from jaldi_hw_caps */ 376 | DECLARE_BITMAP(wireless_modes, JALDI_MODE_MAX); /* JALDI_MODE_* */ 377 | u16 total_queues; 378 | u16 low_5ghz_chan, high_5ghz_chan; 379 | u16 low_2ghz_chan, high_2ghz_chan; 380 | u16 rts_aggr_limit; 381 | u8 tx_chainmask; 382 | u8 rx_chainmask; 383 | u16 tx_triglevel_max; 384 | u16 reg_cap; 385 | u8 num_gpio_pins; 386 | u8 num_antcfg_2ghz; 387 | u8 num_antcfg_5ghz; 388 | u8 rx_hp_qdepth; 389 | u8 rx_lp_qdepth; 390 | u8 rx_status_len; 391 | u8 tx_desc_len; 392 | u8 txs_len; 393 | }; 394 | 395 | 396 | struct jaldi_bus_ops { 397 | enum jaldi_bus_type type; 398 | void (*read_cachesize)(struct jaldi_softc *sc, int *cache_size); 399 | bool (*eeprom_read)(struct jaldi_softc *sc, u32 off, u16 *data); 400 | }; 401 | 402 | /** 403 | * struct jaldi_register_ops - Register read/write operations 404 | * (formerly ath_ops) 405 | * @read: Register read 406 | * @write: Register write 407 | * 408 | * The below are not used on the hardware jaldi supports: 409 | * @enable_write_buffer: Enable multiple register writes 410 | * @disable_write_buffer: Disable multiple register writes 411 | * @write_flush: Flush buffered register writes 412 | */ 413 | struct jaldi_register_ops { 414 | unsigned int (*read)(void *, u32 reg_offset); 415 | void (*write)(void *, u32 val, u32 reg_offset); 416 | void (*enable_write_buffer)(void *); 417 | void (*disable_write_buffer)(void *); 418 | void (*write_flush) (void *); 419 | }; 420 | 421 | struct jaldi_hw_ops { 422 | bool (*macversion_supported)(u32 macversion); 423 | 424 | /* PHY ops */ 425 | int (*rf_set_freq)(struct jaldi_hw *hw, 426 | struct jaldi_channel *chan); 427 | void (*spur_mitigate_freq)(struct jaldi_hw *hw, 428 | struct jaldi_channel *chan); 429 | void (*do_getnf)(struct jaldi_hw *hw, int16_t nfarray[NUM_NF_READINGS]); 430 | u32 (*compute_pll_control)(struct jaldi_hw *hw, 431 | struct jaldi_channel *chan); 432 | void (*set_rfmode)(struct jaldi_hw *hw, struct jaldi_channel *chan); 433 | void (*olc_init)(struct jaldi_hw *hw); 434 | void (*rfbus_done)(struct jaldi_hw *hw); 435 | bool (*rfbus_req)(struct jaldi_hw *hw); 436 | void (*set_channel_regs)(struct jaldi_hw *hw, struct jaldi_channel *chan); 437 | 438 | /* MAC ops */ /* TODO: should move more of the hard-coded mac ops into here from hw.c */ 439 | bool (*get_isr)(struct jaldi_hw *hw, enum jaldi_intr_type *masked); 440 | void (*rx_enable)(struct jaldi_hw *hw); 441 | }; 442 | 443 | struct jaldi_hw { 444 | struct jaldi_hw_version hw_version; 445 | struct jaldi_softc *sc; 446 | 447 | struct jaldi_channel *curchan; 448 | struct jaldi_bitrate *cur_rate; 449 | enum jaldi_power_mode power_mode; 450 | enum jaldi_device_state dev_state; 451 | enum jaldi_opmode opmode; 452 | struct jaldi_hw_capabilities caps; 453 | u32 hw_flags; // generic hw flags 454 | 455 | /* Support for killing rf ("airplane mode") */ 456 | u16 rfsilent; 457 | u32 rfkill_gpio; 458 | u32 rfkill_polarity; 459 | bool need_an_top2_fixup; 460 | 461 | union { 462 | struct ar5416_eeprom_def def; 463 | struct ar5416_eeprom_4k map4k; 464 | struct ar9287_eeprom map9287; 465 | } eeprom; 466 | 467 | /* Used to program the radio on non single-chip devices */ 468 | u32 *analogBank0Data; 469 | u32 *analogBank1Data; 470 | u32 *analogBank2Data; 471 | u32 *analogBank3Data; 472 | u32 *analogBank6Data; 473 | u32 *analogBank6TPCData; 474 | u32 *analogBank7Data; 475 | u32 *addac5416_21; 476 | u32 *bank6Temp; 477 | 478 | u32 slottime; /* tx slot duration */ 479 | u32 ifstime; /* interframe spacing time */ 480 | u32 globaltxtimeout; 481 | 482 | u32 intr_txqs; 483 | u8 txchainmask; 484 | u8 rxchainmask; 485 | 486 | /* Gain stuff (olc) */ 487 | u32 originalGain[22]; 488 | int initPDADC; 489 | int PDADCdelta; 490 | 491 | enum jaldi_intr_type imask; /* the interrupts we care about */ 492 | u32 imrs2_reg; 493 | u32 txok_interrupt_mask; 494 | u32 txerr_interrupt_mask; 495 | u32 txdesc_interrupt_mask; 496 | u32 txeol_interrupt_mask; 497 | u32 txurn_interrupt_mask; 498 | u32 intr_gen_timer_trigger; 499 | u32 intr_gen_timer_thresh; 500 | bool chip_fullsleep; 501 | 502 | struct jaldi_tx_queue_info txq[JALDI_NUM_TX_QUEUES]; 503 | 504 | /* hw config (takes place of ath9k_ops_config) */ 505 | bool rx_intr_mitigation; 506 | bool tx_intr_mitigation; 507 | bool is_pciexpress; 508 | int serialize_regmode; 509 | u8 ht_enable; 510 | u8 max_txtrig_level; /* tx fifo */ 511 | u16 tx_trig_level; 512 | u8 analog_shiftreg; 513 | int spurmode; 514 | u16 spurchans[AR_EEPROM_MODAL_SPURS][2]; 515 | bool disable_acks; /* disable hw generated acks */ 516 | bool disable_cs; /* disable carrier sense */ 517 | 518 | /* functions to control hw */ 519 | struct jaldi_hw_ops ops; 520 | struct jaldi_register_ops *reg_ops; 521 | struct jaldi_bus_ops *bus_ops; 522 | const struct eeprom_ops *eep_ops; // This is more or less copied from ath9k 523 | }; 524 | 525 | static inline struct jaldi_hw_ops *jaldi_get_hw_ops(struct jaldi_hw *hw) { 526 | return &hw->ops; 527 | } 528 | 529 | int jaldi_hw_init(struct jaldi_hw *hw); 530 | void jaldi_hw_deinit(struct jaldi_hw *hw); 531 | void jaldi_hw_init_global_settings(struct jaldi_hw *hw); 532 | 533 | bool jaldi_hw_intrpend(struct jaldi_hw *hw); 534 | enum jaldi_intr_type jaldi_hw_set_interrupts(struct jaldi_hw *hw, 535 | enum jaldi_intr_type ints); 536 | bool jaldi_hw_wait(struct jaldi_hw *hw, u32 reg, u32 mask, u32 val, u32 timeout); 537 | 538 | void jaldi_hw_attach_phy_ops(struct jaldi_hw *hw); 539 | void jaldi_hw_attach_mac_ops(struct jaldi_hw *hw); 540 | void jaldi_hw_get_channel_centers(struct jaldi_channel *chan, 541 | struct chan_centers *centers); 542 | bool jaldi_hw_setpower(struct jaldi_hw *hw, enum jaldi_power_mode mode); 543 | void jaldi_hw_set11n_txdesc(struct jaldi_hw *hw, void *ds, 544 | u32 pktLen, enum jaldi_pkt_type type, 545 | u32 txPower, u32 flags); 546 | void jaldi_hw_fill_txdesc(struct jaldi_hw *hw, struct jaldi_desc *ds, u32 seglen, 547 | bool is_firstseg, bool is_lastseg, 548 | const struct jaldi_desc *ds0, dma_addr_t buf_addr, 549 | unsigned int qcu); 550 | u32 jaldi_hw_getrxfilter(struct jaldi_hw *hw); 551 | void jaldi_hw_setrxfilter(struct jaldi_hw *hw, u32 bits); 552 | bool jaldi_hw_stoptxdma(struct jaldi_hw *hw, u32 q); 553 | 554 | void jaldi_hw_set_txpowerlimit(struct jaldi_hw *hw, u32 limit); 555 | void jaldi_hw_setmac(struct jaldi_hw *hw, const u8 *mac); 556 | void jaldi_hw_setmcastfilter(struct jaldi_hw *hw, u32 filter0, u32 filter1); 557 | void jaldi_hw_set_opmode(struct jaldi_hw *hw); 558 | 559 | #endif 560 | -------------------------------------------------------------------------------- /kerneldriver/init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * jaldimac 3 | */ 4 | 5 | #include "jaldi.h" 6 | 7 | /* We use the hw_value as an index into our private channel structure */ 8 | 9 | #define CHAN2G(_freq, _idx) { \ 10 | .channel = (_freq), \ 11 | .center_freq = (_freq), \ 12 | .hw_value = (_idx), \ 13 | .max_power = 20, \ 14 | } 15 | 16 | #define CHAN5G(_freq, _idx) { \ 17 | .channel = (_freq), \ 18 | .center_freq = (_freq), \ 19 | .hw_value = (_idx), \ 20 | .max_power = 20, \ 21 | } 22 | 23 | /* From a9k: 24 | * "Some 5 GHz radios are actually tunable on XXXX-YYYY 25 | * on 5 MHz steps, we support the channels which we know 26 | * we have calibration data for all cards though to make 27 | * this static" 28 | * 29 | * Because we (JaldiMAC) are not doing anything with calibration yet, 30 | * perhaps we can leverage this capability. TODO: does 9280 support this? 31 | */ 32 | static struct jaldi_channel jaldi_2ghz_chantable[] = {}; 33 | static struct jaldi_channel jaldi_5ghz_chantable[] = { 34 | /* _We_ call this UNII 1 */ 35 | CHAN5G(5180, 14), /* Channel 36 */ 36 | CHAN5G(5200, 15), /* Channel 40 */ 37 | CHAN5G(5220, 16), /* Channel 44 */ 38 | CHAN5G(5240, 17), /* Channel 48 */ 39 | /* _We_ call this UNII 2 */ 40 | CHAN5G(5260, 18), /* Channel 52 */ 41 | CHAN5G(5280, 19), /* Channel 56 */ 42 | CHAN5G(5300, 20), /* Channel 60 */ 43 | CHAN5G(5320, 21), /* Channel 64 */ 44 | /* _We_ call this "Middle band" */ 45 | CHAN5G(5500, 22), /* Channel 100 */ 46 | CHAN5G(5520, 23), /* Channel 104 */ 47 | CHAN5G(5540, 24), /* Channel 108 */ 48 | CHAN5G(5560, 25), /* Channel 112 */ 49 | CHAN5G(5580, 26), /* Channel 116 */ 50 | CHAN5G(5600, 27), /* Channel 120 */ 51 | CHAN5G(5620, 28), /* Channel 124 */ 52 | CHAN5G(5640, 29), /* Channel 128 */ 53 | CHAN5G(5660, 30), /* Channel 132 */ 54 | CHAN5G(5680, 31), /* Channel 136 */ 55 | CHAN5G(5700, 32), /* Channel 140 */ 56 | /* _We_ call this UNII 3 */ 57 | CHAN5G(5745, 33), /* Channel 149 */ 58 | CHAN5G(5765, 34), /* Channel 153 */ 59 | CHAN5G(5785, 35), /* Channel 157 */ 60 | CHAN5G(5805, 36), /* Channel 161 */ 61 | CHAN5G(5825, 37), /* Channel 165 */ 62 | }; 63 | 64 | /* List of rates we can select from. 65 | * TODO: What is the hardware limit for these rates? 66 | */ 67 | #define RATE(_bitrate, _hw_rate) { \ 68 | .bitrate = (_bitrate), \ 69 | .hw_value = (_hw_rate), \ 70 | } 71 | 72 | static struct jaldi_bitrate jaldi_rates[] = { 73 | RATE(10, 0x1b), 74 | RATE(20, 0x1a), 75 | RATE(55, 0x19), 76 | RATE(110, 0x18), 77 | RATE(60, 0x0b), 78 | RATE(90, 0x0f), 79 | RATE(120, 0x0a), 80 | RATE(180, 0x0e), 81 | RATE(240, 0x09), 82 | RATE(360, 0x0d), 83 | RATE(480, 0x08), 84 | RATE(540, 0x0c), 85 | }; 86 | 87 | static void jaldi_deinit_softc(struct jaldi_softc *sc); 88 | 89 | static void jaldi_iowrite32(struct jaldi_hw *hw, u32 val, u32 reg_offset) { 90 | struct jaldi_softc *sc = hw->sc; 91 | 92 | if (hw->serialize_regmode == SER_REG_MODE_ON) { 93 | unsigned long flags; 94 | spin_lock_irqsave(&sc->sc_serial_rw, flags); 95 | iowrite32(val, sc->mem + reg_offset); 96 | spin_unlock_irqrestore(&sc->sc_serial_rw, flags); 97 | } else { 98 | iowrite32(val, sc->mem + reg_offset); 99 | } 100 | } 101 | 102 | static unsigned int jaldi_ioread32(struct jaldi_hw *hw, u32 reg_offset) { 103 | struct jaldi_softc *sc = hw->sc; 104 | u32 val; 105 | 106 | if (hw->serialize_regmode == SER_REG_MODE_ON) { 107 | unsigned long flags; 108 | spin_lock_irqsave(&sc->sc_serial_rw, flags); 109 | val = ioread32(sc->mem + reg_offset); 110 | spin_unlock_irqrestore(&sc->sc_serial_rw, flags); 111 | } else { 112 | val = ioread32(sc->mem + reg_offset); 113 | } 114 | 115 | // jaldi_print(JALDI_DEBUG, "jaldi_ioread32: %8X\n", val); 116 | 117 | return val; 118 | } 119 | 120 | static const struct jaldi_register_ops jaldi_reg_ops = { 121 | .read = jaldi_ioread32, 122 | .write = jaldi_iowrite32, 123 | }; 124 | 125 | /* Should set up DMA as well as worker thread to handle setting up queues, etc. */ 126 | int jaldi_tx_init(struct jaldi_softc *sc, int nbufs) 127 | { 128 | int error = 0; 129 | 130 | DBG_START_MSG; 131 | spin_lock_init(&sc->tx.txbuflock); 132 | 133 | error = jaldi_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, 134 | "tx", nbufs, 1, 1); 135 | 136 | if (error != 0) { 137 | jaldi_print(JALDI_ALERT, "Failed to allocate tx descriptors\n"); 138 | jaldi_tx_cleanup(sc); 139 | return error; 140 | } 141 | 142 | /* TODO ath9k has a bugfix here for tx lockups after ~1hr or so, see 143 | * ath_tx_complete_poll_work */ 144 | 145 | return 0; 146 | 147 | } 148 | 149 | struct sk_buff *jaldi_rxbuf_alloc(struct jaldi_softc *sc, u32 len) 150 | { 151 | struct sk_buff *skb; 152 | u32 off; 153 | 154 | /* 155 | * Cache-line-align. This is important (for the 156 | * 5210 at least) as not doing so causes bogus data 157 | * in rx'd frames. 158 | */ 159 | 160 | /* Note: the kernel can allocate a value greater than 161 | * what we ask it to give us. We really only need 4 KB as that 162 | * is this hardware supports and in fact we need at least 3849 163 | * as that is the MAX AMSDU size this hardware supports. 164 | * Unfortunately this means we may get 8 KB here from the 165 | * kernel... and that is actually what is observed on some 166 | * systems :( */ 167 | skb = dev_alloc_skb(len + sc->cachelsz - 1); 168 | if (skb != NULL) { 169 | off = ((unsigned long) skb->data) % sc->cachelsz; 170 | if (off != 0) 171 | skb_reserve(skb, sc->cachelsz - off); 172 | } else { 173 | printk(KERN_ERR "skbuff alloc of size %u failed\n", len); 174 | return NULL; 175 | } 176 | 177 | return skb; 178 | } 179 | 180 | int jaldi_rx_init(struct jaldi_softc *sc, int nbufs) 181 | { 182 | struct sk_buff *skb; 183 | struct jaldi_buf *bf; 184 | int error = 0; 185 | 186 | spin_lock_init(&sc->rx.rxflushlock); 187 | sc->sc_flags &= ~SC_OP_RXFLUSH; 188 | spin_lock_init(&sc->rx.rxbuflock); 189 | 190 | /* we're not doing edma right now; if we were that would go here, like ath9k */ 191 | 192 | sc->rx_bufsize = roundup(JALDI_MAX_MPDU_LEN, 193 | min(sc->cachelsz, (u16)64)); 194 | 195 | jaldi_print(JALDI_DEBUG, "cachelsz %u rxbufsize %u\n", 196 | sc->cachelsz, sc->rx_bufsize); 197 | 198 | /* Initialize rx descriptors */ 199 | 200 | error = jaldi_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, 201 | "rx", nbufs, 1, 0); 202 | if (error != 0) { 203 | jaldi_print(JALDI_FATAL, 204 | "failed to allocate rx descriptors: %d\n", 205 | error); 206 | goto err; 207 | } 208 | 209 | list_for_each_entry(bf, &sc->rx.rxbuf, list) { 210 | skb = jaldi_rxbuf_alloc(sc, sc->rx_bufsize); 211 | 212 | if (skb == NULL) { 213 | error = -ENOMEM; 214 | goto err; 215 | } 216 | 217 | bf->bf_mpdu = skb; 218 | bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, 219 | sc->rx_bufsize, 220 | DMA_FROM_DEVICE); 221 | if (unlikely(dma_mapping_error(sc->dev, 222 | bf->bf_buf_addr))) { 223 | dev_kfree_skb_any(skb); 224 | bf->bf_mpdu = NULL; 225 | jaldi_print(JALDI_FATAL, 226 | "dma_mapping_error() on RX init\n"); 227 | error = -ENOMEM; 228 | goto err; 229 | } 230 | bf->bf_dmacontext = bf->bf_buf_addr; 231 | } 232 | sc->rx.rxlink = NULL; 233 | 234 | err: 235 | if (error) 236 | jaldi_rx_cleanup(sc); 237 | 238 | return error; 239 | } 240 | 241 | 242 | 243 | 244 | void jaldi_tx_cleanup(struct jaldi_softc *sc) 245 | { 246 | DBG_START_MSG; 247 | if (sc->tx.txdma.dd_desc_len != 0) 248 | jaldi_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); 249 | 250 | } 251 | 252 | void jaldi_rx_cleanup(struct jaldi_softc *sc) 253 | { 254 | struct sk_buff *skb; 255 | struct jaldi_buf *bf; 256 | 257 | /* if we were doing edma it'd go here */ 258 | 259 | list_for_each_entry(bf, &sc->rx.rxbuf, list) { 260 | skb = bf->bf_mpdu; 261 | if (skb) { 262 | dma_unmap_single(sc->dev, bf->bf_buf_addr, 263 | sc->rx_bufsize, 264 | DMA_FROM_DEVICE); 265 | dev_kfree_skb(skb); 266 | } 267 | } 268 | 269 | if (sc->rx.rxdma.dd_desc_len != 0) 270 | jaldi_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf); 271 | } 272 | void jaldi_descdma_cleanup(struct jaldi_softc *sc, struct jaldi_descdma *dd, 273 | struct list_head *head) 274 | { 275 | DBG_START_MSG; 276 | dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, 277 | dd->dd_desc_paddr); 278 | 279 | INIT_LIST_HEAD(head); 280 | kfree(dd->dd_bufptr); 281 | memset(dd, 0, sizeof(*dd)); 282 | } 283 | 284 | /* From ath9k: 285 | * "This function will allocate both the DMA descriptor structure, and the 286 | * buffers it contains. These are used to contain the descriptors used 287 | * by the system." 288 | */ 289 | int jaldi_descdma_setup(struct jaldi_softc *sc, struct jaldi_descdma *dd, 290 | struct list_head *head, const char *name, 291 | int nbuf, int ndesc, bool is_tx) 292 | { 293 | #define DS2PHYS(_dd, _ds) \ 294 | ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) 295 | #define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) 296 | #define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) 297 | u8 *ds; 298 | struct jaldi_buf *bf; 299 | int i, bsize, error, desc_len; 300 | 301 | DBG_START_MSG; 302 | jaldi_print(JALDI_DEBUG, "%s DMA: %u buffers %u desc/buf\n", 303 | name, nbuf, ndesc); 304 | 305 | INIT_LIST_HEAD(head); 306 | 307 | if (is_tx) 308 | desc_len = sc->hw->caps.tx_desc_len; 309 | else 310 | desc_len = sizeof(struct jaldi_desc); 311 | 312 | /* ath_desc must be a multiple of DWORDs */ 313 | if ((desc_len % 4) != 0) { 314 | jaldi_print(JALDI_FATAL, 315 | "jaldi_desc not DWORD aligned\n"); 316 | BUG_ON((desc_len % 4) != 0); 317 | error = -ENOMEM; 318 | goto fail; 319 | } 320 | 321 | dd->dd_desc_len = desc_len * nbuf * ndesc; 322 | 323 | /* 324 | * Need additional DMA memory because we can't use 325 | * descriptors that cross the 4K page boundary. Assume 326 | * one skipped descriptor per 4K page. 327 | */ 328 | if (!(sc->hw->caps.hw_caps & JALDI_HW_CAP_4KB_SPLITTRANS)) { 329 | u32 ndesc_skipped = 330 | ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); 331 | u32 dma_len; 332 | 333 | while (ndesc_skipped) { 334 | dma_len = ndesc_skipped * desc_len; 335 | dd->dd_desc_len += dma_len; 336 | 337 | ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); 338 | } 339 | } 340 | 341 | /* allocate descriptors */ 342 | dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, 343 | &dd->dd_desc_paddr, GFP_KERNEL); 344 | if (dd->dd_desc == NULL) { 345 | error = -ENOMEM; 346 | goto fail; 347 | } 348 | ds = (u8 *) dd->dd_desc; 349 | jaldi_print(JALDI_INFO, "%s DMA map: %p (%u) -> %llx (%u)\n", 350 | name, ds, (u32) dd->dd_desc_len, 351 | ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); 352 | 353 | /* allocate buffers */ 354 | bsize = sizeof(struct jaldi_buf) * nbuf; 355 | bf = kzalloc(bsize, GFP_KERNEL); 356 | if (bf == NULL) { 357 | error = -ENOMEM; 358 | goto fail2; 359 | } 360 | dd->dd_bufptr = bf; 361 | 362 | for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { 363 | bf->bf_desc = ds; 364 | bf->bf_daddr = DS2PHYS(dd, ds); 365 | 366 | if (!(sc->hw->caps.hw_caps & 367 | JALDI_HW_CAP_4KB_SPLITTRANS)) { 368 | /* 369 | * Skip descriptor addresses which can cause 4KB 370 | * boundary crossing (addr + length) with a 32 dword 371 | * descriptor fetch. 372 | */ 373 | while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { 374 | BUG_ON((caddr_t) bf->bf_desc >= 375 | ((caddr_t) dd->dd_desc + 376 | dd->dd_desc_len)); 377 | 378 | ds += (desc_len * ndesc); 379 | bf->bf_desc = ds; 380 | bf->bf_daddr = DS2PHYS(dd, ds); 381 | } 382 | } 383 | list_add_tail(&bf->list, head); 384 | } 385 | return 0; 386 | fail2: 387 | dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, 388 | dd->dd_desc_paddr); 389 | fail: 390 | memset(dd, 0, sizeof(*dd)); 391 | return error; 392 | #undef ATH_DESC_4KB_BOUND_CHECK 393 | #undef ATH_DESC_4KB_BOUND_NUM_SKIPPED 394 | #undef DS2PHYS 395 | } 396 | 397 | static int jaldi_init_queues(struct jaldi_softc *sc) 398 | { 399 | int i = 0; 400 | 401 | DBG_START_MSG; 402 | for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) 403 | sc->tx.hwq_map[i] = -1; 404 | 405 | 406 | if (!jaldi_tx_setup(sc, JALDI_WME_AC_BK)) { 407 | jaldi_print(JALDI_FATAL, 408 | "Unable to setup xmit queue for BK traffic\n"); 409 | goto err; 410 | } 411 | 412 | if (!jaldi_tx_setup(sc, JALDI_WME_AC_BE)) { 413 | jaldi_print(JALDI_FATAL, 414 | "Unable to setup xmit queue for BE traffic\n"); 415 | goto err; 416 | } 417 | if (!jaldi_tx_setup(sc, JALDI_WME_AC_VI)) { 418 | jaldi_print(JALDI_FATAL, 419 | "Unable to setup xmit queue for VI traffic\n"); 420 | goto err; 421 | } 422 | if (!jaldi_tx_setup(sc, JALDI_WME_AC_VO)) { 423 | jaldi_print(JALDI_FATAL, 424 | "Unable to setup xmit queue for VO traffic\n"); 425 | goto err; 426 | } 427 | 428 | return 0; 429 | err: 430 | for (i = 0; i < JALDI_NUM_TX_QUEUES; i++) 431 | if (JALDI_TXQ_SETUP(sc, i)) 432 | jaldi_tx_cleanupq(sc, &sc->tx.txq[i]); 433 | 434 | return -EIO; 435 | } 436 | 437 | int jaldi_init_softc(u16 devid, struct jaldi_softc *sc, u16 subsysid, const struct jaldi_bus_ops *bus_ops) 438 | { 439 | struct jaldi_hw *hw = NULL; 440 | struct ath9k_platform_data *pdata; 441 | int ret = 0; 442 | int csz = 0; 443 | 444 | DBG_START_MSG; 445 | hw = kzalloc(sizeof(struct jaldi_hw), GFP_KERNEL); 446 | if (!hw) return -ENOMEM; 447 | 448 | hw->hw_version.devid = devid; 449 | hw->hw_version.subsysid = subsysid; 450 | 451 | pdata = (struct ath9k_platform_data *) sc->dev->platform_data; 452 | if (!pdata) { 453 | jaldi_print(JALDI_DEBUG, "no pdev\n"); 454 | hw->hw_flags |= AH_USE_EEPROM; 455 | } 456 | 457 | hw->sc = sc; 458 | sc->hw = hw; 459 | 460 | hw->reg_ops = &jaldi_reg_ops; 461 | hw->bus_ops = bus_ops; 462 | 463 | spin_lock_init(&sc->sc_resetlock); 464 | spin_lock_init(&sc->sc_netdevlock); 465 | spin_lock_init(&sc->sc_pm_lock); 466 | spin_lock_init(&sc->sc_serial_rw); 467 | mutex_init(&sc->mutex); 468 | tasklet_init(&sc->intr_tq, jaldi_tasklet, (unsigned long)sc); 469 | /* init tasklets and other locks here */ 470 | 471 | hrtimer_init(&sc->tx_timer,CLOCK_REALTIME, HRTIMER_MODE_ABS); 472 | 473 | hw->bus_ops->read_cachesize(sc, &csz); 474 | sc->cachelsz = csz; 475 | 476 | /* ath9k reads cache line size here... may be relevant */ 477 | ret = jaldi_hw_init(hw); 478 | if (ret) goto err_hw; 479 | 480 | ret = jaldi_init_debug(hw); 481 | if (ret) { 482 | jaldi_print(JALDI_WARN, "Couldn't create debubfs\n"); 483 | goto err_debug; 484 | } 485 | 486 | sc->chans[JALDI_2GHZ] = jaldi_2ghz_chantable; 487 | sc->chans[JALDI_5GHZ] = jaldi_5ghz_chantable; 488 | 489 | ret = jaldi_init_queues(sc); 490 | if (ret) goto err_queues; 491 | 492 | return 0; 493 | 494 | err_queues: 495 | jaldi_hw_deinit(hw); 496 | err_debug: 497 | jaldi_exit_debug(hw); 498 | err_hw: 499 | tasklet_kill(&sc->intr_tq); 500 | kfree(hw); 501 | sc->hw = NULL; 502 | jaldi_print(JALDI_FATAL,"init_device failed, ret=%d\n",ret); 503 | return ret; 504 | } 505 | 506 | int jaldi_init_device(u16 devid, struct jaldi_softc *sc, u16 subsysid, const struct jaldi_bus_ops *bus_ops) 507 | { 508 | int error; 509 | 510 | DBG_START_MSG; 511 | error = jaldi_init_softc(devid, sc, subsysid, bus_ops); 512 | if (error != 0) 513 | goto error_init; 514 | 515 | 516 | /* Setup TX DMA */ 517 | error = jaldi_tx_init(sc, JALDI_NUM_TXBUF); 518 | if (error) { goto error_tx; } 519 | 520 | /* Setup RX DMA */ 521 | error = jaldi_rx_init(sc, JALDI_NUM_RXBUF); // TODO 522 | if (error) { goto error_rx; } 523 | 524 | /* initialize workers here if needed */ 525 | 526 | return 0; 527 | 528 | error_rx: 529 | jaldi_tx_cleanup(sc); 530 | error_tx: 531 | jaldi_deinit_softc(sc); 532 | error_init: 533 | jaldi_print(JALDI_FATAL, "init_device failed, error %d.\n",error); 534 | return error; 535 | } 536 | 537 | /* TODO 538 | * this is probably similar to ath9k_init_interrupt_masks in ath9k's hw.c 539 | */ 540 | int jaldi_init_interrupts(struct jaldi_softc *sc) 541 | { 542 | DBG_START_MSG; 543 | return 0; 544 | } 545 | 546 | /*****************************/ 547 | /* De-Initialization */ 548 | /*****************************/ 549 | 550 | static void jaldi_deinit_softc(struct jaldi_softc *sc) 551 | { 552 | DBG_START_MSG; 553 | int i = 0; 554 | 555 | for (i = 0; i < JALDI_NUM_TX_QUEUES; i++) 556 | if (JALDI_TXQ_SETUP(sc, i)) 557 | jaldi_tx_cleanupq(sc, &sc->tx.txq[i]); 558 | 559 | jaldi_hw_deinit(sc->hw); 560 | 561 | tasklet_kill(&sc->intr_tq); 562 | 563 | kfree(sc->hw); 564 | sc->hw = NULL; 565 | } 566 | 567 | void jaldi_deinit_device(struct jaldi_softc *sc) 568 | { 569 | DBG_START_MSG; 570 | jaldi_ps_wakeup(sc); 571 | 572 | jaldi_rx_cleanup(sc); 573 | jaldi_tx_cleanup(sc); 574 | jaldi_deinit_softc(sc); 575 | } 576 | 577 | /* deinit of descdma could go here */ 578 | 579 | 580 | /*******************/ 581 | /* net_dev */ 582 | /*******************/ 583 | /* This is our alloc_netdev callback. It just sets up the softc memory 584 | * region in the netdev. We actually perform the rest of our device 585 | * initialization through our bus probe calls, which start in 586 | * jaldi_init_device. We call alloc_netdev during bus probe as well, but 587 | * we call init_device. */ 588 | void jaldi_init(struct net_device *dev) 589 | { 590 | struct jaldi_softc *sc; 591 | 592 | DBG_START_MSG; 593 | 594 | ether_setup(dev); 595 | 596 | jaldi_attach_netdev_ops(dev); 597 | dev->flags = IFF_NOARP; 598 | dev->features = NETIF_F_NO_CSUM; 599 | 600 | sc = netdev_priv(dev); 601 | 602 | memset(sc,0,sizeof(struct jaldi_softc)); 603 | 604 | sc->net_dev = dev; 605 | 606 | jaldi_print(JALDI_DEBUG, "init sc: %p\n", sc); 607 | 608 | if(jaldi_init_interrupts(sc)) { 609 | jaldi_print(JALDI_FATAL, "error initializing interrupt handlers\n"); 610 | return; 611 | } 612 | 613 | jaldi_print(JALDI_INFO, "jaldi_init end\n"); 614 | } 615 | 616 | /* Allocates and registers network device 617 | * Also allocates memory for jaldi_softc 618 | */ 619 | struct net_device *jaldi_init_netdev(void) 620 | { 621 | struct net_device *jaldi_dev; 622 | 623 | DBG_START_MSG; 624 | jaldi_dev = alloc_netdev(sizeof(struct jaldi_softc), "jaldi%d", jaldi_init); 625 | if (jaldi_dev == NULL) { 626 | jaldi_print(JALDI_FATAL, "net_dev is null\n"); 627 | return -ENOMEM; 628 | } 629 | 630 | jaldi_print(JALDI_INFO, "netdev allocated.\n"); 631 | 632 | return jaldi_dev; 633 | } 634 | 635 | int jaldi_start_netdev(struct jaldi_softc *sc) 636 | { 637 | int result; 638 | struct net_device *ndev; 639 | 640 | DBG_START_MSG; 641 | ndev = sc->net_dev; 642 | 643 | result = register_netdev(ndev); 644 | if (result) { 645 | jaldi_print(JALDI_FATAL, "error %i registering device \"%s\"\n", result, ndev->name); 646 | return -ENOMEM; 647 | } 648 | 649 | jaldi_print(JALDI_INFO, "netdev registered.\n"); 650 | 651 | return 0; 652 | } 653 | -------------------------------------------------------------------------------- /kerneldriver/jaldi.h: -------------------------------------------------------------------------------- 1 | /* JaldiMAC 2 | * GPL. 3 | * 4 | * Written by Shaddi Hasan (shaddi@eecs.berkeley.edu) 5 | * Based strongly off ath9k, architecture inspired by i2400m. 6 | * 7 | * GENERAL DRIVER ARCHITECTURE 8 | * 9 | * THe jaldi driver is split into two major parts: 10 | * 11 | * - Device specific driver (so far only targets UBNT NSM5, running AR9280) 12 | * - Device generic part (this part) 13 | * 14 | * Because of the ath9k heritage, this demarcation may be fuzzy at times. The 15 | * device specific part of the driver handles tasks involving moving data 16 | * between the kernal and the device, and bus-related tasks such as probing, 17 | * hardware resets, and disconnecting. 18 | * 19 | * The device generic part aims to implement a fairly normal layer, if thin, 20 | * layer between Linux and the hardware. It appears as an Ethernet device for 21 | * the sake of simplicity, but packets passed to this driver should follow the 22 | * as-yet-to-be-determined JaldiMAC packet format. 23 | */ 24 | 25 | 26 | 27 | #ifndef JALDI_H 28 | #define JALDI_H 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include "hw.h" 35 | #include "debug.h" 36 | 37 | /* Macro to expand scalars to 64-bit objects */ 38 | #define ito64(x) (sizeof(x) == 1) ? \ 39 | (((unsigned long long int)(x)) & (0xff)) : \ 40 | (sizeof(x) == 2) ? \ 41 | (((unsigned long long int)(x)) & 0xffff) : \ 42 | ((sizeof(x) == 4) ? \ 43 | (((unsigned long long int)(x)) & 0xffffffff) : \ 44 | (unsigned long long int)(x)) 45 | 46 | #define JALDI_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<bf_stale = false; \ 69 | (_bf)->bf_lastbf = NULL; \ 70 | (_bf)->bf_next = NULL; \ 71 | memset(&((_bf)->bf_state), 0, \ 72 | sizeof(struct jaldi_buf_state)); \ 73 | } while (0) 74 | 75 | #define JALDI_RXBUF_RESET(_bf) do { \ 76 | (_bf)->bf_stale = false; \ 77 | } while (0) 78 | 79 | /***********/ 80 | /* RX / TX */ 81 | /***********/ 82 | #define JALDI_MAX_MPDU_LEN 1500 /* MTU, bytes */ 83 | #define JALDI_MAX_ANTENNA 3 84 | #define JALDI_NUM_RXBUF 512 85 | #define JALDI_NUM_TXBUF 512 86 | #define JALDI_TX_ERROR 0x01 87 | 88 | 89 | struct jaldi_wiphy; 90 | struct jaldi_rate_table; 91 | 92 | enum qos_type { 93 | JALDI_QOS_BULK, 94 | JALDI_QOS_LATENCY_SENSITIVE, 95 | JALDI_QOS_UNDEFINED, 96 | }; 97 | 98 | enum jaldi_freq_band { 99 | JALDI_2GHZ = 0, 100 | JALDI_5GHZ, 101 | }; 102 | 103 | enum jaldi_pkt_type { 104 | JALDI_PKT_TYPE_NORMAL = 0, /* all packets that are tx'd are of this type */ 105 | JALDI_PKT_TYPE_CONTROL, /* packets used to set an internal setting (not tx'd) */ 106 | }; 107 | 108 | struct jaldi_packet { 109 | struct jaldi_packet *next; 110 | struct jaldi_softc *sc; 111 | struct sk_buff *skb; 112 | enum jaldi_pkt_type type; 113 | struct jaldi_txq *txq; 114 | int datalen; 115 | char *data; 116 | s64 tx_time; /* the time at which this packet should be sent */ 117 | int qos_type; 118 | }; 119 | 120 | struct jaldi_buf_state { 121 | int bfs_nframes; 122 | u16 bfs_al; 123 | u16 bfs_frmlen; 124 | int bfs_seqno; 125 | int bfs_tidno; 126 | int bfs_retries; 127 | u8 bfs_type; 128 | }; 129 | 130 | /* TIL: when experienced kernel devs write weird code they're probably doing it that 131 | * way for a reason. */ 132 | #define bf_nframes bf_state.bfs_nframes 133 | #define bf_al bf_state.bfs_al 134 | #define bf_frmlen bf_state.bfs_frmlen 135 | #define bf_retries bf_state.bfs_retries 136 | #define bf_seqno bf_state.bfs_seqno 137 | #define bf_tidno bf_state.bfs_tidno 138 | 139 | struct jaldi_buf { 140 | struct list_head list; 141 | 142 | struct jaldi_buf *bf_lastbf; /* for aggregation, the last bf */ 143 | struct jaldi_buf *bf_next; 144 | 145 | void *bf_desc; /* virtual addr of desc */ 146 | dma_addr_t bf_daddr; /* physical addr of desc */ 147 | dma_addr_t bf_buf_addr; /* physical addr of data buffer */ 148 | dma_addr_t bf_dmacontext; 149 | struct sk_buff *bf_mpdu; /* MAC protocol data unit */ 150 | 151 | bool bf_stale; 152 | bool bf_tx_aborted; 153 | 154 | struct jaldi_buf_state bf_state; 155 | 156 | u16 bf_flags; 157 | }; 158 | 159 | struct jaldi_descdma { 160 | void *dd_desc; 161 | dma_addr_t dd_desc_paddr; 162 | u32 dd_desc_len; 163 | struct jaldi_buf *dd_bufptr; 164 | }; 165 | 166 | 167 | /**********/ 168 | /* MAC */ 169 | /**********/ 170 | struct jaldi_tx { 171 | u16 seq_no; 172 | u32 txqsetup; 173 | int hwq_map[JALDI_WME_AC_VO+1]; // the five jaldi hw queues 174 | spinlock_t txbuflock; 175 | struct list_head txbuf; 176 | struct jaldi_txq txq[JALDI_NUM_TX_QUEUES]; 177 | struct jaldi_descdma txdma; 178 | }; 179 | 180 | struct jaldi_rx { 181 | u8 defant; 182 | u8 rxotherant; 183 | u32 *rxlink; 184 | unsigned int rxfilter; 185 | spinlock_t rxflushlock; 186 | spinlock_t rxbuflock; 187 | struct list_head rxbuf; 188 | struct jaldi_descdma rxdma; 189 | struct jaldi_buf *rx_bufptr; 190 | }; 191 | 192 | struct jaldi_softc { 193 | struct device *dev; 194 | struct net_device *net_dev; 195 | 196 | /* Hardware related */ 197 | struct tasklet_struct intr_tq; // jaldi_tasklet, general intr bottom 198 | struct jaldi_hw *hw; // from ath9k_hw, hw main struct 199 | void __iomem *mem; // see pci_iomap and lwn article 200 | int irq; // irq number... 201 | struct mutex mutex; 202 | spinlock_t sc_resetlock; 203 | spinlock_t sc_serial_rw; 204 | spinlock_t sc_pm_lock; 205 | 206 | struct hrtimer tx_timer; 207 | 208 | u32 intrstatus; // keep track of reason for interrupt 209 | u32 sc_flags; 210 | bool hw_ready; // flag to see if hw is ready 211 | u16 ps_flags; /* powersave */ 212 | unsigned long ps_usecount; 213 | bool ps_idle; 214 | u16 curtxpow; /* tx power (.5 dBm units) */ 215 | u16 cachelsz; 216 | 217 | struct jaldi_channel *chans[2]; 218 | struct jaldi_channel curchan; 219 | 220 | 221 | /* netdev */ 222 | struct net_device_stats stats; 223 | int status; 224 | int rx_int_enabled; 225 | int tx_int_enabled; 226 | struct jaldi_packet *tx_queue; /* packets scheduled for sending */ 227 | struct sk_buff *skb; 228 | spinlock_t sc_netdevlock; 229 | 230 | u8 macaddr[ETH_ALEN]; 231 | 232 | /* tx/rx */ 233 | struct jaldi_tx tx; 234 | struct jaldi_rx rx; 235 | u32 rx_bufsize; 236 | 237 | /* ops */ 238 | // none at softc level yet... 239 | 240 | struct jaldi_debug debug; 241 | }; 242 | 243 | static const struct net_device_ops jaldi_netdev_ops; 244 | 245 | // PCI/AHB init 246 | int jaldi_pci_init(void); 247 | void jaldi_pci_exit(void); 248 | int jaldi_ahb_init(void); 249 | void jaldi_ahb_exit(void); 250 | 251 | /* netdev */ 252 | struct net_device *jaldi_init_netdev(void); 253 | int jaldi_start_netdev(struct jaldi_softc *sc); 254 | void jaldi_attach_netdev_ops(struct net_device *dev); 255 | void jaldi_tasklet(unsigned long data); 256 | 257 | int jaldi_hw_reset(struct jaldi_hw *hw, struct jaldi_channel *chan, bool bChannelChange); 258 | bool jaldi_setpower(struct jaldi_softc *sc, enum jaldi_power_mode mode); 259 | void jaldi_ps_wakeup(struct jaldi_softc *sc); 260 | 261 | int jaldi_init_softc(u16 devid, struct jaldi_softc *sc, u16 subsysid, const struct jaldi_bus_ops *bus_ops); 262 | int jaldi_init_device(u16 devid, struct jaldi_softc *sc, u16 subsysid, const struct jaldi_bus_ops *bus_ops); 263 | void jaldi_deinit_device(struct jaldi_softc *sc); 264 | int jaldi_init_interrupts(struct jaldi_softc *sc); 265 | struct jaldi_txq *jaldi_txq_setup(struct jaldi_softc *sc, int qtype, int subtype); 266 | int jaldi_tx_setup(struct jaldi_softc *sc, int haltype); 267 | void jaldi_tx_cleanup(struct jaldi_softc *sc); 268 | void jaldi_rx_cleanup(struct jaldi_softc *sc); 269 | struct sk_buff *jaldi_rxbuf_alloc(struct jaldi_softc *sc, u32 len); 270 | 271 | int jaldi_descdma_setup(struct jaldi_softc *sc, struct jaldi_descdma *dd, 272 | struct list_head *head, const char *name, 273 | int nbuf, int ndesc, bool is_tx); 274 | void jaldi_descdma_cleanup(struct jaldi_softc *sc, struct jaldi_descdma *dd, 275 | struct list_head *head); 276 | 277 | void jaldi_tx_cleanupq(struct jaldi_softc *sc, struct jaldi_txq *txq); 278 | irqreturn_t jaldi_isr(int irq, void *dev); 279 | int jaldi_rx_tasklet(struct jaldi_softc *sc, int flush); 280 | 281 | #endif /* JALDI_H */ 282 | 283 | -------------------------------------------------------------------------------- /kerneldriver/pci.c: -------------------------------------------------------------------------------- 1 | /* 2 | * JaldiMAC PCI related stuff 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include "jaldi.h" 9 | 10 | /* device id table taken from ath9k/pci.c */ 11 | //static struct pci_device_id jaldi_pci_id_table[] __devinitdata = { 12 | static DEFINE_PCI_DEVICE_TABLE(jaldi_pci_id_table) = { 13 | { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ 14 | { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ 15 | { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ 16 | { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ 17 | { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ 18 | { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ 19 | { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */ 20 | { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ 21 | { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ 22 | { 0 } 23 | }; 24 | 25 | /* bus ops */ 26 | static void jaldi_pci_read_cachesize(struct jaldi_softc *sc, int *csz) { 27 | u8 u8tmp; 28 | DBG_START_MSG; 29 | pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp); 30 | *csz = (int)u8tmp; 31 | 32 | /* Apparently cache line size register sometimes is not set, so we check here */ 33 | if (*csz == 0) { *csz = DEFAULT_CACHELINE >> 2; } 34 | } 35 | 36 | static bool jaldi_pci_eeprom_read(struct jaldi_softc *sc, u32 off, u16 *data) 37 | { 38 | u32 val; 39 | struct ath9k_platform_data *pdata = sc->dev->platform_data; 40 | 41 | if (pdata) { 42 | if (off >= ARRAY_SIZE(pdata->eeprom_data)) { 43 | jaldi_print(JALDI_FATAL, "%s: eeprom read failed, offset %08x is out of range.\n", 44 | __func__, off); 45 | } 46 | 47 | *data = pdata->eeprom_data[off]; 48 | } else { 49 | jaldi_print(JALDI_WARN, "Uh-oh, not using pdata for eeprom_read. EEPROM probably ain't going to work.\n"); 50 | struct jaldi_hw *hw = sc->hw; 51 | 52 | hw->reg_ops->read(hw, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); 53 | 54 | if (!jaldi_hw_wait(hw, 55 | AR_EEPROM_STATUS_DATA, 56 | AR_EEPROM_STATUS_DATA_BUSY | 57 | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, 58 | JALDI_WAIT_TIMEOUT)) 59 | { return false; } 60 | 61 | /* The value we have specified via the passed offset is placed 62 | * in this register. We save save the last two bytes of the value 63 | * we read, and no shift occurs (shift is 0). */ 64 | val = hw->reg_ops->read(hw, AR_EEPROM_STATUS_DATA); 65 | *data = MS(val, AR_EEPROM_STATUS_DATA_VAL); 66 | // jaldi_print(JALDI_DEBUG, "pci_eeprom_read reg_off: %lx val: %8x data: %8x\n", 67 | // (unsigned long)(AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)), val, *data); 68 | } 69 | return true; 70 | } 71 | 72 | static const struct jaldi_bus_ops jaldi_pci_bus_ops = { 73 | .type = JALDI_PCI, 74 | .read_cachesize = jaldi_pci_read_cachesize, 75 | .eeprom_read = jaldi_pci_eeprom_read, 76 | }; 77 | 78 | static int jaldi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 79 | { 80 | void __iomem *mem; 81 | struct jaldi_softc *sc; 82 | struct net_device *jaldi_dev; 83 | u8 csz; 84 | u16 subsysid; 85 | u32 val; 86 | int ret = 0; 87 | 88 | DBG_START_MSG; 89 | if (pci_enable_device(pdev)) { 90 | return -EIO; 91 | } 92 | 93 | ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 94 | if (ret) { 95 | printk(KERN_ERR "jaldi: 32-bit DMA not available\n"); 96 | goto err_dma; 97 | } 98 | 99 | ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); 100 | if (ret) { 101 | printk(KERN_ERR "jaldi: 32-bit DMA consistent " 102 | "DMA enable failed\n"); 103 | goto err_dma; 104 | } 105 | 106 | /* 107 | * Cache line size is used to size and align various 108 | * structures used to communicate with the hardware. 109 | */ 110 | pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); 111 | if (csz == 0) { 112 | /* 113 | * Linux 2.4.18 (at least) writes the cache line size 114 | * register as a 16-bit wide register which is wrong. 115 | * We must have this setup properly for rx buffer 116 | * DMA to work so force a reasonable value here if it 117 | * comes up zero. 118 | */ 119 | csz = L1_CACHE_BYTES / sizeof(u32); 120 | pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); 121 | } 122 | /* 123 | * The default setting of latency timer yields poor results, 124 | * set it to the value used by other systems. It may be worth 125 | * tweaking this setting more. 126 | */ 127 | pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); 128 | 129 | pci_set_master(pdev); 130 | 131 | /* 132 | * Disable the RETRY_TIMEOUT register (0x41) to keep 133 | * PCI Tx retries from interfering with C3 CPU state. 134 | */ 135 | pci_read_config_dword(pdev, 0x40, &val); 136 | if ((val & 0x0000ff00) != 0) 137 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); 138 | 139 | ret = pci_request_region(pdev, 0, "jaldi"); 140 | if (ret) { 141 | dev_err(&pdev->dev, "PCI memory region reserve error\n"); 142 | ret = -ENODEV; 143 | goto err_region; 144 | } 145 | 146 | mem = pci_iomap(pdev, 0, 0); 147 | if (!mem) { 148 | jaldi_print(JALDI_FATAL, "PCI memory map error\n") ; 149 | ret = -EIO; 150 | goto err_iomap; 151 | } 152 | 153 | /* allocate and register net_dev, also allocs softc */ 154 | jaldi_dev = jaldi_init_netdev(); 155 | 156 | if (jaldi_dev < 0) { 157 | jaldi_print(JALDI_FATAL, "could not init netdev\n"); 158 | goto err_alloc_hw; 159 | } 160 | 161 | sc = netdev_priv(jaldi_dev); 162 | 163 | if (!sc) { 164 | dev_err(&pdev->dev, "No memory for jaldi_softc\n"); 165 | ret = -ENOMEM; 166 | goto err_no_softc; 167 | } 168 | 169 | 170 | jaldi_print(JALDI_DEBUG, "jnd: %p jnd_priv: %p\n", 171 | jaldi_dev, netdev_priv(jaldi_dev)); 172 | jaldi_print(JALDI_DEBUG, "sc->dev: %p sc: %p\n", 173 | sc->net_dev, sc); 174 | pci_set_drvdata(pdev, sc); 175 | sc->dev = &pdev->dev; 176 | sc->mem = mem; 177 | 178 | 179 | sc->sc_flags |= SC_OP_INVALID; // irq is not ready, don't try to use the device yet. 180 | 181 | ret = request_irq(pdev->irq, jaldi_isr, IRQF_SHARED, "jaldi", sc); 182 | 183 | sc->irq = pdev->irq; // Keep track of IRQ in softc 184 | 185 | if (ret) { 186 | dev_err(&pdev->dev, "request_irq failed\n"); 187 | goto err_irq; 188 | } 189 | 190 | jaldi_print(JALDI_INFO, "sc->mem: %lx irq:%d\n", (unsigned long)mem, pdev->irq); 191 | jaldi_print(JALDI_INFO, "irq:%d\n", ((struct jaldi_softc *)netdev_priv(sc->net_dev))->irq); 192 | 193 | pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); 194 | ret = jaldi_init_device(id->device, sc, subsysid, &jaldi_pci_bus_ops); 195 | if (ret) { 196 | jaldi_print(JALDI_FATAL, "Failed to initialize device.\n"); 197 | goto err_init; 198 | } 199 | 200 | /* alright let's do this */ 201 | ret = jaldi_start_netdev(sc); 202 | if (ret) { 203 | jaldi_print(JALDI_FATAL, "Failed to register netdev\n"); 204 | goto err_start; 205 | } 206 | 207 | jaldi_print(JALDI_INFO, "pci probe done\n"); 208 | 209 | return 0; 210 | 211 | err_start: 212 | jaldi_deinit_device(sc); 213 | err_init: 214 | free_irq(sc->irq, sc); 215 | err_irq: 216 | /* nothing, init_netdev cleans itself up now */ 217 | err_no_softc: 218 | free_netdev(jaldi_dev); 219 | err_alloc_hw: 220 | pci_iounmap(pdev, mem); 221 | err_iomap: 222 | pci_release_region(pdev, 0); 223 | err_region: 224 | /* Nothing */ 225 | err_dma: 226 | pci_disable_device(pdev); 227 | return ret; 228 | } 229 | 230 | static void jaldi_pci_remove(struct pci_dev *pdev) 231 | { 232 | struct jaldi_softc *sc; 233 | void __iomem *mem; 234 | 235 | jaldi_print(JALDI_DEBUG,"Entering '%s'\n", __FUNCTION__); 236 | sc = pci_get_drvdata(pdev); 237 | mem = sc->mem; 238 | 239 | unregister_netdev(sc->net_dev); 240 | 241 | jaldi_deinit_device(sc); 242 | free_irq(sc->irq, sc); 243 | 244 | free_netdev(sc->net_dev); 245 | 246 | pci_iounmap(pdev, mem); 247 | pci_disable_device(pdev); 248 | pci_release_region(pdev, 0); 249 | } 250 | 251 | MODULE_DEVICE_TABLE(pci, jaldi_pci_id_table); 252 | 253 | static struct pci_driver jaldi_pci_driver = { 254 | .name = "jaldi", 255 | .id_table = jaldi_pci_id_table, 256 | .probe = jaldi_pci_probe, 257 | .remove = jaldi_pci_remove, 258 | }; 259 | 260 | int jaldi_pci_init(void) 261 | { 262 | jaldi_print(JALDI_DEBUG,"Entering '%s'\n", __FUNCTION__); 263 | return pci_register_driver(&jaldi_pci_driver); 264 | } 265 | 266 | void jaldi_pci_exit(void) 267 | { 268 | jaldi_print(JALDI_DEBUG,"Entering '%s'\n", __FUNCTION__); 269 | pci_unregister_driver(&jaldi_pci_driver); 270 | } 271 | -------------------------------------------------------------------------------- /kerneldriver/phy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PHY-related settings. 3 | */ 4 | 5 | #include "jaldi.h" 6 | #include "hw.h" 7 | 8 | /************** 9 | * General phy 10 | **************/ 11 | static int jaldi_hw_set_freq(struct jaldi_hw *hw, struct jaldi_channel *chan) 12 | { 13 | u16 bMode, fracMode, aModeRefSel = 0; 14 | u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0; 15 | u32 refDivA = 24; 16 | 17 | struct chan_centers centers; 18 | jaldi_hw_get_channel_centers(chan, ¢ers); 19 | 20 | freq = centers.synth_center; 21 | 22 | reg32 = REG_READ(hw, AR_PHY_SYNTH_CONTROL); 23 | reg32 &= 0xc0000000; 24 | 25 | if (freq < 4800) { 26 | // we're on an unsupported 2GHz band 27 | jaldi_print(0, "2Ghz band is not supported.\n"); 28 | } else { 29 | // we're on the 5Ghz band 30 | switch (hw->eep_ops->get_eeprom(hw, EEP_FRAC_N_5G)) { 31 | case 0: 32 | if ((freq % 20) == 0 ) { aModeRefSel = 3; } 33 | else if ((freq % 10) == 0) { aModeRefSel = 2; } 34 | if (aModeRefSel) { break; } 35 | case 1: 36 | default: 37 | aModeRefSel = 0; 38 | /* Enable "2G (fractional) mode for 5Mhz spaced channels */ 39 | fracMode = 1; 40 | refDivA = 1; 41 | channelSel = CHANSEL_5G(freq); 42 | 43 | /* RefDivA setting */ 44 | REG_RMW_FIELD(hw, AR_AN_SYNTH9, AR_AN_SYNTH9_REFDIVA, refDivA); 45 | } 46 | 47 | if(!fracMode) { 48 | ndiv = (freq * (refDivA >> aModeRefSel)) / 60; 49 | channelSel = ndiv & 0x1ff; 50 | channelFrac = (ndiv & 0xfffffe00) * 2; 51 | channelSel = (channelSel << 17) | channelFrac; 52 | } 53 | 54 | } 55 | 56 | reg32 = reg32 | 57 | (bMode << 29) | // not used on 5G band 58 | (fracMode << 28) | 59 | (aModeRefSel << 26) | 60 | (channelSel); 61 | 62 | REG_WRITE(hw, AR_PHY_SYNTH_CONTROL, reg32); 63 | 64 | hw->curchan = chan; 65 | 66 | return 0; 67 | } 68 | 69 | 70 | /** 71 | * ar9002_hw_spur_mitigate - convert baseband spur frequency 72 | * @hw: hardware structure 73 | * @chan: 74 | * 75 | * For single-chip solutions. Converts to baseband spur frequency given the 76 | * input channel frequency and compute register settings below. 77 | */ 78 | static void jaldi_hw_spur_mitigate(struct jaldi_hw *hw, 79 | struct jaldi_channel *chan) 80 | { 81 | int bb_spur = AR_NO_SPUR; 82 | int freq; 83 | int bin, cur_bin; 84 | int bb_spur_off, spur_subchannel_sd; 85 | int spur_freq_sd; 86 | int spur_delta_phase; 87 | int denominator; 88 | int upper, lower, cur_vit_mask; 89 | int tmp, newVal; 90 | int i; 91 | int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, 92 | AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 93 | }; 94 | int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, 95 | AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 96 | }; 97 | int inc[4] = { 0, 100, 0, 0 }; 98 | struct chan_centers centers; 99 | 100 | int8_t mask_m[123]; 101 | int8_t mask_p[123]; 102 | int8_t mask_amt; 103 | int tmp_mask; 104 | int cur_bb_spur; 105 | bool is2GHz = IS_CHAN_2GHZ(chan); 106 | 107 | memset(&mask_m, 0, sizeof(int8_t) * 123); 108 | memset(&mask_p, 0, sizeof(int8_t) * 123); 109 | 110 | jaldi_hw_get_channel_centers(chan, ¢ers); 111 | freq = centers.synth_center; 112 | 113 | hw->spurmode = SPUR_ENABLE_EEPROM; 114 | for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { 115 | cur_bb_spur = hw->eep_ops->get_spur_channel(hw, i, is2GHz); 116 | 117 | if (is2GHz) 118 | cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; 119 | else 120 | cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; 121 | 122 | if (AR_NO_SPUR == cur_bb_spur) 123 | break; 124 | cur_bb_spur = cur_bb_spur - freq; 125 | 126 | if (IS_CHAN_HT40(chan)) { 127 | if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && 128 | (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { 129 | bb_spur = cur_bb_spur; 130 | break; 131 | } 132 | } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && 133 | (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { 134 | bb_spur = cur_bb_spur; 135 | break; 136 | } 137 | } 138 | 139 | if (AR_NO_SPUR == bb_spur) { 140 | REG_CLR_BIT(hw, AR_PHY_FORCE_CLKEN_CCK, 141 | AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); 142 | return; 143 | } else { 144 | REG_CLR_BIT(hw, AR_PHY_FORCE_CLKEN_CCK, 145 | AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); 146 | } 147 | 148 | bin = bb_spur * 320; 149 | 150 | tmp = REG_READ(hw, AR_PHY_TIMING_CTRL4(0)); 151 | 152 | ENABLE_REGWRITE_BUFFER(hw); 153 | 154 | newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | 155 | AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | 156 | AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | 157 | AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); 158 | REG_WRITE(hw, AR_PHY_TIMING_CTRL4(0), newVal); 159 | 160 | newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | 161 | AR_PHY_SPUR_REG_ENABLE_MASK_PPM | 162 | AR_PHY_SPUR_REG_MASK_RATE_SELECT | 163 | AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | 164 | SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); 165 | REG_WRITE(hw, AR_PHY_SPUR_REG, newVal); 166 | 167 | if (IS_CHAN_HT40(chan)) { 168 | if (bb_spur < 0) { 169 | spur_subchannel_sd = 1; 170 | bb_spur_off = bb_spur + 10; 171 | } else { 172 | spur_subchannel_sd = 0; 173 | bb_spur_off = bb_spur - 10; 174 | } 175 | } else { 176 | spur_subchannel_sd = 0; 177 | bb_spur_off = bb_spur; 178 | } 179 | 180 | if (IS_CHAN_HT40(chan)) 181 | spur_delta_phase = 182 | ((bb_spur * 262144) / 183 | 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; 184 | else 185 | spur_delta_phase = 186 | ((bb_spur * 524288) / 187 | 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; 188 | 189 | denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; 190 | spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; 191 | 192 | newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | 193 | SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | 194 | SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); 195 | REG_WRITE(hw, AR_PHY_TIMING11, newVal); 196 | 197 | newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; 198 | REG_WRITE(hw, AR_PHY_SFCORR_EXT, newVal); 199 | 200 | cur_bin = -6000; 201 | upper = bin + 100; 202 | lower = bin - 100; 203 | 204 | for (i = 0; i < 4; i++) { 205 | int pilot_mask = 0; 206 | int chan_mask = 0; 207 | int bp = 0; 208 | for (bp = 0; bp < 30; bp++) { 209 | if ((cur_bin > lower) && (cur_bin < upper)) { 210 | pilot_mask = pilot_mask | 0x1 << bp; 211 | chan_mask = chan_mask | 0x1 << bp; 212 | } 213 | cur_bin += 100; 214 | } 215 | cur_bin += inc[i]; 216 | REG_WRITE(hw, pilot_mask_reg[i], pilot_mask); 217 | REG_WRITE(hw, chan_mask_reg[i], chan_mask); 218 | } 219 | 220 | cur_vit_mask = 6100; 221 | upper = bin + 120; 222 | lower = bin - 120; 223 | 224 | for (i = 0; i < 123; i++) { 225 | if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { 226 | 227 | /* workaround for gcc bug #37014 */ 228 | volatile int tmp_v = abs(cur_vit_mask - bin); 229 | 230 | if (tmp_v < 75) 231 | mask_amt = 1; 232 | else 233 | mask_amt = 0; 234 | if (cur_vit_mask < 0) 235 | mask_m[abs(cur_vit_mask / 100)] = mask_amt; 236 | else 237 | mask_p[cur_vit_mask / 100] = mask_amt; 238 | } 239 | cur_vit_mask -= 100; 240 | } 241 | 242 | tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) 243 | | (mask_m[48] << 26) | (mask_m[49] << 24) 244 | | (mask_m[50] << 22) | (mask_m[51] << 20) 245 | | (mask_m[52] << 18) | (mask_m[53] << 16) 246 | | (mask_m[54] << 14) | (mask_m[55] << 12) 247 | | (mask_m[56] << 10) | (mask_m[57] << 8) 248 | | (mask_m[58] << 6) | (mask_m[59] << 4) 249 | | (mask_m[60] << 2) | (mask_m[61] << 0); 250 | REG_WRITE(hw, AR_PHY_BIN_MASK_1, tmp_mask); 251 | REG_WRITE(hw, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); 252 | 253 | tmp_mask = (mask_m[31] << 28) 254 | | (mask_m[32] << 26) | (mask_m[33] << 24) 255 | | (mask_m[34] << 22) | (mask_m[35] << 20) 256 | | (mask_m[36] << 18) | (mask_m[37] << 16) 257 | | (mask_m[48] << 14) | (mask_m[39] << 12) 258 | | (mask_m[40] << 10) | (mask_m[41] << 8) 259 | | (mask_m[42] << 6) | (mask_m[43] << 4) 260 | | (mask_m[44] << 2) | (mask_m[45] << 0); 261 | REG_WRITE(hw, AR_PHY_BIN_MASK_2, tmp_mask); 262 | REG_WRITE(hw, AR_PHY_MASK2_M_31_45, tmp_mask); 263 | 264 | tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) 265 | | (mask_m[18] << 26) | (mask_m[18] << 24) 266 | | (mask_m[20] << 22) | (mask_m[20] << 20) 267 | | (mask_m[22] << 18) | (mask_m[22] << 16) 268 | | (mask_m[24] << 14) | (mask_m[24] << 12) 269 | | (mask_m[25] << 10) | (mask_m[26] << 8) 270 | | (mask_m[27] << 6) | (mask_m[28] << 4) 271 | | (mask_m[29] << 2) | (mask_m[30] << 0); 272 | REG_WRITE(hw, AR_PHY_BIN_MASK_3, tmp_mask); 273 | REG_WRITE(hw, AR_PHY_MASK2_M_16_30, tmp_mask); 274 | 275 | tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) 276 | | (mask_m[2] << 26) | (mask_m[3] << 24) 277 | | (mask_m[4] << 22) | (mask_m[5] << 20) 278 | | (mask_m[6] << 18) | (mask_m[7] << 16) 279 | | (mask_m[8] << 14) | (mask_m[9] << 12) 280 | | (mask_m[10] << 10) | (mask_m[11] << 8) 281 | | (mask_m[12] << 6) | (mask_m[13] << 4) 282 | | (mask_m[14] << 2) | (mask_m[15] << 0); 283 | REG_WRITE(hw, AR_PHY_MASK_CTL, tmp_mask); 284 | REG_WRITE(hw, AR_PHY_MASK2_M_00_15, tmp_mask); 285 | 286 | tmp_mask = (mask_p[15] << 28) 287 | | (mask_p[14] << 26) | (mask_p[13] << 24) 288 | | (mask_p[12] << 22) | (mask_p[11] << 20) 289 | | (mask_p[10] << 18) | (mask_p[9] << 16) 290 | | (mask_p[8] << 14) | (mask_p[7] << 12) 291 | | (mask_p[6] << 10) | (mask_p[5] << 8) 292 | | (mask_p[4] << 6) | (mask_p[3] << 4) 293 | | (mask_p[2] << 2) | (mask_p[1] << 0); 294 | REG_WRITE(hw, AR_PHY_BIN_MASK2_1, tmp_mask); 295 | REG_WRITE(hw, AR_PHY_MASK2_P_15_01, tmp_mask); 296 | 297 | tmp_mask = (mask_p[30] << 28) 298 | | (mask_p[29] << 26) | (mask_p[28] << 24) 299 | | (mask_p[27] << 22) | (mask_p[26] << 20) 300 | | (mask_p[25] << 18) | (mask_p[24] << 16) 301 | | (mask_p[23] << 14) | (mask_p[22] << 12) 302 | | (mask_p[21] << 10) | (mask_p[20] << 8) 303 | | (mask_p[19] << 6) | (mask_p[18] << 4) 304 | | (mask_p[17] << 2) | (mask_p[16] << 0); 305 | REG_WRITE(hw, AR_PHY_BIN_MASK2_2, tmp_mask); 306 | REG_WRITE(hw, AR_PHY_MASK2_P_30_16, tmp_mask); 307 | 308 | tmp_mask = (mask_p[45] << 28) 309 | | (mask_p[44] << 26) | (mask_p[43] << 24) 310 | | (mask_p[42] << 22) | (mask_p[41] << 20) 311 | | (mask_p[40] << 18) | (mask_p[39] << 16) 312 | | (mask_p[38] << 14) | (mask_p[37] << 12) 313 | | (mask_p[36] << 10) | (mask_p[35] << 8) 314 | | (mask_p[34] << 6) | (mask_p[33] << 4) 315 | | (mask_p[32] << 2) | (mask_p[31] << 0); 316 | REG_WRITE(hw, AR_PHY_BIN_MASK2_3, tmp_mask); 317 | REG_WRITE(hw, AR_PHY_MASK2_P_45_31, tmp_mask); 318 | 319 | tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) 320 | | (mask_p[59] << 26) | (mask_p[58] << 24) 321 | | (mask_p[57] << 22) | (mask_p[56] << 20) 322 | | (mask_p[55] << 18) | (mask_p[54] << 16) 323 | | (mask_p[53] << 14) | (mask_p[52] << 12) 324 | | (mask_p[51] << 10) | (mask_p[50] << 8) 325 | | (mask_p[49] << 6) | (mask_p[48] << 4) 326 | | (mask_p[47] << 2) | (mask_p[46] << 0); 327 | REG_WRITE(hw, AR_PHY_BIN_MASK2_4, tmp_mask); 328 | REG_WRITE(hw, AR_PHY_MASK2_P_61_45, tmp_mask); 329 | 330 | REGWRITE_BUFFER_FLUSH(hw); 331 | DISABLE_REGWRITE_BUFFER(hw); 332 | } 333 | 334 | static void jaldi_hw_do_getnf(struct jaldi_hw *hw, 335 | int16_t nfarray[NUM_NF_READINGS]) 336 | { 337 | int16_t nf; 338 | 339 | nf = MS(REG_READ(hw, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); 340 | 341 | if (nf & 0x100) 342 | nf = 0 - ((nf ^ 0x1ff) + 1); 343 | jaldi_print(JALDI_DEBUG, 344 | "NF calibrated [ctl] [chain 0] is %d\n", nf); 345 | 346 | if (AR_SREV_9271(hw) && (nf >= -114)) 347 | nf = -116; 348 | 349 | nfarray[0] = nf; 350 | 351 | if (!AR_SREV_9285(hw) && !AR_SREV_9271(hw)) { 352 | nf = MS(REG_READ(hw, AR_PHY_CH1_CCA), 353 | AR9280_PHY_CH1_MINCCA_PWR); 354 | 355 | if (nf & 0x100) 356 | nf = 0 - ((nf ^ 0x1ff) + 1); 357 | jaldi_print(JALDI_INFO, 358 | "NF calibrated [ctl] [chain 1] is %d\n", nf); 359 | nfarray[1] = nf; 360 | } 361 | 362 | nf = MS(REG_READ(hw, AR_PHY_EXT_CCA), AR9280_PHY_EXT_MINCCA_PWR); 363 | if (nf & 0x100) 364 | nf = 0 - ((nf ^ 0x1ff) + 1); 365 | jaldi_print(JALDI_INFO, 366 | "NF calibrated [ext] [chain 0] is %d\n", nf); 367 | 368 | if (AR_SREV_9271(hw) && (nf >= -114)) 369 | nf = -116; 370 | 371 | nfarray[3] = nf; 372 | 373 | if (!AR_SREV_9285(hw) && !AR_SREV_9271(hw)) { 374 | nf = MS(REG_READ(hw, AR_PHY_CH1_EXT_CCA), 375 | AR9280_PHY_CH1_EXT_MINCCA_PWR); 376 | 377 | if (nf & 0x100) 378 | nf = 0 - ((nf ^ 0x1ff) + 1); 379 | jaldi_print(JALDI_INFO, 380 | "NF calibrated [ext] [chain 1] is %d\n", nf); 381 | nfarray[4] = nf; 382 | } 383 | } 384 | 385 | static void ar5008_hw_set_rfmode(struct jaldi_hw *hw, struct jaldi_channel *chan) 386 | { 387 | u32 rfMode = 0; 388 | 389 | if (chan == NULL) 390 | return; 391 | 392 | rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) 393 | ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; 394 | 395 | if (!AR_SREV_9280_10_OR_LATER(hw)) 396 | rfMode |= (IS_CHAN_5GHZ(chan)) ? 397 | AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ; 398 | 399 | if (IS_CHAN_A_FAST_CLOCK(hw, chan)) 400 | rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); 401 | 402 | REG_WRITE(hw, AR_PHY_MODE, rfMode); 403 | } 404 | 405 | static u32 ar9002_hw_compute_pll_control(struct jaldi_hw *hw, 406 | struct jaldi_channel *chan) 407 | { 408 | u32 pll; 409 | 410 | DBG_START_MSG; 411 | 412 | pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); 413 | 414 | if (chan && IS_CHAN_HALF_RATE(chan)) 415 | pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); 416 | else if (chan && IS_CHAN_QUARTER_RATE(chan)) 417 | pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); 418 | 419 | if (chan && IS_CHAN_5GHZ(chan)) { 420 | if (IS_CHAN_A_FAST_CLOCK(hw, chan)) 421 | pll = 0x142c; 422 | else if (AR_SREV_9280_20(hw)) 423 | pll = 0x2850; 424 | else 425 | pll |= SM(0x28, AR_RTC_9160_PLL_DIV); 426 | } else { 427 | pll |= SM(0x2c, AR_RTC_9160_PLL_DIV); 428 | } 429 | 430 | return pll; 431 | } 432 | 433 | static u32 ar9100_hw_compute_pll_control(struct jaldi_hw *hw, 434 | struct jaldi_channel *chan) 435 | { 436 | DBG_START_MSG; 437 | if (chan && IS_CHAN_5GHZ(chan)) 438 | return 0x1450; 439 | return 0x1458; 440 | } 441 | 442 | static u32 ar9160_hw_compute_pll_control(struct jaldi_hw *hw, 443 | struct jaldi_channel *chan) 444 | { 445 | u32 pll; 446 | 447 | DBG_START_MSG; 448 | pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); 449 | 450 | if (chan && IS_CHAN_HALF_RATE(chan)) 451 | pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); 452 | else if (chan && IS_CHAN_QUARTER_RATE(chan)) 453 | pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); 454 | 455 | if (chan && IS_CHAN_5GHZ(chan)) 456 | pll |= SM(0x50, AR_RTC_9160_PLL_DIV); 457 | else 458 | pll |= SM(0x58, AR_RTC_9160_PLL_DIV); 459 | 460 | return pll; 461 | } 462 | 463 | static u32 ar5008_hw_compute_pll_control(struct jaldi_hw *hw, 464 | struct jaldi_channel *chan) 465 | { 466 | u32 pll; 467 | 468 | DBG_START_MSG; 469 | pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; 470 | 471 | if (chan && IS_CHAN_HALF_RATE(chan)) 472 | pll |= SM(0x1, AR_RTC_PLL_CLKSEL); 473 | else if (chan && IS_CHAN_QUARTER_RATE(chan)) 474 | pll |= SM(0x2, AR_RTC_PLL_CLKSEL); 475 | 476 | if (chan && IS_CHAN_5GHZ(chan)) 477 | pll |= SM(0xa, AR_RTC_PLL_DIV); 478 | else 479 | pll |= SM(0xb, AR_RTC_PLL_DIV); 480 | 481 | return pll; 482 | } 483 | 484 | static void ar9002_olc_init(struct jaldi_hw *hw) 485 | { 486 | u32 i; 487 | 488 | if (!OLC_FOR_AR9280_20_LATER) 489 | return; 490 | 491 | if (OLC_FOR_AR9287_10_LATER) { 492 | REG_SET_BIT(hw, AR_PHY_TX_PWRCTRL9, 493 | AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL); 494 | jaldi_hw_analog_shift_rmw(hw, AR9287_AN_TXPC0, 495 | AR9287_AN_TXPC0_TXPCMODE, 496 | AR9287_AN_TXPC0_TXPCMODE_S, 497 | AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE); 498 | udelay(100); 499 | } else { 500 | for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) 501 | hw->originalGain[i] = 502 | MS(REG_READ(hw, AR_PHY_TX_GAIN_TBL1 + i * 4), 503 | AR_PHY_TX_GAIN); 504 | hw->PDADCdelta = 0; 505 | } 506 | } 507 | 508 | static void ar5008_hw_set_channel_regs(struct jaldi_hw *hw, 509 | struct jaldi_channel *chan) 510 | { 511 | u32 phymode; 512 | u32 macmode; 513 | u32 enableDacFifo = 0; 514 | 515 | if (AR_SREV_9285_10_OR_LATER(hw)) 516 | enableDacFifo = (REG_READ(hw, AR_PHY_TURBO) & 517 | AR_PHY_FC_ENABLE_DAC_FIFO); 518 | 519 | phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 520 | | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo; 521 | 522 | if (IS_CHAN_HT40(chan)) { 523 | phymode |= AR_PHY_FC_DYN2040_EN; 524 | 525 | if ((chan->chanmode == CHANNEL_A_HT40PLUS) || 526 | (chan->chanmode == CHANNEL_G_HT40PLUS)) 527 | phymode |= AR_PHY_FC_DYN2040_PRI_CH; 528 | 529 | } 530 | REG_WRITE(hw, AR_PHY_TURBO, phymode); 531 | 532 | if(IS_CHAN_HT40(chan)) 533 | macmode = AR_2040_JOINED_RX_CLEAR; 534 | else 535 | macmode = 0; 536 | 537 | REG_WRITE(hw, AR_2040_MODE, macmode); 538 | 539 | ENABLE_REGWRITE_BUFFER(hw); 540 | 541 | REG_WRITE(hw, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); 542 | REG_WRITE(hw, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); 543 | 544 | REGWRITE_BUFFER_FLUSH(hw); 545 | DISABLE_REGWRITE_BUFFER(hw); 546 | } 547 | 548 | static bool ar5008_hw_rfbus_req(struct jaldi_hw *hw) 549 | { 550 | REG_WRITE(hw, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); 551 | return jaldi_hw_wait(hw, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, 552 | AR_PHY_RFBUS_GRANT_EN, JALDI_WAIT_TIMEOUT); 553 | } 554 | 555 | static void ar5008_hw_rfbus_done(struct jaldi_hw *hw) 556 | { 557 | u32 synthDelay = REG_READ(hw, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; 558 | if (IS_CHAN_B(hw->curchan)) 559 | synthDelay = (4 * synthDelay) / 22; 560 | else 561 | synthDelay /= 10; 562 | 563 | udelay(synthDelay + BASE_ACTIVATE_DELAY); 564 | 565 | REG_WRITE(hw, AR_PHY_RFBUS_REQ, 0); 566 | } 567 | 568 | void jaldi_hw_attach_phy_ops(struct jaldi_hw *hw) 569 | { 570 | struct jaldi_hw_ops *ops = jaldi_get_hw_ops(hw); 571 | 572 | ops->rf_set_freq = jaldi_hw_set_freq; 573 | ops->spur_mitigate_freq = jaldi_hw_spur_mitigate; 574 | ops->do_getnf = jaldi_hw_do_getnf; 575 | ops->set_rfmode = ar5008_hw_set_rfmode; 576 | ops->olc_init = ar9002_olc_init; 577 | ops->rfbus_done = ar5008_hw_rfbus_done; 578 | ops->rfbus_req = ar5008_hw_rfbus_req; 579 | ops->set_channel_regs = ar5008_hw_set_channel_regs; 580 | 581 | if (AR_SREV_9280_10_OR_LATER(hw)) 582 | ops->compute_pll_control = ar9002_hw_compute_pll_control; 583 | else if (AR_SREV_9100(hw)) 584 | ops->compute_pll_control = ar9100_hw_compute_pll_control; 585 | else if (AR_SREV_9160_10_OR_LATER(hw)) 586 | ops->compute_pll_control = ar9160_hw_compute_pll_control; 587 | else 588 | ops->compute_pll_control = ar5008_hw_compute_pll_control; 589 | } 590 | 591 | /* 592 | * Remaining phy_ops (as seen in ar9002_phy.c) 593 | * set_rf_regs = NULL; 594 | * set_rf_alloc_ext_banks = NULL; 595 | * set_rf_free_ext_banks = NULL; 596 | * rf_set_freq (implemented above) 597 | * spur_mitigate_freq = ar9002_hw_spur_mitigate; (not sure what this does) 598 | * olc_init = ar9002_olc_init 599 | * - For before AR9280, this does not seem to be used (i.e., not supported on chip) 600 | * - For AR9287 and later, does something with tempsense 601 | * - For everything else, does something with gain (gain table... what is this?) 602 | * compute_pll_control = ar9002_hw_compute_pll_control 603 | - ... 604 | * do_getnf = ar9002_hw_do_getnf (reads various CCA registers and sets nf to 'min pwr' on each) 605 | */ 606 | -------------------------------------------------------------------------------- /openwrt-feed/jaldi-click/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2006-2010 OpenWrt.org 3 | # 4 | # This is free software, licensed under the GNU General Public License v2. 5 | # See /LICENSE for more information. 6 | # 7 | 8 | include $(TOPDIR)/rules.mk 9 | 10 | PKG_NAME:=jaldiclick 11 | PKG_VERSION:=20110221 12 | PKG_RELEASE:=1 13 | PKG_REV:=effd89b3ef232a2fe34a63d18de274012397cd6c 14 | 15 | PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz 16 | PKG_SOURCE_URL:=git://github.com/kohler/click.git 17 | PKG_SOURCE_PROTO:=git 18 | PKG_SOURCE_VERSION:=$(PKG_REV) 19 | PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) 20 | #PKG_MD5SUM:=c3cba1c923d0a034cc518720b5ba7b40 21 | 22 | include $(INCLUDE_DIR)/package.mk 23 | 24 | define Package/jaldiclick 25 | SECTION:=net 26 | CATEGORY:=Network 27 | TITLE:=Click Modular Router - JaldiMAC additions 28 | URL:=http://read.cs.ucla.edu/click 29 | endef 30 | 31 | define Package/jaldiclick/Description 32 | The Click Modular Router userspace package, with JaldiMAC additions 33 | endef 34 | 35 | TARGET_CFLAGS += "-static -O2 -MD" 36 | TARGET_CXXFLAGS += "-static -O2 -MD" 37 | 38 | define Build/Configure 39 | (cd $(PKG_BUILD_DIR); \ 40 | rm -rf config.{cache,status} ; \ 41 | ./configure \ 42 | --prefix=/usr \ 43 | --target=$(GNU_TARGET_NAME) \ 44 | --host=$(GNU_HOST_NAME) \ 45 | --build=$(GNU_BUILD_NAME) \ 46 | --enable-tools=mixed \ 47 | --enable-userlevel \ 48 | --enable-wifi \ 49 | --enable-fixincludes \ 50 | --disable-linuxmodule \ 51 | ) 52 | endef 53 | 54 | define Build/Compile 55 | $(MAKE) -C $(PKG_BUILD_DIR) \ 56 | tools elementmap.xml 57 | (cd $(PKG_BUILD_DIR)/userlevel; \ 58 | ../tools/click-mkmindriver/click-mkmindriver -p $(PKG_NAME) -C .. \ 59 | -f $(PKG_BUILD_DIR)/conf/wifi/dump.click \ 60 | -A --all -E Discard -E Print; \ 61 | ) 62 | $(MAKE) -C $(PKG_BUILD_DIR) MINDRIVER=$(PKG_NAME) 63 | endef 64 | 65 | define Package/jaldiclick/install 66 | $(INSTALL_DIR) $(1)/usr 67 | $(INSTALL_DIR) $(1)/usr/bin 68 | $(INSTALL_DIR) $(1)/usr/share/jaldiclick 69 | $(CP) $(PKG_BUILD_DIR)/userlevel/$(PKG_NAME)click $(1)/usr/bin/jaldiclick 70 | $(CP) $(PKG_BUILD_DIR)/tools/click-align/click-align $(1)/usr/bin/click-align 71 | $(CP) $(PKG_BUILD_DIR)/elementmap.xml $(1)/usr/share/jaldiclick/elementmap.xml 72 | endef 73 | 74 | $(eval $(call BuildPackage,jaldiclick)) 75 | -------------------------------------------------------------------------------- /shared/Frame.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Frame.hh" 4 | 5 | using namespace jaldimac; 6 | 7 | CLICK_DECLS 8 | 9 | const size_t Frame::header_size = 4 * sizeof(uint8_t) /* preamble */ 10 | + sizeof(uint8_t) /* src_id */ 11 | + sizeof(uint8_t) /* dest_id */ 12 | + sizeof(uint8_t) /* type */ 13 | + sizeof(uint8_t) /* tag */ 14 | + sizeof(uint32_t) /* length */ 15 | + sizeof(uint32_t) /* seq */; 16 | 17 | const size_t Frame::footer_size = sizeof(uint32_t); /* timestamp */ 18 | 19 | const size_t Frame::empty_frame_size = Frame::header_size + Frame::footer_size; 20 | 21 | CLICK_ENDDECLS 22 | ELEMENT_PROVIDES(Frame) 23 | -------------------------------------------------------------------------------- /shared/Frame.hh: -------------------------------------------------------------------------------- 1 | #ifndef FRAME_HH 2 | #define FRAME_HH 3 | 4 | #include 5 | 6 | namespace jaldimac { 7 | 8 | enum FrameType 9 | { 10 | BULK_FRAME = 0, 11 | VOIP_FRAME, 12 | REQUEST_FRAME, 13 | CONTENTION_SLOT, 14 | VOIP_SLOT, 15 | TRANSMIT_SLOT, 16 | BITRATE_MESSAGE, 17 | ROUND_COMPLETE_MESSAGE, 18 | DELAY_MESSAGE 19 | }; 20 | 21 | struct Frame 22 | { 23 | // Fields 24 | uint8_t preamble[4]; 25 | uint8_t src_id; 26 | uint8_t dest_id; 27 | uint8_t type; 28 | uint8_t tag; // Currently unused 29 | uint32_t length; 30 | uint32_t seq; 31 | uint8_t payload[0]; // Actual size determined by length 32 | 33 | // Static constants 34 | static const size_t header_size; 35 | static const size_t footer_size; 36 | static const size_t empty_frame_size; 37 | 38 | // Member functions 39 | inline void initialize(); 40 | inline size_t payload_length() const { return length - empty_frame_size; } 41 | 42 | } __attribute__((__packed__)); 43 | 44 | // Important constants: 45 | const uint8_t CURRENT_VERSION = 1; 46 | const uint8_t PREAMBLE[4] = {'J', 'L', 'D', CURRENT_VERSION}; 47 | const unsigned FLOWS_PER_VOIP_SLOT = 4; 48 | 49 | inline void Frame::initialize() 50 | { 51 | // Set up preamble 52 | std::memcpy(preamble, PREAMBLE, sizeof(PREAMBLE)); 53 | 54 | // Set up defaults for other values 55 | src_id = 0; 56 | dest_id = 0; 57 | type = BULK_FRAME; 58 | tag = 0; 59 | length = empty_frame_size; 60 | seq = 0; 61 | } 62 | 63 | // Cast the payload to one of the following structs as appropriate for the 64 | // frame type. After the payload comes an additional 32 bit TX timestamp which 65 | // is added by the driver; it is only used for debugging purposes and should 66 | // not affect the semantics of the protocol. 67 | // BULK_FRAME and VOIP_FRAME do not have a struct below as their payload consists 68 | // of an encapsulated IP packet. 69 | 70 | struct RequestFramePayload 71 | { 72 | uint32_t bulk_request_bytes; 73 | uint8_t voip_request_flows; 74 | } __attribute__((__packed__)); 75 | 76 | struct ContentionSlotPayload 77 | { 78 | uint32_t duration_us; 79 | } __attribute__((__packed__)); 80 | 81 | struct VoIPSlotPayload 82 | { 83 | uint32_t duration_us; 84 | uint8_t stations[FLOWS_PER_VOIP_SLOT]; 85 | } __attribute__((__packed__)); 86 | 87 | struct TransmitSlotPayload 88 | { 89 | uint32_t duration_us; 90 | uint8_t voip_granted_flows; 91 | } __attribute__((__packed__)); 92 | 93 | struct BitrateMessagePayload 94 | { 95 | /* REPLACE WITH BITRATE ENUM TYPE */ uint32_t bitrate; 96 | } __attribute__((__packed__)); 97 | 98 | struct RoundCompleteMessagePayload 99 | { 100 | } __attribute__((__packed__)); 101 | 102 | struct DelayMessagePayload 103 | { 104 | uint32_t duration_us; 105 | } __attribute__((__packed__)); 106 | 107 | // Node IDs: 108 | const uint8_t BROADCAST_ID = 0; 109 | const uint8_t DRIVER_ID = 0; 110 | const uint8_t MASTER_ID = 1; 111 | const uint8_t FIRST_STATION_ID = 2; 112 | 113 | // MTUs: 114 | const unsigned BULK_MTU__BYTES = 1500; 115 | const unsigned VOIP_MTU__BYTES = 300; 116 | 117 | // Sizes: 118 | const uint32_t REQUEST_FRAME_SIZE__BYTES = Frame::empty_frame_size + sizeof(RequestFramePayload); 119 | 120 | // Bitrates: (these will be replaced by a better bitrate mechanism) 121 | const unsigned MEGABIT__BYTES = 1000000 /* bits */ / 8 /* bytes */; 122 | const unsigned ETH_10_MEGABIT__BYTES_PER_US = (MEGABIT__BYTES * 10 /* hz */) / 1000000 /* us/s */; 123 | const unsigned ETH_100_MEGABIT__BYTES_PER_US = (MEGABIT__BYTES * 100 /* hz */) / 1000000 /* us/s */; 124 | const unsigned ETH_1000_MEGABIT__BYTES_PER_US = (MEGABIT__BYTES * 1000 /* hz */) / 1000000 /* us/s */; 125 | const unsigned WIFI_20_MEGABIT__BYTES_PER_US = (MEGABIT__BYTES * 20 /* hz */) / 1000000 /* us/s */; 126 | const unsigned BITRATE__BYTES_PER_US = WIFI_20_MEGABIT__BYTES_PER_US; 127 | 128 | // VoIP-related constants: 129 | const uint32_t VOIP_SLOT_GUARD_SIZE__BYTES = 2 * BULK_MTU__BYTES; 130 | const uint32_t VOIP_SLOT_SIZE_PER_FLOW__BYTES = REQUEST_FRAME_SIZE__BYTES + VOIP_MTU__BYTES + VOIP_SLOT_GUARD_SIZE__BYTES; 131 | const uint32_t VOIP_SLOT_SIZE__BYTES = FLOWS_PER_VOIP_SLOT * VOIP_SLOT_SIZE_PER_FLOW__BYTES; 132 | 133 | // Round constraints: 134 | const uint32_t MIN_CHUNK_SIZE__BYTES = BITRATE__BYTES_PER_US * 1 /* ms */ * 1000 /* us/ms */; 135 | const uint32_t MAX_ROUND_SIZE__BYTES = BITRATE__BYTES_PER_US * 500 /* ms */ * 1000 /* us/ms */; 136 | const uint32_t CONTENTION_SLOT_DURATION__US = 50 /* ms */ * 1000 /* us/ms */; 137 | const uint32_t INTER_VOIP_SLOT_DISTANCE__BYTES = BITRATE__BYTES_PER_US * 40 /* ms */ * 1000 /* us/ms */; 138 | const uint32_t DEFAULT_CONTENTION_SLOT_ONLY_DISTANCE__US = 50 /* ms */ * 1000 /* us/ms */; 139 | 140 | // Other temporary constants: 141 | const unsigned STATION_COUNT = 4; 142 | 143 | } 144 | 145 | #endif 146 | --------------------------------------------------------------------------------