ltq-vectoring: add driver
authorJan Hoffmann <jan@3e8.eu>
Sun, 13 Mar 2022 21:14:35 +0000 (22:14 +0100)
committerDaniel Golle <daniel@makrotopia.org>
Mon, 21 Mar 2022 12:28:26 +0000 (12:28 +0000)
In order to calculate the required pre-distortion for downstream
vectoring, the vectoring control entity (VCE) at the carrier office
needs error samples from the modem. On Lantiq VR9 modems, error reports
are generated by the firmware, but need to be multiplexed into the data
stream by the driver on the main processor when L2 encapsulation is
selected by the VCE.

This driver provides the necessary callback function, which is called by
the MEI driver after receiving an error report from the firmware.

Originally, it is part of the Lantiq PPA driver, but after a few changes
it also works with the PTM driver used in OpenWrt. The direct call to
ndo_start_xmit needs to be replaced, as the PTM driver relies on locks
from the kernel. Instead dev_queue_xmit is used, which is called from a
work queue, as it is not safe to call from an interrupt handler.

Additional changes include fixes to support recent kernel versions and
a change of the used interface from ptm0 to dsl0.

Tested-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Signed-off-by: Jan Hoffmann <jan@3e8.eu>
package/kernel/lantiq/ltq-vectoring/Makefile [new file with mode: 0644]
package/kernel/lantiq/ltq-vectoring/patches/001-fix-compile.patch [new file with mode: 0644]
package/kernel/lantiq/ltq-vectoring/patches/100-cleanup.patch [new file with mode: 0644]
package/kernel/lantiq/ltq-vectoring/patches/200-compat.patch [new file with mode: 0644]

diff --git a/package/kernel/lantiq/ltq-vectoring/Makefile b/package/kernel/lantiq/ltq-vectoring/Makefile
new file mode 100644 (file)
index 0000000..b7b1b83
--- /dev/null
@@ -0,0 +1,61 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ltq-vectoring
+PKG_RELEASE:=$(AUTORELEASE)
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://gitlab.com/prpl-foundation/intel/ppa_drv.git
+PKG_SOURCE_DATE:=2019-05-20
+PKG_SOURCE_VERSION:=4fa7ac30fcc8ec4eddae9debba5f4230981f469f
+PKG_MIRROR_HASH:=444eb823dd9ddd25453976bf7a3230955e4148b8bf92f35f165ecffee32c4555
+PKG_LICENSE:=GPL-2.0 BSD-2-Clause
+
+MAKE_PATH:=src/vectoring
+PKG_EXTMOD_SUBDIRS:=$(MAKE_PATH)
+
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/ltq-vectoring
+  SECTION:=sys
+  CATEGORY:=Kernel modules
+  SUBMENU:=Network Devices
+  TITLE:=driver for sending vectoring error samples
+  DEPENDS:=@TARGET_lantiq_xrx200
+  FILES:=$(PKG_BUILD_DIR)/$(MAKE_PATH)/ltq_vectoring.ko
+  AUTOLOAD:=$(call AutoLoad,49,ltq_vectoring)
+endef
+
+define Package/ltq-vectoring/description
+       This driver is responsible for sending error reports to the vectoring
+       control entity, which is required for downstream vectoring to work.
+
+       The error reports are generated by the DSL firmware, and passed to this
+       driver by the MEI driver.
+endef
+
+define KernelPackage/ltq-vectoring-test
+  SECTION:=sys
+  CATEGORY:=Kernel modules
+  SUBMENU:=Network Devices
+  TITLE:=driver for testing the vectoring driver
+  DEPENDS:=@TARGET_lantiq_xrx200 +kmod-ltq-vectoring
+  FILES:=$(PKG_BUILD_DIR)/$(MAKE_PATH)/ltq_vectoring_test.ko
+endef
+
+define Package/ltq-vectoring-test/description
+       This allows to send dummy data to the vectoring error block callback.
+       This is only needed for test and development purposes.
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+       +$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \
+               $(KERNEL_MAKE_FLAGS) \
+               M="$(PKG_BUILD_DIR)/$(MAKE_PATH)" \
+               modules
+endef
+
+$(eval $(call KernelPackage,ltq-vectoring))
+$(eval $(call KernelPackage,ltq-vectoring-test))
diff --git a/package/kernel/lantiq/ltq-vectoring/patches/001-fix-compile.patch b/package/kernel/lantiq/ltq-vectoring/patches/001-fix-compile.patch
new file mode 100644 (file)
index 0000000..c97ec4d
--- /dev/null
@@ -0,0 +1,95 @@
+--- a/src/vectoring/Makefile
++++ b/src/vectoring/Makefile
+@@ -1,5 +1,5 @@
+-obj-$(CONFIG_PTM_VECTORING)   += ifxmips_vectoring.o
+-obj-y += ifxmips_vectoring_stub.o
+-ifeq ($(CONFIG_DSL_MEI_CPE_DRV),)
+-obj-$(CONFIG_PTM_VECTORING)   += ifxmips_vectoring_test.o
+-endif
++obj-m += ltq_vectoring.o
++ltq_vectoring-objs = ifxmips_vectoring.o ifxmips_vectoring_stub.o
++
++obj-m += ltq_vectoring_test.o
++ltq_vectoring_test-objs = ifxmips_vectoring_test.o
+--- a/src/vectoring/ifxmips_vectoring.c
++++ b/src/vectoring/ifxmips_vectoring.c
+@@ -30,9 +30,11 @@
+ /*
+  *  Common Head File
+  */
++#include <linux/version.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/etherdevice.h>
++#include <linux/proc_fs.h>
+ /*
+  *  Chip Specific Head File
+@@ -239,7 +241,7 @@ static int netdev_event_handler(struct n
+         && event != NETDEV_UNREGISTER )
+         return NOTIFY_DONE;
+-    netif = (struct net_device *)netdev;
++    netif = netdev_notifier_info_to_dev(netdev);
+     if ( strcmp(netif->name, "ptm0") != 0 )
+         return NOTIFY_DONE;
+@@ -356,6 +358,7 @@ static int proc_write_dbg(struct file *f
+     return count;
+ }
++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
+ static struct file_operations g_proc_file_vectoring_dbg_seq_fops = {
+     .owner      = THIS_MODULE,
+     .open       = proc_read_dbg_seq_open,
+@@ -364,6 +367,15 @@ static struct file_operations g_proc_fil
+     .llseek     = seq_lseek,
+     .release    = single_release,
+ };
++#else
++static struct proc_ops g_proc_file_vectoring_dbg_seq_fops = {
++    .proc_open    = proc_read_dbg_seq_open,
++    .proc_read    = seq_read,
++    .proc_write   = proc_write_dbg,
++    .proc_lseek   = seq_lseek,
++    .proc_release = single_release,
++};
++#endif
+ static int proc_read_dbg_seq_open(struct inode *inode, struct file *file)
+ {
+--- a/src/vectoring/ifxmips_vectoring_test.c
++++ b/src/vectoring/ifxmips_vectoring_test.c
+@@ -1,6 +1,8 @@
++#include <linux/version.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/proc_fs.h>
++#include <linux/seq_file.h>
+ #include "ifxmips_vectoring_stub.h"
+@@ -82,6 +84,7 @@ static int proc_write_vectoring(struct f
+     return count;
+ }
++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
+ static struct file_operations g_proc_file_vectoring_seq_fops = {
+     .owner      = THIS_MODULE,
+     .open       = proc_read_vectoring_seq_open,
+@@ -90,6 +93,15 @@ static struct file_operations g_proc_fil
+     .llseek     = seq_lseek,
+     .release    = single_release,
+ };
++#else
++static struct proc_ops g_proc_file_vectoring_seq_fops = {
++    .proc_open    = proc_read_vectoring_seq_open,
++    .proc_read    = seq_read,
++    .proc_write   = proc_write_vectoring,
++    .proc_lseek   = seq_lseek,
++    .proc_release = single_release,
++};
++#endif
+ static int proc_read_vectoring_seq_open(struct inode *inode, struct file *file)
+ {
diff --git a/package/kernel/lantiq/ltq-vectoring/patches/100-cleanup.patch b/package/kernel/lantiq/ltq-vectoring/patches/100-cleanup.patch
new file mode 100644 (file)
index 0000000..2b00673
--- /dev/null
@@ -0,0 +1,73 @@
+--- a/src/vectoring/ifxmips_vectoring.c
++++ b/src/vectoring/ifxmips_vectoring.c
+@@ -325,7 +325,7 @@ static int proc_write_dbg(struct file *f
+             else
+                 printk(dbg_enable_mask_str[i] + 1);
+         }
+-        printk("] > /proc/vectoring\n");
++        printk("] > /proc/driver/vectoring\n");
+     }
+     if ( f_enable )
+@@ -433,11 +433,10 @@ static int __init vectoring_init(void)
+ {
+     struct proc_dir_entry *res;
+-    res = proc_create("vectoring",
++    res = proc_create("driver/vectoring",
+                               S_IRUGO|S_IWUSR,
+                               0,
+                               &g_proc_file_vectoring_dbg_seq_fops);
+-    printk("res = %p\n", res);
+     register_netdev_event_handler();
+     g_ptm_net_dev = dev_get_by_name(&init_net, "ptm0");
+@@ -460,7 +459,7 @@ static void __exit vectoring_exit(void)
+     unregister_netdev_event_handler();
+-    remove_proc_entry("vectoring", NULL);
++    remove_proc_entry("driver/vectoring", NULL);
+ }
+ module_init(vectoring_init);
+--- a/src/vectoring/ifxmips_vectoring_test.c
++++ b/src/vectoring/ifxmips_vectoring_test.c
+@@ -79,7 +79,7 @@ static int proc_write_vectoring(struct f
+         }
+     }
+     else
+-        printk("echo send <size> > /proc/eth/vectoring\n");
++        printk("echo send <size> > /proc/driver/vectoring_test\n");
+     return count;
+ }
+@@ -112,9 +112,7 @@ static __init void proc_file_create(void
+ {
+     struct proc_dir_entry *res;
+-//    g_proc_dir = proc_mkdir("eth", NULL);
+-
+-    res = proc_create("eth/vectoring",
++    res = proc_create("driver/vectoring_test",
+                             S_IRUGO|S_IWUSR,
+                             g_proc_dir,
+                       &g_proc_file_vectoring_seq_fops);
+@@ -122,10 +120,7 @@ static __init void proc_file_create(void
+ static __exit void proc_file_delete(void)
+ {
+-    remove_proc_entry("vectoring",
+-                      g_proc_dir);
+-
+-    remove_proc_entry("eth", NULL);
++    remove_proc_entry("driver/vectoring_test", NULL);
+ }
+@@ -151,3 +146,5 @@ static void __exit vectoring_test_exit(v
+ module_init(vectoring_test_init);
+ module_exit(vectoring_test_exit);
++
++MODULE_LICENSE("GPL");
diff --git a/package/kernel/lantiq/ltq-vectoring/patches/200-compat.patch b/package/kernel/lantiq/ltq-vectoring/patches/200-compat.patch
new file mode 100644 (file)
index 0000000..04c6880
--- /dev/null
@@ -0,0 +1,120 @@
+--- a/src/vectoring/ifxmips_vectoring.c
++++ b/src/vectoring/ifxmips_vectoring.c
+@@ -35,6 +35,8 @@
+ #include <linux/module.h>
+ #include <linux/etherdevice.h>
+ #include <linux/proc_fs.h>
++#include <linux/pkt_sched.h>
++#include <linux/workqueue.h>
+ /*
+  *  Chip Specific Head File
+@@ -88,6 +90,7 @@ static void dump_skb(struct sk_buff *skb
+ static void ltq_vectoring_priority(uint32_t priority);
++static void xmit_work_handler(struct work_struct *);
+ /*
+  * ####################################
+@@ -118,9 +121,11 @@ struct erb_head {
+ static struct notifier_block g_netdev_event_handler_nb = {0};
+ static struct net_device *g_ptm_net_dev = NULL;
+-static uint32_t vector_prio = 0;
++static uint32_t vector_prio = TC_PRIO_CONTROL;
+ static int g_dbg_enable = 0;
++DECLARE_WORK(xmit_work, xmit_work_handler);
++struct sk_buff_head xmit_queue;
+ /*
+@@ -129,9 +134,16 @@ static int g_dbg_enable = 0;
+  * ####################################
+  */
++static void xmit_work_handler(__attribute__((unused)) struct work_struct *work) {
++      struct sk_buff *skb;
++
++      while ((skb = skb_dequeue(&xmit_queue)) != NULL) {
++              dev_queue_xmit(skb);
++      }
++}
++
+ static int mei_dsm_cb_func(unsigned int *p_error_vector)
+ {
+-    int rc, ret;
+     struct sk_buff *skb_list = NULL;
+     struct sk_buff *skb;
+     struct erb_head *erb;
+@@ -179,7 +191,6 @@ static int mei_dsm_cb_func(unsigned int
+         }
+     }
+-    rc = 0;
+     sent_size = 0;
+     segment_code = 0;
+     while ( (skb = skb_list) != NULL ) {
+@@ -197,24 +208,23 @@ static int mei_dsm_cb_func(unsigned int
+             segment_code |= 0xC0;
+         ((struct erb_head *)skb->data)->segment_code = segment_code;
+-        skb->cb[13] = 0x5A; /* magic number indicating forcing QId */
+-        skb->cb[15] = 0x00; /* highest priority queue */
+-              skb->priority = vector_prio;
++        skb_reset_mac_header(skb);
++        skb_set_network_header(skb, offsetof(struct erb_head, llc_header));
++        skb->protocol = htons(ETH_P_802_2);
++        skb->priority = vector_prio;
+         skb->dev = g_ptm_net_dev;
+         dump_skb(skb, ~0, "vectoring TX", 0, 0, 1, 0);
+-        ret = g_ptm_net_dev->netdev_ops->ndo_start_xmit(skb, g_ptm_net_dev);
+-        if ( rc == 0 )
+-            rc = ret;
++        skb_queue_tail(&xmit_queue, skb);
++        schedule_work(&xmit_work);
+         segment_code++;
+     }
+     *p_error_vector = 0;    /* notify DSL firmware that ERB is sent */
+-    ASSERT(rc == 0, "dev_queue_xmit fail - %d", rc);
+-    return rc;
++    return 0;
+ }
+ static void ltq_vectoring_priority(uint32_t priority)
+ {
+@@ -242,7 +252,7 @@ static int netdev_event_handler(struct n
+         return NOTIFY_DONE;
+     netif = netdev_notifier_info_to_dev(netdev);
+-    if ( strcmp(netif->name, "ptm0") != 0 )
++    if ( strcmp(netif->name, "dsl0") != 0 )
+         return NOTIFY_DONE;
+     g_ptm_net_dev = event == NETDEV_REGISTER ? netif : NULL;
+@@ -438,8 +448,10 @@ static int __init vectoring_init(void)
+                               0,
+                               &g_proc_file_vectoring_dbg_seq_fops);
++    skb_queue_head_init(&xmit_queue);
++
+     register_netdev_event_handler();
+-    g_ptm_net_dev = dev_get_by_name(&init_net, "ptm0");
++    g_ptm_net_dev = dev_get_by_name(&init_net, "dsl0");
+     if ( g_ptm_net_dev != NULL )
+         dev_put(g_ptm_net_dev);
+@@ -459,6 +471,8 @@ static void __exit vectoring_exit(void)
+     unregister_netdev_event_handler();
++    flush_scheduled_work();
++
+     remove_proc_entry("driver/vectoring", NULL);
+ }