高通qca-wifi移植

SPF6.1_QCA-WIFI移植

  • 概述
  • qca-wifi 移植
    • 代码合入
    • 编译
    • insmod qca-wifi
    • 初始化调试
    • luci联调
  • 总结

概述

移植的方案是高通的SPF6.1版本,移植到开源OpenWrt18.06.1版本上。SPF6.1采用的内核是3.3.8,OpenWrt18采用的是4.14.90.内核差异只是其中一个难点,主要还是两者之间的框架差异,虽然都是基于OpenWrt开源框架,但是对于OpenWrt18.06.1来讲,更新的很多新的功能,在老的版本上有些组件要么丢弃要么更新。
主要工作我这边划分了这么几个阶段。代码合入、编译、insmod qca-wifi、初始化调试、luci联调。以下就是根据这几个阶段进行详细讲解,不仅仅是移植步骤,其中也包括移植过程中遇到的一些典型问题。

qca-wifi 移植

先简单看下qca-wifi的代码框架

代码合入

高通私有代码目录比较清晰,在根目录下的qca文件夹下,直接把这个文件夹移植过去放在OpenWrt的根目录下或者其他目录下,但是在添加feeds配置时要指定路径。

OpenWrt#cat feeds.conf
src-link qca ../qca/feeds/qca
# 这个文件创建好之后,在执行./scripts/feeds install -a时会自动创建相关软链接。
# 预期目标
[zhangyugang@mos openwrt]$ cd package/feeds/qca/
[zhangyugang@mos qca]$ ll
total 0
lrwxrwxrwx 1 zhangyugang zhangyugang 31 Sep 16 14:16 btdiag -> ../../../feeds/qca/utils/btdiag
lrwxrwxrwx 1 zhangyugang zhangyugang 31 Sep 16 14:16 qca-acfg -> ../../../feeds/qca/net/qca-acfg
lrwxrwxrwx 1 zhangyugang zhangyugang 33 Sep 16 14:16 qca-hostap -> ../../../feeds/qca/net/qca-hostap
lrwxrwxrwx 1 zhangyugang zhangyugang 41 Sep 16 14:16 qca-iface-mgr-10.4 -> ../../../feeds/qca/net/qca-iface-mgr-10.4
lrwxrwxrwx 1 zhangyugang zhangyugang 31 Sep 16 14:16 qca-lowi -> ../../../feeds/qca/net/qca-lowi
lrwxrwxrwx 1 zhangyugang zhangyugang 37 Sep 16 14:16 qca-spectral -> ../../../feeds/qca/utils/qca-spectral
lrwxrwxrwx 1 zhangyugang zhangyugang 42 Sep 16 14:16 qca-thermald-10.4 -> ../../../feeds/qca/utils/qca-thermald-10.4
lrwxrwxrwx 1 zhangyugang zhangyugang 31 Sep 16 14:16 qca-wifi -> ../../../feeds/qca/net/qca-wifi
lrwxrwxrwx 1 zhangyugang zhangyugang 43 Sep 16 14:16 qca-wifi-fulloffload -> ../../../feeds/qca/net/qca-wifi-fulloffload
lrwxrwxrwx 1 zhangyugang zhangyugang 41 Sep 16 14:16 qca-wifi-fw-10.2.4 -> ../../../feeds/qca/net/qca-wifi-fw-10.2.4
lrwxrwxrwx 1 zhangyugang zhangyugang 39 Sep 16 14:16 qca-wifi-fw-10.4 -> ../../../feeds/qca/net/qca-wifi-fw-10.4
lrwxrwxrwx 1 zhangyugang zhangyugang 46 Sep 16 14:16 qca-wifi-fw-10.4-ar71xx -> ../../../feeds/qca/net/qca-wifi-fw-10.4-ar71xx
lrwxrwxrwx 1 zhangyugang zhangyugang 30 Sep 16 14:16 qca-wpc -> ../../../feeds/qca/net/qca-wpc
lrwxrwxrwx 1 zhangyugang zhangyugang 32 Sep 16 14:16 qca-wrapd -> ../../../feeds/qca/net/qca-wrapd
lrwxrwxrwx 1 zhangyugang zhangyugang 35 Sep 16 14:16 qcmbr-10.4 -> ../../../feeds/qca/utils/qcmbr-10.4

安装过程中可能会遇到一些问题,诸如depend或者一些未定义的东西。未定义基本都是一些Makefile的函数或者变量,只需要找到openwrt/logs/package/feeds/qca/qca-wifi 这个目录下的log信息,打开看下就知道少些什么文件了,把相应的移植过来就可以了。
对于一些依赖问题,目前最快的解决方法是对报错的依赖Makefile文件,进行拆分编译,先编译依赖模块,然后再编译报错模块(前提是需要把依赖配置删除掉,类似# PKG_BUILD_DEPENDS+=$(FW_10_4))。

编译

由于移植的大部分都是驱动程序,所以编译报错基本都涉及到内核的报错。修改思路是尽量不要动内核源码,以免污染内核。修改起来比较繁琐,而且基本上都是新旧接口替换,头文件替换等等。没什么比较难的东西,这部分主要还是耐心修改就可以了。
编译模块选择:

make package/feeds/qca/qca-wifi/compile V=s
	1.qca-wifi-ga54129d-dirty/hal/ar5416/ar5416_xmit_ds.c
	2.hal/ar9300/ar9300_txbf.c
	3.cmn_dev/qdf/linux/src/i_qdf_nbuf.h  替换新接口atomic_set()---->refcount_set()
	4.cmn_dev/qdf/inc/qdf_nbuf.h  替换新接口atomic_set()---->refcount_set()
	5.cmn_dev/qdf/linux/src/qdf_perf.c 暂时先把头文件uaccess.h注释掉
	6.cmn_dev/qdf/linux/src/qdf_threads.c signal_pending()函数未声明,新版内核放在linux/sched/signal.h中,把头文件换下。
	7.lmac/ath_dev/ath_main.c 中包含的头文件,osdep_adf_internal.h(os/linux/include)random_input_words()函数未定义,
														换成get_random_bytes(b,2*s),这个不确定**************
	8.lmac/ath_dev/ath_xmit.c 3154if报错,this 'if' clause does not guard,在if语句下加"{}"即可.
	9.os/linux/src/ath_osdep.c 在#if !ATH_RXBUF_RECYCLE 下面紧挨着加
				#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0),后期可能需要重新调试。
	10.lmac/ath_pktlog/pktlog.c line:789  在报错的地方加上双括号。
	
	11.lmac/ath_pktlog/linux.c 两处错误。
			vmf->virtual_address;----》vmf->address;把地址换成新的。
			针对linux.c文件,找到linux-4.14.90/include/linux/mm.h新版本内核就一个参数。删掉一个参数。
	12.lmac/dfs/dfs_process_phyerr.c line:148 代码bug,if语句没有加括号。
	13.ieee80211_aponly.c line:4567 ath_can_wbuf_recycle出现未定义,因为上面在,ath_osdep.c中加了限制。
		#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)才会走这个流程。
		
	14.os/linux/src/ath_linux.c 
	一个netdevice.h中的一个结构体针对3.3.84.1490有了变化,*****************************************************************内核变动
	内核代码在linux-4.14.90/include/linux/netdevice.h
		struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev,
						   struct rtnl_link_stats64 *storage); 按照3.6的修改,加个返回值类型。
						   --------------------此处修改导致内核其他驱动编译失败drivers/net/ifb.c 
						   
	15.umac/if_lmac/if_ath.c if语句没有加括号导致报错。
	16.umac/if_lmac/if_ath_mat.c  if语句没有加括号。
	17.qca_da/if_ath_ahb.c 编译器检测到可能使用一个为初始化的指针,加个判空操作。
	18.offload/wlan/lmac_offload_if/ol_if_ath.c 头文件关联找不到linux/ath79_wlan.h文件,从3.3.8移植过去,**********************修改内核
		对应修改dev-wmac.c文件。
	19.offload/wlan/lmac_offload_if/ol_if_vap.c  if else未加括号
	20.offload/os/linux/ol_ath_linux.c 由于内核改动,添加头文件<linux/sched/signal.h>
	21.qca_ol/osif_ol.c line:805  ********************************************************************************************修改内核
		内核头文件include/linux/netdevice.h 4.14.90中添加3.3.8中的last_rx成员变量,
			由于qca-wifi驱动中使用的过多,所以适配内核。hello world welcome to China
	22.qca_ol/osif_ol.c  内核ktime_t定义有变化,根据最新内核来,直接删除掉tv64,qca-wifi驱动关于该变量的都要删除。
	23.cmn_dev/hif/src/pcie/if_pci.c 
		line:2325 内核pci 接口pci_enable_msi_range----》pci_enable_msi   
		MSI全称Message Signaled Interrupt当设备向一个特殊地址写入时,会向CPU产生一个中断,即也MSI中断
	24.offload/os/linux/ath_pci.c 添加内核头文件<linux/sched/signal.h>,并删除掉两个内核没有的头文件,led的
	25.offload/os/linux/ol_tx.c 添加内核<linux/sched/signal.h>头文件
	26.offload/wlan/ath_pktlog/linux_remote_pktlog.c  line:229 socket->ops->accept()内核接口多了一个参数,最后一个补true
	27.umac/mlme/ieee80211_mgmt.c line:2823 vap->iv_des_ssid[0].ssid --> vap->iv_des_ssid[0].ssid[0]
	28.os/linux/src/osif_umac.c osif_net.c内核更新,struct net_device dev->destructor  -----> dev->priv_destructor
	29.os/linux/src/ath_papi.c  更换接口,对结构体进行整合static struct genl_family papi_genl_family
	30.os/linux/src/if_bus.c 
			1.包含的头文件if_ath_ahb.h中的头文件<asm/uaccess.h>替换成<linux/uaccess.h>
			2.替换两个接口dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
						  dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
	31.os/linux/tools/80211stats.c 替换头文件 <sys/types.h> --> <linux/types.h>
											  修改Makefile -I$(KERNELPATH)/arch/$(KERNELARCH)/include/  解决找不到asm/linkage.h

insmod qca-wifi

在编译完各个模块驱动的时候,就可以根据以下顺序进行插入调试。

#openwrt/qca/feeds/qca/net/qca-wifi/files
$ cat qca-wifi-modules 
mem_manager
asf
qdf
ath_dfs
ath_spectral
umac
ath_hal
ath_rate_atheros
hst_tx99
ath_dev
qca_da
qca_ol
ath_pktlog
smart_antenna

插入的时候也遇到了几个问题,根据提示进行解决

	1.vfs_read/vfs_write 接口替换,新的内核已经不导出了,为了不污染内核,使用新的kernel_read/kernel_write接口。
	2.ath79_get_wlan_fw_dump_buffer 函数未定义,在dev-wmac.c中重新移植。
//	3.qca_da.ko驱动探测qca956x_wmac 失败,在target/linux/ar71xx/config-4.14放开CONFIG_OF定义.
					并注掉相关编译不过问题:setup.c中关于device tree的初始化注掉。
						放开该配置导致内核编译异常。着手修改9563探测部分。
						保证可以分配到中断号以及所需内存。
	4.修改qca/src/qca-wifi/Makefile 添加ifeq ($(QCA_PLATFORM),ar71xx) 的宏定义到QCAWLAN_MAKEOPTS里面去。
	5.插入qca_da出现kernel panic,走读代码,修改if_ath_ahb.c探测部分代码,需要重新分配中断号和匹配dev_id。

初始化调试

这部分调试比较繁琐,首先抓住一个核心脚本,即/sbin/wifi。从这个脚本出发,调试各个功能。这个前提是要把wireless配置文件以及校准数据准备好。

	1.内核自动插入,修改Makefile 添加AUTOLOAD:=$(call AutoLoad,80,$(notdir $(QCAWLAN_MODULE_LIST)))。
												-----------后期发现无需添加,qcawifi.sh会自动检测。
	2.加载校验数据,移植81_load_wifi_board_bin文件,用于启动时调用。
		target/linux/ar71xx/base-files/lib/preinit/
		移植ar71xx_read_caldata_to_fs.sh文件,用于校准时调用。
		target/linux/ar71xx/base-files/lib/
		这两个文件移植过去,需修改内部的ar71xx_board_name 替换成board_name变量。
		调用顺序为 单板启动-----》etc/preinit------>/lib/preinit/各个文件,即会执行/lib/preinit/81_load_wifi_board_bin

		**最后为了不污染openwrt框架,把这两个文件放在qca/feeds/qca/net/qca-wifi/files目录下,在Makefile安装。

	3.适配qcawifi.sh文件,启动默认插入相关驱动。顺便把/lib/functions.sh脚本也移植过来。
		qca/feeds/qca/net/qca-wifi/files/
		
	4.把内核中wireless驱动mac80211部分勾选去掉,只需要加载qca-wifi即可。(ath驱动很多配置文件都来自于mac80211). 
	
	5.package/base-files/sbin/wifi  暂时先删除掉,后期再放在mac80211文件下(package/kernel )*****
	
	6.修改wireless配置创建的地方
		/package/base-files/files/etc/init.d/boot    在boot阶段,添加wireless的创建。
		
	7.wifi启动调试,一般直接执行/sbin/wifi down/up即可下发配置。使用此命令进行wifi调试。
	
	8.无线暂时出来了,注掉/lib/wifi/qcawifi.sh 中调用wlanconfig命令,根据返回值设置ifname。
			---------目前这个地方还有点问题,老版本正常执行,在新版本中会把ifname清空,导致后面iwpriv命令下发失败。
	
	10.高通针对每个WLAN接口会创建一个VAP(虚拟ap)接口,当前系统下发wifi1时错误(系统对应创建ath0,ath11,1)
		可能是/sbin/wifi 在做scan_wifi时,CONFIG_SECTION变量保存错误,在config_set时,该值在老版本和新版本中不同
		-----------------老版本中保存的是上一次的值,而新版本是当前设置的值。先替换掉functions.sh(config_set)
		***替换掉会出现./usr/lib/opkg/info/base-files.postinst: line 5: default_postinst: command not found
				解决方法:暂时先把新版本的functions.sh中default_postinst 函数移植到老版本中去。

	11.解决iwpriv命令问题,这个命令在wireless_tools下,打补丁修改。
		在/lib/wifi/qcawifi.sh 下添加DEBUG='OPEN' 会有调试信息输出,发现iwpriv 命令下发失败
		(主要是ioctl找不到相关的私有命令no private ioctls)。
		***下发iwpriv ath0 提示没有相关的ioctls,
				是因为wireless_tools工具源码中,iwlib.c中获取信息给的空间太小导致。已打补丁
		参考笔记:http://blog.chinaunix.net/uid-25564582-id-5751599.html  研究私有ioctl交互流程。
		
	12.待上面问题都解决完之后,log输出信息基本和SPF6.1保持一致,但是终端还是无法连接到AP。定位流程:
		1》无法连接-------查看连接阶段,用笔记本抓包,发现无dhcp回应。
		2》wifi驱动,研究无线收发流程,添加调试信息,发现DHCP报文已上送内核osif_umac.c->osif_deliver_data()
			参考笔记:https://blog.csdn.net/zimiao815/article/details/55510939
		3》由于内核过于复杂,先跳过内核协议栈,直接排查dhcp应用程序,是否接受和发送dhcp报文。
			在package/network/services/dnsmasq/files/dnsmasq.init 
			启动dnsmasq时添加参数--log-facility /tmp/dnsmasq.log --log-queries
			由打印信息并且对比SPF6.1可以知,dhcp报文在内核丢失了。
			参考笔记:http://blog.chinaunix.net/uid-563939-id-4768621.html
		4》排查内核UDP报文处理流程,发现在ip处理过程中已经丢弃了。
			if (skb->pkt_type == PACKET_OTHERHOST)goto drop;
				------>在dev.c ---__netif_receive_skb_core()处理vlantag时加的。
				暂时解决方案:qca-wifi/os/linux/BuildCaps.inc 中先去掉vlan的支持
	
	13.2.4G和5.8G均可连接。简单测试情况:
		1》2.4G可连接并下载上传均可。
		2》5.8G:	
				有时会出现终端连接时弹出无法加入网络
				可能无法上传,采用测试工具hfc测试,上传失败。
		最后排查发现是信道干扰,因为对比调试,所以启了一块SPF6.1板本的单板,关掉就好了。

luci联调

	1.经研究发现,前后端经过libiwinfo.so库提供的接口,进行数据交互。
		暂时尝试把SPF6.1的iwinfo 目录移植到package/network/utils/iwinfo 下,主要是替换iwinfo库。
	2.rpcd下iwinfo.c中需要适配692行的添加qcawifi名称。

	3.针对网页配置主要修改思路是上下传参不一致。
		1》获取状态信息,突破口主要在wifi.lua中(按编辑按钮跳转到wifi配置页面),对比SPF6.1Wireless Network: Master "Mexon_qca2.4G" (ath0),看下ath0怎么显示出来的。
		2》主要修改model/network.lua 中wifinet.__init__初始化部分,会对iwinfo进行初始化,但是这个需要传参athx设备
						故修改_wifi_netid_by_sid_private 重新对/etc/config/wireless 接口添加ifname选项。
		3》前段在显示时是调用wifinet.ifname(self),所以看下self.iwinfo.ifname 怎么获取。
				这段赋值就是前面_wifi_iwinfo_by_ifname(radioname) 而这个函数的参数有时_wifi_netid_by_sid_private在/etc/config/wireless中读取的。
		4》上面是获取状态信息,初始化已有的ath设备,下面讲下怎么添加虚拟设备。
			*:onclick="cbi_submit(this, 'device', '<%=dev:name()%>', '<%=url('admin/wireless/wireless_add')%>')"
			*:推断出要加载wireless_add页面,该页面在controller/admin/wireless.lua中添加,即直接调用该文件下的wifi_add()。
			*:在network.lua中wifidev.add_wifinet(self, options) 改造该函数,对wireless配置文件添加ifname选项。
			*:写了一个新函数,即遍历所有相同device下的接口,得出索引,得到athxx设备名。(_wifi_ifname_by_dev(dev))
		5》在重新适配下radio.lua/radio_5G.lua ,让其支持qcawifi驱动

总结

至此所有的功能模块都已经调试完成,遇到每一个问题都需要找到相应的突破口,要不然面对这么个大的框架,会让人无从下手。通过这个qca-wifi的移植可以说把OpenWRt的基本知识大概研究了一遍,从代码移植、编译、install、insmod、芯片探测、系统初始化、wifi初始化、校准数据初始化、wifi基本配置工具(wlanconfig、iwconfig、iwpriv等)、luci调试等等。以及在解决问题过程中研究了下netifd的网络配置管理,dnsmasq的dhcp管理等等。模块虽然很独立,但是和系统其它基本组件需要很多配合。

你可能感兴趣的:(OpenWrt,qca-wifi,高通wifi驱动,OpenWrt无线驱动移植)