【问题标题】:n_gsm Line discipline problem with Telit LE910B1 Modem and CMUXTelit LE910B1 调制解调器和 CMUX 的 n_gsm 线路规则问题
【发布时间】:2023-03-04 16:32:02
【问题描述】:

我们在运行 Linux 5.1.0 内核的嵌入式设备上使用 Telit LE910B1 调制解调器。我们只有一个可用于调制解调器的 UART,因此我们在调制解调器上使用带有 CMUX 的 n_gsm 线路规则。一切设置好后,我们的应用程序会创建两个虚拟 tty,使用一个来获取调制解调器信息,另一个传递给 pppd 以启动 PPP 会话。然后我们可以通过 TCP/IP 启动数据 RX/TX。这一切都可以在短时间内正常工作,传输少量数据,但是当我们尝试传输大量数据时,PPP 连接会锁定,让事情再次运行的唯一方法是杀死 pppd,重启调制解调器,然后重新启动应用程序。

Telit 能够在两个不同版本的 Ubuntu(18.04 和side" 可能没有制作正确的 CMUX 帧或不遵守最大帧大小。以下是 Telit 从调制解调器跟踪分析中提供给我们的一些摘录:

<-- Packet discarded because of flag("0xF9") missing in CMUX frame.
<-- Packet discarded because of dlc is not valid in frame.
<-- Packet discarded because of length size more then RD_BUF_SIZE = 1510
<-- Packet dropped because of in PPP frame FCS is not valid

在我的情况下,“主机应用程序端”是 Linux 中的 n_gsm 驱动程序,我唯一可以设置的是 mru 和 mtu 大小,我已将其设置为 Telit 所说的调制解调器的默认值(即 121) .

我用来配置调制解调器的代码非常简单(为简洁起见,省略了错误检查):

struct termios tio;
int serial_fd;

serial_fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NDELAY);
tcgetattr(serial_fd, &tio);
tio.c_iflag = 0;
tio.c_oflag = 0;
tio.c_cflag = CS8 | CREAD | CLOCAL;
tio.c_cflag |= CRTSCTS;
tio.c_lflag = 0;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;

cfsetospeed(&tio, B115200);
cfsetispeed(&tio, B115200);
tcsetattr(serial_fd, TCSANOW, &tio);

要配置调制解调器,我使用以下命令:

send_at_command(serial_fd, "ATE0V1&K3&D2\r");
send_at_command(serial_fd, "AT#CMUXMODE=5\r");
send_at_command(serial_fd, "AT+CMUX=0,0\r");

完成后,我启用 n_gsm 规则

struct gsm_config gsm;

int ldisc = N_GSM0710;
ioctl(serial_fd, TIOCSETD, &ldisc);
ioctl(serial_fd, GSMIOC_GETCONF, &gsm) ;

gsm.initiator = 1;
gsm.encapsulation = 0;
gsm.mru = 121;
gsm.mtu = 121;

ioctl(serial_fd, GSMIOC_SETCONF, &gsm);
/* Create /dev/ttyGSM1 and /dev/ttyGSM2. Do not close /dev/ttyS1 */

有没有其他人在 Linux 5.1.0 或更高版本的内核上使用具有 CMUX 和 n_gsm 线路规则的 LE910* 调制解调器?你有什么问题吗?我显示的代码有什么问题吗?或者您能建议我尝试一下吗?

编辑

我查看了 n_gsm.c 驱动程序代码,发现您可以启用 3 个跟踪级别。我从启用第 4 级和第 2 级开始:

echo "6" > /sys/module/n_gsm/parameters/debug

这将在数据包构建并发送到 tty 时记录它们。我发现英特尔所说的是正确的。驱动程序正在向调制解调器发送垃圾。日志显示正常数据包发出,但随后是这样的:

Jan 19 18:09:51 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000000: f9 0b ef f3 21 45 10 05 74 aa 6a 40 00 40 06 d1  ....!E..t.j@.@..
Jan 19 18:09:51 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000010: a5 46 19 8e 6f cc 65 18 76 00 16 0b 58 5b e6 da  .F..o.e.v...X[..
Jan 19 18:09:51 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000020: 55 bd 3e 38 ad 80 18 1f 4a 4d dc 00 00 01 01 08  U.>8....JM......
Jan 19 18:09:51 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000030: 0a 65 3c e5 73 7b 9d 4c 86 f8 53 e4 9f ff a4 9e  .e<.s{.L..S.....
Jan 19 18:09:51 ZFG0000805 kern.debug kernel: gsmld_output: 00000060: 27 3c ee ab 28 29 51 e7 4e 04 f4 70 ce d4 e3 f2  '<..()Q.N..p....
Jan 19 18:09:51 ZFG0000805 kern.debug kernel: gsmld_output: 00000070: 93 ed 71 30 c7 1e 93 d8 b3 4a 90 88 e7 f9        ..q0.....J....

通常你会看到一个踢,然后是一个输出,其中数据包完全相同,但不是在这里。 CMUX 数据包应该以 0xf9 字节开始和结束,但“输出”数据包似乎已损坏。在此之后,所有踢记录显示完整的数据包,但以下输出跟踪从帧开始字符开始一个字节。

Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000000: f9 0b ef f3 87 8d e0 d0 db 2a 22 96 92 80 b6 a4  .........*".....
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000010: 31 33 43 f0 13 e9 f3 79 13 d9 b4 13 8a 85 10 15  13C....y........
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000020: 26 0d ab c2 89 f2 ad a2 6f cd 5d a9 15 f2 fe e8  &.......o.].....
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000030: 6a 90 06 ef f3 d2 4c c1 65 4e 3c 22 f5 db f8 66  j.....L.eN<"...f
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000040: d5 d7 70 fa f5 47 03 09 52 d3 1f 30 91 55 20 ce  ..p..G..R..0.U .
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000050: bc 71 51 b5 f7 ac f4 2a 7d 5d 1d 47 8d 30 73 22  .qQ....*}].G.0s"
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000060: 38 fa 39 f4 64 9f f6 7d 5d 7d 5d 2a ab b6 a6 cf  8.9.d..}]}]*....
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000070: 76 dd 8f 0a fd 27 8f 09 b2 78 99 da f8 e7 f9     v....'...x.....
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000000: 0b ef f3 87 8d e0 d0 db 2a 22 96 92 80 b6 a4 31  ........*".....1
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000010: 33 43 f0 13 e9 f3 79 13 d9 b4 13 8a 85 10 15 26  3C....y........&
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000020: 0d ab c2 89 f2 ad a2 6f cd 5d a9 15 f2 fe e8 6a  .......o.].....j
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000030: 90 06 ef f3 d2 4c c1 65 4e 3c 22 f5 db f8 66 d5  .....L.eN<"...f.
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000040: d7 70 fa f5 47 03 09 52 d3 1f 30 91 55 20 ce bc  .p..G..R..0.U ..
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000050: 71 51 b5 f7 ac f4 2a 7d 5d 1d 47 8d 30 73 22 38  qQ....*}].G.0s"8
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000060: fa 39 f4 64 9f f6 7d 5d 7d 5d 2a ab b6 a6 cf 76  .9.d..}]}]*....v
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000070: dd 8f 0a fd 27 8f 09 b2 78 99 da f8 e7 f9        ....'...x.....

现在是真正奇怪的部分。当我启用数据包日志记录时,

echo "7" > /sys/module/n_gsm/parameters/debug

在排队等待发送之前记录数据包。这会减慢整个系统的速度,但无论我尝试什么,我都无法让网络会话挂起。一切似乎都运行良好,尽管速度非常慢。

【问题讨论】:

  • 什么 UART 主控制器以及您连接到它的速度?
  • LPC3250微控制器,速度115200。
  • 如果使用没有CMUX的PPP会出现故障吗?
  • 不,PPP 会话将启动并保持没有问题。一切正常。我应该补充一点,当这个问题发生时,pppd 会像一切正常一样继续运行,但是,没有数据会流过 PPP 会话。
  • 这与我在 Ublox 调制解调器和内核 4.9.11 中看到的问题非常相似。还没有弄清楚:/

标签: linux linux-kernel gsm


【解决方案1】:

我们在内核 4.1.15 的嵌入式 Linux 和内核 5.3.0 的 ubuntu 上遇到了类似的问题。

当在上游方向(主机 -> 世界)执行较大的数据传输(iperf、scp、...)时,传输小块数据可以正常工作,ppp 在一段时间内(大约 30 秒)停止发送数据。

但是,我们没有看到格式错误的数据包的问题(如原始问题),如果启用调试,问题就消失了。

这个问题从何而来。当 DLCI fifo 被填满时,gsmtty_write 函数返回值 0。重试 3 次后,ppp 回退一段时间(根据观察,这大约是 30 秒,但不确定确切的时间/条件)。

当 DLCI fifo 被释放或低于某个阈值时,代码中缺少 tty_wakeup。

我们正在努力解决此问题。有了下面的补丁,问题就消失了,但离最终补丁还很远。

--- a/n_gsm.c
+++ b/n_gsm.c
@@ -2408,6 +2408,8 @@ static void gsmld_write_wakeup(struct tty_struct *tty)
 {
        struct gsm_mux *gsm = tty->disc_data;
        unsigned long flags;
+       struct tty_struct *tty_dlci = NULL;
+       int i = 0;

        /* Queue poll */
        clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
@@ -2416,7 +2418,33 @@ static void gsmld_write_wakeup(struct tty_struct *tty)
        if (gsm->tx_bytes < TX_THRESH_LO) {
                gsm_dlci_data_sweep(gsm);
        }
+
+       while (i < NUM_DLCI) {
+               struct gsm_dlci *dlci;
+
+               if (debug & 200)
+                       printk("%s: gsm->tx_bytes: %u\n", __FUNCTION__, gsm->tx_bytes);
+
+               if (gsm->tx_bytes > TX_THRESH_HI)
+                       break;
+
+               dlci = gsm->dlci[i];
+               if (dlci == NULL) {
+                       i++;
+                       continue;
+               }
+               if (kfifo_len(dlci->fifo) < 2048)  {
+                       tty_dlci = tty_port_tty_get(&dlci->port);
+                       if (tty_dlci)
+                               printk("We should call tty_wakeup for DLCI %d, tty_dlci: 0x%x\n", i, (unsigned int) tty_dlci );
+               }
+               i++;
+       }
+
        spin_unlock_irqrestore(&gsm->tx_lock, flags);
+
+       if (tty_dlci)
+               tty_wakeup(tty_dlci);
 }

 /**

【讨论】:

  • 这是在某处被跟踪的错误吗?我很想跟踪进入主线内核的进度
  • 我们最终签约某人来解决这个问题。我想它会以某种方式进入内核,但我不知道这个过程,所以我不知道需要多长时间。
猜你喜欢
  • 1970-01-01
  • 2014-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多