--- /dev/null
+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))
--- /dev/null
+--- 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)
+ {
--- /dev/null
+--- 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");
--- /dev/null
+--- 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);
+ }
+