diff --git a/fibocom_QMI_WWAN/Makefile b/fibocom_QMI_WWAN/Makefile index 82ebd49e..836085e2 100644 --- a/fibocom_QMI_WWAN/Makefile +++ b/fibocom_QMI_WWAN/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=qmi_wwan_f PKG_VERSION:=1.0 -PKG_RELEASE:=1 +PKG_RELEASE:=2 include $(INCLUDE_DIR)/kernel.mk include $(INCLUDE_DIR)/package.mk diff --git a/fibocom_QMI_WWAN/src/qmi_wwan_f.c b/fibocom_QMI_WWAN/src/qmi_wwan_f.c index ab24bfb0..48efef72 100644 --- a/fibocom_QMI_WWAN/src/qmi_wwan_f.c +++ b/fibocom_QMI_WWAN/src/qmi_wwan_f.c @@ -712,27 +712,19 @@ static struct rtnl_link_stats64 *_rmnet_vnd_get_stats64(struct net_device *net, stats64 = per_cpu_ptr(dev->stats64, cpu); do { -#if LINUX_VERSION_CODE < KERNEL_VERSION(6,6,0) start = u64_stats_fetch_begin_irq(&stats64->syncp); -#else - start = u64_stats_fetch_begin(&stats64->syncp); -#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) rx_packets = stats64->rx_packets; rx_bytes = stats64->rx_bytes; tx_packets = stats64->tx_packets; tx_bytes = stats64->tx_bytes; #else - rx_packets = u64_stats_read(&stats64->rx_packets); - rx_bytes = u64_stats_read(&stats64->rx_bytes); - tx_packets = u64_stats_read(&stats64->tx_packets); - tx_bytes = u64_stats_read(&stats64->tx_bytes); + rx_packets = u64_stats_read(&stats64->rx_packets); + rx_bytes = u64_stats_read(&stats64->rx_bytes); + tx_packets = u64_stats_read(&stats64->tx_packets); + tx_bytes = u64_stats_read(&stats64->tx_bytes); #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(6,6,0) } while (u64_stats_fetch_retry_irq(&stats64->syncp, start)); -#else - } while (u64_stats_fetch_retry(&stats64->syncp, start)); -#endif stats->rx_packets += rx_packets; stats->rx_bytes += rx_bytes; @@ -1195,11 +1187,7 @@ static int qmap_register_device(sQmiWwanQmap * pDev, u8 offset_id) priv->mux_id = FIBOCOM_QMAP_MUX_ID + offset_id; sprintf(qmap_net->name, "%s.%d", real_dev->name, offset_id + 1); qmap_net->netdev_ops = &qmap_netdev_ops; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,17,0) - memcpy(qmap_net->dev_addr, real_dev->dev_addr, ETH_ALEN); -#else - __dev_addr_set(qmap_net, real_dev->dev_addr, ETH_ALEN); -#endif + memcpy (qmap_net->dev_addr, real_dev->dev_addr, ETH_ALEN); #ifdef FIBOCOM_BRIDGE_MODE priv->bridge_mode = !!(pDev->bridge_mode & BIT(offset_id)); @@ -1772,14 +1760,8 @@ static void ql_net_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *i { /* Inherit standard device info */ usbnet_get_drvinfo(net, info); - /* strlcpy() is deprecated in kernel 6.8.0+, using strscpy instead */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(6,8,0)) strlcpy(info->driver, driver_name, sizeof(info->driver)); strlcpy(info->version, VERSION_NUMBER, sizeof(info->version)); -#else - strscpy(info->driver, driver_name, sizeof(info->driver)); - strscpy(info->version, VERSION_NUMBER, sizeof(info->version)); -#endif } static struct ethtool_ops ql_net_ethtool_ops; diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index 6b88afea..460c3ac8 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall PKG_VERSION:=26.6.2 -PKG_RELEASE:=153 +PKG_RELEASE:=154 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/luci-app-passwall/luasrc/passwall/util_sing-box.lua index f9662125..ad76c2a9 100644 --- a/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -1762,6 +1762,12 @@ function gen_config(var) end end + table.insert(route.rules, { + action = "route", + ip_is_private = true, + outbound = "direct" + }) + if COMMON.default_outbound_tag then route.final = COMMON.default_outbound_tag end diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua index a73d48a2..d886bf33 100644 --- a/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -1482,6 +1482,11 @@ function gen_config(var) end end) + table.insert(rules, { + outboundTag = "direct", + ip = { "geoip:private" } + }) + if default_outboundTag then local rule = { _flag = "default", diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 6e3e8d74..141bea8b 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 PKG_VERSION:=26.6.3 -PKG_RELEASE:=51 +PKG_RELEASE:=52 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua index c7c98007..513a5cd8 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua @@ -1797,6 +1797,12 @@ function gen_config(var) end end + table.insert(route.rules, { + action = "route", + ip_is_private = true, + outbound = "direct" + }) + if COMMON.default_outbound_tag then route.final = COMMON.default_outbound_tag end diff --git a/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/luci-app-passwall2/luasrc/passwall2/util_xray.lua index 00e9aa4f..50638170 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -1518,6 +1518,11 @@ function gen_config(var) end end) + table.insert(rules, { + outboundTag = "direct", + ip = { "geoip:private" } + }) + if default_outboundTag then local rule = { ruleTag = "default", diff --git a/luci-mod-system/htdocs/luci-static/resources/view/system/flash.js b/luci-mod-system/htdocs/luci-static/resources/view/system/flash.js index ab3f71e6..b471fe81 100644 --- a/luci-mod-system/htdocs/luci-static/resources/view/system/flash.js +++ b/luci-mod-system/htdocs/luci-static/resources/view/system/flash.js @@ -15,7 +15,54 @@ const callSystemValidateFirmwareImage = rpc.declare({ expect: { '': { valid: false, forcable: true } } }); -function findStorageSize(procmtd, procpart) { +function getBlockDevice(name) { + const diskPatterns = [ + /^(sd[a-z]+)$/, + /^(sd[a-z]+)\d+$/, + /^(vd[a-z]+)$/, + /^(vd[a-z]+)\d+$/, + /^(xvd[a-z]+)$/, + /^(xvd[a-z]+)\d+$/, + /^(hd[a-z]+)$/, + /^(hd[a-z]+)\d+$/, + /^(mmcblk\d+)$/, + /^(mmcblk\d+)p\d+$/, + /^(nvme\d+n\d+)$/, + /^(nvme\d+n\d+)p\d+$/ + ]; + + for (const pattern of diskPatterns) { + const match = name.match(pattern); + + if (match) + return match[1]; + } + + return null; +} + +function findMountedDisk(procmounts) { + const preferredMounts = new Set([ '/', '/rom', '/boot', '/boot/efi' ]); + const mountedDisks = new Set(); + + procmounts.split(/\n/).forEach(function(ln) { + const fields = ln.trim().split(/\s+/); + const source = fields[0]; + const target = fields[1]; + + if (!preferredMounts.has(target) || !source || !source.startsWith('/dev/')) + return; + + const disk = getBlockDevice(source.substring(5)); + + if (disk) + mountedDisks.add(disk); + }); + + return mountedDisks; +} + +function findStorageSize(procmtd, procpart, procmounts) { let kernsize = 0, rootsize = 0, wholesize = 0; procmtd.split(/\n/).forEach(function(ln) { @@ -48,16 +95,43 @@ function findStorageSize(procmtd, procpart) { else if (kernsize > 0 && rootsize > kernsize) return kernsize + rootsize; + const mountedDisks = findMountedDisk(procmounts); + const disks = {}; + const partitionedDisks = new Set(); + procpart.split(/\n/).forEach(function(ln) { const match = ln.match(/^\s*\d+\s+\d+\s+(\d+)\s+(\S+)$/); - if (match) { - const size = parseInt(match[1], 10); + if (!match) + return; - if (!match[2].match(/\d/) && size > 2048 && wholesize == 0) - wholesize = size * 1024; + const size = parseInt(match[1], 10) * 1024; + const name = match[2]; + const disk = getBlockDevice(name); + + if (!disk || size <= 2048 * 1024) + return; + + if (name == disk) { + disks[disk] = size; + return; } + + partitionedDisks.add(disk); }); + for (const disk of mountedDisks) { + if (disks[disk] > wholesize) + wholesize = disks[disk]; + } + + if (wholesize > 0) + return wholesize; + + for (const disk of partitionedDisks) { + if (disks[disk] > wholesize) + wholesize = disks[disk]; + } + return wholesize; } @@ -381,7 +455,7 @@ return view.extend({ render([p_fstat, hostname, procmtd, procpart, procmounts]) { const has_sysupgrade = (p_fstat.type == 'file'); const has_rootfs_data = (procmtd.match(/"rootfs_data"/) != null) || (procmounts.match("overlayfs:/overlay / ") != null); - const storage_size = findStorageSize(procmtd, procpart); + const storage_size = findStorageSize(procmtd, procpart, procmounts); let m, s, o, ss; m = new form.JSONMap(mapdata, _('Flash operations')); diff --git a/natflow/Makefile b/natflow/Makefile index 290eeec2..fb935909 100644 --- a/natflow/Makefile +++ b/natflow/Makefile @@ -9,8 +9,8 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=natflow -PKG_VERSION:=20260313 -PKG_RELEASE:=10 +PKG_VERSION:=20260531 +PKG_RELEASE:=11 PKG_SOURCE:=$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git diff --git a/quectel-cm/Makefile b/quectel-cm/Makefile deleted file mode 100644 index ddfc8ffc..00000000 --- a/quectel-cm/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=quectel-cm -PKG_VERSION:=1.6.7 -PKG_RELEASE:=1 - -PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL:=https://github.com/quectel-open-source/Quectel_QConnectManager_Linux -PKG_SOURCE_VERSION:=170ed7177cc3beb831bc85571aad956492ff7e7e -PKG_MIRROR_HASH:=skip - -include $(INCLUDE_DIR)/package.mk - -define Package/quectel-cm - SECTION:=net - CATEGORY:=Network - TITLE:=Quectel dial program - DEPENDS:=+libpthread -endef - -define Package/quectel-cm/install - $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/quectel-CM $(1)/usr/bin -endef - -$(eval $(call BuildPackage,quectel-cm)) diff --git a/quectel_MHI/Makefile b/quectel_MHI/Makefile old mode 100755 new mode 100644 index 59e75b0c..cd33b9c0 --- a/quectel_MHI/Makefile +++ b/quectel_MHI/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=pcie_mhi PKG_VERSION:=1.3.8 -PKG_RELEASE:=3 +PKG_RELEASE:=4 include $(INCLUDE_DIR)/kernel.mk include $(INCLUDE_DIR)/package.mk @@ -17,7 +17,7 @@ include $(INCLUDE_DIR)/package.mk define KernelPackage/pcie_mhi SUBMENU:=WWAN Support TITLE:=Kernel pcie driver for MHI device - DEPENDS:=@PCIE_SUPPORT + DEPENDS:=+pciids +pciutils +quectel-cm FILES:=$(PKG_BUILD_DIR)/pcie_mhi.ko AUTOLOAD:=$(call AutoLoad,90,pcie_mhi) endef diff --git a/quectel_MHI/src/Makefile b/quectel_MHI/src/Makefile index 9e1161b8..1b2c1f58 100644 --- a/quectel_MHI/src/Makefile +++ b/quectel_MHI/src/Makefile @@ -1,4 +1,4 @@ -ccflags-y += -Wno-error=declaration-after-statement +#ccflags-y += -g obj-m += pcie_mhi.o pcie_mhi-objs := core/mhi_init.o core/mhi_main.o core/mhi_pm.o core/mhi_boot.o core/mhi_dtr.o controllers/mhi_qti.o pcie_mhi-objs += devices/mhi_uci.o diff --git a/quectel_MHI/src/README b/quectel_MHI/src/README index 2bb6ff0a..927df0cf 100644 --- a/quectel_MHI/src/README +++ b/quectel_MHI/src/README @@ -1,36 +1,36 @@ -1. porting pcie_mhi driver as next - -$ git diff drivers/Makefile -diff --git a/drivers/Makefile b/drivers/Makefile -index 77fbc52..e45837e 100644 ---- a/drivers/Makefile -+++ b/drivers/Makefile -@@ -184,3 +184,4 @@ obj-$(CONFIG_FPGA) += fpga/ - obj-$(CONFIG_FSI) += fsi/ - obj-$(CONFIG_TEE) += tee/ - obj-$(CONFIG_MULTIPLEXER) += mux/ -+obj-y += pcie_mhi/ - -$ tree drivers/pcie_mhi/ -L 1 -drivers/pcie_mhi/ - controllers - core - devices - Makefile - -2. check RG500 attach pcie_mhi driver successful - -root@OpenWrt:/# lspci -00:00.0 Class 0604: 17cb:0302 -01:00.0 Class ff00: 17cb:0306 - -root@OpenWrt:~# dmesg | grep mhi -[ 138.483252] mhi_init Quectel_Linux_PCIE_MHI_Driver_V1.3.0.6 -[ 138.492350] mhi_pci_probe pci_dev->name = 0000:01:00.0, domain=0, bus=1, slot=0, vendor=17CB, device=0306 - -3. how to use, see next logs - -log/QXDM_OVER_PCIE.txt -log/AT_OVER_PCIE.txt -log/MBIM_OVER_PCIE.txt -log/QMI_OVER_PCIE.txt +1. porting pcie_mhi driver as next + +$ git diff drivers/Makefile +diff --git a/drivers/Makefile b/drivers/Makefile +index 77fbc52..e45837e 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -184,3 +184,4 @@ obj-$(CONFIG_FPGA) += fpga/ + obj-$(CONFIG_FSI) += fsi/ + obj-$(CONFIG_TEE) += tee/ + obj-$(CONFIG_MULTIPLEXER) += mux/ ++obj-y += pcie_mhi/ + +$ tree drivers/pcie_mhi/ -L 1 +drivers/pcie_mhi/ + controllers + core + devices + Makefile + +2. check RG500 attach pcie_mhi driver successful + +root@OpenWrt:/# lspci +00:00.0 Class 0604: 17cb:0302 +01:00.0 Class ff00: 17cb:0306 + +root@OpenWrt:~# dmesg | grep mhi +[ 138.483252] mhi_init Quectel_Linux_PCIE_MHI_Driver_V1.3.0.6 +[ 138.492350] mhi_pci_probe pci_dev->name = 0000:01:00.0, domain=0, bus=1, slot=0, vendor=17CB, device=0306 + +3. how to use, see next logs + +log/QXDM_OVER_PCIE.txt +log/AT_OVER_PCIE.txt +log/MBIM_OVER_PCIE.txt +log/QMI_OVER_PCIE.txt diff --git a/quectel_MHI/src/ReleaseNote.txt b/quectel_MHI/src/ReleaseNote.txt index d923b98d..8a55788d 100644 --- a/quectel_MHI/src/ReleaseNote.txt +++ b/quectel_MHI/src/ReleaseNote.txt @@ -1,103 +1,132 @@ -Release Notes - -[V1.3.4] -Date: 12/8/2022 -enhancement: - 1. only allow to enable autosuspend when module is in MHI_EE_AMSS - 2. show pcie link speed and width when driver probe - 3. check pcie link status by read pcie vid and pid when driver probe, - if pcie link is down, return -EIO - 4. support RM520 (1eac:1004) - 5. support qmap command packet -fix: - 1. fix tx queue is wrong stop when do uplink TPUT - 2. fix after QFirehose, module fail to bootup at very small probability - 3. mhi uci add mutex lock for concurrent reads/writes - -[V1.3.3] -Date: 30/6/2022 -enhancement: - 1. remove one un-necessary kmalloc when do qfirehose - 2. support mhi monitor (like usbmon), usage: cat /sys/kernel/debug/mhi_q/0306_00\:01.00/mhimon - 3. set ring size of event 0 to 256 (from 1024), required by x6x - 4. support PCIE local network card mhi_swip0 (chan 46/47), default disabled - 5. porting IPQ5018 mhi rate controll code from spf11.5 - 6. set pcie rmnet download max qmap packet size to 15KB (same to IPQ MHI Driver) - 7. support set different mac address for rmnet net card - 8. when mhi netdev fail to malloc, use delay_work instead work - 9. optimize code for 'when driver load, modem is still in MHI_EE_PTHRU' -fix: - 1. Fix not synchronize access rp/wp when mhi_queue_xxx and mhi_process_xxx_ring run on different CPU - 2. set dma mask when driver probe, some SOC like rpi_4 need it - -[V1.3.2] -Date: 12/16/2021 -enhancement: - 1. support Linux Kernel V5.14 - 2. mhi_netdev_quectel.c do not print log in softirq context - -[V1.3.1] -Date: 9/26/2021 -enhancement: -fix: - -[V1.3.0.19] -Date: 9/18/2021 -enhancement: - 1. support sdx62 (17cb:0308) - 2. support IPQ5018's NSS - 3. use 'qsdk/qca/src/data-kernel/drivers/rmnet-nss/rmnet_nss.c' instead myself rmnet_nss.c - and pcie_mhi.ko must load after then rmnet_nss.ko - 4. allow bhi irq is not 0 (for ipq5018) -fix: - -[V1.3.0.18] -Date: 4/14/2021 -enhancement: - 1. support mbim multiple call, usage: - # insmod pcie_mhi.ko mhi_mbim_enabeld=1 qmap_mode=4 - # quectel-mbim-proxy -d /dev/mhi_MBIM & - # quectel-CM -n X -fix: - -[V1.3.0.17] -Date: 3/11/2021 -enhancement: -fix: - 1. fix CPU loading very high when TPUT test when only one MSI interrupt - 2. fix error on latest X24 modem - -[V1.3.0.16] -Date: 11/18/2020 -enhancement: -fix: - 1. add ring size to 32, for in-bound chan, if one ring is full, modem will not generate MSI interrupt for all chan - -[V1.3.0.15] -Date: 10/30/2020 -enhancement: - 1. support multi-modems, named as /dev/mhi_X -fix: - 1. fix compile error on kernel v5.8 - -[V1.3.0.14] -Date: 10/9/2020 -enhancement: - 1. suppport EM120&EM160 -fix: - 1. fix compile error on kernel v5.6 - 2. support runtime suspend - -[V1.3.0.13] -Date: 9/7/2020 -enhancement: - 1. suppport EM120&EM160 -fix: - 1. fix error on X55 + PCIE2.0(e.g IPQ4019) - 2. support runtime suspend - -[V1.3.0.12] -Date: 7/7/2020 -enhancement: - 1. suppport create only none netcard (enabled by marco MHI_NETDEV_ONE_CARD_MODE), +Release Notes +[V1.3.8] +Date: 27/06/2024 +enhancement: + 1. support SDX7x's PID/VID + +Release Notes +[V1.3.7] +Date: 27/03/2024 +enhancement: + 1. support SDX35's PID/VID + 2. support IPQ QSDK MHI used with rmnetdata driver + +Release Notes +[V1.3.6] +Date: 01/08/2023 +enhancement: + 1. support Linux Kernel V6.4 + 2. support change mtu +fix: + 1. fix compile error on ipq's spf12.x + +Release Notes +[V1.3.5] +Date: 25/02/2023 +enhancement: + 1. support efuse SDX sleep + 2. support IPQ9574 SFE +fix: + 1. fix cannot find the node when dialing. Nodes in the /sys/bus/mhi_q/devices directory named hex + +[V1.3.4] +Date: 12/8/2022 +enhancement: + 1. only allow to enable autosuspend when module is in MHI_EE_AMSS + 2. show pcie link speed and width when driver probe + 3. check pcie link status by read pcie vid and pid when driver probe, + if pcie link is down, return -EIO + 4. support RM520 (1eac:1004) + 5. support qmap command packet +fix: + 1. fix tx queue is wrong stop when do uplink TPUT + 2. fix after QFirehose, module fail to bootup at very small probability + 3. mhi uci add mutex lock for concurrent reads/writes + +[V1.3.3] +Date: 30/6/2022 +enhancement: + 1. remove one un-necessary kmalloc when do qfirehose + 2. support mhi monitor (like usbmon), usage: cat /sys/kernel/debug/mhi_q/0306_00\:01.00/mhimon + 3. set ring size of event 0 to 256 (from 1024), required by x6x + 4. support PCIE local network card mhi_swip0 (chan 46/47), default disabled + 5. porting IPQ5018 mhi rate controll code from spf11.5 + 6. set pcie rmnet download max qmap packet size to 15KB (same to IPQ MHI Driver) + 7. support set different mac address for rmnet net card + 8. when mhi netdev fail to malloc, use delay_work instead work + 9. optimize code for 'when driver load, modem is still in MHI_EE_PTHRU' +fix: + 1. Fix not synchronize access rp/wp when mhi_queue_xxx and mhi_process_xxx_ring run on different CPU + 2. set dma mask when driver probe, some SOC like rpi_4 need it + +[V1.3.2] +Date: 12/16/2021 +enhancement: + 1. support Linux Kernel V5.14 + 2. mhi_netdev_quectel.c do not print log in softirq context + +[V1.3.1] +Date: 9/26/2021 +enhancement: +fix: + +[V1.3.0.19] +Date: 9/18/2021 +enhancement: + 1. support sdx62 (17cb:0308) + 2. support IPQ5018's NSS + 3. use 'qsdk/qca/src/data-kernel/drivers/rmnet-nss/rmnet_nss.c' instead myself rmnet_nss.c + and pcie_mhi.ko must load after then rmnet_nss.ko + 4. allow bhi irq is not 0 (for ipq5018) +fix: + +[V1.3.0.18] +Date: 4/14/2021 +enhancement: + 1. support mbim multiple call, usage: + # insmod pcie_mhi.ko mhi_mbim_enabeld=1 qmap_mode=4 + # quectel-mbim-proxy -d /dev/mhi_MBIM & + # quectel-CM -n X +fix: + +[V1.3.0.17] +Date: 3/11/2021 +enhancement: +fix: + 1. fix CPU loading very high when TPUT test when only one MSI interrupt + 2. fix error on latest X24 modem + +[V1.3.0.16] +Date: 11/18/2020 +enhancement: +fix: + 1. add ring size to 32, for in-bound chan, if one ring is full, modem will not generate MSI interrupt for all chan + +[V1.3.0.15] +Date: 10/30/2020 +enhancement: + 1. support multi-modems, named as /dev/mhi_X +fix: + 1. fix compile error on kernel v5.8 + +[V1.3.0.14] +Date: 10/9/2020 +enhancement: + 1. suppport EM120&EM160 +fix: + 1. fix compile error on kernel v5.6 + 2. support runtime suspend + +[V1.3.0.13] +Date: 9/7/2020 +enhancement: + 1. suppport EM120&EM160 +fix: + 1. fix error on X55 + PCIE2.0(e.g IPQ4019) + 2. support runtime suspend + +[V1.3.0.12] +Date: 7/7/2020 +enhancement: + 1. suppport create only none netcard (enabled by marco MHI_NETDEV_ONE_CARD_MODE), fix: \ No newline at end of file diff --git a/quectel_MHI/src/controllers/mhi_qcom.c b/quectel_MHI/src/controllers/mhi_qcom.c index df6ce193..70dd9172 100644 --- a/quectel_MHI/src/controllers/mhi_qcom.c +++ b/quectel_MHI/src/controllers/mhi_qcom.c @@ -1,715 +1,715 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../core/mhi.h" -#include "mhi_qcom.h" - -#if 1 -#ifndef PCI_IRQ_MSI -#define PCI_IRQ_MSI (1 << 1) /* Allow MSI interrupts */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,10,53 )) -int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) -{ - int nvec = maxvec; - int rc; - - if (maxvec < minvec) - return -ERANGE; - - do { - rc = pci_enable_msi_block(dev, nvec); - if (rc < 0) { - return rc; - } else if (rc > 0) { - if (rc < minvec) - return -ENOSPC; - nvec = rc; - } - } while (rc); - - return nvec; -} -#endif - -static int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, - unsigned int max_vecs, unsigned int flags) -{ - return pci_enable_msi_range(dev, min_vecs, max_vecs); -} - -static void pci_free_irq_vectors(struct pci_dev *dev) -{ - pci_disable_msi(dev); -} - -static int pci_irq_vector(struct pci_dev *dev, unsigned int nr) -{ - return dev->irq + nr; -} -#endif -#endif - -static struct pci_device_id mhi_pcie_device_id[] = { - {PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0303)}, //SDX20 - {PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0304)}, //SDX24 - {PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0305)}, - {PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0306)}, //SDX55 - {PCI_DEVICE(0x2C7C, 0x0512)}, - {PCI_DEVICE(MHI_PCIE_VENDOR_ID, MHI_PCIE_DEBUG_ID)}, - {0}, -}; - -MODULE_DEVICE_TABLE(pci, mhi_pcie_device_id); - -static struct pci_driver mhi_pcie_driver; - -void mhi_deinit_pci_dev(struct mhi_controller *mhi_cntrl) -{ - struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); - struct pci_dev *pci_dev = mhi_dev->pci_dev; - - pci_free_irq_vectors(pci_dev); - iounmap(mhi_cntrl->regs); - mhi_cntrl->regs = NULL; - pci_clear_master(pci_dev); - pci_release_region(pci_dev, mhi_dev->resn); - pci_disable_device(pci_dev); -} - -static int mhi_init_pci_dev(struct mhi_controller *mhi_cntrl) -{ - struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); - struct pci_dev *pci_dev = mhi_dev->pci_dev; - int ret; - resource_size_t start, len; - int i; - - mhi_dev->resn = MHI_PCI_BAR_NUM; - ret = pci_assign_resource(pci_dev, mhi_dev->resn); - if (ret) { - MHI_ERR("Error assign pci resources, ret:%d\n", ret); - return ret; - } - - ret = pci_enable_device(pci_dev); - if (ret) { - MHI_ERR("Error enabling device, ret:%d\n", ret); - goto error_enable_device; - } - - ret = pci_request_region(pci_dev, mhi_dev->resn, "mhi"); - if (ret) { - MHI_ERR("Error pci_request_region, ret:%d\n", ret); - goto error_request_region; - } - - pci_set_master(pci_dev); - - start = pci_resource_start(pci_dev, mhi_dev->resn); - len = pci_resource_len(pci_dev, mhi_dev->resn); - mhi_cntrl->regs = ioremap_nocache(start, len); - MHI_LOG("mhi_cntrl->regs = %p\n", mhi_cntrl->regs); - if (!mhi_cntrl->regs) { - MHI_ERR("Error ioremap region\n"); - goto error_ioremap; - } - - ret = pci_alloc_irq_vectors(pci_dev, 1, mhi_cntrl->msi_required, PCI_IRQ_MSI); - if (IS_ERR_VALUE((ulong)ret) || ret < mhi_cntrl->msi_required) { - if (ret == -ENOSPC) { - /* imx_3.14.52_1.1.0_ga - diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c - index f06e8f0..6a9614f 100644 - --- a/drivers/pci/host/pcie-designware.c - +++ b/drivers/pci/host/pcie-designware.c - @@ -376,6 +376,13 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, - if (msgvec > 5) - msgvec = 0; - - +#if 1 //Add by Quectel 20190419 - + if (msgvec > 0 && pdev->vendor == 0x17cb) { - + dev_info(&pdev->dev, "%s quectel fixup pos=%d, msg_ctr=%04x, msgvec=%d\n", __func__, desc->msi_attrib.pos, msg_ctr, msgvec); - + msgvec = 0; - + } - +#endif - + - irq = assign_irq((1 << msgvec), desc, &pos); - if (irq < 0) - return irq; - */ - } - //imx_4.1.15_2.0.0_ga & DELL_OPTIPLEX_7010 only alloc one msi interrupt for one pcie device - if (ret != 1) { - MHI_ERR("Failed to enable MSI, ret=%d, msi_required=%d\n", ret, mhi_cntrl->msi_required); - goto error_req_msi; - } - } - - mhi_cntrl->msi_allocated = ret; - MHI_LOG("msi_required = %d, msi_allocated = %d, msi_irq = %u\n", mhi_cntrl->msi_required, mhi_cntrl->msi_allocated, pci_dev->irq); - - for (i = 0; i < mhi_cntrl->msi_allocated; i++) { - mhi_cntrl->irq[i] = pci_irq_vector(pci_dev, i); - if (mhi_cntrl->irq[i] < 0) { - ret = mhi_cntrl->irq[i]; - goto error_get_irq_vec; - } - } - -#if 0 - /* configure runtime pm */ - pm_runtime_set_autosuspend_delay(&pci_dev->dev, MHI_RPM_SUSPEND_TMR_MS); - pm_runtime_dont_use_autosuspend(&pci_dev->dev); - pm_suspend_ignore_children(&pci_dev->dev, true); - - /* - * pci framework will increment usage count (twice) before - * calling local device driver probe function. - * 1st pci.c pci_pm_init() calls pm_runtime_forbid - * 2nd pci-driver.c local_pci_probe calls pm_runtime_get_sync - * Framework expect pci device driver to call - * pm_runtime_put_noidle to decrement usage count after - * successful probe and and call pm_runtime_allow to enable - * runtime suspend. - */ - pm_runtime_mark_last_busy(&pci_dev->dev); - pm_runtime_put_noidle(&pci_dev->dev); -#endif - - return 0; - -error_get_irq_vec: - pci_free_irq_vectors(pci_dev); - -error_req_msi: - iounmap(mhi_cntrl->regs); - -error_ioremap: - pci_clear_master(pci_dev); - -error_request_region: - pci_disable_device(pci_dev); - -error_enable_device: - pci_release_region(pci_dev, mhi_dev->resn); - - return ret; -} - -#ifdef CONFIG_PM -static int mhi_runtime_idle(struct device *dev) -{ - struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); - - MHI_LOG("Entered returning -EBUSY\n"); - - /* - * RPM framework during runtime resume always calls - * rpm_idle to see if device ready to suspend. - * If dev.power usage_count count is 0, rpm fw will call - * rpm_idle cb to see if device is ready to suspend. - * if cb return 0, or cb not defined the framework will - * assume device driver is ready to suspend; - * therefore, fw will schedule runtime suspend. - * In MHI power management, MHI host shall go to - * runtime suspend only after entering MHI State M2, even if - * usage count is 0. Return -EBUSY to disable automatic suspend. - */ - return -EBUSY; -} - -static int mhi_runtime_suspend(struct device *dev) -{ - int ret = 0; - struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); - - MHI_LOG("Enter\n"); - - mutex_lock(&mhi_cntrl->pm_mutex); - - ret = mhi_pm_suspend(mhi_cntrl); - if (ret) { - MHI_LOG("Abort due to ret:%d\n", ret); - goto exit_runtime_suspend; - } - - ret = mhi_arch_link_off(mhi_cntrl, true); - if (ret) - MHI_ERR("Failed to Turn off link ret:%d\n", ret); - -exit_runtime_suspend: - mutex_unlock(&mhi_cntrl->pm_mutex); - MHI_LOG("Exited with ret:%d\n", ret); - - return ret; -} - -static int mhi_runtime_resume(struct device *dev) -{ - int ret = 0; - struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); - struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); - - MHI_LOG("Enter\n"); - - mutex_lock(&mhi_cntrl->pm_mutex); - - if (!mhi_dev->powered_on) { - MHI_LOG("Not fully powered, return success\n"); - mutex_unlock(&mhi_cntrl->pm_mutex); - return 0; - } - - /* turn on link */ - ret = mhi_arch_link_on(mhi_cntrl); - if (ret) - goto rpm_resume_exit; - - /* enter M0 state */ - ret = mhi_pm_resume(mhi_cntrl); - -rpm_resume_exit: - mutex_unlock(&mhi_cntrl->pm_mutex); - MHI_LOG("Exited with :%d\n", ret); - - return ret; -} - -static int mhi_system_resume(struct device *dev) -{ - int ret = 0; - struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); - - ret = mhi_runtime_resume(dev); - if (ret) { - MHI_ERR("Failed to resume link\n"); - } else { - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - } - - return ret; -} - -int mhi_system_suspend(struct device *dev) -{ - struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); - - MHI_LOG("Entered\n"); - - /* if rpm status still active then force suspend */ - if (!pm_runtime_status_suspended(dev)) - return mhi_runtime_suspend(dev); - - pm_runtime_set_suspended(dev); - pm_runtime_disable(dev); - - MHI_LOG("Exit\n"); - return 0; -} -#endif - -/* checks if link is down */ -static int mhi_link_status(struct mhi_controller *mhi_cntrl, void *priv) -{ - struct mhi_dev *mhi_dev = priv; - u16 dev_id; - int ret; - - /* try reading device id, if dev id don't match, link is down */ - ret = pci_read_config_word(mhi_dev->pci_dev, PCI_DEVICE_ID, &dev_id); - - return (ret || dev_id != mhi_cntrl->dev_id) ? -EIO : 0; -} - -static int mhi_runtime_get(struct mhi_controller *mhi_cntrl, void *priv) -{ - struct mhi_dev *mhi_dev = priv; - struct device *dev = &mhi_dev->pci_dev->dev; - - return pm_runtime_get(dev); -} - -static void mhi_runtime_put(struct mhi_controller *mhi_cntrl, void *priv) -{ - struct mhi_dev *mhi_dev = priv; - struct device *dev = &mhi_dev->pci_dev->dev; - - pm_runtime_put_noidle(dev); -} - -static void mhi_status_cb(struct mhi_controller *mhi_cntrl, - void *priv, - enum MHI_CB reason) -{ - struct mhi_dev *mhi_dev = priv; - struct device *dev = &mhi_dev->pci_dev->dev; - - if (reason == MHI_CB_IDLE) { - MHI_LOG("Schedule runtime suspend 1\n"); - pm_runtime_mark_last_busy(dev); - pm_request_autosuspend(dev); - } -} - -int mhi_debugfs_trigger_m0(void *data, u64 val) -{ - struct mhi_controller *mhi_cntrl = data; - struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); - - MHI_LOG("Trigger M3 Exit\n"); - pm_runtime_get(&mhi_dev->pci_dev->dev); - pm_runtime_put(&mhi_dev->pci_dev->dev); - - return 0; -} - -int mhi_debugfs_trigger_m3(void *data, u64 val) -{ - struct mhi_controller *mhi_cntrl = data; - struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); - - MHI_LOG("Trigger M3 Entry\n"); - pm_runtime_mark_last_busy(&mhi_dev->pci_dev->dev); - pm_request_autosuspend(&mhi_dev->pci_dev->dev); - - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(debugfs_trigger_m0_fops, NULL, - mhi_debugfs_trigger_m0, "%llu\n"); - -DEFINE_SIMPLE_ATTRIBUTE(debugfs_trigger_m3_fops, NULL, - mhi_debugfs_trigger_m3, "%llu\n"); - -static int mhi_init_debugfs_trigger_go(void *data, u64 val) -{ - struct mhi_controller *mhi_cntrl = data; - - MHI_LOG("Trigger power up sequence\n"); - - mhi_async_power_up(mhi_cntrl); - - return 0; -} -DEFINE_SIMPLE_ATTRIBUTE(mhi_init_debugfs_trigger_go_fops, NULL, - mhi_init_debugfs_trigger_go, "%llu\n"); - - -int mhi_init_debugfs_debug_show(struct seq_file *m, void *d) -{ - seq_puts(m, "Enable debug mode to debug external soc\n"); - seq_puts(m, - "Usage: echo 'devid,timeout,domain,smmu_cfg' > debug_mode\n"); - seq_puts(m, "No spaces between parameters\n"); - seq_puts(m, "\t1. devid : 0 or pci device id to register\n"); - seq_puts(m, "\t2. timeout: mhi cmd/state transition timeout\n"); - seq_puts(m, "\t3. domain: Rootcomplex\n"); - seq_puts(m, "\t4. smmu_cfg: smmu configuration mask:\n"); - seq_puts(m, "\t\t- BIT0: ATTACH\n"); - seq_puts(m, "\t\t- BIT1: S1 BYPASS\n"); - seq_puts(m, "\t\t-BIT2: FAST_MAP\n"); - seq_puts(m, "\t\t-BIT3: ATOMIC\n"); - seq_puts(m, "\t\t-BIT4: FORCE_COHERENT\n"); - seq_puts(m, "\t\t-BIT5: GEOMETRY\n"); - seq_puts(m, "\tAll timeout are in ms, enter 0 to keep default\n"); - seq_puts(m, "Examples inputs: '0x307,10000'\n"); - seq_puts(m, "\techo '0,10000,1'\n"); - seq_puts(m, "\techo '0x307,10000,0,0x3d'\n"); - seq_puts(m, "firmware image name will be changed to debug.mbn\n"); - - return 0; -} - -static int mhi_init_debugfs_debug_open(struct inode *node, struct file *file) -{ - return single_open(file, mhi_init_debugfs_debug_show, NULL); -} - -static ssize_t mhi_init_debugfs_debug_write(struct file *fp, - const char __user *ubuf, - size_t count, - loff_t *pos) -{ - char *buf = kmalloc(count + 1, GFP_KERNEL); - /* #,devid,timeout,domain,smmu-cfg */ - int args[5] = {0}; - static char const *dbg_fw = "debug.mbn"; - int ret; - struct mhi_controller *mhi_cntrl = fp->f_inode->i_private; - struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); - struct pci_device_id *id; - - if (!buf) - return -ENOMEM; - - ret = copy_from_user(buf, ubuf, count); - if (ret) - goto error_read; - buf[count] = 0; - get_options(buf, ARRAY_SIZE(args), args); - kfree(buf); - - /* override default parameters */ - mhi_cntrl->fw_image = dbg_fw; - mhi_cntrl->edl_image = dbg_fw; - - if (args[0] >= 2 && args[2]) - mhi_cntrl->timeout_ms = args[2]; - - if (args[0] >= 3 && args[3]) - mhi_cntrl->domain = args[3]; - - if (args[0] >= 4 && args[4]) - mhi_dev->smmu_cfg = args[4]; - - /* If it's a new device id register it */ - if (args[0] && args[1]) { - /* find the debug_id and overwrite it */ - for (id = mhi_pcie_device_id; id->vendor; id++) - if (id->device == MHI_PCIE_DEBUG_ID) { - id->device = args[1]; - pci_unregister_driver(&mhi_pcie_driver); - ret = pci_register_driver(&mhi_pcie_driver); - } - } - - mhi_dev->debug_mode = true; - debugfs_create_file("go", 0444, mhi_cntrl->parent, mhi_cntrl, - &mhi_init_debugfs_trigger_go_fops); - pr_info( - "%s: ret:%d pcidev:0x%x smm_cfg:%u timeout:%u\n", - __func__, ret, args[1], mhi_dev->smmu_cfg, - mhi_cntrl->timeout_ms); - return count; - -error_read: - kfree(buf); - return ret; -} - -static const struct file_operations debugfs_debug_ops = { - .open = mhi_init_debugfs_debug_open, - .release = single_release, - .read = seq_read, - .write = mhi_init_debugfs_debug_write, -}; - -static struct mhi_controller * mhi_platform_probe(struct pci_dev *pci_dev) -{ - struct mhi_controller *mhi_cntrl; - struct mhi_dev *mhi_dev; - u64 addr_win[2]; - int ret; - - mhi_cntrl = mhi_alloc_controller(sizeof(*mhi_dev)); - if (!mhi_cntrl) { - pr_err("mhi_alloc_controller fail\n"); - return NULL; - } - - mhi_dev = mhi_controller_get_devdata(mhi_cntrl); - - mhi_cntrl->dev_id = pci_dev->device; - mhi_cntrl->domain = pci_domain_nr(pci_dev->bus); - mhi_cntrl->bus = pci_dev->bus->number; - mhi_cntrl->slot = PCI_SLOT(pci_dev->devfn); - mhi_dev->smmu_cfg = 0; - #if 0 //def CONFIG_HAVE_MEMBLOCK - addr_win[0] = memblock_start_of_DRAM(); - addr_win[1] = memblock_end_of_DRAM(); - #else -#define MHI_MEM_BASE_DEFAULT 0x000000000 -#define MHI_MEM_SIZE_DEFAULT 0x2000000000 - addr_win[0] = MHI_MEM_BASE_DEFAULT; - addr_win[1] = MHI_MEM_SIZE_DEFAULT; - if (sizeof(dma_addr_t) == 4) { - addr_win[1] = 0xFFFFFFFF; - } - #endif - - mhi_cntrl->iova_start = addr_win[0]; - mhi_cntrl->iova_stop = addr_win[1]; - - mhi_dev->pci_dev = pci_dev; - mhi_cntrl->pci_dev = pci_dev; - - /* setup power management apis */ - mhi_cntrl->status_cb = mhi_status_cb; - mhi_cntrl->runtime_get = mhi_runtime_get; - mhi_cntrl->runtime_put = mhi_runtime_put; - mhi_cntrl->link_status = mhi_link_status; - - ret = mhi_arch_platform_init(mhi_dev); - if (ret) - goto error_probe; - - ret = mhi_register_mhi_controller(mhi_cntrl); - if (ret) - goto error_register; - - if (mhi_cntrl->parent) - debugfs_create_file("debug_mode", 0444, mhi_cntrl->parent, - mhi_cntrl, &debugfs_debug_ops); - - return mhi_cntrl; - -error_register: - mhi_arch_platform_deinit(mhi_dev); - -error_probe: - mhi_free_controller(mhi_cntrl); - - return NULL; -} - -int mhi_pci_probe(struct pci_dev *pci_dev, - const struct pci_device_id *device_id) -{ - struct mhi_controller *mhi_cntrl = NULL; - u32 domain = pci_domain_nr(pci_dev->bus); - u32 bus = pci_dev->bus->number; - u32 slot = PCI_SLOT(pci_dev->devfn); - struct mhi_dev *mhi_dev; - int ret; - - pr_info("%s pci_dev->name = %s, domain=%d, bus=%d, slot=%d, vendor=%04X, device=%04X\n", - __func__, dev_name(&pci_dev->dev), domain, bus, slot, pci_dev->vendor, pci_dev->device); - - mhi_cntrl = mhi_platform_probe(pci_dev); - if (!mhi_cntrl) { - pr_err("mhi_platform_probe fail\n"); - return -EPROBE_DEFER; - } - - mhi_cntrl->dev_id = pci_dev->device; - mhi_dev = mhi_controller_get_devdata(mhi_cntrl); - mhi_dev->pci_dev = pci_dev; - mhi_dev->powered_on = true; - - ret = mhi_arch_pcie_init(mhi_cntrl); - if (ret) { - MHI_ERR("Error mhi_arch_pcie_init, ret:%d\n", ret); - return ret; - } - - ret = mhi_arch_iommu_init(mhi_cntrl); - if (ret) { - MHI_ERR("Error mhi_arch_iommu_init, ret:%d\n", ret); - goto error_iommu_init; - } - - ret = mhi_init_pci_dev(mhi_cntrl); - if (ret) { - MHI_ERR("Error mhi_init_pci_dev, ret:%d\n", ret); - goto error_init_pci; - } - - /* start power up sequence if not in debug mode */ - if (!mhi_dev->debug_mode) { - ret = mhi_async_power_up(mhi_cntrl); - if (ret) { - MHI_ERR("Error mhi_async_power_up, ret:%d\n", ret); - goto error_power_up; - } - } - -#if 0 - pm_runtime_mark_last_busy(&pci_dev->dev); - pm_runtime_allow(&pci_dev->dev); - pm_runtime_disable(&pci_dev->dev); -#endif - - if (mhi_cntrl->dentry) { - debugfs_create_file("m0", 0444, mhi_cntrl->dentry, mhi_cntrl, - &debugfs_trigger_m0_fops); - debugfs_create_file("m3", 0444, mhi_cntrl->dentry, mhi_cntrl, - &debugfs_trigger_m3_fops); - } - - dev_set_drvdata(&pci_dev->dev, mhi_cntrl); - MHI_LOG("Return successful\n"); - - return 0; - -error_power_up: - mhi_deinit_pci_dev(mhi_cntrl); - -error_init_pci: - mhi_arch_iommu_deinit(mhi_cntrl); - -error_iommu_init: - mhi_arch_pcie_deinit(mhi_cntrl); - - return ret; -} - -static void mhi_pci_remove(struct pci_dev *pci_dev) -{ - struct mhi_controller *mhi_cntrl = (struct mhi_controller *)dev_get_drvdata(&pci_dev->dev); - - if (mhi_cntrl && mhi_cntrl->pci_dev == pci_dev) { - struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); - MHI_LOG("%s\n", dev_name(&pci_dev->dev)); - if (!mhi_dev->debug_mode) { - mhi_power_down(mhi_cntrl, 1); - } - mhi_deinit_pci_dev(mhi_cntrl); - mhi_arch_iommu_deinit(mhi_cntrl); - mhi_arch_pcie_deinit(mhi_cntrl); - mhi_unregister_mhi_controller(mhi_cntrl); - } -} - -static const struct dev_pm_ops pm_ops = { - SET_RUNTIME_PM_OPS(mhi_runtime_suspend, - mhi_runtime_resume, - mhi_runtime_idle) - SET_SYSTEM_SLEEP_PM_OPS(mhi_system_suspend, mhi_system_resume) -}; - -static struct pci_driver mhi_pcie_driver = { - .name = "mhi", - .id_table = mhi_pcie_device_id, - .probe = mhi_pci_probe, - .remove = mhi_pci_remove, - .driver = { - .pm = &pm_ops - } -}; - -int __init mhi_controller_qcom_init(void) -{ - return pci_register_driver(&mhi_pcie_driver); -}; - -void mhi_controller_qcom_exit(void) -{ - pr_info("%s enter\n", __func__); - pci_unregister_driver(&mhi_pcie_driver); - pr_info("%s exit\n", __func__); -} +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../core/mhi.h" +#include "mhi_qcom.h" + +#if 1 +#ifndef PCI_IRQ_MSI +#define PCI_IRQ_MSI (1 << 1) /* Allow MSI interrupts */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,10,53 )) +int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) +{ + int nvec = maxvec; + int rc; + + if (maxvec < minvec) + return -ERANGE; + + do { + rc = pci_enable_msi_block(dev, nvec); + if (rc < 0) { + return rc; + } else if (rc > 0) { + if (rc < minvec) + return -ENOSPC; + nvec = rc; + } + } while (rc); + + return nvec; +} +#endif + +static int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, + unsigned int max_vecs, unsigned int flags) +{ + return pci_enable_msi_range(dev, min_vecs, max_vecs); +} + +static void pci_free_irq_vectors(struct pci_dev *dev) +{ + pci_disable_msi(dev); +} + +static int pci_irq_vector(struct pci_dev *dev, unsigned int nr) +{ + return dev->irq + nr; +} +#endif +#endif + +static struct pci_device_id mhi_pcie_device_id[] = { + {PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0303)}, //SDX20 + {PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0304)}, //SDX24 + {PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0305)}, + {PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0306)}, //SDX55 + {PCI_DEVICE(0x2C7C, 0x0512)}, + {PCI_DEVICE(MHI_PCIE_VENDOR_ID, MHI_PCIE_DEBUG_ID)}, + {0}, +}; + +MODULE_DEVICE_TABLE(pci, mhi_pcie_device_id); + +static struct pci_driver mhi_pcie_driver; + +void mhi_deinit_pci_dev(struct mhi_controller *mhi_cntrl) +{ + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + struct pci_dev *pci_dev = mhi_dev->pci_dev; + + pci_free_irq_vectors(pci_dev); + iounmap(mhi_cntrl->regs); + mhi_cntrl->regs = NULL; + pci_clear_master(pci_dev); + pci_release_region(pci_dev, mhi_dev->resn); + pci_disable_device(pci_dev); +} + +static int mhi_init_pci_dev(struct mhi_controller *mhi_cntrl) +{ + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + struct pci_dev *pci_dev = mhi_dev->pci_dev; + int ret; + resource_size_t start, len; + int i; + + mhi_dev->resn = MHI_PCI_BAR_NUM; + ret = pci_assign_resource(pci_dev, mhi_dev->resn); + if (ret) { + MHI_ERR("Error assign pci resources, ret:%d\n", ret); + return ret; + } + + ret = pci_enable_device(pci_dev); + if (ret) { + MHI_ERR("Error enabling device, ret:%d\n", ret); + goto error_enable_device; + } + + ret = pci_request_region(pci_dev, mhi_dev->resn, "mhi"); + if (ret) { + MHI_ERR("Error pci_request_region, ret:%d\n", ret); + goto error_request_region; + } + + pci_set_master(pci_dev); + + start = pci_resource_start(pci_dev, mhi_dev->resn); + len = pci_resource_len(pci_dev, mhi_dev->resn); + mhi_cntrl->regs = ioremap_nocache(start, len); + MHI_LOG("mhi_cntrl->regs = %p\n", mhi_cntrl->regs); + if (!mhi_cntrl->regs) { + MHI_ERR("Error ioremap region\n"); + goto error_ioremap; + } + + ret = pci_alloc_irq_vectors(pci_dev, 1, mhi_cntrl->msi_required, PCI_IRQ_MSI); + if (IS_ERR_VALUE((ulong)ret) || ret < mhi_cntrl->msi_required) { + if (ret == -ENOSPC) { + /* imx_3.14.52_1.1.0_ga + diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c + index f06e8f0..6a9614f 100644 + --- a/drivers/pci/host/pcie-designware.c + +++ b/drivers/pci/host/pcie-designware.c + @@ -376,6 +376,13 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, + if (msgvec > 5) + msgvec = 0; + + +#if 1 //Add by Quectel 20190419 + + if (msgvec > 0 && pdev->vendor == 0x17cb) { + + dev_info(&pdev->dev, "%s quectel fixup pos=%d, msg_ctr=%04x, msgvec=%d\n", __func__, desc->msi_attrib.pos, msg_ctr, msgvec); + + msgvec = 0; + + } + +#endif + + + irq = assign_irq((1 << msgvec), desc, &pos); + if (irq < 0) + return irq; + */ + } + //imx_4.1.15_2.0.0_ga & DELL_OPTIPLEX_7010 only alloc one msi interrupt for one pcie device + if (ret != 1) { + MHI_ERR("Failed to enable MSI, ret=%d, msi_required=%d\n", ret, mhi_cntrl->msi_required); + goto error_req_msi; + } + } + + mhi_cntrl->msi_allocated = ret; + MHI_LOG("msi_required = %d, msi_allocated = %d, msi_irq = %u\n", mhi_cntrl->msi_required, mhi_cntrl->msi_allocated, pci_dev->irq); + + for (i = 0; i < mhi_cntrl->msi_allocated; i++) { + mhi_cntrl->irq[i] = pci_irq_vector(pci_dev, i); + if (mhi_cntrl->irq[i] < 0) { + ret = mhi_cntrl->irq[i]; + goto error_get_irq_vec; + } + } + +#if 0 + /* configure runtime pm */ + pm_runtime_set_autosuspend_delay(&pci_dev->dev, MHI_RPM_SUSPEND_TMR_MS); + pm_runtime_dont_use_autosuspend(&pci_dev->dev); + pm_suspend_ignore_children(&pci_dev->dev, true); + + /* + * pci framework will increment usage count (twice) before + * calling local device driver probe function. + * 1st pci.c pci_pm_init() calls pm_runtime_forbid + * 2nd pci-driver.c local_pci_probe calls pm_runtime_get_sync + * Framework expect pci device driver to call + * pm_runtime_put_noidle to decrement usage count after + * successful probe and and call pm_runtime_allow to enable + * runtime suspend. + */ + pm_runtime_mark_last_busy(&pci_dev->dev); + pm_runtime_put_noidle(&pci_dev->dev); +#endif + + return 0; + +error_get_irq_vec: + pci_free_irq_vectors(pci_dev); + +error_req_msi: + iounmap(mhi_cntrl->regs); + +error_ioremap: + pci_clear_master(pci_dev); + +error_request_region: + pci_disable_device(pci_dev); + +error_enable_device: + pci_release_region(pci_dev, mhi_dev->resn); + + return ret; +} + +#ifdef CONFIG_PM +static int mhi_runtime_idle(struct device *dev) +{ + struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); + + MHI_LOG("Entered returning -EBUSY\n"); + + /* + * RPM framework during runtime resume always calls + * rpm_idle to see if device ready to suspend. + * If dev.power usage_count count is 0, rpm fw will call + * rpm_idle cb to see if device is ready to suspend. + * if cb return 0, or cb not defined the framework will + * assume device driver is ready to suspend; + * therefore, fw will schedule runtime suspend. + * In MHI power management, MHI host shall go to + * runtime suspend only after entering MHI State M2, even if + * usage count is 0. Return -EBUSY to disable automatic suspend. + */ + return -EBUSY; +} + +static int mhi_runtime_suspend(struct device *dev) +{ + int ret = 0; + struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); + + MHI_LOG("Enter\n"); + + mutex_lock(&mhi_cntrl->pm_mutex); + + ret = mhi_pm_suspend(mhi_cntrl); + if (ret) { + MHI_LOG("Abort due to ret:%d\n", ret); + goto exit_runtime_suspend; + } + + ret = mhi_arch_link_off(mhi_cntrl, true); + if (ret) + MHI_ERR("Failed to Turn off link ret:%d\n", ret); + +exit_runtime_suspend: + mutex_unlock(&mhi_cntrl->pm_mutex); + MHI_LOG("Exited with ret:%d\n", ret); + + return ret; +} + +static int mhi_runtime_resume(struct device *dev) +{ + int ret = 0; + struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + + MHI_LOG("Enter\n"); + + mutex_lock(&mhi_cntrl->pm_mutex); + + if (!mhi_dev->powered_on) { + MHI_LOG("Not fully powered, return success\n"); + mutex_unlock(&mhi_cntrl->pm_mutex); + return 0; + } + + /* turn on link */ + ret = mhi_arch_link_on(mhi_cntrl); + if (ret) + goto rpm_resume_exit; + + /* enter M0 state */ + ret = mhi_pm_resume(mhi_cntrl); + +rpm_resume_exit: + mutex_unlock(&mhi_cntrl->pm_mutex); + MHI_LOG("Exited with :%d\n", ret); + + return ret; +} + +static int mhi_system_resume(struct device *dev) +{ + int ret = 0; + struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); + + ret = mhi_runtime_resume(dev); + if (ret) { + MHI_ERR("Failed to resume link\n"); + } else { + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + } + + return ret; +} + +int mhi_system_suspend(struct device *dev) +{ + struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); + + MHI_LOG("Entered\n"); + + /* if rpm status still active then force suspend */ + if (!pm_runtime_status_suspended(dev)) + return mhi_runtime_suspend(dev); + + pm_runtime_set_suspended(dev); + pm_runtime_disable(dev); + + MHI_LOG("Exit\n"); + return 0; +} +#endif + +/* checks if link is down */ +static int mhi_link_status(struct mhi_controller *mhi_cntrl, void *priv) +{ + struct mhi_dev *mhi_dev = priv; + u16 dev_id; + int ret; + + /* try reading device id, if dev id don't match, link is down */ + ret = pci_read_config_word(mhi_dev->pci_dev, PCI_DEVICE_ID, &dev_id); + + return (ret || dev_id != mhi_cntrl->dev_id) ? -EIO : 0; +} + +static int mhi_runtime_get(struct mhi_controller *mhi_cntrl, void *priv) +{ + struct mhi_dev *mhi_dev = priv; + struct device *dev = &mhi_dev->pci_dev->dev; + + return pm_runtime_get(dev); +} + +static void mhi_runtime_put(struct mhi_controller *mhi_cntrl, void *priv) +{ + struct mhi_dev *mhi_dev = priv; + struct device *dev = &mhi_dev->pci_dev->dev; + + pm_runtime_put_noidle(dev); +} + +static void mhi_status_cb(struct mhi_controller *mhi_cntrl, + void *priv, + enum MHI_CB reason) +{ + struct mhi_dev *mhi_dev = priv; + struct device *dev = &mhi_dev->pci_dev->dev; + + if (reason == MHI_CB_IDLE) { + MHI_LOG("Schedule runtime suspend 1\n"); + pm_runtime_mark_last_busy(dev); + pm_request_autosuspend(dev); + } +} + +int mhi_debugfs_trigger_m0(void *data, u64 val) +{ + struct mhi_controller *mhi_cntrl = data; + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + + MHI_LOG("Trigger M3 Exit\n"); + pm_runtime_get(&mhi_dev->pci_dev->dev); + pm_runtime_put(&mhi_dev->pci_dev->dev); + + return 0; +} + +int mhi_debugfs_trigger_m3(void *data, u64 val) +{ + struct mhi_controller *mhi_cntrl = data; + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + + MHI_LOG("Trigger M3 Entry\n"); + pm_runtime_mark_last_busy(&mhi_dev->pci_dev->dev); + pm_request_autosuspend(&mhi_dev->pci_dev->dev); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(debugfs_trigger_m0_fops, NULL, + mhi_debugfs_trigger_m0, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(debugfs_trigger_m3_fops, NULL, + mhi_debugfs_trigger_m3, "%llu\n"); + +static int mhi_init_debugfs_trigger_go(void *data, u64 val) +{ + struct mhi_controller *mhi_cntrl = data; + + MHI_LOG("Trigger power up sequence\n"); + + mhi_async_power_up(mhi_cntrl); + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(mhi_init_debugfs_trigger_go_fops, NULL, + mhi_init_debugfs_trigger_go, "%llu\n"); + + +int mhi_init_debugfs_debug_show(struct seq_file *m, void *d) +{ + seq_puts(m, "Enable debug mode to debug external soc\n"); + seq_puts(m, + "Usage: echo 'devid,timeout,domain,smmu_cfg' > debug_mode\n"); + seq_puts(m, "No spaces between parameters\n"); + seq_puts(m, "\t1. devid : 0 or pci device id to register\n"); + seq_puts(m, "\t2. timeout: mhi cmd/state transition timeout\n"); + seq_puts(m, "\t3. domain: Rootcomplex\n"); + seq_puts(m, "\t4. smmu_cfg: smmu configuration mask:\n"); + seq_puts(m, "\t\t- BIT0: ATTACH\n"); + seq_puts(m, "\t\t- BIT1: S1 BYPASS\n"); + seq_puts(m, "\t\t-BIT2: FAST_MAP\n"); + seq_puts(m, "\t\t-BIT3: ATOMIC\n"); + seq_puts(m, "\t\t-BIT4: FORCE_COHERENT\n"); + seq_puts(m, "\t\t-BIT5: GEOMETRY\n"); + seq_puts(m, "\tAll timeout are in ms, enter 0 to keep default\n"); + seq_puts(m, "Examples inputs: '0x307,10000'\n"); + seq_puts(m, "\techo '0,10000,1'\n"); + seq_puts(m, "\techo '0x307,10000,0,0x3d'\n"); + seq_puts(m, "firmware image name will be changed to debug.mbn\n"); + + return 0; +} + +static int mhi_init_debugfs_debug_open(struct inode *node, struct file *file) +{ + return single_open(file, mhi_init_debugfs_debug_show, NULL); +} + +static ssize_t mhi_init_debugfs_debug_write(struct file *fp, + const char __user *ubuf, + size_t count, + loff_t *pos) +{ + char *buf = kmalloc(count + 1, GFP_KERNEL); + /* #,devid,timeout,domain,smmu-cfg */ + int args[5] = {0}; + static char const *dbg_fw = "debug.mbn"; + int ret; + struct mhi_controller *mhi_cntrl = fp->f_inode->i_private; + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + struct pci_device_id *id; + + if (!buf) + return -ENOMEM; + + ret = copy_from_user(buf, ubuf, count); + if (ret) + goto error_read; + buf[count] = 0; + get_options(buf, ARRAY_SIZE(args), args); + kfree(buf); + + /* override default parameters */ + mhi_cntrl->fw_image = dbg_fw; + mhi_cntrl->edl_image = dbg_fw; + + if (args[0] >= 2 && args[2]) + mhi_cntrl->timeout_ms = args[2]; + + if (args[0] >= 3 && args[3]) + mhi_cntrl->domain = args[3]; + + if (args[0] >= 4 && args[4]) + mhi_dev->smmu_cfg = args[4]; + + /* If it's a new device id register it */ + if (args[0] && args[1]) { + /* find the debug_id and overwrite it */ + for (id = mhi_pcie_device_id; id->vendor; id++) + if (id->device == MHI_PCIE_DEBUG_ID) { + id->device = args[1]; + pci_unregister_driver(&mhi_pcie_driver); + ret = pci_register_driver(&mhi_pcie_driver); + } + } + + mhi_dev->debug_mode = true; + debugfs_create_file("go", 0444, mhi_cntrl->parent, mhi_cntrl, + &mhi_init_debugfs_trigger_go_fops); + pr_info( + "%s: ret:%d pcidev:0x%x smm_cfg:%u timeout:%u\n", + __func__, ret, args[1], mhi_dev->smmu_cfg, + mhi_cntrl->timeout_ms); + return count; + +error_read: + kfree(buf); + return ret; +} + +static const struct file_operations debugfs_debug_ops = { + .open = mhi_init_debugfs_debug_open, + .release = single_release, + .read = seq_read, + .write = mhi_init_debugfs_debug_write, +}; + +static struct mhi_controller * mhi_platform_probe(struct pci_dev *pci_dev) +{ + struct mhi_controller *mhi_cntrl; + struct mhi_dev *mhi_dev; + u64 addr_win[2]; + int ret; + + mhi_cntrl = mhi_alloc_controller(sizeof(*mhi_dev)); + if (!mhi_cntrl) { + pr_err("mhi_alloc_controller fail\n"); + return NULL; + } + + mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + + mhi_cntrl->dev_id = pci_dev->device; + mhi_cntrl->domain = pci_domain_nr(pci_dev->bus); + mhi_cntrl->bus = pci_dev->bus->number; + mhi_cntrl->slot = PCI_SLOT(pci_dev->devfn); + mhi_dev->smmu_cfg = 0; + #if 0 //def CONFIG_HAVE_MEMBLOCK + addr_win[0] = memblock_start_of_DRAM(); + addr_win[1] = memblock_end_of_DRAM(); + #else +#define MHI_MEM_BASE_DEFAULT 0x000000000 +#define MHI_MEM_SIZE_DEFAULT 0x2000000000 + addr_win[0] = MHI_MEM_BASE_DEFAULT; + addr_win[1] = MHI_MEM_SIZE_DEFAULT; + if (sizeof(dma_addr_t) == 4) { + addr_win[1] = 0xFFFFFFFF; + } + #endif + + mhi_cntrl->iova_start = addr_win[0]; + mhi_cntrl->iova_stop = addr_win[1]; + + mhi_dev->pci_dev = pci_dev; + mhi_cntrl->pci_dev = pci_dev; + + /* setup power management apis */ + mhi_cntrl->status_cb = mhi_status_cb; + mhi_cntrl->runtime_get = mhi_runtime_get; + mhi_cntrl->runtime_put = mhi_runtime_put; + mhi_cntrl->link_status = mhi_link_status; + + ret = mhi_arch_platform_init(mhi_dev); + if (ret) + goto error_probe; + + ret = mhi_register_mhi_controller(mhi_cntrl); + if (ret) + goto error_register; + + if (mhi_cntrl->parent) + debugfs_create_file("debug_mode", 0444, mhi_cntrl->parent, + mhi_cntrl, &debugfs_debug_ops); + + return mhi_cntrl; + +error_register: + mhi_arch_platform_deinit(mhi_dev); + +error_probe: + mhi_free_controller(mhi_cntrl); + + return NULL; +} + +int mhi_pci_probe(struct pci_dev *pci_dev, + const struct pci_device_id *device_id) +{ + struct mhi_controller *mhi_cntrl = NULL; + u32 domain = pci_domain_nr(pci_dev->bus); + u32 bus = pci_dev->bus->number; + u32 slot = PCI_SLOT(pci_dev->devfn); + struct mhi_dev *mhi_dev; + int ret; + + pr_info("%s pci_dev->name = %s, domain=%d, bus=%d, slot=%d, vendor=%04X, device=%04X\n", + __func__, dev_name(&pci_dev->dev), domain, bus, slot, pci_dev->vendor, pci_dev->device); + + mhi_cntrl = mhi_platform_probe(pci_dev); + if (!mhi_cntrl) { + pr_err("mhi_platform_probe fail\n"); + return -EPROBE_DEFER; + } + + mhi_cntrl->dev_id = pci_dev->device; + mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + mhi_dev->pci_dev = pci_dev; + mhi_dev->powered_on = true; + + ret = mhi_arch_pcie_init(mhi_cntrl); + if (ret) { + MHI_ERR("Error mhi_arch_pcie_init, ret:%d\n", ret); + return ret; + } + + ret = mhi_arch_iommu_init(mhi_cntrl); + if (ret) { + MHI_ERR("Error mhi_arch_iommu_init, ret:%d\n", ret); + goto error_iommu_init; + } + + ret = mhi_init_pci_dev(mhi_cntrl); + if (ret) { + MHI_ERR("Error mhi_init_pci_dev, ret:%d\n", ret); + goto error_init_pci; + } + + /* start power up sequence if not in debug mode */ + if (!mhi_dev->debug_mode) { + ret = mhi_async_power_up(mhi_cntrl); + if (ret) { + MHI_ERR("Error mhi_async_power_up, ret:%d\n", ret); + goto error_power_up; + } + } + +#if 0 + pm_runtime_mark_last_busy(&pci_dev->dev); + pm_runtime_allow(&pci_dev->dev); + pm_runtime_disable(&pci_dev->dev); +#endif + + if (mhi_cntrl->dentry) { + debugfs_create_file("m0", 0444, mhi_cntrl->dentry, mhi_cntrl, + &debugfs_trigger_m0_fops); + debugfs_create_file("m3", 0444, mhi_cntrl->dentry, mhi_cntrl, + &debugfs_trigger_m3_fops); + } + + dev_set_drvdata(&pci_dev->dev, mhi_cntrl); + MHI_LOG("Return successful\n"); + + return 0; + +error_power_up: + mhi_deinit_pci_dev(mhi_cntrl); + +error_init_pci: + mhi_arch_iommu_deinit(mhi_cntrl); + +error_iommu_init: + mhi_arch_pcie_deinit(mhi_cntrl); + + return ret; +} + +static void mhi_pci_remove(struct pci_dev *pci_dev) +{ + struct mhi_controller *mhi_cntrl = (struct mhi_controller *)dev_get_drvdata(&pci_dev->dev); + + if (mhi_cntrl && mhi_cntrl->pci_dev == pci_dev) { + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + MHI_LOG("%s\n", dev_name(&pci_dev->dev)); + if (!mhi_dev->debug_mode) { + mhi_power_down(mhi_cntrl, 1); + } + mhi_deinit_pci_dev(mhi_cntrl); + mhi_arch_iommu_deinit(mhi_cntrl); + mhi_arch_pcie_deinit(mhi_cntrl); + mhi_unregister_mhi_controller(mhi_cntrl); + } +} + +static const struct dev_pm_ops pm_ops = { + SET_RUNTIME_PM_OPS(mhi_runtime_suspend, + mhi_runtime_resume, + mhi_runtime_idle) + SET_SYSTEM_SLEEP_PM_OPS(mhi_system_suspend, mhi_system_resume) +}; + +static struct pci_driver mhi_pcie_driver = { + .name = "mhi", + .id_table = mhi_pcie_device_id, + .probe = mhi_pci_probe, + .remove = mhi_pci_remove, + .driver = { + .pm = &pm_ops + } +}; + +int __init mhi_controller_qcom_init(void) +{ + return pci_register_driver(&mhi_pcie_driver); +}; + +void mhi_controller_qcom_exit(void) +{ + pr_info("%s enter\n", __func__); + pci_unregister_driver(&mhi_pcie_driver); + pr_info("%s exit\n", __func__); +} diff --git a/quectel_MHI/src/controllers/mhi_qcom.h b/quectel_MHI/src/controllers/mhi_qcom.h index bced45b3..65ec5b8d 100644 --- a/quectel_MHI/src/controllers/mhi_qcom.h +++ b/quectel_MHI/src/controllers/mhi_qcom.h @@ -1,92 +1,92 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _MHI_QCOM_ -#define _MHI_QCOM_ - -/* iova cfg bitmask */ -#define MHI_SMMU_ATTACH BIT(0) -#define MHI_SMMU_S1_BYPASS BIT(1) -#define MHI_SMMU_FAST BIT(2) -#define MHI_SMMU_ATOMIC BIT(3) -#define MHI_SMMU_FORCE_COHERENT BIT(4) - -#define MHI_PCIE_VENDOR_ID (0x17cb) -#define MHI_PCIE_DEBUG_ID (0xffff) -#define MHI_RPM_SUSPEND_TMR_MS (3000) -#define MHI_PCI_BAR_NUM (0) - -struct mhi_dev { - struct pci_dev *pci_dev; - u32 smmu_cfg; - int resn; - void *arch_info; - bool powered_on; - bool debug_mode; -}; - -void mhi_deinit_pci_dev(struct mhi_controller *mhi_cntrl); -int mhi_pci_probe(struct pci_dev *pci_dev, - const struct pci_device_id *device_id); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,10,65 )) -static inline int dma_set_mask_and_coherent(struct device *dev, u64 mask) -{ - int rc = dma_set_mask(dev, mask); - if (rc == 0) - dma_set_coherent_mask(dev, mask); - return rc; -} -#endif - -static inline int mhi_arch_iommu_init(struct mhi_controller *mhi_cntrl) -{ - struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); - - mhi_cntrl->dev = &mhi_dev->pci_dev->dev; - - return dma_set_mask_and_coherent(mhi_cntrl->dev, DMA_BIT_MASK(64)); -} - -static inline void mhi_arch_iommu_deinit(struct mhi_controller *mhi_cntrl) -{ -} - -static inline int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) -{ - return 0; -} - -static inline void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl) -{ -} - -static inline int mhi_arch_platform_init(struct mhi_dev *mhi_dev) -{ - return 0; -} - -static inline void mhi_arch_platform_deinit(struct mhi_dev *mhi_dev) -{ -} - -static inline int mhi_arch_link_off(struct mhi_controller *mhi_cntrl, - bool graceful) -{ - return 0; -} - -static inline int mhi_arch_link_on(struct mhi_controller *mhi_cntrl) -{ - return 0; -} - -#endif /* _MHI_QCOM_ */ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _MHI_QCOM_ +#define _MHI_QCOM_ + +/* iova cfg bitmask */ +#define MHI_SMMU_ATTACH BIT(0) +#define MHI_SMMU_S1_BYPASS BIT(1) +#define MHI_SMMU_FAST BIT(2) +#define MHI_SMMU_ATOMIC BIT(3) +#define MHI_SMMU_FORCE_COHERENT BIT(4) + +#define MHI_PCIE_VENDOR_ID (0x17cb) +#define MHI_PCIE_DEBUG_ID (0xffff) +#define MHI_RPM_SUSPEND_TMR_MS (3000) +#define MHI_PCI_BAR_NUM (0) + +struct mhi_dev { + struct pci_dev *pci_dev; + u32 smmu_cfg; + int resn; + void *arch_info; + bool powered_on; + bool debug_mode; +}; + +void mhi_deinit_pci_dev(struct mhi_controller *mhi_cntrl); +int mhi_pci_probe(struct pci_dev *pci_dev, + const struct pci_device_id *device_id); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,10,65 )) +static inline int dma_set_mask_and_coherent(struct device *dev, u64 mask) +{ + int rc = dma_set_mask(dev, mask); + if (rc == 0) + dma_set_coherent_mask(dev, mask); + return rc; +} +#endif + +static inline int mhi_arch_iommu_init(struct mhi_controller *mhi_cntrl) +{ + struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); + + mhi_cntrl->dev = &mhi_dev->pci_dev->dev; + + return dma_set_mask_and_coherent(mhi_cntrl->dev, DMA_BIT_MASK(64)); +} + +static inline void mhi_arch_iommu_deinit(struct mhi_controller *mhi_cntrl) +{ +} + +static inline int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) +{ + return 0; +} + +static inline void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl) +{ +} + +static inline int mhi_arch_platform_init(struct mhi_dev *mhi_dev) +{ + return 0; +} + +static inline void mhi_arch_platform_deinit(struct mhi_dev *mhi_dev) +{ +} + +static inline int mhi_arch_link_off(struct mhi_controller *mhi_cntrl, + bool graceful) +{ + return 0; +} + +static inline int mhi_arch_link_on(struct mhi_controller *mhi_cntrl) +{ + return 0; +} + +#endif /* _MHI_QCOM_ */ diff --git a/quectel_MHI/src/controllers/mhi_qti.c b/quectel_MHI/src/controllers/mhi_qti.c index 9090fbbd..e31db982 100644 --- a/quectel_MHI/src/controllers/mhi_qti.c +++ b/quectel_MHI/src/controllers/mhi_qti.c @@ -430,8 +430,7 @@ rpm_resume_exit: return ret; } -#ifdef CONFIG_PM_SLEEP -static int mhi_system_resume(struct device *dev) +static int __maybe_unused mhi_system_resume(struct device *dev) { int ret = 0; struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); @@ -475,7 +474,6 @@ int mhi_system_suspend(struct device *dev) return 0; } #endif -#endif /* checks if link is down */ static int mhi_link_status(struct mhi_controller *mhi_cntrl, void *priv) diff --git a/quectel_MHI/src/core/mhi_init.c b/quectel_MHI/src/core/mhi_init.c index bd8c2675..6d8eec50 100644 --- a/quectel_MHI/src/core/mhi_init.c +++ b/quectel_MHI/src/core/mhi_init.c @@ -644,9 +644,7 @@ static int mon_text_release(struct inode *inode, struct file *file) static const struct file_operations mon_fops_text_u = { .owner = THIS_MODULE, .open = mon_text_open, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 12, 0)) .llseek = no_llseek, -#endif .read = mon_text_read_u, .release = mon_text_release, }; @@ -2371,11 +2369,7 @@ void mhi_unprepare_after_power_down(struct mhi_controller *mhi_cntrl) } /* match dev to drv */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)) -static int mhi_match(struct device *dev, const struct device_driver *drv) -#else static int mhi_match(struct device *dev, struct device_driver *drv) -#endif { struct mhi_device *mhi_dev = to_mhi_device(dev); struct mhi_driver *mhi_drv = to_mhi_driver(drv); diff --git a/quectel_MHI/src/core/mhi_sdx20.h b/quectel_MHI/src/core/mhi_sdx20.h index 5a92efa4..2bc5dc7b 100644 --- a/quectel_MHI/src/core/mhi_sdx20.h +++ b/quectel_MHI/src/core/mhi_sdx20.h @@ -1,362 +1,362 @@ -#ifndef __SDX20_MHI_H -#define __SDX20_MHI_H - -#include - -/* MHI control data structures alloted by the host, including - * channel context array, event context array, command context and rings */ - -/* Channel context state */ -enum mhi_dev_ch_ctx_state { - MHI_DEV_CH_STATE_DISABLED, - MHI_DEV_CH_STATE_ENABLED, - MHI_DEV_CH_STATE_RUNNING, - MHI_DEV_CH_STATE_SUSPENDED, - MHI_DEV_CH_STATE_STOP, - MHI_DEV_CH_STATE_ERROR, - MHI_DEV_CH_STATE_RESERVED, - MHI_DEV_CH_STATE_32BIT = 0x7FFFFFFF -}; - -/* Channel type */ -enum mhi_dev_ch_ctx_type { - MHI_DEV_CH_TYPE_NONE, - MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL, - MHI_DEV_CH_TYPE_INBOUND_CHANNEL, - MHI_DEV_CH_RESERVED -}; - -/* Channel context type */ -struct mhi_dev_ch_ctx { - enum mhi_dev_ch_ctx_state ch_state; - enum mhi_dev_ch_ctx_type ch_type; - uint32_t err_indx; - uint64_t rbase; - uint64_t rlen; - uint64_t rp; - uint64_t wp; -} __packed; - -enum mhi_dev_ring_element_type_id { - MHI_DEV_RING_EL_INVALID = 0, - MHI_DEV_RING_EL_NOOP = 1, - MHI_DEV_RING_EL_TRANSFER = 2, - MHI_DEV_RING_EL_RESET = 16, - MHI_DEV_RING_EL_STOP = 17, - MHI_DEV_RING_EL_START = 18, - MHI_DEV_RING_EL_MHI_STATE_CHG = 32, - MHI_DEV_RING_EL_CMD_COMPLETION_EVT = 33, - MHI_DEV_RING_EL_TRANSFER_COMPLETION_EVENT = 34, - MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY = 64, - MHI_DEV_RING_EL_UNDEF -}; - -enum mhi_dev_ring_state { - RING_STATE_UINT = 0, - RING_STATE_IDLE, - RING_STATE_PENDING, -}; - -enum mhi_dev_ring_type { - RING_TYPE_CMD = 0, - RING_TYPE_ER, - RING_TYPE_CH, - RING_TYPE_INVAL -}; - -/* Event context interrupt moderation */ -enum mhi_dev_evt_ctx_int_mod_timer { - MHI_DEV_EVT_INT_MODERATION_DISABLED -}; - -/* Event ring type */ -enum mhi_dev_evt_ctx_event_ring_type { - MHI_DEV_EVT_TYPE_DEFAULT, - MHI_DEV_EVT_TYPE_VALID, - MHI_DEV_EVT_RESERVED -}; - -/* Event ring context type */ -struct mhi_dev_ev_ctx { - uint32_t res1:16; - enum mhi_dev_evt_ctx_int_mod_timer intmodt:16; - enum mhi_dev_evt_ctx_event_ring_type ertype; - uint32_t msivec; - uint64_t rbase; - uint64_t rlen; - uint64_t rp; - uint64_t wp; -} __packed; - -/* Command context */ -struct mhi_dev_cmd_ctx { - uint32_t res1; - uint32_t res2; - uint32_t res3; - uint64_t rbase; - uint64_t rlen; - uint64_t rp; - uint64_t wp; -} __packed; - -/* generic context */ -struct mhi_dev_gen_ctx { - uint32_t res1; - uint32_t res2; - uint32_t res3; - uint64_t rbase; - uint64_t rlen; - uint64_t rp; - uint64_t wp; -} __packed; - -/* Transfer ring element */ -struct mhi_dev_transfer_ring_element { - uint64_t data_buf_ptr; - uint32_t len:16; - uint32_t res1:16; - uint32_t chain:1; - uint32_t res2:7; - uint32_t ieob:1; - uint32_t ieot:1; - uint32_t bei:1; - uint32_t res3:5; - enum mhi_dev_ring_element_type_id type:8; - uint32_t res4:8; -} __packed; - -/* Command ring element */ -/* Command ring No op command */ -struct mhi_dev_cmd_ring_op { - uint64_t res1; - uint32_t res2; - uint32_t res3:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -/* Command ring reset channel command */ -struct mhi_dev_cmd_ring_reset_channel_cmd { - uint64_t res1; - uint32_t res2; - uint32_t res3:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -/* Command ring stop channel command */ -struct mhi_dev_cmd_ring_stop_channel_cmd { - uint64_t res1; - uint32_t res2; - uint32_t res3:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -/* Command ring start channel command */ -struct mhi_dev_cmd_ring_start_channel_cmd { - uint64_t res1; - uint32_t seqnum; - uint32_t reliable:1; - uint32_t res2:15; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -enum mhi_dev_cmd_completion_code { - MHI_CMD_COMPL_CODE_INVALID = 0, - MHI_CMD_COMPL_CODE_SUCCESS = 1, - MHI_CMD_COMPL_CODE_EOT = 2, - MHI_CMD_COMPL_CODE_OVERFLOW = 3, - MHI_CMD_COMPL_CODE_EOB = 4, - MHI_CMD_COMPL_CODE_UNDEFINED = 16, - MHI_CMD_COMPL_CODE_RING_EL = 17, - MHI_CMD_COMPL_CODE_RES -}; - -/* Event ring elements */ -/* Transfer completion event */ -struct mhi_dev_event_ring_transfer_completion { - uint64_t ptr; - uint32_t len:16; - uint32_t res1:8; - enum mhi_dev_cmd_completion_code code:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -/* Command completion event */ -struct mhi_dev_event_ring_cmd_completion { - uint64_t ptr; - uint32_t res1:24; - enum mhi_dev_cmd_completion_code code:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t res3:8; -} __packed; - -enum mhi_dev_state { - MHI_DEV_RESET_STATE = 0, - MHI_DEV_READY_STATE, - MHI_DEV_M0_STATE, - MHI_DEV_M1_STATE, - MHI_DEV_M2_STATE, - MHI_DEV_M3_STATE, - MHI_DEV_MAX_STATE, - MHI_DEV_SYSERR_STATE = 0xff -}; - -/* MHI state change event */ -struct mhi_dev_event_ring_state_change { - uint64_t ptr; - uint32_t res1:24; - enum mhi_dev_state mhistate:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t res3:8; -} __packed; - -enum mhi_dev_execenv { - MHI_DEV_SBL_EE = 1, - MHI_DEV_AMSS_EE = 2, - MHI_DEV_UNRESERVED -}; - -/* EE state change event */ -struct mhi_dev_event_ring_ee_state_change { - uint64_t ptr; - uint32_t res1:24; - enum mhi_dev_execenv execenv:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t res3:8; -} __packed; - -/* Generic cmd to parse common details like type and channel id */ -struct mhi_dev_ring_generic { - uint64_t ptr; - uint32_t res1:24; - enum mhi_dev_state mhistate:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -struct mhi_config { - uint32_t mhi_reg_len; - uint32_t version; - uint32_t event_rings; - uint32_t channels; - uint32_t chdb_offset; - uint32_t erdb_offset; -}; - -#define NUM_CHANNELS 128 -#define HW_CHANNEL_BASE 100 -#define HW_CHANNEL_END 107 -#define MHI_ENV_VALUE 2 -#define MHI_MASK_ROWS_CH_EV_DB 4 -#define TRB_MAX_DATA_SIZE 8192 -#define MHI_CTRL_STATE 25 -#define IPA_DMA_SYNC 1 -#define IPA_DMA_ASYNC 0 - -/*maximum trasnfer completion events buffer*/ -#define MAX_TR_EVENTS 50 -/*maximum event requests */ -#define MHI_MAX_EVT_REQ 50 - -/* Possible ring element types */ -union mhi_dev_ring_element_type { - struct mhi_dev_cmd_ring_op cmd_no_op; - struct mhi_dev_cmd_ring_reset_channel_cmd cmd_reset; - struct mhi_dev_cmd_ring_stop_channel_cmd cmd_stop; - struct mhi_dev_cmd_ring_start_channel_cmd cmd_start; - struct mhi_dev_transfer_ring_element cmd_transfer; - struct mhi_dev_event_ring_transfer_completion evt_tr_comp; - struct mhi_dev_event_ring_cmd_completion evt_cmd_comp; - struct mhi_dev_event_ring_state_change evt_state_change; - struct mhi_dev_event_ring_ee_state_change evt_ee_state; - struct mhi_dev_ring_generic generic; -}; - -/* Transfer ring element type */ -union mhi_dev_ring_ctx { - struct mhi_dev_cmd_ctx cmd; - struct mhi_dev_ev_ctx ev; - struct mhi_dev_ch_ctx ch; - struct mhi_dev_gen_ctx generic; -}; - -/* MHI host Control and data address region */ -struct mhi_host_addr { - uint32_t ctrl_base_lsb; - uint32_t ctrl_base_msb; - uint32_t ctrl_limit_lsb; - uint32_t ctrl_limit_msb; - uint32_t data_base_lsb; - uint32_t data_base_msb; - uint32_t data_limit_lsb; - uint32_t data_limit_msb; -}; - -/* MHI physical and virtual address region */ -struct mhi_meminfo { - struct device *dev; - uintptr_t pa_aligned; - uintptr_t pa_unaligned; - uintptr_t va_aligned; - uintptr_t va_unaligned; - uintptr_t size; -}; - -struct mhi_addr { - uint64_t host_pa; - uintptr_t device_pa; - uintptr_t device_va; - size_t size; - dma_addr_t phy_addr; - void *virt_addr; - bool use_ipa_dma; -}; - -struct mhi_interrupt_state { - uint32_t mask; - uint32_t status; -}; - -enum mhi_dev_channel_state { - MHI_DEV_CH_UNINT, - MHI_DEV_CH_STARTED, - MHI_DEV_CH_PENDING_START, - MHI_DEV_CH_PENDING_STOP, - MHI_DEV_CH_STOPPED, - MHI_DEV_CH_CLOSED, -}; - -enum mhi_dev_ch_operation { - MHI_DEV_OPEN_CH, - MHI_DEV_CLOSE_CH, - MHI_DEV_READ_CH, - MHI_DEV_READ_WR, - MHI_DEV_POLL, -}; - -enum mhi_ctrl_info { - MHI_STATE_CONFIGURED = 0, - MHI_STATE_CONNECTED = 1, - MHI_STATE_DISCONNECTED = 2, - MHI_STATE_INVAL, -}; - -enum mhi_dev_tr_compl_evt_type { - SEND_EVENT_BUFFER, - SEND_EVENT_RD_OFFSET, -}; - -enum mhi_dev_transfer_type { - MHI_DEV_DMA_SYNC, - MHI_DEV_DMA_ASYNC, -}; -#endif /* _SDX20_MHI_H_ */ +#ifndef __SDX20_MHI_H +#define __SDX20_MHI_H + +#include + +/* MHI control data structures alloted by the host, including + * channel context array, event context array, command context and rings */ + +/* Channel context state */ +enum mhi_dev_ch_ctx_state { + MHI_DEV_CH_STATE_DISABLED, + MHI_DEV_CH_STATE_ENABLED, + MHI_DEV_CH_STATE_RUNNING, + MHI_DEV_CH_STATE_SUSPENDED, + MHI_DEV_CH_STATE_STOP, + MHI_DEV_CH_STATE_ERROR, + MHI_DEV_CH_STATE_RESERVED, + MHI_DEV_CH_STATE_32BIT = 0x7FFFFFFF +}; + +/* Channel type */ +enum mhi_dev_ch_ctx_type { + MHI_DEV_CH_TYPE_NONE, + MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL, + MHI_DEV_CH_TYPE_INBOUND_CHANNEL, + MHI_DEV_CH_RESERVED +}; + +/* Channel context type */ +struct mhi_dev_ch_ctx { + enum mhi_dev_ch_ctx_state ch_state; + enum mhi_dev_ch_ctx_type ch_type; + uint32_t err_indx; + uint64_t rbase; + uint64_t rlen; + uint64_t rp; + uint64_t wp; +} __packed; + +enum mhi_dev_ring_element_type_id { + MHI_DEV_RING_EL_INVALID = 0, + MHI_DEV_RING_EL_NOOP = 1, + MHI_DEV_RING_EL_TRANSFER = 2, + MHI_DEV_RING_EL_RESET = 16, + MHI_DEV_RING_EL_STOP = 17, + MHI_DEV_RING_EL_START = 18, + MHI_DEV_RING_EL_MHI_STATE_CHG = 32, + MHI_DEV_RING_EL_CMD_COMPLETION_EVT = 33, + MHI_DEV_RING_EL_TRANSFER_COMPLETION_EVENT = 34, + MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY = 64, + MHI_DEV_RING_EL_UNDEF +}; + +enum mhi_dev_ring_state { + RING_STATE_UINT = 0, + RING_STATE_IDLE, + RING_STATE_PENDING, +}; + +enum mhi_dev_ring_type { + RING_TYPE_CMD = 0, + RING_TYPE_ER, + RING_TYPE_CH, + RING_TYPE_INVAL +}; + +/* Event context interrupt moderation */ +enum mhi_dev_evt_ctx_int_mod_timer { + MHI_DEV_EVT_INT_MODERATION_DISABLED +}; + +/* Event ring type */ +enum mhi_dev_evt_ctx_event_ring_type { + MHI_DEV_EVT_TYPE_DEFAULT, + MHI_DEV_EVT_TYPE_VALID, + MHI_DEV_EVT_RESERVED +}; + +/* Event ring context type */ +struct mhi_dev_ev_ctx { + uint32_t res1:16; + enum mhi_dev_evt_ctx_int_mod_timer intmodt:16; + enum mhi_dev_evt_ctx_event_ring_type ertype; + uint32_t msivec; + uint64_t rbase; + uint64_t rlen; + uint64_t rp; + uint64_t wp; +} __packed; + +/* Command context */ +struct mhi_dev_cmd_ctx { + uint32_t res1; + uint32_t res2; + uint32_t res3; + uint64_t rbase; + uint64_t rlen; + uint64_t rp; + uint64_t wp; +} __packed; + +/* generic context */ +struct mhi_dev_gen_ctx { + uint32_t res1; + uint32_t res2; + uint32_t res3; + uint64_t rbase; + uint64_t rlen; + uint64_t rp; + uint64_t wp; +} __packed; + +/* Transfer ring element */ +struct mhi_dev_transfer_ring_element { + uint64_t data_buf_ptr; + uint32_t len:16; + uint32_t res1:16; + uint32_t chain:1; + uint32_t res2:7; + uint32_t ieob:1; + uint32_t ieot:1; + uint32_t bei:1; + uint32_t res3:5; + enum mhi_dev_ring_element_type_id type:8; + uint32_t res4:8; +} __packed; + +/* Command ring element */ +/* Command ring No op command */ +struct mhi_dev_cmd_ring_op { + uint64_t res1; + uint32_t res2; + uint32_t res3:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +/* Command ring reset channel command */ +struct mhi_dev_cmd_ring_reset_channel_cmd { + uint64_t res1; + uint32_t res2; + uint32_t res3:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +/* Command ring stop channel command */ +struct mhi_dev_cmd_ring_stop_channel_cmd { + uint64_t res1; + uint32_t res2; + uint32_t res3:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +/* Command ring start channel command */ +struct mhi_dev_cmd_ring_start_channel_cmd { + uint64_t res1; + uint32_t seqnum; + uint32_t reliable:1; + uint32_t res2:15; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +enum mhi_dev_cmd_completion_code { + MHI_CMD_COMPL_CODE_INVALID = 0, + MHI_CMD_COMPL_CODE_SUCCESS = 1, + MHI_CMD_COMPL_CODE_EOT = 2, + MHI_CMD_COMPL_CODE_OVERFLOW = 3, + MHI_CMD_COMPL_CODE_EOB = 4, + MHI_CMD_COMPL_CODE_UNDEFINED = 16, + MHI_CMD_COMPL_CODE_RING_EL = 17, + MHI_CMD_COMPL_CODE_RES +}; + +/* Event ring elements */ +/* Transfer completion event */ +struct mhi_dev_event_ring_transfer_completion { + uint64_t ptr; + uint32_t len:16; + uint32_t res1:8; + enum mhi_dev_cmd_completion_code code:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +/* Command completion event */ +struct mhi_dev_event_ring_cmd_completion { + uint64_t ptr; + uint32_t res1:24; + enum mhi_dev_cmd_completion_code code:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t res3:8; +} __packed; + +enum mhi_dev_state { + MHI_DEV_RESET_STATE = 0, + MHI_DEV_READY_STATE, + MHI_DEV_M0_STATE, + MHI_DEV_M1_STATE, + MHI_DEV_M2_STATE, + MHI_DEV_M3_STATE, + MHI_DEV_MAX_STATE, + MHI_DEV_SYSERR_STATE = 0xff +}; + +/* MHI state change event */ +struct mhi_dev_event_ring_state_change { + uint64_t ptr; + uint32_t res1:24; + enum mhi_dev_state mhistate:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t res3:8; +} __packed; + +enum mhi_dev_execenv { + MHI_DEV_SBL_EE = 1, + MHI_DEV_AMSS_EE = 2, + MHI_DEV_UNRESERVED +}; + +/* EE state change event */ +struct mhi_dev_event_ring_ee_state_change { + uint64_t ptr; + uint32_t res1:24; + enum mhi_dev_execenv execenv:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t res3:8; +} __packed; + +/* Generic cmd to parse common details like type and channel id */ +struct mhi_dev_ring_generic { + uint64_t ptr; + uint32_t res1:24; + enum mhi_dev_state mhistate:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +struct mhi_config { + uint32_t mhi_reg_len; + uint32_t version; + uint32_t event_rings; + uint32_t channels; + uint32_t chdb_offset; + uint32_t erdb_offset; +}; + +#define NUM_CHANNELS 128 +#define HW_CHANNEL_BASE 100 +#define HW_CHANNEL_END 107 +#define MHI_ENV_VALUE 2 +#define MHI_MASK_ROWS_CH_EV_DB 4 +#define TRB_MAX_DATA_SIZE 8192 +#define MHI_CTRL_STATE 25 +#define IPA_DMA_SYNC 1 +#define IPA_DMA_ASYNC 0 + +/*maximum trasnfer completion events buffer*/ +#define MAX_TR_EVENTS 50 +/*maximum event requests */ +#define MHI_MAX_EVT_REQ 50 + +/* Possible ring element types */ +union mhi_dev_ring_element_type { + struct mhi_dev_cmd_ring_op cmd_no_op; + struct mhi_dev_cmd_ring_reset_channel_cmd cmd_reset; + struct mhi_dev_cmd_ring_stop_channel_cmd cmd_stop; + struct mhi_dev_cmd_ring_start_channel_cmd cmd_start; + struct mhi_dev_transfer_ring_element cmd_transfer; + struct mhi_dev_event_ring_transfer_completion evt_tr_comp; + struct mhi_dev_event_ring_cmd_completion evt_cmd_comp; + struct mhi_dev_event_ring_state_change evt_state_change; + struct mhi_dev_event_ring_ee_state_change evt_ee_state; + struct mhi_dev_ring_generic generic; +}; + +/* Transfer ring element type */ +union mhi_dev_ring_ctx { + struct mhi_dev_cmd_ctx cmd; + struct mhi_dev_ev_ctx ev; + struct mhi_dev_ch_ctx ch; + struct mhi_dev_gen_ctx generic; +}; + +/* MHI host Control and data address region */ +struct mhi_host_addr { + uint32_t ctrl_base_lsb; + uint32_t ctrl_base_msb; + uint32_t ctrl_limit_lsb; + uint32_t ctrl_limit_msb; + uint32_t data_base_lsb; + uint32_t data_base_msb; + uint32_t data_limit_lsb; + uint32_t data_limit_msb; +}; + +/* MHI physical and virtual address region */ +struct mhi_meminfo { + struct device *dev; + uintptr_t pa_aligned; + uintptr_t pa_unaligned; + uintptr_t va_aligned; + uintptr_t va_unaligned; + uintptr_t size; +}; + +struct mhi_addr { + uint64_t host_pa; + uintptr_t device_pa; + uintptr_t device_va; + size_t size; + dma_addr_t phy_addr; + void *virt_addr; + bool use_ipa_dma; +}; + +struct mhi_interrupt_state { + uint32_t mask; + uint32_t status; +}; + +enum mhi_dev_channel_state { + MHI_DEV_CH_UNINT, + MHI_DEV_CH_STARTED, + MHI_DEV_CH_PENDING_START, + MHI_DEV_CH_PENDING_STOP, + MHI_DEV_CH_STOPPED, + MHI_DEV_CH_CLOSED, +}; + +enum mhi_dev_ch_operation { + MHI_DEV_OPEN_CH, + MHI_DEV_CLOSE_CH, + MHI_DEV_READ_CH, + MHI_DEV_READ_WR, + MHI_DEV_POLL, +}; + +enum mhi_ctrl_info { + MHI_STATE_CONFIGURED = 0, + MHI_STATE_CONNECTED = 1, + MHI_STATE_DISCONNECTED = 2, + MHI_STATE_INVAL, +}; + +enum mhi_dev_tr_compl_evt_type { + SEND_EVENT_BUFFER, + SEND_EVENT_RD_OFFSET, +}; + +enum mhi_dev_transfer_type { + MHI_DEV_DMA_SYNC, + MHI_DEV_DMA_ASYNC, +}; +#endif /* _SDX20_MHI_H_ */ diff --git a/quectel_MHI/src/core/sdx20_mhi.h b/quectel_MHI/src/core/sdx20_mhi.h index a7d37839..29c4a3a2 100644 --- a/quectel_MHI/src/core/sdx20_mhi.h +++ b/quectel_MHI/src/core/sdx20_mhi.h @@ -1,426 +1,426 @@ -#ifndef __SDX20_MHI_H -#define __SDX20_MHI_H - -#include - -/* MHI control data structures alloted by the host, including - * channel context array, event context array, command context and rings */ - -/* Channel context state */ -enum mhi_dev_ch_ctx_state { - MHI_DEV_CH_STATE_DISABLED, - MHI_DEV_CH_STATE_ENABLED, - MHI_DEV_CH_STATE_RUNNING, - MHI_DEV_CH_STATE_SUSPENDED, - MHI_DEV_CH_STATE_STOP, - MHI_DEV_CH_STATE_ERROR, - MHI_DEV_CH_STATE_RESERVED, - MHI_DEV_CH_STATE_32BIT = 0x7FFFFFFF -}; - -/* Channel type */ -enum mhi_dev_ch_ctx_type { - MHI_DEV_CH_TYPE_NONE, - MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL, - MHI_DEV_CH_TYPE_INBOUND_CHANNEL, - MHI_DEV_CH_RESERVED -}; - -/* Channel context type */ -struct mhi_dev_ch_ctx { - enum mhi_dev_ch_ctx_state ch_state; - enum mhi_dev_ch_ctx_type ch_type; - uint32_t err_indx; - uint64_t rbase; - uint64_t rlen; - uint64_t rp; - uint64_t wp; -} __packed; - -enum mhi_dev_ring_element_type_id { - MHI_DEV_RING_EL_INVALID = 0, - MHI_DEV_RING_EL_NOOP = 1, - MHI_DEV_RING_EL_TRANSFER = 2, - MHI_DEV_RING_EL_RESET = 16, - MHI_DEV_RING_EL_STOP = 17, - MHI_DEV_RING_EL_START = 18, - MHI_DEV_RING_EL_MHI_STATE_CHG = 32, - MHI_DEV_RING_EL_CMD_COMPLETION_EVT = 33, - MHI_DEV_RING_EL_TRANSFER_COMPLETION_EVENT = 34, - MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY = 64, - MHI_DEV_RING_EL_UNDEF -}; - -enum mhi_dev_ring_state { - RING_STATE_UINT = 0, - RING_STATE_IDLE, - RING_STATE_PENDING, -}; - -enum mhi_dev_ring_type { - RING_TYPE_CMD = 0, - RING_TYPE_ER, - RING_TYPE_CH, - RING_TYPE_INVAL -}; - -/* Event context interrupt moderation */ -enum mhi_dev_evt_ctx_int_mod_timer { - MHI_DEV_EVT_INT_MODERATION_DISABLED -}; - -/* Event ring type */ -enum mhi_dev_evt_ctx_event_ring_type { - MHI_DEV_EVT_TYPE_DEFAULT, - MHI_DEV_EVT_TYPE_VALID, - MHI_DEV_EVT_RESERVED -}; - -/* Event ring context type */ -struct mhi_dev_ev_ctx { - uint32_t res1:16; - enum mhi_dev_evt_ctx_int_mod_timer intmodt:16; - enum mhi_dev_evt_ctx_event_ring_type ertype; - uint32_t msivec; - uint64_t rbase; - uint64_t rlen; - uint64_t rp; - uint64_t wp; -} __packed; - -/* Command context */ -struct mhi_dev_cmd_ctx { - uint32_t res1; - uint32_t res2; - uint32_t res3; - uint64_t rbase; - uint64_t rlen; - uint64_t rp; - uint64_t wp; -} __packed; - -/* generic context */ -struct mhi_dev_gen_ctx { - uint32_t res1; - uint32_t res2; - uint32_t res3; - uint64_t rbase; - uint64_t rlen; - uint64_t rp; - uint64_t wp; -} __packed; - -/* Transfer ring element */ -struct mhi_dev_transfer_ring_element { - uint64_t data_buf_ptr; - uint32_t len:16; - uint32_t res1:16; - uint32_t chain:1; - uint32_t res2:7; - uint32_t ieob:1; - uint32_t ieot:1; - uint32_t bei:1; - uint32_t res3:5; - enum mhi_dev_ring_element_type_id type:8; - uint32_t res4:8; -} __packed; - -/* Command ring element */ -/* Command ring No op command */ -struct mhi_dev_cmd_ring_op { - uint64_t res1; - uint32_t res2; - uint32_t res3:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -/* Command ring reset channel command */ -struct mhi_dev_cmd_ring_reset_channel_cmd { - uint64_t res1; - uint32_t res2; - uint32_t res3:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -/* Command ring stop channel command */ -struct mhi_dev_cmd_ring_stop_channel_cmd { - uint64_t res1; - uint32_t res2; - uint32_t res3:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -/* Command ring start channel command */ -struct mhi_dev_cmd_ring_start_channel_cmd { - uint64_t res1; - uint32_t seqnum; - uint32_t reliable:1; - uint32_t res2:15; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -enum mhi_dev_cmd_completion_code { - MHI_CMD_COMPL_CODE_INVALID = 0, - MHI_CMD_COMPL_CODE_SUCCESS = 1, - MHI_CMD_COMPL_CODE_EOT = 2, - MHI_CMD_COMPL_CODE_OVERFLOW = 3, - MHI_CMD_COMPL_CODE_EOB = 4, - MHI_CMD_COMPL_CODE_UNDEFINED = 16, - MHI_CMD_COMPL_CODE_RING_EL = 17, - MHI_CMD_COMPL_CODE_RES -}; - -/* Event ring elements */ -/* Transfer completion event */ -struct mhi_dev_event_ring_transfer_completion { - uint64_t ptr; - uint32_t len:16; - uint32_t res1:8; - enum mhi_dev_cmd_completion_code code:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -/* Command completion event */ -struct mhi_dev_event_ring_cmd_completion { - uint64_t ptr; - uint32_t res1:24; - enum mhi_dev_cmd_completion_code code:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t res3:8; -} __packed; - -enum mhi_dev_state { - MHI_DEV_RESET_STATE = 0, - MHI_DEV_READY_STATE, - MHI_DEV_M0_STATE, - MHI_DEV_M1_STATE, - MHI_DEV_M2_STATE, - MHI_DEV_M3_STATE, - MHI_DEV_MAX_STATE, - MHI_DEV_SYSERR_STATE = 0xff -}; - -/* MHI state change event */ -struct mhi_dev_event_ring_state_change { - uint64_t ptr; - uint32_t res1:24; - enum mhi_dev_state mhistate:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t res3:8; -} __packed; - -enum mhi_dev_execenv { - MHI_DEV_SBL_EE = 1, - MHI_DEV_AMSS_EE = 2, - MHI_DEV_UNRESERVED -}; - -/* EE state change event */ -struct mhi_dev_event_ring_ee_state_change { - uint64_t ptr; - uint32_t res1:24; - enum mhi_dev_execenv execenv:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t res3:8; -} __packed; - -/* Generic cmd to parse common details like type and channel id */ -struct mhi_dev_ring_generic { - uint64_t ptr; - uint32_t res1:24; - enum mhi_dev_state mhistate:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -struct mhi_config { - uint32_t mhi_reg_len; - uint32_t version; - uint32_t event_rings; - uint32_t channels; - uint32_t chdb_offset; - uint32_t erdb_offset; -}; - -#define NUM_CHANNELS 128 -#define HW_CHANNEL_BASE 100 -#define HW_CHANNEL_END 107 -#define MHI_ENV_VALUE 2 -#define MHI_MASK_ROWS_CH_EV_DB 4 -#define TRB_MAX_DATA_SIZE 8192 -#define MHI_CTRL_STATE 25 -#define IPA_DMA_SYNC 1 -#define IPA_DMA_ASYNC 0 - -/*maximum trasnfer completion events buffer*/ -#define MAX_TR_EVENTS 50 -/*maximum event requests */ -#define MHI_MAX_EVT_REQ 50 - -/* Possible ring element types */ -union mhi_dev_ring_element_type { - struct mhi_dev_cmd_ring_op cmd_no_op; - struct mhi_dev_cmd_ring_reset_channel_cmd cmd_reset; - struct mhi_dev_cmd_ring_stop_channel_cmd cmd_stop; - struct mhi_dev_cmd_ring_start_channel_cmd cmd_start; - struct mhi_dev_transfer_ring_element tre; - struct mhi_dev_event_ring_transfer_completion evt_tr_comp; - struct mhi_dev_event_ring_cmd_completion evt_cmd_comp; - struct mhi_dev_event_ring_state_change evt_state_change; - struct mhi_dev_event_ring_ee_state_change evt_ee_state; - struct mhi_dev_ring_generic generic; -}; - -/* Transfer ring element type */ -union mhi_dev_ring_ctx { - struct mhi_dev_cmd_ctx cmd; - struct mhi_dev_ev_ctx ev; - struct mhi_dev_ch_ctx ch; - struct mhi_dev_gen_ctx generic; -}; - -/* MHI host Control and data address region */ -struct mhi_host_addr { - uint32_t ctrl_base_lsb; - uint32_t ctrl_base_msb; - uint32_t ctrl_limit_lsb; - uint32_t ctrl_limit_msb; - uint32_t data_base_lsb; - uint32_t data_base_msb; - uint32_t data_limit_lsb; - uint32_t data_limit_msb; -}; - -/* MHI physical and virtual address region */ -struct mhi_meminfo { - struct device *dev; - uintptr_t pa_aligned; - uintptr_t pa_unaligned; - uintptr_t va_aligned; - uintptr_t va_unaligned; - uintptr_t size; -}; - -struct mhi_addr { - uint64_t host_pa; - uintptr_t device_pa; - uintptr_t device_va; - size_t size; - dma_addr_t phy_addr; - void *virt_addr; - bool use_ipa_dma; -}; - -struct mhi_interrupt_state { - uint32_t mask; - uint32_t status; -}; - -enum mhi_dev_channel_state { - MHI_DEV_CH_UNINT, - MHI_DEV_CH_STARTED, - MHI_DEV_CH_PENDING_START, - MHI_DEV_CH_PENDING_STOP, - MHI_DEV_CH_STOPPED, - MHI_DEV_CH_CLOSED, -}; - -enum mhi_dev_ch_operation { - MHI_DEV_OPEN_CH, - MHI_DEV_CLOSE_CH, - MHI_DEV_READ_CH, - MHI_DEV_READ_WR, - MHI_DEV_POLL, -}; - -enum mhi_ctrl_info { - MHI_STATE_CONFIGURED = 0, - MHI_STATE_CONNECTED = 1, - MHI_STATE_DISCONNECTED = 2, - MHI_STATE_INVAL, -}; - -enum mhi_dev_tr_compl_evt_type { - SEND_EVENT_BUFFER, - SEND_EVENT_RD_OFFSET, -}; - -enum mhi_dev_transfer_type { - MHI_DEV_DMA_SYNC, - MHI_DEV_DMA_ASYNC, -}; - -#if 0 -/* SW channel client list */ -enum mhi_client_channel { - MHI_CLIENT_LOOPBACK_OUT = 0, - MHI_CLIENT_LOOPBACK_IN = 1, - MHI_CLIENT_SAHARA_OUT = 2, - MHI_CLIENT_SAHARA_IN = 3, - MHI_CLIENT_DIAG_OUT = 4, - MHI_CLIENT_DIAG_IN = 5, - MHI_CLIENT_SSR_OUT = 6, - MHI_CLIENT_SSR_IN = 7, - MHI_CLIENT_QDSS_OUT = 8, - MHI_CLIENT_QDSS_IN = 9, - MHI_CLIENT_EFS_OUT = 10, - MHI_CLIENT_EFS_IN = 11, - MHI_CLIENT_MBIM_OUT = 12, - MHI_CLIENT_MBIM_IN = 13, - MHI_CLIENT_QMI_OUT = 14, - MHI_CLIENT_QMI_IN = 15, - MHI_CLIENT_IP_CTRL_0_OUT = 16, - MHI_CLIENT_IP_CTRL_0_IN = 17, - MHI_CLIENT_IP_CTRL_1_OUT = 18, - MHI_CLIENT_IP_CTRL_1_IN = 19, - MHI_CLIENT_DCI_OUT = 20, - MHI_CLIENT_DCI_IN = 21, - MHI_CLIENT_IP_CTRL_3_OUT = 22, - MHI_CLIENT_IP_CTRL_3_IN = 23, - MHI_CLIENT_IP_CTRL_4_OUT = 24, - MHI_CLIENT_IP_CTRL_4_IN = 25, - MHI_CLIENT_IP_CTRL_5_OUT = 26, - MHI_CLIENT_IP_CTRL_5_IN = 27, - MHI_CLIENT_IP_CTRL_6_OUT = 28, - MHI_CLIENT_IP_CTRL_6_IN = 29, - MHI_CLIENT_IP_CTRL_7_OUT = 30, - MHI_CLIENT_IP_CTRL_7_IN = 31, - MHI_CLIENT_DUN_OUT = 32, - MHI_CLIENT_DUN_IN = 33, - MHI_CLIENT_IP_SW_0_OUT = 34, - MHI_CLIENT_IP_SW_0_IN = 35, - MHI_CLIENT_IP_SW_1_OUT = 36, - MHI_CLIENT_IP_SW_1_IN = 37, - MHI_CLIENT_IP_SW_2_OUT = 38, - MHI_CLIENT_IP_SW_2_IN = 39, - MHI_CLIENT_IP_SW_3_OUT = 40, - MHI_CLIENT_IP_SW_3_IN = 41, - MHI_CLIENT_CSVT_OUT = 42, - MHI_CLIENT_CSVT_IN = 43, - MHI_CLIENT_SMCT_OUT = 44, - MHI_CLIENT_SMCT_IN = 45, - MHI_CLIENT_IP_SW_4_OUT = 46, - MHI_CLIENT_IP_SW_4_IN = 47, - MHI_MAX_SOFTWARE_CHANNELS = 48, - MHI_CLIENT_TEST_OUT = 60, - MHI_CLIENT_TEST_IN = 61, - MHI_CLIENT_RESERVED_1_LOWER = 62, - MHI_CLIENT_RESERVED_1_UPPER = 99, - MHI_CLIENT_IP_HW_0_OUT = 100, - MHI_CLIENT_IP_HW_0_IN = 101, - MHI_CLIENT_RESERVED_2_LOWER = 102, - MHI_CLIENT_RESERVED_2_UPPER = 127, - MHI_MAX_CHANNELS = 102, -}; -#endif -#endif /* _SDX20_MHI_H_ */ +#ifndef __SDX20_MHI_H +#define __SDX20_MHI_H + +#include + +/* MHI control data structures alloted by the host, including + * channel context array, event context array, command context and rings */ + +/* Channel context state */ +enum mhi_dev_ch_ctx_state { + MHI_DEV_CH_STATE_DISABLED, + MHI_DEV_CH_STATE_ENABLED, + MHI_DEV_CH_STATE_RUNNING, + MHI_DEV_CH_STATE_SUSPENDED, + MHI_DEV_CH_STATE_STOP, + MHI_DEV_CH_STATE_ERROR, + MHI_DEV_CH_STATE_RESERVED, + MHI_DEV_CH_STATE_32BIT = 0x7FFFFFFF +}; + +/* Channel type */ +enum mhi_dev_ch_ctx_type { + MHI_DEV_CH_TYPE_NONE, + MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL, + MHI_DEV_CH_TYPE_INBOUND_CHANNEL, + MHI_DEV_CH_RESERVED +}; + +/* Channel context type */ +struct mhi_dev_ch_ctx { + enum mhi_dev_ch_ctx_state ch_state; + enum mhi_dev_ch_ctx_type ch_type; + uint32_t err_indx; + uint64_t rbase; + uint64_t rlen; + uint64_t rp; + uint64_t wp; +} __packed; + +enum mhi_dev_ring_element_type_id { + MHI_DEV_RING_EL_INVALID = 0, + MHI_DEV_RING_EL_NOOP = 1, + MHI_DEV_RING_EL_TRANSFER = 2, + MHI_DEV_RING_EL_RESET = 16, + MHI_DEV_RING_EL_STOP = 17, + MHI_DEV_RING_EL_START = 18, + MHI_DEV_RING_EL_MHI_STATE_CHG = 32, + MHI_DEV_RING_EL_CMD_COMPLETION_EVT = 33, + MHI_DEV_RING_EL_TRANSFER_COMPLETION_EVENT = 34, + MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY = 64, + MHI_DEV_RING_EL_UNDEF +}; + +enum mhi_dev_ring_state { + RING_STATE_UINT = 0, + RING_STATE_IDLE, + RING_STATE_PENDING, +}; + +enum mhi_dev_ring_type { + RING_TYPE_CMD = 0, + RING_TYPE_ER, + RING_TYPE_CH, + RING_TYPE_INVAL +}; + +/* Event context interrupt moderation */ +enum mhi_dev_evt_ctx_int_mod_timer { + MHI_DEV_EVT_INT_MODERATION_DISABLED +}; + +/* Event ring type */ +enum mhi_dev_evt_ctx_event_ring_type { + MHI_DEV_EVT_TYPE_DEFAULT, + MHI_DEV_EVT_TYPE_VALID, + MHI_DEV_EVT_RESERVED +}; + +/* Event ring context type */ +struct mhi_dev_ev_ctx { + uint32_t res1:16; + enum mhi_dev_evt_ctx_int_mod_timer intmodt:16; + enum mhi_dev_evt_ctx_event_ring_type ertype; + uint32_t msivec; + uint64_t rbase; + uint64_t rlen; + uint64_t rp; + uint64_t wp; +} __packed; + +/* Command context */ +struct mhi_dev_cmd_ctx { + uint32_t res1; + uint32_t res2; + uint32_t res3; + uint64_t rbase; + uint64_t rlen; + uint64_t rp; + uint64_t wp; +} __packed; + +/* generic context */ +struct mhi_dev_gen_ctx { + uint32_t res1; + uint32_t res2; + uint32_t res3; + uint64_t rbase; + uint64_t rlen; + uint64_t rp; + uint64_t wp; +} __packed; + +/* Transfer ring element */ +struct mhi_dev_transfer_ring_element { + uint64_t data_buf_ptr; + uint32_t len:16; + uint32_t res1:16; + uint32_t chain:1; + uint32_t res2:7; + uint32_t ieob:1; + uint32_t ieot:1; + uint32_t bei:1; + uint32_t res3:5; + enum mhi_dev_ring_element_type_id type:8; + uint32_t res4:8; +} __packed; + +/* Command ring element */ +/* Command ring No op command */ +struct mhi_dev_cmd_ring_op { + uint64_t res1; + uint32_t res2; + uint32_t res3:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +/* Command ring reset channel command */ +struct mhi_dev_cmd_ring_reset_channel_cmd { + uint64_t res1; + uint32_t res2; + uint32_t res3:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +/* Command ring stop channel command */ +struct mhi_dev_cmd_ring_stop_channel_cmd { + uint64_t res1; + uint32_t res2; + uint32_t res3:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +/* Command ring start channel command */ +struct mhi_dev_cmd_ring_start_channel_cmd { + uint64_t res1; + uint32_t seqnum; + uint32_t reliable:1; + uint32_t res2:15; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +enum mhi_dev_cmd_completion_code { + MHI_CMD_COMPL_CODE_INVALID = 0, + MHI_CMD_COMPL_CODE_SUCCESS = 1, + MHI_CMD_COMPL_CODE_EOT = 2, + MHI_CMD_COMPL_CODE_OVERFLOW = 3, + MHI_CMD_COMPL_CODE_EOB = 4, + MHI_CMD_COMPL_CODE_UNDEFINED = 16, + MHI_CMD_COMPL_CODE_RING_EL = 17, + MHI_CMD_COMPL_CODE_RES +}; + +/* Event ring elements */ +/* Transfer completion event */ +struct mhi_dev_event_ring_transfer_completion { + uint64_t ptr; + uint32_t len:16; + uint32_t res1:8; + enum mhi_dev_cmd_completion_code code:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +/* Command completion event */ +struct mhi_dev_event_ring_cmd_completion { + uint64_t ptr; + uint32_t res1:24; + enum mhi_dev_cmd_completion_code code:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t res3:8; +} __packed; + +enum mhi_dev_state { + MHI_DEV_RESET_STATE = 0, + MHI_DEV_READY_STATE, + MHI_DEV_M0_STATE, + MHI_DEV_M1_STATE, + MHI_DEV_M2_STATE, + MHI_DEV_M3_STATE, + MHI_DEV_MAX_STATE, + MHI_DEV_SYSERR_STATE = 0xff +}; + +/* MHI state change event */ +struct mhi_dev_event_ring_state_change { + uint64_t ptr; + uint32_t res1:24; + enum mhi_dev_state mhistate:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t res3:8; +} __packed; + +enum mhi_dev_execenv { + MHI_DEV_SBL_EE = 1, + MHI_DEV_AMSS_EE = 2, + MHI_DEV_UNRESERVED +}; + +/* EE state change event */ +struct mhi_dev_event_ring_ee_state_change { + uint64_t ptr; + uint32_t res1:24; + enum mhi_dev_execenv execenv:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t res3:8; +} __packed; + +/* Generic cmd to parse common details like type and channel id */ +struct mhi_dev_ring_generic { + uint64_t ptr; + uint32_t res1:24; + enum mhi_dev_state mhistate:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +struct mhi_config { + uint32_t mhi_reg_len; + uint32_t version; + uint32_t event_rings; + uint32_t channels; + uint32_t chdb_offset; + uint32_t erdb_offset; +}; + +#define NUM_CHANNELS 128 +#define HW_CHANNEL_BASE 100 +#define HW_CHANNEL_END 107 +#define MHI_ENV_VALUE 2 +#define MHI_MASK_ROWS_CH_EV_DB 4 +#define TRB_MAX_DATA_SIZE 8192 +#define MHI_CTRL_STATE 25 +#define IPA_DMA_SYNC 1 +#define IPA_DMA_ASYNC 0 + +/*maximum trasnfer completion events buffer*/ +#define MAX_TR_EVENTS 50 +/*maximum event requests */ +#define MHI_MAX_EVT_REQ 50 + +/* Possible ring element types */ +union mhi_dev_ring_element_type { + struct mhi_dev_cmd_ring_op cmd_no_op; + struct mhi_dev_cmd_ring_reset_channel_cmd cmd_reset; + struct mhi_dev_cmd_ring_stop_channel_cmd cmd_stop; + struct mhi_dev_cmd_ring_start_channel_cmd cmd_start; + struct mhi_dev_transfer_ring_element tre; + struct mhi_dev_event_ring_transfer_completion evt_tr_comp; + struct mhi_dev_event_ring_cmd_completion evt_cmd_comp; + struct mhi_dev_event_ring_state_change evt_state_change; + struct mhi_dev_event_ring_ee_state_change evt_ee_state; + struct mhi_dev_ring_generic generic; +}; + +/* Transfer ring element type */ +union mhi_dev_ring_ctx { + struct mhi_dev_cmd_ctx cmd; + struct mhi_dev_ev_ctx ev; + struct mhi_dev_ch_ctx ch; + struct mhi_dev_gen_ctx generic; +}; + +/* MHI host Control and data address region */ +struct mhi_host_addr { + uint32_t ctrl_base_lsb; + uint32_t ctrl_base_msb; + uint32_t ctrl_limit_lsb; + uint32_t ctrl_limit_msb; + uint32_t data_base_lsb; + uint32_t data_base_msb; + uint32_t data_limit_lsb; + uint32_t data_limit_msb; +}; + +/* MHI physical and virtual address region */ +struct mhi_meminfo { + struct device *dev; + uintptr_t pa_aligned; + uintptr_t pa_unaligned; + uintptr_t va_aligned; + uintptr_t va_unaligned; + uintptr_t size; +}; + +struct mhi_addr { + uint64_t host_pa; + uintptr_t device_pa; + uintptr_t device_va; + size_t size; + dma_addr_t phy_addr; + void *virt_addr; + bool use_ipa_dma; +}; + +struct mhi_interrupt_state { + uint32_t mask; + uint32_t status; +}; + +enum mhi_dev_channel_state { + MHI_DEV_CH_UNINT, + MHI_DEV_CH_STARTED, + MHI_DEV_CH_PENDING_START, + MHI_DEV_CH_PENDING_STOP, + MHI_DEV_CH_STOPPED, + MHI_DEV_CH_CLOSED, +}; + +enum mhi_dev_ch_operation { + MHI_DEV_OPEN_CH, + MHI_DEV_CLOSE_CH, + MHI_DEV_READ_CH, + MHI_DEV_READ_WR, + MHI_DEV_POLL, +}; + +enum mhi_ctrl_info { + MHI_STATE_CONFIGURED = 0, + MHI_STATE_CONNECTED = 1, + MHI_STATE_DISCONNECTED = 2, + MHI_STATE_INVAL, +}; + +enum mhi_dev_tr_compl_evt_type { + SEND_EVENT_BUFFER, + SEND_EVENT_RD_OFFSET, +}; + +enum mhi_dev_transfer_type { + MHI_DEV_DMA_SYNC, + MHI_DEV_DMA_ASYNC, +}; + +#if 0 +/* SW channel client list */ +enum mhi_client_channel { + MHI_CLIENT_LOOPBACK_OUT = 0, + MHI_CLIENT_LOOPBACK_IN = 1, + MHI_CLIENT_SAHARA_OUT = 2, + MHI_CLIENT_SAHARA_IN = 3, + MHI_CLIENT_DIAG_OUT = 4, + MHI_CLIENT_DIAG_IN = 5, + MHI_CLIENT_SSR_OUT = 6, + MHI_CLIENT_SSR_IN = 7, + MHI_CLIENT_QDSS_OUT = 8, + MHI_CLIENT_QDSS_IN = 9, + MHI_CLIENT_EFS_OUT = 10, + MHI_CLIENT_EFS_IN = 11, + MHI_CLIENT_MBIM_OUT = 12, + MHI_CLIENT_MBIM_IN = 13, + MHI_CLIENT_QMI_OUT = 14, + MHI_CLIENT_QMI_IN = 15, + MHI_CLIENT_IP_CTRL_0_OUT = 16, + MHI_CLIENT_IP_CTRL_0_IN = 17, + MHI_CLIENT_IP_CTRL_1_OUT = 18, + MHI_CLIENT_IP_CTRL_1_IN = 19, + MHI_CLIENT_DCI_OUT = 20, + MHI_CLIENT_DCI_IN = 21, + MHI_CLIENT_IP_CTRL_3_OUT = 22, + MHI_CLIENT_IP_CTRL_3_IN = 23, + MHI_CLIENT_IP_CTRL_4_OUT = 24, + MHI_CLIENT_IP_CTRL_4_IN = 25, + MHI_CLIENT_IP_CTRL_5_OUT = 26, + MHI_CLIENT_IP_CTRL_5_IN = 27, + MHI_CLIENT_IP_CTRL_6_OUT = 28, + MHI_CLIENT_IP_CTRL_6_IN = 29, + MHI_CLIENT_IP_CTRL_7_OUT = 30, + MHI_CLIENT_IP_CTRL_7_IN = 31, + MHI_CLIENT_DUN_OUT = 32, + MHI_CLIENT_DUN_IN = 33, + MHI_CLIENT_IP_SW_0_OUT = 34, + MHI_CLIENT_IP_SW_0_IN = 35, + MHI_CLIENT_IP_SW_1_OUT = 36, + MHI_CLIENT_IP_SW_1_IN = 37, + MHI_CLIENT_IP_SW_2_OUT = 38, + MHI_CLIENT_IP_SW_2_IN = 39, + MHI_CLIENT_IP_SW_3_OUT = 40, + MHI_CLIENT_IP_SW_3_IN = 41, + MHI_CLIENT_CSVT_OUT = 42, + MHI_CLIENT_CSVT_IN = 43, + MHI_CLIENT_SMCT_OUT = 44, + MHI_CLIENT_SMCT_IN = 45, + MHI_CLIENT_IP_SW_4_OUT = 46, + MHI_CLIENT_IP_SW_4_IN = 47, + MHI_MAX_SOFTWARE_CHANNELS = 48, + MHI_CLIENT_TEST_OUT = 60, + MHI_CLIENT_TEST_IN = 61, + MHI_CLIENT_RESERVED_1_LOWER = 62, + MHI_CLIENT_RESERVED_1_UPPER = 99, + MHI_CLIENT_IP_HW_0_OUT = 100, + MHI_CLIENT_IP_HW_0_IN = 101, + MHI_CLIENT_RESERVED_2_LOWER = 102, + MHI_CLIENT_RESERVED_2_UPPER = 127, + MHI_MAX_CHANNELS = 102, +}; +#endif +#endif /* _SDX20_MHI_H_ */ diff --git a/quectel_MHI/src/devices/mhi_netdev.c b/quectel_MHI/src/devices/mhi_netdev.c index 1d3a4317..ed7b24ba 100644 --- a/quectel_MHI/src/devices/mhi_netdev.c +++ b/quectel_MHI/src/devices/mhi_netdev.c @@ -559,14 +559,9 @@ static int mhi_netdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static void mhi_netdev_get_drvinfo (struct net_device *ndev, struct ethtool_drvinfo *info) { //struct mhi_netdev *mhi_netdev = ndev_to_mhi(ndev); - /* strlcpy() is deprecated in kernel 6.8.0+, using strscpy instead */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(6,8,0)) - strlcpy(info->driver, "pcie_mhi", sizeof(info->driver)); - strlcpy(info->version, PCIE_MHI_DRIVER_VERSION, sizeof(info->version)); -#else - strscpy(info->driver, "pcie_mhi", sizeof(info->driver)); - strscpy(info->version, PCIE_MHI_DRIVER_VERSION, sizeof(info->version)); -#endif + + strlcpy (info->driver, "pcie_mhi", sizeof info->driver); + strlcpy (info->version, PCIE_MHI_DRIVER_VERSION, sizeof info->version); } static const struct ethtool_ops mhi_netdev_ethtool_ops = { diff --git a/quectel_MHI/src/devices/mhi_netdev_quectel.c b/quectel_MHI/src/devices/mhi_netdev_quectel.c index e0ce5cfe..f38742ff 100644 --- a/quectel_MHI/src/devices/mhi_netdev_quectel.c +++ b/quectel_MHI/src/devices/mhi_netdev_quectel.c @@ -63,8 +63,8 @@ struct rmnet_nss_cb { int (*nss_tx)(struct sk_buff *skb); }; static struct rmnet_nss_cb __read_mostly *nss_cb = NULL; -#if defined(CONFIG_PINCTRL_IPQ807x) || defined(CONFIG_PINCTRL_IPQ5018) -#ifdef CONFIG_RMNET_DATA +#if defined(CONFIG_PINCTRL_IPQ807x) || defined(CONFIG_PINCTRL_IPQ5018) || defined(CONFIG_PINCTRL_IPQ8074) +//#ifdef CONFIG_RMNET_DATA //spf12.x have no macro defined, just for spf11.x #define CONFIG_QCA_NSS_DRV #define CONFIG_USE_RMNET_DATA_FOR_SKIP_MEMCPY /* define at qca/src/linux-4.4/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c */ //for spf11.x @@ -72,9 +72,9 @@ static struct rmnet_nss_cb __read_mostly *nss_cb = NULL; /* set at qsdk/qca/src/data-kernel/drivers/rmnet-nss/rmnet_nss.c */ /* need add DEPENDS:= kmod-rmnet-core in feeds/makefile */ extern struct rmnet_nss_cb *rmnet_nss_callbacks __rcu __read_mostly; +//#endif #endif -#endif - + int mhi_netdev_use_xfer_type_dma(unsigned chan) { @@ -2589,14 +2589,9 @@ static const struct net_device_ops mhi_netdev_ops_ip = { static void mhi_netdev_get_drvinfo (struct net_device *ndev, struct ethtool_drvinfo *info) { //struct mhi_netdev *mhi_netdev = ndev_to_mhi(ndev); - /* strlcpy() is deprecated in kernel 6.8.0+, using strscpy instead */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(6,8,0)) - strlcpy(info->driver, "pcie_mhi", sizeof(info->driver)); - strlcpy(info->version, PCIE_MHI_DRIVER_VERSION, sizeof(info->version)); -#else - strscpy(info->driver, "pcie_mhi", sizeof(info->driver)); - strscpy(info->version, PCIE_MHI_DRIVER_VERSION, sizeof(info->version)); -#endif + + strscpy (info->driver, "pcie_mhi", sizeof info->driver); + strscpy (info->version, PCIE_MHI_DRIVER_VERSION, sizeof info->version); } static const struct ethtool_ops mhi_netdev_ethtool_ops = { diff --git a/quectel_MHI/src/log/AT_OVER_PCIE.txt b/quectel_MHI/src/log/AT_OVER_PCIE.txt index 9f86ac32..bc485047 100644 --- a/quectel_MHI/src/log/AT_OVER_PCIE.txt +++ b/quectel_MHI/src/log/AT_OVER_PCIE.txt @@ -1,31 +1,31 @@ -root@imx6qsabresd:~# busybox microcom /dev/mhi_DUN -[ 384.652992] [I][mhi_uci_open] Node open, ref counts 1 -[ 384.658144] [I][mhi_uci_open] Starting channel -[ 384.662612] [I][__mhi_prepare_channel] Entered: preparing channel:32 -[ 384.680397] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 384.685890] [I][__mhi_prepare_channel] Chan:32 successfully moved to start state -[ 384.693312] [I][__mhi_prepare_channel] Entered: preparing channel:33 -[ 384.708692] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 384.714324] [I][__mhi_prepare_channel] Chan:33 successfully moved to start state - -RDY - -+CFUN: 1 - -+CPIN: READY - -+QUSIM: 1 - -+QIND: SMS DONE - -+QIND: PB DONE -ati -Quectel -EM20 -Revision: EM20GR01A01M4G - -OK -at+cpin? -+CPIN: READY - -OK +root@imx6qsabresd:~# busybox microcom /dev/mhi_DUN +[ 384.652992] [I][mhi_uci_open] Node open, ref counts 1 +[ 384.658144] [I][mhi_uci_open] Starting channel +[ 384.662612] [I][__mhi_prepare_channel] Entered: preparing channel:32 +[ 384.680397] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 384.685890] [I][__mhi_prepare_channel] Chan:32 successfully moved to start state +[ 384.693312] [I][__mhi_prepare_channel] Entered: preparing channel:33 +[ 384.708692] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 384.714324] [I][__mhi_prepare_channel] Chan:33 successfully moved to start state + +RDY + ++CFUN: 1 + ++CPIN: READY + ++QUSIM: 1 + ++QIND: SMS DONE + ++QIND: PB DONE +ati +Quectel +EM20 +Revision: EM20GR01A01M4G + +OK +at+cpin? ++CPIN: READY + +OK diff --git a/quectel_MHI/src/log/MBIM_OVER_PCIE.txt b/quectel_MHI/src/log/MBIM_OVER_PCIE.txt index a91b7387..927a9b2a 100644 --- a/quectel_MHI/src/log/MBIM_OVER_PCIE.txt +++ b/quectel_MHI/src/log/MBIM_OVER_PCIE.txt @@ -1,145 +1,145 @@ -root@OpenWrt:~# insmod pcie_mhi.ko mhi_mbim_enabled=1 -root@OpenWrt:~# dmesg | grep mhi -[ 65.587160] mhi_init Quectel_Linux_PCIE_MHI_Driver_V1.3.0.6 -[ 65.597089] mhi_pci_probe pci_dev->name = 0000:01:00.0, domain=0, bus=1, slot=0, vendor=17CB, device=0306 -[ 65.602250] mhi_q 0000:01:00.0: BAR 0: assigned [mem 0x20300000-0x20300fff 64bit] -[ 65.611690] mhi_q 0000:01:00.0: enabling device (0140 -> 0142) -[ 65.619307] [I][mhi_init_pci_dev] msi_required = 5, msi_allocated = 5, msi_irq = 63 -[ 65.619327] [I][mhi_power_up] dev_state:RESET -[ 65.619331] [I][mhi_async_power_up] Requested to power on -[ 65.619449] [I][mhi_alloc_coherent] size = 114688, dma_handle = 6fca0000 -[ 65.619462] [I][mhi_init_dev_ctxt] mhi_ctxt->ctrl_seg = c221e000 -[ 65.619731] [I][mhi_async_power_up] dev_state:RESET ee:AMSS -[ 65.619747] [I][mhi_pm_st_worker] Transition to state:READY -[ 65.619760] [I][mhi_pm_st_worker] INVALID_EE -> AMSS -[ 65.619764] [I][mhi_ready_state_transition] Waiting to enter READY state -[ 65.619885] [I][mhi_async_power_up] Power on setup success -[ 65.619897] [I][mhi_pci_probe] Return successful -[ 65.665114] [I][mhi_ready_state_transition] Device in READY State -[ 65.665125] [I][mhi_intvec_threaded_handlr] device ee:AMSS dev_state:READY, pm_state:POR -[ 65.665131] [I][mhi_intvec_threaded_handlr] device ee:AMSS dev_state:READY, INVALID_EE -[ 65.665133] [I][mhi_tryset_pm_state] Transition to pm state from:POR to:POR -[ 65.665137] [I][mhi_init_mmio] Initializing MMIO -[ 65.665142] [I][mhi_init_mmio] CHDBOFF:0x300 -[ 65.665151] [I][mhi_init_mmio] ERDBOFF:0x700 -[ 65.665156] [I][mhi_init_mmio] Programming all MMIO values. -[ 65.786283] [I][mhi_dump_tre] carl_ev evt_state_change mhistate=2 -[ 65.786289] [I][mhi_process_ctrl_ev_ring] MHI state change event to state:M0 -[ 65.786295] [I][mhi_pm_m0_transition] Entered With State:READY PM_STATE:POR -[ 65.786300] [I][mhi_tryset_pm_state] Transition to pm state from:POR to:M0 -[ 65.789734] [I][mhi_dump_tre] carl_ev evt_ee_state execenv=2 -[ 65.789739] [I][mhi_process_ctrl_ev_ring] MHI EE received event:AMSS -[ 65.789756] [I][mhi_pm_st_worker] Transition to state:MISSION MODE -[ 65.789767] [I][mhi_pm_st_worker] INVALID_EE -> AMSS -[ 65.789771] [I][mhi_pm_mission_mode_transition] Processing Mission Mode Transition -[ 65.789787] [I][mhi_init_timesync] No timesync capability found -[ 65.789791] [I][mhi_pm_mission_mode_transition] Adding new devices -[ 65.790570] [I][mhi_dtr_probe] Enter for DTR control channel -[ 65.790577] [I][__mhi_prepare_channel] Entered: preparing channel:18 -[ 65.797036] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 65.797051] [I][__mhi_prepare_channel] Chan:18 successfully moved to start state -[ 65.797055] [I][__mhi_prepare_channel] Entered: preparing channel:19 -[ 65.802457] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 65.802469] [I][__mhi_prepare_channel] Chan:19 successfully moved to start state -[ 65.802485] [I][mhi_dtr_probe] Exit with ret:0 -[ 65.802748] [I][mhi_netdev_enable_iface] Prepare the channels for transfer -[ 65.802772] [I][__mhi_prepare_channel] Entered: preparing channel:100 -[ 65.825279] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 65.825293] [I][__mhi_prepare_channel] Chan:100 successfully moved to start state -[ 65.825297] [I][__mhi_prepare_channel] Entered: preparing channel:101 -[ 65.835565] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 65.835578] [I][__mhi_prepare_channel] Chan:101 successfully moved to start state -[ 65.839141] [I][mhi_netdev_enable_iface] Exited. -[ 65.839875] rmnet_vnd_register_device(rmnet_mhi0.1)=0 -[ 65.843278] net rmnet_mhi0 rmnet_mhi0.1: NSS context created -[ 65.861808] [I][mhi_pm_mission_mode_transition] Exit with ret:0 -[ 68.625595] [I][__mhi_prepare_channel] Entered: preparing channel:12 -[ 68.634610] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 68.634622] [I][__mhi_prepare_channel] Chan:12 successfully moved to start state -[ 68.634625] [I][__mhi_prepare_channel] Entered: preparing channel:13 -[ 68.644978] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 68.644987] [I][__mhi_prepare_channel] Chan:13 successfully moved to start state -[ 69.170666] net rmnet_mhi0: link_state 0x0 -> 0x1 -[ 69.177035] [I][mhi_netdev_open] Opened net dev interface -[ 71.655431] [I][mhi_netdev_open] Opened net dev interface - -root@OpenWrt:~# ./quectel-CM & -[04-02_04:14:12:134] Quectel_QConnectManager_Linux_V1.6.0.5 -[04-02_04:14:12:134] Find /sys/bus/usb/devices/4-1 idVendor=0x2c7c idProduct=0x800, bus=0x004, dev=0x002 -[04-02_04:14:12:135] network interface '' or qmidev '' is not exist -[04-02_04:14:12:135] netcard driver = pcie_mhi, driver version = V1.3.0.6 -[04-02_04:14:12:135] Modem works in MBIM mode -[04-02_04:14:12:135] apn (null), user (null), passwd (null), auth 0 -[04-02_04:14:12:135] IP Proto MBIMContextIPTypeIPv4 -[04-02_04:14:12:154] mbim_read_thread is created -sh: can't create /sys/class/net/rmnet_mhi0/mbim/link_state: nonexistent directory -[04-02_04:14:12:156] system(echo 0 > /sys/class/net/rmnet_mhi0/mbim/link_state)=256 -[04-02_04:14:12:185] system(ip address flush dev rmnet_mhi0)=0 -[04-02_04:14:12:187] system(ip link set dev rmnet_mhi0 down)=0 -[04-02_04:14:12:188] mbim_open_device() -[04-02_04:14:12:605] mbim_device_caps_query() -[04-02_04:14:12:610] DeviceId: 869710030002905 -[04-02_04:14:12:610] HardwareInfo: 0 -[04-02_04:14:12:610] mbim_set_radio_state( 1 ) -[04-02_04:14:12:613] HwRadioState: 1, SwRadioState: 1 -[04-02_04:14:12:613] mbim_subscriber_status_query() -[04-02_04:14:12:620] SubscriberReadyState NotInitialized -> Initialized -[04-02_04:14:12:620] mbim_register_state_query() -[04-02_04:14:12:625] RegisterState Unknown -> Home -[04-02_04:14:12:625] mbim_packet_service_query() -[04-02_04:14:12:629] PacketServiceState Unknown -> Attached -[04-02_04:14:12:629] mbim_query_connect(sessionID=0) -[04-02_04:14:12:633] ActivationState Unknown -> Deactivated -[04-02_04:14:12:633] mbim_set_connect(onoff=1, sessionID=0) -[ 69.170666] net rmnet_mhi0: link_state 0x0 -> 0x1 -[04-02_04:14:12:680] ActivationState Deactivated -> Activated -[ 69.177035] [I][mhi_netdev_open] Opened net dev interface -[04-02_04:14:12:680] mbim_ip_config(sessionID=0) -[04-02_04:14:12:683] < SessionId = 0 -[04-02_04:14:12:683] < IPv4ConfigurationAvailable = 0xf -[04-02_04:14:12:683] < IPv6ConfigurationAvailable = 0x0 -[04-02_04:14:12:683] < IPv4AddressCount = 0x1 -[04-02_04:14:12:683] < IPv4AddressOffset = 0x3c -[04-02_04:14:12:683] < IPv6AddressCount = 0x0 -[04-02_04:14:12:683] < IPv6AddressOffset = 0x0 -[04-02_04:14:12:683] < IPv4 = 10.129.59.93/30 -[04-02_04:14:12:683] < gw = 10.129.59.94 -[04-02_04:14:12:683] < dns1 = 211.138.180.2 -[04-02_04:14:12:683] < dns2 = 211.138.180.3 -[04-02_04:14:12:683] < ipv4 mtu = 1500 -sh: can't create /sys/class/net/rmnet_mhi0/mbim/link_state: nonexistent directory -[04-02_04:14:12:684] system(echo 1 > /sys/class/net/rmnet_mhi0/mbim/link_state)=256 -[04-02_04:14:12:689] system(ip link set dev rmnet_mhi0 up)=0 -[04-02_04:14:12:692] system(ip -4 address flush dev rmnet_mhi0)=0 -[04-02_04:14:12:694] system(ip -4 address add 10.129.59.93/30 dev rmnet_mhi0)=0 -[04-02_04:14:12:697] system(ip -4 route add default via 10.129.59.94 dev rmnet_mhi0)=0 -[04-02_04:14:12:699] system(ip -4 link set dev rmnet_mhi0 mtu 1500)=0 - -root@OpenWrt:~# ifconfig rmnet_mhi0 -rmnet_mhi0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 - UP RUNNING NOARP MTU:1500 Metric:1 - RX packets:99379 errors:0 dropped:0 overruns:0 frame:0 - TX packets:176569 errors:0 dropped:0 overruns:0 carrier:0 - collisions:0 txqueuelen:1000 - RX bytes:1528181052 (1.4 GiB) TX bytes:62467192 (59.5 MiB) - -root@OpenWrt:~# ifconfig rmnet_mhi0.1 -rmnet_mhi0.1 Link encap:UNSPEC HWaddr 02-50-F4-00-00-00-00-00-00-00-00-00-00-00-00-00 - inet addr:10.129.59.93 Mask:255.255.255.252 - inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link - UP RUNNING NOARP MTU:1500 Metric:1 - RX packets:1089360 errors:0 dropped:0 overruns:0 frame:0 - TX packets:176581 errors:0 dropped:0 overruns:0 carrier:0 - collisions:0 txqueuelen:1000 - RX bytes:1521449058 (1.4 GiB) TX bytes:57525792 (54.8 MiB) - -# adjust CPU load balancing -root@OpenWrt:~# echo 2 > /sys/class/net/rmnet_mhi0/queues/rx-0/rps_cpus -root@OpenWrt:~# echo 4 > /sys/class/net/rmnet_mhi0.1/queues/rx-0/rps_cpus -root@OpenWrt:~# echo 2000 > /proc/sys/net/core/netdev_max_backlog -root@OpenWrt:~# cat /sys/class/net/rmnet_mhi0/queues/rx-0/rps_cpus -2 -root@OpenWrt:~# cat /sys/class/net/rmnet_mhi0.1/queues/rx-0/rps_cpus -4 -root@OpenWrt:~# cat /proc/sys/net/core/netdev_max_backlog -2000 +root@OpenWrt:~# insmod pcie_mhi.ko mhi_mbim_enabled=1 +root@OpenWrt:~# dmesg | grep mhi +[ 65.587160] mhi_init Quectel_Linux_PCIE_MHI_Driver_V1.3.0.6 +[ 65.597089] mhi_pci_probe pci_dev->name = 0000:01:00.0, domain=0, bus=1, slot=0, vendor=17CB, device=0306 +[ 65.602250] mhi_q 0000:01:00.0: BAR 0: assigned [mem 0x20300000-0x20300fff 64bit] +[ 65.611690] mhi_q 0000:01:00.0: enabling device (0140 -> 0142) +[ 65.619307] [I][mhi_init_pci_dev] msi_required = 5, msi_allocated = 5, msi_irq = 63 +[ 65.619327] [I][mhi_power_up] dev_state:RESET +[ 65.619331] [I][mhi_async_power_up] Requested to power on +[ 65.619449] [I][mhi_alloc_coherent] size = 114688, dma_handle = 6fca0000 +[ 65.619462] [I][mhi_init_dev_ctxt] mhi_ctxt->ctrl_seg = c221e000 +[ 65.619731] [I][mhi_async_power_up] dev_state:RESET ee:AMSS +[ 65.619747] [I][mhi_pm_st_worker] Transition to state:READY +[ 65.619760] [I][mhi_pm_st_worker] INVALID_EE -> AMSS +[ 65.619764] [I][mhi_ready_state_transition] Waiting to enter READY state +[ 65.619885] [I][mhi_async_power_up] Power on setup success +[ 65.619897] [I][mhi_pci_probe] Return successful +[ 65.665114] [I][mhi_ready_state_transition] Device in READY State +[ 65.665125] [I][mhi_intvec_threaded_handlr] device ee:AMSS dev_state:READY, pm_state:POR +[ 65.665131] [I][mhi_intvec_threaded_handlr] device ee:AMSS dev_state:READY, INVALID_EE +[ 65.665133] [I][mhi_tryset_pm_state] Transition to pm state from:POR to:POR +[ 65.665137] [I][mhi_init_mmio] Initializing MMIO +[ 65.665142] [I][mhi_init_mmio] CHDBOFF:0x300 +[ 65.665151] [I][mhi_init_mmio] ERDBOFF:0x700 +[ 65.665156] [I][mhi_init_mmio] Programming all MMIO values. +[ 65.786283] [I][mhi_dump_tre] carl_ev evt_state_change mhistate=2 +[ 65.786289] [I][mhi_process_ctrl_ev_ring] MHI state change event to state:M0 +[ 65.786295] [I][mhi_pm_m0_transition] Entered With State:READY PM_STATE:POR +[ 65.786300] [I][mhi_tryset_pm_state] Transition to pm state from:POR to:M0 +[ 65.789734] [I][mhi_dump_tre] carl_ev evt_ee_state execenv=2 +[ 65.789739] [I][mhi_process_ctrl_ev_ring] MHI EE received event:AMSS +[ 65.789756] [I][mhi_pm_st_worker] Transition to state:MISSION MODE +[ 65.789767] [I][mhi_pm_st_worker] INVALID_EE -> AMSS +[ 65.789771] [I][mhi_pm_mission_mode_transition] Processing Mission Mode Transition +[ 65.789787] [I][mhi_init_timesync] No timesync capability found +[ 65.789791] [I][mhi_pm_mission_mode_transition] Adding new devices +[ 65.790570] [I][mhi_dtr_probe] Enter for DTR control channel +[ 65.790577] [I][__mhi_prepare_channel] Entered: preparing channel:18 +[ 65.797036] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 65.797051] [I][__mhi_prepare_channel] Chan:18 successfully moved to start state +[ 65.797055] [I][__mhi_prepare_channel] Entered: preparing channel:19 +[ 65.802457] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 65.802469] [I][__mhi_prepare_channel] Chan:19 successfully moved to start state +[ 65.802485] [I][mhi_dtr_probe] Exit with ret:0 +[ 65.802748] [I][mhi_netdev_enable_iface] Prepare the channels for transfer +[ 65.802772] [I][__mhi_prepare_channel] Entered: preparing channel:100 +[ 65.825279] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 65.825293] [I][__mhi_prepare_channel] Chan:100 successfully moved to start state +[ 65.825297] [I][__mhi_prepare_channel] Entered: preparing channel:101 +[ 65.835565] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 65.835578] [I][__mhi_prepare_channel] Chan:101 successfully moved to start state +[ 65.839141] [I][mhi_netdev_enable_iface] Exited. +[ 65.839875] rmnet_vnd_register_device(rmnet_mhi0.1)=0 +[ 65.843278] net rmnet_mhi0 rmnet_mhi0.1: NSS context created +[ 65.861808] [I][mhi_pm_mission_mode_transition] Exit with ret:0 +[ 68.625595] [I][__mhi_prepare_channel] Entered: preparing channel:12 +[ 68.634610] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 68.634622] [I][__mhi_prepare_channel] Chan:12 successfully moved to start state +[ 68.634625] [I][__mhi_prepare_channel] Entered: preparing channel:13 +[ 68.644978] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 68.644987] [I][__mhi_prepare_channel] Chan:13 successfully moved to start state +[ 69.170666] net rmnet_mhi0: link_state 0x0 -> 0x1 +[ 69.177035] [I][mhi_netdev_open] Opened net dev interface +[ 71.655431] [I][mhi_netdev_open] Opened net dev interface + +root@OpenWrt:~# ./quectel-CM & +[04-02_04:14:12:134] Quectel_QConnectManager_Linux_V1.6.0.5 +[04-02_04:14:12:134] Find /sys/bus/usb/devices/4-1 idVendor=0x2c7c idProduct=0x800, bus=0x004, dev=0x002 +[04-02_04:14:12:135] network interface '' or qmidev '' is not exist +[04-02_04:14:12:135] netcard driver = pcie_mhi, driver version = V1.3.0.6 +[04-02_04:14:12:135] Modem works in MBIM mode +[04-02_04:14:12:135] apn (null), user (null), passwd (null), auth 0 +[04-02_04:14:12:135] IP Proto MBIMContextIPTypeIPv4 +[04-02_04:14:12:154] mbim_read_thread is created +sh: can't create /sys/class/net/rmnet_mhi0/mbim/link_state: nonexistent directory +[04-02_04:14:12:156] system(echo 0 > /sys/class/net/rmnet_mhi0/mbim/link_state)=256 +[04-02_04:14:12:185] system(ip address flush dev rmnet_mhi0)=0 +[04-02_04:14:12:187] system(ip link set dev rmnet_mhi0 down)=0 +[04-02_04:14:12:188] mbim_open_device() +[04-02_04:14:12:605] mbim_device_caps_query() +[04-02_04:14:12:610] DeviceId: 869710030002905 +[04-02_04:14:12:610] HardwareInfo: 0 +[04-02_04:14:12:610] mbim_set_radio_state( 1 ) +[04-02_04:14:12:613] HwRadioState: 1, SwRadioState: 1 +[04-02_04:14:12:613] mbim_subscriber_status_query() +[04-02_04:14:12:620] SubscriberReadyState NotInitialized -> Initialized +[04-02_04:14:12:620] mbim_register_state_query() +[04-02_04:14:12:625] RegisterState Unknown -> Home +[04-02_04:14:12:625] mbim_packet_service_query() +[04-02_04:14:12:629] PacketServiceState Unknown -> Attached +[04-02_04:14:12:629] mbim_query_connect(sessionID=0) +[04-02_04:14:12:633] ActivationState Unknown -> Deactivated +[04-02_04:14:12:633] mbim_set_connect(onoff=1, sessionID=0) +[ 69.170666] net rmnet_mhi0: link_state 0x0 -> 0x1 +[04-02_04:14:12:680] ActivationState Deactivated -> Activated +[ 69.177035] [I][mhi_netdev_open] Opened net dev interface +[04-02_04:14:12:680] mbim_ip_config(sessionID=0) +[04-02_04:14:12:683] < SessionId = 0 +[04-02_04:14:12:683] < IPv4ConfigurationAvailable = 0xf +[04-02_04:14:12:683] < IPv6ConfigurationAvailable = 0x0 +[04-02_04:14:12:683] < IPv4AddressCount = 0x1 +[04-02_04:14:12:683] < IPv4AddressOffset = 0x3c +[04-02_04:14:12:683] < IPv6AddressCount = 0x0 +[04-02_04:14:12:683] < IPv6AddressOffset = 0x0 +[04-02_04:14:12:683] < IPv4 = 10.129.59.93/30 +[04-02_04:14:12:683] < gw = 10.129.59.94 +[04-02_04:14:12:683] < dns1 = 211.138.180.2 +[04-02_04:14:12:683] < dns2 = 211.138.180.3 +[04-02_04:14:12:683] < ipv4 mtu = 1500 +sh: can't create /sys/class/net/rmnet_mhi0/mbim/link_state: nonexistent directory +[04-02_04:14:12:684] system(echo 1 > /sys/class/net/rmnet_mhi0/mbim/link_state)=256 +[04-02_04:14:12:689] system(ip link set dev rmnet_mhi0 up)=0 +[04-02_04:14:12:692] system(ip -4 address flush dev rmnet_mhi0)=0 +[04-02_04:14:12:694] system(ip -4 address add 10.129.59.93/30 dev rmnet_mhi0)=0 +[04-02_04:14:12:697] system(ip -4 route add default via 10.129.59.94 dev rmnet_mhi0)=0 +[04-02_04:14:12:699] system(ip -4 link set dev rmnet_mhi0 mtu 1500)=0 + +root@OpenWrt:~# ifconfig rmnet_mhi0 +rmnet_mhi0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + UP RUNNING NOARP MTU:1500 Metric:1 + RX packets:99379 errors:0 dropped:0 overruns:0 frame:0 + TX packets:176569 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:1000 + RX bytes:1528181052 (1.4 GiB) TX bytes:62467192 (59.5 MiB) + +root@OpenWrt:~# ifconfig rmnet_mhi0.1 +rmnet_mhi0.1 Link encap:UNSPEC HWaddr 02-50-F4-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:10.129.59.93 Mask:255.255.255.252 + inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link + UP RUNNING NOARP MTU:1500 Metric:1 + RX packets:1089360 errors:0 dropped:0 overruns:0 frame:0 + TX packets:176581 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:1000 + RX bytes:1521449058 (1.4 GiB) TX bytes:57525792 (54.8 MiB) + +# adjust CPU load balancing +root@OpenWrt:~# echo 2 > /sys/class/net/rmnet_mhi0/queues/rx-0/rps_cpus +root@OpenWrt:~# echo 4 > /sys/class/net/rmnet_mhi0.1/queues/rx-0/rps_cpus +root@OpenWrt:~# echo 2000 > /proc/sys/net/core/netdev_max_backlog +root@OpenWrt:~# cat /sys/class/net/rmnet_mhi0/queues/rx-0/rps_cpus +2 +root@OpenWrt:~# cat /sys/class/net/rmnet_mhi0.1/queues/rx-0/rps_cpus +4 +root@OpenWrt:~# cat /proc/sys/net/core/netdev_max_backlog +2000 diff --git a/quectel_MHI/src/log/QMI_OVER_PCIE.txt b/quectel_MHI/src/log/QMI_OVER_PCIE.txt index 3604545b..14a64f9f 100644 --- a/quectel_MHI/src/log/QMI_OVER_PCIE.txt +++ b/quectel_MHI/src/log/QMI_OVER_PCIE.txt @@ -1,134 +1,134 @@ -disable ccflags-y += -DCONFIG_MHI_NETDEV_MBIM in pcie_mhi/Makefile - -root@OpenWrt:~# insmod pcie_mhi.ko - -root@OpenWrt:~# dmesg | grep mhi -[ 138.483252] mhi_init Quectel_Linux_PCIE_MHI_Driver_V1.3.0.6 -[ 138.492350] mhi_pci_probe pci_dev->name = 0000:01:00.0, domain=0, bus=1, slot=0, vendor=17CB, device=0306 -[ 138.497564] mhi_q 0000:01:00.0: BAR 0: assigned [mem 0x20300000-0x20300fff 64bit] -[ 138.506952] mhi_q 0000:01:00.0: enabling device (0140 -> 0142) -[ 138.514562] [I][mhi_init_pci_dev] msi_required = 5, msi_allocated = 5, msi_irq = 63 -[ 138.514581] [I][mhi_power_up] dev_state:RESET -[ 138.514587] [I][mhi_async_power_up] Requested to power on -[ 138.514728] [I][mhi_alloc_coherent] size = 114688, dma_handle = 72160000 -[ 138.514734] [I][mhi_init_dev_ctxt] mhi_ctxt->ctrl_seg = c221f000 -[ 138.515030] [I][mhi_async_power_up] dev_state:RESET ee:AMSS -[ 138.515056] [I][mhi_pm_st_worker] Transition to state:READY -[ 138.515067] [I][mhi_pm_st_worker] INVALID_EE -> AMSS -[ 138.515073] [I][mhi_ready_state_transition] Waiting to enter READY state -[ 138.515210] [I][mhi_async_power_up] Power on setup success -[ 138.515227] [I][mhi_pci_probe] Return successful -[ 138.589013] [I][mhi_ready_state_transition] Device in READY State -[ 138.589029] [I][mhi_intvec_threaded_handlr] device ee:AMSS dev_state:READY, pm_state:POR -[ 138.589038] [I][mhi_intvec_threaded_handlr] device ee:AMSS dev_state:READY, INVALID_EE -[ 138.589041] [I][mhi_tryset_pm_state] Transition to pm state from:POR to:POR -[ 138.589046] [I][mhi_init_mmio] Initializing MMIO -[ 138.589050] [I][mhi_init_mmio] CHDBOFF:0x300 -[ 138.589060] [I][mhi_init_mmio] ERDBOFF:0x700 -[ 138.589065] [I][mhi_init_mmio] Programming all MMIO values. -[ 138.706124] [I][mhi_dump_tre] carl_ev evt_state_change mhistate=2 -[ 138.706132] [I][mhi_process_ctrl_ev_ring] MHI state change event to state:M0 -[ 138.706140] [I][mhi_pm_m0_transition] Entered With State:READY PM_STATE:POR -[ 138.706146] [I][mhi_tryset_pm_state] Transition to pm state from:POR to:M0 -[ 138.708699] [I][mhi_dump_tre] carl_ev evt_ee_state execenv=2 -[ 138.708706] [I][mhi_process_ctrl_ev_ring] MHI EE received event:AMSS -[ 138.708726] [I][mhi_pm_st_worker] Transition to state:MISSION MODE -[ 138.708736] [I][mhi_pm_st_worker] INVALID_EE -> AMSS -[ 138.708742] [I][mhi_pm_mission_mode_transition] Processing Mission Mode Transition -[ 138.708758] [I][mhi_init_timesync] No timesync capability found -[ 138.708764] [I][mhi_pm_mission_mode_transition] Adding new devices -[ 138.709785] [I][mhi_dtr_probe] Enter for DTR control channel -[ 138.709794] [I][__mhi_prepare_channel] Entered: preparing channel:18 -[ 138.715378] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 138.715397] [I][__mhi_prepare_channel] Chan:18 successfully moved to start state -[ 138.715403] [I][__mhi_prepare_channel] Entered: preparing channel:19 -[ 138.720201] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 138.720218] [I][__mhi_prepare_channel] Chan:19 successfully moved to start state -[ 138.720236] [I][mhi_dtr_probe] Exit with ret:0 -[ 138.720590] [I][mhi_netdev_enable_iface] Prepare the channels for transfer -[ 138.720630] [I][__mhi_prepare_channel] Entered: preparing channel:100 -[ 138.757230] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 138.757253] [I][__mhi_prepare_channel] Chan:100 successfully moved to start state -[ 138.757259] [I][__mhi_prepare_channel] Entered: preparing channel:101 -[ 138.774352] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 138.774370] [I][__mhi_prepare_channel] Chan:101 successfully moved to start state -[ 138.778137] [I][mhi_netdev_enable_iface] Exited. -[ 138.779018] rmnet_vnd_register_device(rmnet_mhi0.1)=0 -[ 138.782283] net rmnet_mhi0 rmnet_mhi0.1: NSS context created -[ 138.800865] [I][mhi_pm_mission_mode_transition] Exit with ret:0 - -root@OpenWrt:~# ./quectel-CM & -root@OpenWrt:~# [04-02_04:12:16:477] Quectel_QConnectManager_Linux_V1.6.0.5 -[04-02_04:12:16:477] Find /sys/bus/usb/devices/4-1 idVendor=0x2c7c idProduct=0x800, bus=0x004, dev=0x002 -[04-02_04:12:16:478] network interface '' or qmidev '' is not exist -[04-02_04:12:16:478] netcard driver = pcie_mhi, driver version = V1.3.0.6 -[04-02_04:12:16:479] qmap_mode = 1, qmap_version = 9, qmap_size = 16384, muxid = 0x81, qmap_netcard = rmnet_mhi0.1 -[04-02_04:12:16:479] Modem works in QMI mode -[04-02_04:12:16:505] cdc_wdm_fd = 7 -[04-02_04:12:17:506] QmiThreadSendQMITimeout pthread_cond_timeout_np timeout -[04-02_04:12:18:516] Get clientWDS = 19 -[04-02_04:12:18:520] Get clientDMS = 1 -[04-02_04:12:18:524] Get clientNAS = 3 -[04-02_04:12:18:527] Get clientUIM = 1 -[04-02_04:12:18:531] Get clientWDA = 1 -[04-02_04:12:18:535] requestBaseBandVersion RM500QGLAAR03A01M4G_BETA_20200107F 1 [Dec 30 2019 17:00:00] -[04-02_04:12:18:539] qmap_settings.rx_urb_size = 16384 -[04-02_04:12:18:539] qmap_settings.ul_data_aggregation_max_datagrams = 16 -[04-02_04:12:18:539] qmap_settings.ul_data_aggregation_max_size = 8192 -[04-02_04:12:18:539] qmap_settings.dl_minimum_padding = 0 -[04-02_04:12:18:550] requestSetLoopBackState(loopback_state=1, replication_factor=14) -[04-02_04:12:18:557] requestGetSIMStatus SIMStatus: SIM_ABSENT -[04-02_04:12:18:560] requestGetProfile[1] ///0 -[04-02_04:12:18:563] requestRegistrationState2 MCC: 0, MNC: 0, PS: Detached, DataCap: UNKNOW -[04-02_04:12:18:565] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED -[04-02_04:12:18:566] ifconfig rmnet_mhi0.1 down -[04-02_04:12:18:571] ifconfig rmnet_mhi0.1 0.0.0.0 -ifconfig: SIOCSIFFLAGS: Network is down -[04-02_04:12:18:575] SetLoopBackInd: loopback_state=1, replication_factor=14 -[04-02_04:12:18:591] requestSetupDataCall WdsConnectionIPv4Handle: 0xe40182a0 -[04-02_04:12:18:601] ifconfig rmnet_mhi0 up -[04-02_04:12:18:607] ifconfig rmnet_mhi0.1 up -[04-02_04:12:18:613] you are use OpenWrt? -[04-02_04:12:18:614] should not calling udhcpc manually? -[04-02_04:12:18:614] should modify /etc/config/network as below? -[04-02_04:12:18:614] config interface wan -[04-02_04:12:18:614] option ifname rmnet_mhi0.1 -[04-02_04:12:18:614] option proto dhcp -[04-02_04:12:18:614] should use "/sbin/ifstaus wan" to check rmnet_mhi0.1 's status? -[04-02_04:12:18:614] busybox udhcpc -f -n -q -t 5 -i rmnet_mhi0.1 -udhcpc: started, v1.28.3 -udhcpc: sending discover -udhcpc: sending select for 192.168.48.171 -udhcpc: lease of 192.168.48.171 obtained, lease time 7200 -[04-02_04:12:18:809] udhcpc: ifconfig rmnet_mhi0.1 192.168.48.171 netmask 255.255.255.248 broadcast + -[04-02_04:12:18:819] udhcpc: setting default routers: 192.168.48.172 - -root@OpenWrt:~# ifconfig rmnet_mhi0 -rmnet_mhi0 Link encap:Ethernet HWaddr 02:50:F4:00:00:00 - inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link - UP RUNNING NOARP MTU:1500 Metric:1 - RX packets:2 errors:0 dropped:0 overruns:0 frame:0 - TX packets:2 errors:0 dropped:0 overruns:0 carrier:0 - collisions:0 txqueuelen:1000 - RX bytes:608 (608.0 B) TX bytes:672 (672.0 B) - -root@OpenWrt:~# ifconfig rmnet_mhi0.1 -rmnet_mhi0.1 Link encap:UNSPEC HWaddr 02-50-F4-00-00-00-00-00-00-00-00-00-00-00-00-00 - inet addr:192.168.48.171 Mask:255.255.255.248 - inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link - UP RUNNING NOARP MTU:1500 Metric:1 - RX packets:2 errors:0 dropped:0 overruns:0 frame:0 - TX packets:2 errors:0 dropped:0 overruns:0 carrier:0 - collisions:0 txqueuelen:1000 - RX bytes:592 (592.0 B) TX bytes:656 (656.0 B) - -# adjust CPU load balancing -root@OpenWrt:~# echo 2 > /sys/class/net/rmnet_mhi0/queues/rx-0/rps_cpus -root@OpenWrt:~# echo 4 > /sys/class/net/rmnet_mhi0.1/queues/rx-0/rps_cpus -root@OpenWrt:~# echo 2000 > /proc/sys/net/core/netdev_max_backlog -root@OpenWrt:~# cat /sys/class/net/rmnet_mhi0/queues/rx-0/rps_cpus -2 -root@OpenWrt:~# cat /sys/class/net/rmnet_mhi0.1/queues/rx-0/rps_cpus -4 -root@OpenWrt:~# cat /proc/sys/net/core/netdev_max_backlog +disable ccflags-y += -DCONFIG_MHI_NETDEV_MBIM in pcie_mhi/Makefile + +root@OpenWrt:~# insmod pcie_mhi.ko + +root@OpenWrt:~# dmesg | grep mhi +[ 138.483252] mhi_init Quectel_Linux_PCIE_MHI_Driver_V1.3.0.6 +[ 138.492350] mhi_pci_probe pci_dev->name = 0000:01:00.0, domain=0, bus=1, slot=0, vendor=17CB, device=0306 +[ 138.497564] mhi_q 0000:01:00.0: BAR 0: assigned [mem 0x20300000-0x20300fff 64bit] +[ 138.506952] mhi_q 0000:01:00.0: enabling device (0140 -> 0142) +[ 138.514562] [I][mhi_init_pci_dev] msi_required = 5, msi_allocated = 5, msi_irq = 63 +[ 138.514581] [I][mhi_power_up] dev_state:RESET +[ 138.514587] [I][mhi_async_power_up] Requested to power on +[ 138.514728] [I][mhi_alloc_coherent] size = 114688, dma_handle = 72160000 +[ 138.514734] [I][mhi_init_dev_ctxt] mhi_ctxt->ctrl_seg = c221f000 +[ 138.515030] [I][mhi_async_power_up] dev_state:RESET ee:AMSS +[ 138.515056] [I][mhi_pm_st_worker] Transition to state:READY +[ 138.515067] [I][mhi_pm_st_worker] INVALID_EE -> AMSS +[ 138.515073] [I][mhi_ready_state_transition] Waiting to enter READY state +[ 138.515210] [I][mhi_async_power_up] Power on setup success +[ 138.515227] [I][mhi_pci_probe] Return successful +[ 138.589013] [I][mhi_ready_state_transition] Device in READY State +[ 138.589029] [I][mhi_intvec_threaded_handlr] device ee:AMSS dev_state:READY, pm_state:POR +[ 138.589038] [I][mhi_intvec_threaded_handlr] device ee:AMSS dev_state:READY, INVALID_EE +[ 138.589041] [I][mhi_tryset_pm_state] Transition to pm state from:POR to:POR +[ 138.589046] [I][mhi_init_mmio] Initializing MMIO +[ 138.589050] [I][mhi_init_mmio] CHDBOFF:0x300 +[ 138.589060] [I][mhi_init_mmio] ERDBOFF:0x700 +[ 138.589065] [I][mhi_init_mmio] Programming all MMIO values. +[ 138.706124] [I][mhi_dump_tre] carl_ev evt_state_change mhistate=2 +[ 138.706132] [I][mhi_process_ctrl_ev_ring] MHI state change event to state:M0 +[ 138.706140] [I][mhi_pm_m0_transition] Entered With State:READY PM_STATE:POR +[ 138.706146] [I][mhi_tryset_pm_state] Transition to pm state from:POR to:M0 +[ 138.708699] [I][mhi_dump_tre] carl_ev evt_ee_state execenv=2 +[ 138.708706] [I][mhi_process_ctrl_ev_ring] MHI EE received event:AMSS +[ 138.708726] [I][mhi_pm_st_worker] Transition to state:MISSION MODE +[ 138.708736] [I][mhi_pm_st_worker] INVALID_EE -> AMSS +[ 138.708742] [I][mhi_pm_mission_mode_transition] Processing Mission Mode Transition +[ 138.708758] [I][mhi_init_timesync] No timesync capability found +[ 138.708764] [I][mhi_pm_mission_mode_transition] Adding new devices +[ 138.709785] [I][mhi_dtr_probe] Enter for DTR control channel +[ 138.709794] [I][__mhi_prepare_channel] Entered: preparing channel:18 +[ 138.715378] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 138.715397] [I][__mhi_prepare_channel] Chan:18 successfully moved to start state +[ 138.715403] [I][__mhi_prepare_channel] Entered: preparing channel:19 +[ 138.720201] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 138.720218] [I][__mhi_prepare_channel] Chan:19 successfully moved to start state +[ 138.720236] [I][mhi_dtr_probe] Exit with ret:0 +[ 138.720590] [I][mhi_netdev_enable_iface] Prepare the channels for transfer +[ 138.720630] [I][__mhi_prepare_channel] Entered: preparing channel:100 +[ 138.757230] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 138.757253] [I][__mhi_prepare_channel] Chan:100 successfully moved to start state +[ 138.757259] [I][__mhi_prepare_channel] Entered: preparing channel:101 +[ 138.774352] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 138.774370] [I][__mhi_prepare_channel] Chan:101 successfully moved to start state +[ 138.778137] [I][mhi_netdev_enable_iface] Exited. +[ 138.779018] rmnet_vnd_register_device(rmnet_mhi0.1)=0 +[ 138.782283] net rmnet_mhi0 rmnet_mhi0.1: NSS context created +[ 138.800865] [I][mhi_pm_mission_mode_transition] Exit with ret:0 + +root@OpenWrt:~# ./quectel-CM & +root@OpenWrt:~# [04-02_04:12:16:477] Quectel_QConnectManager_Linux_V1.6.0.5 +[04-02_04:12:16:477] Find /sys/bus/usb/devices/4-1 idVendor=0x2c7c idProduct=0x800, bus=0x004, dev=0x002 +[04-02_04:12:16:478] network interface '' or qmidev '' is not exist +[04-02_04:12:16:478] netcard driver = pcie_mhi, driver version = V1.3.0.6 +[04-02_04:12:16:479] qmap_mode = 1, qmap_version = 9, qmap_size = 16384, muxid = 0x81, qmap_netcard = rmnet_mhi0.1 +[04-02_04:12:16:479] Modem works in QMI mode +[04-02_04:12:16:505] cdc_wdm_fd = 7 +[04-02_04:12:17:506] QmiThreadSendQMITimeout pthread_cond_timeout_np timeout +[04-02_04:12:18:516] Get clientWDS = 19 +[04-02_04:12:18:520] Get clientDMS = 1 +[04-02_04:12:18:524] Get clientNAS = 3 +[04-02_04:12:18:527] Get clientUIM = 1 +[04-02_04:12:18:531] Get clientWDA = 1 +[04-02_04:12:18:535] requestBaseBandVersion RM500QGLAAR03A01M4G_BETA_20200107F 1 [Dec 30 2019 17:00:00] +[04-02_04:12:18:539] qmap_settings.rx_urb_size = 16384 +[04-02_04:12:18:539] qmap_settings.ul_data_aggregation_max_datagrams = 16 +[04-02_04:12:18:539] qmap_settings.ul_data_aggregation_max_size = 8192 +[04-02_04:12:18:539] qmap_settings.dl_minimum_padding = 0 +[04-02_04:12:18:550] requestSetLoopBackState(loopback_state=1, replication_factor=14) +[04-02_04:12:18:557] requestGetSIMStatus SIMStatus: SIM_ABSENT +[04-02_04:12:18:560] requestGetProfile[1] ///0 +[04-02_04:12:18:563] requestRegistrationState2 MCC: 0, MNC: 0, PS: Detached, DataCap: UNKNOW +[04-02_04:12:18:565] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED +[04-02_04:12:18:566] ifconfig rmnet_mhi0.1 down +[04-02_04:12:18:571] ifconfig rmnet_mhi0.1 0.0.0.0 +ifconfig: SIOCSIFFLAGS: Network is down +[04-02_04:12:18:575] SetLoopBackInd: loopback_state=1, replication_factor=14 +[04-02_04:12:18:591] requestSetupDataCall WdsConnectionIPv4Handle: 0xe40182a0 +[04-02_04:12:18:601] ifconfig rmnet_mhi0 up +[04-02_04:12:18:607] ifconfig rmnet_mhi0.1 up +[04-02_04:12:18:613] you are use OpenWrt? +[04-02_04:12:18:614] should not calling udhcpc manually? +[04-02_04:12:18:614] should modify /etc/config/network as below? +[04-02_04:12:18:614] config interface wan +[04-02_04:12:18:614] option ifname rmnet_mhi0.1 +[04-02_04:12:18:614] option proto dhcp +[04-02_04:12:18:614] should use "/sbin/ifstaus wan" to check rmnet_mhi0.1 's status? +[04-02_04:12:18:614] busybox udhcpc -f -n -q -t 5 -i rmnet_mhi0.1 +udhcpc: started, v1.28.3 +udhcpc: sending discover +udhcpc: sending select for 192.168.48.171 +udhcpc: lease of 192.168.48.171 obtained, lease time 7200 +[04-02_04:12:18:809] udhcpc: ifconfig rmnet_mhi0.1 192.168.48.171 netmask 255.255.255.248 broadcast + +[04-02_04:12:18:819] udhcpc: setting default routers: 192.168.48.172 + +root@OpenWrt:~# ifconfig rmnet_mhi0 +rmnet_mhi0 Link encap:Ethernet HWaddr 02:50:F4:00:00:00 + inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link + UP RUNNING NOARP MTU:1500 Metric:1 + RX packets:2 errors:0 dropped:0 overruns:0 frame:0 + TX packets:2 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:1000 + RX bytes:608 (608.0 B) TX bytes:672 (672.0 B) + +root@OpenWrt:~# ifconfig rmnet_mhi0.1 +rmnet_mhi0.1 Link encap:UNSPEC HWaddr 02-50-F4-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:192.168.48.171 Mask:255.255.255.248 + inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link + UP RUNNING NOARP MTU:1500 Metric:1 + RX packets:2 errors:0 dropped:0 overruns:0 frame:0 + TX packets:2 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:1000 + RX bytes:592 (592.0 B) TX bytes:656 (656.0 B) + +# adjust CPU load balancing +root@OpenWrt:~# echo 2 > /sys/class/net/rmnet_mhi0/queues/rx-0/rps_cpus +root@OpenWrt:~# echo 4 > /sys/class/net/rmnet_mhi0.1/queues/rx-0/rps_cpus +root@OpenWrt:~# echo 2000 > /proc/sys/net/core/netdev_max_backlog +root@OpenWrt:~# cat /sys/class/net/rmnet_mhi0/queues/rx-0/rps_cpus +2 +root@OpenWrt:~# cat /sys/class/net/rmnet_mhi0.1/queues/rx-0/rps_cpus +4 +root@OpenWrt:~# cat /proc/sys/net/core/netdev_max_backlog 2000 \ No newline at end of file diff --git a/quectel_MHI/src/log/QXDM_OVER_PCIE.txt b/quectel_MHI/src/log/QXDM_OVER_PCIE.txt index 13e9cc38..f7cff567 100644 --- a/quectel_MHI/src/log/QXDM_OVER_PCIE.txt +++ b/quectel_MHI/src/log/QXDM_OVER_PCIE.txt @@ -1,14 +1,14 @@ -root@imx6qsabresd:~# ./QLog -p /dev/mhi_DIAG -s log & -root@imx6qsabresd:~# [000.000]QLog Version: Quectel_QLog_Linux&Android_V1.2.4 -[ 298.597963] [I][mhi_uci_open] Node open, ref counts 1 -[ 298.605601] [I][mhi_uci_open] Starting channel -[ 298.612159] [I][__mhi_prepare_channel] Entered: preparing channel:4 -[ 298.629906] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 298.635415] [I][__mhi_prepare_channel] Chan:4 successfully moved to start state -[ 298.642749] [I][__mhi_prepare_channel] Entered: preparing channel:5 -[ 298.658043] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 -[ 298.663543] [I][__mhi_prepare_channel] Chan:5 successfully moved to start state -[000.075]open /dev/mhi_DIAG ttyfd = 3 -[000.075]Press CTRL+C to stop catch log. -[000.096]qlog_logfile_create log/20160920_145758_0000.qmdl logfd=4 -[005.268]recv: 0M 70K 490B in 5181 msec +root@imx6qsabresd:~# ./QLog -p /dev/mhi_DIAG -s log & +root@imx6qsabresd:~# [000.000]QLog Version: Quectel_QLog_Linux&Android_V1.2.4 +[ 298.597963] [I][mhi_uci_open] Node open, ref counts 1 +[ 298.605601] [I][mhi_uci_open] Starting channel +[ 298.612159] [I][__mhi_prepare_channel] Entered: preparing channel:4 +[ 298.629906] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 298.635415] [I][__mhi_prepare_channel] Chan:4 successfully moved to start state +[ 298.642749] [I][__mhi_prepare_channel] Entered: preparing channel:5 +[ 298.658043] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1 +[ 298.663543] [I][__mhi_prepare_channel] Chan:5 successfully moved to start state +[000.075]open /dev/mhi_DIAG ttyfd = 3 +[000.075]Press CTRL+C to stop catch log. +[000.096]qlog_logfile_create log/20160920_145758_0000.qmdl logfd=4 +[005.268]recv: 0M 70K 490B in 5181 msec diff --git a/quectel_QMI_WWAN/Makefile b/quectel_QMI_WWAN/Makefile index 4238c1ba..b27dfad7 100644 --- a/quectel_QMI_WWAN/Makefile +++ b/quectel_QMI_WWAN/Makefile @@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=qmi_wwan_q -PKG_VERSION:=1.2.9 -PKG_RELEASE:=1 +PKG_VERSION:=3.0 +PKG_RELEASE:=2 include $(INCLUDE_DIR)/kernel.mk include $(INCLUDE_DIR)/package.mk diff --git a/quectel_QMI_WWAN/src/qmi_wwan_q.c b/quectel_QMI_WWAN/src/qmi_wwan_q.c index 8cb20d3d..6c81b039 100644 --- a/quectel_QMI_WWAN/src/qmi_wwan_q.c +++ b/quectel_QMI_WWAN/src/qmi_wwan_q.c @@ -1,16 +1,13 @@ /* - Copyright (c) Bjørn Mork of author - - This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General - Public licenseas published byFree Software Foundation; either version 2theof the License,(at your option) - any later version.O1 - This program isdistributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the - implied warranty ofOr FITNESS FOR A PARTICULAR PURPOSE.MERCHANTABILITYSee theGNU General Public License - for more details. - You should have received a copy of the GNU General Public licensealong withthis program; if not, write to - the Free SoftwareFoundation, Inc.r51 Franklin Street, Fifth Floor,Boston,MA 02110-1301,USA. - - Based on version modification, the author is Quectel + * Copyright (c) 2012 Bjørn Mork + * + * The probing code is heavily inspired by cdc_ether, which is: + * Copyright (C) 2003-2005 by David Brownell + * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. */ #include @@ -65,10 +62,8 @@ static struct rmnet_nss_cb __read_mostly *nss_cb = NULL; #if defined(CONFIG_PINCTRL_IPQ807x) || defined(CONFIG_PINCTRL_IPQ5018) #ifdef CONFIG_RMNET_DATA #define CONFIG_QCA_NSS_DRV -/* define at qsdk/qca/src/linux-4.4/net/rmnet_data/rmnet_data_main.c */ //for spf11.x -/* define at qsdk/qca/src/datarmnet/core/rmnet_config.c */ //for spf12.x +/* define at qsdk/qca/src/linux-4.4/net/rmnet_data/rmnet_data_main.c */ /* set at qsdk/qca/src/data-kernel/drivers/rmnet-nss/rmnet_nss.c */ -/* need add DEPENDS:= kmod-rmnet-core in feeds/makefile */ extern struct rmnet_nss_cb *rmnet_nss_callbacks __rcu __read_mostly; #endif #endif @@ -96,7 +91,7 @@ extern struct rmnet_nss_cb *rmnet_nss_callbacks __rcu __read_mostly; * These devices may alternatively/additionally be configured using AT * commands on a serial interface */ -#define VERSION_NUMBER "V1.2.9" +#define VERSION_NUMBER "V1.2.2" #define QUECTEL_WWAN_VERSION "Quectel_Linux&Android_QMI_WWAN_Driver_"VERSION_NUMBER static const char driver_name[] = "qmi_wwan_q"; @@ -120,7 +115,6 @@ static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3}; 1 - QMAP (Aggregation protocol) X - QMAP (Multiplexing and Aggregation protocol) */ -//#define CONFIG_CLEAR_HALT #define QUECTEL_WWAN_QMAP 4 //MAX is 7 #if defined(QUECTEL_WWAN_QMAP) @@ -222,7 +216,7 @@ struct qmap_priv { struct timespec64 agg_time; struct hrtimer agg_hrtimer; struct work_struct agg_wq; - + #ifdef QUECTEL_BRIDGE_MODE uint bridge_mode; uint bridge_ipv4; @@ -231,7 +225,7 @@ struct qmap_priv { unsigned char bridge_self_mac[ETH_ALEN]; #endif #endif - uint use_qca_nss; + uint use_qca_nss; }; struct qmap_hdr { @@ -325,10 +319,10 @@ static int bridge_arp_reply(struct net_device *net, struct sk_buff *skb, uint br reply->ip_summed = CHECKSUM_UNNECESSARY; reply->pkt_type = PACKET_HOST; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION( 5,18,0 )) - netif_rx(reply); -#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) netif_rx_ni(reply); +#else + netif_rx(reply); #endif } return 1; @@ -363,14 +357,14 @@ static struct sk_buff *bridge_mode_tx_fixup(struct net_device *net, struct sk_bu bridge_mac[0], bridge_mac[1], bridge_mac[2], bridge_mac[3], bridge_mac[4], bridge_mac[5]); } } - + #ifdef CONFIG_BRIDGE_LAN //bridge Lan IP 192.168.0.0 if (ehdr->h_proto == htons(ETH_P_IP) && (iph->daddr & 0xFFFF) == 0xA8C0) { struct sk_buff *reply = skb_copy(skb, GFP_ATOMIC); ehdr = eth_hdr(reply); - + memcpy(ehdr->h_source, default_modem_addr, ETH_ALEN); if(is_qmap_netdev(net)) { @@ -384,16 +378,20 @@ static struct sk_buff *bridge_mode_tx_fixup(struct net_device *net, struct sk_bu sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; memcpy(ehdr->h_dest, pQmapDev->bridge_self_mac, ETH_ALEN); } - + //pr_info("%s br rx pkt addr: %02x:%02x:%02x:%02x:%02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x\n", netdev_name(net), // ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2], ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[5], // ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2], ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[5]); - + skb_reset_mac_header(reply); __skb_pull(reply, skb_network_offset(reply)); reply->ip_summed = CHECKSUM_UNNECESSARY; reply->pkt_type = PACKET_HOST; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) netif_rx_ni(reply); +#else + netif_rx(reply); +#endif return NULL; } #endif @@ -409,7 +407,7 @@ static void bridge_mode_rx_fixup(sQmiWwanQmap *pQmapDev, struct net_device *net, uint bridge_mode = 0; unsigned char *bridge_mac; - if (pQmapDev->qmap_mode > 1 || ((pQmapDev->use_rmnet_usb == 1) && !one_card_mode)) { + if (pQmapDev->qmap_mode > 1 || pQmapDev->use_rmnet_usb == 1) { struct qmap_priv *priv = netdev_priv(net); bridge_mode = priv->bridge_mode; bridge_mac = priv->bridge_mac; @@ -512,7 +510,7 @@ static ssize_t link_state_store(struct device *dev, struct device_attribute *att } } - if (usbnetdev->net->flags & IFF_UP) { + if (usbnetdev->net->flags & IFF_UP) { if (!pQmapDev->link_state) { netif_carrier_off(usbnetdev->net); } @@ -685,7 +683,7 @@ static void qmap_wake_queue(sQmiWwanQmap *pQmapDev) if (!pQmapDev || !pQmapDev->use_rmnet_usb) return; - + for (i = 0; i < pQmapDev->qmap_mode; i++) { struct net_device *qmap_net = pQmapDev->mpQmapNetDev[i]; @@ -695,7 +693,7 @@ static void qmap_wake_queue(sQmiWwanQmap *pQmapDev) } } -static struct sk_buff * add_qhdr(struct sk_buff *skb, u8 mux_id, int *hdr_data, int ip_offset) { +static struct sk_buff * add_qhdr(struct sk_buff *skb, u8 mux_id) { struct qmap_hdr *qhdr; int pad = 0; @@ -703,55 +701,44 @@ static struct sk_buff * add_qhdr(struct sk_buff *skb, u8 mux_id, int *hdr_data, if (pad) { pad = 4 - pad; if (skb_tailroom(skb) < pad) { - //printk("skb_tailroom small!\n"); + printk("skb_tailroom small!\n"); pad = 0; } if (pad) __skb_put(skb, pad); } - - if (hdr_data) { - qhdr = (struct qmap_hdr *)hdr_data; - qhdr->pkt_len = cpu_to_be16(skb->len - ip_offset); - } - else { - qhdr = (struct qmap_hdr *)skb_push(skb, sizeof(struct qmap_hdr)); - qhdr->pkt_len = cpu_to_be16(skb->len - sizeof(struct qmap_hdr)); - } + + qhdr = (struct qmap_hdr *)skb_push(skb, sizeof(struct qmap_hdr)); qhdr->cd_rsvd_pad = pad; qhdr->mux_id = mux_id; + qhdr->pkt_len = cpu_to_be16(skb->len - sizeof(struct qmap_hdr)); return skb; } -static struct sk_buff * add_qhdr_v5(struct sk_buff *skb, u8 mux_id, int *hdr_data, int ip_offset) { +static struct sk_buff * add_qhdr_v5(struct sk_buff *skb, u8 mux_id) { struct rmnet_map_header *map_header; struct rmnet_map_v5_csum_header *ul_header; - int pad = 0; + u32 padding, map_datalen; - pad = (skb->len - ip_offset) %4; - if (pad) { - pad = 4 - pad; - if (skb_tailroom(skb) < pad) { - //printk("skb_tailroom small!\n"); - pad = 0; + map_datalen = skb->len; + padding = map_datalen%4; + if (padding) { + padding = 4 - padding; + if (skb_tailroom(skb) < padding) { + printk("skb_tailroom small!\n"); + padding = 0; } - if (pad) - __skb_put(skb, pad); - } - - if (hdr_data) { - map_header = (struct rmnet_map_header *)hdr_data; - map_header->pkt_len = htons(skb->len - ip_offset); - } - else { - map_header = (struct rmnet_map_header *)skb_push(skb, (sizeof(struct rmnet_map_header) + sizeof(struct rmnet_map_v5_csum_header))); - map_header->pkt_len = htons(skb->len - (sizeof(struct rmnet_map_header) + sizeof(struct rmnet_map_v5_csum_header))); + if (padding) + __skb_put(skb, padding); } + + map_header = (struct rmnet_map_header *)skb_push(skb, (sizeof(struct rmnet_map_header) + sizeof(struct rmnet_map_v5_csum_header))); map_header->cd_bit = 0; map_header->next_hdr = 1; - map_header->pad_len = pad; + map_header->pad_len = padding; map_header->mux_id = mux_id; + map_header->pkt_len = htons(map_datalen + padding); ul_header = (struct rmnet_map_v5_csum_header *)(map_header + 1); memset(ul_header, 0, sizeof(*ul_header)); @@ -774,38 +761,48 @@ static void rmnet_vnd_update_rx_stats(struct net_device *net, struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64); u64_stats_update_begin(&stats64->syncp); -#if (LINUX_VERSION_CODE < KERNEL_VERSION( 6,0,0 )) +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) stats64->rx_packets += rx_packets; stats64->rx_bytes += rx_bytes; #else - u64_stats_add(&stats64->rx_packets, rx_packets); - u64_stats_add(&stats64->rx_bytes, rx_bytes); + u64_stats_add(&stats64->rx_packets, rx_packets); + u64_stats_add(&stats64->rx_bytes, rx_bytes); #endif u64_stats_update_end(&stats64->syncp); #else +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) net->stats.rx_packets += rx_packets; net->stats.rx_bytes += rx_bytes; +#else + u64_stats_add(&net->stats.rx_packets, rx_packets); + u64_stats_add(&net->stats.rx_bytes, rx_bytes); +#endif #endif } static void rmnet_vnd_update_tx_stats(struct net_device *net, - unsigned tx_packets, unsigned tx_bytes) { + unsigned tx_packets, unsigned tx_bytes) { #if defined(MHI_NETDEV_STATUS64) struct qmap_priv *dev = netdev_priv(net); struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64); u64_stats_update_begin(&stats64->syncp); -#if (LINUX_VERSION_CODE < KERNEL_VERSION( 6,0,0 )) +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) stats64->tx_packets += tx_packets; stats64->tx_bytes += tx_bytes; #else - u64_stats_add(&stats64->tx_packets, tx_packets); - u64_stats_add(&stats64->tx_bytes, tx_bytes); + u64_stats_add(&stats64->tx_packets, tx_packets); + u64_stats_add(&stats64->tx_bytes, tx_bytes); #endif u64_stats_update_end(&stats64->syncp); #else +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) net->stats.tx_packets += tx_packets; net->stats.tx_bytes += tx_bytes; +#else + u64_stats_add(&net->stats.tx_packets, tx_packets); + u64_stats_add(&net->tx_bytes, tx_bytes); +#endif #endif } @@ -825,43 +822,32 @@ static struct rtnl_link_stats64 *_rmnet_vnd_get_stats64(struct net_device *net, for_each_possible_cpu(cpu) { struct pcpu_sw_netstats *stats64; -#if (LINUX_VERSION_CODE < KERNEL_VERSION( 6,1,0 )) u64 rx_packets, rx_bytes; u64 tx_packets, tx_bytes; -#else - u64_stats_t rx_packets, rx_bytes; - u64_stats_t tx_packets, tx_bytes; -#endif stats64 = per_cpu_ptr(dev->stats64, cpu); do { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION( 6,6,0 )) start = u64_stats_fetch_begin(&stats64->syncp); -#else - start = u64_stats_fetch_begin_irq(&stats64->syncp); -#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) rx_packets = stats64->rx_packets; rx_bytes = stats64->rx_bytes; tx_packets = stats64->tx_packets; tx_bytes = stats64->tx_bytes; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION( 6,6,0 )) - } while (u64_stats_fetch_retry(&stats64->syncp, start)); #else - } while (u64_stats_fetch_retry_irq(&stats64->syncp, start)); + rx_packets = u64_stats_read(&stats64->rx_packets); + rx_bytes = u64_stats_read(&stats64->rx_bytes); + tx_packets = u64_stats_read(&stats64->tx_packets); + tx_bytes = u64_stats_read(&stats64->tx_bytes); #endif + } while (u64_stats_fetch_retry(&stats64->syncp, start)); + -#if (LINUX_VERSION_CODE < KERNEL_VERSION( 6,1,0 )) stats->rx_packets += rx_packets; stats->rx_bytes += rx_bytes; stats->tx_packets += tx_packets; stats->tx_bytes += tx_bytes; -#else - stats->rx_packets += u64_stats_read(&rx_packets); - stats->rx_bytes += u64_stats_read(&rx_bytes); - stats->tx_packets += u64_stats_read(&tx_packets); - stats->tx_bytes += u64_stats_read(&tx_bytes); -#endif + } return stats; @@ -911,7 +897,7 @@ static void rmnet_usb_tx_skb_destructor(struct sk_buff *skb) { if (pQmapDev && pQmapDev->use_rmnet_usb) { int i; - + for (i = 0; i < pQmapDev->qmap_mode; i++) { struct net_device *qmap_net = pQmapDev->mpQmapNetDev[i]; @@ -981,7 +967,7 @@ static void rmnet_usb_tx_agg_work(struct work_struct *work) ktime_get_ts64(&priv->agg_time); } spin_unlock_irqrestore(&priv->agg_lock, flags); - + if (skb) { int err; #if 0 @@ -1012,7 +998,7 @@ static long agg_bypass_time __read_mostly = 10000000L; module_param(agg_bypass_time, long, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(agg_bypass_time, "Skip agg when apart spaced more than this"); -static int rmnet_usb_tx_agg(struct sk_buff *skb, struct qmap_priv *priv, int *hdr_data, int hdr_len, int ip_offset) { +static int rmnet_usb_tx_agg(struct sk_buff *skb, struct qmap_priv *priv) { struct qmi_wwan_state *info = (void *)&priv->dev->data; sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; struct tx_agg_ctx *ctx = &pQmapDev->tx_ctx; @@ -1035,22 +1021,15 @@ static int rmnet_usb_tx_agg(struct sk_buff *skb, struct qmap_priv *priv, int *hd rmnet_vnd_update_tx_stats(pNet, 1, skb->len); if (ctx->ul_data_aggregation_max_datagrams == 1) { - agg_skb = alloc_skb(skb->len + hdr_len, GFP_ATOMIC); - if (agg_skb) { - memcpy(skb_put(agg_skb, hdr_len), hdr_data, hdr_len); - memcpy(skb_put(agg_skb, skb->len - ip_offset), skb->data + ip_offset, skb->len - ip_offset); - agg_skb->protocol = htons(ETH_P_MAP); - agg_skb->dev = priv->real_dev; + skb->protocol = htons(ETH_P_MAP); + skb->dev = priv->real_dev; #if 0 - if (!agg_skb->destructor) - agg_skb->destructor = rmnet_usb_tx_skb_destructor; + if (!skb->destructor) + skb->destructor = rmnet_usb_tx_skb_destructor; #endif - err = dev_queue_xmit(agg_skb); - if (err != NET_XMIT_SUCCESS) + err = dev_queue_xmit(skb); + if (err != NET_XMIT_SUCCESS) pNet->stats.tx_errors++; - } - dev_kfree_skb_any(skb); - skb = NULL; return NET_XMIT_SUCCESS; } @@ -1062,9 +1041,8 @@ new_packet: diff = timespec64_sub(now, priv->agg_time); if (priv->agg_skb) { - if ((priv->agg_skb->len + skb->len + hdr_len) < ctx->ul_data_aggregation_max_size) { - memcpy(skb_put(priv->agg_skb, hdr_len), hdr_data, hdr_len); - memcpy(skb_put(priv->agg_skb, skb->len - ip_offset), skb->data + ip_offset, skb->len - ip_offset); + if ((priv->agg_skb->len + skb->len) < ctx->ul_data_aggregation_max_size) { + memcpy(skb_put(priv->agg_skb, skb->len), skb->data, skb->len); priv->agg_count++; if (diff.tv_sec > 0 || diff.tv_nsec > agg_time_limit) { @@ -1074,14 +1052,14 @@ new_packet: ready2send = 1; } else if (xmit_more == 0) { - struct rmnet_map_header *map_header = (struct rmnet_map_header *)hdr_data; + struct rmnet_map_header *map_header = (struct rmnet_map_header *)skb->data; size_t offset = sizeof(struct rmnet_map_header); if (map_header->next_hdr) offset += sizeof(struct rmnet_map_v5_csum_header); ready2send = rmnet_usb_tx_agg_skip(skb, offset); } - + dev_kfree_skb_any(skb); skb = NULL; } @@ -1100,7 +1078,7 @@ new_packet: ready2send = 1; } else if (xmit_more == 0) { - struct rmnet_map_header *map_header = (struct rmnet_map_header *)hdr_data; + struct rmnet_map_header *map_header = (struct rmnet_map_header *)skb->data; size_t offset = sizeof(struct rmnet_map_header); if (map_header->next_hdr) offset += sizeof(struct rmnet_map_v5_csum_header); @@ -1112,8 +1090,7 @@ new_packet: priv->agg_skb = alloc_skb(ctx->ul_data_aggregation_max_size, GFP_ATOMIC); if (priv->agg_skb) { skb_reset_network_header(priv->agg_skb); //protocol da1a is buggy, dev wwan0 - memcpy(skb_put(priv->agg_skb, hdr_len), hdr_data, hdr_len); - memcpy(skb_put(priv->agg_skb, skb->len - ip_offset), skb->data + ip_offset, skb->len - ip_offset); + memcpy(skb_put(priv->agg_skb, skb->len), skb->data, skb->len); priv->agg_count++; dev_kfree_skb_any(skb); skb = NULL; @@ -1124,12 +1101,7 @@ new_packet: } if (ready2send) { - agg_skb = alloc_skb(skb->len + hdr_len, GFP_ATOMIC); - if (agg_skb) { - memcpy(skb_put(agg_skb, hdr_len), hdr_data, hdr_len); - memcpy(skb_put(agg_skb, skb->len - ip_offset), skb->data + ip_offset, skb->len - ip_offset); - } - dev_kfree_skb_any(skb); + agg_skb = skb; skb = NULL; } } @@ -1170,9 +1142,6 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, { int err; struct qmap_priv *priv = netdev_priv(pNet); - int qmap_hdr[2]; - int hdr_len = 0; - int ip_offset = 0; if (netif_queue_stopped(priv->real_dev)) { netif_stop_queue(pNet); @@ -1190,24 +1159,18 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, } #endif -#if 1 - ip_offset = ETH_HLEN; -#else if (skb_pull(skb, ETH_HLEN) == NULL) { dev_kfree_skb_any (skb); return NETDEV_TX_OK; } -#endif } //printk("%s 2 skb=%p, len=%d, protocol=%x, hdr_len=%d\n", __func__, skb, skb->len, skb->protocol, skb->hdr_len); if (priv->qmap_version == 5) { - add_qhdr(skb, priv->mux_id, qmap_hdr, ip_offset); - hdr_len = 4; + add_qhdr(skb, priv->mux_id); } else if (priv->qmap_version == 9) { - add_qhdr_v5(skb, priv->mux_id, qmap_hdr, ip_offset); - hdr_len = 8; + add_qhdr_v5(skb, priv->mux_id); } else { dev_kfree_skb_any (skb); @@ -1215,7 +1178,7 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, } //printk("%s skb=%p, len=%d, protocol=%x, hdr_len=%d\n", __func__, skb, skb->len, skb->protocol, skb->hdr_len); - err = rmnet_usb_tx_agg(skb, priv, qmap_hdr, hdr_len, ip_offset); + err = rmnet_usb_tx_agg(skb, priv); return err; } @@ -1283,7 +1246,7 @@ static rx_handler_result_t qca_nss_rx_handler(struct sk_buff **pskb) if (!skb) return RX_HANDLER_CONSUMED; - + //printk("%s skb=%p, len=%d, protocol=%x, hdr_len=%d\n", __func__, skb, skb->len, skb->protocol, skb->hdr_len); if (skb->pkt_type == PACKET_LOOPBACK) @@ -1332,10 +1295,10 @@ static int qmap_register_device(sQmiWwanQmap * pDev, u8 offset_id) priv->dev = pDev->mpNetDev; priv->qmap_version = pDev->qmap_version; priv->mux_id = QUECTEL_QMAP_MUX_ID + offset_id; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0) - __dev_addr_set(qmap_net, real_dev->dev_addr, ETH_ALEN); -#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) memcpy (qmap_net->dev_addr, real_dev->dev_addr, ETH_ALEN); +#else + eth_hw_addr_set (real_dev, qmap_net->dev_addr); #endif #ifdef QUECTEL_BRIDGE_MODE @@ -1351,9 +1314,7 @@ static int qmap_register_device(sQmiWwanQmap * pDev, u8 offset_id) if (nss_cb && use_qca_nss) { rmnet_usb_rawip_setup(qmap_net); } -#ifdef CONFIG_PINCTRL_IPQ9574 - rmnet_usb_rawip_setup(qmap_net); -#endif + priv->agg_skb = NULL; priv->agg_count = 0; hrtimer_init(&priv->agg_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); @@ -1389,7 +1350,7 @@ static int qmap_register_device(sQmiWwanQmap * pDev, u8 offset_id) netdev_info(qmap_net, "NSS context created\n"); rtnl_lock(); netdev_rx_handler_register(qmap_net, qca_nss_rx_handler, NULL); - rtnl_unlock(); + rtnl_unlock(); } } @@ -1418,7 +1379,7 @@ static void qmap_unregister_device(sQmiWwanQmap * pDev, u8 offset_id) { pDev->mpQmapNetDev[offset_id] = NULL; netif_carrier_off( qmap_net ); netif_stop_queue( qmap_net ); - + hrtimer_cancel(&priv->agg_hrtimer); cancel_work_sync(&priv->agg_wq); spin_lock_irqsave(&priv->agg_lock, flags); @@ -1460,8 +1421,6 @@ typedef struct { } BRMAC_SETTING; #endif -static int qma_setting_store(struct device *dev, QMAP_SETTING *qmap_settings, size_t size); - int qma_setting_store(struct device *dev, QMAP_SETTING *qmap_settings, size_t size) { struct net_device *netdev = to_net_dev(dev); struct usbnet * usbnetdev = netdev_priv( netdev ); @@ -1501,11 +1460,7 @@ static int qmap_ndo_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) #ifdef CONFIG_BRIDGE_LAN BRMAC_SETTING brmac_settings = {0}; #endif -#ifdef CONFIG_CLEAR_HALT - uint clear_halt = 0; -#endif - - + switch (cmd) { case 0x89F1: //SIOCDEVPRIVATE rc = copy_from_user(&link_state, ifr->ifr_ifru.ifru_data, sizeof(link_state)); @@ -1538,7 +1493,7 @@ static int qmap_ndo_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) rc = copy_to_user(ifr->ifr_ifru.ifru_data, &pQmapDev->rmnet_info, sizeof(pQmapDev->rmnet_info)); } break; - + #ifdef CONFIG_BRIDGE_LAN case 0x89F4: //SIOCDEVPRIVATE rc = copy_from_user(&brmac_settings, ifr->ifr_ifru.ifru_data, sizeof(brmac_settings)); @@ -1560,16 +1515,6 @@ static int qmap_ndo_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } break; #endif -#ifdef CONFIG_CLEAR_HALT - case 0x89F5: //SIOCDEVPRIVATE - rc = copy_from_user(&clear_halt, ifr->ifr_ifru.ifru_data, sizeof(clear_halt)); - if (rc == 0 && clear_halt == 1) { - usb_clear_halt(usbnetdev->udev,usbnetdev->in); - usb_clear_halt(usbnetdev->udev,usbnetdev->out); - pr_info("usb_clear_halt EPIN EPOUT\n"); - } - break; -#endif default: break; @@ -1712,9 +1657,9 @@ static struct sk_buff *qmap_qmi_wwan_tx_fixup(struct usbnet *dev, struct sk_buff if (skb) { if(pQmapDev->qmap_version == 5) - add_qhdr(skb, QUECTEL_QMAP_MUX_ID, NULL, 0); + add_qhdr(skb, QUECTEL_QMAP_MUX_ID); else - add_qhdr_v5(skb, QUECTEL_QMAP_MUX_ID, NULL, 0); + add_qhdr_v5(skb, QUECTEL_QMAP_MUX_ID); } else { return NULL; @@ -1745,7 +1690,7 @@ static void qmap_packet_decode(sQmiWwanQmap *pQmapDev, while (skb_in->len > sizeof(struct qmap_hdr)) { struct rmnet_map_header *map_header = (struct rmnet_map_header *)skb_in->data; struct rmnet_map_v5_csum_header *ul_header = NULL; - size_t hdr_size = sizeof(struct rmnet_map_header); + size_t hdr_size = sizeof(struct rmnet_map_header); struct net_device *qmap_net; int pkt_len = ntohs(map_header->pkt_len); int skb_len; @@ -1757,7 +1702,7 @@ static void qmap_packet_decode(sQmiWwanQmap *pQmapDev, ul_header = (struct rmnet_map_v5_csum_header *)(map_header + 1); hdr_size += sizeof(struct rmnet_map_v5_csum_header); } - + skb_len = pkt_len - (map_header->pad_len&0x3F); skb_len -= dl_minimum_padding; @@ -1772,7 +1717,7 @@ static void qmap_packet_decode(sQmiWwanQmap *pQmapDev, dev_info(dev, "drop qmap unknow mux_id %x\n", map_header->mux_id); goto skip_pkt; } - + if (skb_len > qmap_net->mtu) { dev_info(dev, "drop skb_len=%x larger than mtu=%d\n", skb_len, qmap_net->mtu); goto error_pkt; @@ -1815,7 +1760,7 @@ static void qmap_packet_decode(sQmiWwanQmap *pQmapDev, dev_info(dev, "unknow skb->protocol %02x\n", skb_in->data[hdr_size]); goto error_pkt; } - + qmap_skb = netdev_alloc_skb(qmap_net, skb_len); if (qmap_skb) { skb_put(qmap_skb, skb_len); @@ -1870,7 +1815,7 @@ static int qmap_qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; struct sk_buff *qmap_skb; struct sk_buff_head skb_chain; - + if (pQmapDev->qmap_mode == 0) return qmi_wwan_rx_fixup(dev, skb_in); @@ -1917,7 +1862,7 @@ static void (*_usbnet_get_stats64)(struct net_device *net, struct rtnl_link_stat static void qmi_wwan_get_stats64(struct net_device *net, struct rtnl_link_stats64 *stats) { if (_usbnet_get_stats64) ////c8b5d129ee293bcf972e7279ac996bb8a138505c return _usbnet_get_stats64(net, stats); - + netdev_stats_to_stats64(stats, &net->stats); } #else @@ -1926,7 +1871,7 @@ static struct rtnl_link_stats64 * (*_usbnet_get_stats64)(struct net_device *net, static struct rtnl_link_stats64 * qmi_wwan_get_stats64(struct net_device *net, struct rtnl_link_stats64 *stats) { if (_usbnet_get_stats64) return _usbnet_get_stats64(net, stats); - + netdev_stats_to_stats64(stats, &net->stats); return stats; } @@ -1951,7 +1896,7 @@ static int qmi_wwan_open (struct net_device *net) { } static netdev_tx_t qmi_wwan_start_xmit (struct sk_buff *skb, - struct net_device *net) + struct net_device *net) { struct usbnet * usbnetdev = netdev_priv( net ); struct qmi_wwan_state *info = (void *)&usbnetdev->data; @@ -1962,7 +1907,7 @@ static netdev_tx_t qmi_wwan_start_xmit (struct sk_buff *skb, if (netif_queue_stopped(net) && pQmapDev && pQmapDev->use_rmnet_usb) { int i; - + for (i = 0; i < pQmapDev->qmap_mode; i++) { struct net_device *qmap_net = pQmapDev->mpQmapNetDev[i]; if (qmap_net) { @@ -2004,14 +1949,8 @@ static void ql_net_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *i { /* Inherit standard device info */ usbnet_get_drvinfo(net, info); - /* strlcpy() is deprecated in kernel 6.8.0+, using strscpy instead */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(6,8,0)) strlcpy(info->driver, driver_name, sizeof(info->driver)); strlcpy(info->version, VERSION_NUMBER, sizeof(info->version)); -#else - strscpy(info->driver, driver_name, sizeof(info->driver)); - strscpy(info->version, VERSION_NUMBER, sizeof(info->version)); -#endif } static struct ethtool_ops ql_net_ethtool_ops; @@ -2076,7 +2015,7 @@ static int qmi_wwan_register_subdriver(struct usbnet *dev) atomic_set(&info->pmcount, 0); /* register subdriver */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION( 5,14,0 )) //cac6fb015f719104e60b1c68c15ca5b734f57b9c +#if (LINUX_VERSION_CODE > KERNEL_VERSION( 5,12,0 )) //cac6fb015f719104e60b1c68c15ca5b734f57b9c subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc, 4096, WWAN_PORT_QMI, &qmi_wwan_cdc_wdm_manage_power); #else @@ -2127,17 +2066,17 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) /* make MAC addr easily distinguishable from an IP header */ if (possibly_iphdr(dev->net->dev_addr)) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0) - u8 temp_addr[ETH_ALEN]; - memcpy(temp_addr, dev->net->dev_addr, ETH_ALEN); - temp_addr[0] |= 0x02; /* set local assignment bit */ - temp_addr[0] &= 0xbf; /* clear "IP" bit */ - __dev_addr_set(dev->net, temp_addr, ETH_ALEN); -#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) dev->net->dev_addr[0] |= 0x02; /* set local assignment bit */ dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */ +#else + u8 addr = dev->net->dev_addr[0]; + + addr |= 0x02; /* set local assignment bit */ + addr &= 0xbf; /* clear "IP" bit */ + dev_addr_mod(dev->net, 0, &addr, 1); #endif - } + } if (!_usbnet_get_stats64) _usbnet_get_stats64 = dev->net->netdev_ops->ndo_get_stats64; dev->net->netdev_ops = &qmi_wwan_netdev_ops; @@ -2170,9 +2109,6 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) NULL, 0, 100); } - usb_clear_halt(dev->udev,dev->in); - usb_clear_halt(dev->udev,dev->out); - //to advoid module report mtu 1460, but rx 1500 bytes IP packets, and cause the customer's system crash //next setting can make usbnet.c:usbnet_change_mtu() do not modify rx_urb_size according to hard mtu dev->rx_urb_size = ETH_DATA_LEN + ETH_HLEN + 6; @@ -2204,13 +2140,12 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) int qmap_version = (dev->driver_info->data>>8)&0xFF; int qmap_size = (dev->driver_info->data)&0xFF; int idProduct = le16_to_cpu(dev->udev->descriptor.idProduct); - int lte_a = (idProduct == 0x0306 || idProduct == 0x030B || idProduct == 0x0512 || idProduct == 0x0620 || - idProduct == 0x0800 || idProduct == 0x0801 || idProduct == 0x0122 || idProduct == 0x0316); + int lte_a = (idProduct == 0x0306 || idProduct == 0x030B || idProduct == 0x0512 || idProduct == 0x0620 || idProduct == 0x0800 || idProduct == 0x0801); if (qmap_size > 4096 || dev->udev->speed >= USB_SPEED_SUPER) { //if meet this requirements, must be LTE-A or 5G lte_a = 1; } - + pQmapDev->qmap_mode = qmap_mode; if (lte_a && pQmapDev->qmap_mode == 0) { pQmapDev->qmap_mode = 1; //force use QMAP @@ -2227,19 +2162,17 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) if (pQmapDev->qmap_mode > 1) pQmapDev->use_rmnet_usb = 1; - else if (idProduct == 0x0800 || idProduct == 0x0801 || idProduct == 0x0122) + else if (idProduct == 0x0800 || idProduct == 0x0801) pQmapDev->use_rmnet_usb = 1; //benefit for ul data agg #ifdef QMI_NETDEV_ONE_CARD_MODE if(pQmapDev->use_rmnet_usb == 1 && pQmapDev->qmap_mode == 1) one_card_mode = 1; pQmapDev->rmnet_info.mux_id[0] = QUECTEL_QMAP_MUX_ID; -#endif +#endif pQmapDev->rmnet_info.size = sizeof(RMNET_INFO); pQmapDev->rmnet_info.rx_urb_size = pQmapDev->qmap_size; pQmapDev->rmnet_info.ep_type = 2; //DATA_EP_TYPE_HSUSB - pQmapDev->rmnet_info.iface_id = 4;//Interface ID - if(idProduct == 0x0316) - pQmapDev->rmnet_info.iface_id = 3;// SDX35 Interface ID + pQmapDev->rmnet_info.iface_id = 4; pQmapDev->rmnet_info.qmap_mode = pQmapDev->qmap_mode; pQmapDev->rmnet_info.qmap_version = pQmapDev->qmap_version; pQmapDev->rmnet_info.dl_minimum_padding = 0; @@ -2249,7 +2182,7 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) pQmapDev->tx_ctx.ul_data_aggregation_max_size = 1500; #endif - if (pQmapDev->use_rmnet_usb && !one_card_mode) { + if (pQmapDev->use_rmnet_usb && !one_card_mode) { pQmapDev->driver_info = rmnet_usb_info; pQmapDev->driver_info.data = dev->driver_info->data; dev->driver_info = &pQmapDev->driver_info; @@ -2417,7 +2350,7 @@ static int rmnet_usb_rx_fixup(struct usbnet *dev, struct sk_buff *skb) return 1; } - + return 0; } @@ -2478,7 +2411,7 @@ static const struct driver_info qmi_wwan_info = { }; #define qmi_wwan_raw_ip_info \ - .description = "WWAN/QMI Raw IP device", \ + .description = "WWAN/QMI device", \ .flags = FLAG_WWAN | FLAG_RX_ASSEMBLE | FLAG_NOARP | FLAG_SEND_ZLP, \ .bind = qmi_wwan_bind, \ .unbind = qmi_wwan_unbind, \ @@ -2526,7 +2459,6 @@ static const struct usb_device_id products[] = { { QMI_FIXED_INTF(0x05C6, 0x9215, 4) }, /* Quectel EC20 (MDM9215) */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0125, 4, mdm9x07) }, /* Quectel EC20 (MDM9X07)/EC25/EG25 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0121, 4, mdm9x07) }, /* Quectel EC21 */ - { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x030E, 4, mdm9x07) }, /* Quectel EM05G */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0191, 4, mdm9x07) }, /* Quectel EG91 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0195, 4, mdm9x07) }, /* Quectel EG95 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0700, 3, mdm9x07) }, /* Quectel BG95 (at+qcfgext="usbnet","rmnet") */ @@ -2536,10 +2468,8 @@ static const struct usb_device_id products[] = { { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0296, 4, mdm9x07) }, /* Quectel BG96 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0435, 4, mdm9x07) }, /* Quectel AG35 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0620, 4, mdm9x40) }, /* Quectel EG20 */ - { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0316, 3, mdm9x40) }, /* Quectel RG255 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0800, 4, sdx55) }, /* Quectel RG500 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0801, 4, sdx55) }, /* Quectel RG520 */ - { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0122, 4, sdx55) }, /* Quectel RG650 */ { } /* END */ }; MODULE_DEVICE_TABLE(usb, products); @@ -2646,11 +2576,11 @@ static void qmap_qmi_wwan_disconnect(struct usb_interface *intf) } tasklet_kill(&pQmapDev->txq); - + usbnet_disconnect(intf); /* struct usbnet *dev had free by usbnet_disconnect()->free_netdev(). so we should access info. */ - //info->unused = 0; + //info->unused = 0; kfree(pQmapDev); } #endif diff --git a/sendat/Makefile b/sendat/Makefile index e5765cec..1e7c776b 100644 --- a/sendat/Makefile +++ b/sendat/Makefile @@ -1,28 +1,34 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=sendat -PKG_RELEASE:=1 - -PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL:=https://github.com/ouyangzq/sendat.git -PKG_SOURCE_DATE:=2023-10-26 -PKG_SOURCE_VERSION:=624c58f6331e5be3eac6d144ed985b4a4af94b10 -PKG_MIRROR_HASH:=skip - -MAKE_PATH:=src - -include $(INCLUDE_DIR)/package.mk - +include $(TOPDIR)/rules.mk#将openwrt顶层目录下的rules.mk文件中的内容导入进来 + +PKG_NAME:=sendat#软件包名 +PKG_VERSION:=6.8.2#软件包版本 +PKG_RELEASE:=2 +PKG_BUILD_DIR:= $(BUILD_DIR)/$(PKG_NAME)#真正编译当前软件包的目录 + + +include $(INCLUDE_DIR)/package.mk#将$(TOPDIR)/include目录下的package.mk文件中的内容导入进来 + define Package/sendat - SECTION:=utils - CATEGORY:=Utilities - TITLE:=Send AT Commnad - DEPENDS:=+libpthread + SECTION:=wrtnode#软件包类型 + CATEGORY:=Daocaoren#menuconfig中软件包所属的一级目录 + SUBMENU :=CPE#menuconfig中软件包所属的二级目录 + TITLE:=Sendat AT#软件包标题 + DEPENDS:=+libpthread#运行本软件依赖的其他包 endef - -define Package/sendat/install - $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/sendat $(1)/usr/bin/ + +define Package/sendat/description #软件包描述 + A sample for sendat test endef - -$(eval $(call BuildPackage,sendat)) + +define Build/Prepare #编译之前的准备动作 + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + + +define Package/sendat/install #软件包的安装方法,主要就是将一系列编译好的文件、启动脚本、UCI配置文件等拷贝到指定位置 + $(INSTALL_DIR) $(1)/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/sendat $(1)/bin/ +endef + +$(eval $(call BuildPackage,sendat)) \ No newline at end of file diff --git a/sendat/README.md b/sendat/README.md new file mode 100644 index 00000000..00fe05ce --- /dev/null +++ b/sendat/README.md @@ -0,0 +1,5 @@ +# sendat +AT 命令工具 +1简化使用AT命令请求方式 +使用命令说明 +sendat 2 'ATI' 2表示 /dev/ttyUSB2 'ATI' 为at命令 diff --git a/sendat/src/Makefile b/sendat/src/Makefile new file mode 100644 index 00000000..301b189d --- /dev/null +++ b/sendat/src/Makefile @@ -0,0 +1,9 @@ +all:sendat + +OBJS = sendat.o + +sendat:$(OBJS) + $(CC) $(CFLAGS) -o $@ $(OBJS) -lpthread + +clean: + rm -f sendat *.o \ No newline at end of file diff --git a/sendat/src/pdu.c b/sendat/src/pdu.c new file mode 100644 index 00000000..df7d9d4b --- /dev/null +++ b/sendat/src/pdu.c @@ -0,0 +1,420 @@ +/* + * 2017 - 2021 Cezary Jackiewicz + * 2014 lovewilliam + */ +// Copyright 2011 The Avalon Project Authors. All rights reserved. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the LICENSE file. +// +// SMS encoding/decoding functions, which are based on examples from: +// http://www.dreamfabric.com/sms/ + +#include "pdu.h" + +#include +#include + +enum { + BITMASK_7BITS = 0x7F, + BITMASK_8BITS = 0xFF, + BITMASK_HIGH_4BITS = 0xF0, + BITMASK_LOW_4BITS = 0x0F, + + TYPE_OF_ADDRESS_UNKNOWN = 0x81, + TYPE_OF_ADDRESS_INTERNATIONAL_PHONE = 0x91, + TYPE_OF_ADDRESS_NATIONAL_SUBSCRIBER = 0xC8, + TYPE_OF_ADDRESS_ALPHANUMERIC = 0xD0, + + SMS_DELIVER_ONE_MESSAGE = 0x04, + SMS_SUBMIT = 0x11, + + SMS_MAX_7BIT_TEXT_LENGTH = 160, +}; + +// Swap decimal digits of a number (e.g. 12 -> 21). +static unsigned char +SwapDecimalNibble(const unsigned char x) +{ + return (x / 16) + ((x % 16) * 10); +} + +// Encode/Decode PDU: Translate ASCII 7bit characters to 8bit buffer. +// SMS encoding example from: http://www.dreamfabric.com/sms/. +// +// 7-bit ASCII: "hellohello" +// [0]:h [1]:e [2]:l [3]:l [4]:o [5]:h [6]:e [7]:l [8]:l [9]:o +// 1101000 1100101 1101100 1101100 1101111 1101000 1100101 1101100 1101100 1101111 +// | ||| ||||| | ||||||| |||||| +// /-------------/ ///-------/// /////-///// \------------\ ||||||| \\\\\\ . +// | ||| ||||| | ||||||| |||||| +// input buffer position +// 10000000 22111111 33322222 44443333 55555333 66666655 77777776 98888888 --999999 +// | ||| ||||| | ||||||| |||||| +// 8bit encoded buffer +// 11101000 00110010 10011011 11111101 01000110 10010111 11011001 11101100 00110111 +// E8 32 9B FD 46 97 D9 EC 37 + + +// Encode PDU message by merging 7 bit ASCII characters into 8 bit octets. +int +EncodePDUMessage(const char* sms_text, int sms_text_length, unsigned char* output_buffer, int buffer_size) +{ + // Check if output buffer is big enough. + if ((sms_text_length * 7 + 7) / 8 > buffer_size) + return -1; + + int output_buffer_length = 0; + int carry_on_bits = 1; + int i = 0; + + for (; i < sms_text_length - 1; ++i) { + output_buffer[output_buffer_length++] = + ((sms_text[i] & BITMASK_7BITS) >> (carry_on_bits - 1)) | + ((sms_text[i + 1] & BITMASK_7BITS) << (8 - carry_on_bits)); + carry_on_bits++; + if (carry_on_bits == 8) { + carry_on_bits = 1; + ++i; + } + } + + if (i <= sms_text_length) + output_buffer[output_buffer_length++] = (sms_text[i] & BITMASK_7BITS) >> (carry_on_bits - 1); + + return output_buffer_length; +} + +// Decode PDU message by splitting 8 bit encoded buffer into 7 bit ASCII +// characters. +int +DecodePDUMessage_GSM_7bit(const unsigned char* buffer, int buffer_length, char* output_sms_text, int sms_text_length) +{ + int output_text_length = 0; + if (buffer_length > 0) + output_sms_text[output_text_length++] = BITMASK_7BITS & buffer[0]; + + if (sms_text_length > 1) { + int carry_on_bits = 1; + int i = 1; + for (; i < buffer_length; ++i) { + + output_sms_text[output_text_length++] = BITMASK_7BITS & ((buffer[i] << carry_on_bits) | (buffer[i - 1] >> (8 - carry_on_bits))); + + if (output_text_length == sms_text_length) break; + + carry_on_bits++; + + if (carry_on_bits == 8) { + carry_on_bits = 1; + output_sms_text[output_text_length++] = buffer[i] & BITMASK_7BITS; + if (output_text_length == sms_text_length) break; + } + + } + if (output_text_length < sms_text_length) // Add last remainder. + output_sms_text[output_text_length++] = buffer[i - 1] >> (8 - carry_on_bits); + } + + return output_text_length; +} + +#define GSM_7BITS_ESCAPE 0x1b + +static const unsigned char gsm7bits_to_latin1[128] = { + '@', 0xa3, '$', 0xa5, 0xe8, 0xe9, 0xf9, 0xec, 0xf2, 0xc7, '\n', 0xd8, 0xf8, '\r', 0xc5, 0xe5, + 0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc6, 0xe6, 0xdf, 0xc9, + ' ', '!', '"', '#', 0xa4, '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', + 0xa1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0xc4, 0xd6, 0xd1, 0xdc, 0xa7, + 0xbf, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0xe4, 0xf6, 0xf1, 0xfc, 0xe0, +}; + +static const unsigned char gsm7bits_extend_to_latin1[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\f', 0, 0, 0, 0, 0, + 0, 0, 0, 0, '^', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, '{', '}', 0, 0, 0, 0, 0,'\\', + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[', '~', ']', 0, + '|', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static int +G7bitToAscii(char* buffer, int buffer_length) +{ + int i; + + for (i = 0; i buffer_size) + return -1; + + int i = 0; + for (; i < phone_number_length; ++i) { + + if (phone_number[i] < '0' && phone_number[i] > '9') + return -1; + + if (i % 2 == 0) { + output_buffer[output_buffer_length++] = BITMASK_HIGH_4BITS | (phone_number[i] - '0'); + } else { + output_buffer[output_buffer_length - 1] = + (output_buffer[output_buffer_length - 1] & BITMASK_LOW_4BITS) | + ((phone_number[i] - '0') << 4); + } + } + + return output_buffer_length; +} + +// Decode a digit based phone number for SMS based format. +static int +DecodePhoneNumber(const unsigned char* buffer, int phone_number_length, char* output_phone_number) +{ + int i = 0; + for (; i < phone_number_length; ++i) { + if (i % 2 == 0) + output_phone_number[i] = (buffer[i / 2] & BITMASK_LOW_4BITS) + '0'; + else + output_phone_number[i] = ((buffer[i / 2] & BITMASK_HIGH_4BITS) >> 4) + '0'; + } + output_phone_number[phone_number_length] = '\0'; // Terminate C string. + return phone_number_length; +} + +// Encode a SMS message to PDU +int +pdu_encode(const char* service_center_number, const char* phone_number, const char* sms_text, + unsigned char* output_buffer, int buffer_size) +{ + if (buffer_size < 2) + return -1; + + int output_buffer_length = 0; + + // 1. Set SMS center number. + int length = 0; + if (service_center_number && strlen(service_center_number) > 0) { + output_buffer[1] = TYPE_OF_ADDRESS_INTERNATIONAL_PHONE; + length = EncodePhoneNumber(service_center_number, + output_buffer + 2, buffer_size - 2); + if (length < 0 && length >= 254) + return -1; + length++; // Add type of address. + } + output_buffer[0] = length; + output_buffer_length = length + 1; + if (output_buffer_length + 4 > buffer_size) + return -1; // Check if it has space for four more bytes. + + // 2. Set type of message. + output_buffer[output_buffer_length++] = SMS_SUBMIT; + output_buffer[output_buffer_length++] = 0x00; // Message reference. + + // 3. Set phone number. + output_buffer[output_buffer_length] = strlen(phone_number); + + if (strlen(phone_number) < 6) { + output_buffer[output_buffer_length + 1] = TYPE_OF_ADDRESS_UNKNOWN; + } else { + output_buffer[output_buffer_length + 1] = TYPE_OF_ADDRESS_INTERNATIONAL_PHONE; + } + + length = EncodePhoneNumber(phone_number, + output_buffer + output_buffer_length + 2, + buffer_size - output_buffer_length - 2); + output_buffer_length += length + 2; + if (output_buffer_length + 4 > buffer_size) + return -1; // Check if it has space for four more bytes. + + + // 4. Protocol identifiers. + output_buffer[output_buffer_length++] = 0x00; // TP-PID: Protocol identifier. + output_buffer[output_buffer_length++] = 0x00; // TP-DCS: Data coding scheme. + output_buffer[output_buffer_length++] = 0xB0; // TP-VP: Validity: 10 days + + // 5. SMS message. + int sms_text_length = strlen(sms_text); + char sms_text_7bit[2*SMS_MAX_7BIT_TEXT_LENGTH]; + sms_text_length = AsciiToG7bit(sms_text, sms_text_length, sms_text_7bit); + if (sms_text_length > SMS_MAX_7BIT_TEXT_LENGTH) + return -1; + output_buffer[output_buffer_length++] = sms_text_length; + length = EncodePDUMessage(sms_text_7bit, sms_text_length, + output_buffer + output_buffer_length, + buffer_size - output_buffer_length); + if (length < 0) + return -1; + output_buffer_length += length; + + return output_buffer_length; +} + +int pdu_decode(const unsigned char* buffer, int buffer_length, + time_t* output_sms_time, + char* output_sender_phone_number, int sender_phone_number_size, + char* output_sms_text, int sms_text_size, + int* tp_dcs, + int* ref_number, + int* total_parts, + int* part_number, + int* skip_bytes) +{ + + if (buffer_length <= 0) + return -1; + + const int sms_deliver_start = 1 + buffer[0]; + if (sms_deliver_start + 1 > buffer_length) + return -2; + + const int user_data_header_length = (buffer[sms_deliver_start]>>4); + + const int sender_number_length = buffer[sms_deliver_start + 1]; + if (sender_number_length + 1 > sender_phone_number_size) + return -3; // Buffer too small to hold decoded phone number. + + const int sender_type_of_address = buffer[sms_deliver_start + 2]; + if (sender_type_of_address == TYPE_OF_ADDRESS_ALPHANUMERIC) { + DecodePDUMessage_GSM_7bit(buffer + sms_deliver_start + 3, (sender_number_length + 1) / 2, output_sender_phone_number, sender_number_length); + } else { + DecodePhoneNumber(buffer + sms_deliver_start + 3, sender_number_length, output_sender_phone_number); + } + + const int sms_pid_start = sms_deliver_start + 3 + (buffer[sms_deliver_start + 1] + 1) / 2; + + // Decode timestamp. + struct tm sms_broken_time; + sms_broken_time.tm_year = 100 + SwapDecimalNibble(buffer[sms_pid_start + 2]); + sms_broken_time.tm_mon = SwapDecimalNibble(buffer[sms_pid_start + 3]) - 1; + sms_broken_time.tm_mday = SwapDecimalNibble(buffer[sms_pid_start + 4]); + sms_broken_time.tm_hour = SwapDecimalNibble(buffer[sms_pid_start + 5]); + sms_broken_time.tm_min = SwapDecimalNibble(buffer[sms_pid_start + 6]); + sms_broken_time.tm_sec = SwapDecimalNibble(buffer[sms_pid_start + 7]); + (*output_sms_time) = timegm(&sms_broken_time); + + const int sms_start = sms_pid_start + 2 + 7; + if (sms_start + 1 > buffer_length) return -1; // Invalid input buffer. + + int tmp; + if((user_data_header_length&0x04)==0x04) { + tmp = buffer[sms_start + 1] + 1; + *skip_bytes = tmp; + *ref_number = 0x000000FF&buffer[sms_start + tmp - 2]; + *total_parts = 0x000000FF&buffer[sms_start + tmp - 1]; + *part_number = 0x000000FF&buffer[sms_start + tmp]; + } else { + tmp = 0; + *skip_bytes = tmp; + *ref_number = tmp; + *total_parts = tmp; + *part_number = tmp; + } + + int output_sms_text_length = buffer[sms_start]; + if (sms_text_size < output_sms_text_length) return -1; // Cannot hold decoded buffer. + + const int sms_tp_dcs_start = sms_pid_start + 1; + *tp_dcs = buffer[sms_tp_dcs_start]; + + switch((*tp_dcs / 4) % 4) + { + case 0: + { + // GSM 7 bit + int decoded_sms_text_size = DecodePDUMessage_GSM_7bit(buffer + sms_start + 1, buffer_length - (sms_start + 1), + output_sms_text, output_sms_text_length); + if (decoded_sms_text_size != output_sms_text_length) return -1; // Decoder length is not as expected. + output_sms_text_length = G7bitToAscii(output_sms_text, output_sms_text_length); + break; + } + case 2: + { + // UCS2 + memcpy(output_sms_text, buffer + sms_start + 1, output_sms_text_length); + break; + } + default: + break; + } + + // Add a C string end. + if (output_sms_text_length < sms_text_size) + output_sms_text[output_sms_text_length] = 0; + else + output_sms_text[sms_text_size-1] = 0; + + return output_sms_text_length; +} + diff --git a/sendat/src/pdu.h b/sendat/src/pdu.h new file mode 100644 index 00000000..734a393b --- /dev/null +++ b/sendat/src/pdu.h @@ -0,0 +1,52 @@ +/* + * 2017 - 2021 Cezary Jackiewicz + * 2014 lovewilliam + */ +// Copyright 2011 The Avalon Project Authors. All rights reserved. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the LICENSE file. +#ifndef SMS_PDU_H_ +#define SMS_PDU_H_ + +#include + +enum { SMS_MAX_PDU_LENGTH = 256 }; + +/* + * Encode an SMS message. Output the encoded message into output pdu buffer. + * Returns the length of the SMS encoded message in the output buffer or + * a negative number in case encoding failed (for example provided output buffer + * does not have enough space). + */ +int pdu_encode(const char* service_center_number, const char* phone_number, const char* text, + unsigned char* pdu, int pdu_size); + +/* + * Decode an SMS message. Output the decoded message into the sms text buffer. + * Returns the length of the SMS dencoded message or a negative number in + * case encoding failed (for example provided output buffer has not enough + * space). + */ +int pdu_decode(const unsigned char* pdu, int pdu_len, + time_t* sms_time, + char* phone_number, int phone_number_size, + char* text, int text_size, + int* tp_dcs, + int* ref_number, + int* total_parts, + int* part_number, + int* skip_bytes); + +int ucs2_to_utf8 (int ucs2, unsigned char * utf8); + +int DecodePDUMessage_GSM_7bit(const unsigned char* buffer, + int buffer_length, + char* output_sms_text, + int sms_text_length); + +int EncodePDUMessage(const char* sms_text, + int sms_text_length, + unsigned char* output_buffer, + int buffer_size); + +#endif // SMS_SMS_H_ diff --git a/sendat/src/pdu_decoder.c b/sendat/src/pdu_decoder.c new file mode 100644 index 00000000..9e9e0551 --- /dev/null +++ b/sendat/src/pdu_decoder.c @@ -0,0 +1,107 @@ +/* + * 2014 lovewilliam + * SMS PDU Decoder + */ +#include "pdu.h" + +#include +#include +#include +#include +#include + +int ucs2_to_utf8 (int ucs2, unsigned char * utf8); + +int sms_decode() +{ + char buffer[2*SMS_MAX_PDU_LENGTH+4]; + char *p = buffer; + char t[2]; + int d; + do + { + t[0] = getchar(); + if(t[0]=='\n') + { + break; + } + t[1] = getchar(); + if(t[1]=='\n') + { + break; + } + *p = strtol(t,NULL,16); + p++; + }while(1); + + time_t sms_time; + char sms_phone[40]; + char sms_text[161]; + int tp_dcs_type; + int ref_number; + int total_parts; + int part_number; + int skip_bytes; + + int sms_text_length = pdu_decode((const unsigned char*)buffer, + sizeof(buffer), + &sms_time, + sms_phone, sizeof(sms_phone), + sms_text, sizeof(sms_text), + &tp_dcs_type, + &ref_number, + &total_parts, + &part_number, + &skip_bytes); + + printf("From:%s\n",sms_phone); + printf("Textlen=%d\n",sms_text_length); + char time_data_str[64]; + strftime(time_data_str,64,"%D %T", localtime(&sms_time)); + printf("Date/Time:%s\n",time_data_str); + + if (total_parts > 0) { + printf("Reference number: %d\n", ref_number); + printf("SMS segment %d of %d\n", part_number, total_parts); + } + + switch((tp_dcs_type / 4) % 4) + { + case 0: + { + // GSM7 bit + int i = skip_bytes; + if(skip_bytes > 0) i = (skip_bytes*8+6)/7; + for(;i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include "pdu.h" + + +#define MAX_PORTS 4 +/*this array hold information about each port we have opened */ +struct PortInfo { + char name[16]; + int port_fd; +}; +int serial_init(int port, int spd, int databits, int parity, \ + int stopbits, int RTSCTS, int need_line_input); +int serial_write(int fd, void *src, int len); +int serial_read(int fd, char *buf, int len); +int serial_recv(int fd,char *rbuf,int rbuf_len, int timeout); +//串口常用初始化接口 +#define serial_com_init(port, spd, databits, parity, stopbits)\ + serial_init(port, spd, databits, parity, stopbits, 0, 0) +//串口默认初始化接口 +#define serial_def_init(port, spd) serial_init(port, spd, 8, 'n', 1, 0, 1) +#endif + + + +/* +** File: uart.c +** +** Description: +** Provides an RS-232 interface that is very similar to the CVI provided +** interface library +*/ +/*this array hold information about each port we have opened */ +struct PortInfo ports[13] = +{ + {"/dev/ttyUSB0", 0}, + {"/dev/ttyUSB1", 0}, + {"/dev/ttyUSB2", 0}, + {"/dev/ttyUSB3", 0}, + {"/dev/ttyUSB4", 0}, + {"/dev/ttyUSB5", 0}, + {"/dev/ttyUSB6", 0}, + {"/dev/ttyUSB7", 0}, + {"/dev/ttyUSB8", 0}, + {"/dev/ttyUSB9", 0}, + {"/dev/ttyUSB10", 0}, + {"/dev/ttyUSB11", 0}, + {"/dev/ttyUSB12", 0}, +}; +FILE* pf; +FILE* pfi; +int spd_arr[] = {B2000000, B1500000, B576000, B500000, B460800, B230400, B115200, B57600, B38400, B19200, B9600, B4800, B2400}; +int name_arr[] = { 2000000, 1500000, 576000, 500000, 460800, 230400, 115200, 57600, 38400, 19200, 9600, 4800, 2400 }; +/** +*@brief 设置串口通信速率 +*@param fd 类型 int 打开串口的文件句柄 +*@param speed 类型 int 串口速度 +*@return void +*/ +int set_speed(int fd, int speed) +{ + int i; + int status; + struct termios Opt; + tcgetattr(fd, &Opt); + for ( i= 0; i < sizeof(spd_arr) / sizeof(int); i++) { + if(speed == name_arr[i]) { + tcflush(fd, TCIOFLUSH); + cfsetispeed(&Opt, spd_arr[i]); + cfsetospeed(&Opt, spd_arr[i]); + status = tcsetattr(fd, TCSANOW, &Opt); + if (status != 0) { + printf("tcsetattr failed"); + return 1; + } + tcflush(fd,TCIOFLUSH); + } + } + // printf("set_speed\n"); + return 0; +} + +/** +*@brief 设置串口数据位,停止位和效验位 +*@param fd 类型 int 打开的串口文件句柄 +*@param databits 类型 int 数据位 取值为 7 或者8 +*@param stopbits 类型 int 停止位 取值为 1 或者2 +*@param parity 类型 int 效验类型 取值为N,E,O,,S +*/ +int set_Parity(int fd, int databits, int parity, int stopbits, int RTSCTS) +{ + struct termios options; + if ( tcgetattr( fd,&options) != 0) { + perror("SetupSerial 1"); + return -1; + } + options.c_cflag &= ~CSIZE; + switch (databits) /*设置数据位数*/ + { + case 7: + options.c_cflag |= CS7; + break; + case 8: + options.c_cflag |= CS8; + break; + default: + fprintf(stderr,"Unsupported data size\n"); + return -1; + } + + options.c_iflag |= INPCK; + cfmakeraw(&options); + //options.c_lflag |= (ICANON | ECHO | ECHOE); + //options.c_lflag &= ~(ICANON | ECHO | ECHOE); + //options.c_iflag &= ~(IXON | IXOFF); + switch (parity) + { + case 'n': + case 'N': + options.c_cflag &= ~PARENB; /* Clear parity enable */ + options.c_iflag &= ~INPCK; /* Enable parity checking */ + break; + case 'o': + case 'O': + options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/ + break; + case 'e': + case 'E': + options.c_cflag |= PARENB; /* Enable parity */ + options.c_cflag &= ~PARODD; /* 转换为偶效验*/ + break; + case 'S': + case 's': /*as no parity*/ + options.c_cflag &= ~PARENB; + options.c_cflag &= ~CSTOPB; + break; + default: + fprintf(stderr,"Unsupported parity\n"); + return -1; + } + + /* 设置停止位*/ + switch (stopbits) + { + case 1: + options.c_cflag &= ~CSTOPB; + break; + case 2: + options.c_cflag |= CSTOPB; + break; + default: + fprintf(stderr,"Unsupported stop bits\n"); + return -1; + } + + /* Set rts/cts */ + if (RTSCTS) + { + printf("Set rts/cts"); + options.c_cflag |= CRTSCTS; + } + + tcflush(fd,TCIFLUSH); + options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/ + options.c_cc[VMIN] = 0; /* Update the options and do it NOW */ + if (tcsetattr(fd,TCSANOW,&options) != 0) + { + printf("SetupSerial failed"); + return -1; + } + // printf("set_Parity\n"); + return 0; +} + +//接收消息结尾加换行符 +int serial_set_line_input(int fd) +{ + struct termios options; + if ( tcgetattr( fd,&options) != 0) { + perror("SetupSerial 1"); + return -1; + } + + options.c_lflag |= ICANON; + + tcflush(fd,TCIFLUSH); + options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/ + options.c_cc[VMIN] = 0; /* Update the options and do it NOW */ + if (tcsetattr(fd,TCSANOW,&options) != 0) + { + perror("SetupSerial 3"); + return -1; + } + return 0; +} + +/** +*@brief +*@param port 串口端口号 +*@param spd 串口速度 +*@param databits,parity,stopbits,RTSCTS,分别为数据位,校验位,停止位,rtscts位 +*@param need_line_input接收数据结尾是否加换行符? +*/ +int serial_init(int port, int spd, int databits, int parity, int stopbits, int RTSCTS, int need_line_input) +{ + int fd; + if(port < 13) + { + // printf("open port:%d\n", port); + } + else { + printf("error: port:%d > MAX_PORTS\n", port); + return -1; + } + // + fd = open(ports[port].name, O_RDWR|O_NOCTTY);//O_NONBLOCK 非阻塞, O_WRONLY 只读写, O_RDONLY 只读, O_RDWR 读写,O_NOCTTY 阻塞 + + if (-1 == fd) { + printf("init %s failed\n", ports[port].name); + return -1; + } + pf = fdopen(port, "w"); + pfi = fdopen(port, "r"); + if (!pf || ! pfi) + fprintf(stderr,"open port failed\n"); + + + + set_speed(fd, spd); + + set_Parity(fd, databits, parity, stopbits, RTSCTS); + + if (need_line_input) { + serial_set_line_input(fd); + } + + ports[port].port_fd = fd; + + return fd; +} + +/** +*@brief +*@param fd 串口端口号文件描述符 +*@param src 需要通过串口发送的数据 +*@param len 需要发送的数据长度 +*@param 成功返回0, 否则返回-1 +*/ +int serial_write(int fd, void *src, int len) +{ + int ret = write(fd, src, len); + if (len != ret) { + perror("oh, write serial failed!"); + return -1; + } + return 0; +} + +/** +*@brief +*@param fd 串口端口号文件描述符 +*@param src 串口接收数据的指针 +*@param len 需要接收的数据长度 +*@param 成功返回0, 否则返回-1 +*/ +int serial_read(int fd, char *buf, int len) +{ + int ret = read(fd, buf, len-1); + if (-1 == ret) { + perror("oh, read serial failed!"); + return -1; + } + buf[ret] = '\0'; + return ret; +} + +int serial_recv(int fd,char *rbuf,int rbuf_len, int timeout) +{ + int retval; + fd_set rset; + struct timeval time_out; + if(!rbuf || rbuf_len <= 0) + { + // printf("serial_recv Invalid parameter.\n"); + return -1; + } + if(timeout) //指定延时等待 + { + time_out.tv_sec = (time_t)(timeout / 1000); + time_out.tv_usec = 0; + FD_ZERO(&rset); + FD_SET(fd,&rset); + + retval = select(fd,&rset,NULL,NULL,&time_out); + if(retval < 0) + { + // printf("%s,Select failed:%s\n",strerror(errno)); + return -2; + } + else if(0 == retval) + { + // printf("Time Out.\n"); + return 0; + } + + } + // usleep(1000); + retval = read(fd, rbuf, rbuf_len); + if( retval <= 0) + { + // printf("Read failed:%s\n",strerror(errno)); + return -3; + } + return retval; + +} + + +static void timeout() +{ + fprintf(stderr,"No response from modem.\n"); + exit(2); +} +/*字符包含判断*/ +static int starts_with(const char* prefix, const char* str) +{ + while(*prefix) + { + if (*prefix++ != *str++) + { + return 0; + } + } + return 1; +} +/*判断是否存在*/ +int FileExist(const char* filename) +{ + if (filename && access(filename, F_OK) == 0) { + return 1; + } + return 0; +} +/*字符转小写*/ +char* str_tolower(const char* str) +{ + size_t len = strlen(str); + char *lower = calloc(len+1, sizeof(char)); + for (size_t i = 0; i < len; ++i) { + lower[i] = tolower((unsigned char)str[i]); + } + /*free(upper);*/ + return lower; +} +/*字符转大写*/ +char* str_toupper(const char* str) +{ + size_t len = strlen(str); + char *upper = calloc(len+1, sizeof(char)); + for (size_t i = 0; i < len; ++i) { + upper[i] = toupper((unsigned char)str[i]); + } + /*free(upper);*/ + return upper; +} +/*char*转char[]*/ +char strx_tostrarr(const char* str) +{ + return 0; +} + + +int main(int argc, char **argv) +{ + if(argc<3) + { + printf("ERROR demo: sendat 2 'ATI'\n"); + exit(1); + return 0; + } + int debug = 1; + int port= 0; + sscanf(argv[1], "%d", &port); + if(FileExist(ports[port].name)==0) + { + printf("AT ERROR absent.\n"); + return 0; + } + char *message= argv[2]; + char *nty= "\r\n"; + char buff[1024]; + signal(SIGALRM,timeout); + alarm(2); + /*信号超时3秒自动退出*/ + int fd = serial_def_init(port, 1500000); + if(fd < 0) return 0; + char *send= strcat(message,nty); + serial_write(fd,send, strlen(send)); + while(1) { + int read = serial_read(fd, buff, sizeof(buff)); + if(starts_with("OK", buff)) { + if (debug == 1) + printf("%s", buff); + close(fd);//关闭串口 + exit(0); + } + if(starts_with("ERROR", buff)) { + if (debug == 1) + printf("%s", buff); + close(fd);//关闭串口 + exit(1); + } + if(starts_with("COMMAND NOT SUPPORT", buff)) { + if (debug == 1) + printf("%s", buff); + close(fd);//关闭串口 + exit(1); + } + if(starts_with("+CME ERROR", buff)) { + if (debug == 1) + printf("%s", buff); + close(fd);//关闭串口 + exit(1); + } + printf("%s", buff); + } + + exit(1); + return 0; +} diff --git a/sendat/src/ucs2_to_utf8.c b/sendat/src/ucs2_to_utf8.c new file mode 100644 index 00000000..5baa433b --- /dev/null +++ b/sendat/src/ucs2_to_utf8.c @@ -0,0 +1,53 @@ +/* + * 2014 lovewilliam + * from http://www.lemoda.net/c/ucs2-to-utf8/ucs2-to-utf8.c + */ +/* Input: a Unicode code point, "ucs2". + + Output: UTF-8 characters in buffer "utf8". + + Return value: the number of bytes written into "utf8", or -1 if + there was an error. + + This adds a zero byte to the end of the string. It assumes that the + buffer "utf8" has at least four bytes of space to write to. */ + +#define UNICODE_SURROGATE_PAIR -2 +#define UNICODE_BAD_INPUT -1 + +int ucs2_to_utf8 (int ucs2, unsigned char * utf8) +{ + if (ucs2 < 0x80) { + utf8[0] = ucs2; + utf8[1] = '\0'; + return 1; + } + if (ucs2 >= 0x80 && ucs2 < 0x800) { + utf8[0] = (ucs2 >> 6) | 0xC0; + utf8[1] = (ucs2 & 0x3F) | 0x80; + utf8[2] = '\0'; + return 2; + } + if (ucs2 >= 0x800 && ucs2 < 0xFFFF) { + if (ucs2 >= 0xD800 && ucs2 <= 0xDFFF) { + /* Ill-formed. */ + return UNICODE_SURROGATE_PAIR; + } + utf8[0] = ((ucs2 >> 12) ) | 0xE0; + utf8[1] = ((ucs2 >> 6 ) & 0x3F) | 0x80; + utf8[2] = ((ucs2 ) & 0x3F) | 0x80; + utf8[3] = '\0'; + return 3; + } + if (ucs2 >= 0x10000 && ucs2 < 0x10FFFF) { + /* http://tidy.sourceforge.net/cgi-bin/lxr/source/src/utf8.c#L380 */ + utf8[0] = 0xF0 | (ucs2 >> 18); + utf8[1] = 0x80 | ((ucs2 >> 12) & 0x3F); + utf8[2] = 0x80 | ((ucs2 >> 6) & 0x3F); + utf8[3] = 0x80 | ((ucs2 & 0x3F)); + utf8[4] = '\0'; + return 4; + } + return UNICODE_BAD_INPUT; +} + diff --git a/simcom_QMI_WWAN/Makefile b/simcom_QMI_WWAN/Makefile deleted file mode 100755 index 48e65057..00000000 --- a/simcom_QMI_WWAN/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# -# Copyright (C) 2015 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=qmi_wwan_s -PKG_VERSION:=1.0 -PKG_RELEASE:=1 - -include $(INCLUDE_DIR)/kernel.mk -include $(INCLUDE_DIR)/package.mk - -define KernelPackage/qmi_wwan_s - SUBMENU:=WWAN Support - TITLE:=Simcom Linux USB QMI WWAN Driver - DEPENDS:=+kmod-usb-net +kmod-usb-wdm - FILES:=$(PKG_BUILD_DIR)/qmi_wwan_s.ko - AUTOLOAD:=$(call AutoLoad,82,qmi_wwan_s) -endef - -define KernelPackage/qmi_wwan_s/description - Simcom Linux USB QMI WWAN Driver -endef - -MAKE_OPTS:= \ - ARCH="$(LINUX_KARCH)" \ - CROSS_COMPILE="$(TARGET_CROSS)" \ - CXXFLAGS="$(TARGET_CXXFLAGS)" \ - M="$(PKG_BUILD_DIR)" \ - $(EXTRA_KCONFIG) - -define Build/Prepare - mkdir -p $(PKG_BUILD_DIR) - $(CP) ./src/* $(PKG_BUILD_DIR)/ -endef - -define Build/Compile - $(MAKE) -C "$(LINUX_DIR)" \ - $(MAKE_OPTS) \ - modules -endef - -$(eval $(call KernelPackage,qmi_wwan_s)) diff --git a/simcom_QMI_WWAN/src/Makefile b/simcom_QMI_WWAN/src/Makefile deleted file mode 100755 index cfef5aa4..00000000 --- a/simcom_QMI_WWAN/src/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -obj-m += qmi_wwan_s.o - -PWD := $(shell pwd) -OUTPUTDIR=/lib/modules/`uname -r`/kernel/drivers/net/usb/ - -ifeq ($(ARCH),) -ARCH := $(shell uname -m) -endif -ifeq ($(CROSS_COMPILE),) -CROSS_COMPILE := -endif -ifeq ($(KDIR),) -KDIR := /lib/modules/$(shell uname -r)/build -ifeq ($(ARCH),i686) -ifeq ($(wildcard $KDIR/arch/$ARCH),) -ARCH=i386 -endif -endif -endif - -ifneq ($(findstring &,${PWD}),) -$(warning "${PWD}") -$(warning "current directory contain special char '&' !") -$(error "please remove it!") -endif - -default: - $(MAKE) ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE} -C $(KDIR) M=$(PWD) modules - -install: default - cp $(PWD)/qmi_wwan_s.ko /lib/modules/$(shell uname -r)/kernel/drivers/net/usb/ - depmod - modprobe -r qmi_wwan_s - modprobe -r qmi_wwan - modprobe qmi_wwan_s -clean: - rm -rf *~ .tmp_versions modules.order Module.symvers - find . -type f -name "*~" -o -name "*.o" -o -name "*.ko" -o -name "*.cmd" -o -name "*.mod.c" | xargs rm -rf diff --git a/simcom_QMI_WWAN/src/qmi_wwan_s.c b/simcom_QMI_WWAN/src/qmi_wwan_s.c deleted file mode 100755 index 028fc368..00000000 --- a/simcom_QMI_WWAN/src/qmi_wwan_s.c +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Copyright (c) 2012 Bjørn Mork - * - * The probing code is heavily inspired by cdc_ether, which is: - * Copyright (C) 2003-2005 by David Brownell - * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* This driver supports wwan (3G/LTE/?) devices using a vendor - * specific management protocol called Qualcomm MSM Interface (QMI) - - * in addition to the more common AT commands over serial interface - * management - * - * QMI is wrapped in CDC, using CDC encapsulated commands on the - * control ("master") interface of a two-interface CDC Union - * resembling standard CDC ECM. The devices do not use the control - * interface for any other CDC messages. Most likely because the - * management protocol is used in place of the standard CDC - * notifications NOTIFY_NETWORK_CONNECTION and NOTIFY_SPEED_CHANGE - * - * Alternatively, control and data functions can be combined in a - * single USB interface. - * - * Handling a protocol like QMI is out of the scope for any driver. - * It is exported as a character device using the cdc-wdm driver as - * a subdriver, enabling userspace applications ("modem managers") to - * handle it. - * - * These devices may alternatively/additionally be configured using AT - * commands on a serial interface - */ - -/* driver specific data */ -struct qmi_wwan_state { - struct usb_driver *subdriver; - atomic_t pmcount; - unsigned long unused; - struct usb_interface *control; - struct usb_interface *data; -}; - -/* default ethernet address used by the modem */ -static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3}; - -/* Make up an ethernet header if the packet doesn't have one. - * - * A firmware bug common among several devices cause them to send raw - * IP packets under some circumstances. There is no way for the - * driver/host to know when this will happen. And even when the bug - * hits, some packets will still arrive with an intact header. - * - * The supported devices are only capably of sending IPv4, IPv6 and - * ARP packets on a point-to-point link. Any packet with an ethernet - * header will have either our address or a broadcast/multicast - * address as destination. ARP packets will always have a header. - * - * This means that this function will reliably add the appropriate - * header iff necessary, provided our hardware address does not start - * with 4 or 6. - * - * Another common firmware bug results in all packets being addressed - * to 00:a0:c6:00:00:00 despite the host address being different. - * This function will also fixup such packets. - */ -static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -{ - __be16 proto; - - /* This check is no longer done by usbnet */ - if (skb->len < dev->net->hard_header_len) - return 0; - - switch (skb->data[0] & 0xf0) { - case 0x40: - proto = htons(ETH_P_IP); - break; - case 0x60: - proto = htons(ETH_P_IPV6); - break; - case 0x00: - if (is_multicast_ether_addr(skb->data)) - return 1; - /* possibly bogus destination - rewrite just in case */ - skb_reset_mac_header(skb); - goto fix_dest; - default: - /* pass along other packets without modifications */ - return 1; - } - if (skb_headroom(skb) < ETH_HLEN) - return 0; - skb_push(skb, ETH_HLEN); - skb_reset_mac_header(skb); - eth_hdr(skb)->h_proto = proto; - memset(eth_hdr(skb)->h_source, 0, ETH_ALEN); -fix_dest: - memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN); - return 1; -} - -struct sk_buff *qmi_wwan_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) -{ - if (dev->udev->descriptor.idVendor != cpu_to_le16(0x1e0e)) - return skb; - //skip ethernet header - if (skb_pull(skb, ETH_HLEN)) - { - return skb; - } - else - { - dev_err(&dev->intf->dev, "Packet Dropped\n"); - } - - if (skb != NULL) - dev_kfree_skb_any(skb); - - return NULL; -} - -/* very simplistic detection of IPv4 or IPv6 headers */ -static bool possibly_iphdr(const char *data) -{ - return (data[0] & 0xd0) == 0x40; -} - -/* disallow addresses which may be confused with IP headers */ -static int qmi_wwan_mac_addr(struct net_device *dev, void *p) -{ - int ret; - struct sockaddr *addr = p; - - ret = eth_prepare_mac_addr_change(dev, p); - if (ret < 0) - return ret; - if (possibly_iphdr(addr->sa_data)) - return -EADDRNOTAVAIL; - eth_commit_mac_addr_change(dev, p); - return 0; -} - -static const struct net_device_ops qmi_wwan_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_set_mac_address = qmi_wwan_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -/* using a counter to merge subdriver requests with our own into a - * combined state - */ -static int qmi_wwan_manage_power(struct usbnet *dev, int on) -{ - struct qmi_wwan_state *info = (void *)&dev->data; - int rv; - - dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, - atomic_read(&info->pmcount), on); - - if ((on && atomic_add_return(1, &info->pmcount) == 1) || - (!on && atomic_dec_and_test(&info->pmcount))) { - /* need autopm_get/put here to ensure the usbcore sees - * the new value - */ - rv = usb_autopm_get_interface(dev->intf); - dev->intf->needs_remote_wakeup = on; - if (!rv) - usb_autopm_put_interface(dev->intf); - } - return 0; -} - -static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on) -{ - struct usbnet *dev = usb_get_intfdata(intf); - - /* can be called while disconnecting */ - if (!dev) - return 0; - return qmi_wwan_manage_power(dev, on); -} - -/* collect all three endpoints and register subdriver */ -static int qmi_wwan_register_subdriver(struct usbnet *dev) -{ - int rv; - struct usb_driver *subdriver = NULL; - struct qmi_wwan_state *info = (void *)&dev->data; - - /* collect bulk endpoints */ - rv = usbnet_get_endpoints(dev, info->data); - if (rv < 0) - goto err; - - /* update status endpoint if separate control interface */ - if (info->control != info->data) - dev->status = &info->control->cur_altsetting->endpoint[0]; - - /* require interrupt endpoint for subdriver */ - if (!dev->status) { - rv = -EINVAL; - goto err; - } - - /* for subdriver power management */ - atomic_set(&info->pmcount, 0); - - /* register subdriver */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION( 5,12,0 )) - subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc, - 4096, WWAN_PORT_QMI, &qmi_wwan_cdc_wdm_manage_power); -#else - subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc, - 4096, &qmi_wwan_cdc_wdm_manage_power); -#endif - if (IS_ERR(subdriver)) { - dev_err(&info->control->dev, "subdriver registration failed\n"); - rv = PTR_ERR(subdriver); - goto err; - } - - /* prevent usbnet from using status endpoint */ - dev->status = NULL; - - /* save subdriver struct for suspend/resume wrappers */ - info->subdriver = subdriver; - -err: - return rv; -} - -static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int status = -1; - u8 *buf = intf->cur_altsetting->extra; - int len = intf->cur_altsetting->extralen; - struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; - struct usb_cdc_union_desc *cdc_union = NULL; - struct usb_cdc_ether_desc *cdc_ether = NULL; - u32 found = 0; - struct usb_driver *driver = driver_of(intf); - struct qmi_wwan_state *info = (void *)&dev->data; - - BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) < - sizeof(struct qmi_wwan_state))); - - /* set up initial state */ - info->control = intf; - info->data = intf; - - /* and a number of CDC descriptors */ - while (len > 3) { - struct usb_descriptor_header *h = (void *)buf; - - /* ignore any misplaced descriptors */ - if (h->bDescriptorType != USB_DT_CS_INTERFACE) - goto next_desc; - - /* buf[2] is CDC descriptor subtype */ - switch (buf[2]) { - case USB_CDC_HEADER_TYPE: - if (found & 1 << USB_CDC_HEADER_TYPE) { - dev_dbg(&intf->dev, "extra CDC header\n"); - goto err; - } - if (h->bLength != sizeof(struct usb_cdc_header_desc)) { - dev_dbg(&intf->dev, "CDC header len %u\n", - h->bLength); - goto err; - } - break; - case USB_CDC_UNION_TYPE: - if (found & 1 << USB_CDC_UNION_TYPE) { - dev_dbg(&intf->dev, "extra CDC union\n"); - goto err; - } - if (h->bLength != sizeof(struct usb_cdc_union_desc)) { - dev_dbg(&intf->dev, "CDC union len %u\n", - h->bLength); - goto err; - } - cdc_union = (struct usb_cdc_union_desc *)buf; - break; - case USB_CDC_ETHERNET_TYPE: - if (found & 1 << USB_CDC_ETHERNET_TYPE) { - dev_dbg(&intf->dev, "extra CDC ether\n"); - goto err; - } - if (h->bLength != sizeof(struct usb_cdc_ether_desc)) { - dev_dbg(&intf->dev, "CDC ether len %u\n", - h->bLength); - goto err; - } - cdc_ether = (struct usb_cdc_ether_desc *)buf; - break; - } - - /* Remember which CDC functional descriptors we've seen. Works - * for all types we care about, of which USB_CDC_ETHERNET_TYPE - * (0x0f) is the highest numbered - */ - if (buf[2] < 32) - found |= 1 << buf[2]; - -next_desc: - len -= h->bLength; - buf += h->bLength; - } - - /* Use separate control and data interfaces if we found a CDC Union */ - if (cdc_union) { - info->data = usb_ifnum_to_if(dev->udev, - cdc_union->bSlaveInterface0); - if (desc->bInterfaceNumber != cdc_union->bMasterInterface0 || - !info->data) { - dev_err(&intf->dev, - "bogus CDC Union: master=%u, slave=%u\n", - cdc_union->bMasterInterface0, - cdc_union->bSlaveInterface0); - goto err; - } - } - - /* errors aren't fatal - we can live with the dynamic address */ - if (cdc_ether && cdc_ether->wMaxSegmentSize) { - dev->hard_mtu = le16_to_cpu(cdc_ether->wMaxSegmentSize); - usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress); - } - - /* claim data interface and set it up */ - if (info->control != info->data) { - status = usb_driver_claim_interface(driver, info->data, dev); - if (status < 0) - goto err; - } - - status = qmi_wwan_register_subdriver(dev); - if (status < 0 && info->control != info->data) { - usb_set_intfdata(info->data, NULL); - usb_driver_release_interface(driver, info->data); - } - - /* Never use the same address on both ends of the link, even - * if the buggy firmware told us to. - */ - if (ether_addr_equal(dev->net->dev_addr, default_modem_addr)) - eth_hw_addr_random(dev->net); - - /* make MAC addr easily distinguishable from an IP header */ - if (possibly_iphdr(dev->net->dev_addr)) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) - dev->net->dev_addr[0] |= 0x02; /* set local assignment bit */ - dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */ -#else - u8 addr = dev->net->dev_addr[0]; - - addr |= 0x02; /* set local assignment bit */ - addr &= 0xbf; /* clear "IP" bit */ - dev_addr_mod(dev->net, 0, &addr, 1); -#endif - } - dev->net->netdev_ops = &qmi_wwan_netdev_ops; - -#if 1 //Added by Simcom - if (dev->udev->descriptor.idVendor == cpu_to_le16(0x1e0e)) { - dev_info(&intf->dev, "SIMCom 8200 work on RawIP mode\n"); - dev->net->flags |= IFF_NOARP; - usb_control_msg( - interface_to_usbdev(intf), - usb_sndctrlpipe(interface_to_usbdev(intf), 0), - 0x22, //USB_CDC_REQ_SET_CONTROL_LINE_STATE - 0x21, //USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE - 1, //active CDC DTR - intf->cur_altsetting->desc.bInterfaceNumber, - NULL, - 0, - 100 - ); - } -#endif - -err: - return status; -} - -static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf) -{ - struct qmi_wwan_state *info = (void *)&dev->data; - struct usb_driver *driver = driver_of(intf); - struct usb_interface *other; - - if (info->subdriver && info->subdriver->disconnect) - info->subdriver->disconnect(info->control); - - /* allow user to unbind using either control or data */ - if (intf == info->control) - other = info->data; - else - other = info->control; - - /* only if not shared */ - if (other && intf != other) { - usb_set_intfdata(other, NULL); - usb_driver_release_interface(driver, other); - } - - info->subdriver = NULL; - info->data = NULL; - info->control = NULL; -} - -/* suspend/resume wrappers calling both usbnet and the cdc-wdm - * subdriver if present. - * - * NOTE: cdc-wdm also supports pre/post_reset, but we cannot provide - * wrappers for those without adding usbnet reset support first. - */ -static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct usbnet *dev = usb_get_intfdata(intf); - struct qmi_wwan_state *info = (void *)&dev->data; - int ret; - - /* Both usbnet_suspend() and subdriver->suspend() MUST return 0 - * in system sleep context, otherwise, the resume callback has - * to recover device from previous suspend failure. - */ - ret = usbnet_suspend(intf, message); - if (ret < 0) - goto err; - - if (intf == info->control && info->subdriver && - info->subdriver->suspend) - ret = info->subdriver->suspend(intf, message); - if (ret < 0) - usbnet_resume(intf); -err: - return ret; -} - -static int qmi_wwan_resume(struct usb_interface *intf) -{ - struct usbnet *dev = usb_get_intfdata(intf); - struct qmi_wwan_state *info = (void *)&dev->data; - int ret = 0; - bool callsub = (intf == info->control && info->subdriver && - info->subdriver->resume); - - if (callsub) - ret = info->subdriver->resume(intf); - if (ret < 0) - goto err; - ret = usbnet_resume(intf); - if (ret < 0 && callsub) - info->subdriver->suspend(intf, PMSG_SUSPEND); -err: - return ret; -} - -static const struct driver_info qmi_wwan_info = { - .description = "WWAN/QMI device", - .flags = FLAG_WWAN, - .bind = qmi_wwan_bind, - .unbind = qmi_wwan_unbind, - .manage_power = qmi_wwan_manage_power, - .rx_fixup = qmi_wwan_rx_fixup, -}; - -static const struct driver_info qmi_wwan_raw_ip_info = { - .description = "WWAN/QMI device", - .flags = FLAG_WWAN, - .bind = qmi_wwan_bind, - .unbind = qmi_wwan_unbind, - .manage_power = qmi_wwan_manage_power, - .rx_fixup = qmi_wwan_rx_fixup, - .tx_fixup = qmi_wwan_tx_fixup, -}; - -#define HUAWEI_VENDOR_ID 0x12D1 - -/* map QMI/wwan function by a fixed interface number */ -#define QMI_FIXED_INTF(vend, prod, num) \ - USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \ - .driver_info = (unsigned long)&qmi_wwan_info - -#define QMI_FIXED_RAWIP_INTF(vend, prod, num) \ - USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \ - .driver_info = (unsigned long)&qmi_wwan_raw_ip_info - -/* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */ -#define QMI_GOBI1K_DEVICE(vend, prod) \ - QMI_FIXED_INTF(vend, prod, 3) - -/* Gobi 2000/3000 QMI/wwan interface number is 0 according to qcserial */ -#define QMI_GOBI_DEVICE(vend, prod) \ - QMI_FIXED_INTF(vend, prod, 0) - -static const struct usb_device_id products[] = { - {QMI_FIXED_RAWIP_INTF(0x1e0e, 0x9001, 5)}, /* SIMCOM 8200 */ - { } /* END */ -}; -MODULE_DEVICE_TABLE(usb, products); - -static bool quectel_ec20_detected(struct usb_interface *intf) -{ - struct usb_device *dev = interface_to_usbdev(intf); - - if (dev->actconfig && - le16_to_cpu(dev->descriptor.idVendor) == 0x05c6 && - le16_to_cpu(dev->descriptor.idProduct) == 0x9215 && - dev->actconfig->desc.bNumInterfaces == 5) - return true; - - return false; -} - -static int qmi_wwan_probe(struct usb_interface *intf, - const struct usb_device_id *prod) -{ - struct usb_device_id *id = (struct usb_device_id *)prod; - struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; - - /* Workaround to enable dynamic IDs. This disables usbnet - * blacklisting functionality. Which, if required, can be - * reimplemented here by using a magic "blacklist" value - * instead of 0 in the static device id table - */ - if (!id->driver_info) { - dev_dbg(&intf->dev, "setting defaults for dynamic device id\n"); - id->driver_info = (unsigned long)&qmi_wwan_info; - } - - /* There are devices where the same interface number can be - * configured as different functions. We should only bind to - * vendor specific functions when matching on interface number - */ - if (id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER && - desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) { - dev_dbg(&intf->dev, - "Rejecting interface number match for class %02x\n", - desc->bInterfaceClass); - return -ENODEV; - } - - /* Quectel EC20 quirk where we've QMI on interface 4 instead of 0 */ - if (quectel_ec20_detected(intf) && desc->bInterfaceNumber == 0) { - dev_dbg(&intf->dev, "Quectel EC20 quirk, skipping interface 0\n"); - return -ENODEV; - } - - return usbnet_probe(intf, id); -} - -static struct usb_driver qmi_wwan_driver = { - .name = "qmi_wwan_s", - .id_table = products, - .probe = qmi_wwan_probe, - .disconnect = usbnet_disconnect, - .suspend = qmi_wwan_suspend, - .resume = qmi_wwan_resume, - .reset_resume = qmi_wwan_resume, - .supports_autosuspend = 1, - .disable_hub_initiated_lpm = 1, -}; - -module_usb_driver(qmi_wwan_driver); - -MODULE_AUTHOR("Bjørn Mork "); -MODULE_DESCRIPTION("Qualcomm MSM Interface (QMI) WWAN driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("Simcom_Linux_QMI_WWAN_Driver_V1.0"); \ No newline at end of file