移植的方案是高通的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文件夹下,直接把这个文件夹移植过去放在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 3154的if报错,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.8到4.14。90有了变化,*****************************************************************内核变动
内核代码在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
在编译完各个模块驱动的时候,就可以根据以下顺序进行插入调试。
#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板本的单板,关掉就好了。
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管理等等。模块虽然很独立,但是和系统其它基本组件需要很多配合。