diff --git a/Documentation/devicetree/bindings/net/intel,falconmx-bm.txt b/Documentation/devicetree/bindings/net/intel,falconmx-bm.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8defde0dda6432d56cf16e42ae6235a2a0223c16
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/intel,falconmx-bm.txt
@@ -0,0 +1,13 @@
+Intel FALCON-MX BM driver Device Tree Bindings
+-------------------------------------------------------------
+
+ - compatible:          "intel,falconmx-bm"
+ - reg:                 TODO:
+
+Examples:
+
+bm@0 {
+        compatible = "intel,falconmx-bm";
+        reg = <0x00>;
+};
+
diff --git a/Documentation/pp_qos_debugfs.txt b/Documentation/pp_qos_debugfs.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e763e7236b76da2897db3c5ff025d59ec0ba7801
--- /dev/null
+++ b/Documentation/pp_qos_debugfs.txt
@@ -0,0 +1,133 @@
+pov4 qos debugfs API
+====================
+
+Each qos device will have its own directory under DEBUGFS_ROOT/ppv4_qos. So the directory for first device
+is DEBUGFS_ROOT/ppv4_qos/qos0, the second will have DEBUGFS_ROOT/ppv4_qos/qos1 and so on. 
+
+The files for each device are:
+
+--w------- 1 root root 0   1 16:50 cmd
+--w------- 1 root root 0   1 16:50 ctrl
+-r-------- 1 root root 0   1 16:50 geninfo
+-rw------- 1 root root 0   1 16:50 node
+-r-------- 1 root root 0   1 16:50 nodeinfo
+-r-------- 1 root root 0   1 16:50 phy2id
+-r-------- 1 root root 0   1 16:50 stat
+
+cmd and ctrl are for internal use, normally should not used by clients. 
+
+For the next explenation I will assume the following configuration:
+3 ports - 0, 7, 26 with logical ids 0 1 2 respectively
+10 queues:  
+	- first 4 iqueues have logical ids 3 4 5 6 and are linked to port 0, 
+	- 3 queues with logical ids 7 8 9 linked to port 7
+	- 3 queues with logical ids 10 11 12 linked to port 26
+
+I will define the term node_phy as the node number where qos scheduler stores information about node.
+For ports and only for them, the node_phy designates the port number, sp port 26 has node_phy 26
+
+
+General system info (geninfo)
+=============================
+Gives general information about the system:
+
+root@LEDE:/sys/kernel/debug/ppv4_qos/qos0# cat geninfo
+Driver version: 1.0.0-fl
+FW version:     major(1) minor(0) build(0)
+Used nodes:     13
+Ports:          3
+Scheds:         0
+Queues:         10
+Internals:      0
+
+Per node information
+====================
+
+File node defines the current node and it interpreted differently by the files. 
+
+Node info (nodeinfo)
+====================
+
+Most of the data is read from hardware(through firmware) and not from driver's database.
+Interprets the content of node file as a logical id of the node for which we want to retrieve info.
+
+root@LEDE:/sys/kernel/debug/ppv4_qos/qos0# echo 1 > node
+root@LEDE:/sys/kernel/debug/ppv4_qos/qos0# cat nodeinfo
+1(7) - Port: suspended(No) internal node(No)
+7(132) 8(133) 9(134)
+Bandwidth: 0 Kbps
+
+We insert 1 to node, meaning we want info about the node whose logical id is 1.
+First line: logical id 1 is mapped to node_phy 7, node is a port, it is not suspended and its not internal node
+Second line: node direct children are logical nodes 7 8 and 9 which have repectively node_phys of 132 133 and 134
+Third line: node's bandwidth limit
+
+Lets get info about the first queue linked to this port:
+root@LEDE:/sys/kernel/debug/ppv4_qos/qos0# echo 7 > node
+root@LEDE:/sys/kernel/debug/ppv4_qos/qos0# cat nodeinfo
+7(132) - Queue: suspended(No) internal node(No)
+7(132) ==> 1(7)
+Physical queue: 235
+Port: 7
+Bandwidth: 0 Kbps
+
+First line: logical id 7 mapped to node_phy 128, node is a queue, it is not suspended and its not internal node
+Second line: ancestors of node, starting with the node itself which is logical id 7 (node_phy 132), its first ancestor is logical id 1 (node_phy 7)
+Third line: physical queue of this node is queue 235
+Fourth line: queue is linked (possibly through schedulers) to port 7 - we could see this also from the second line, the node_phy of the last ancestor is the port number 
+
+Node stat (stat)
+================
+
+Interprets the content of node file as a logical id of the node for which we want to retrieve stat.
+Statistics are aggregated.
+
+root@LEDE:/sys/kernel/debug/ppv4_qos/qos0# ping -5 3 192.168.1.2
+PING 192.168.1.2 (192.168.1.2): 56 data bytes
+64 bytes from 192.168.1.2: seq=0 ttl=64 time=34.501 ms
+64 bytes from 192.168.1.2: seq=1 ttl=64 time=12.055 ms
+64 bytes from 192.168.1.2: seq=2 ttl=64 time=26.934 ms
+64 bytes from 192.168.1.2: seq=3 ttl=64 time=12.084 ms
+64 bytes from 192.168.1.2: seq=4 ttl=64 time=29.290 ms
+
+--- 192.168.1.2 ping statistics ---
+5 packets transmitted, 5 packets received, 0% packet loss
+round-trip min/avg/max = 12.055/22.972/34.501 ms
+root@LEDE:/sys/kernel/debug/ppv4_qos/qos0# cat stat
+7(132) - Queue
+queue_packets_occupancy:0
+queue_bytes_occupancy:0
+total_packets_accepted:6		/**** No idea why it is 6 and not 5 (maybe arp ?) ****/
+total_packets_dropped:0
+total_packets_red_dropped:0
+total_bytes_accepted:598
+total_bytes_dropped:0
+root@LEDE:/sys/kernel/debug/ppv4_qos/qos0# ping -c 3 192.168.1.2
+PING 192.168.1.2 (192.168.1.2): 56 data bytes
+64 bytes from 192.168.1.2: seq=0 ttl=64 time=30.657 ms
+64 bytes from 192.168.1.2: seq=1 ttl=64 time=56.920 ms
+64 bytes from 192.168.1.2: seq=2 ttl=64 time=12.592 ms
+
+--- 192.168.1.2 ping statistics ---
+3 packets transmitted, 3 packets received, 0% packet loss
+round-trip min/avg/max = 12.592/33.389/56.920 ms
+root@LEDE:/sys/kernel/debug/ppv4_qos/qos0# cat stat
+7(132) - Queue
+queue_packets_occupancy:0
+queue_bytes_occupancy:0
+total_packets_accepted:9
+total_packets_dropped:0
+total_packets_red_dropped:0
+total_bytes_accepted:916
+total_bytes_dropped:0
+
+node_phy to id mapping
+======================
+
+Interprets the content of node file as a node_phy of the node for which we want to get the logical id.
+
+root@LEDE:/sys/kernel/debug/ppv4_qos/qos0# echo 7 > node
+root@LEDE:/sys/kernel/debug/ppv4_qos/qos0# cat phy2id
+1
+
+The logical id of node_phy 7 (aka port 7) is 1 
diff --git a/drivers/net/ethernet/lantiq/cqm/cbm_wrapper.c b/drivers/net/ethernet/lantiq/cqm/cbm_wrapper.c
index 4653a4890a265ae07b3eef9e5916382c310c004c..4dca44230e6f782acbadce8b482f74e872b600fc 100644
--- a/drivers/net/ethernet/lantiq/cqm/cbm_wrapper.c
+++ b/drivers/net/ethernet/lantiq/cqm/cbm_wrapper.c
@@ -1,14 +1,5 @@
 #include "cqm_common.h"
 static const struct cbm_ops *g_cbm_ops;
-int cbm_buff_resv_bytes_get(int cbm_inst, int size)
-{
-	if (g_cbm_ops->cbm_buff_resv_bytes_get)
-		return g_cbm_ops->cbm_buff_resv_bytes_get(cbm_inst, size);
-	else
-		return CBM_FAILURE;
-}
-EXPORT_SYMBOL(cbm_buff_resv_bytes_get);
-
 void cbm_setup_DMA_p2p(void)
 {
 	if (g_cbm_ops->cbm_setup_DMA_p2p)
diff --git a/drivers/net/ethernet/lantiq/cqm/cqm_common.h b/drivers/net/ethernet/lantiq/cqm/cqm_common.h
index d0d2ece5ea2cecddddc8fcbed509c22f19f9e0b7..8aeabf6e8f2491f0addb4b26a55fe2813affd7c5 100644
--- a/drivers/net/ethernet/lantiq/cqm/cqm_common.h
+++ b/drivers/net/ethernet/lantiq/cqm/cqm_common.h
@@ -195,7 +195,6 @@ struct cbm_ops {
 	s32 (*pon_deq_cntr_get)(int port, u32 *count);
 	void (*cbm_setup_DMA_p2p)(void);
 	int (*cbm_turn_on_DMA_p2p)(void);
-	int (*cbm_buff_resv_bytes_get)(int, int);
 };
 
 static inline void set_val(void __iomem *reg, u32 val, u32 mask, u32 offset)
diff --git a/drivers/net/ethernet/lantiq/cqm/falconmx/Makefile b/drivers/net/ethernet/lantiq/cqm/falconmx/Makefile
index bdf790ce6119a582502c110f7f3c2139ba6cee6a..ccc6be6814e47b83801566ffe5da9bc0c2457d28 100644
--- a/drivers/net/ethernet/lantiq/cqm/falconmx/Makefile
+++ b/drivers/net/ethernet/lantiq/cqm/falconmx/Makefile
@@ -4,4 +4,5 @@
 
 obj-$(CONFIG_LTQ_CBM) += cqm.o cqm_config.o cqm_proc.o
 #CFLAGS_cqm.o := -DDEBUG
+ccflags-y       += -Iinclude/net
 
diff --git a/drivers/net/ethernet/lantiq/cqm/falconmx/cqm.c b/drivers/net/ethernet/lantiq/cqm/falconmx/cqm.c
index 0c9d2ce36f39bd1e5bb7dc84be184f9a407be217..192b159e3fcc4790a9fd700ca75a33a7b54995c6 100644
--- a/drivers/net/ethernet/lantiq/cqm/falconmx/cqm.c
+++ b/drivers/net/ethernet/lantiq/cqm/falconmx/cqm.c
@@ -2,6 +2,18 @@
 #include "cqm_proc.h"
 #include "../cqm_dev.h"
 #include <net/datapath_proc_api.h>
+#include <net/switch_api/gsw_flow_ops.h>
+
+#ifdef CONFIG_LTQ_PPV4_BM_SLIM
+#define CONFIG_CQM_SIZE0_BUF_SIZE 2048
+#define CONFIG_CQM_SIZE1_BUF_SIZE 2048
+#define CONFIG_CQM_SIZE2_BUF_SIZE 2048
+#define CONFIG_CQM_SIZE3_BUF_SIZE 2048
+#define CONFIG_CQM_NUM_SIZE0_BUF 0x80
+#define CONFIG_CQM_NUM_SIZE1_BUF 0x80
+#define CONFIG_CQM_NUM_SIZE2_BUF 0x80
+#define CONFIG_CQM_NUM_SIZE3_BUF 0x80
+#endif
 
 static const char cqm_name[] = "cqm";
 static void __iomem *bufreq[CQM_FMX_NUM_POOLS];
@@ -45,6 +57,33 @@ struct cqm_egp_map epg_lookup_table[] = {
 
 struct cqm_buf_dbg_cnt cqm_dbg_cntrs[CQM_MAX_POLICY_NUM][CQM_MAX_POOL_NUM];
 
+static int get_buff_resv_bytes(int cbm_inst, int size)
+{
+	int bsl_thr_val = 0;
+
+	dev_info(cqm_ctrl->dev, "BSL thres %d\n", BSL_THRES);
+
+	switch (size) {
+	case 0:
+		bsl_thr_val = CONFIG_CQM_SIZE0_BUF_SIZE - BSL_THRES;
+		break;
+	case 1:
+		bsl_thr_val = CONFIG_CQM_SIZE1_BUF_SIZE - BSL_THRES;
+		break;
+	case 2:
+		bsl_thr_val = CONFIG_CQM_SIZE2_BUF_SIZE - BSL_THRES;
+		break;
+	case 3:
+		bsl_thr_val = CONFIG_CQM_SIZE3_BUF_SIZE - BSL_THRES;
+		break;
+	default:
+		dev_err(cqm_ctrl->dev, "%s: unsupported size %d\n", __func__,
+			size);
+		break;
+	}
+	return bsl_thr_val;
+}
+
 int find_dqm_port_type(int port)
 {
 	if ((port >= DQM_CPU_START_ID) && (port <= DQM_CPU_END_ID))
@@ -1747,7 +1786,6 @@ s32 cqm_cpu_port_get(struct cbm_cpu_port_data *data, u32 flags)
 	int i;
 	int valid_type = 0;
 	u32 type;
-	void *txpush = cqm_ctrl->txpush;
 	struct cbm_tx_push *ptr;
 
 	for (i = 0; i < CQM_MAX_CPU; i++) {
@@ -1761,10 +1799,11 @@ s32 cqm_cpu_port_get(struct cbm_cpu_port_data *data, u32 flags)
 		ptr->deq_port = i;
 		ptr->tx_ring_size = 1;
 		ptr->tx_b_credit = 0;
-		ptr->tx_ring_addr = (u32)(txpush + (TXPUSH_CMD_RX_EGP_1 * i)) &
-				     0x7FFFFFF;
+		ptr->tx_ring_addr = (u32)(cqm_ctrl->txpush +
+					  (TXPUSH_CMD_RX_EGP_1 * i)) &
+					  0x7FFFFF;
 		ptr->tx_ring_offset = TXPUSH_CMD_RX_EGP_1;
-		ptr->tx_pkt_credit = 2;
+		ptr->tx_pkt_credit = dqm_port_info[i].dq_txpush_num;
 	}
 	return CBM_SUCCESS;
 }
@@ -1801,10 +1840,10 @@ static void fill_dp_alloc_data(struct cbm_dp_alloc_data *data, int dp,
 		p_info->dma_ch = chan;
 		snprintf(p_info->dma_chan_str, DMA_CH_STR_LEN, "port%d", port);
 		data->dma_chan = p_info->dma_ch;
-		data->tx_pkt_credit = p_info->deq_info.num_desc;
+		data->tx_pkt_credit = p_info->dq_txpush_num;
 	} else {
 		data->flags |= CBM_PORT_PKT_CRDT_SET;
-		data->tx_pkt_credit = p_info->deq_info.num_desc;
+		data->tx_pkt_credit = p_info->dq_txpush_num;
 	}
 	data->flags |= CBM_PORT_RING_ADDR_SET |
 		       CBM_PORT_RING_SIZE_SET |
@@ -2050,8 +2089,12 @@ static s32 handle_dma_chnl_init(int port, u32 flags)
 static s32 dp_enable(struct module *owner, u32 port_id,
 		     struct cbm_dp_en_data *data, u32 flags, u32 alloc_flags)
 {
-	int port, type;
+	int port, type, i;
 	u32 val;
+	struct core_ops *ops;
+	GSW_PMAC_Glbl_Cfg_t glbl_cfg;
+
+	static bool set_bsl;
 	void *deq = cqm_ctrl->deq;
 
 	port = data->deq_port;
@@ -2073,9 +2116,9 @@ static s32 dp_enable(struct module *owner, u32 port_id,
 			pib_port_enable(port, 0);
 		} else {
 			val = CFG_PON_EGP_26_DQREQ_MASK |
-			      CFG_PON_EGP_26_BUFRTN_MASK |
-			      CFG_PON_EGP_26_BFBPEN_MASK |
-			      CFG_PON_EGP_26_DQPCEN_MASK;
+				CFG_PON_EGP_26_BUFRTN_MASK |
+				CFG_PON_EGP_26_BFBPEN_MASK |
+				CFG_PON_EGP_26_DQPCEN_MASK;
 			val |= ((data->deq_port << CFG_DMA_EGP_7_EPMAP_POS) &
 				CFG_DMA_EGP_7_EPMAP_MASK);
 			cbm_w32((deq + DQ_PON_PORT((port), cfg)),
@@ -2090,6 +2133,20 @@ static s32 dp_enable(struct module *owner, u32 port_id,
 		return CBM_FAILURE;
 	break;
 	}
+	if (!set_bsl) {
+		ops = gsw_get_swcore_ops(0);
+		for (i = 0; i < 2; i++) {
+			glbl_cfg.nPmacId = i;
+			ops->gsw_pmac_ops.Pmac_Gbl_CfgGet(ops, &glbl_cfg);
+			glbl_cfg.nMaxJumboLen = get_buff_resv_bytes(0, 3);
+			glbl_cfg.nBslThreshold[0] = get_buff_resv_bytes(0, 0);
+			glbl_cfg.nBslThreshold[1] = get_buff_resv_bytes(0, 1);
+			glbl_cfg.nBslThreshold[2] = get_buff_resv_bytes(0, 2);
+			ops->gsw_pmac_ops.Pmac_Gbl_CfgSet(ops, &glbl_cfg);
+		}
+		set_bsl = true;
+	}
+
 	return CBM_SUCCESS;
 }
 
@@ -2718,6 +2775,7 @@ static int init_cqm_basic(struct platform_device *pdev)
 
 static int qos_init(struct platform_device *pdev)
 {
+#ifdef CONFIG_LTQ_PPV4_QOS_SLIM
 	u32 adj_size;
 	u32 adjusted_qos_ram_base;
 	u32 size = CONFIG_CQM_QMGR_NUM_DESC * 16;
@@ -2744,6 +2802,9 @@ static int qos_init(struct platform_device *pdev)
 			&adj_size,
 			64);
 	qos_config((void *)__pa(adjusted_qos_ram_base));
+#else
+#warning Updated "qos_init" implementation needed!
+#endif
 	return CBM_SUCCESS;
 }
 
@@ -2794,11 +2855,10 @@ static int pool_config(struct platform_device *pdev, int p, u32 buf_size,
 		panic("Total mem alloc exceeds CMA zone %d\n",
 		      cqm_ctrl->max_mem_alloc);
 	cqm_ctrl->bm_buf_base[p] = dma_alloc_attrs(&pdev->dev, size,
-						   &cqm_ctrl->dma_hndl_p[p],
-						   GFP_KERNEL,
-						   DMA_ATTR_NON_CONSISTENT);
-	dev_dbg(cqm_ctrl->dev, "qos bm buf 0x%p\n",
-		cqm_ctrl->bm_buf_base[p]);
+			&cqm_ctrl->dma_hndl_p[p],
+			GFP_KERNEL,
+			DMA_ATTR_NON_CONSISTENT);
+	dev_dbg(cqm_ctrl->dev, "qos bm buf 0x%p\n", cqm_ctrl->bm_buf_base[p]);
 	if (!cqm_ctrl->bm_buf_base[p]) {
 		dev_err(cqm_ctrl->dev, "Error in pool %d buffer allocation\n",
 			p);
@@ -2817,11 +2877,10 @@ static int pool_config(struct platform_device *pdev, int p, u32 buf_size,
 	return CBM_SUCCESS;
 }
 
-#if 1
 static int bm_init(struct platform_device *pdev)
 {
 	struct bmgr_pool_params p_params;
-	u8 i;
+	u8 i, j;
 	int result, pool = 0;
 	u32 buf_size;
 	u32 start_low;
@@ -2847,7 +2906,9 @@ static int bm_init(struct platform_device *pdev)
 		panic("pool %d allocation failed\n", pool);
 	pool++;
 
+#ifdef CONFIG_LTQ_PPV4_BM_SLIM
 	bmgr_driver_init();
+#endif
 	for (i = 0; i < CQM_FMX_NUM_BM_POOLS; i++) {
 		p_params.group_id = 0;
 		p_params.num_buffers = bm_pool_conf[i].buf_frm_num;
@@ -2867,12 +2928,14 @@ static int bm_init(struct platform_device *pdev)
 		bmgr_pool_configure(&p_params, &i);
 	}
 
-	for (i = 0; i < CQM_FMX_NUM_BM_POLICY; i++)
-		bmgr_policy_configure(&policy_params[i], &i);
+	for (j = 0; j < CQM_FMX_NUM_BM_POLICY; j++)
+		bmgr_policy_configure(&policy_params[j], &i);
+
+#ifdef CONFIG_LTQ_PPV4_BM_SLIM
 	new_init_bm();
+#endif
 	return CBM_SUCCESS;
 }
-#endif
 
 static int cbm_hw_init(struct platform_device *pdev)
 {
@@ -3226,6 +3289,7 @@ static int conf_deq_cpu_port(const struct dqm_cpu_port *cpu_ptr)
 	p_info->cbm_buf_free_base = deq + DQ_CPU_PORT(port, ptr_rtn_dw2);
 	p_info->num_free_entries = (port > 3) ? 32 : 1;
 	p_info->cpu_port_type = cpu_ptr->cpu_port_type;
+	p_info->dq_txpush_num = cpu_ptr->txpush_desc;
 	p_info->valid = 1;
 
 	dev_dbg(cqm_ctrl->dev, "0x%p %d %d %d 0x%p %d\n",
@@ -3277,6 +3341,7 @@ static int conf_deq_dma_port(const struct dqm_dma_port *dma_ptr)
 		p_info->deq_info.dma_tx_chan = dma_ptr->dma_chan + j;
 		p_info->cbm_buf_free_base = NULL;
 		p_info->num_free_entries = 0;
+		p_info->dq_txpush_num = dma_ptr->txpush_desc;
 		if (!get_matching_flag(&flags, index))
 			p_info->egp_type = flags;
 		p_info->dma_dt_ch = dma_ptr->dma_chan + j;
@@ -3401,33 +3466,6 @@ static void cqm_rst(struct cqm_data *lpp)
 	cqm_rst_deassert(lpp);
 }
 
-int get_buff_resv_bytes(int cbm_inst, int size)
-{
-	int bsl_thr_val = 0;
-
-	dev_info(cqm_ctrl->dev, "BSL thres %d\n", BSL_THRES);
-
-	switch (size) {
-	case 0:
-		bsl_thr_val = CONFIG_CQM_SIZE0_BUF_SIZE - BSL_THRES;
-		break;
-	case 1:
-		bsl_thr_val = CONFIG_CQM_SIZE1_BUF_SIZE - BSL_THRES;
-		break;
-	case 2:
-		bsl_thr_val = CONFIG_CQM_SIZE2_BUF_SIZE - BSL_THRES;
-		break;
-	case 3:
-		bsl_thr_val = CONFIG_CQM_SIZE3_BUF_SIZE - BSL_THRES;
-		break;
-	default:
-		dev_err(cqm_ctrl->dev, "%s: unsupported size %d\n", __func__,
-			size);
-		break;
-	}
-	return bsl_thr_val;
-}
-
 static const struct cbm_ops cqm_ops = {
 	.cbm_igp_delay_set = cqm_igp_delay_set,
 	.cbm_igp_delay_get = cqm_igp_delay_get,
@@ -3455,7 +3493,6 @@ static const struct cbm_ops cqm_ops = {
 	.pon_deq_cntr_get = pon_deq_cntr_get,
 	.set_lookup_qid_via_index = set_lookup_qid_via_index_fmx,
 	.get_lookup_qid_via_index = get_lookup_qid_via_idx_fmx,
-	.cbm_buff_resv_bytes_get = get_buff_resv_bytes,
 };
 
 static const struct of_device_id cqm_falconmx_match[] = {
diff --git a/drivers/net/ethernet/lantiq/cqm/falconmx/cqm.h b/drivers/net/ethernet/lantiq/cqm/falconmx/cqm.h
index ad1734fc7dd55f3a8f38c53bda368d5521f93b13..892003a3e053230e473d874955afa9091a534fef 100644
--- a/drivers/net/ethernet/lantiq/cqm/falconmx/cqm.h
+++ b/drivers/net/ethernet/lantiq/cqm/falconmx/cqm.h
@@ -472,6 +472,7 @@ struct cqm_dqm_port_info {
 	void		*cbm_buf_free_base;
 	u32	num_free_entries;/*!< Number of Free Port entries */
 	cbm_dq_info_t	deq_info;
+	u32 dq_txpush_num;
 	u32 egp_type;
 	char dma_chan_str[DMA_CH_STR_LEN];
 	u32 cpu_port_type;
diff --git a/drivers/net/ethernet/lantiq/cqm/falconmx/cqm_config.c b/drivers/net/ethernet/lantiq/cqm/falconmx/cqm_config.c
index 0490c322fcdf1404623882ea3f5be5519a66174e..4a36f9fd5e52923733aaca49fe8bdc5e95c89124 100644
--- a/drivers/net/ethernet/lantiq/cqm/falconmx/cqm_config.c
+++ b/drivers/net/ethernet/lantiq/cqm/falconmx/cqm_config.c
@@ -79,25 +79,29 @@ const struct cqm_config falcon_cqm_config[] = {
 	.type = DQM_CPU_TYPE,
 	.data.dqm_cpu.port = 0,
 	.data.dqm_cpu.cpu_port_type = DP_F_DEQ_CPU,
-	.data.dqm_cpu.num_desc = 2
+	.data.dqm_cpu.num_desc = 2,
+	.data.dqm_cpu.txpush_desc = 2,
 	},
 	{
 	.type = DQM_CPU_TYPE,
 	.data.dqm_cpu.port = 4,
 	.data.dqm_cpu.cpu_port_type = 1,
-	.data.dqm_cpu.num_desc = 32
+	.data.dqm_cpu.num_desc = 32,
+	.data.dqm_cpu.txpush_desc = 32,
 	},
 	{
 	.type = DQM_CPU_TYPE,
 	.data.dqm_cpu.port = 5,
 	.data.dqm_cpu.cpu_port_type = 1,
 	.data.dqm_cpu.num_desc = 32,
+	.data.dqm_cpu.txpush_desc = 32,
 	},
 	{
 	.type = DQM_CPU_TYPE,
 	.data.dqm_cpu.port = 6,
 	.data.dqm_cpu.cpu_port_type = 1,
-	.data.dqm_cpu.num_desc = 32
+	.data.dqm_cpu.num_desc = 32,
+	.data.dqm_cpu.txpush_desc = 32,
 	},
 	{
 	.type = DQM_DMA_TYPE,
@@ -107,6 +111,7 @@ const struct cqm_config falcon_cqm_config[] = {
 	.data.dqm_dma.dma_chan = 0,
 	.data.dqm_dma.port_enable = 1,
 	.data.dqm_dma.num_desc = 8,
+	.data.dqm_dma.txpush_desc = 8,
 	},
 	{
 	.type = DQM_PON_TYPE,
@@ -116,6 +121,7 @@ const struct cqm_config falcon_cqm_config[] = {
 	.data.dqm_dma.dma_chan = 0,
 	.data.dqm_dma.port_enable = 1,
 	.data.dqm_dma.num_desc = 16,
+	.data.dqm_dma.txpush_desc = 8,
 	},
 	{
 	.type = EQM_CPU_TYPE,
diff --git a/drivers/net/ethernet/lantiq/cqm/falconmx/cqm_config.h b/drivers/net/ethernet/lantiq/cqm/falconmx/cqm_config.h
index 1e7196e968f4a788d2ddfd957f10633a426a7461..b82f5f002fd3f14fbdf3815b0cb342293b4dccca 100644
--- a/drivers/net/ethernet/lantiq/cqm/falconmx/cqm_config.h
+++ b/drivers/net/ethernet/lantiq/cqm/falconmx/cqm_config.h
@@ -1,7 +1,11 @@
 #ifndef __CQM_CONFIG_H__
 #define __CQM_CONFIG_H__
 
+#ifdef CONFIG_LTQ_PPV4_BM_SLIM
 #include <net/bm_drv_slim.h>
+#else
+#include "../../ppv4/bm/pp_bm_drv.h"
+#endif
 
 #define CQM_FMX_NUM_BM_POOLS	4
 #define CQM_FMX_NUM_POOLS	(CQM_FMX_NUM_BM_POOLS + 1)
@@ -50,6 +54,7 @@ struct dqm_dma_port {
 	u32 dma_chan;
 	u32 port_enable;
 	u32 num_desc;
+	u32 txpush_desc;
 };
 
 struct dqm_pon_port {
@@ -61,6 +66,7 @@ struct dqm_pon_port {
 	u32 dma_chan;
 	u32 port_enable;
 	u32 num_desc;
+	u32 txpush_desc;
 };
 
 struct dqm_cpu_port {
@@ -68,6 +74,7 @@ struct dqm_cpu_port {
 	u32 queue;
 	u32 cpu_port_type;
 	u32 num_desc;
+	u32 txpush_desc;
 };
 
 struct eqm_dma_port {
@@ -115,4 +122,5 @@ extern const struct cqm_config falcon_cqm_config[];
 extern struct cqm_ctrl g_fmx_ctrl;
 extern struct cqm_bm_pool_config bm_pool_conf[CQM_FMX_NUM_POOLS];
 extern struct bmgr_policy_params policy_params[CQM_FMX_NUM_BM_POLICY];
+
 #endif /* __CQM_CONFIG_H__ */
diff --git a/drivers/net/ethernet/lantiq/datapath/Kconfig b/drivers/net/ethernet/lantiq/datapath/Kconfig
index c431024c9dd414c0b01364eec75b6c93f1a55444..475af401a682b3ea5e0d0b19338ddaed7b244d28 100644
--- a/drivers/net/ethernet/lantiq/datapath/Kconfig
+++ b/drivers/net/ethernet/lantiq/datapath/Kconfig
@@ -9,8 +9,7 @@ menuconfig LTQ_DATAPATH
 	  Datapath Lib is to provide common rx/tx wrapper Lib without taking
 	  care of much HW knowledge and also provide common interface for legacy
 	  devices and different HW like to CBM or LRO.
-	  Take note:
-	    All devices need to register to datapath Lib first
+	  Take note: All devices need to register to datapath Lib first
 
 if LTQ_DATAPATH
 config LTQ_DATAPATH_ACA_CSUM_WORKAROUND
@@ -28,61 +27,76 @@ config LTQ_DATAPATH_MANUAL_PARSE
 	depends on LTQ_DATAPATH
 	default y
 	---help---
-		Manual parse network protocol for tcp offloading
-		Only support limited tunnel yet
-		later need to enhance to support other tunnels
-		Also need to study to use network stack information
+	  Manual parse network protocol for tcp offloading
+	  Only support limited tunnel yet
+	  later need to enhance to support other tunnels
+	  Also need to study to use network stack information
+
 config LTQ_DATAPATH_COPY_LINEAR_BUF_ONLY
-        bool "Datapath Copy linear buffer only for skb"
-        default n
+	bool "Datapath Copy linear buffer only for skb"
+	default n
 	depends on LTQ_DATAPATH
-        ---help---
-           Datapath Copy linear buffer only for skb if need to alloc new buffer.
-		   For TSO/GSO case, it will not consider
-		   Make sure TSO/GSO always with enough header room to insert pmac header
-		   need to enhance in the future
+	---help---
+	  Datapath Copy linear buffer only for skb if need to alloc new buffer.
+	  For TSO/GSO case, it will not consider
+	  Make sure TSO/GSO always with enough header room to insert pmac header
+	  need to enhance in the future
+
 config LTQ_DATAPATH_DBG
 	bool "Datapath Debug Tool"
 	default y
 	depends on LTQ_DATAPATH
 	---help---
-	  Datapath Debug Tool is used to provide simple debug proc tool
-	  Each flag can be enabled/disabled easily
-	  Once this flag is enabled, the debugging information will be printed out
-	  otherwise, no debugging information for this flag will be printed
+	  Datapath Debug Tool is used to provide simple debug tool
+	  All other debug tools is based on it
+	  Once it is disabled, all other datapath debug tool disabled.
+	  By default had better enable it
+
+config LTQ_DATAPATH_LOOPETH
+	bool "Datapath Debug Tool to simulate datapath registration flow"
+	default y
+	depends on LTQ_DATAPATH_DBG
+	---help---
+	  Datapath Debug Tool to simulate different peripheral to register to datapath
+	  For example, it can simulate Fast WIFI/Litepath/Logical device
+	  Also it can simulate tcont and gem dev later.
+	  By default had better to be enabled
+
 config LTQ_DATAPATH_DBG_PROTOCOL_PARSE
-        bool "Datapath Debug Tool for hw checksum's protocol parsing"
-        default n
-        depends on LTQ_DATAPATH_DBG
-        ---help---
-          Datapath Debug Tool for hw checksum's protocol parsing
-		  Only for debugging purpose
-		  By default it should be disabled.
+	bool "Datapath Debug Tool for hw checksum's protocol parsing"
+	default n
+	depends on LTQ_DATAPATH_DBG
+	---help---
+	  Datapath Debug Tool for hw checksum's protocol parsing
+	  Only for debugging purpose
+	  By default it should be disabled.
 config LTQ_DATAPATH_EXTRA_DEBUG
 	bool "extra debugging support"
 	default n
 	depends on  LTQ_DATAPATH_DBG
 	---help---
-		This is to enable/disable extra strict debugging support.
-		This is useful during initial system bring up
-		It will affect performance
-		By default it should be disabled.
+	  This is to enable/disable extra strict debugging support.
+	  This is useful during initial system bring up
+	  It will affect performance
+	  By default it should be disabled.
 
 config LTQ_DATAPATH_SWDEV_TEST
 	bool "Test Switchdev Event"
 	default n
 	depends on  LTQ_DATAPATH_DBG && LTQ_DATAPATH_SWITCHDEV
 	---help---
-		This is to force enable macro CONFIG_SOC_SWITCHDEV_TESTING 
-		in order to test switchdev event
-		without real switchdev handling
+	  This is to force enable macro CONFIG_SOC_SWITCHDEV_TESTING
+	  in order to test switchdev event
+	  without real switchdev handling
+
 config LTQ_DATAPATH_SKB
-        bool "Datapath Skb Hack"
-        default n
-        depends on  LTQ_DATAPATH
-        ---help---
-          For Ethernet OAM and MPE FW purpose testing purpose, 
-	  It needs to hack SKB          
+	bool "Datapath Skb Hack"
+	default n
+	depends on  LTQ_DATAPATH
+	---help---
+	  For Ethernet OAM and MPE FW purpose testing purpose,
+	  It needs to hack SKB
+
 config LTQ_DATAPATH_MPE_FASTHOOK_TEST
 	bool "MPE Fast Hook Test"
 	default n
@@ -93,21 +107,30 @@ config LTQ_DATAPATH_MPE_FASTHOOK_TEST
 	  in order to support MPE FAST HOOK. The reason is that some network driver is
 	  pre-build out of this build system.
 	  The testing code by default is not checked in.
+
 config LTQ_DATAPATH_ETH_OAM
-        bool "ETH OAM SUPPORT"
-        default n
-        depends on  LTQ_DATAPATH_SKB
-        ---help---
-          Datapath Ethernet OAM support. Once it is enabled, it will add some fields in skb structure
-          in order to support MPE FAST HOOK. The reason is that some network driver is
-          pre-build out of this build system.
-          The testing code by default is not checked in.
+	bool "ETH OAM SUPPORT"
+	default n
+	depends on  LTQ_DATAPATH_SKB
+	---help---
+	  Datapath Ethernet OAM support. Once it is enabled, it will add some fields in skb structure
+	  in order to support MPE FAST HOOK. The reason is that some network driver is
+	  pre-build out of this build system.
+	  The testing code by default is not checked in.
+
 config LTQ_DATAPATH_SWITCHDEV
-        bool "Switchdev Support"
-        default n
-        depends on  LTQ_DATAPATH && NET_SWITCHDEV
-        ---help---
-          Switchdev support for different switch in datapath
+	bool "Switchdev Support"
+	default n
+	depends on  LTQ_DATAPATH && NET_SWITCHDEV
+	---help---
+	  Switchdev support for different switch in datapath
+
+config LTQ_DATAPATH_DDR_SIMULATE_GSWIP31
+	bool "Force FALCON-MX SOC"
+	default n
+	depends on LTQ_DATAPATH
+	---help---
+	  test falcon-mx HAL in GRX350 boards
 source "drivers/net/ethernet/lantiq/datapath/gswip31/Kconfig"
 source "drivers/net/ethernet/lantiq/datapath/gswip30/Kconfig"
 endif
diff --git a/drivers/net/ethernet/lantiq/datapath/Makefile b/drivers/net/ethernet/lantiq/datapath/Makefile
index 452bbc36c975fc6e85a1d3faadb0ff2a5d209072..aa4b3716cc9024ebcb1b754624b1cad8025947b0 100644
--- a/drivers/net/ethernet/lantiq/datapath/Makefile
+++ b/drivers/net/ethernet/lantiq/datapath/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_LTQ_DATAPATH) = datapath_api.o datapath_proc_api.o datapath_proc.o  datapath_misc.o datapath_notifier.o datapath_logical_dev.o datapath_instance.o datapath_platform_dev.o datapath_soc.o datapath_qos.o
+obj-$(CONFIG_LTQ_DATAPATH) = datapath_api.o datapath_proc_api.o datapath_proc.o  datapath_misc.o datapath_notifier.o datapath_logical_dev.o datapath_instance.o datapath_platform_dev.o datapath_soc.o datapath_qos.o datapath_proc_qos.o
 ifneq ($(CONFIG_LTQ_DATAPATH_LOOPETH),)
 obj-$(CONFIG_LTQ_DATAPATH) += datapath_loopeth_dev.o
 endif
diff --git a/drivers/net/ethernet/lantiq/datapath/datapath.h b/drivers/net/ethernet/lantiq/datapath/datapath.h
index 6ce2c277a2068bd3ad845dfc4eb1f795bff22ad3..062b6edb4089de9ce498b29309e883164d3ddf51 100644
--- a/drivers/net/ethernet/lantiq/datapath/datapath.h
+++ b/drivers/net/ethernet/lantiq/datapath/datapath.h
@@ -1,4 +1,4 @@
-/*
+ /*
  * Copyright (C) Intel Corporation
  * Author: Shao Guohua <guohua.shao@intel.com>
  *
@@ -17,8 +17,10 @@
 #include <linux/platform_device.h>
 #include <net/lantiq_cbm_api.h>
 
-#define PP_OLD_QOS_API
-#ifdef PP_OLD_QOS_API
+//#define CONFIG_LTQ_DATAPATH_DUMMY_QOS
+//#define DUMMY_PPV4_QOS_API_OLD
+
+#ifdef DUMMY_PPV4_QOS_API_OLD
 /*TODO:currently need to include both header file */
 #include <net/pp_qos_drv_slim.h>
 #include <net/pp_qos_drv.h>
@@ -269,6 +271,9 @@ enum DP_DBG_FLAG {
 	DP_DBG_FLAG_NOTIFY = BIT(16),
 	DP_DBG_FLAG_LOGIC = BIT(17),
 	DP_DBG_FLAG_GSWIP_API = BIT(18),
+	DP_DBG_FLAG_QOS = BIT(19),
+	DP_DBG_FLAG_QOS_DETAIL = BIT(20),
+	DP_DBG_FLAG_LOOKUP = BIT(21),
 
 	/*Note, once add a new entry here int the enum,
 	 *need to add new item in below macro DP_F_FLAG_LIST
@@ -276,29 +281,6 @@ enum DP_DBG_FLAG {
 	DP_DBG_FLAG_MAX = BIT(31)
 };
 
-enum {
-	NODE_LINK_ADD = 0,
-	NODE_LINK_GET,
-	NODE_LINK_EN_GET,
-	NODE_LINK_EN_SET,
-	NODE_UNLINK,
-	LINK_ADD,
-	LINK_GET,
-	LINK_PRIO_SET,
-	LINK_PRIO_GET,
-	QUEUE_CFG_SET,
-	QUEUE_CFG_GET,
-	SHAPER_SET,
-	SHAPER_GET,
-	NODE_ALLOC,
-	NODE_FREE,
-	DEQ_PORT_RES_GET,
-	COUNTER_MODE_SET,
-	COUNTER_MODE_GET,
-	QUEUE_MAP_GET,
-	QUEUE_MAP_SET
-};
-
 /*Note: per bit one variable */
 #define DP_DBG_FLAG_LIST {\
 	DP_DBG_ENUM_OR_STRING(DP_DBG_FLAG_DBG, "dbg"), \
@@ -321,9 +303,40 @@ enum {
 	DP_DBG_ENUM_OR_STRING(DP_DBG_FLAG_SWDEV, "swdev"), \
 	DP_DBG_ENUM_OR_STRING(DP_DBG_FLAG_NOTIFY, "notify"), \
 	DP_DBG_ENUM_OR_STRING(DP_DBG_FLAG_LOGIC, "logic"), \
-	DP_DBG_ENUM_OR_STRING(DP_DBG_FLAG_GSWIP_API, "gswip") \
+	DP_DBG_ENUM_OR_STRING(DP_DBG_FLAG_GSWIP_API, "gswip"), \
+	DP_DBG_ENUM_OR_STRING(DP_DBG_FLAG_QOS, "qos"), \
+	DP_DBG_ENUM_OR_STRING(DP_DBG_FLAG_QOS_DETAIL, "qos2"), \
+	DP_DBG_ENUM_OR_STRING(DP_DBG_FLAG_LOOKUP, "lookup"), \
+	\
+	\
+	/*must be last one */\
+	DP_DBG_ENUM_OR_STRING(DP_DBG_FLAG_MAX, "")\
 }
 
+enum {
+	NODE_LINK_ADD = 0,
+	NODE_LINK_GET,
+	NODE_LINK_EN_GET,
+	NODE_LINK_EN_SET,
+	NODE_UNLINK,
+	LINK_ADD,
+	LINK_GET,
+	LINK_PRIO_SET,
+	LINK_PRIO_GET,
+	QUEUE_CFG_SET,
+	QUEUE_CFG_GET,
+	SHAPER_SET,
+	SHAPER_GET,
+	NODE_ALLOC,
+	NODE_FREE,
+	DEQ_PORT_RES_GET,
+	COUNTER_MODE_SET,
+	COUNTER_MODE_GET,
+	QUEUE_MAP_GET,
+	QUEUE_MAP_SET
+};
+
+
 struct dev_mib {
 	atomic_t rx_fn_rxif_pkt; /*! received packet counter */
 	atomic_t rx_fn_txif_pkt; /*! transmitted packet counter */
@@ -359,11 +372,13 @@ struct dp_subif_info {
 #ifdef CONFIG_NET_SWITCHDEV
 	struct switchdev_ops *old_swdev_ops;
 	struct switchdev_ops new_swdev_ops;
+	void *swdev_priv; /*to store ext vlan info*/
 #endif
 	u16 qid;    /*! physical queue id */
 	u16 q_node; /*! logical queue node Id if applicable */
 	u16 qos_deq_port;
 	u16 cqm_deq_port;
+	u16 cqm_port_idx; /*like tconf id */
 };
 
 struct vlan_info {
@@ -440,12 +455,82 @@ struct subif_platform_data {
 	int act; /*Set by HAL subif_platform_set and used by DP lib */
 };
 
+#if 0
 struct vlan_prop {
 	u8 num;
 	u16 out_proto, out_vid;
 	u16 in_proto, in_vid;
 	struct net_device *base;
 };
+#endif
+
+#if 1
+struct vlan_info1 {
+	/* Changed this TPID field to GSWIP API enum type.
+	 * We do not have flexible for any TPID, only following are supported:
+	 * 1. ignore (don't care)
+	 * 2. 0x8100
+	 * 3. Value configured int VTE Type register
+	 */
+	GSW_ExtendedVlanFilterTpid_t tpid;  /* TPID like 0x8100, 0x8800 */
+	u16 vid ;  /*VLAN ID*/
+	/*note: user priority/CFI both don't care */
+	/* DSCP to Priority value mapping is possible */
+};
+
+struct vlan1 {
+	int bp;  /*assigned bp for this single VLAN dev */
+	struct vlan_info1 outer_vlan; /*out vlan info */
+	/* Add Ethernet type with GSWIP API enum type.
+	 * Following types are supported:
+	 * 1. ignore	(don't care)
+	 * 2. IPoE  	(0x0800)
+	 * 3. PPPoE 	(0x8863 or 0x8864)
+	 * 4. ARP   	(0x0806)
+	 * 5. IPv6 IPoE	(0x86DD)
+	 */
+	GSW_ExtendedVlanFilterEthertype_t ether_type;
+};
+
+struct vlan2 {
+	int bp;  /*assigned bp for this double VLAN dev */
+	struct vlan_info1 outer_vlan;  /*out vlan info */
+	struct vlan_info1 inner_vlan;   /*in vlan info */
+	/* Add Ethernet type with GSWIP API enum type.
+	 * Following types are supported:
+	 * 1. ignore	(don't care)
+	 * 2. IPoE  	(0x0800)
+	 * 3. PPPoE 	(0x8863 or 0x8864)
+	 * 4. ARP   	(0x0806)
+	 * 5. IPv6 IPoE	(0x86DD)
+	 */
+	GSW_ExtendedVlanFilterEthertype_t ether_type;
+};
+#endif
+
+struct ext_vlan_info {
+	int subif_grp, logic_port; /* base subif group and logical port.
+				    * In DP it is subif
+				    */
+	int bp; /*default bp for this ctp */
+	int n_vlan1, n_vlan2; /*size of vlan1/2_list*/
+	int n_vlan1_drop, n_vlan2_drop; /*size of vlan1/2_drop_list */
+	struct vlan1 *vlan1_list; /*allow single vlan dev info list auto
+				   * bp is for egress VLAN setting
+				   */
+	struct vlan2 *vlan2_list; /* allow double vlan dev info list auto
+				   * bp is for egress VLAN setting
+				   */
+	struct vlan1 *vlan1_drop_list; /* drop single vlan list - manual
+					*  bp no use
+					*/
+	struct vlan2 *vlan2_drop_list; /* drop double vlan list - manual
+					* bp no use
+					*/
+	/* Need add other input / output information for deletion. ?? */
+	/* private data stored by function set_gswip_ext_vlan */
+	void *priv;
+};
 
 /*port 0 is reserved*/
 extern int dp_inst_num;
@@ -495,6 +580,10 @@ void proc_mib_timer_read(struct seq_file *s);
 int mpe_fh_netfiler_install(void);
 int dp_coc_cpufreq_exit(void);
 int dp_coc_cpufreq_init(void);
+int qos_dump_start(void);
+int qos_dump(struct seq_file *s, int pos);
+ssize_t proc_qos_write(struct file *file, const char *buf,
+		       size_t count, loff_t *ppos);
 int update_coc_up_sub_module(enum ltq_cpufreq_state new_state,
 			     enum ltq_cpufreq_state old_state, uint32_t flag);
 void proc_coc_read(struct seq_file *s);
@@ -574,6 +663,8 @@ int dp_request_inst(struct dp_inst_info *info, u32 flag);
 int register_dp_cap(u32 flag);
 int print_symbol_name(unsigned long addr);
 typedef GSW_return_t(*dp_gsw_cb)(void *, void *);
+void falcon_test(void); /*defined in Pp qos driver */
+
 
 #endif /*DATAPATH_H */
 
diff --git a/drivers/net/ethernet/lantiq/datapath/datapath_api.c b/drivers/net/ethernet/lantiq/datapath/datapath_api.c
index 0ea926f345c442a98c1621de60533cd76847e8f3..c044db267e6095cd306abf8754a113031d0580c4 100644
--- a/drivers/net/ethernet/lantiq/datapath/datapath_api.c
+++ b/drivers/net/ethernet/lantiq/datapath/datapath_api.c
@@ -49,7 +49,7 @@ struct dma_rx_desc_1 dma_tx_desc_mask1;
 u32 dp_drop_all_tcp_err;
 u32 dp_pkt_size_check;
 
-u32 dp_dbg_flag;
+u32 dp_dbg_flag = DP_DBG_FLAG_QOS;
 EXPORT_SYMBOL(dp_dbg_flag);
 
 #ifdef CONFIG_LTQ_DATAPATH_MPE_FASTHOOK_TEST
@@ -90,6 +90,7 @@ char *dp_port_status_str[] = {
 	"Invalid"
 };
 
+static int try_walkaround;
 static int dp_init_ok;
 static DEFINE_SPINLOCK(dp_lock); /*datapath spinlock*/
 unsigned int dp_dbg_err = 1; /*print error */
@@ -398,8 +399,9 @@ static int32_t dp_alloc_port_private(int inst,
 	dp_port_info[inst][port_id].port_id = cbm_data.dp_port;
 	dp_port_info[inst][port_id].deq_port_base = cbm_data.deq_port;
 	dp_port_info[inst][port_id].deq_port_num = cbm_data.deq_port_num;
-	PR_ERR("cbm alloc dp_port:%d deq:%d deq_num:%d\n", cbm_data.dp_port,
-	       cbm_data.deq_port, cbm_data.deq_port_num);
+	DP_DEBUG(DP_DBG_FLAG_DBG,
+		 "cbm alloc dp_port:%d deq:%d deq_num:%d\n",
+		 cbm_data.dp_port, cbm_data.deq_port, cbm_data.deq_port_num);
 	if (cbm_data.flags & CBM_PORT_DMA_CHAN_SET)
 		dp_port_info[inst][port_id].dma_chan = cbm_data.dma_chan;
 	if (cbm_data.flags & CBM_PORT_PKT_CRDT_SET)
@@ -520,7 +522,8 @@ int32_t dp_register_subif_private(int inst, struct module *owner,
 				PR_ERR("subif_platform_set fail\n");
 				goto EXIT;
 			} else {
-				PR_ERR("subif_platform_set succeed\n");
+				DP_DEBUG(DP_DBG_FLAG_DBG,
+					 "subif_platform_set succeed\n");
 			}
 		} else {
 			PR_ERR("port info status fail for 0\n");
@@ -686,7 +689,8 @@ int32_t dp_deregister_subif_private(int inst, struct module *owner,
 		cbm_data.deq_port = port_info->deq_port_base;
 		if (cbm_dp_enable(owner, port_id, &cbm_data,
 				  CBM_PORT_F_DISABLE, port_info->alloc_flags)) {
-			DP_DEBUG(DP_DBG_FLAG_DBG, "cbm_dp_disable:port %d\n",
+			DP_DEBUG(DP_DBG_FLAG_DBG,
+				 "cbm_dp_disable:port %d\n",
 				 port_id);
 
 			return res;
@@ -724,9 +728,12 @@ int32_t dp_alloc_port_ext(int inst, struct module *owner,
 	int res;
 
 	if (unlikely(!dp_init_ok)) {
-		DP_LIB_LOCK(&dp_lock);
-		dp_probe(NULL); /*workaround to re-init */
-		DP_LIB_UNLOCK(&dp_lock);
+		spin_lock(&dp_lock);
+		if (!try_walkaround) {
+			try_walkaround = 1;
+			dp_probe(NULL); /*workaround to re-init */
+		}
+		spin_unlock(&dp_lock);
 		if (!dp_init_ok) {
 			PR_ERR("dp_alloc_port fail: datapath can't init\n");
 			return DP_FAILURE;
@@ -933,10 +940,10 @@ int32_t dp_register_subif_ext(int inst, struct module *owner,
 		return DP_FAILURE;
 	}
 
-	DP_LIB_LOCK(&dp_lock);
+	spin_lock(&dp_lock);
 	if (port_info->owner != owner) {
 		DP_DEBUG(DP_DBG_FLAG_DBG,
-			 "Unregister subif failed:Not matching:%p(%s)->%p(%s)\n",
+			 "Unregister subif fail:Not matching:%p(%s)->%p(%s)\n",
 			 owner, owner->name, port_info->owner,
 			 port_info->owner->name);
 		DP_LIB_UNLOCK(&dp_lock);
@@ -949,7 +956,7 @@ int32_t dp_register_subif_ext(int inst, struct module *owner,
 	else /*register */
 		res = dp_register_subif_private(inst, owner, dev, subif_name,
 						subif_id, data, flags);
-	DP_LIB_UNLOCK(&dp_lock);
+	spin_unlock(&dp_lock);
 	return res;
 }
 EXPORT_SYMBOL(dp_register_subif_ext);
@@ -2315,11 +2322,24 @@ int dp_basic_proc(void)
 	if (dp_init_ok) /*alredy init */
 		return 0;
 	register_notifier(0);
+#ifdef CONFIG_LTQ_DATAPATH_DUMMY_QOS_VIA_FALCON_TEST
+	PR_INFO("\n\n--Falcon_test to simulate SLIM QOS drv---\n\n\n");
+	falcon_test();  /*Must put before register_dp_cap 
+			 *since it needs to do CPU path cfg
+			 */
+#endif /*CONFIG_LTQ_DATAPATH_DUMMY_QOS_VIA_FALCON_TEST*/
 	register_dp_cap(0);
 	if (request_dp(0)) /*register 1st dp instance */ {
 		PR_ERR("register_dp instance fail\n");
 		return -1;
 	}
+	PR_ERR("preempt_count=%x\n", preempt_count());
+	if (preempt_count() & HARDIRQ_MASK)
+		PR_ERR("HARDIRQ_MASK\n");
+	if (preempt_count() & SOFTIRQ_MASK)
+		PR_ERR("SOFTIRQ_MASK\n");
+	if (preempt_count() & NMI_MASK)
+		PR_ERR("NMI_MASK\n");
 	dp_init_ok = 1;
 	PR_INFO("datapath init done\n");
 	return res;
@@ -2349,3 +2369,13 @@ int dp_basic_proc(void)
 }
 
 MODULE_LICENSE("GPL");
+
+static int __init dp_dbg_lvl_set(char *str)
+{
+	PR_INFO("\n\ndp_dbg=%s\n\n", str);
+	dp_dbg_flag = dp_atoi(str);
+
+	return 0;
+}
+early_param("dp_dbg", dp_dbg_lvl_set);
+
diff --git a/drivers/net/ethernet/lantiq/datapath/datapath_instance.c b/drivers/net/ethernet/lantiq/datapath/datapath_instance.c
index 02e4ca5d19960d80001108dcb0c878e769712d27..5b3aa6cb47eedb45ed0bc5370ac9a45eff8b2a7f 100644
--- a/drivers/net/ethernet/lantiq/datapath/datapath_instance.c
+++ b/drivers/net/ethernet/lantiq/datapath/datapath_instance.c
@@ -122,6 +122,7 @@ int dp_request_inst(struct dp_inst_info *info, u32 flag)
 	dp_port_prop[i].ops[1] = info->ops[1];
 	dp_port_prop[i].info = hw_cap_list[k].info;
 	dp_port_prop[i].cbm_inst = info->cbm_inst;
+	dp_port_prop[i].qos_inst = info->qos_inst;
 	dp_port_prop[i].valid = 1;
 	if (dp_port_prop[i].info.dp_platform_set(i, DP_PLATFORM_INIT) < 0) {
 		dp_port_prop[i].valid = 0;
diff --git a/drivers/net/ethernet/lantiq/datapath/datapath_logical_dev.c b/drivers/net/ethernet/lantiq/datapath/datapath_logical_dev.c
index e48f9544f988b9d48afa8968b80b28ec6d0fab60..259d21b9a3bec5cb4efb5a38c516307be2542638 100644
--- a/drivers/net/ethernet/lantiq/datapath/datapath_logical_dev.c
+++ b/drivers/net/ethernet/lantiq/datapath/datapath_logical_dev.c
@@ -198,7 +198,7 @@ int del_logic_dev(int inst, struct list_head *head, struct net_device *dev,
 	dp_port_prop[inst].info.subif_platform_set_unexplicit(inst,
 		logic_dev->ep,
 		logic_dev, flags);
-	dp_inst_del_dev(dev, NULL, inst, logic_dev->bp, logic_dev->ctp, 0);
+	dp_inst_del_dev(dev, NULL, inst, logic_dev->ep, logic_dev->ctp, 0);
 	list_del(&logic_dev->list);
 	kfree(logic_dev);
 
diff --git a/drivers/net/ethernet/lantiq/datapath/datapath_loopeth_dev.c b/drivers/net/ethernet/lantiq/datapath/datapath_loopeth_dev.c
index 2972b11237d4aede25aa7716c877b2959a38c61b..70e32aa7181214e29a3b8b2ca2400e8975ab0efd 100644
--- a/drivers/net/ethernet/lantiq/datapath/datapath_loopeth_dev.c
+++ b/drivers/net/ethernet/lantiq/datapath/datapath_loopeth_dev.c
@@ -48,6 +48,13 @@
  *              Definition
  * ####################################
  */
+#define PROC_NAME	"loop"
+#define PROC_DBG	"dbg"
+#define PROC_DEV	"dev"
+#define PROC_MIB	"mib"
+#define PROC_DP		"directpath"
+#define PROC_CPUTX	"cputx"
+
 #define ENABLE_DEBUG                            1
 
 #define ENABLE_ASSERT                           1
@@ -75,7 +82,7 @@
 #define dbg(format, arg...) do { if ((g_dbg_enable &\
 	DBG_ENABLE_MASK_DEBUG_PRINT)) \
 	PR_INFO(KERN_WARNING ":%d:%s: " format "\n",\
-	        __LINE__, __func__, ##arg); } \
+	__LINE__, __func__, ##arg); } \
 	while (0)
 #else
 #if !defined(dbg)
@@ -912,7 +919,7 @@ static int proc_write_dbg(struct file *file, const char *buf, size_t count,
 	}
 
 	return count;
- help:
+help:
 	PR_INFO("echo <enable/disable> [");
 
 	for (i = 0; i < ARRAY_SIZE(dbg_enable_mask_str); i++) {
@@ -1133,7 +1140,7 @@ static int proc_write_dev(struct file *file, const char *buf, size_t count,
 
 	return count;
 
- help:
+help:
 	PR_INFO("echo add [index] %s/dev\n", PROC_DIR);
 	PR_INFO("   example: echo add 1 > %s/dev\n", PROC_DIR);
 	PR_INFO("   example: echo add    > %s/dev\n", PROC_DIR);
@@ -1238,7 +1245,7 @@ static int proc_write_mib(struct file *file, const char *buf, size_t count,
 	}
 
 	return count;
- help:
+help:
 	PR_INFO("echo <clear> [all/device name] > %s/mib\n", PROC_DIR);
 	return count;
 }
@@ -1352,10 +1359,18 @@ int get_dev_type_index(char *flag_name)
 	return -1;
 }
 
+#define OPT_PORT  "[-e <dp_port>]"
+#define OPT_F "[-f explicit]"
+#define OPT_Q "[-q <num_resv_queue>]"
+#define OPT_SCH "[-s <num_resv_schedule>]"
+#define OPT_NUM  "[-p <num_resv_port>]"
+#define OPT_NO "[ -b <start_port_no>]"
+#define OPT_ALLOC_PORT (OPT_PORT OPT_F OPT_Q OPT_SCH OPT_NUM OPT_NO)
+
 static int proc_write_directpath(struct file *file, const char *buf,
 				 size_t count, loff_t *ppos)
 {
-	char str[300];
+	char str[150];
 	int len, rlen;
 	char *ifname = NULL;
 	dp_cb_t cb = {
@@ -1397,9 +1412,17 @@ static int proc_write_directpath(struct file *file, const char *buf,
 	if (((dp_strcmpi(param_list[0], "register") == 0) ||
 	     (dp_strcmpi(param_list[0], "reg") == 0)) &&
 	    (dp_strcmpi(param_list[1], "dev") == 0)) {
-		if (param_list_num < 5)
-			goto help;
-
+		PR_INFO("Not finished yet, need to continue here\n");
+		return count;
+#if 0
+		if((c = dp_getopt(param_list, num, &start, &opt_arg, optstring)) > 0)
+				printf("c=%c opt_arg=%s next_offset=%d\n", c, opt_arg, start);
+			else if (c ==0) 
+				break;
+			else {
+				printf("wrong format %s\n", opt[start]);
+				break;
+			}
 		PR_INFO("Try to register dev %s to datapath\n", ifname);
 		dev_port_str = param_list[3];
 		flag_str = param_list[4];
@@ -1409,7 +1432,7 @@ static int proc_write_directpath(struct file *file, const char *buf,
 		PR_INFO("flag_str=%s\n", flag_str ? flag_str : "NULL");
 		PR_INFO("dp_port_str=%s\n",
 			dp_port_str ? dp_port_str : "NULL");
-
+#endif
 		dev_port = dp_atoi(dev_port_str);
 		flag_index = get_dev_type_index(flag_str);
 		dp_port_id = dp_atoi(dp_port_str);
@@ -1466,7 +1489,7 @@ static int proc_write_directpath(struct file *file, const char *buf,
 			if (param_list[3])
 				priv->dp_subif.subif = dp_atoi(param_list[3]);
 			else
-				priv->dp_subif.subif = -1;	/*dynamic */
+				priv->dp_subif.subif = -1;/*dynamic */
 
 			if (dp_register_subif
 			    (priv->owner, g_loop_eth_dev[i],
@@ -1556,15 +1579,15 @@ static int proc_write_directpath(struct file *file, const char *buf,
 		goto help;
 	}
 
- exit:
+exit:
 	return count;
- help:
+help:
 	/*   param_list[0]    [1]    [2]         [3]      [4]     [5]   */
-	PR_INFO("echo register dev <name> <dev_port> <type> [dp_port]>%s\n",
-		PROC_DIRECTPATH);
+	PR_INFO("echo register dev <name> <dev_port> <type>  %s > %s\n",
+		OPT_ALLOC_PORT, PROC_DIRECTPATH);
 	PR_INFO("echo unregister dev  <dev_name>  > %s\n",
 		PROC_DIRECTPATH);
-	PR_INFO("echo register subif <dev> [parent_dev_name]> %s\n",
+	PR_INFO("echo register subif <dev> -p [parent_dev_name] -i <idx> %s\n",
 		PROC_DIRECTPATH);
 	PR_INFO("Note: parent_dev_name is for register different subif\n");
 	PR_INFO("Device Type:\n");
@@ -1589,16 +1612,6 @@ static int proc_write_directpath(struct file *file, const char *buf,
 	return count;
 }
 
-/*###################################
- *           Global Function
- * ####################################
- */
-#define PROC_NAME		"loop"
-#define PROC_DBG		"dbg"
-#define PROC_READ_DEV		"dev"
-#define PROC_READ_MIB		"mib"
-#define PROC_READ_DP		"directpath"
-#define PROC_READ_CPUTX		"cputx"
 static struct dp_proc_entry proc_entries[] = {
 	/*name single_callback_t multi_callback_t multi_callback_start
 	 *write_callback_t
@@ -1606,9 +1619,9 @@ static struct dp_proc_entry proc_entries[] = {
 #if defined(ENABLE_DBG_PROC) && ENABLE_DBG_PROC
 	{PROC_DBG, proc_read_dbg, NULL, NULL, proc_write_dbg},
 #endif
-	{PROC_READ_DEV, NULL, proc_read_dev, NULL, proc_write_dev},
-	{PROC_READ_MIB, NULL, proc_read_mib, NULL, proc_write_mib},
-	{PROC_READ_DP, NULL, proc_read_dp, NULL, proc_write_directpath},
+	{PROC_DEV, NULL, proc_read_dev, NULL, proc_write_dev},
+	{PROC_MIB, NULL, proc_read_mib, NULL, proc_write_mib},
+	{PROC_DP, NULL, proc_read_dp, NULL, proc_write_directpath},
 
 	/*last one for place holder */
 	{NULL, NULL, NULL, NULL, NULL}
diff --git a/drivers/net/ethernet/lantiq/datapath/datapath_notifier.c b/drivers/net/ethernet/lantiq/datapath/datapath_notifier.c
index 094af53dc386304cae55ba768c26efbd43bb1139..761d7aa127b49a67f715d4d505369d2b886423c2 100644
--- a/drivers/net/ethernet/lantiq/datapath/datapath_notifier.c
+++ b/drivers/net/ethernet/lantiq/datapath/datapath_notifier.c
@@ -81,14 +81,14 @@ int dp_event(struct notifier_block *this, unsigned long event, void *ptr)
 			 "MAC:", addr[0], addr[1], addr[2],
 			 addr[3], addr[4], addr[5]);
 		prop = &dp_port_prop[inst];
-		prop->info.dp_mac_reset(port->subif_info[vap].bp,
+		prop->info.dp_mac_reset(0,
 					dp_dev->fid,
 					dp_dev->inst,
 					addr);
 	break;
 	case NETDEV_CHANGEUPPER:
 		port = &dp_port_info[inst][dp_dev->ep];
-		dp_port_prop[inst].info.dp_mac_reset(port->subif_info[vap].bp,
+		dp_port_prop[inst].info.dp_mac_reset(0,
 						     dp_dev->fid,
 						     dp_dev->inst,
 						     addr);
diff --git a/drivers/net/ethernet/lantiq/datapath/datapath_proc.c b/drivers/net/ethernet/lantiq/datapath/datapath_proc.c
index ece8cb1d8411d34a62f8957dae9b8b9050636a66..acf5944eb27bea3a853966d8746395bbd2648c01 100644
--- a/drivers/net/ethernet/lantiq/datapath/datapath_proc.c
+++ b/drivers/net/ethernet/lantiq/datapath/datapath_proc.c
@@ -35,6 +35,8 @@
 #define PROC_INST_MOD "inst_mod"
 #define PROC_INST_HAL "inst_hal"
 #define PROC_INST "inst"
+#define PROC_TX_PKT "tx"
+#define PROC_QOS  "qos"
 
 static int tmp_inst;
 static ssize_t proc_port_write(struct file *file, const char *buf,
@@ -84,6 +86,13 @@ int proc_port_dump(struct seq_file *s, int pos)
 					   *port zero's member
 					   */
 				print_ctp_bp(s, tmp_inst, port, 0, 0);
+			i = 0;
+			seq_printf(s, "          : qid/node:    %d/%d\n",
+			   port->subif_info[i].qid,
+			   port->subif_info[i].q_node);
+			seq_printf(s, "          : port/node:    %d/%d\n",
+				   port->subif_info[i].cqm_deq_port,
+				   port->subif_info[i].qos_deq_port);
 
 		} else
 			seq_printf(s,
@@ -92,6 +101,8 @@ int proc_port_dump(struct seq_file *s, int pos)
 				   STATS_GET(port->rx_err_drop),
 				   STATS_GET(port->tx_err_drop));
 
+		
+
 		goto EXIT;
 	}
 
@@ -126,18 +137,18 @@ int proc_port_dump(struct seq_file *s, int pos)
 		   (u32)port->cb.stop_fn);
 	seq_printf(s, "    cb->get_subifid_fn:0x%0x\n",
 		   (u32)port->cb.get_subifid_fn);
-	seq_printf(s, "    num_subif:         %02d\n", port->num_subif);
+	seq_printf(s, "    num_subif:         %d\n", port->num_subif);
 	seq_printf(s, "    vap_offset/mask:   %d/0x%x\n", port->vap_offset,
 		   port->vap_mask);
-	seq_printf(s, "    flag_other:         %02d\n", port->flag_other);
-	seq_printf(s, "    deq_port_base:    %02d\n", port->deq_port_base);
-	seq_printf(s, "    deq_port_num:         %02d\n", port->deq_port_num);
-	seq_printf(s, "    dma_chan:         %02d\n", port->dma_chan);
-	seq_printf(s, "    tx_pkt_credit:         %02d\n", port->tx_pkt_credit);
-	seq_printf(s, "    tx_b_credit:         %02d\n", port->tx_b_credit);
-	seq_printf(s, "    tx_ring_addr:         %02d\n", port->tx_ring_addr);
-	seq_printf(s, "    tx_ring_size:         %02d\n", port->tx_ring_size);
-	seq_printf(s, "    tx_ring_offset:         %02d\n",
+	seq_printf(s, "    flag_other:        0x%x\n", port->flag_other);
+	seq_printf(s, "    deq_port_base:     %d\n", port->deq_port_base);
+	seq_printf(s, "    deq_port_num:      %d\n", port->deq_port_num);
+	seq_printf(s, "    dma_chan:          0x%x\n", port->dma_chan);
+	seq_printf(s, "    tx_pkt_credit:     %d\n", port->tx_pkt_credit);
+	seq_printf(s, "    tx_b_credit:       %02d\n", port->tx_b_credit);
+	seq_printf(s, "    tx_ring_addr:      0x%x\n", port->tx_ring_addr);
+	seq_printf(s, "    tx_ring_size:      %d\n", port->tx_ring_size);
+	seq_printf(s, "    tx_ring_offset:    %d(to next dequeue port)\n",
 		   port->tx_ring_offset);
 	for (i = 0; i < port->ctp_max; i++) {
 		if (!port->subif_info[i].flags)
@@ -172,10 +183,12 @@ int proc_port_dump(struct seq_file *s, int pos)
 			   STATS_GET(port->subif_info[i].mib.tx_hdr_room_pkt));
 		if (print_ctp_bp)
 			print_ctp_bp(s, tmp_inst, port, i, 0);
-		seq_printf(s, "          : qid:         %02d\n",
-			   port->subif_info[i].qid);
-		seq_printf(s, "          : q_node:         %02d\n",
+		seq_printf(s, "          : qid/node:    %d/%d\n",
+			   port->subif_info[i].qid,
 			   port->subif_info[i].q_node);
+		seq_printf(s, "          : port/node:    %d/%d\n",
+			   port->subif_info[i].cqm_deq_port,
+			   port->subif_info[i].qos_deq_port);
 	}
 	seq_printf(s, "    rx_err_drop=0x%08x  tx_err_drop=0x%08x\n",
 		   STATS_GET(port->rx_err_drop),
@@ -778,12 +791,17 @@ ssize_t proc_logical_dev_write(struct file *file, const char *buf,
 {
 	u16 len;
 	char str[64];
-	char *param_list[20 * 4];
+	static char *param_list[20 * 4];
 	unsigned int num;
 	struct net_device *dev = NULL, *base = NULL;
 	dp_subif_t *subif = NULL;
+
 	struct pmac_port_info *port_info;
+	static struct vlan_prop vlan_prop;
 
+	memset(&subif, 0, sizeof(subif));
+	memset(param_list, 0, sizeof(*param_list));
+	memset(&vlan_prop, 0, sizeof(vlan_prop));
 	len = (sizeof(str) > count) ? count : sizeof(str) - 1;
 	len -= copy_from_user(str, buf, len);
 	str[len] = 0;
@@ -796,8 +814,6 @@ ssize_t proc_logical_dev_write(struct file *file, const char *buf,
 		goto EXIT1;
 	}
 	if (dp_strcmpi(param_list[0], "check") == 0) {
-		struct vlan_prop vlan_prop = {0};
-
 		if (num != 2)
 			goto HELP;
 		dev = dev_get_by_name(&init_net, param_list[1]);
@@ -1167,6 +1183,250 @@ void print_device_tree_node(struct device_node *node, int depth)
 	kfree(indent);
 }
 
+static u8 ipv4_plain_udp[] = {
+	0x00, 0x01, 0x01, 0x01, 0x01, 0x01, /*mac */
+	0x00, 0x10, 0x94, 0x00, 0x00, 0x02,
+	0x08, 0x00,	/*type */
+	0x45, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x11, /*ip hdr*/
+	0x3A, 0x56, 0xC0, 0x55, 0x01, 0x02, 0xC0, 0x00, 0x00, 0x01,
+	0x04, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x7A, 0x41, 0x00, 0x00, /*udp hdr*/
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00
+};
+
+static u8 ipv4_plain_tcp[1514] = {
+	0x00, 0x01, 0x01, 0x01, 0x01, 0x01, /*mac */
+	0x00, 0x10, 0x94, 0x00, 0x00, 0x02,
+	0x08, 0x00,	/*type */
+	0x45, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x06, /*ip hdr*/
+	0x3A, 0x61, 0xC0, 0x55, 0x01, 0x02, 0xC0, 0x00, 0x00, 0x01,
+	0x04, 0x00, 0x04, 0x00, 0x00, 0x01, 0xE2, 0x40, 0x00, 0x03, /*tcp hdr*/
+	0x94, 0x47, 0x50, 0x10, 0x10, 0x00, 0x9F, 0xD9, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*data */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00
+};
+
+/*flag: for dp_xmit
+ *pool: 1-CPU
+ *discard: discard bit in DMA descriptor, CQM HW will drop the packet
+ *priority: for skb->priority
+ */
+static int dp_send_packet(u8 *pdata, int len, char *devname, u32 flag,
+			  u32 pool, u32 discard, int priority, int color)
+{
+	struct sk_buff *skb;
+	dp_subif_t subif = { 0 };
+	#define PAD  32
+
+	if (pool == 1) {
+		len += PAD;
+		if (len < ETH_ZLEN)
+			len = ETH_ZLEN;
+		skb = alloc_skb(len, GFP_ATOMIC);
+		if (skb)
+			skb_reserve(skb, PAD);
+		PR_INFO_ONCE("Allocate CPU buffer\n");
+	} else {
+		skb = cbm_alloc_skb(len + 8, GFP_ATOMIC);
+		PR_INFO_ONCE("Allocate bm buffer\n");
+	}
+
+	if (unlikely(!skb)) {
+		PR_ERR("allocate cbm buffer fail\n");
+		return -1;
+	}
+
+	skb->DW0 = 0;
+	skb->DW1 = 0;
+	skb->DW2 = 0;
+	skb->DW3 = 0;
+	if (discard) {
+		((struct dma_tx_desc_3 *)&skb->DW3)->field.dic = 1;
+		PR_INFO_ONCE("discard bit set in DW3\n");
+	}
+	((struct dma_tx_desc_1 *)&skb->DW1)->field.color = color;
+	memcpy(skb->data, pdata, len);
+	skb->data[5] = (char )priority;
+	skb->len = 0;
+	skb_put(skb, len);
+	skb->dev = dev_get_by_name(&init_net, devname);
+	skb->priority = priority;
+
+	if (dp_get_netif_subifid(skb->dev, skb, NULL, skb->data, &subif, 0)) {
+		PR_ERR("dp_get_netif_subifid failed for %s\n",
+		       skb->dev->name);
+		dev_kfree_skb_any(skb);
+		return -1;
+	}
+
+	((struct dma_tx_desc_1 *)&skb->DW1)->field.ep = subif.port_id;
+	((struct dma_tx_desc_0 *)&skb->DW0)->field.dest_sub_if_id =
+		subif.subif;
+
+	if (dp_xmit(skb->dev, &subif, skb, skb->len, flag))
+		return -1;
+
+	return 0;
+}
+
+
+#define OPT_TX_DEV "[-i <dev_name>]"
+#define OPT_TX_NUM "[-n <pkt_num>]"
+#define OPT_TX_PROT "[-t <types: udp/tcp/raw>]"
+#define OPT_TX_POOL "[-p <pool:cpu/bm>]"
+#define OPT_TX_F_DISC "[-d]"
+#define OPT_TX_PRIO "[-c <class/prio range>]"
+#define OPT_TX_COLOR "[-o <color>]"
+#define OPT_TX1 (OPT_TX_DEV OPT_TX_NUM OPT_TX_PROT)
+#define OPT_TX2 (OPT_TX_POOL OPT_TX_F_DISC OPT_TX_PRIO OPT_TX_COLOR)
+#define OPT_TX (OPT_TX1 OPT_TX2)
+char l2_hdr[]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x11,
+		0x12, 0x34};
+ssize_t proc_tx_pkt(struct file *file, const char *buf,
+		    size_t count, loff_t *ppos)
+{
+	int len = 0, c;
+	char data[100];
+	char *param_list[10];
+	int num, pkt_num = 1, times, pool = 0, disc = 0;
+	char *p = ipv4_plain_udp;
+	int size = sizeof(ipv4_plain_udp);
+	short prio_range = 1, color = 0;
+	int opt_offset;
+	char* optstring = "i:n:t:p:dc:o:";
+	char *optarg = 0;
+	char *dev_name = "eth1";
+
+	len = (count >= sizeof(data)) ? (sizeof(data) - 1) : count;
+	DP_DEBUG(DP_DBG_FLAG_DBG, "len=%d\n", len);
+
+	if (len <= 0) {
+		PR_ERR("Wrong len value (%d)\n", len);
+		return count;
+	}
+	if (copy_from_user(data, buf, len)) {
+		PR_ERR("copy_from_user fail");
+		return count;
+	}
+	data[len - 1] = 0; /* Make string */
+	num = dp_split_buffer(data, param_list, ARRAY_SIZE(param_list));
+	if (num <= 1)
+		goto help;
+	pkt_num = dp_atoi(param_list[1]);
+	if (pkt_num <= 0)
+		pkt_num = 1;
+
+	opt_offset = 0;
+	while((c = dp_getopt(param_list, num,
+	      &opt_offset, &optarg, optstring)) > 0) {
+		if (optstring)
+			DP_DEBUG(DP_DBG_FLAG_DBG, "opt_offset=%d optarg=%s.\n",
+				 opt_offset, optarg);
+		switch (c) {
+		case 'i':
+			dev_name = optarg;
+			DP_DEBUG(DP_DBG_FLAG_DBG, "dev_name=%s\n", dev_name);
+			break;
+		case 'n':
+			pkt_num = dp_atoi(optarg);
+			PR_INFO("pkt_num=%d\n", pkt_num);
+			break;
+		case 't':
+			if (dp_strcmpi(optarg, "tcp") == 0) {
+				p = ipv4_plain_tcp;
+				size = sizeof(ipv4_plain_tcp);
+			} else if (dp_strcmpi(optarg, "udp") == 0) {
+				p = ipv4_plain_udp;
+				size = sizeof(ipv4_plain_udp);
+			} else  {
+				PR_INFO("Wrong procol selected\n");
+				return count;
+			}
+			break;
+		case 'p':
+			if (dp_strcmpi(optarg, "cpu") == 0) {
+				pool = 1;
+			} else if (dp_strcmpi(optarg, "bm") == 0) {
+				pool = 0;
+			} else  {
+				PR_INFO("Wrong procol selected\n");
+				return count;
+			}
+			break;
+		case 'd':
+			disc = 1;
+			break;
+		case 'c':
+			prio_range = dp_atoi(optarg);
+			if (prio_range <= 0)
+				prio_range = 1;
+			PR_INFO("prio_range=%d\n", prio_range);
+			break;
+		case 'o':
+			color = dp_atoi(optarg);
+			if (color < 0)
+				color = 0;
+			else if (color > 3)
+				color = 3;
+			PR_INFO("color=%d\n", color);
+			break;
+		default:
+			PR_INFO("Wrong command\n");
+			goto help;
+		}
+	}
+	if (c < 0) { /*c == 0 means reach end of list */
+		PR_INFO("Wrong command\n");
+		goto help;
+	}
+
+	if (!dev_name) { /*c == 0 means reach end of list */
+		PR_INFO("Must provide dev_name\n");
+		return count;
+	}
+		
+	
+#if 0
+	if (dp_strcmpi("tcp", param_list[2]) == 0) {
+		p = ipv4_plain_tcp;
+		size = sizeof(ipv4_plain_tcp);
+		PR_INFO("send tcp packet\n");
+	} else { /*udp*/
+		p = ipv4_plain_udp;
+		size = sizeof(ipv4_plain_udp);
+		PR_INFO("send udp packet\n");
+	}
+	if (dp_strcmpi("bm", param_list[3]) == 0) {
+		PR_INFO("BM\n");
+		pool = 0;
+	} else {
+		PR_INFO("CPU buffer\n");
+		pool = 1;
+	}
+	if (dp_strcmpi("disc", param_list[4]) == 0) {
+		PR_INFO("disc\n");
+		disc = 1;
+	}
+#endif
+	times = 0;
+	while (pkt_num--) {
+		if (dp_send_packet(p, size, dev_name, 0, pool, disc,
+		    times%prio_range, color))
+			break;
+		times++;
+	}
+	PR_INFO("sent %d packet already\n", times);
+	return count;
+help:   /*                        [0]         [1]         [2]     [3] [4]*/
+	PR_INFO("tx packet: echo %s\n", OPT_TX1);
+	PR_INFO("                %s\n", OPT_TX2);
+	return count;
+}
+
 static struct dp_proc_entry dp_proc_entries[] = {
 	/*name single_callback_t multi_callback_t/_start write_callback_t */
 #if defined(CONFIG_LTQ_DATAPATH_DBG) && CONFIG_LTQ_DATAPATH_DBG
@@ -1180,6 +1440,8 @@ static struct dp_proc_entry dp_proc_entries[] = {
 	{PROC_INST_MOD, NULL, proc_inst_mod_dump, proc_inst_mod_start, NULL},
 	{PROC_INST_HAL, NULL, proc_inst_hal_dump, NULL, NULL},
 	{PROC_INST, NULL, proc_inst_dump, NULL, NULL},
+	{PROC_TX_PKT, NULL, NULL, NULL, proc_tx_pkt},
+	{PROC_QOS, NULL, qos_dump, qos_dump_start, proc_qos_write},
 
 	/*the last place holder */
 	{NULL, NULL, NULL, NULL, NULL}
diff --git a/drivers/net/ethernet/lantiq/datapath/datapath_proc_api.c b/drivers/net/ethernet/lantiq/datapath/datapath_proc_api.c
index e39a2a12e815a3b8bc20ee92be5f4ff9efff1560..c44bc908b685bddc226f0d2be2e722cab8685cce 100644
--- a/drivers/net/ethernet/lantiq/datapath/datapath_proc_api.c
+++ b/drivers/net/ethernet/lantiq/datapath/datapath_proc_api.c
@@ -105,9 +105,11 @@ EXPORT_SYMBOL(dp_replace_ch);
 static unsigned int btoi(char *str)
 {
 	unsigned int sum = 0;
-	u32 len = 0, i = 0;
+	int len = 0, i = 0;
 
 	len = strlen(str);
+	if (len == 0)
+		return 0;
 	len = len - 1;
 	while (len >= 0) {
 		if (*(str + len) == '1')
@@ -254,6 +256,55 @@ void set_start_end_id(unsigned int new_start, unsigned int new_end,
 }
 EXPORT_SYMBOL(set_start_end_id);
 
+/*
+ cmd: command line, its format should be like
+ cmd_len: the lenth of command line
+ optcurser: 
+ */
+int dp_getopt(char *cmd[], int cmd_size, int *cmd_offset,
+	      char **optarg, const char* optstring)
+{
+	char *p;
+	int offset;
+	int i;
+
+	if (!cmd || !cmd_offset || !optstring || !optarg) {
+		return -1;
+	}
+	if (*cmd_offset >= cmd_size)
+		return 0;
+	offset = *cmd_offset;
+	while (1) {
+		p = cmd[offset];
+		if(p[0] != '-') {
+			offset ++;
+			return -1; /*wrong format*/
+		}
+		for ( i = 0; i < strlen(optstring); i++) {
+			if (optstring[i] != p[1])
+				continue;
+			/*match*/
+			if (optstring[i+1] == ':') { /*opt + value */
+				if (offset + 1 > cmd_size)
+					return -1;
+				*optarg = cmd[offset + 1];
+				offset += 2;
+			} else { /*no value */
+				*optarg = NULL;
+				offset += 1;
+			}
+			*cmd_offset = offset;
+			return (int) optstring[i];
+		}
+		return -1;
+	}
+	return -1;
+}
+
+EXPORT_SYMBOL(dp_getopt);
+
+
+
 static void *dp_seq_start(struct seq_file *s, loff_t *pos)
 {
 	struct dp_proc_file_entry *p = s->private;
diff --git a/drivers/net/ethernet/lantiq/datapath/datapath_proc_qos.c b/drivers/net/ethernet/lantiq/datapath/datapath_proc_qos.c
new file mode 100644
index 0000000000000000000000000000000000000000..ad4c2d1cdf904c9782c311dc0c416cadd8e011e9
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/datapath/datapath_proc_qos.c
@@ -0,0 +1,842 @@
+#include <net/datapath_api.h>
+#include "datapath.h"
+
+#define PROC_MAX_BOX_LVL (DP_MAX_SCH_LVL + 1) /*Sched/Port both map to a box*/
+#define PROC_DP_MAX_CHILD_PER_SCH_PORT 8 /*max direct child per scheduer/port*/
+#define PROC_MAX_Q_PER_PORT 16 /*max queues per port */
+#define PROC_DP_MAX_SCH_PER_PORT 4 /*max schedulers per port */
+
+struct location {
+	int x1, y1; /*!< start axis */
+	int x2, y2; /*!< end axis */
+};
+
+struct box_info;
+
+struct child_node {
+	int filled;
+	enum dp_node_type type;
+	union {
+		int qid;
+		struct box_info *box;
+		} box_qid;
+	struct location l;
+};
+
+struct box_info {
+	int filled;
+	int id;  /*!< physical id if available, otherwise -1 */
+	int node; /*!< node id if available, otherwise -1 */
+	int pir, cir, pbs, cbs;
+	int prn_leaf;  /*since PPV4 not support leaf, here generate leaf for layout printing*/
+
+	int box_x, box_y, box_height; /*!< axis (x,y) for box */
+	int size;
+	int n_q, n_sch; /*direct child queue/scheduler*/
+	struct box_info *p_box; /*parent box*/
+	struct child_node child[PROC_DP_MAX_CHILD_PER_SCH_PORT];
+	struct location l; /*!< location */
+};
+
+struct q_print_info {
+	int q_num;
+	int q_id[PROC_MAX_Q_PER_PORT]; /*!< physical queue id if available, otherwise -1 */
+	int q_node_id[PROC_MAX_Q_PER_PORT]; /*!< queue node id if available, otherwise -1 */
+	int q_prn_leaf[PROC_MAX_Q_PER_PORT];  /*since PPV4 not support leaf, here generate leaf for layout printing*/
+	int sch_lvl[PROC_MAX_Q_PER_PORT];
+
+	struct box_info *sch_box[PROC_MAX_Q_PER_PORT][PROC_MAX_BOX_LVL];
+	struct box_info port_box;
+	int box_num;
+	struct box_info box[PROC_DP_MAX_SCH_PER_PORT]; /*!<need kmalloc/kfree */
+};
+
+static char *get_node_stat(int node_id, int type);
+struct box_info *find_box_via_nodeid(struct box_info *box,
+		 int box_num, int sch_node_id)
+{
+	int i;
+
+	for (i = 0; i < box_num; i++) {
+		if (box[i].node != sch_node_id) 
+			continue;
+		return &box[i];
+	}
+	return NULL;
+}
+
+struct box_info *find_child_box(
+	struct child_node child_list[PROC_DP_MAX_CHILD_PER_SCH_PORT],
+	struct box_info *curr_box)
+{
+	int i = 0;
+
+	while (child_list[i].filled) {
+		if (child_list[i].type != DP_NODE_SCH) {
+			i++;
+			continue;
+		}
+		if (child_list[i].box_qid.box == curr_box) 
+			return curr_box;
+		i++;
+	}
+	return NULL;
+}
+
+void set_child_per_box(struct q_print_info *q_info)
+{
+	int i, j, idx;
+	struct box_info *p_box, *c_box;
+
+	/* Get child number and info */
+	for (i = 0; i < q_info->q_num; i++) { /*queue */
+		if (!q_info->sch_box[i][0]) {/*queue to port case*/
+			p_box = &q_info->port_box;
+			idx = p_box->n_q + p_box->n_sch;
+
+			if (idx >= PROC_DP_MAX_CHILD_PER_SCH_PORT) {
+				PR_ERR("too many child: should <%d\n",
+					PROC_DP_MAX_CHILD_PER_SCH_PORT);
+				return;					
+			}
+			p_box->child[idx].filled = 1;
+			p_box->child[idx].box_qid.qid = q_info->q_id[i];
+			p_box->child[idx].type = DP_NODE_QUEUE;
+			q_info->q_prn_leaf[i] = idx;
+			p_box->n_q++;
+			continue;
+		}
+		/*queue to 1st scheduler */
+		p_box = q_info->sch_box[i][0];
+		idx = p_box->n_q + p_box->n_sch;
+
+		if (idx >= PROC_DP_MAX_CHILD_PER_SCH_PORT) {
+			PR_ERR("too many child: should <%d\n",
+				PROC_DP_MAX_CHILD_PER_SCH_PORT);
+			return;					
+		}
+		p_box->child[idx].filled = 1;
+		p_box->child[idx].box_qid.qid = q_info->q_id[i];
+		p_box->child[idx].type = DP_NODE_QUEUE;
+		q_info->q_prn_leaf[i] = idx;
+		p_box->n_q++;
+
+		/*scheduler to schduer/port */
+		for (j = 0; j < q_info->sch_lvl[i]; j++) {
+			if (j < (q_info->sch_lvl[i]-1))
+				p_box = q_info->sch_box[i][j+1];
+			else
+				p_box = &q_info->port_box;
+			c_box = q_info->sch_box[i][j];
+			idx = p_box->n_q + p_box->n_sch;
+			c_box->p_box = p_box;
+			if (find_child_box(p_box->child,  c_box))
+				 	continue;
+			if (idx >= PROC_DP_MAX_CHILD_PER_SCH_PORT - 1) {
+				PR_ERR("too many child: should <%d\n",
+					PROC_DP_MAX_CHILD_PER_SCH_PORT);
+				return;					
+			}
+			p_box->child[idx].filled = 1;
+			p_box->child[idx].box_qid.box = c_box;
+			p_box->child[idx].type = DP_NODE_SCH;
+			c_box->prn_leaf = idx;
+			p_box->n_sch++;
+		}
+	}
+}
+#define PREFIX_SIZE_PER_BOX 1 /*for opening ----- */
+#define INFO_SIZE_PER_BOX   2 /*for box info, like node id and others*/
+#define SUFIX_SIZE_PER_BOX  1 /*for closing ---- */
+#define EXTRA_SIZE_PER_BOX (PREFIX_SIZE_PER_BOX + INFO_SIZE_PER_BOX + \
+							SUFIX_SIZE_PER_BOX)
+#define PADDING_BETWEEN_BOX_X 4 /*x */
+#define PADDING_BETWEEN_BOX_Y 1
+#define SIZE_PER_QUEUE      3
+#define BOX_WIDTH           20
+#define Q_WIDTH             18
+#define PORT_OTHER_INFO     20
+
+int set_location_size(struct box_info *box, int y)
+{
+	int i, y2 = 0, size = 0;
+
+	box->l.x1 = Q_WIDTH + box->box_x * (BOX_WIDTH + PADDING_BETWEEN_BOX_X);
+	box->l.x2 = box->l.x1 + BOX_WIDTH;	
+	box->l.y1 = y;
+	y2 = box->l.y1 + PREFIX_SIZE_PER_BOX + INFO_SIZE_PER_BOX;
+	for (i = 0;
+	     (box->child[i].filled && (i < (box->n_q + box->n_sch)));
+	     i++) {
+		if (box->child[i].type == DP_NODE_QUEUE) {
+			box->child[i].l.x2 = box->l.x1;
+			box->child[i].l.y2 = y2 ;
+			size += SIZE_PER_QUEUE;
+			y2 += SIZE_PER_QUEUE;
+		} else if (box->child[i].type == DP_NODE_SCH) {
+			set_location_size(box->child[i].box_qid.box, y2);
+			box->child[i].l.x2 = box->l.x1;
+			box->child[i].l.y2 = y2;
+			size += box->child[i].box_qid.box->size;
+			y2 += box->child[i].box_qid.box->size; 
+		}
+	}
+	y2 += SUFIX_SIZE_PER_BOX;
+	size += EXTRA_SIZE_PER_BOX;
+	box->l.y2 = y2;
+	box->size = size;
+	return 0;
+}
+
+int check_location(struct q_print_info *q_info)
+{
+	int i;
+
+	for (i = 0; i < q_info->box_num; i++) {		
+		if ((q_info->box[i].l.x2 - q_info->box[i].l.x1) != BOX_WIDTH) {
+			PR_ERR("sched[%d] x1/x2: %d - %d should equal%d\n",
+					   q_info->box[i].node,
+					   q_info->box[i].l.x2,
+					   q_info->box[i].l.x1, 
+					   q_info->box[i].l.x2 - q_info->box[i].l.x1);
+			return -1;
+		}
+		if (!q_info->box[i].p_box)
+			continue;
+		if ((q_info->box[i].p_box->l.x1 - q_info->box[i].l.x2) !=
+			PADDING_BETWEEN_BOX_X) {
+			PR_ERR("sched[%d]<->sched[%d]: %d - %d should equal%d\n",
+				   q_info->box[i].node, q_info->box[i].p_box->node,
+				   q_info->box[i].p_box->l.x2,
+				   q_info->box[i].l.x1, 
+				   q_info->box[i].p_box->l.x2 - q_info->box[i].l.x1);
+			return -1;
+				
+		}
+			
+	}
+	return 0;
+}
+
+void virtual_print_box(struct box_info *box, 
+			   struct box_info *p_box,
+		char *buf, int rows, int cols)
+{
+	char *p;
+	int i, len;
+	char *stat = NULL;
+
+	/*The format like below
+	 *         -----------------------
+	 *        |sched[%03d]            |
+	 *        |                       |
+	 *        |leaf[%2d]:kbps         |
+	 *        | cir/pir:%5d/%5d       |  20
+	 *        | cbs/pbs:%5d/%5d       |  
+	 *        | ....                  |
+	 *        |                       |
+	 *         -----------------------
+	 */
+	p = &buf[cols * box->l.y1];
+	for (i = box->l.x1; i < box->l.x2; i++)
+		p[i] = '-';
+	p = &buf[cols * (box->l.y2 - 1)];
+	for (i = box->l.x1; i < box->l.x2; i++)
+		p[i] = '-';
+
+	for (i = 0; i < INFO_SIZE_PER_BOX; i++) {
+		p = &buf[cols * (box->l.y1 + 1 + i)];
+		p += box->l.x1 + 1;
+		if (i == 0) { /*print 1st info of box*/
+			if (!p_box) { /*port box*/
+				len = snprintf(p, BOX_WIDTH - 3,
+					       "port[%d/%d]",
+					       box->id, box->node);
+				stat = get_node_stat(box->id, DP_NODE_PORT);
+				p[len] = ' ';
+			} else { /*sched box */
+				len = snprintf(p, BOX_WIDTH - 3,
+					       "sched[/%d]",  box->node);
+				stat = get_node_stat(box->node, DP_NODE_SCH);
+				p[len] = ' ';
+			}
+		} else if (i == 1) {
+				len = snprintf(p, BOX_WIDTH - 3,
+							   " stat:%s", stat ? stat : "NULL");
+				p[len] = ' ';
+		}
+	}
+
+	for (i = box->l.y1 + 1; i < box->l.y2 - 1; i++) {
+		p = &buf[cols * i];
+		p[box->l.x1] = '|';
+	}
+	for (i = box->l.y1 + 1; i < box->l.y2 - 1; i++) {
+		p = &buf[cols * i];
+		p[box->l.x2 - 1] = '|';
+	}
+	if (!p_box) 
+		return;
+
+	p = &buf[cols * ((box->l.y1 + box->l.y2) / 2)];
+	for (i = box->l.x2; i < p_box->l.x1; i++)
+		p[i] = '-';
+}
+
+void virtual_print_queues(struct q_print_info *q_info,
+	char *buf, int rows, int cols)
+{
+	int i, j;
+	struct box_info *box;
+	int len, idx;
+	char *p;
+	char *stat = NULL;
+
+	for (i = 0; i < q_info->q_num; i++) {
+		if (q_info->sch_box[i][0])
+			box = q_info->sch_box[i][0];
+		else
+			box = &q_info->port_box;
+		idx = q_info->q_prn_leaf[i];
+		stat = get_node_stat(q_info->q_id[i], DP_NODE_QUEUE);
+		p = &buf[cols * box->child[idx].l.y2];
+		len = snprintf(p, Q_WIDTH - 1, "q[%4d/%4d] %s",
+					  q_info->q_id[i], q_info->q_node_id[i],
+					  stat ? stat : "NULL");
+		for (j = len; j < box->l.x1; j++)
+			p[j] = '-';
+
+
+		/*print leaf info in the parent box:sched/port */
+		p += box->l.x1 + 1; /*skip '|' */
+		for (j = 0; j < SIZE_PER_QUEUE; j++) {
+			if (j == 0) {
+				len = snprintf(p, BOX_WIDTH - 3, /*skip: | and | and null */
+						   "prn_leaf[%d]", q_info->q_prn_leaf[i]);
+				p[len] = ' ';
+			} else if ( j == 1 ) {
+				len = snprintf(p, BOX_WIDTH - 3,
+						   " C/P:%5d/%5d", 0, 0);
+				p[len] = ' '; 
+			} else if (j == 2) {
+				len = snprintf(p, BOX_WIDTH - 3,
+						   " c/p:%5d/%5d", 0, 0);
+				p[len] = ' '; 
+			}
+			/*move to next row */
+			p += cols;
+		}
+	}
+}
+
+void print_all(struct seq_file *s, struct q_print_info *q_info)
+{
+	int cols = q_info->port_box.l.x2 + 1;
+	int rows = q_info->port_box.l.y2 + 1;
+	int i;
+	char *buf;
+	char *p;
+
+	buf = (char *)kmalloc(cols * rows + 1, GFP_KERNEL);
+	if (!buf) {
+		PR_ERR("fail to alloc %d bytes\n", cols * rows + 1);
+		return;
+	}
+	memset(buf, ' ', cols * rows);
+	buf[cols * rows] = 0;
+	seq_printf(s, "allocte buffer: %d bytes(%d * %d)\n", 
+		cols * rows, cols, rows);
+
+	p = buf;
+	for (i=0; i<rows; i++) {
+		p += cols;
+		*(p - 1) = 0;
+	}
+
+	/*print port box*/
+	virtual_print_box(&q_info->port_box, NULL, buf, rows, cols);
+	for (i = 0; i < q_info->box_num; i++)
+		virtual_print_box(&q_info->box[i], q_info->box[i].p_box, buf, rows, cols);
+	/*print queue */
+	virtual_print_queues(q_info, buf, rows, cols);
+	p = buf;
+	for (i=0; i<rows; i++) {
+		seq_printf(s, "%s\n", p);
+		p += cols;
+	}	
+	kfree(buf);
+}
+
+/*print_box_lvl must bigger 1 than sch_lvl */
+struct q_print_info *collect_info(struct seq_file *s,
+				  struct dp_dequeue_res *res,
+				  int print_box_lvl)
+{
+	int i, j, size, curr_box_y = 0, curr_box_x;
+	struct q_print_info *q_info = NULL;
+	struct box_info *box;
+	char f_new_box;
+
+	if (!res || !res->num_q || (res->num_deq_ports < 1)) {
+		goto ERR_EXIT;
+	}
+	if (res->num_q >= PROC_MAX_Q_PER_PORT) {
+		seq_printf(s, "too many queues in one port:%d should <%d\n",
+			res->num_q, PROC_MAX_Q_PER_PORT);
+		return NULL;
+	}
+	for (i = 0; i < res->num_q; i++) {
+		if (print_box_lvl < res->q_res[i].sch_lvl + 1) {
+			PR_ERR("wrong print_box_lvl(%d) < queue's real sch_lvl(%d)\n",
+				print_box_lvl,
+				res->q_res[i].sch_lvl + 1);
+		}
+	}
+
+	size = sizeof(*q_info);
+	q_info = (struct q_print_info *)kmalloc(size, GFP_KERNEL);
+	if (!q_info) {
+		PR_ERR("fail to alloc %d bytes\n", size);
+		return NULL;
+	}
+	memset(q_info, 0, size);
+
+	q_info->port_box.filled = 1;
+	q_info->port_box.id = res->q_res[0].cqm_deq_port;
+	q_info->port_box.node = res->q_res[0].qos_deq_port;
+	q_info->port_box.box_x = print_box_lvl - 1;
+	q_info->port_box.box_y = 0;
+
+	for (i = 0; i < res->num_q; i++) { /*q loop */
+		q_info->q_id[i] = res->q_res[i].q_id;
+		q_info->q_node_id[i] =  res->q_res[i].q_node;
+		if (!res->q_res[i].sch_lvl)
+			continue;
+		f_new_box = 0;
+		curr_box_x = print_box_lvl - res->q_res[i].sch_lvl - 1;
+		for (j = 0; j < res->q_res[i].sch_lvl; j++) { /*each sched */
+			box = find_box_via_nodeid(q_info->box,
+						  q_info->box_num,
+						  res->q_res[i].sch_id[j]);
+			if (box) {
+				q_info->sch_box[i][j] = box;
+				continue;
+			}
+			/*create a new box */
+			q_info->box[q_info->box_num].filled = 1;
+			q_info->box[q_info->box_num].node = res->q_res[i].sch_id[j];
+			q_info->box[q_info->box_num].id = -1; /*not valid */
+			q_info->box[q_info->box_num].box_x = curr_box_x + j ;
+			q_info->box[q_info->box_num].box_y = curr_box_y;
+			q_info->sch_box[i][j] = &q_info->box[q_info->box_num];
+			q_info->box_num++;
+			f_new_box = 1;
+		}
+		q_info->sch_lvl[i] = res->q_res[i].sch_lvl;
+		if (f_new_box)
+			curr_box_y++;
+	}
+	q_info->q_num = res->num_q;
+	return q_info;
+ERR_EXIT:
+	if (q_info)
+		kfree(q_info);
+	return NULL;
+}
+
+//static struct dp_dequeue_res res;
+static struct dp_queue_res q_res[PROC_MAX_Q_PER_PORT * 4];
+static int qos_layout_inst = 0;
+static int qos_layout_max_lvl = PROC_MAX_BOX_LVL;
+static int max_tconf_idx = 0;
+struct dp_dequeue_res tmp_res;
+struct dp_queue_res tmp_q_res[PROC_MAX_Q_PER_PORT] = {0};
+
+char *get_node_stat(int id, int type)
+{
+	struct dp_node_link_enable node_en;
+	static char stat[20];
+
+	node_en.inst = qos_layout_inst;
+	node_en.id.q_id = id;
+	node_en.type = (enum dp_node_type)type;
+	stat[0] = 0;
+	PR_INFO("inst=%d id=%d type=%d\n",
+		node_en.inst, node_en.id.q_id, node_en.type);
+	if (dp_node_link_en_get(&node_en, 0))
+		strcpy(stat, "?");
+	else {
+		if (node_en.en & DP_NODE_DIS)
+			strcat(stat, "B");
+		if (node_en.en & DP_NODE_SUSPEND)
+			strcat(stat, "S");
+	}
+
+	return stat;
+}
+int get_num_deq_ports(int inst, int dp_port)
+{
+	if (inst != 0)
+		return 0;
+	memset(&tmp_res, 0, sizeof(tmp_res));
+	tmp_res.inst = inst;
+	tmp_res.dp_port = dp_port;
+	tmp_res.q_res = NULL;
+	tmp_res.cqm_deq_idx = DEQ_PORT_OFFSET_ALL;
+	if(dp_deq_port_res_get(&tmp_res, 0)) {
+		return -1;
+	}
+
+	return tmp_res.num_deq_ports;
+}
+
+int get_res(int inst, int dp_port, int tconf_idx)
+{
+	memset(&tmp_res, 0, sizeof(tmp_res));
+	tmp_res.inst = inst;
+	tmp_res.dp_port = dp_port;
+	tmp_res.cqm_deq_idx = tconf_idx;
+	tmp_res.q_res = q_res;
+	tmp_res.q_res_size = ARRAY_SIZE(q_res);
+	DP_DEBUG(DP_DBG_FLAG_QOS_DETAIL,
+		 "get_res: dp_port=%d tconf_idx=%d\n",
+		 tmp_res.dp_port, tmp_res.cqm_deq_idx);
+	if(dp_deq_port_res_get(&tmp_res, 0)) {
+		PR_ERR("dp_deq_port_res_get fail: inst=%d dp_port=%d, tconf_idx=%d\n",
+		       qos_layout_inst, tmp_res.dp_port, tconf_idx);
+		return -1;
+	}
+	return 0;
+}
+
+int dump_q_info_dbg(struct seq_file *s, struct dp_dequeue_res *res)
+{
+	struct dp_queue_res *q_res = res->q_res;
+	int i, j;
+
+	for (i = 0; i < res->num_q; i++) {
+		seq_printf(s, "q[%d]-", q_res[i].q_id);
+		for (j = 0; j < q_res[i].sch_lvl; j++)
+			seq_printf(s, "sched[%d]-", q_res[i].sch_id[j]);
+		seq_printf(s, "p[%d/%d]\n", q_res[i].cqm_deq_port, q_res[i].qos_deq_port);	
+	}
+	return 0;	
+}
+
+
+int qos_dump(struct seq_file *s, int pos)
+{
+	struct q_print_info *q_info;
+	int i;
+
+	if (pos == 0) {
+		seq_printf(s, "Note:\n");
+		seq_printf(s, "  x/y: physical node/logical node\n");
+		seq_printf(s, "     : cqm dequeue port/ppv4 logical node\n");
+		seq_printf(s, "  B: blocked, ie, new incoming packet will be dropped\n");
+		seq_printf(s, "  S: suspended, ie, packet in queue will not be trasmitted\n");
+		seq_printf(s, "\n");
+	}
+	max_tconf_idx = get_num_deq_ports(qos_layout_inst, pos);
+	if (max_tconf_idx <= 0)
+		goto NEXT_DP_PORT;
+	for (i = 0; i < max_tconf_idx; i++) {
+		/*get qos resource and store into tmp_res */
+		if (get_res(qos_layout_inst, pos, i)) {
+			PR_ERR("get_res fail\n");
+			return -1;
+		}
+		if (!tmp_res.num_q)
+			continue;
+		dump_q_info_dbg(s, &tmp_res);
+		q_info = collect_info(s, &tmp_res, qos_layout_max_lvl);
+		if (!q_info) {
+			PR_ERR("failed \n");
+			pos = -1;
+			return pos;
+		}
+		set_child_per_box(q_info);
+		set_location_size(&q_info->port_box, 0);
+		if (check_location(q_info))
+			continue;
+
+		print_all(s, q_info);
+		kfree(q_info);
+	}
+NEXT_DP_PORT:
+	pos ++;
+	if (pos >= 16)
+		pos = -1;
+
+	return pos;
+}
+
+
+int qos_dump_start(void)
+{	
+	qos_layout_inst = 0;
+	/*current just use maximum one. Later should check real QOS configuration
+	 *and get its maxim hirachy layers
+	 */
+	qos_layout_max_lvl = PROC_MAX_BOX_LVL;
+	max_tconf_idx = 0;
+	return 0;
+}
+
+ssize_t proc_qos_write(struct file *file, const char *buf,
+		       size_t count, loff_t *ppos)
+{
+#if 0
+	int len;
+	char str[100];
+	int sbit[SCHEDULE_MAX_LEVEL];
+	int leaf[SCHEDULE_MAX_LEVEL];
+	char *param_list[15] = { 0 };
+	char *temp_list[3] = { 0 };
+	int i;
+	unsigned int LINK_A = 0, LINK_B = 0, LEAF, egress_port = 0, qid = 0;
+	unsigned int level = 0, num = 0, tb = 0, sbid = 0;
+	len = (sizeof(str) > count) ? count : sizeof(str) - 1;
+	len -= copy_from_user(str, buf, len);
+	str[len] = 0;
+
+	if (!len)
+		return count;
+
+	num = dp_split_buffer(str, param_list, ARRAY_SIZE(param_list));
+	level = num - 3;
+
+	if (num <= 1 || num > ARRAY_SIZE(param_list)
+	    || dp_strcmpi(param_list[0], "help") == 0)
+		tmu_proc_tmu_create_cascade_help();
+	else if (dp_strcmpi(param_list[0], "set_wfq") == 0) {
+		struct tmu_sched_blk_in_link ilink;
+
+		if (num != 3) {
+			TMU_PRINT
+			    ("Wrong (try help): echo help > cascade\n");
+			return count;
+		}
+
+		dp_replace_ch(param_list[2], tmu_strlen(param_list[2]), ':',
+			      ' ');
+		dp_split_buffer(param_list[2], temp_list,
+				ARRAY_SIZE(temp_list));
+		LINK_B = dp_atoi(temp_list[0]);
+
+		if (LINK_B > (SCHEDULER_BLOCK_ID_MAX - 1)) {
+			TMU_PRINT("Wrong Parameter: SBID[%d]>SB_ID =0~%d]\n",
+			     LINK_B, (SCHEDULER_BLOCK_ID_MAX - 1));
+			return count;
+		}
+
+		LEAF = dp_atoi(temp_list[1]);
+
+		if (LEAF > (SCHEDULER_MAX_LEAF - 1)) {
+			TMU_PRINT
+			    ("Wrong: SBID:LEAF[%d] > [LEAF = 0 to 7]\n",
+			     LEAF);
+			return count;
+		}
+
+		tmu_sched_blk_in_link_get(((LINK_B + 0) << 3) + LEAF, &ilink);
+		ilink.iwgt = dp_atoi(param_list[1]);
+
+		if (ilink.iwgt >
+		    (TMU_SBITR0_IWGT_MASK >> TMU_SBITR0_IWGT_OFFSET)) {
+			TMU_PRINT("Wrong IWGT out of range [IWGT = 0 to 1023]\n");
+			TMU_PRINT("IWGT set to MAX value = %d\n",
+				  (TMU_SBITR0_IWGT_MASK >>
+				   TMU_SBITR0_IWGT_OFFSET));
+			ilink.iwgt =
+			    (TMU_SBITR0_IWGT_MASK >> TMU_SBITR0_IWGT_OFFSET);
+		}
+
+		tmu_sched_blk_in_link_set(((LINK_B + 0) << 3) + LEAF, &ilink);
+	} else if (dp_strcmpi(param_list[0], "del_q") == 0) {
+		qid = dp_atoi(param_list[1]);
+		tmu_egress_queue_delete(qid);
+		TMU_PRINT("\nQueue %d deleted\n\n", qid);
+	} else if (dp_strcmpi(param_list[0], "del_sb") == 0) {
+		sbid = dp_atoi(param_list[1]);
+
+		if (tmu_sched_blk_delete(sbid)) {
+			TMU_PRINT("\nCan not delete SB %d", sbid);
+			TMU_PRINT("(one of the SB's leaf input link ");
+			TMU_PRINT("has a vaild SB/Queue id)\n\n");
+		} else
+			TMU_PRINT("\nSB %d deleted\n\n", sbid);
+	} else if (dp_strcmpi(param_list[0], "attach_tb") == 0) {
+		if (num != 3) {
+			TMU_PRINT("Wrong:echo help > cascade\n");
+			return count;
+		}
+
+		dp_replace_ch(param_list[2], tmu_strlen(param_list[2]), ':',
+			      ' ');
+		dp_split_buffer(param_list[2], temp_list,
+				ARRAY_SIZE(temp_list));
+		LINK_B = dp_atoi(temp_list[0]);
+
+		if (LINK_B > (SCHEDULER_BLOCK_ID_MAX - 1)) {
+			TMU_PRINT("Wrong:SBID[%d]>[SB_ID=0 to %d]\n",
+			     LINK_B, (SCHEDULER_BLOCK_ID_MAX - 1));
+			return count;
+		}
+
+		LEAF = dp_atoi(temp_list[1]);
+
+		if (LEAF > (SCHEDULER_MAX_LEAF - 1)) {
+			TMU_PRINT("Wrong: SBID:LEAF[%d] > [LEAF = 0 to 7]\n",
+			     LEAF);
+			return count;
+		}
+
+		tb = dp_atoi(param_list[1]);
+
+		if (tb > (TOCKEN_BUCKET_ID - 1)) {
+			TMU_PRINT
+			    ("Wrong Parameter: TBID[%d] > [TBID = 0 to %d]\n",
+			     tb, (TOCKEN_BUCKET_ID - 1));
+			return count;
+		}
+
+		tmu_token_bucket_shaper_create(tb, ((LINK_B << 3) + LEAF));
+	} else if (dp_strcmpi(param_list[0], "remove_tb") == 0) {
+		if (num != 3) {
+			TMU_PRINT("Wrong: echo help > cascade\n");
+			return count;
+		}
+
+		dp_replace_ch(param_list[2], tmu_strlen(param_list[2]), ':',
+			      ' ');
+		dp_split_buffer(param_list[2], temp_list,
+				ARRAY_SIZE(temp_list));
+		LINK_B = dp_atoi(temp_list[0]);
+
+		if (LINK_B > (SCHEDULER_BLOCK_ID_MAX - 1)) {
+			TMU_PRINT("Wrong:SD[%d]>SCHEDULER_BLOCK_ID_MAX=0~%d\n",
+			     LINK_B, (SCHEDULER_BLOCK_ID_MAX - 1));
+			return count;
+		}
+
+		LEAF = dp_atoi(temp_list[1]);
+
+		if (LEAF > (SCHEDULER_MAX_LEAF - 1)) {
+			TMU_PRINT("Wrong:SBID:LF[%d] > [LEAF = 0 to 7]\n",
+			     LEAF);
+			return count;
+		}
+
+		tb = dp_atoi(param_list[1]);
+
+		if (tb > (TOCKEN_BUCKET_ID - 1)) {
+			TMU_PRINT("Wrong:TB[%d]>[TBID=0~%d]\n",
+			     tb, (TOCKEN_BUCKET_ID - 1));
+			return count;
+		}
+
+		tmu_token_bucket_shaper_delete(tb, ((LINK_B << 3) + LEAF));
+	} else if (dp_strcmpi(param_list[0], "cfg_tb") == 0) {
+		uint32_t tbid, cir, pir, cbs, pbs, mode;
+
+		if (num < 7) {
+			TMU_PRINT("Wrong Parameter(try help): echo help > cascade\n");
+			return count;
+		}
+
+		tbid = dp_atoi(param_list[1]);
+
+		if (tbid > (TOCKEN_BUCKET_ID - 1)) {
+			TMU_PRINT
+			    ("Wrong Parameter: TBID[%d] out of range [TBID = 0 to %d]\n",
+			     tbid, (TOCKEN_BUCKET_ID - 1));
+			return count;
+		}
+
+		cir = dp_atoi(param_list[2]);
+		pir = dp_atoi(param_list[3]);
+		cbs = dp_atoi(param_list[4]);
+		pbs = dp_atoi(param_list[5]);
+		mode = dp_atoi(param_list[6]);
+		tmu_shaper_cfg_set(tbid, 1, mode, cir, pir, cbs, pbs);
+	} else if (dp_strcmpi(param_list[0], "create") == 0) {
+		if (num < 4) {
+			TMU_PRINT("Wrong Parameter(try help): echo help > cascade\n");
+			return count;
+		}
+
+		qid = dp_atoi(param_list[1]);
+
+		if (qid > (EGRESS_QUEUE_ID_MAX - 1)) {
+			TMU_PRINT("Wrong Parameter: QID[%d] out of range [QID = 0 to %d]\n",
+			     qid, (EGRESS_QUEUE_ID_MAX - 1));
+			return count;
+		}
+
+		egress_port = dp_atoi(param_list[num - 1]);
+
+		if (egress_port > (EGRESS_PORT_ID_MAX - 1)) {
+			TMU_PRINT("Wrong Parameter: egress_port[%d] out of range [egress_port = 0 to %d]\n",
+			     egress_port, EGRESS_PORT_ID_MAX - 1);
+			return count;
+		}
+
+		for (i = 2; ((num - 1) > i && i < 10); i++) {
+			dp_replace_ch(param_list[i],
+				      tmu_strlen(param_list[i]), ':', ' ');
+			dp_split_buffer(param_list[i], temp_list,
+					ARRAY_SIZE(temp_list));
+			LINK_B = dp_atoi(temp_list[0]);
+			LEAF = dp_atoi(temp_list[1]);
+			sbit[i - 2] = LINK_B;
+			leaf[i - 2] = LEAF;
+
+			if (LINK_B > (SCHEDULER_BLOCK_ID_MAX - 1)) {
+				TMU_PRINT("Wrong Parameter: SBID[%d] out of range [SCHEDULER_BLOCK_ID_MAX = 0 to %d]\n",
+				     LINK_B, (SCHEDULER_BLOCK_ID_MAX - 1));
+				return count;
+			}
+
+			if (LEAF > (SCHEDULER_MAX_LEAF - 1)) {
+				TMU_PRINT("Wrong:SB[%d]:LF[%d]>[%d:LF=0~7\n",
+				     LINK_B, LEAF, LINK_B);
+				return count;
+			}
+		}
+
+		for (i = 2; ((num - 1) > i && i < 10); i++) {
+			LINK_B = sbit[i - 2];
+			LEAF = leaf[i - 2];
+
+			if (i == 2) {
+				LINK_A = qid;
+				TMU_PRINT("QID %d->SB %d:LEAF %d->", LINK_A,
+					  LINK_B, LEAF);
+				tmu_egress_queue_create(LINK_A,
+							((LINK_B << 3) +
+							 LEAF), egress_port);
+				tmu_set_wfq(((LINK_B << 3) + LEAF), 0);
+				level--;
+			} else if (i != 2) {
+				TMU_PRINT("SB %d:LEAF %d->", LINK_B, LEAF);
+				tmu_sched_blk_create(LINK_A, level,
+						     ((LINK_B << 3) + LEAF),
+						     1, 0);
+				level--;
+			}
+
+			LINK_A = LINK_B;
+		}
+
+		TMU_PRINT("EP %d\n", egress_port);
+		tmu_sched_blk_create(LINK_A, level, egress_port, 0, 0);
+		tmu_egress_port_enable(egress_port, true);
+	} else {
+		TMU_PRINT("Wrong Parameter:\n");
+		tmu_proc_tmu_create_cascade_help();
+	}
+#endif
+	return count;
+}
+
diff --git a/drivers/net/ethernet/lantiq/datapath/datapath_qos.c b/drivers/net/ethernet/lantiq/datapath/datapath_qos.c
index bb4592e23ddc39765eafc5bbf7b42c206597d903..d3d10e05abb658ac1f5e9f746adf7be03f8c9a20 100644
--- a/drivers/net/ethernet/lantiq/datapath/datapath_qos.c
+++ b/drivers/net/ethernet/lantiq/datapath/datapath_qos.c
@@ -125,6 +125,28 @@ EXPORT_SYMBOL(dp_node_free);
 
 int dp_deq_port_res_get(struct dp_dequeue_res *res, int flag)
 {
+	dp_subif_t *subif;
+	struct pmac_port_info *port_info;
+
+	if (!res)
+		return DP_FAILURE;
+	if (res->dev) { /*fill dp_port if dev is provided */
+		subif = kzalloc(sizeof(*subif), GFP_KERNEL);
+		if (!subif)
+			return DP_FAILURE;
+		dp_get_netif_subifid(res->dev, NULL, NULL, NULL, subif, 0);
+		if (!subif->subif_num) {
+			PR_ERR("Not found dev %s\n", res->dev->name);
+			return DP_FAILURE;
+		}
+		res->dp_port = subif->port_id;
+		kfree(subif);
+		subif = NULL;
+	}
+	port_info = &dp_port_info[res->inst][res->dp_port];
+	DP_DEBUG(DP_DBG_FLAG_QOS_DETAIL,
+		 "dp_deq_port_res_get: dp_port=%d tconf_idx=%d\n",
+		 res->dp_port, res->cqm_deq_idx);
 	dp_port_prop[res->inst].info.
 		dp_qos_platform_set(DEQ_PORT_RES_GET, res, flag);
 	return DP_SUCCESS;
diff --git a/drivers/net/ethernet/lantiq/datapath/datapath_soc.c b/drivers/net/ethernet/lantiq/datapath/datapath_soc.c
index e1ba835f7830d0fba7f7d039f450220110288d90..407558d7d2dda70111650d35046bcb4913b2ec51 100644
--- a/drivers/net/ethernet/lantiq/datapath/datapath_soc.c
+++ b/drivers/net/ethernet/lantiq/datapath/datapath_soc.c
@@ -39,6 +39,7 @@ int request_dp(u32 flag)
 	info.ops[1] = gsw_get_swcore_ops(1);
 #endif
 	info.cbm_inst = 0;
+	info.qos_inst = 0;
 	if (dp_request_inst(&info, flag)) {
 		PR_ERR("dp_request_inst failed\n");
 		return -1;
diff --git a/drivers/net/ethernet/lantiq/datapath/datapath_swdev.c b/drivers/net/ethernet/lantiq/datapath/datapath_swdev.c
index 9a4d97e4f124bbcf6ba3fe70c365c324d1a63993..f9b6de7f86b90be45a185b3b27e114aa1ece167c 100644
--- a/drivers/net/ethernet/lantiq/datapath/datapath_swdev.c
+++ b/drivers/net/ethernet/lantiq/datapath/datapath_swdev.c
@@ -61,28 +61,27 @@ struct br_info *dp_swdev_bridge_entry_lookup(char *br_name,
 	struct hlist_head *tmp;
 
 	idx = dp_swdev_cal_hash(br_name);
-	DP_DEBUG(DP_DBG_FLAG_SWDEV, "%s hash index:%d\n", __func__, idx);
+	DP_DEBUG(DP_DBG_FLAG_SWDEV, "hash index:%d\n", idx);
 	tmp = (&g_bridge_id_entry_hash_table[inst][idx]);
 	hlist_for_each_entry(br_item, tmp, br_hlist) {
 		if (br_item) {
 			if (strcmp(br_name, br_item->br_device_name) == 0) {
 				DP_DEBUG(DP_DBG_FLAG_SWDEV,
-					 "%s hash entry found(%s)\n",
-					 __func__, br_name);
+					 "hash entry found(%s)\n",
+					 br_name);
 				return br_item;
 			}
 		}
 	}
-	DP_DEBUG(DP_DBG_FLAG_SWDEV, "%s No hash entry found(%s)\n",
-		 __func__, br_name);
+	DP_DEBUG(DP_DBG_FLAG_SWDEV, "No hash entry found(%s)\n",
+		 br_name);
 	return NULL;
 }
 
-static void dp_swdev_remove_bridge_id_entry(struct br_info
-					   *br_item)
+static void dp_swdev_remove_bridge_id_entry(struct br_info *br_item)
 {
 	/*TODO reset switch bridge configurations*/
-	DP_DEBUG(DP_DBG_FLAG_SWDEV, "%s hash del\n", __func__);
+	DP_DEBUG(DP_DBG_FLAG_SWDEV, "hash del\n");
 	hlist_del(&br_item->br_hlist);
 	kfree(br_item);
 }
@@ -96,8 +95,8 @@ static void dp_swdev_insert_bridge_id_entry(struct br_info
 	idx = dp_swdev_cal_hash(br_item->br_device_name);
 	tmp = (&g_bridge_id_entry_hash_table[br_item->inst][idx]);
 	hlist_add_head(&br_item->br_hlist, tmp);
-	DP_DEBUG(DP_DBG_FLAG_SWDEV, "%s hash added idx:%d bridge(%s)\n",
-		 __func__, idx, br_item->br_device_name);
+	DP_DEBUG(DP_DBG_FLAG_SWDEV, "hash added idx:%d bridge(%s)\n",
+		 idx, br_item->br_device_name);
 }
 
 int dp_swdev_bridge_id_entry_free(int instance)
@@ -188,8 +187,7 @@ static int dp_swdev_clr_gswip_cfg(struct bridge_id_entry_item *br_item,
 
 	if (br_item->flags == BRIDGE_NO_ACTION) {
 		DP_DEBUG(DP_DBG_FLAG_SWDEV,
-			 "%s bport not added so no action required\n",
-			 __func__);
+			 "bport not added so no action required\n");
 		return 0;
 	}
 	br_info = dp_swdev_bridge_entry_lookup(br_item->br_device_name,
@@ -206,16 +204,84 @@ static int dp_swdev_clr_gswip_cfg(struct bridge_id_entry_item *br_item,
 				swdev_free_brcfg(br_item->inst, br_item->fid);
 			dp_swdev_remove_bridge_id_entry(br_info);
 			DP_DEBUG(DP_DBG_FLAG_SWDEV,
-				 "%s rem bport(%d),bridge(%s)\n",
-				 __func__, br_item->portid,
+				 "rem bport(%d),bridge(%s)\n",
+				 br_item->portid,
 				 br_item->br_device_name);
 		}
-		DP_DEBUG(DP_DBG_FLAG_SWDEV, "%s rem bport(%d)\n",
-			 __func__, br_item->portid);
+		DP_DEBUG(DP_DBG_FLAG_SWDEV, "rem bport(%d)\n",
+			 br_item->portid);
 		return 0;
 	}
 	DP_DEBUG(DP_DBG_FLAG_SWDEV,
-		 "%s No configuration,Pls check!!\n", __func__);
+		 "No configuration,Pls check!!\n");
+	return 0;
+}
+
+static int dp_swdev_cfg_vlan(struct bridge_id_entry_item *br_item,
+			     struct net_device *dev)
+{
+	struct br_info *br_info;
+	struct vlan_prop vlan_prop = {0};
+	struct dp_dev *dp_dev;
+	struct logic_dev *tmp = NULL;
+	u32 idx;
+	int vap, i;
+
+	//if (br_info->flag & LOGIC_DEV_REGISTER) {
+	if (br_item->flags & LOGIC_DEV_REGISTER) {
+		//get_vlan_via_dev(dev, &vlan_prop);
+		idx = dp_dev_hash(dev, NULL);
+		dp_dev = dp_dev_lookup(&dp_dev_list[idx], dev, NULL, 0);
+		vap = GET_VAP(dp_dev->ctp,
+			      dp_port_info[br_item->inst][dp_dev->ep].vap_offset,
+			      dp_port_info[br_item->inst][dp_dev->ep].vap_mask);
+		DP_DEBUG(DP_DBG_FLAG_SWDEV, "vap=%d ep=%d bp=%d\n",
+			 vap, dp_dev->ep, dp_dev->bp);
+		dp_port_prop[br_item->inst].info.dp_cfg_vlan(br_item->inst,
+							     vap, dp_dev->ep);
+	}
+	return 0;
+}
+
+static int dp_swdev_filter_vlan(struct net_device *dev,
+				const struct switchdev_obj *obj,
+				struct switchdev_trans *trans,
+				struct net_device *br_dev)
+{
+	struct br_info *br_info;
+	struct bridge_id_entry_item *br_item;
+	dp_subif_t subif = {0};
+
+	if (switchdev_trans_ph_prepare(trans)) {
+		/*Get current BPORT ID,instance from DP*/
+		if (dp_get_netif_subifid(dev, NULL, NULL, NULL, &subif, 0)) {
+			PR_ERR("%s dp_get_netif_subifid failed for %s\n",
+			       __func__, dev->name);
+			return -EOPNOTSUPP;
+		}
+		br_item = kmalloc(sizeof(*br_item), GFP_KERNEL);
+		if (!br_item)
+			//TODO need to check dequeue if no memory
+			return -ENOMEM;
+		br_item->inst = subif.inst;
+		/* current bridge member port*/
+		br_item->portid = subif.bport;
+		swdev_lock();
+		br_info = dp_swdev_bridge_entry_lookup(br_dev->name,
+						       subif.inst);
+		if (br_info) {
+			strcpy(br_item->br_device_name,
+			       br_info->br_device_name);
+			br_item->fid = br_info->fid;
+		}
+		switchdev_trans_item_enqueue(trans, br_item,
+					     kfree, &br_item->tritem);
+		swdev_unlock();
+		return 0;
+	}
+	br_item = switchdev_trans_item_dequeue(trans);
+	if (br_item)
+		dp_swdev_cfg_vlan(br_item, dev);
 	return 0;
 }
 
@@ -223,8 +289,7 @@ static int dp_swdev_cfg_gswip(struct bridge_id_entry_item *br_item, u8 *addr)
 {
 	struct br_info *br_info;
 
-	DP_DEBUG(DP_DBG_FLAG_SWDEV, "%s britem flags:%x\n", __func__,
-		 br_item->flags);
+	DP_DEBUG(DP_DBG_FLAG_SWDEV, "britem flags:%x\n", br_item->flags);
 	if (br_item->flags & ADD_BRENTRY) {
 		DP_DEBUG(DP_DBG_FLAG_SWDEV, "Add br entry %s\n",
 			 br_item->br_device_name);
@@ -245,11 +310,11 @@ static int dp_swdev_cfg_gswip(struct bridge_id_entry_item *br_item, u8 *addr)
 			br_info->inst = br_item->inst;
 			br_info->cpu_port = ENABLE;
 			/* Logic dev flag added to verify if SWDEV registered
-			 * the logical i.e. VLAN device. Helpful during
+			 * the logical i.e. VLAN device.Helpful during
 			 * br/bport delete
 			 */
 			if (br_item->flags & LOGIC_DEV_REGISTER) {
-				br_item->flags &= ~LOGIC_DEV_REGISTER;
+				//br_item->flags &= ~LOGIC_DEV_REGISTER;
 				br_info->flag = LOGIC_DEV_REGISTER;
 			}
 			strcpy(br_info->br_device_name,
@@ -264,8 +329,8 @@ static int dp_swdev_cfg_gswip(struct bridge_id_entry_item *br_item, u8 *addr)
 							  br_item->portid);
 			br_item->flags &= ~ADD_BRENTRY;
 			DP_DEBUG(DP_DBG_FLAG_SWDEV,
-				 "%s added bport(%d),bridge(%s)\n",
-				 __func__, br_item->portid,
+				 "added bport(%d),bridge(%s)\n",
+				 br_item->portid,
 				 br_info->br_device_name);
 			return 0;
 		}
@@ -274,6 +339,7 @@ static int dp_swdev_cfg_gswip(struct bridge_id_entry_item *br_item, u8 *addr)
 						       br_item->inst);
 		if (!br_info)
 			return 0;
+		br_info->flag = 0;
 		if (br_item->flags & LOGIC_DEV_REGISTER)
 			br_info->flag = LOGIC_DEV_REGISTER;
 		dp_swdev_add_bport_to_list(br_info, br_item->portid);
@@ -281,12 +347,11 @@ static int dp_swdev_cfg_gswip(struct bridge_id_entry_item *br_item, u8 *addr)
 			swdev_bridge_port_cfg_set(br_info,
 						  br_item->inst,
 						  br_item->portid);
-		DP_DEBUG(DP_DBG_FLAG_SWDEV, "%s added bport(%d)\n",
-			 __func__, br_item->portid);
+		DP_DEBUG(DP_DBG_FLAG_SWDEV, "added bport(%d)\n",
+			 br_item->portid);
 		return 0;
 	}
-	DP_DEBUG(DP_DBG_FLAG_SWDEV, "%s No configuration,Pls check!!\n",
-		 __func__);
+	DP_DEBUG(DP_DBG_FLAG_SWDEV, "No configuration,Pls check!!\n");
 	return 0;
 }
 
@@ -308,8 +373,8 @@ static int dp_swdev_add_if(struct net_device *dev,
 	if (switchdev_trans_ph_prepare(trans)) {
 		/*Get current BPORT ID,instance from DP*/
 		if (dp_get_netif_subifid(dev, NULL, NULL, NULL, &subif, 0)) {
-			PR_ERR("%s dp_get_netif_subifid failed for %s\n",
-			       __func__, dev->name);
+			PR_ERR("dp_get_netif_subifid failed for %s\n",
+			       dev->name);
 			/*Check bridge port exists otherwise register
 			 *device with datapath  i.e. only in case of new
 			 *VLAN interface
@@ -341,8 +406,8 @@ static int dp_swdev_add_if(struct net_device *dev,
 				}
 				flag = LOGIC_DEV_REGISTER;
 				DP_DEBUG(DP_DBG_FLAG_SWDEV,
-					 "registered subif:%d\n",
-					 subif.bport);
+					 "registered subif,bp=%d port=%d\n",
+					 subif.bport, subif.port_id);
 			} else {
 				return -EOPNOTSUPP;
 			}
@@ -388,8 +453,11 @@ static int dp_swdev_add_if(struct net_device *dev,
 	/*configure switch in commit phase and it cannot return failure*/
 	swdev_lock();
 	br_item = switchdev_trans_item_dequeue(trans);
-	if (br_item)
+	if (br_item) {
 		dp_swdev_cfg_gswip(br_item, addr);
+		if (br_item->flags & LOGIC_DEV_REGISTER)
+			dp_swdev_cfg_vlan(br_item, dev);/*only for vlan flag*/
+	}
 	swdev_unlock();
 	return 0;
 }
@@ -415,9 +483,10 @@ static int dp_swdev_del_if(struct net_device *dev,
 		/*Get current BR_PORT ID from DP*/
 		if (dp_get_netif_subifid(dev, NULL, NULL, NULL, &subif, 0)) {
 			DP_DEBUG(DP_DBG_FLAG_SWDEV,
-				 "%s dp_get_netif_subifid failed for %s\n",
-				 __func__, dev->name);
-			return -EINVAL;
+				 "dp_get_netif_subifid failed for %s\n",
+				 dev->name);
+			if (!is_vlan_dev(dev))
+				return -EINVAL;
 		}
 		br_item = kmalloc(sizeof(*br_item), GFP_KERNEL);
 		if (!br_item)
@@ -471,6 +540,11 @@ static int dp_swdev_del_if(struct net_device *dev,
 				 base ? base->name : "NULL");
 			if (!base)
 				base = dev;
+			/*the previous sequence was running into a deadlock in
+			 *taking the swdev_lock
+			 */
+			dp_swdev_cfg_vlan(br_item, dev);
+			swdev_unlock();
 			if (dp_get_netif_subifid(base, NULL, NULL,
 						 NULL, &subif, 0)) {
 				PR_ERR("dp_get_netif_subifid fail:%s\n",
@@ -483,9 +557,9 @@ static int dp_swdev_del_if(struct net_device *dev,
 			port = subif.port_id;
 			inst = subif.inst;
 			if (dp_register_subif(dp_port_info[inst][port]
-					      .owner,
-					      dev, dev->name, &subif,
-					      DP_F_DEREGISTER)) {
+						.owner,
+						dev, dev->name, &subif,
+						DP_F_DEREGISTER)) {
 				PR_ERR("dp_register_subif fail: %s\n",
 				       dev->name);
 				/*Cannot Return -EOPNOTSUPP
@@ -493,6 +567,7 @@ static int dp_swdev_del_if(struct net_device *dev,
 				 */
 				return 0;
 			}
+			swdev_lock();
 		}
 	}
 	swdev_unlock();
@@ -644,14 +719,13 @@ static int dp_swdev_port_attr_get(struct net_device *dev,
 		if (!br_info)
 			return 0;
 		if (br_info->fid < 0)
-			return 0;
-		snprintf(attr->u.ppid.id, sizeof(attr->u.ppid.id), "%d",
-			 br_info->fid);
-		attr->u.ppid.id_len = strlen(attr->u.ppid.id) + 1;
-		DP_DEBUG(DP_DBG_FLAG_SWDEV,
-			 "SWITCHDEV_ATTR_ID_PORT_PARENT_ID:%s fid:%d attr:%s\n",
-			 attr->orig_dev ? attr->orig_dev->name : "NULL",
-			 br_info->fid, attr->u.ppid.id);
+			return -EOPNOTSUPP;
+		attr->u.ppid.id_len = sizeof(br_info->fid);
+		memcpy(&attr->u.ppid.id, &br_info->fid, attr->u.ppid.id_len);
+		PR_INFO("SWITCHDEV_ATTR_ID_PORT_PARENT_ID:%s fid=%d\n",
+			attr->orig_dev ? attr->orig_dev->name : "NULL",
+			br_info->fid);
+		//err = 0;
 		break;
 	case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
 		break;
@@ -666,6 +740,7 @@ static int dp_swdev_port_obj_add(struct net_device *dev,
 				 struct switchdev_trans *trans)
 {
 	int err = -EOPNOTSUPP;
+	struct net_device *br_dev;
 #ifdef CONFIG_LTQ_DATAPATH_SWDEV_TEST
 	{
 		struct net_device *br_dev = netdev_master_upper_dev_get(dev);
@@ -678,7 +753,6 @@ static int dp_swdev_port_obj_add(struct net_device *dev,
 		 br_dev ? br_dev->name : "Null");
 		return 0;
 	}
-#endif
 	return err; //TODO
 
 	DP_DEBUG(DP_DBG_FLAG_SWDEV, "%s id:%d flags:%d dev name:%s\r\n",
@@ -690,8 +764,16 @@ static int dp_swdev_port_obj_add(struct net_device *dev,
 	if (trans->ph_prepare == 1)
 		DP_DEBUG(DP_DBG_FLAG_SWDEV, "%s ph->prepare:%d\r\n",
 			 __func__, trans->ph_prepare);
+#endif
+	DP_DEBUG(DP_DBG_FLAG_SWDEV, "%s id:%d flags:%d dev name:%s\r\n",
+		 __func__, obj->id,
+		 obj->flags, dev->name);
+	br_dev = netdev_master_upper_dev_get(obj->orig_dev);
+	if (!br_dev)
+		return err;
 	switch (obj->id) {
 	case SWITCHDEV_OBJ_ID_PORT_VLAN:
+		dp_swdev_filter_vlan(obj->orig_dev, obj, trans, br_dev);
 		break;
 	case SWITCHDEV_OBJ_ID_PORT_FDB:
 		break;
@@ -874,6 +956,7 @@ int dp_notif_br_alloc(struct net_device *br_dev)
 			br_info->fid = br_id;
 			br_info->inst = 0;
 			br_info->cpu_port = ENABLE;
+			br_info->flag = 0;
 			strcpy(br_info->br_device_name, br_dev->name);
 			INIT_LIST_HEAD(&br_info->bp_list);
 			dp_swdev_insert_bridge_id_entry(br_info);
@@ -896,17 +979,23 @@ void dp_port_register_switchdev(struct dp_dev  *dp_dev,
 {
 	if (dp_port_prop[dp_dev->inst].info.swdev_flag == 1) {
 		/*backup ops*/
-		SET_OPS(dp_dev->old_dev_ops,
-			(struct net_device_ops *)dp_port->netdev_ops);
-		SET_OPS(dp_dev->old_swdev_ops,
-			(struct switchdev_ops *)dp_port->switchdev_ops);
+		dp_dev->old_dev_ops = NULL;
+		dp_dev->old_swdev_ops = NULL;
+		if (dp_port->netdev_ops)
+			SET_OPS(dp_dev->old_dev_ops,
+				(struct net_device_ops *)dp_port->netdev_ops);
+		if (dp_dev->old_swdev_ops)
+			SET_OPS(dp_dev->old_swdev_ops,
+				(struct switchdev_ops *)dp_port->switchdev_ops);
 		/*create new one */
 		/* Current comment it out
 		 *SET_OPS(sub_info->new_dev_ops, dp_port->netdev_ops);
 		 *SET_OPS(sub_info->new_swdev_ops, dp_port->switchdev_ops);
 		 */
-		dp_dev->new_dev_ops = *dp_port->netdev_ops;
-		dp_dev->new_swdev_ops = *dp_port->switchdev_ops;
+		if (dp_port->netdev_ops)
+			dp_dev->new_dev_ops = *dp_port->netdev_ops;
+		if (dp_port->switchdev_ops)
+			dp_dev->new_swdev_ops = *dp_port->switchdev_ops;
 		/*tune new ops */
 		dp_dev->new_swdev_ops.switchdev_port_attr_get =
 							dp_swdev_port_attr_get;
@@ -954,7 +1043,7 @@ void dp_port_deregister_switchdev(struct dp_dev *dp_dev,
 	struct net_device *br_dev;
 
 	/* Workaround for ethernet ifconfig down case
-	 * to remove port from switchdev as dev is de-register
+	 * to remove port from switchdev as dev is de-registered
 	 * from DP lib
 	 */
 	if (netif_is_bridge_port(dev)) {
@@ -968,8 +1057,8 @@ void dp_port_deregister_switchdev(struct dp_dev *dp_dev,
 		}
 	}
 	if (dp_dev->old_swdev_ops && dp_dev->old_dev_ops) {
-	dev->switchdev_ops = dp_dev->old_swdev_ops;
-	dev->netdev_ops = dp_dev->old_dev_ops;
+		dev->switchdev_ops = dp_dev->old_swdev_ops;
+		dev->netdev_ops = dp_dev->old_dev_ops;
 	}
 }
 
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip30/Kconfig b/drivers/net/ethernet/lantiq/datapath/gswip30/Kconfig
index c510e8415d4588df8c0c2d33fa6e255db143901b..161052dc9d2a416c0bd3fc8371da259b1a7ba3aa 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip30/Kconfig
+++ b/drivers/net/ethernet/lantiq/datapath/gswip30/Kconfig
@@ -1,26 +1,25 @@
 menuconfig LTQ_DATAPATH_HAL_GSWIP30
-        bool "Datapath HAL_GSWIP30"
-        default y
-        depends on LTQ_DATAPATH
-        ---help---
-          Datapath Lib is to provide common rx/tx wrapper Lib without taking
-          care of much HW knowledge and also provide common interface for legacy
-          devices and different HW like to CBM or LRO.
-          Take note:
-            All devices need to register to datapath Lib first
+	bool "Datapath HAL_GSWIP30"
+	default y
+	depends on LTQ_DATAPATH
+	---help---
+	  Datapath Lib is to provide common rx/tx wrapper Lib without taking
+	  care of much HW knowledge and also provide common interface for legacy
+	  devices and different HW like to CBM or LRO.
+	  Take note: All devices need to register to datapath Lib first
 
 if LTQ_DATAPATH_HAL_GSWIP30
 config LTQ_DATAPATH_HAL_GSWIP30_MIB
-        bool "Datapath aggregated mib support"
-        depends on LTQ_DATAPATH_HAL_GSWIP30 && SOC_GRX500 && LTQ_TMU && LTQ_PPA_TMU_MIB_SUPPORT
-        default y
-        ---help---
-           It is to aggregate GSWIP-L/R, TMU and driver's MIB counter
-config LTQ_DATAPATH_HAL_GSWIP30_CPUFREQ
-        bool "Datapath DFS(COC) support"
-        depends on LTQ_DATAPATH && LTQ_CPUFREQ && LTQ_ETHSW_API
-        default y
-        ---help---
-           It is to support DFS(COC) in Datapath
+	bool "Datapath aggregated mib support"
+	depends on LTQ_DATAPATH_HAL_GSWIP30 && SOC_GRX500 && LTQ_TMU && LTQ_PPA_TMU_MIB_SUPPORT
+	default y
+	---help---
+	  It is to aggregate GSWIP-L/R, TMU and driver's MIB counter
 
+config LTQ_DATAPATH_HAL_GSWIP30_CPUFREQ
+	bool "Datapath DFS(COC) support"
+	depends on LTQ_DATAPATH && LTQ_CPUFREQ && LTQ_ETHSW_API
+	default y
+	---help---
+	  It is to support DFS(COC) in Datapath
 endif
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip30/datapath_lookup_proc.c b/drivers/net/ethernet/lantiq/datapath/gswip30/datapath_lookup_proc.c
index e875617c10b21b40c4f0a3ae7ff8ae908ed8d5ff..39c99c09979444c113e8951f2e00b2bce8a5ef60 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip30/datapath_lookup_proc.c
+++ b/drivers/net/ethernet/lantiq/datapath/gswip30/datapath_lookup_proc.c
@@ -192,7 +192,7 @@ static void lookup_pattern_match(int tmp_index)
 	int t[LOOKUP_FIELD_BITS] = { 0 };
 	int index;
 
-	DP_DEBUG(DP_DBG_FLAG_DBG,
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP,
 		 "trying with tmp_index=0x%x with lookup_match_num=%d\n",
 		 tmp_index, lookup_match_num);
 	pattern_match_flag = PATTERN_MATCH_INIT;
@@ -202,12 +202,12 @@ static void lookup_pattern_match(int tmp_index)
 		index = tmp_index;
 		for (i = 0; i < LOOKUP_FIELD_BITS; i++)
 			index |= (t[i] << i);
-		DP_DEBUG(DP_DBG_FLAG_DBG, "don't care[14]=");
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "don't care[14]=");
 		for (i = 0; i < LOOKUP_FIELD_BITS; i++)
-			DP_DEBUG(DP_DBG_FLAG_DBG, "%d ", t[i]);
-		DP_DEBUG(DP_DBG_FLAG_DBG, "\n");
+			DP_DEBUG(DP_DBG_FLAG_LOOKUP, "%d ", t[i]);
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "\n");
 
-		DP_DEBUG(DP_DBG_FLAG_DBG, "don't care index=%x\n", index);
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "don't care index=%x\n", index);
 
 		if (lookup_tbl_flags[index] == ENTRY_USED) {
 			pattern_match_flag = PATTERN_MATCH_FAIL;
@@ -221,7 +221,7 @@ static void lookup_pattern_match(int tmp_index)
 			first_qid = qid;
 		} else if (first_qid != qid) {
 			pattern_match_flag = PATTERN_MATCH_FAIL;
-			DP_DEBUG(DP_DBG_FLAG_DBG, "first_qid(%d) != qid(%d)\n",
+			DP_DEBUG(DP_DBG_FLAG_LOOKUP, "first_qid(%d) != qid(%d)\n",
 				 first_qid, qid);
 			goto END;
 		}
@@ -250,7 +250,7 @@ static void lookup_pattern_match(int tmp_index)
 			if (lookup_mask1[i])
 				lookup_match_mask[lookup_match_num] |= 1 << i;
 		lookup_match_num++;
-		DP_DEBUG(DP_DBG_FLAG_DBG,
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP,
 			 "left_n=%d lookup_mask_n=%d. Need reduce=%d\n",
 			 left_n, lookup_mask_n, (1 << lookup_mask_n));
 		left_n -= (1 << lookup_mask_n);
@@ -270,11 +270,11 @@ static int list_care_combination(int tmp_index)
 		index = tmp_index;
 		for (i = 0; i < LOOKUP_FIELD_BITS; i++)
 			index |= (t[i] << i);
-		DP_DEBUG(DP_DBG_FLAG_DBG, "care index=%x\n", index);
-		DP_DEBUG(DP_DBG_FLAG_DBG, "care t[14]=");
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "care index=%x\n", index);
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "care t[14]=");
 		for (k = 0; k < LOOKUP_FIELD_BITS; k++)
-			DP_DEBUG(DP_DBG_FLAG_DBG, "%d ", t[k]);
-		DP_DEBUG(DP_DBG_FLAG_DBG, "\n");
+			DP_DEBUG(DP_DBG_FLAG_LOOKUP, "%d ", t[k]);
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "\n");
 		lookup_pattern_match(index);
 	}
 
@@ -291,19 +291,19 @@ static int check_pattern(int *data, int r)
 	int i;
 
 	memset(lookup_mask1, 0, sizeof(lookup_mask1));
-	DP_DEBUG(DP_DBG_FLAG_DBG, "data:");
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP, "data:");
 	for (i = 0; i < r; i++) {
-		DP_DEBUG(DP_DBG_FLAG_DBG, "%d ", data[i]);
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "%d ", data[i]);
 		lookup_mask1[data[i]] = CARE_NOT_FLAG;
 	}
 	lookup_mask_n = r;
 	pattern_match_flag = 0;
-	DP_DEBUG(DP_DBG_FLAG_DBG, "\n");
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP, "\n");
 
-	DP_DEBUG(DP_DBG_FLAG_DBG, "Don't care flag: ");
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP, "Don't care flag: ");
 	for (i = 0; i < LOOKUP_FIELD_BITS; i++)
-		DP_DEBUG(DP_DBG_FLAG_DBG, "%c ", lookup_mask1[i] ? 'x' : '0');
-	DP_DEBUG(DP_DBG_FLAG_DBG, "\n");
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "%c ", lookup_mask1[i] ? 'x' : '0');
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP, "\n");
 
 	list_care_combination(tmp_pattern_port_id << 4);
 	return 0;
@@ -332,7 +332,7 @@ int find_pattern(int port_id, struct seq_file *s, int qid)
 		if (left_n <= 0)
 			break;
 		c_not_care_walkthrought(arr, n, r);
-		DP_DEBUG(DP_DBG_FLAG_DBG, "left_n=%d\n", left_n);
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "left_n=%d\n", left_n);
 		if (!left_n)
 			break;
 	}
@@ -397,7 +397,7 @@ ssize_t proc_get_qid_via_index30(struct file *file, const char *buf,
 	int num;
 
 	len = (count >= sizeof(data)) ? (sizeof(data) - 1) : count;
-	DP_DEBUG(DP_DBG_FLAG_DBG, "len=%d\n", len);
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP, "len=%d\n", len);
 
 	if (len <= 0) {
 		err = -EFAULT;
@@ -494,7 +494,7 @@ void lookup_table_via_qid(int qid)
 {
 	u32 index, tmp, i, j, k, f = 0;
 
-	DP_DEBUG(DP_DBG_FLAG_DBG,
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP,
 		 "Try to find all lookup flags mapped to qid %d\n", qid);
 	for (i = 0; i < 16; i++) {	/*ep */
 		for (j = 0; j < 16; j++) {	/*class */
@@ -518,7 +518,7 @@ void lookup_table_remap(int old_q, int new_q)
 {
 	u32 index, tmp, i, j, k, f = 0;
 
-	DP_DEBUG(DP_DBG_FLAG_DBG,
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP,
 		 "Try to remap lookup flags mapped from old_q %d to new_q %d\n",
 		 old_q, new_q);
 	for (i = 0; i < 16; i++) {	/*ep */
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip30/datapath_mib.c b/drivers/net/ethernet/lantiq/datapath/gswip30/datapath_mib.c
index 5b7cc3a856be1f3b62857f2071505903eb728369..53cea28eb19b6598eb3e7a2e53df4a2d5e577041 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip30/datapath_mib.c
+++ b/drivers/net/ethernet/lantiq/datapath/gswip30/datapath_mib.c
@@ -220,7 +220,9 @@ static u64 wraparound(u64 curr, u64 last, u32 size)
 	if ((size > 4) || /*for 8 bytes(64bit mib),no need to do wraparound*/
 	    (curr >= last))
 		return curr - last;
-
+	PR_INFO("Wraparound happen: \n");
+	PR_INFO("  current mib: 0x%x\n", curr);
+	PR_INFO("  last    mib: 0x%x\n", last);
 	return ((u64)WRAPAROUND_MAX_32) + (u64)curr - last;
 }
 
@@ -245,7 +247,7 @@ static int port_mib_wraparound(u32 ep, struct mibs_low_lvl_port *curr,
 		last_tmp = &last->r;
 	}
 	/*First handle common RMON mib */
-	spin_lock_bh(&dp_mib_lock);
+	//spin_lock_bh(&dp_mib_lock);
 	aggregate_mib[ep].curr.rx_good_bytes +=
 	    RMON_PORT_WRAP(curr_tmp, last_tmp, nRxGoodBytes);
 	aggregate_mib[ep].curr.rx_bad_bytes +=
@@ -318,7 +320,7 @@ static int port_mib_wraparound(u32 ep, struct mibs_low_lvl_port *curr,
 
 		/*save */
 		*last = *curr;
-		spin_unlock_bh(&dp_mib_lock);
+		//spin_unlock_bh(&dp_mib_lock);
 		return 0;
 	}
 
@@ -383,7 +385,7 @@ static int port_mib_wraparound(u32 ep, struct mibs_low_lvl_port *curr,
 	}
 	/*save */
 	*last = *curr;
-	spin_unlock_bh(&dp_mib_lock);
+	//spin_unlock_bh(&dp_mib_lock);
 	return 0;
 }
 
@@ -411,7 +413,7 @@ static int vap_mib_wraparound(dp_subif_t *subif,
 	if ((ep <= 0) ||
 	    (ep >= PMAC_MAX_NUM))
 		return -1;
-	spin_lock_bh(&dp_mib_lock);
+	//spin_lock_bh(&dp_mib_lock);
 	aggregate_mib[ep].curr_vap[vap].rx_pkts_itf +=
 	    VAP_RMON_WRAP_ITF(curr, last, nRxPktsCount);
 	aggregate_mib[ep].curr_vap[vap].rx_disc_pkts_itf +=
@@ -433,7 +435,7 @@ static int vap_mib_wraparound(dp_subif_t *subif,
 	    VAP_RMON_WRAP_DRV(curr, last, tx_drop_pkts);
 	/*save */
 	*last = *curr;
-	spin_unlock_bh(&dp_mib_lock);
+	//spin_unlock_bh(&dp_mib_lock);
 	return 0;
 }
 
@@ -1050,6 +1052,7 @@ int dp_get_port_vap_mib_30(dp_subif_t *subif, void *priv,
 	    (subif->port_id >= PMAC_MAX_NUM) ||
 	    !net_mib)
 		return -1;
+	spin_lock_bh(&dp_mib_lock);
 	port_id = subif->port_id;
 	vap = GET_VAP(subif->subif,
 		      PORT_INFO(0, subif->port_id, vap_offset),
@@ -1081,7 +1084,7 @@ int dp_get_port_vap_mib_30(dp_subif_t *subif, void *priv,
 		    aggregate_mib[port_id].curr_vap[vap].tx_disc_pkts_drv;
 		net_mib->tx_packets =
 		    aggregate_mib[port_id].curr_vap[vap].tx_pkts_itf;
-
+		spin_unlock_bh(&dp_mib_lock);
 		return 0;
 	}
 
@@ -1548,7 +1551,7 @@ int dp_get_port_vap_mib_30(dp_subif_t *subif, void *priv,
 			 aggregate_mib[port_id].curr.rx_good_bytes,
 			 aggregate_mib[port_id].curr.rx_bad_bytes);
 	}
-
+	spin_unlock_bh(&dp_mib_lock);
 	return 0;
 }
 
@@ -1608,8 +1611,9 @@ int dp_clear_netif_mib_30(dp_subif_t *subif, void *priv, u32 flag)
 
 	gsw_l = dp_port_prop[inst].ops[GSWIP_L];
 	gsw_r = dp_port_prop[inst].ops[GSWIP_R];
-
+	
 	if (!subif) { /*clear all */
+		spin_lock_bh(&dp_mib_lock);
 		gsw_mib_reset_30(0, 0);
 		gsw_mib_reset_30(1, 0);
 		tmu_reset_mib_all(flag);
@@ -1632,17 +1636,20 @@ int dp_clear_netif_mib_30(dp_subif_t *subif, void *priv, u32 flag)
 		memset(aggregate_mib_r, 0, sizeof(aggregate_mib_r));
 		memset(&last, 0, sizeof(last));
 		memset(&last_vap, 0, sizeof(last_vap));
+		spin_unlock_bh(&dp_mib_lock);
 		return 0;
 	}
 
 	if ((subif->port_id <= 0) ||
 	    subif->port_id >= PMAC_MAX_NUM)
 		return -1;
+
 	port_id = subif->port_id;
 	vap = GET_VAP(subif->subif,
 		      PORT_INFO(0, port_id, vap_offset),
 		      PORT_INFO(0, port_id, vap_mask));
 	if ((flag & DP_F_STATS_SUBIF)) {
+		spin_lock_bh(&dp_mib_lock);
 		/*clear the specific subif mib counter */
 		clear_gsw_itf_mib(subif, flag);
 		dp_clear_mib(subif, 0);
@@ -1663,9 +1670,10 @@ int dp_clear_netif_mib_30(dp_subif_t *subif, void *priv, u32 flag)
 		memset(&last_vap[port_id][vap], 0,
 		       sizeof(last_vap[port_id][vap]));
 		/*how about last[] & last_vap[]*/
+		spin_unlock_bh(&dp_mib_lock);
 		return 0;
 	}
-
+	spin_lock_bh(&dp_mib_lock);
 	/*Clear port based RMON mib */
 	DP_DEBUG(DP_DBG_FLAG_MIB,
 		 "dp_clear_netif_mib port %u mib flag=0x%x\n", port_id, flag);
@@ -1739,6 +1747,7 @@ int dp_clear_netif_mib_30(dp_subif_t *subif, void *priv, u32 flag)
 	subif->subif = -1;
 	clear_gsw_itf_mib(subif, 0);
 	memset(&last[port_id], 0, sizeof(last[port_id]));
+	spin_unlock_bh(&dp_mib_lock);
 	return 0;
 }
 
@@ -2060,7 +2069,8 @@ ssize_t proc_mib_vap_write(struct file *file, const char *buf, size_t count,
 int mib_wraparound_thread(void *data)
 {
 	while (1) {
-		mib_wraparound_timer_poll(0);
+		if (poll_interval) 
+			mib_wraparound_timer_poll(0);
 		msleep(poll_interval / HZ * 1000 / PMAC_MAX_NUM / 2);
 		DP_DEBUG(DP_DBG_FLAG_MIB, "mib_wraparound_thread\n");
 	}
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip30/datapath_proc.c b/drivers/net/ethernet/lantiq/datapath/gswip30/datapath_proc.c
index e27dc62851fdcd43884155c766a4aff1b85ee5f0..7a732d8cb70800dba263ed510c879f92e09b8395 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip30/datapath_proc.c
+++ b/drivers/net/ethernet/lantiq/datapath/gswip30/datapath_proc.c
@@ -176,10 +176,11 @@ static ssize_t proc_parser_write(struct file *file, const char *buf,
 	char *param_list[20];
 	s8 cpu = 0, mpe1 = 0, mpe2 = 0, mpe3 = 0, flag = 0;
 	static int pce_rule_id;
-	GSW_PCE_rule_t pce;
+	static GSW_PCE_rule_t pce;
 	int inst = 0;
 	struct core_ops *gsw_handle;
 
+	memset(&pce, 0, sizeof(pce));
 	gsw_handle = dp_port_prop[inst].ops[GSWIP_R];
 	len = (sizeof(str) > count) ? count : sizeof(str) - 1;
 	len -= copy_from_user(str, buf, len);
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/Kconfig b/drivers/net/ethernet/lantiq/datapath/gswip31/Kconfig
index df86a9a1a9accbc722edadd3269536195e1f2fb5..d5c8cbac2c3b2727959c93fd96aac4a947cf340c 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip31/Kconfig
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/Kconfig
@@ -1,33 +1,49 @@
 menuconfig LTQ_DATAPATH_HAL_GSWIP31
-        bool "Datapath HAL_GSWIP31"
-        default y
-        depends on LTQ_DATAPATH
-        ---help---
-          Datapath Lib is to provide common rx/tx wrapper Lib without taking
-          care of much HW knowledge and also provide common interface for legacy
-          devices and different HW like to CBM or LRO.
-          Take note:
-            All devices need to register to datapath Lib first
+	bool "Datapath HAL_GSWIP31"
+	default y
+	depends on LTQ_DATAPATH
+	---help---
+	  Datapath Lib is to provide common rx/tx wrapper Lib without taking
+	  care of much HW knowledge and also provide common interface for legacy
+	  devices and different HW like to CBM or LRO.
+	  Take note: All devices need to register to datapath Lib first
 
 if LTQ_DATAPATH_HAL_GSWIP31
 config LTQ_DATAPATH_HAL_GSWIP31_MIB
-        bool "Datapath aggregated mib support"
-        depends on LTQ_DATAPATH_HAL_GSWIP30 && SOC_GRX500 && LTQ_TMU && LTQ_PPA_TMU_MIB_SUPPORT
-        default y
-        ---help---
-           It is to aggregate GSWIP-L/R, TMU and driver's MIB counter
+	bool "Datapath aggregated mib support"
+	depends on LTQ_DATAPATH_HAL_GSWIP30 && SOC_GRX500 && LTQ_TMU && LTQ_PPA_TMU_MIB_SUPPORT
+	default y
+	---help---
+	  It is to aggregate GSWIP-L/R, TMU and driver's MIB counter
+
 config LTQ_DATAPATH_HAL_GSWIP30_CPUFREQ
-        bool "Datapath DFS(COC) support"
-        depends on LTQ_DATAPATH && LTQ_CPUFREQ && LTQ_ETHSW_API
-        default y
-        ---help---
-           It is to support DFS(COC) in Datapath
+	bool "Datapath DFS(COC) support"
+	depends on LTQ_DATAPATH && LTQ_CPUFREQ && LTQ_ETHSW_API
+	default y
+	---help---
+	  It is to support DFS(COC) in Datapath
+
 config LTQ_DATAPATH_DDR_SIMULATE_GSWIP31
-        bool "Datapath Simulation GSWIP3.1 based on GRX500 board"
-        default n
-        depends on LTQ_DATAPATH_DBG
-        ---help---
-          Datapath Debug Tool for GSWIP DDR simulation
-                  Only for debugging purpose
-                  By default it should be disabled.
+	bool "Datapath Simulation GSWIP3.1 based on GRX500 board"
+	default n
+	depends on LTQ_DATAPATH_DBG
+	---help---
+		Datapath Debug Tool for GSWIP DDR simulation
+		Only for debugging purpose
+		By default it should be disabled.
+
+config LTQ_DATAPATH_DUMMY_QOS
+	bool "datapath dummy QOS based on slim QOS driver or real QOS API with falcon_test API"
+	default y
+	depends on LTQ_PPV4_QOS_SLIM || (LTQ_PPV4_QOS || LTQ_PPV4)
+
+config LTQ_DATAPATH_DUMMY_QOS_VIA_FALCON_TEST
+	bool "datapath dummy QOS via ppv4 qos driver's falcon_test api, like slim driver"
+	default y
+	depends on (LTQ_PPV4_QOS || LTQ_PPV4) && !LTQ_PPV4_QOS_SLIM && LTQ_DATAPATH_DUMMY_QOS
+
+config LTQ_DATAPATH_QOS_HAL
+	bool "datapath QOS hal"
+	default n
+	depends on (LTQ_PPV4_QOS || LTQ_PPV4) && !LTQ_DATAPATH_DUMMY_QOS_VIA_FALCON_TEST
 endif
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/Makefile b/drivers/net/ethernet/lantiq/datapath/gswip31/Makefile
index 4473af94f8b018b700e234d3e3355971714f6d87..c9a605e077ad812f61bc19dc208f9f32bb715e8a 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip31/Makefile
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/Makefile
@@ -2,7 +2,9 @@ ifneq ($(CONFIG_LTQ_DATAPATH_DDR_SIMULATE_GSWIP31),)
 obj-$(CONFIG_LTQ_DATAPATH) += datapath_gswip_simulate.o
 endif
 
-obj-$(CONFIG_LTQ_DATAPATH) += datapath_misc.o datapath_gswip.o datapath_proc.o datapath_ppv4.o datapath_lookup_proc.o datapath_ppv4_api.o 
+obj-$(CONFIG_LTQ_DATAPATH) += datapath_misc.o datapath_gswip.o datapath_proc.o
+obj-$(CONFIG_LTQ_DATAPATH) += datapath_debugfs.o datapath_ppv4.o
+obj-$(CONFIG_LTQ_DATAPATH) += datapath_lookup_proc.o datapath_ppv4_api.o
 
 ifneq ($(CONFIG_LTQ_DATAPATH_HAL_GSWIP31_MIB),)
 obj-$(CONFIG_LTQ_DATAPATH) += datapath_mib.o
@@ -13,5 +15,5 @@ obj-$(CONFIG_LTQ_DATAPATH) += datapath_coc.o
 endif
 
 ifneq ($(CONFIG_LTQ_DATAPATH_SWITCHDEV),)
-obj-$(CONFIG_LTQ_DATAPATH) += datapath_switchdev.o
+obj-$(CONFIG_LTQ_DATAPATH) += datapath_switchdev.o datapath_ext_vlan.o
 endif
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_debugfs.c b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_debugfs.c
new file mode 100644
index 0000000000000000000000000000000000000000..d2bbea0be29a97c67f41bbdad09cd3c0c3472bab
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_debugfs.c
@@ -0,0 +1,166 @@
+#include <linux/klogging.h>
+#include <net/datapath_proc_api.h>	/*for proc api */
+#include <net/datapath_api.h>
+#include <linux/list.h>
+
+#include "../datapath.h"
+#include "datapath_misc.h"
+
+#include "../datapath_swdev.h"
+
+#define PRINTK  LOGF_KLOG_CONT
+#define DP_MIB_Q "qos_mib"
+#define PRINT_Q_MIB(i, c, x, y, z)\
+	PR_INFO("Q[%03d]:0x%08x 0x%08x 0x%08x 0x%08x\n",\
+		i, c, x, y, z)\
+
+static ssize_t dp_qos_write(struct file *file, const char __user *buf,
+		      size_t count, loff_t *ppos)
+{
+	int len;
+	char str[64];
+	char *p = (char *)str;
+	char *param_list[5] = { 0 };
+	int num = 0;
+	int start, end, i;
+	int inst = 0;
+	u32 c;
+	u32 total_accept_pkt, total_drop_pkt, red_drop_ktp;
+	u32 gree_b, yellow_b;
+
+	len = (sizeof(str) > count) ? count : sizeof(str) - 1;
+	len -= copy_from_user(str, buf, len);
+	str[len] = 0;
+	if (!len)
+		return count;
+
+	num = dp_split_buffer(p, param_list, ARRAY_SIZE(param_list));
+	if ((num == 1) && (strncmp(param_list[0], "help", 4) == 0)) {
+		goto help;
+	} else if (num >= 1) {
+		if (dp_strcmpi(param_list[0], "q") == 0) {
+			start = 0;
+			end = MAX_QUEUE;
+			if (param_list[1])
+				start = dp_atoi(param_list[1]);
+			if (param_list[2])
+				end = dp_atoi(param_list[2]);
+			if (start < 0)
+				start = 0;
+			if (end <= start)
+				end = start + 1;
+			if (end > MAX_QUEUE)
+				end = MAX_QUEUE;
+			PR_INFO("%5s:%10s %10s  %10s  %10s (%d-%d)\n",
+				"QID", "qocc(b)", "accept(p)", "drop(p)", "red_drop(p)",
+				start, end);
+			for (i = start; i < end; i++) {
+				get_q_qocc(inst, i, &c);
+				get_q_mib(inst, i, &total_accept_pkt,
+					  &total_drop_pkt, &red_drop_ktp);
+//	  			if (c || total_accept_pkt || total_drop_pkt ||
+//				    red_drop_ktp)
+					PRINT_Q_MIB(i, c, total_accept_pkt,
+					    total_drop_pkt,	red_drop_ktp);
+			}
+
+		} else if (dp_strcmpi(param_list[0], "p") == 0) {
+            start = 0;
+			end = MAX_QUEUE;
+			if (param_list[1])
+				start = dp_atoi(param_list[1]);
+			if (param_list[2])
+				end = dp_atoi(param_list[2]);
+			if (start < 0)
+				start = 0;
+			if (end <= start)
+				end = start + 1;
+			if (end > MAX_QUEUE)
+				end = MAX_QUEUE;
+			PR_INFO("Port Id :green(b)   yellow(b)  (%d_%d)\n",
+				start, end);
+			for (i = start; i < end; i++) {
+				get_p_mib(inst, i, &gree_b, &yellow_b);
+//				if (gree_b || yellow_b)
+					PR_INFO("P[%03d]: 0x%08x 0x%08x\n",
+						i, gree_b, yellow_b);
+			}
+		}
+	}
+	return count;
+help:   /*                        [0]    [1]*/
+	PR_INFO("queue mib: echo <q> <start qid> <end qid> > %s\n",
+		"/proc/dp/" DP_MIB_Q);
+	PR_INFO("port  mib: echo <p> <start port_id> <end port_id> > %s\n",
+		"/proc/dp/" DP_MIB_Q);
+	return count;
+}
+
+static int dp_qos_seq_read(struct seq_file *s, void *v)
+{
+	int start, end, i;
+	int inst = 0;
+	u32 c;
+	u32 total_accept_pkt, total_drop_pkt, red_drop_ktp;
+	u32 gree_b, yellow_b;
+
+	start = 0;
+	end = MAX_QUEUE;
+	seq_printf(s, "%5s:%10s %10s  %10s  %10s (%d-%d)\n",
+		"QID", "qocc(b)", "accept(p)", "drop(p)", "red_drop(p)",
+		start, end);
+	for (i = start; i < end; i++) {
+		get_q_qocc(inst, i, &c);
+		get_q_mib(inst, i, &total_accept_pkt,
+		  &total_drop_pkt, &red_drop_ktp);
+		if (c || total_accept_pkt || total_drop_pkt ||
+		    red_drop_ktp)
+			seq_printf(s, "Q[%03d]:0x%08x 0x%08x 0x%08x 0x%08x\n", i, c, total_accept_pkt, total_drop_pkt, red_drop_ktp);
+	}
+	seq_printf(s, "Port Id :green(b)   yellow(b)  (%d_%d)\n",
+		start, end);
+	for (i = start; i < end; i++) {
+		get_p_mib(inst, i, &gree_b, &yellow_b);
+		if (gree_b || yellow_b)
+			seq_printf(s, "P[%03d]: 0x%08x 0x%08x\n",
+				i, gree_b, yellow_b);
+	}
+
+	return 0;
+}
+
+static int dp_qos_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dp_qos_seq_read, inode->i_private);
+}
+
+static const struct file_operations dp_qos_fops = {
+	.open = dp_qos_open,
+	.read = seq_read,
+	.write = dp_qos_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+int datapath_debugfs_init(struct datapath_ctrl *pctrl)
+{
+	char datapath_dir[64] = {0};
+	struct dentry *file;
+
+	strlcpy(datapath_dir, pctrl->name, sizeof(datapath_dir));
+	pctrl->debugfs = debugfs_create_dir(datapath_dir, NULL);
+	if (!pctrl->debugfs)
+		return -ENOMEM;
+
+	file = debugfs_create_file("qos_mib", 0644, pctrl->debugfs,
+		   pctrl, &dp_qos_fops);
+   	if (!file)
+		goto err;
+
+	return 0;
+err:
+	debugfs_remove_recursive(pctrl->debugfs);
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(datapath_debugfs_init);
+
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ext_vlan.c b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ext_vlan.c
new file mode 100644
index 0000000000000000000000000000000000000000..07489b874e6118084a829ec208443a218ee46eb3
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ext_vlan.c
@@ -0,0 +1,666 @@
+/*#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include "lantiq_gsw.h"
+#include "lantiq_gsw_api.h"
+#include "gsw_flow_ops.h"*/
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/etherdevice.h>
+#include <net/datapath_api.h>
+#include "../datapath.h"
+
+/*
+ * Adaption
+ */
+/*#define kfree(x)	free(x)
+#define kmalloc(x, y)	malloc(x)*/
+
+/*
+ * Structure passed in by user
+ */
+#if 0
+struct vlan_info1 {
+	/* Changed this TPID field to GSWIP API enum type.
+	 * We do not have flexible for any TPID, only following are supported:
+	 * 1. ignore (don't care)
+	 * 2. 0x8100
+	 * 3. Value configured int VTE Type register
+	 */
+	GSW_ExtendedVlanFilterTpid_t tpid;  /* TPID like 0x8100, 0x8800 */
+	u16 vid ;  /*VLAN ID*/
+	/*note: user priority/CFI both don��t care */
+	/* DSCP to Priority value mapping is possible */
+};
+
+struct vlan1 {
+	int bp;  /*assigned bp for this single VLAN dev */
+	struct vlan_info1 outer_vlan; /*out vlan info */
+	/* Add Ethernet type with GSWIP API enum type.
+	 * Following types are supported:
+	 * 1. ignore	(don't care)
+	 * 2. IPoE  	(0x0800)
+	 * 3. PPPoE 	(0x8863 or 0x8864)
+	 * 4. ARP   	(0x0806)
+	 * 5. IPv6 IPoE	(0x86DD)
+	 */
+	GSW_ExtendedVlanFilterEthertype_t ether_type;
+};
+
+struct vlan2 {
+	int bp;  /*assigned bp for this double VLAN dev */
+	struct vlan_info1 outer_vlan;  /*out vlan info */
+	struct vlan_info1 inner_vlan;   /*in vlan info */
+	/* Add Ethernet type with GSWIP API enum type.
+	 * Following types are supported:
+	 * 1. ignore	(don't care)
+	 * 2. IPoE  	(0x0800)
+	 * 3. PPPoE 	(0x8863 or 0x8864)
+	 * 4. ARP   	(0x0806)
+	 * 5. IPv6 IPoE	(0x86DD)
+	 */
+	GSW_ExtendedVlanFilterEthertype_t ether_type;
+};
+#endif
+
+/*
+ * Structure only used by function set_gswip_ext_vlan
+ */
+struct priv_ext_vlan {
+	/* number of bridge ports has VLAN */
+	u32 num_bp;
+	/* bridge port list (vlan1_list + vlan2_list) */
+	u32 bp[1];
+};
+
+/*
+ * Supporting Functions
+ */
+static int update_vlan0(struct core_ops *ops, u32 bp,
+			GSW_EXTENDEDVLAN_config_t *vcfg)
+{
+	GSW_return_t ret;
+	u32 block = vcfg->nExtendedVlanBlockId;
+
+	memset(vcfg, 0, sizeof(*vcfg));
+	vcfg->nExtendedVlanBlockId = block;
+	vcfg->nEntryIndex = 0;
+	vcfg->sFilter.sOuterVlan.eType = GSW_EXTENDEDVLAN_FILTER_TYPE_NO_TAG;
+	vcfg->sFilter.eEtherType = GSW_EXTENDEDVLAN_FILTER_ETHERTYPE_NO_FILTER;
+	vcfg->sTreatment.bReassignBridgePort = LTQ_TRUE;
+	vcfg->sTreatment.nNewBridgePortId = bp;
+	ret = ops->gsw_extvlan_ops.ExtendedVlan_Set(ops, vcfg);
+
+	if (ret != GSW_statusOk)
+		return -EIO;
+
+	memset(vcfg, 0, sizeof(*vcfg));
+	vcfg->nExtendedVlanBlockId = block;
+	vcfg->nEntryIndex = 1;
+	vcfg->sFilter.sOuterVlan.eType = GSW_EXTENDEDVLAN_FILTER_TYPE_DEFAULT;
+	vcfg->sFilter.sInnerVlan.eType = GSW_EXTENDEDVLAN_FILTER_TYPE_NO_TAG;
+	vcfg->sFilter.eEtherType = GSW_EXTENDEDVLAN_FILTER_ETHERTYPE_NO_FILTER;
+	vcfg->sTreatment.bReassignBridgePort = LTQ_TRUE;
+	vcfg->sTreatment.nNewBridgePortId = bp;
+	ret = ops->gsw_extvlan_ops.ExtendedVlan_Set(ops, vcfg);
+
+	if (ret != GSW_statusOk)
+		return -EIO;
+
+	memset(vcfg, 0, sizeof(*vcfg));
+	vcfg->nExtendedVlanBlockId = block;
+	vcfg->nEntryIndex = 2;
+	vcfg->sFilter.sInnerVlan.eType = GSW_EXTENDEDVLAN_FILTER_TYPE_DEFAULT;
+	vcfg->sFilter.eEtherType = GSW_EXTENDEDVLAN_FILTER_ETHERTYPE_NO_FILTER;
+	vcfg->sTreatment.bReassignBridgePort = LTQ_TRUE;
+	vcfg->sTreatment.nNewBridgePortId = bp;
+	ret = ops->gsw_extvlan_ops.ExtendedVlan_Set(ops, vcfg);
+
+	if (ret != GSW_statusOk)
+		return -EIO;
+
+	return 0;
+}
+
+static int update_vlan1(struct core_ops *ops, int base, int num,
+			struct vlan1 *vlan_list, int drop,
+			GSW_EXTENDEDVLAN_config_t *vcfg)
+{
+	GSW_return_t ret;
+	u32 block = vcfg->nExtendedVlanBlockId;
+	int i;
+
+	for (i = 0; i < num; i++, base += 2) {
+		memset(vcfg, 0, sizeof(*vcfg));
+		vcfg->nExtendedVlanBlockId = block;
+		vcfg->nEntryIndex = base;
+
+		vcfg->sFilter.sOuterVlan.eType =
+			GSW_EXTENDEDVLAN_FILTER_TYPE_NORMAL;
+		vcfg->sFilter.sOuterVlan.bPriorityEnable = LTQ_FALSE;
+		vcfg->sFilter.sOuterVlan.bVidEnable = LTQ_TRUE;
+		vcfg->sFilter.sOuterVlan.nVidVal = vlan_list[i].outer_vlan.vid;
+		vcfg->sFilter.sOuterVlan.eTpid = vlan_list[i].outer_vlan.tpid;
+		vcfg->sFilter.sOuterVlan.eDei =
+			GSW_EXTENDEDVLAN_FILTER_DEI_NO_FILTER;
+
+		vcfg->sFilter.sInnerVlan.eType =
+			GSW_EXTENDEDVLAN_FILTER_TYPE_NO_TAG;
+
+		vcfg->sFilter.eEtherType = vlan_list[i].ether_type;
+
+		if (drop) {
+			vcfg->sTreatment.eRemoveTag =
+				GSW_EXTENDEDVLAN_TREATMENT_DISCARD_UPSTREAM;
+		} else {
+			vcfg->sTreatment.eRemoveTag =
+				GSW_EXTENDEDVLAN_TREATMENT_REMOVE_1_TAG;
+			vcfg->sTreatment.bReassignBridgePort = LTQ_TRUE;
+			vcfg->sTreatment.nNewBridgePortId = vlan_list[i].bp;
+		}
+
+		ret = ops->gsw_extvlan_ops.ExtendedVlan_Set(ops, vcfg);
+
+		if (ret != GSW_statusOk)
+			return -EIO;
+
+		memset(vcfg, 0, sizeof(*vcfg));
+		vcfg->nExtendedVlanBlockId = block;
+		vcfg->nEntryIndex = base + 1;
+
+		vcfg->sFilter.sOuterVlan.eType =
+			GSW_EXTENDEDVLAN_FILTER_TYPE_NORMAL;
+		vcfg->sFilter.sOuterVlan.bPriorityEnable = LTQ_FALSE;
+		vcfg->sFilter.sOuterVlan.bVidEnable = LTQ_TRUE;
+		vcfg->sFilter.sOuterVlan.nVidVal = vlan_list[i].outer_vlan.vid;
+		vcfg->sFilter.sOuterVlan.eTpid = vlan_list[i].outer_vlan.tpid;
+		vcfg->sFilter.sOuterVlan.eDei =
+			GSW_EXTENDEDVLAN_FILTER_DEI_NO_FILTER;
+
+		vcfg->sFilter.sInnerVlan.eType =
+			GSW_EXTENDEDVLAN_FILTER_TYPE_NO_FILTER;
+
+		vcfg->sFilter.eEtherType = vlan_list[i].ether_type;
+
+		if (drop) {
+			vcfg->sTreatment.eRemoveTag =
+				GSW_EXTENDEDVLAN_TREATMENT_DISCARD_UPSTREAM;
+		} else {
+			vcfg->sTreatment.eRemoveTag =
+				GSW_EXTENDEDVLAN_TREATMENT_REMOVE_1_TAG;
+			vcfg->sTreatment.bReassignBridgePort = LTQ_TRUE;
+			vcfg->sTreatment.nNewBridgePortId = vlan_list[i].bp;
+		}
+
+		ret = ops->gsw_extvlan_ops.ExtendedVlan_Set(ops, vcfg);
+
+		if (ret != GSW_statusOk)
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static int update_vlan2(struct core_ops *ops, int base, int num,
+			struct vlan2 *vlan_list, int drop,
+			GSW_EXTENDEDVLAN_config_t *vcfg)
+{
+	GSW_return_t ret;
+	u32 block = vcfg->nExtendedVlanBlockId;
+	int i;
+
+	for (i = 0; i < num; i++, base++) {
+		memset(vcfg, 0, sizeof(*vcfg));
+		vcfg->nExtendedVlanBlockId = block;
+		vcfg->nEntryIndex = base;
+
+		vcfg->sFilter.sOuterVlan.eType =
+			GSW_EXTENDEDVLAN_FILTER_TYPE_NORMAL;
+		vcfg->sFilter.sOuterVlan.bPriorityEnable = LTQ_FALSE;
+		vcfg->sFilter.sOuterVlan.bVidEnable = LTQ_TRUE;
+		vcfg->sFilter.sOuterVlan.nVidVal = vlan_list[i].outer_vlan.vid;
+		vcfg->sFilter.sOuterVlan.eTpid = vlan_list[i].outer_vlan.tpid;
+		vcfg->sFilter.sOuterVlan.eDei =
+			GSW_EXTENDEDVLAN_FILTER_DEI_NO_FILTER;
+
+		vcfg->sFilter.sInnerVlan.eType =
+			GSW_EXTENDEDVLAN_FILTER_TYPE_NORMAL;
+		vcfg->sFilter.sInnerVlan.bPriorityEnable = LTQ_FALSE;
+		vcfg->sFilter.sInnerVlan.bVidEnable = LTQ_TRUE;
+		vcfg->sFilter.sInnerVlan.nVidVal = vlan_list[i].inner_vlan.vid;
+		vcfg->sFilter.sInnerVlan.eTpid = vlan_list[i].inner_vlan.tpid;
+		vcfg->sFilter.sInnerVlan.eDei =
+			GSW_EXTENDEDVLAN_FILTER_DEI_NO_FILTER;
+
+		vcfg->sFilter.eEtherType = vlan_list[i].ether_type;
+
+		if (drop) {
+			vcfg->sTreatment.eRemoveTag =
+				GSW_EXTENDEDVLAN_TREATMENT_DISCARD_UPSTREAM;
+		} else {
+			vcfg->sTreatment.eRemoveTag =
+				GSW_EXTENDEDVLAN_TREATMENT_REMOVE_2_TAG;
+			vcfg->sTreatment.bReassignBridgePort = LTQ_TRUE;
+			vcfg->sTreatment.nNewBridgePortId = vlan_list[i].bp;
+		}
+
+		ret = ops->gsw_extvlan_ops.ExtendedVlan_Set(ops, vcfg);
+
+		if (ret != GSW_statusOk)
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static int update_ctp(struct core_ops *ops, struct ext_vlan_info *vlan)
+{
+	static GSW_CTP_portConfig_t ctp;
+	static GSW_EXTENDEDVLAN_config_t vcfg;
+	DP_DEBUG(DP_DBG_FLAG_SWDEV, "bp=%d v1=%d v1_d=%d v2=%d v2_d=%d\n",
+		vlan->bp, vlan->n_vlan1, vlan->n_vlan1_drop,
+		vlan->n_vlan2, vlan->n_vlan2_drop);
+
+	GSW_return_t ret, ret1;
+	ltq_bool_t enable;
+	u32 block;
+	GSW_EXTENDEDVLAN_alloc_t alloc;
+	int i;
+
+	memset(&ctp, 0, sizeof(ctp));
+	memset(&alloc, 0, sizeof(GSW_EXTENDEDVLAN_alloc_t));
+
+	ctp.nLogicalPortId = vlan->logic_port;
+	ctp.nSubIfIdGroup = vlan->subif_grp;
+	ctp.eMask = GSW_CTP_PORT_CONFIG_MASK_INGRESS_VLAN;
+	ret = ops->gsw_ctp_ops.CTP_PortConfigGet(ops, &ctp);
+
+	if (ret != GSW_statusOk)
+		return -EIO;
+
+	enable = ctp.bIngressExtendedVlanEnable;
+	block = ctp.nIngressExtendedVlanBlockId;
+
+	/*disable previous vlan block operation,if enabled and
+	  free the previous allocated vlan blocks
+	  so that new vlan block can be allocated and configured to ctp*/
+	if(enable) {
+		ctp.bIngressExtendedVlanEnable = LTQ_FALSE;
+		ret = ops->gsw_ctp_ops.CTP_PortConfigSet(ops, &ctp);
+		if (ret != GSW_statusOk) {
+			PR_INFO("ERROR : ingress VLan operation disable fail in ctp\n");
+			return -EIO;
+		} else {
+			PR_INFO("ingress VLan operation disabled in ctp\n");
+		}
+
+		alloc.nExtendedVlanBlockId = block;
+		ret = ops->gsw_extvlan_ops.ExtendedVlan_Free(ops, &alloc);
+		if (ret != GSW_statusOk) {
+			PR_INFO("VLAN Free fail\n");
+			return -EIO;
+			PR_INFO("VLAN Free Success\n");
+		}
+	}
+	memset(&alloc, 0, sizeof(GSW_EXTENDEDVLAN_alloc_t));
+
+	alloc.nNumberOfEntries += vlan->n_vlan1 * 2;
+	alloc.nNumberOfEntries += vlan->n_vlan2;
+	alloc.nNumberOfEntries += vlan->n_vlan1_drop * 2;
+	alloc.nNumberOfEntries += vlan->n_vlan2_drop;
+	if (alloc.nNumberOfEntries == 0) {
+		PR_INFO("nNumberOfEntries == 0 , returning to caller\n");
+		return 0;
+	}
+
+	alloc.nNumberOfEntries += 3;
+	ret = ops->gsw_extvlan_ops.ExtendedVlan_Alloc(ops, &alloc);
+
+	if (ret != GSW_statusOk)
+		return -EIO;
+
+
+	vcfg.nExtendedVlanBlockId = alloc.nExtendedVlanBlockId;
+	ret = update_vlan0(ops, vlan->bp, &vcfg);
+
+	if (ret < 0)
+		goto UPDATE_ERROR;
+
+	i = 3;
+	ret = update_vlan2(ops, i, vlan->n_vlan2, vlan->vlan2_list, 0, &vcfg);
+
+	if (ret < 0)
+		goto UPDATE_ERROR;
+
+	i += vlan->n_vlan2;
+	ret = update_vlan2(ops, i, vlan->n_vlan2_drop, vlan->vlan2_drop_list, 1, &vcfg);
+
+	if (ret < 0)
+		goto UPDATE_ERROR;
+
+	i += vlan->n_vlan2_drop;
+	ret = update_vlan1(ops, i, vlan->n_vlan1, vlan->vlan1_list, 0, &vcfg);
+
+	if (ret < 0)
+		goto UPDATE_ERROR;
+
+	i += vlan->n_vlan1;
+	ret = update_vlan1(ops, i, vlan->n_vlan1_drop, vlan->vlan1_drop_list, 1, &vcfg);
+
+	if (ret < 0)
+		goto UPDATE_ERROR;
+
+	ctp.bIngressExtendedVlanEnable = LTQ_TRUE;
+	ctp.nIngressExtendedVlanBlockId = alloc.nExtendedVlanBlockId;
+	ctp.nIngressExtendedVlanBlockSize = 0;
+	ret = ops->gsw_ctp_ops.CTP_PortConfigSet(ops, &ctp);
+
+	if (ret != GSW_statusOk) {
+		PR_INFO("Enable ingress vlan in ctp fail\n");
+		return -EIO;
+	} else {
+		PR_INFO("Enable ingress vlan in ctp success\n");
+		return 0;
+	}
+UPDATE_ERROR:
+	ops->gsw_extvlan_ops.ExtendedVlan_Free(ops, &alloc);
+	return ret;
+}
+
+static int bp_add_vlan1(struct core_ops *ops, struct vlan1 *vlan,
+			GSW_BRIDGE_portConfig_t *bpcfg, GSW_EXTENDEDVLAN_config_t *vcfg)
+{
+	int ret;
+	GSW_EXTENDEDVLAN_alloc_t alloc = {0};
+	GSW_ExtendedVlanFilterType_t types[6] = {
+		GSW_EXTENDEDVLAN_FILTER_TYPE_NO_TAG,
+		GSW_EXTENDEDVLAN_FILTER_TYPE_NO_FILTER,
+		GSW_EXTENDEDVLAN_FILTER_TYPE_DEFAULT,
+		GSW_EXTENDEDVLAN_FILTER_TYPE_NO_TAG,
+		GSW_EXTENDEDVLAN_FILTER_TYPE_NO_FILTER,
+		GSW_EXTENDEDVLAN_FILTER_TYPE_DEFAULT
+	};
+	u32 i;
+
+	memset(bpcfg, 0, sizeof(*bpcfg));
+	bpcfg->nBridgePortId = vlan->bp;
+	bpcfg->eMask = GSW_BRIDGE_PORT_CONFIG_MASK_EGRESS_VLAN;
+	ret = ops->gsw_brdgport_ops.BridgePort_ConfigGet(ops, bpcfg);
+
+	if (ret != GSW_statusOk)
+		return -EIO;
+
+	/* This bridge port should have no egress VLAN configured yet */
+	if (bpcfg->bEgressExtendedVlanEnable != LTQ_FALSE)
+		return -EINVAL;
+
+	alloc.nNumberOfEntries = ARRAY_SIZE(types) / 2;
+	ret = ops->gsw_extvlan_ops.ExtendedVlan_Alloc(ops, &alloc);
+
+	if (ret != GSW_statusOk)
+		return -EIO;
+
+	for (i = 0; i < alloc.nNumberOfEntries; i++) {
+		memset(vcfg, 0, sizeof(*vcfg));
+		vcfg->nExtendedVlanBlockId = alloc.nExtendedVlanBlockId;
+		vcfg->nEntryIndex = i;
+		vcfg->sFilter.sOuterVlan.eType = types[i * 2];
+		vcfg->sFilter.sInnerVlan.eType = types[i * 2 + 1];
+		vcfg->sFilter.eEtherType = vlan->ether_type; /* filter ether_type as ingress */
+
+		vcfg->sTreatment.bAddOuterVlan = LTQ_TRUE;
+		vcfg->sTreatment.sOuterVlan.ePriorityMode =
+			GSW_EXTENDEDVLAN_TREATMENT_PRIORITY_VAL;
+		vcfg->sTreatment.sOuterVlan.ePriorityVal = 0;
+		vcfg->sTreatment.sOuterVlan.eVidMode =
+			GSW_EXTENDEDVLAN_TREATMENT_VID_VAL;
+		vcfg->sTreatment.sOuterVlan.eVidVal = vlan->outer_vlan.vid;
+		vcfg->sTreatment.sOuterVlan.eTpid = vlan->outer_vlan.tpid;
+		vcfg->sTreatment.sOuterVlan.eDei =
+			GSW_EXTENDEDVLAN_TREATMENT_DEI_0;
+
+		vcfg->sTreatment.bAddInnerVlan = LTQ_FALSE;
+
+		ret = ops->gsw_extvlan_ops.ExtendedVlan_Set(ops, vcfg);
+
+		if (ret != GSW_statusOk) {
+			PR_INFO("Failed in updating Extended VLAN entry (%u, %u).\n",
+				alloc.nExtendedVlanBlockId, i);
+			ops->gsw_extvlan_ops.ExtendedVlan_Free(ops, &alloc);
+			return -EIO;
+		}
+	}
+
+	bpcfg->bEgressExtendedVlanEnable = LTQ_TRUE;
+	bpcfg->nEgressExtendedVlanBlockId = alloc.nExtendedVlanBlockId;
+	bpcfg->nEgressExtendedVlanBlockSize = 0;
+	ret = ops->gsw_brdgport_ops.BridgePort_ConfigSet(ops, bpcfg);
+
+	if (ret != GSW_statusOk) {
+		PR_INFO("Failed in attaching Extended VLAN to Bridge Port.\n");
+		ops->gsw_extvlan_ops.ExtendedVlan_Free(ops, &alloc);
+		return -EIO;
+	}
+	else
+		return 0;
+}
+
+static int bp_add_vlan2(struct core_ops *ops, struct vlan2 *vlan,
+			GSW_BRIDGE_portConfig_t *bpcfg, GSW_EXTENDEDVLAN_config_t *vcfg)
+{
+	int ret;
+	GSW_EXTENDEDVLAN_alloc_t alloc = {0};
+	GSW_ExtendedVlanFilterType_t types[6] = {
+		GSW_EXTENDEDVLAN_FILTER_TYPE_NO_TAG,
+		GSW_EXTENDEDVLAN_FILTER_TYPE_NO_FILTER,
+		GSW_EXTENDEDVLAN_FILTER_TYPE_DEFAULT,
+		GSW_EXTENDEDVLAN_FILTER_TYPE_NO_TAG,
+		GSW_EXTENDEDVLAN_FILTER_TYPE_NO_FILTER,
+		GSW_EXTENDEDVLAN_FILTER_TYPE_DEFAULT
+	};
+	u32 i;
+
+	memset(bpcfg, 0, sizeof(*bpcfg));
+	bpcfg->nBridgePortId = vlan->bp;
+	bpcfg->eMask = GSW_BRIDGE_PORT_CONFIG_MASK_EGRESS_VLAN;
+	ret = ops->gsw_brdgport_ops.BridgePort_ConfigGet(ops, bpcfg);
+
+	if (ret != GSW_statusOk)
+		return -EIO;
+
+	/* This bridge port should have no egress VLAN configured yet */
+	if (bpcfg->bEgressExtendedVlanEnable != LTQ_FALSE)
+		return -EINVAL;
+
+	alloc.nNumberOfEntries = ARRAY_SIZE(types) / 2;
+	ret = ops->gsw_extvlan_ops.ExtendedVlan_Alloc(ops, &alloc);
+
+	if (ret != GSW_statusOk)
+		return -EIO;
+
+	for (i = 0; i < alloc.nNumberOfEntries; i++) {
+		memset(vcfg, 0, sizeof(*vcfg));
+		vcfg->nExtendedVlanBlockId = alloc.nExtendedVlanBlockId;
+		vcfg->nEntryIndex = i;
+		vcfg->sFilter.sOuterVlan.eType = types[i * 2];
+		vcfg->sFilter.sInnerVlan.eType = types[i * 2 + 1];
+		vcfg->sFilter.eEtherType = vlan->ether_type; /* filter ether_type as ingress */
+
+		vcfg->sTreatment.bAddOuterVlan = LTQ_TRUE;
+		vcfg->sTreatment.sOuterVlan.ePriorityMode =
+			GSW_EXTENDEDVLAN_TREATMENT_PRIORITY_VAL;
+		vcfg->sTreatment.sOuterVlan.ePriorityVal = 0;
+		vcfg->sTreatment.sOuterVlan.eVidMode =
+			GSW_EXTENDEDVLAN_TREATMENT_VID_VAL;
+		vcfg->sTreatment.sOuterVlan.eVidVal = vlan->outer_vlan.vid;
+		vcfg->sTreatment.sOuterVlan.eTpid = vlan->outer_vlan.tpid;
+		vcfg->sTreatment.sOuterVlan.eDei =
+			GSW_EXTENDEDVLAN_TREATMENT_DEI_0;
+
+		vcfg->sTreatment.bAddInnerVlan = LTQ_TRUE;
+		vcfg->sTreatment.sInnerVlan.ePriorityMode =
+			GSW_EXTENDEDVLAN_TREATMENT_PRIORITY_VAL;
+		vcfg->sTreatment.sInnerVlan.ePriorityVal = 0;
+		vcfg->sTreatment.sInnerVlan.eVidMode =
+			GSW_EXTENDEDVLAN_TREATMENT_VID_VAL;
+		vcfg->sTreatment.sInnerVlan.eVidVal = vlan->inner_vlan.vid;
+		vcfg->sTreatment.sInnerVlan.eTpid = vlan->inner_vlan.tpid;
+		vcfg->sTreatment.sInnerVlan.eDei =
+			GSW_EXTENDEDVLAN_TREATMENT_DEI_0;
+
+		ret = ops->gsw_extvlan_ops.ExtendedVlan_Set(ops, vcfg);
+
+		if (ret != GSW_statusOk) {
+			PR_INFO("Failed in updating Extended VLAN entry (%u, %u).\n",
+				alloc.nExtendedVlanBlockId, i);
+			ops->gsw_extvlan_ops.ExtendedVlan_Free(ops, &alloc);
+			return -EIO;
+		}
+	}
+
+	bpcfg->bEgressExtendedVlanEnable = LTQ_TRUE;
+	bpcfg->nEgressExtendedVlanBlockId = alloc.nExtendedVlanBlockId;
+	bpcfg->nEgressExtendedVlanBlockSize = 0;
+	ret = ops->gsw_brdgport_ops.BridgePort_ConfigSet(ops, bpcfg);
+
+	if (ret != GSW_statusOk) {
+		PR_INFO("Failed in attaching Extended VLAN to Bridge Port.\n");
+		ops->gsw_extvlan_ops.ExtendedVlan_Free(ops, &alloc);
+		return -EIO;
+	}
+	else
+		return 0;
+}
+
+static int bp_add_vlan(struct core_ops *ops, struct ext_vlan_info *vlan,
+		       int idx, GSW_BRIDGE_portConfig_t *bpcfg)
+{
+	static GSW_EXTENDEDVLAN_config_t vcfg;
+
+	if (idx < vlan->n_vlan1)
+		return bp_add_vlan1(ops, vlan->vlan1_list + idx, bpcfg, &vcfg);
+	else
+		return bp_add_vlan2(ops,
+				    vlan->vlan2_list + (idx - vlan->n_vlan1),
+				    bpcfg, &vcfg);
+}
+
+static int bp_rm_vlan(struct core_ops *ops, u32 bp,
+		      GSW_BRIDGE_portConfig_t *bpcfg)
+{
+	DP_DEBUG(DP_DBG_FLAG_SWDEV,"bp=%d\n", bp);
+	int ret;
+	GSW_EXTENDEDVLAN_alloc_t alloc = {0};
+
+	memset(bpcfg, 0, sizeof(*bpcfg));
+	bpcfg->nBridgePortId = bp;
+	bpcfg->eMask = GSW_BRIDGE_PORT_CONFIG_MASK_EGRESS_VLAN;
+	ret = ops->gsw_brdgport_ops.BridgePort_ConfigGet(ops, bpcfg);
+
+	if (ret != GSW_statusOk)
+		return -EIO;
+
+	if (bpcfg->bEgressExtendedVlanEnable == LTQ_FALSE)
+		return 0;
+
+	alloc.nExtendedVlanBlockId = bpcfg->nEgressExtendedVlanBlockId;
+	bpcfg->bEgressExtendedVlanEnable = LTQ_FALSE;
+	ret = ops->gsw_brdgport_ops.BridgePort_ConfigSet(ops, bpcfg);
+
+	if (ret != GSW_statusOk)
+		return -EIO;
+
+	ret = ops->gsw_extvlan_ops.ExtendedVlan_Free(ops, &alloc);
+
+	if (ret != GSW_statusOk)
+		return -EIO;
+	else
+		return 0;
+}
+
+/*
+ * Function for VLAN configure
+ */
+int set_gswip_ext_vlan(struct core_ops *ops, struct ext_vlan_info *vlan,
+		       int flag)
+{
+	static GSW_BRIDGE_portConfig_t bpcfg;
+
+	int ret;
+	struct priv_ext_vlan *old_priv, *new_priv;
+	size_t new_priv_size;
+	int i, j;
+
+	/* Assumptions:
+	 * 1. Every time this function is called, one and only one "vlan" is
+	 *    added or removed. No replacement happens.
+	 * 2. The content of 2 vlan_list (not vlan_drop_list) keeps sequence.
+	 *    Only one new item is inserted or removed. No re-ordering happens.
+	 * 3. Bridge ports are not freed before this function is called. This
+	 *    is not compulsary. Just in case any resource free function
+	 *    such as free VLAN block, disable VLAN from bridge port, fails.
+	 * 4. In egress, assume packet at bridge port has no VLAN before
+	 *    Extended VLAN processing to save 2 Extended VLAN entries. This
+	 *    can be changed later if required.
+	 */
+	DP_DEBUG(DP_DBG_FLAG_SWDEV, "ext vlan info bp=%d logic=%d subif=%d\n",
+		vlan->bp, vlan->logic_port, vlan->subif_grp);
+	ret = update_ctp(ops, vlan);
+
+	if (ret < 0)
+		return ret;
+
+	/* prepare new private data */
+	new_priv_size = sizeof(*new_priv);
+	new_priv_size += sizeof(new_priv->bp[0])
+			 * (vlan->n_vlan1 + vlan->n_vlan2);
+	new_priv = kmalloc(new_priv_size, GFP_KERNEL);
+
+	if (new_priv == NULL)
+		return -ENOMEM;
+
+	new_priv->num_bp = (u32)(vlan->n_vlan1 + vlan->n_vlan2);
+	new_priv->bp[0] = vlan->bp;
+
+	for (i = 0, j = 1; i < vlan->n_vlan1; i++, j++)
+		new_priv->bp[j] = vlan->vlan1_list[i].bp;
+
+	for (i = 0; i < vlan->n_vlan2; i++, j++)
+		new_priv->bp[j] = vlan->vlan2_list[i].bp;
+
+	/* remember pointer to old private data */
+	old_priv = vlan->priv;
+
+	if (old_priv == NULL) {
+		/* no old private data, vlan is added */
+		ret = bp_add_vlan(ops, vlan, 0, &bpcfg);
+	} else if (old_priv->num_bp < new_priv->num_bp) {
+		/* vlan added */
+		for (i = 0;
+		     (u32)i < old_priv->num_bp
+		     && old_priv->bp[i] == new_priv->bp[i];
+		     i++);
+
+		ret = bp_add_vlan(ops, vlan, i, &bpcfg);
+	} else if (old_priv->num_bp > new_priv->num_bp) {
+		/* vlan removed */
+		for (i = 0;
+		     (u32)i < new_priv->num_bp
+		     && old_priv->bp[i] == new_priv->bp[i];
+		     i++);
+
+		bp_rm_vlan(ops, old_priv->bp[i], &bpcfg);
+		ret = 0;
+	} else
+		ret = 0;
+
+	/* return new private data in vlan structure */
+	vlan->priv = new_priv;
+
+	/* free old private data if any */
+	if (old_priv != NULL)
+		kfree(old_priv);
+
+	return ret;
+}
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_gswip.c b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_gswip.c
index 826ce56b2d0d451fc3a890745b064c3dac337366..545f6856aced359145e9c772e36697aff812a294 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_gswip.c
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_gswip.c
@@ -608,7 +608,8 @@ struct gsw_itf *ctp_port_assign(int inst, u8 ep, int bp_default,
 		return NULL;
 	}
 
-	PR_ERR("assign ep=%d with eMode=%d\n", ep, assign->emode);
+	DP_DEBUG(DP_DBG_FLAG_DBG, "assign ep=%d with eMode=%d\n",
+		 ep, assign->emode);
 	itf_assign[ep].mode = assign->emode;
 	itf_assign[ep].n = ctp_assign.nNumberOfCtpPort;
 	itf_assign[ep].start = ctp_assign.nFirstCtpPortId;
@@ -701,7 +702,7 @@ int alloc_bridge_port(int inst, int port_id, int subif, int fid, int bp_member)
  */
 int free_bridge_port(int inst, int bp)
 {
-	GSW_BRIDGE_portConfig_t tmp = {0}, tmp2 = {0};
+	GSW_BRIDGE_portConfig_t *tmp = NULL, *tmp2 = NULL;
 	int i, j;
 	GSW_return_t ret;
 	struct core_ops *gsw_handle;
@@ -709,40 +710,44 @@ int free_bridge_port(int inst, int bp)
 	gsw_handle = dp_port_prop[inst].ops[GSWIP_L];
 	if (bp == CPU_BP)
 		return 0;
+
+	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+	tmp2 = kzalloc(sizeof(*tmp2), GFP_KERNEL);
+	if (!tmp || !tmp2)
+		goto FREE_EXIT;
+	
 	/*read out this delting bridge port's member*/
-	memset(&tmp, 0, sizeof(tmp));
-	tmp.nBridgePortId = bp;
-	tmp.eMask = GSW_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP;
+	tmp->nBridgePortId = bp;
+	tmp->eMask = GSW_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP;
 	ret = gsw_core_api((dp_gsw_cb)gsw_handle->gsw_brdgport_ops
-			   .BridgePort_ConfigGet, gsw_handle, &tmp);
+			   .BridgePort_ConfigGet, gsw_handle, tmp);
 	if (ret != GSW_statusOk) {
 		PR_ERR("Failed GSW_BRIDGE_PORT_CONFIG_GET: %d\n", bp);
 		goto EXIT;
 	}
 	/*remove this delting bridgeport from other bridge port's member*/
-	memset(&tmp2, 0, sizeof(tmp2));
-	for (i = 0; i < ARRAY_SIZE(tmp.nBridgePortMap); i++) {
+	for (i = 0; i < ARRAY_SIZE(tmp->nBridgePortMap); i++) {
 		for (j = 0; j < 16 /*u16*/; j++) {
-			if (!(tmp.nBridgePortMap[i] & (1 << j)))
+			if (!(tmp->nBridgePortMap[i] & (1 << j)))
 				continue; /*not memmber bit set */
-			memset(tmp2.nBridgePortMap, 0,
-			       sizeof(tmp2.nBridgePortMap));
-			tmp2.eMask =
+			memset(tmp2->nBridgePortMap, 0,
+			       sizeof(tmp2->nBridgePortMap));
+			tmp2->eMask =
 				GSW_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP;
-			tmp2.nBridgePortId = i * 16 + j;
+			tmp2->nBridgePortId = i * 16 + j;
 			ret = gsw_core_api((dp_gsw_cb)gsw_handle
 					   ->gsw_brdgport_ops
 					   .BridgePort_ConfigGet, gsw_handle,
-					   &tmp2);
+					   tmp2);
 			if (ret != GSW_statusOk) {
 				PR_ERR("Failed GSW_BRIDGE_PORT_CONFIG_GET\n");
 				goto EXIT;
 			}
-			UNSET_BP_MAP(tmp2.nBridgePortMap, bp);
+			UNSET_BP_MAP(tmp2->nBridgePortMap, bp);
 			ret = gsw_core_api((dp_gsw_cb)gsw_handle
 					   ->gsw_brdgport_ops
 					   .BridgePort_ConfigSet, gsw_handle,
-					   &tmp2);
+					   tmp2);
 			if (ret != GSW_statusOk) {
 				PR_ERR("Failed GSW_BRIDGE_PORT_CONFIG_SET\n");
 				goto EXIT;
@@ -751,15 +756,18 @@ int free_bridge_port(int inst, int bp)
 	}
 EXIT:
 	/*FRee thie bridge port */
-	memset(&tmp, 0, sizeof(tmp));
-	tmp.nBridgePortId = bp;
-	tmp.eMask = GSW_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP;
+	memset(tmp, 0, sizeof(tmp));
+	tmp->nBridgePortId = bp;
+	tmp->eMask = GSW_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP;
 	ret = gsw_core_api((dp_gsw_cb)gsw_handle->gsw_brdgport_ops
-			   .BridgePort_Free, gsw_handle, &tmp);
-	if (ret != GSW_statusOk) {
+			   .BridgePort_Free, gsw_handle, tmp);
+	if (ret != GSW_statusOk)
 		PR_ERR("Failed to GSW_BRIDGE_PORT_FREE:%d\n", bp);
-		return -1;
-	}
+FREE_EXIT:
+	if (tmp)
+		kfree(tmp);
+	if (tmp2)
+		kfree(tmp2);
 	return 0;
 }
 
@@ -814,3 +822,30 @@ int dp_gswip_mac_entry_del(int bport, int fid, int inst, u8 *addr)
 	}
 	return 0;
 }
+
+int cpu_vlan_mod_dis(int inst)
+{
+	GSW_QoS_portRemarkingCfg_t cfg = {0};
+	struct core_ops *ops;
+	int ret;
+
+	ops = dp_port_prop[inst].ops[GSWIP_L];
+
+	cfg.nPortId = 0;
+	ret = gsw_core_api((dp_gsw_cb)ops->gsw_qos_ops.
+			   QoS_PortRemarkingCfgGet, ops, &cfg);
+	if (ret != GSW_statusOk){
+		PR_ERR("QoS_PortRemarkingCfgGet failed\n");
+		return -1;
+	}
+
+	cfg.bPCP_EgressRemarkingEnable = LTQ_FALSE;
+	ret = gsw_core_api((dp_gsw_cb)ops->gsw_qos_ops.
+			   QoS_PortRemarkingCfgSet, ops, &cfg);
+	if (ret != GSW_statusOk){
+		PR_ERR("QoS_PortRemarkingCfgSet failed\n");
+		return -1;
+	}
+
+	return 0;
+}
\ No newline at end of file
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_lookup_proc.c b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_lookup_proc.c
index 62fcf97a532eb3994ccf0c9168e858dae88c2cb7..9ab991884f3d3276cbefa1509362f82693c25e56 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_lookup_proc.c
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_lookup_proc.c
@@ -192,7 +192,7 @@ static void lookup_pattern_match(int tmp_index)
 	int t[LOOKUP_FIELD_BITS] = { 0 };
 	int index;
 
-	DP_DEBUG(DP_DBG_FLAG_DBG,
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP,
 		 "trying with tmp_index=0x%x with lookup_match_num=%d\n",
 		 tmp_index, lookup_match_num);
 	pattern_match_flag = PATTERN_MATCH_INIT;
@@ -202,12 +202,12 @@ static void lookup_pattern_match(int tmp_index)
 		index = tmp_index;
 		for (i = 0; i < LOOKUP_FIELD_BITS; i++)
 			index |= (t[i] << i);
-		DP_DEBUG(DP_DBG_FLAG_DBG, "don't care[14]=");
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "don't care[14]=");
 		for (i = 0; i < LOOKUP_FIELD_BITS; i++)
-			DP_DEBUG(DP_DBG_FLAG_DBG, "%d ", t[i]);
-		DP_DEBUG(DP_DBG_FLAG_DBG, "\n");
+			DP_DEBUG(DP_DBG_FLAG_LOOKUP, "%d ", t[i]);
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "\n");
 
-		DP_DEBUG(DP_DBG_FLAG_DBG, "don't care index=%x\n", index);
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "don't care index=%x\n", index);
 
 		if (lookup_tbl_flags[index] == ENTRY_USED) {
 			pattern_match_flag = PATTERN_MATCH_FAIL;
@@ -221,13 +221,13 @@ static void lookup_pattern_match(int tmp_index)
 			first_qid = qid;
 		} else if (first_qid != qid) {
 			pattern_match_flag = PATTERN_MATCH_FAIL;
-			DP_DEBUG(DP_DBG_FLAG_DBG, "first_qid(%d) != qid(%d)\n",
+			DP_DEBUG(DP_DBG_FLAG_LOOKUP, "first_qid(%d) != qid(%d)\n",
 				 first_qid, qid);
 			goto END;
 		}
 	}
 
- END:
+END:
 	/*save the result if necessary here */
 	if (pattern_match_flag == PATTERN_MATCH_START) {
 		/*pass since still not fail yet */
@@ -250,7 +250,7 @@ static void lookup_pattern_match(int tmp_index)
 			if (lookup_mask1[i])
 				lookup_match_mask[lookup_match_num] |= 1 << i;
 		lookup_match_num++;
-		DP_DEBUG(DP_DBG_FLAG_DBG,
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP,
 			 "left_n=%d lookup_mask_n=%d. Need reduce=%d\n",
 			 left_n, lookup_mask_n, (1 << lookup_mask_n));
 		left_n -= (1 << lookup_mask_n);
@@ -270,11 +270,11 @@ static int list_care_combination(int tmp_index)
 		index = tmp_index;
 		for (i = 0; i < LOOKUP_FIELD_BITS; i++)
 			index |= (t[i] << i);
-		DP_DEBUG(DP_DBG_FLAG_DBG, "care index=%x\n", index);
-		DP_DEBUG(DP_DBG_FLAG_DBG, "care t[14]=");
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "care index=%x\n", index);
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "care t[14]=");
 		for (k = 0; k < LOOKUP_FIELD_BITS; k++)
-			DP_DEBUG(DP_DBG_FLAG_DBG, "%d ", t[k]);
-		DP_DEBUG(DP_DBG_FLAG_DBG, "\n");
+			DP_DEBUG(DP_DBG_FLAG_LOOKUP, "%d ", t[k]);
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "\n");
 		lookup_pattern_match(index);
 	}
 
@@ -291,19 +291,19 @@ static int check_pattern(int *data, int r)
 	int i;
 
 	memset(lookup_mask1, 0, sizeof(lookup_mask1));
-	DP_DEBUG(DP_DBG_FLAG_DBG, "data:");
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP, "data:");
 	for (i = 0; i < r; i++) {
-		DP_DEBUG(DP_DBG_FLAG_DBG, "%d ", data[i]);
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "%d ", data[i]);
 		lookup_mask1[data[i]] = CARE_NOT_FLAG;
 	}
 	lookup_mask_n = r;
 	pattern_match_flag = 0;
-	DP_DEBUG(DP_DBG_FLAG_DBG, "\n");
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP, "\n");
 
-	DP_DEBUG(DP_DBG_FLAG_DBG, "Don't care flag: ");
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP, "Don't care flag: ");
 	for (i = 0; i < LOOKUP_FIELD_BITS; i++)
-		DP_DEBUG(DP_DBG_FLAG_DBG, "%c ", lookup_mask1[i] ? 'x' : '0');
-	DP_DEBUG(DP_DBG_FLAG_DBG, "\n");
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "%c ", lookup_mask1[i] ? 'x' : '0');
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP, "\n");
 
 	list_care_combination(tmp_pattern_port_id << 4);
 	return 0;
@@ -333,7 +333,7 @@ int find_pattern(int port_id, struct seq_file *s, int qid)
 		if (left_n <= 0)
 			break;
 		c_not_care_walkthrought(arr, n, r);
-		DP_DEBUG(DP_DBG_FLAG_DBG, "left_n=%d\n", left_n);
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "left_n=%d\n", left_n);
 		if (!left_n)
 			break;
 	}
@@ -398,7 +398,7 @@ ssize_t proc_get_qid_via_index31(struct file *file, const char *buf,
 	int num;
 
 	len = (count >= sizeof(data)) ? (sizeof(data) - 1) : count;
-	DP_DEBUG(DP_DBG_FLAG_DBG, "len=%d\n", len);
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP, "len=%d\n", len);
 
 	if (len <= 0) {
 		err = -EFAULT;
@@ -412,7 +412,7 @@ ssize_t proc_get_qid_via_index31(struct file *file, const char *buf,
 		return count;
 	}
 
-	data[len - 1] = 0;	/* Make string */
+	data[len - 1] = 0; /* Make string */
 	num = dp_split_buffer(data, param_list, ARRAY_SIZE(param_list));
 
 	if (num <= 1)
@@ -429,16 +429,15 @@ ssize_t proc_get_qid_via_index31(struct file *file, const char *buf,
 			return count;
 		}
 		qid = dp_atoi(param_list[2]);
-
 		/*workaround for mask support */
 		if (get_dont_care_lookup(param_list[1]) == 0) {
 			lookup_table_recursive(LOOKUP_FIELD_BITS - 1, 0, 1,
 					       qid);
 			return count;
 		}
+		PR_INFO("Set to queue[%u] done\n", qid);
 		set_lookup_qid_via_index(lookup_index, qid);
-		PR_INFO("Set lookup[%u 0x%x] ->     queue[%u]\n",
-			lookup_index, lookup_index, qid);
+		return count;
 	} else if ((dp_strcmpi(param_list[0], "get") == 0) ||
 		   (dp_strcmpi(param_list[0], "read") == 0)) {
 		if (get_dont_care_lookup(param_list[1]) == 0) {
@@ -449,6 +448,7 @@ ssize_t proc_get_qid_via_index31(struct file *file, const char *buf,
 		qid = get_lookup_qid_via_index(lookup_index);
 		PR_INFO("Get lookup[%05u 0x%04x] ->     queue[%u]\n",
 			lookup_index, lookup_index, qid);
+		return count;
 	} else if (dp_strcmpi(param_list[0], "find") == 0) {
 		/*read out its all flags for specified qid */
 		int i;
@@ -467,11 +467,13 @@ ssize_t proc_get_qid_via_index31(struct file *file, const char *buf,
 		int new_q = dp_atoi(param_list[2]);
 
 		lookup_table_remap(old_q, new_q);
+		PR_INFO("remap queue[%d] to queue[%d] done\n",
+			old_q, new_q);
 		return count;
 	}
 
 	goto help;
- help:
+help:
 	PR_INFO("Usage: echo set lookup_flags queue_id > /proc/dp/lookup\n");
 	PR_INFO("     : echo get lookup_flags > /proc/dp/lookup\n");
 	PR_INFO("     : echo find  <x> > /proc/dp/lookup\n");
@@ -495,7 +497,7 @@ void lookup_table_via_qid(int qid)
 {
 	u32 index, tmp, i, j, k, f = 0;
 
-	DP_DEBUG(DP_DBG_FLAG_DBG,
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP,
 		 "Try to find all lookup flags mapped to qid %d\n", qid);
 	for (i = 0; i < 16; i++) {	/*ep */
 		for (j = 0; j < 16; j++) {	/*class */
@@ -519,7 +521,7 @@ void lookup_table_remap(int old_q, int new_q)
 {
 	u32 index, tmp, i, j, k, f = 0;
 
-	DP_DEBUG(DP_DBG_FLAG_DBG,
+	DP_DEBUG(DP_DBG_FLAG_LOOKUP,
 		 "Try to remap lookup flags mapped from old_q %d to new_q %d\n",
 		 old_q, new_q);
 	for (i = 0; i < 16; i++) {	/*ep */
@@ -531,9 +533,10 @@ void lookup_table_remap(int old_q, int new_q)
 					continue;
 				set_lookup_qid_via_index(index, new_q);
 				f = 1;
-				PR_INFO("Remap lookup[%05u 0x%04x] %s[%d]\n",
-					index, index,
-					"->     queue", new_q);
+				DP_DEBUG(DP_DBG_FLAG_LOOKUP,
+					 "Remap lookup[%05u 0x%04x] %s[%d]\n",
+					 index, index,
+					 "->     queue", new_q);
 			}
 		}
 	}
@@ -568,7 +571,6 @@ int get_dont_care_lookup(char *s)
 
 	if (len >= LOOKUP_FIELD_BITS + 1)
 		len = LOOKUP_FIELD_BITS + 1;
-	PR_INFO("len=%d\n", len);
 	for (i = len - 1, j = 0; i >= 1; i--, j++) {
 		if ((s[i] == 'x') || (s[i] == 'X')) {
 			lookup_mask2[j] = 1;
@@ -584,14 +586,15 @@ int get_dont_care_lookup(char *s)
 		}
 	}
 	if (flag) {
-		PR_INFO("\nGet lookup flag: ");
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "\nGet lookup flag: ");
 		for (i = LOOKUP_FIELD_BITS - 1; i >= 0; i--) {
 			if (lookup_mask2[i])
-				PR_INFO("x");
+				DP_DEBUG(DP_DBG_FLAG_LOOKUP, "x");
 			else
-				PR_INFO("%d", lookup_flags2[i]);
+				DP_DEBUG(DP_DBG_FLAG_LOOKUP, "%d",
+					lookup_flags2[i]);
 		}
-		PR_INFO("\n");
+		DP_DEBUG(DP_DBG_FLAG_LOOKUP, "\n");
 
 		return 0;
 	} else {
@@ -606,11 +609,12 @@ void lookup_table_recursive(int k, int tmp_index, int set_flag, int qid)
 	if (k < 0) {	/*finish recursive and start real read/set action */
 		if (set_flag) {
 			set_lookup_qid_via_index(tmp_index, qid);
-			PR_INFO("Set lookup[%05u 0x%04x] ->     queue[%d]\n",
-				tmp_index, tmp_index, qid);
+			DP_DEBUG(DP_DBG_FLAG_LOOKUP,
+				 "Set lookup[%05u/0x%04x] ->     queue[%d]\n",
+				 tmp_index, tmp_index, qid);
 		} else {
 			qid = get_lookup_qid_via_index(tmp_index);
-			PR_INFO("Get lookup[%05u 0x%04x] ->     queue[%d]\n",
+			PR_INFO("Get lookup[%05u/0x%04x] ->     queue[%d]\n",
 				tmp_index, tmp_index, qid);
 		}
 		return;
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_misc.c b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_misc.c
index b5992cdfaa69007eaa1a776171bda75b7bcee249..b50adf05d7e80648cfccd9b1081324d74b0a6330 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_misc.c
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_misc.c
@@ -44,6 +44,8 @@
 #include "datapath_switchdev.h"
 #endif
 
+static struct datapath_ctrl dp_ctrl;
+
 static void init_dma_desc_mask(void)
 {
 	/*mask 0: to remove the bit, 1 -- keep the bit */
@@ -235,7 +237,8 @@ void dump_rx_dma_desc(struct dma_rx_desc_0 *desc_0,
 	PR_INFO(" DMA Descripotr:D0=0x%08x D1=0x%08x D2=0x%08x D3=0x%08x\n",
 		*(u32 *)desc_0, *(u32 *)desc_1,
 		*(u32 *)desc_2, *(u32 *)desc_3);
-	PR_INFO("  DW0:res=%d tunl_id=%d flow_id=%d eth_type=%d subif=0x%04x\n",
+	PR_INFO("  DW0:redir=%d res=%d tunl=%d flow=%d ether=%d subif=0x%04x\n",
+		desc_0->field.redir,
 		desc_0->field.resv, desc_0->field.tunnel_id,
 		desc_0->field.flow_id, desc_0->field.eth_type,
 		desc_0->field.dest_sub_if_id);
@@ -272,7 +275,8 @@ void dump_tx_dma_desc(struct dma_tx_desc_0 *desc_0,
 	PR_INFO(" DMA Descripotr:D0=0x%08x D1=0x%08x D2=0x%08x D3=0x%08x\n",
 		*(u32 *)desc_0, *(u32 *)desc_1,
 		*(u32 *)desc_2, *(u32 *)desc_3);
-	PR_INFO("  DW0:res=%d tunl_id=%d flow_id=%d eth_type=%d subif=0x%04x\n",
+	PR_INFO("  DW0:redir=%d res=%d tunl=%d flow=%d ether=%d subif=0x%04x\n",
+		desc_0->field.redir,
 		desc_0->field.resv, desc_0->field.tunnel_id,
 		desc_0->field.flow_id, desc_0->field.eth_type,
 		desc_0->field.dest_sub_if_id);
@@ -280,9 +284,9 @@ void dump_tx_dma_desc(struct dma_tx_desc_0 *desc_0,
 		desc_1->field.session_id, desc_1->field.tcp_err,
 		desc_1->field.nat, desc_1->field.dec, desc_1->field.enc,
 		desc_1->field.mpe2, desc_1->field.mpe1);
-	PR_INFO("  color=%02d ep=%02d ip=%02d\n",
+	PR_INFO("  color=%02d ep=%02d ip=%02d class=%d\n",
 		desc_1->field.color, desc_1->field.ep,
-		desc_1->field.ip);
+		desc_1->field.ip, desc_1->field.classid);
 	PR_INFO("  DW2:data_ptr=0x%08x\n", desc_2->field.data_ptr);
 	PR_INFO("  DW3:own=%d c=%d sop=%d eop=%d dic=%d pdu_type=%d\n",
 		desc_3->field.own, desc_3->field.c, desc_3->field.sop,
@@ -437,41 +441,51 @@ void dp_sys_mib_reset_31(u32 flag)
 #endif
 }
 
+#ifndef CONFIG_LTQ_DATAPATH_QOS_HAL
 int alloc_q_to_port(struct ppv4_q_sch_port *info, u32 flag)
 {
 	struct ppv4_queue q;
 	struct ppv4_port port;
-	int i;
 	int inst = info->inst;
-	struct hal_priv *priv = (struct hal_priv *)dp_port_prop[inst].priv_hal;
+	struct hal_priv *priv = HAL(inst);
 
-	if (!priv)
+	if (!priv) {
 		PR_ERR("why priv NULL ???\n");
+		return -1;
+	}
 
-	if (priv->deq_port_stat[info->cqe_deq].flag != PP_NODE_ALLOC) {
-		port.qos_deq_port = info->cqe_deq;
+	if (priv->deq_port_stat[info->cqe_deq].flag == PP_NODE_FREE) {
+		port.cqm_deq_port = info->cqe_deq;
 		port.tx_pkt_credit = info->tx_pkt_credit;
 		port.tx_ring_addr = info->tx_ring_addr;
 		port.tx_ring_size = info->tx_ring_size;
+		port.inst = inst;
+		port.dp_port = info->dp_port;
 		if (dp_pp_alloc_port(&port)) {
 			PR_ERR("%s fail for deq_port=%d qos_deq_port=%d\n",
 			       "dp_pp_alloc_port",
-			       port.qos_deq_port, port.qos_deq_port);
+			       port.cqm_deq_port, port.qos_deq_port);
 			return -1;
 		}
-		priv->deq_port_stat[info->cqe_deq].node_id = port.node_id;
-		priv->deq_port_stat[info->cqe_deq].flag = PP_NODE_ALLOC;
+		//priv->deq_port_stat[info->cqe_deq].node_id = port.node_id;
+		//priv->deq_port_stat[info->cqe_deq].flag = PP_NODE_ALLOC;
+		info->port_node = port.node_id;
 		info->f_deq_port_en = 1;
 	} else {
 		port.node_id = priv->deq_port_stat[info->cqe_deq].node_id;
 	}
 	q.qid = -1;
 	q.parent = port.node_id;
+	q.inst = inst;
+#ifdef CONFIG_LTQ_DATAPATH_DUMMY_QOS
+	q.dq_port = info->cqe_deq; /*for qos slim driver only */
+#endif
 	if (dp_pp_alloc_queue(&q)) {
 		PR_ERR("%s fail\n",
 		       "dp_pp_alloc_queue");
 		return -1;
 	}
+#ifdef DP_TMP_DEL
 	/*Save queue/scheduler/port information */
 	for (i = 0; i < MAX_PP_CHILD_PER_NODE; i++) {
 		if (priv->deq_port_stat[info->cqe_deq].child[i].flag ==
@@ -483,20 +497,59 @@ int alloc_q_to_port(struct ppv4_q_sch_port *info, u32 flag)
 		PR_ERR("Failed to find one free child ??\n");
 		return -1;
 	}
-	PR_ERR("Get qid=%d for cqe_deq=%d\n", q.qid, info->cqe_deq);
+	DP_DEBUG(DP_DBG_FLAG_DBG,
+		 "Get qid=%d for cqe_deq=%d\n", q.qid, info->cqe_deq);
 	priv->deq_port_stat[info->cqe_deq].child[i].flag = PP_NODE_ALLOC;
 	priv->deq_port_stat[info->cqe_deq].child[i].node_id = q.node_id;
 	priv->deq_port_stat[info->cqe_deq].child[i].type = DP_NODE_QUEUE;
 	priv->deq_port_stat[info->cqe_deq].flag = PP_NODE_ALLOC;
+#endif
 	PORT_VAP(info->inst, info->dp_port, info->ctp, qid) = q.qid;
 	PORT_VAP(info->inst, info->dp_port, info->ctp, q_node) = q.node_id;
 	info->qid = q.qid;
+	info->q_node = q.node_id;
 	priv->qos_queue_stat[q.qid].deq_port = info->cqe_deq;
 	priv->qos_queue_stat[q.qid].node_id = q.node_id;
 	priv->qos_queue_stat[q.qid].flag = PP_NODE_ALLOC;
-	PR_ERR("alloc_q_to_port done\n");
+	DP_DEBUG(DP_DBG_FLAG_DBG, "alloc_q_to_port done\n");
 	return 0;
 }
+#else
+int alloc_q_to_port(struct ppv4_q_sch_port *info, u32 flag)
+{
+	struct dp_node_link link = {0};
+	
+	link.cqm_deq_port.cqm_deq_port = info->cqe_deq;
+	link.dp_port = info->dp_port; /*in case for qos node alloc resv pool*/
+	link.inst = info->inst;
+	link.node_id.q_id = DP_NODE_AUTO_ID;
+	link.node_type = DP_NODE_QUEUE;
+	link.p_node_id.cqm_deq_port = info->cqe_deq;
+	link.p_node_type = DP_NODE_PORT;
+
+#ifdef XXX_TEST /*testing only */
+	{
+		static int kk = 0;
+		info->qid = ++kk;
+		info->q_node = kk * 2;
+		info->port_node = kk * 2 + 1;
+
+		return 0;
+	}
+#endif
+	
+	if (dp_node_link_add(&link, 0)) {
+		PR_ERR("dp_node_link_add_31 fail: cqm_deq_port=%d\n",
+		       info->cqe_deq);
+		return -1;
+	}
+	info->f_deq_port_en = 1;
+	info->qid = link.node_id.q_id;
+	PR_INFO("qid=%d p_node_id=%d for cqm port=%d\n",
+		link.node_id.q_id, link.p_node_id.cqm_deq_port, info->cqe_deq);
+	return 0;
+}
+#endif /*CONFIG_LTQ_DATAPATH_QOS_HAL*/
 
 int dp_platform_queue_set(int inst, u32 flag)
 {
@@ -508,7 +561,9 @@ int dp_platform_queue_set(int inst, u32 flag)
 	u8 f_cpu_q = 0;
 	struct cbm_dp_en_data en_data = {0};
 	struct hal_priv *priv = (struct hal_priv *)dp_port_prop[inst].priv_hal;
+	struct pmac_port_info *port_info;
 
+	port_info = &dp_port_info[inst][0]; /*CPU*/
 	if ((flag & DP_PLATFORM_DE_INIT) == DP_PLATFORM_DE_INIT) {
 		PR_ERR("Need to free resoruce in the future\n");
 		return 0;
@@ -517,6 +572,7 @@ int dp_platform_queue_set(int inst, u32 flag)
 	/*Allocate a drop queue*/
 	if (priv->ppv4_drop_q < 0) {
 		q.parent = 0;
+		q.inst = inst;
 		if (dp_pp_alloc_queue(&q)) {
 			PR_ERR("%s fail to alloc a drop queue ??\n",
 			       "dp_pp_alloc_queue");
@@ -524,7 +580,7 @@ int dp_platform_queue_set(int inst, u32 flag)
 		}
 		priv->ppv4_drop_q = q.qid;
 	} else {
-		PR_ERR("Hardcoded drop queue: %d\n", priv->ppv4_drop_q);
+		PR_INFO("drop queue: %d\n", priv->ppv4_drop_q);
 	}
 	/*Map all lookup entry to drop queue at the beginning*/
 	lookup.mode = CQE_LU_MODE0;
@@ -551,26 +607,65 @@ int dp_platform_queue_set(int inst, u32 flag)
 	/*Alloc queue/scheduler/port per CPU port */
 	cpu_data.dp_inst = inst;
 	cpu_data.cbm_inst = dp_port_prop[inst].cbm_inst;
+#if IS_ENABLED(CONFIG_LTQ_DATAPATH_DDR_SIMULATE_GSWIP31)
+	cpu_data.dq_tx_push_info[0].deq_port = 0;
+	cpu_data.dq_tx_push_info[1].deq_port = -1;
+	cpu_data.dq_tx_push_info[2].deq_port = -1;
+	cpu_data.dq_tx_push_info[3].deq_port = -1;
+#else
 	ret = cbm_cpu_port_get(&cpu_data, 0);
+#endif
 	if (ret == -1) {
 		PR_ERR("%s fail for CPU Port. Why ???\n",
 		       "cbm_cpu_port_get");
 		return -1;
 	}
+	port_info->deq_port_base = 0;
+	port_info->deq_port_num = 0;
 	for (i = 0; i < ARRAY_SIZE(cpu_data.dq_tx_push_info); i++) {
 		if (cpu_data.dq_tx_push_info[i].deq_port == (u32)-1)
 			continue;
-		PR_ERR("cpu(%d) deq_port=%d", i,
-		       cpu_data.dq_tx_push_info[i].deq_port);
+		DP_DEBUG(DP_DBG_FLAG_DBG, "cpu(%d) deq_port=%d",
+			 i, cpu_data.dq_tx_push_info[i].deq_port);
 		q_port.cqe_deq = cpu_data.dq_tx_push_info[i].deq_port;
 		q_port.tx_pkt_credit = cpu_data.dq_tx_push_info[i].
 							tx_pkt_credit;
 		q_port.tx_ring_addr = cpu_data.dq_tx_push_info[i].tx_ring_addr;
 		q_port.tx_ring_size = cpu_data.dq_tx_push_info[i].tx_ring_size;
+
+		/*Sotre Ring Info */
+		priv->deq_port_info[q_port.cqe_deq].tx_pkt_credit =
+			cpu_data.dq_tx_push_info[i].tx_pkt_credit;
+		priv->deq_port_info[q_port.cqe_deq].tx_ring_addr =
+			cpu_data.dq_tx_push_info[i].tx_ring_addr;
+		priv->deq_port_info[q_port.cqe_deq].tx_ring_size =
+			cpu_data.dq_tx_push_info[i].tx_ring_size;
+		PR_INFO("Store CPU ring info\n");
+		PR_INFO("  ring_address[%d]=0x%x\n",
+			q_port.cqe_deq,
+			priv->deq_port_info[q_port.cqe_deq].tx_ring_addr);
+		PR_INFO("  ring_size[%d]=%d\n",
+			q_port.cqe_deq,
+			priv->deq_port_info[q_port.cqe_deq].tx_ring_size);
+		PR_INFO("  credit[%d]=%d\n",
+			q_port.cqe_deq,
+			priv->deq_port_info[q_port.cqe_deq].tx_pkt_credit);
 		q_port.inst = inst;
 		q_port.dp_port = PMAC_CPU_ID;
+		PR_INFO("CPU[%d] ring addr=%x\n", i,
+			cpu_data.dq_tx_push_info[i].tx_ring_addr);
 		q_port.ctp = i; /*fake CTP for CPU port to store its qid*/
-		alloc_q_to_port(&q_port, 0);
+		PR_INFO("alloc_q_to_port...\n");
+		if (alloc_q_to_port(&q_port, 0) ) {
+			PR_ERR("alloc_q_to_port fail for dp_port=%d\n",
+				q_port.dp_port);
+			return -1;
+		}
+		port_info->deq_port_num ++;
+		port_info->subif_info[i].qid = q_port.qid;
+		port_info->subif_info[i].q_node = q_port.q_node;
+		port_info->subif_info[i].qos_deq_port = q_port.port_node;
+		port_info->subif_info[i].cqm_deq_port = q_port.cqe_deq;
 		if (!f_cpu_q) {
 			f_cpu_q = 1;
 			/*Map all CPU port's lookup to its 1st queue only */
@@ -617,7 +712,6 @@ static int dp_platform_set(int inst, u32 flag)
 		priv = (struct hal_priv *)dp_port_prop[inst].priv_hal;
 		priv->ppv4_drop_q = MAX_QUEUE - 1; /*Need change later */
 		gsw_handle = dp_port_prop[inst].ops[0];
-		PR_ERR("dp_platform_set\n");
 		if (!inst)/*only inst zero need DMA descriptor */
 			init_dma_desc_mask();
 		if (!dp_port_prop[inst].ops[0] ||
@@ -627,13 +721,17 @@ static int dp_platform_set(int inst, u32 flag)
 		}
 		if (!inst)
 			dp_sub_proc_install_31();
+		init_qos_fn();
+		dp_ctrl.name = "datapath";
+		datapath_debugfs_init(&dp_ctrl);
 		/*just for debugging purpose */
 		dp_port_info[inst][0].subif_info[0].bp = CPU_BP;
 		INIT_LIST_HEAD(&dp_port_info[inst][0].subif_info[0].logic_dev);
 
 		priv->bp_def = alloc_bridge_port(inst, CPU_PORT, CPU_SUBIF,
 						 CPU_FID, CPU_BP);
-		PR_ERR("bp_def[%d]=%d\n", inst, priv->bp_def);
+		DP_DEBUG(DP_DBG_FLAG_DBG, "bp_def[%d]=%d\n",
+			 inst, priv->bp_def);
 
 		if (!inst) /*only inst zero will support mib feature */
 			mib_init(0);
@@ -658,7 +756,19 @@ static int dp_platform_set(int inst, u32 flag)
 			return -1;
 		}
 
-		dp_platform_queue_set(inst, flag);
+		if (init_ppv4_qos(inst, flag)) {
+			PR_ERR("init_ppv4_qos fail\n");
+			return -1;
+		}
+		if (dp_platform_queue_set(inst, flag)) {
+			PR_ERR("dp_platform_queue_set fail\n");
+
+			return -1;
+		}
+		if (cpu_vlan_mod_dis(inst)) {
+			PR_ERR("cpu_vlan_mod_dis fail\n");
+			return -1;
+		}
 		return 0;
 	}
 
@@ -666,6 +776,7 @@ static int dp_platform_set(int inst, u32 flag)
 	priv = (struct hal_priv *)dp_port_prop[inst].priv_hal;
 	if (priv->bp_def)
 		free_bridge_port(inst, priv->bp_def);
+	init_ppv4_qos(inst, flag); /*de-initialize qos */
 	kfree(priv);
 	dp_port_prop[inst].priv_hal = NULL;
 	return 0;
@@ -673,12 +784,42 @@ static int dp_platform_set(int inst, u32 flag)
 
 static int port_platform_set(int inst, u8 ep, u32 flags)
 {
+	int idx, i;
 	struct hal_priv *priv = (struct hal_priv *)dp_port_prop[inst].priv_hal;
-
 	struct gsw_itf *itf = ctp_port_assign(inst, ep, priv->bp_def, flags);
+	struct pmac_port_info *port_info = &dp_port_info[inst][ep];
 	/*reset_gsw_itf(ep); */
 	dp_port_info[inst][ep].itf_info = itf;
+	if (flags & DP_F_DEREGISTER) {
+		return 0;
+	}
 
+	PR_INFO("priv=%p deq_port_stat=%p qdev=%p\n",
+		priv, 
+		priv  ?priv->deq_port_stat:NULL,
+		priv  ?priv->qdev:NULL);
+	idx = port_info->deq_port_base;
+	
+	for (i = 0; i < port_info->deq_port_num; i++) {
+		priv->deq_port_info[i + idx].tx_ring_addr =
+			port_info->tx_ring_addr +
+			(port_info->tx_ring_offset * i);
+		priv->deq_port_info[i + idx].tx_ring_size =
+			port_info->tx_ring_size;
+		priv->deq_port_info[i + idx].tx_pkt_credit =
+			port_info->tx_pkt_credit;
+	}
+#if IS_ENABLED(CONFIG_LTQ_DATAPATH_DBG)
+	if (DP_DBG_FLAG_DBG & dp_dbg_flag) {
+		for (i = 0; i < port_info->deq_port_num; i++) {
+			PR_INFO("cqm[%d]: addr=%x credit=%d size==%d\n",
+				i + idx,
+				priv->deq_port_info[i + idx].tx_ring_addr,
+				priv->deq_port_info[i + idx].tx_pkt_credit,
+				priv->deq_port_info[i + idx].tx_ring_size);
+		}
+	}
+#endif
 	return 0;
 }
 
@@ -727,7 +868,7 @@ static int subif_hw_set(int inst, int portid, int subif_ix,
 			struct subif_platform_data *data, u32 flags)
 {
 	struct ppv4_q_sch_port q_port = {0};
-	cbm_queue_map_entry_t lookup = {0};
+	static cbm_queue_map_entry_t lookup = {0};
 	u32 lookup_f = CBM_QUEUE_MAP_F_FLOWID_L_DONTCARE |
 		CBM_QUEUE_MAP_F_FLOWID_H_DONTCARE |
 		CBM_QUEUE_MAP_F_EN_DONTCARE |
@@ -735,9 +876,14 @@ static int subif_hw_set(int inst, int portid, int subif_ix,
 		CBM_QUEUE_MAP_F_MPE1_DONTCARE |
 		CBM_QUEUE_MAP_F_MPE2_DONTCARE |
 		CBM_QUEUE_MAP_F_TC_DONTCARE;
-	int subif;
+	int subif, deq_port_idx = 0;
 	struct pmac_port_info *port_info;
+	struct hal_priv *priv = HAL(inst);
 
+	if (!data) {
+		PR_ERR("data NULL\n");
+		return -1;
+	}
 	port_info = &dp_port_info[inst][portid];
 	subif = SET_VAP(subif_ix, port_info->vap_offset,
 			port_info->vap_mask);
@@ -750,33 +896,56 @@ static int subif_hw_set(int inst, int portid, int subif_ix,
 		PR_ERR("need more for logical dev??\n");
 		return 0;
 	}
-	PR_ERR("inst=%d portid=%d dp numsubif=%d subif_ix=%d\n", inst, portid,
-	       port_info->num_subif, subif_ix);
+	DP_DEBUG(DP_DBG_FLAG_DBG,
+		 "inst=%d portid=%d dp numsubif=%d subif_ix=%d\n", inst, portid,
+		 port_info->num_subif, subif_ix);
+	if (data->subif_data)
+		deq_port_idx = data->subif_data->deq_port_idx;
+	if (port_info->deq_port_num < deq_port_idx + 1) {
+		PR_ERR("Wrong deq_port_idx(%d), should < %d\n",
+		       deq_port_idx, port_info->deq_port_num);
+		return -1;
+	}
 	/*1st subif need config queue*/
 	if (!port_info->num_subif)
 		goto QUEUE_CFG;
-	if (!data || !data->subif_data ||
+	if (!data->subif_data ||
 	    !(data->subif_data->flag_ops & DP_SUBIF_Q_PER_CTP))
 		return 0;
-
+	
 QUEUE_CFG:
-	q_port.cqe_deq = port_info->deq_port_base;
-	if ((port_info->deq_port_num > 1) &&
-	    (data && data->subif_data && data->subif_data))
-		q_port.cqe_deq += data->subif_data->deq_port_idx;
-	PR_ERR("cqe_deq=%d\n", q_port.cqe_deq);
-	q_port.tx_pkt_credit = port_info->tx_pkt_credit;
-	q_port.tx_ring_addr = port_info->tx_ring_addr;
-	q_port.tx_ring_size = port_info->tx_ring_size;
+	PR_INFO("QUEUE_CFG\n");
+	q_port.cqe_deq = port_info->deq_port_base + deq_port_idx;
+	DP_DEBUG(DP_DBG_FLAG_DBG, "cqe_deq=%d\n", q_port.cqe_deq);
+	if (!priv) {
+		PR_ERR("priv NULL\n");
+		return -1;
+	}
+	PR_INFO("priv=%p deq_port_stat=%p qdev=%p\n",
+		priv,
+		priv  ?priv->deq_port_stat:NULL,
+		priv  ?priv->qdev:NULL);
+	PR_INFO("cqe_deq=%d inst=%d\n", q_port.cqe_deq, inst);
+	q_port.tx_pkt_credit =
+		priv->deq_port_info[q_port.cqe_deq].tx_pkt_credit;
+	q_port.tx_ring_addr =
+		priv->deq_port_info[q_port.cqe_deq].tx_ring_addr;
+	q_port.tx_ring_size = 
+		priv->deq_port_info[q_port.cqe_deq].tx_ring_size;
+
 	q_port.inst = inst;
 	q_port.dp_port = portid;
 	q_port.ctp = subif_ix;
-
-	alloc_q_to_port(&q_port, 0);
+	if (alloc_q_to_port(&q_port, 0)) {
+		PR_ERR("alloc_q_to_port fail for dp_port=%d\n",
+			q_port.dp_port);
+		return -1;
+	}
 	port_info->subif_info[subif_ix].qid = q_port.qid;
 	port_info->subif_info[subif_ix].q_node = q_port.q_node;
-	port_info->subif_info[subif_ix].qos_deq_port = q_port.cqe_deq;
+	port_info->subif_info[subif_ix].qos_deq_port = q_port.port_node;
 	port_info->subif_info[subif_ix].cqm_deq_port = q_port.cqe_deq;
+	port_info->subif_info[subif_ix].cqm_port_idx = deq_port_idx;
 
 	/*Set CPU port to Mode0 only*/
 	lookup.mode = dp_port_info[inst][portid].cqe_lu_mode;
@@ -796,8 +965,9 @@ QUEUE_CFG:
 			  q_port.qid,
 			  &lookup,
 			  lookup_f);
-	PR_ERR("cbm_queue_map_set qid=%d for dp_port=%d\n",
-	       q_port.qid, lookup.ep);
+	DP_DEBUG(DP_DBG_FLAG_DBG,
+		 "cbm_queue_map_set qid=%d for dp_port=%d\n",
+		 q_port.qid, lookup.ep);
 	if (q_port.f_deq_port_en)
 		data->act = TRIGGER_CQE_DP_ENABLE;
 	return 0;
@@ -806,17 +976,31 @@ QUEUE_CFG:
 static int subif_hw_reset(int inst, int portid, int subif_ix,
 			  struct subif_platform_data *data, u32 flags)
 {
+#ifndef CONFIG_LTQ_DATAPATH_QOS_HAL
 	struct hal_priv *priv = (struct hal_priv *)dp_port_prop[inst].priv_hal;
+#endif /*CONFIG_LTQ_DATAPATH_QOS_HAL*/
 	struct pmac_port_info *port_info = &dp_port_info[inst][portid];
+	struct dp_node_alloc node;
 
 	reset_ctp_bp(inst, subif_ix, portid,
 		     dp_port_info[inst][portid].subif_info[subif_ix].bp);
 	free_bridge_port(inst,
 			 dp_port_info[inst][portid].subif_info[subif_ix].bp);
-	pp_qos_queue_remove(NULL, port_info->subif_info[subif_ix].qid);
-	pp_qos_port_remove(NULL, port_info->subif_info[subif_ix].qos_deq_port);
-	priv->deq_port_stat[port_info->subif_info[subif_ix].qos_deq_port].flag =
+#ifdef CONFIG_LTQ_DATAPATH_QOS_HAL
+	node.inst = inst;
+	node.dp_port = portid;
+	node.type = DP_NODE_QUEUE;
+	node.id.q_id = port_info->subif_info[subif_ix].qid;
+	dp_node_free(&node, 0);
+#else
+	qos_queue_flush(priv->qdev, port_info->subif_info[subif_ix].q_node);
+	qos_queue_remove(priv->qdev, port_info->subif_info[subif_ix].q_node);
+	qos_port_remove(priv->qdev,
+			port_info->subif_info[subif_ix].qos_deq_port);
+	priv->deq_port_stat[port_info->subif_info[subif_ix].cqm_deq_port].flag =
 		PP_NODE_FREE;
+#endif /* CONFIG_LTQ_DATAPATH_QOS_HAL */
+
 	return 0;
 }
 
@@ -961,6 +1145,7 @@ int register_dp_cap_gswip31(int flag)
 	cap.info.swdev_bridge_port_cfg_set = dp_swdev_bridge_port_cfg_set;
 	cap.info.dp_mac_set = dp_gswip_mac_entry_add;
 	cap.info.dp_mac_reset = dp_gswip_mac_entry_del;
+	cap.info.dp_cfg_vlan = dp_gswip_ext_vlan;
 #endif
 	cap.info.cap.tx_hw_chksum = 0;
 	cap.info.cap.rx_hw_chksum = 0;
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_misc.h b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_misc.h
index 504df73a09bf240871f186a16eca8dda03517cd3..c0aae97fd89cc1fedb170959e46044b86e46da35 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_misc.h
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_misc.h
@@ -13,6 +13,8 @@
 #include <linux/notifier.h>
 #include <linux/netdevice.h>
 #include "datapath_ppv4.h"
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #define PMAC_MAX_NUM  16
 #define PAMC_LAN_MAX_NUM 7
@@ -76,14 +78,28 @@ struct resv_info {
 	struct resv_sch *resv_sched; /*!< reserved schedulers info */
 };
 
+struct pp_qos_dev;
 struct hal_priv {
 	struct cqm_deq_stat deq_port_stat[MAX_CQM_DEQ];
 	struct pp_queue_stat qos_queue_stat[MAX_QUEUE];
 	struct pp_sch_stat qos_sch_stat[QOS_MAX_NODES];
+	struct cqm_port_info deq_port_info[MAX_CQM_DEQ];
 
 	struct resv_info resv[MAX_DP_PORTS];
 	int bp_def;
-	s32 ppv4_drop_q;
+	struct pp_qos_dev *qdev; /*ppv4 qos dev */
+	s32 ppv4_drop_q;  /*drop queue: physical id */
+	int cqm_drop_p;
+	unsigned int ppv4_drop_p;  /*drop qos port: workaround for PPV4 API issue.  */
+	unsigned int ppv4_tmp_p; /*workaround for ppv4 queue allocate to
+				  *to get physical queue id
+				  */
+	
+};
+
+struct datapath_ctrl {
+    struct dentry *debugfs;
+    const char *name;
 };
 
 #define SET_PMAC_IGP_EGP(pmac, port_id) ((pmac)->igp_egp = (port_id) & 0xF)
@@ -106,11 +122,27 @@ int proc_print_ctp_bp_info(struct seq_file *s, int inst,
 			   struct pmac_port_info *port,
 			   int subif_index, u32 flag);
 
+#if IS_ENABLED(CONFIG_LTQ_DATAPATH_SWITCHDEV)
 int dp_gswip_mac_entry_add(int bport, int fid, int inst, u8 *addr);
 int dp_gswip_mac_entry_del(int bport, int fid, int inst, u8 *addr);
+int set_gswip_ext_vlan(struct core_ops *ops, struct ext_vlan_info *vlan,
+		       int flag);
+#endif
 int qos_platform_set(int cmd_id, void *node, int flag);
 int dp_node_alloc_31(struct dp_node_alloc *node, int flag);
 int dp_node_free_31(struct dp_node_alloc *node, int flag);
+int dp_deq_port_res_get_31(struct dp_dequeue_res *res, int flag);
+int dp_node_link_en_get_31(struct dp_node_link_enable *en, int flag);
+int dp_node_link_en_set_31(struct dp_node_link_enable *en, int flag);
+int dp_qos_link_prio_set_31(struct dp_node_prio *info, int flag);
+int dp_qos_link_prio_get_31(struct dp_node_prio *info, int flag);
+int dp_node_link_add_31(struct dp_node_link *info, int flag);
+int dp_link_add_31(struct dp_qos_link *cfg, int flag);
+int dp_link_get_31(struct dp_qos_link *cfg, int flag);
+int dp_node_unlink_31(struct dp_node_link *info, int flag);
+int dp_node_link_get_31(struct dp_node_link *info, int flag);
+int dp_queue_conf_set_31(struct dp_queue_conf *cfg, int flag);
+int dp_queue_conf_get_31(struct dp_queue_conf *cfg, int flag);
 
 #if IS_ENABLED(CONFIG_LTQ_DATAPATH_DDR_SIMULATE_GSWIP31)
 GSW_return_t gsw_core_api_ddr_simu31(dp_gsw_cb func, void *ops, void *param);
@@ -156,4 +188,14 @@ ssize_t proc_get_qid_via_index31(struct file *file, const char *buf,
 				 size_t count, loff_t *ppos);
 ssize_t proc_get_qid_via_index(struct file *file, const char *buf,
 			       size_t count, loff_t *ppos);
+int datapath_debugfs_init(struct datapath_ctrl *pctrl);
+int get_q_qocc(int inst, int qid, u32 *c);
+int get_q_mib(int inst, int qid,
+      u32 *total_accept,
+      u32 *total_drop,
+      u32 *red_drop);
+int get_p_mib(int inst, int pid,
+      u32 *green /*green bytes*/,
+      u32 *yellow/*yellow bytes*/);
+int cpu_vlan_mod_dis(int inst);
 #endif
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ppv4.c b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ppv4.c
index 01dd09a51f868e65b212d2f49334b0c546b516b3..9ce537fe4687827c1569f448c542aaf5020c0373 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ppv4.c
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ppv4.c
@@ -11,44 +11,83 @@
 #include "../datapath.h"
 #include "datapath_misc.h"
 
-#define DUMMY_PPV4_QOS
-#ifdef DUMMY_PPV4_QOS
+int (*qos_queue_remove)(struct pp_qos_dev *qos_dev, unsigned int id);
+int (*qos_queue_allocate)(struct pp_qos_dev *qos_dev, unsigned int *id);
+int (*qos_queue_info_get)(struct pp_qos_dev *qos_dev, unsigned int id,
+			  struct pp_qos_queue_info *info);
+int (*qos_port_remove)(struct pp_qos_dev *qos_dev, unsigned int id);
+int (*qos_sched_allocate)(struct pp_qos_dev *qos_dev, unsigned int *id);
+int (*qos_sched_remove)(struct pp_qos_dev *qos_dev, unsigned int id);
+int (*qos_port_allocate)(struct pp_qos_dev *qos_dev,
+			 unsigned int physical_id,
+			 unsigned int *id);
+int (*qos_port_set)(struct pp_qos_dev *qos_dev, unsigned int id,
+		    const struct pp_qos_port_conf *conf);
+void (*qos_port_conf_set_default)(struct pp_qos_port_conf *conf);
+void (*qos_queue_conf_set_default)(struct pp_qos_queue_conf *conf);
+int (*qos_queue_set)(struct pp_qos_dev *qos_dev, unsigned int id,
+		     const struct pp_qos_queue_conf *conf);
+void (*qos_sched_conf_set_default)(struct pp_qos_sched_conf *conf);
+int (*qos_sched_set)(struct pp_qos_dev *qos_dev, unsigned int id,
+		     const struct pp_qos_sched_conf *conf);
+int (*qos_queue_conf_get)(struct pp_qos_dev *qos_dev, unsigned int id,
+			  struct pp_qos_queue_conf *conf);
+int (*qos_queue_flush)(struct pp_qos_dev *qos_dev, unsigned int id);
+int (*qos_sched_conf_get)(struct pp_qos_dev *qos_dev, unsigned int id,
+			  struct pp_qos_sched_conf *conf);
+int (*qos_sched_get_queues)(struct pp_qos_dev *qos_dev, unsigned int id,
+			    uint16_t *queue_ids, unsigned int size,
+			    unsigned int *queues_num);
+int (*qos_port_get_queues)(struct pp_qos_dev *qos_dev, unsigned int id,
+			   uint16_t *queue_ids, unsigned int size,
+				  unsigned int *queues_num);
+int (*qos_port_conf_get)(struct pp_qos_dev *qdev, unsigned int id,
+				   struct pp_qos_port_conf *conf);
+int (*qos_port_info_get)(struct pp_qos_dev *qdev, unsigned int id,
+			 struct pp_qos_port_info *info);
+struct pp_qos_dev *(*qos_dev_open)(unsigned int id);
+int (*qos_dev_init)(struct pp_qos_dev *qos_dev,
+		    struct pp_qos_init_param *conf);
+
+#ifdef CONFIG_LTQ_DATAPATH_DUMMY_QOS
 struct fixed_q_port {
-	int deq_port;
-	int queue_id;
-	int port_node;
-	int queue_node;
-	int q_used;
+	int deq_port; /*cqm dequeue port */
+	int queue_id; /*queue physical id*/
+	int port_node; /*qos dequeue port node id */
+	int queue_node; /*queue node id */
+	int q_used;    /*flag to indicate used or free*/
 };
 
 struct fixed_q_port q_port[] = {
-	{0, 14, 1, 2, 0},
-	{0, 74, 3, 4, 0},
-	{0, 30, 5, 6, 0},
-	{0, 87, 7, 8, 0},
-	{7, 235, 9, 10, 0},
-	{7, 42, 11, 12, 0},
-	{7, 242, 13, 14, 0},
-	{26, 190, 15, 16, 0},
-	{25, 119, 17, 18, 0},
-	{26, 103, 19, 20, 0}
+	{0, 14, 0, 2, 0},
+	{0, 74, 0, 4, 0},
+	{0, 30, 0, 6, 0},
+	{0, 87, 0, 8, 0},
+	{7, 235, 7, 10, 0},
+	{7, 42, 7, 12, 0},
+	{7, 242, 7, 14, 0},
+	{26, 190, 26, 16, 0},
+	{26, 119, 26, 18, 0},
+	{26, 103, 26, 20, 0}
 };
 
-int pp_qos_queue_remove(struct pp_qos_dev *qos_dev, int id)
+static struct pp_qos_dev qdev;
+
+int test_qos_queue_remove(struct pp_qos_dev *qos_dev, unsigned int id)
 {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(q_port); i++) {
 		if (q_port[i].queue_id == id) {
 			q_port[i].q_used = PP_NODE_FREE;
-			PR_INFO("to free qid=%d\n", id);
-			break;
+			DP_DEBUG(DP_DBG_FLAG_DBG, "to free qid=%d\n", id);
+			return 0;
 		}
 	}
-	return 0;
+	return -1;
 }
 
-int pp_qos_queue_allocate(struct pp_qos_dev *qos_dev, int *id)
+int test_qos_queue_allocate(struct pp_qos_dev *qos_dev, unsigned int *id)
 {
 	int i;
 
@@ -56,23 +95,25 @@ int pp_qos_queue_allocate(struct pp_qos_dev *qos_dev, int *id)
 		if ((q_port[i].deq_port == qos_dev->dq_port) &&
 		    (q_port[i].q_used == PP_NODE_FREE)) {
 			q_port[i].q_used = PP_NODE_ALLOC;
-			PR_INFO("allocate qnode_id=%d\n", q_port[i].queue_node);
+			DP_DEBUG(DP_DBG_FLAG_DBG, "allocate qnode_id=%d\n",
+				 q_port[i].queue_node);
 			*id = q_port[i].queue_node;
-			break;
+			return 0;
 		}
 	}
-	return 0;
+	return -1;
 }
 
-int pp_qos_queue_info_get(struct pp_qos_dev *qos_dev, int id,
+int test_qos_queue_info_get(struct pp_qos_dev *qos_dev, unsigned int id,
 			  struct pp_qos_queue_info *info)
 {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(q_port); i++) {
-		if ((q_port[i].queue_node == id) &&
-		    (q_port[i].q_used == PP_NODE_ALLOC)) {
-			PR_INFO("allocate qphy_id=%d\n", q_port[i].queue_id);
+		if ((q_port[i].queue_node == id) /*&&
+		    (q_port[i].q_used == PP_NODE_ALLOC)*/) {
+			DP_DEBUG(DP_DBG_FLAG_DBG, "q[%d]'s qid=%d\n",
+				 id, q_port[i].queue_id);
 			info->physical_id = q_port[i].queue_id;
 			return 0;
 		}
@@ -80,21 +121,167 @@ int pp_qos_queue_info_get(struct pp_qos_dev *qos_dev, int id,
 	return -1;
 }
 
-int pp_qos_port_remove(struct pp_qos_dev *qos_dev, int id)
+int test_qos_port_remove(struct pp_qos_dev *qos_dev, unsigned int id)
+{
+	return 0;
+}
+
+int test_qos_sched_allocate(struct pp_qos_dev *qos_dev, unsigned int *id)
+{
+	return 0;
+}
+
+int test_qos_sched_remove(struct pp_qos_dev *qos_dev, unsigned int id)
+{
+	return 0;
+}
+
+int test_qos_port_allocate(struct pp_qos_dev *qos_dev, unsigned int physical_id,
+			 unsigned int *id)
+{
+	int i;
+
+	if (!id)
+		return -1;
+
+	for (i = 0; i < ARRAY_SIZE(q_port); i++) {
+		if (physical_id == q_port[i].deq_port) {
+			*id = q_port[i].port_node;
+			DP_DEBUG(DP_DBG_FLAG_DBG,
+				 "Ok: Deq_port/Node_id=%d/%d\n",
+				 physical_id, *id);
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int test_qos_port_set(struct pp_qos_dev *qos_dev, unsigned int id,
+		    const struct pp_qos_port_conf *conf)
+{
+	return 0;
+}
+
+void test_qos_port_conf_set_default(struct pp_qos_port_conf *conf)
+{
+}
+
+void test_qos_queue_conf_set_default(struct pp_qos_queue_conf *conf)
+{
+}
+
+int test_qos_queue_set(struct pp_qos_dev *qos_dev, unsigned int id,
+		     const struct pp_qos_queue_conf *conf)
+{
+	return 0;
+}
+
+void test_qos_sched_conf_set_default(struct pp_qos_sched_conf *conf)
+{
+}
+
+int test_qos_sched_set(struct pp_qos_dev *qos_dev, unsigned int id,
+		     const struct pp_qos_sched_conf *conf)
+{
+	return 0;
+}
+
+int test_qos_queue_conf_get(struct pp_qos_dev *qos_dev, unsigned int id,
+			  struct pp_qos_queue_conf *conf)
+{
+	int i;
+
+	if (!conf)
+		return -1;
+	memset(conf, 0, sizeof(*conf));
+	for (i = 0; i < ARRAY_SIZE(q_port); i++) {
+		if (id == q_port[i].queue_node) {
+			conf->queue_child_prop.parent = q_port[i].port_node;
+			conf->common_prop.bandwidth_limit = 0;
+			conf->common_prop.suspended = 0;
+			conf->blocked = 0;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int test_qos_queue_flush(struct pp_qos_dev *qos_dev, unsigned int id)
+{
+	return 0;
+}
+
+int test_qos_sched_conf_get(struct pp_qos_dev *qos_dev, unsigned int id,
+			  struct pp_qos_sched_conf *conf)
+{
+	return -1;
+}
+
+int test_qos_sched_get_queues(struct pp_qos_dev *qos_dev, unsigned int id,
+			    uint16_t *queue_ids, unsigned int size,
+			    unsigned int *queues_num)
+{
+	return 0;
+}
+
+int test_qos_port_get_queues(struct pp_qos_dev *qos_dev, unsigned int id,
+			   uint16_t *queue_ids, unsigned int size,
+			   unsigned int *queues_num)
+{
+	int i, num = 0;
+
+	for (i = 0; i < ARRAY_SIZE(q_port); i++) {
+		if (q_port[i].port_node != id)
+			continue;
+		if (queue_ids && (num < size)) {
+			queue_ids[num] = q_port[i].queue_node;
+			DP_DEBUG(DP_DBG_FLAG_QOS,
+				 "saved[%d] qid[%d/%d] for cqm[%d/%d]\n",
+				 num,
+				 q_port[i].queue_id,
+				 q_port[i].queue_node,
+				 q_port[i].deq_port,
+				 q_port[i].port_node);
+		} else {
+			DP_DEBUG(DP_DBG_FLAG_QOS,
+				 "unsaved[%d]: qid[%d/%d] for cqm[%d/%d]\n",
+				 num,
+				 q_port[i].queue_id,
+				 q_port[i].queue_node,
+				 q_port[i].deq_port,
+				 q_port[i].port_node);
+		}
+		num++;
+	}
+	if (queues_num)
+		*queues_num = num;
+	return 0;
+}
+
+int test_qos_port_conf_get(struct pp_qos_dev *qdev, unsigned int id,
+			   struct pp_qos_port_conf *conf)
 {
 	return 0;
 }
 
-int pp_qos_sched_allocate(struct pp_qos_dev *qos_dev, int *id)
+int test_qos_port_info_get(struct pp_qos_dev *qdev, unsigned int id,
+			   struct pp_qos_port_info *info)
 {
 	return 0;
 }
 
-int pp_qos_sched_remove(struct pp_qos_dev *qos_dev, int id)
+/*this test code is only support one instance */
+struct pp_qos_dev *test_qos_dev_open(unsigned int id)
+{
+	return &qdev;
+}
+
+int test_qos_dev_init(struct pp_qos_dev *qos_dev, struct pp_qos_init_param *conf)
 {
 	return 0;
 }
 
+#ifdef DUMMY_PPV4_QOS_API_OLD
 s32 qos_node_config(struct qos_node_api_param *param)
 {
 	int i;
@@ -107,9 +294,10 @@ s32 qos_node_config(struct qos_node_api_param *param)
 		for (i = 0; i < ARRAY_SIZE(q_port); i++) {
 			if (param->deq_port == q_port[i].deq_port) {
 				param->out_param.node_id = q_port[i].port_node;
-				PR_ERR("Ok: Deq_port/Node_id=%d/%d\n",
-				       param->deq_port,
-				       param->out_param.node_id);
+				DP_DEBUG(DP_DBG_FLAG_DBG,
+					 "Ok: Deq_port/Node_id=%d/%d\n",
+					 param->deq_port,
+					 param->out_param.node_id);
 				return 0;
 			}
 		}
@@ -127,12 +315,13 @@ s32 qos_node_config(struct qos_node_api_param *param)
 				param->out_param.node_id = q_port[i].queue_node;
 				param->out_param.queue_id = q_port[i].queue_id;
 				q_port[i].q_used = 1;
-				PR_ERR("Ok: Deq_port/Node_id=%d/%d %s=%d/%d\n",
-				       q_port[i].deq_port,
-				       param->node_conf.parent_node_id,
-				       "Queue_id/Node",
-				       param->out_param.queue_id,
-				       param->out_param.node_id);
+				DP_DEBUG(DP_DBG_FLAG_DBG,
+					 "Ok:Deq_port/Node_id=%d/%d %s=%d/%d\n",
+					 q_port[i].deq_port,
+					 param->node_conf.parent_node_id,
+					 "Queue_id/Node",
+					 param->out_param.queue_id,
+					 param->out_param.node_id);
 				return 0;
 			}
 		}
@@ -141,8 +330,65 @@ s32 qos_node_config(struct qos_node_api_param *param)
 	       param->node_conf.parent_node_id);
 	return -1;
 }
-#endif
+#endif /*DUMMY_PPV4_QOS_API_OLD*/
 
+#endif /*CONFIG_LTQ_DATAPATH_DUMMY_QOS*/
+
+void init_qos_fn(void)
+{
+#ifdef CONFIG_LTQ_DATAPATH_DUMMY_QOS
+	qos_queue_remove = test_qos_queue_remove;
+	qos_queue_allocate = test_qos_queue_allocate;
+	qos_queue_info_get = test_qos_queue_info_get;
+	qos_port_remove = test_qos_port_remove;
+	qos_sched_allocate = test_qos_sched_allocate;
+	qos_sched_remove = test_qos_sched_remove;
+	qos_port_allocate = test_qos_port_allocate;
+	qos_port_set = test_qos_port_set;
+	qos_port_conf_set_default = test_qos_port_conf_set_default;
+	qos_queue_conf_set_default = test_qos_queue_conf_set_default;
+	qos_queue_set = test_qos_queue_set;
+	qos_sched_conf_set_default = test_qos_sched_conf_set_default;
+	qos_sched_set = test_qos_sched_set;
+	qos_queue_conf_get = test_qos_queue_conf_get;
+	qos_queue_flush = test_qos_queue_flush;
+	qos_sched_conf_get = test_qos_sched_conf_get;
+	qos_sched_get_queues = test_qos_sched_get_queues;
+	qos_port_get_queues = test_qos_port_get_queues;
+	qos_port_conf_get = test_qos_port_conf_get;
+	qos_dev_open = test_qos_dev_open;
+	qos_dev_init = test_qos_dev_init;
+#elif CONFIG_LTQ_PPV4_QOS
+	qos_queue_remove = pp_qos_queue_remove;
+	qos_queue_allocate = pp_qos_queue_allocate;
+	qos_queue_info_get = pp_qos_queue_info_get;
+	qos_port_remove = pp_qos_port_remove;
+	qos_sched_allocate = pp_qos_sched_allocate;
+	qos_sched_remove = pp_qos_sched_remove;
+	qos_port_allocate = pp_qos_port_allocate;
+	qos_port_set = pp_qos_port_set;
+	qos_port_conf_set_default = pp_qos_port_conf_set_default;
+	qos_queue_conf_set_default = pp_qos_queue_conf_set_default;
+	qos_queue_set = pp_qos_queue_set;
+	qos_sched_conf_set_default = pp_qos_sched_conf_set_default;
+	qos_sched_set = pp_qos_sched_set;
+	qos_queue_conf_get = pp_qos_queue_conf_get;
+	qos_queue_flush = pp_qos_queue_flush;
+	qos_sched_conf_get = pp_qos_sched_conf_get;
+	qos_sched_get_queues = pp_qos_sched_get_queues;
+	qos_port_get_queues = pp_qos_port_get_queues;
+	qos_port_conf_get = pp_qos_port_conf_get;
+	qos_dev_open = pp_qos_dev_open;
+	qos_dev_init = pp_qos_dev_init;
+#else
+	/*all NULL function pointer */
+	PR_INFO("call QOS function pointer set to NULL\n");
+#endif /*CONFIG_LTQ_DATAPATH_DUMMY_QOS*/
+
+}
+
+
+#ifdef DUMMY_PPV4_QOS_API_OLD
 /*Port Add
  * Input
  *    Operation Type: Add
@@ -171,6 +417,7 @@ s32 qos_node_config(struct qos_node_api_param *param)
 int dp_pp_alloc_port(struct ppv4_port *info)
 {
 	struct qos_node_api_param param = {0};
+	struct hal_priv *priv = HAL(info->inst);
 
 	param.op_type = QOS_OP_ADD;
 	param.node_conf_flags = NODE_PARAM_FLAG_BW_LIMIT_SET |
@@ -189,12 +436,14 @@ int dp_pp_alloc_port(struct ppv4_port *info)
 	param.port_conf.port_tx_packets_credit = info->tx_pkt_credit;
 	param.port_conf.port_tx_ring_address = info->tx_ring_addr;
 	param.port_conf.port_tx_ring_size = info->tx_ring_size;
-	param.deq_port = info->qos_deq_port;
+	param.deq_port = info->cqm_port;
 
 	if (qos_node_config(&param)) {
 		PR_ERR("Failed to alloc QoS for deq_port=%d\n", param.deq_port);
 		return -1;
 	}
+	priv->deq_port_stat[info->cqm_port].flag = PP_NODE_ALLOC;
+	priv->deq_port_stat[info->cqm_port].node_id = param.out_param.node_id;
 	info->node_id = param.out_param.node_id;
 	return 0;
 }
@@ -313,3 +562,232 @@ int dp_pp_alloc_queue(struct ppv4_queue *info)
 	return 0;
 }
 
+#else /*DUMMY_PPV4_QOS_API_OLD*/
+
+int dp_pp_alloc_port(struct ppv4_port *info)
+{
+	int qos_p_id = 0;
+	struct pp_qos_port_conf conf;
+	struct hal_priv *priv = HAL(info->inst);
+	struct pp_qos_dev *qos_dev = priv->qdev;
+
+	if (qos_port_allocate(qos_dev,
+			      info->cqm_deq_port,
+			      &qos_p_id)) {
+		PR_ERR("Failed to alloc QoS for deq_port=%d\n",
+		       info->cqm_deq_port);
+		return -1;
+	}
+	DP_DEBUG(DP_DBG_FLAG_QOS,
+		 "qos_port_allocate ok with port(cqm/qos)=%d/%d\n",
+		 info->cqm_deq_port, qos_p_id);
+
+	qos_port_conf_set_default(&conf);
+	conf.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	conf.ring_address = (void *)info->tx_ring_addr;
+	conf.ring_size = info->tx_ring_size;
+	conf.packet_credit_enable = 1;
+	conf.credit = info->tx_pkt_credit;
+#if IS_ENABLED(CONFIG_LTQ_DATAPATH_DBG)
+	if (dp_dbg_flag & DP_DBG_FLAG_QOS) {
+		DP_DEBUG(DP_DBG_FLAG_QOS,
+			 "qos_port_set info for p[%d/%d] dp_port=%d:\n",
+			 info->cqm_deq_port, qos_p_id,
+			 info->dp_port);
+		DP_DEBUG(DP_DBG_FLAG_QOS, "  arbitration=%d\n",
+			 conf.port_parent_prop.arbitration);
+		DP_DEBUG(DP_DBG_FLAG_QOS,"  ring_address=0x%x\n",
+			 (unsigned int)conf.ring_address);
+		DP_DEBUG(DP_DBG_FLAG_QOS,"  ring_size=%d\n",
+			 conf.ring_size);
+		DP_DEBUG(DP_DBG_FLAG_QOS,"  packet_credit_enable=%d\n",
+			 conf.packet_credit_enable);
+		DP_DEBUG(DP_DBG_FLAG_QOS,"  credit=%d\n",
+			 conf.credit);
+	}
+#endif
+	if (qos_port_set(qos_dev, qos_p_id, &conf)) {
+		PR_ERR("qos_port_set fail for port(cqm/qos) %d/%d\n",
+		       info->cqm_deq_port, qos_p_id);
+		qos_port_remove(qos_dev, qos_p_id);
+		return -1;
+	}
+	DP_DEBUG(DP_DBG_FLAG_QOS,
+		 "qos_port_set ok for port(cqm/qos) %d/%d\n",
+		       info->cqm_deq_port, qos_p_id);
+	info->node_id = qos_p_id;
+	priv->deq_port_stat[info->cqm_deq_port].flag = PP_NODE_ALLOC;
+	priv->deq_port_stat[info->cqm_deq_port].node_id = qos_p_id;
+	info->node_id = qos_p_id;
+	return 0;
+}
+
+int dp_pp_alloc_queue(struct ppv4_queue *info)
+{
+	struct pp_qos_queue_conf conf;
+	int q_node_id;
+	struct pp_qos_queue_info q_info;
+	struct hal_priv *priv = HAL(info->inst);
+	struct pp_qos_dev *qos_dev = priv->qdev;
+
+#ifdef CONFIG_LTQ_DATAPATH_DUMMY_QOS
+	qos_dev->dq_port = info->dq_port;
+#endif
+	if (qos_queue_allocate(qos_dev, &q_node_id)) {
+#ifdef CONFIG_LTQ_DATAPATH_DUMMY_QOS
+		PR_ERR("qos_queue_allocate fail for dq_port %d\n",
+		       info->dq_port);
+#else
+		PR_ERR("qos_queue_allocate fail\n");
+#endif
+		return -1;
+	}
+	DP_DEBUG(DP_DBG_FLAG_QOS,"qos_queue_allocate ok q_node=%d\n", q_node_id);
+
+	qos_queue_conf_set_default(&conf);
+	conf.wred_enable = 0;
+	conf.queue_wred_max_allowed = 0x400; /*max qocc in pkt */
+	conf.queue_child_prop.parent = info->parent;
+	if (qos_queue_set(qos_dev, q_node_id, &conf)) {
+		PR_ERR("qos_queue_set fail for node_id=%d to parent=%d\n",
+		       q_node_id, info->parent);
+		return -1;
+	}
+	DP_DEBUG(DP_DBG_FLAG_QOS, "To attach q_node=%d to parent_node=%d\n",
+		 q_node_id, conf.queue_child_prop.parent);
+	if (qos_queue_info_get(qos_dev, q_node_id, &q_info)) {
+		PR_ERR("qos_queue_info_get fail for queue node_id=%d\n",
+		       q_node_id);
+		return -1;
+	}
+	info->qid = q_info.physical_id;
+	info->node_id = q_node_id;
+	DP_DEBUG(DP_DBG_FLAG_QOS,"Attached q[%d/%d] to parent_node=%d\n",
+		 q_info.physical_id, q_node_id,
+		 info->parent);
+	return 0;
+}
+#endif /*DUMMY_PPV4_QOS_API_OLD*/
+
+int init_ppv4_qos(int inst, int flag)
+{
+	union {
+		struct pp_qos_port_conf p_conf;
+		struct pp_qos_queue_conf q_conf;
+		struct pp_qos_queue_info q_info;
+		struct pp_qos_init_param param;
+	} t = {0};
+	int res, i;
+	struct hal_priv *priv = HAL(inst);
+#ifdef CONFIG_LTQ_DATAPATH_QOS_HAL
+	unsigned int q;
+	int drop_cqm_port = 26 + 63;
+#endif
+	if (!(flag & DP_PLATFORM_INIT)) {
+		PR_INFO("need to implement de-initialization for qos later\n");
+		priv->qdev = NULL;
+		return DP_SUCCESS;
+	}
+	priv->qdev = qos_dev_open(dp_port_prop[inst].qos_inst);
+	PR_INFO("qos_dev_open qdev=%p\n", priv->qdev);
+	if (!priv->qdev) {
+		PR_ERR("Could not open qos instance %d\n",
+		       dp_port_prop[inst].qos_inst);
+		return DP_FAILURE;
+	}
+	memset(&t.param, 0, sizeof(t.param));
+	t.param.wred_total_avail_resources = 0x10000;
+	t.param.wred_p_const = 512;
+	t.param.wred_max_q_size = 10000;
+	/*reserve all ppv4 port to 1:1 sequnce link cqm port */
+	for (i = 0; i < ARRAY_SIZE(t.param.reserved_ports); i++)
+		t.param.reserved_ports[i] = 1;
+	res = qos_dev_init(priv->qdev, &t.param);
+	if (res) {
+		PR_ERR("qos_dev_init fail for qos inst %d\n",
+		       dp_port_prop[inst].qos_inst);
+		return DP_FAILURE;
+	}
+	PR_INFO("qos_dev_init done\n");
+#ifdef CONFIG_LTQ_DATAPATH_QOS_HAL
+	PR_INFO("Hard-coded last port as drop port: %d\n",
+		drop_cqm_port);
+	PR_INFO("priv=%p deq_port_stat=%p q_dev=%p\n",
+		priv, priv  ?priv->deq_port_stat:NULL,
+		priv  ?priv->qdev:NULL);
+	if (qos_port_allocate(priv->qdev,
+			      drop_cqm_port,
+			      &priv->ppv4_drop_p)) {
+		PR_ERR("Failed to alloc  qos drop port=%d\n",
+			       drop_cqm_port);
+		return -1;
+	}
+	qos_port_conf_set_default(&t.p_conf);
+	t.p_conf.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	t.p_conf.ring_address = (void *)0x24590;  /*dummy addres*/
+	t.p_conf.ring_size = 1;
+	t.p_conf.packet_credit_enable = 0;
+	t.p_conf.credit = 2;
+	t.p_conf.common_prop.suspended = 1;
+	
+#if IS_ENABLED(CONFIG_LTQ_DATAPATH_DBG)
+	if (dp_dbg_flag & DP_DBG_FLAG_QOS) {
+		DP_DEBUG(DP_DBG_FLAG_QOS,
+			 "qos_port_set param: %d/%d for drop pot:\n",
+			 drop_cqm_port, priv->ppv4_drop_p);
+		DP_DEBUG(DP_DBG_FLAG_QOS, "  arbitration=%d\n",
+			 t.p_conf.port_parent_prop.arbitration);
+		DP_DEBUG(DP_DBG_FLAG_QOS,"  ring_address=0x%x\n",
+			 (unsigned int)t.p_conf.ring_address);
+		DP_DEBUG(DP_DBG_FLAG_QOS,"  ring_size=%d\n",
+			 t.p_conf.ring_size);
+		DP_DEBUG(DP_DBG_FLAG_QOS,"  packet_credit_enable=%d\n",
+			 t.p_conf.packet_credit_enable);
+		DP_DEBUG(DP_DBG_FLAG_QOS,"  credit=%d\n",
+			 t.p_conf.credit);
+		DP_DEBUG(DP_DBG_FLAG_QOS,"  suspend=%d\n",
+			 t.p_conf.common_prop.suspended);
+	}
+#endif
+	if (qos_port_set(priv->qdev, priv->ppv4_drop_p, &t.p_conf)) {
+		PR_ERR("qos_port_set fail for port(cqm/qos) %d/%d\n",
+		       drop_cqm_port, priv->ppv4_drop_p);
+		qos_port_remove(priv->qdev, priv->ppv4_drop_p);
+		return -1;
+	}
+
+	if (qos_queue_allocate(priv->qdev, &q)) {
+		PR_ERR("qos_queue_allocate fail\n");
+		qos_port_remove(priv->qdev, q);
+		return -1;
+	}
+	DP_DEBUG(DP_DBG_FLAG_QOS,"ppv4_drop_q alloc ok q_node=%d\n", q);
+
+	qos_queue_conf_set_default(&t.q_conf);\
+	t.q_conf.blocked = 1; /*drop mode */
+	t.q_conf.wred_enable = 0;
+	t.q_conf.queue_wred_max_allowed = 0x400; /*max qocc in pkt */
+	t.q_conf.queue_child_prop.parent = priv->ppv4_drop_p;
+	if (qos_queue_set(priv->qdev, q, &t.q_conf)) {
+		PR_ERR("qos_queue_set fail for node_id=%d to parent=%d\n",
+		       q, t.q_conf.queue_child_prop.parent);
+		return -1;
+	}
+	DP_DEBUG(DP_DBG_FLAG_QOS, "To attach q_node=%d to parent_node=%d\n",
+		 q, priv->ppv4_drop_p);
+	if (qos_queue_info_get(priv->qdev, q, &t.q_info)) {
+		PR_ERR("qos_queue_info_get fail for queue node_id=%d\n",
+		       q);
+		return -1;
+	}
+	priv->ppv4_drop_q = t.q_info.physical_id;
+	priv->cqm_drop_p = drop_cqm_port;
+	DP_DEBUG(DP_DBG_FLAG_QOS, "Drop queue q[%d/%d] to parent=%d/%d\n",
+		 priv->ppv4_drop_q, q,
+		 drop_cqm_port,
+		 priv->ppv4_drop_p);
+#endif
+	PR_INFO("init_ppv4_qos done\n");
+	
+	return res;
+}
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ppv4.h b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ppv4.h
index 5f9fc09d8acb6fc3a8534389441358afe35b2ced..6fcd963fef8d0b1bb5d3ee2da27c53bc7075d3a8 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ppv4.h
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ppv4.h
@@ -10,13 +10,34 @@
 #ifndef DATAPATH_PPV4_H
 #define DATAPATH_PPV4_H
 
+#ifdef CONFIG_LTQ_DATAPATH_DUMMY_QOS
+struct pp_qos_dev {
+	int dq_port;
+};
+#endif
+
+#define MAX_CQM_DEQ 128 /*Need further check*/
+#define MAX_QUEUE   256 /*Need further check*/
+#define MAX_PP_CHILD_PER_NODE  8 /*Maximum queue per scheduler*/
+#define MAX_Q_PER_PORT 32 /* Maximum queue per port */
+#define QOS_MAX_NODES  2048 /*Maximum PPV4 nodes */
+
+#define HAL(inst) ((struct hal_priv *)dp_port_prop[inst].priv_hal)
+#define PARENT(x) (x.queue_child_prop.parent)
+#define PARENT_S(x) (x.sched_child_prop.parent)
+
 struct ppv4_queue {
+	int inst;  /* dp instance */
 	u16 qid;  /*-1 means dynammic, otherwise already configured*/
 	u16 node_id; /*output */
 	u16 sch;  /*-1 means dynammic, otherwise already configured*/
 	u16 parent; /*-1 means no parent.
 		     *it is used for shared dropping queueu purpose
 		     */
+
+#ifdef CONFIG_LTQ_DATAPATH_DUMMY_QOS
+	int dq_port; /*cqm dequeue port for qos slim driver queue alloc only */
+#endif
 };
 
 struct ppv4_scheduler {
@@ -26,9 +47,10 @@ struct ppv4_scheduler {
 };
 
 struct ppv4_port {
+	int inst;
 	u16 dp_port;
-	u16 qos_deq_port; /*-1 means dynammic, otherwise already specified*/
-	u16 cqm_deq_port;
+	u16 qos_deq_port; /*-1 means dynammic, otherwise already specified. Remove in new datapath lib*/
+	u16 cqm_deq_port;  /*rename in new datapath lib*/
 	u16 node_id; /*output */
 
 	u32 tx_pkt_credit;  /*PP port tx bytes credit */
@@ -51,15 +73,7 @@ struct ppv4_q_sch_port {
 	u32 q_node;
 	u32 schd_node;
 	u32 port_node;
-	u32 f_deq_port_en:1; /*Need enable dequee port later */
-};
-
-struct pp_q_list {
-	u32 flag:1; /*0: valid 1-used 2-reserved*/
-	u16 qid;  /*physical queue id */
-	u16 node;
-	u16 parent_type;  /*scheduler/port*/
-	u16 parent;
+	u32 f_deq_port_en:1; /*flag to trigger cbm_dp_enable */
 };
 
 struct pp_sch_list {
@@ -83,21 +97,11 @@ enum PP_NODE_STAT {
 };
 
 struct pp_node {
-	enum PP_NODE_STAT flag; /*0: valid 1-used 2-reserved*/
-	u16 type;
-	u16 node_id;
-	struct pp_node *child[MAX_PP_CHILD_PER_NODE];
+	enum PP_NODE_STAT flag; /*0: FREE 1-used/alloc*/
+	u16 type; /*node type*/
+	u16 node_id;  /*node id */
 };
 
-struct cqm_deq_stat {
-	enum PP_NODE_STAT flag; /*0: valid 1-used 2-reserved*/
-	u16 deq_id; /*qos dequeue port physical id. Maybe no need */
-	u16 node_id; /* qos dequeue port's node id */
-	struct pp_node child[MAX_PP_CHILD_PER_NODE];
-};
-
-#define QOS_MAX_NODES 2048
-
 struct pp_queue_stat {
 	enum PP_NODE_STAT flag; /*0: valid 1-used 2-reserved*/
 	u16 deq_port; /*cqm dequeue port id */
@@ -106,15 +110,78 @@ struct pp_queue_stat {
 };
 
 struct pp_sch_stat {
-	enum PP_NODE_STAT flag; /*0: valid 1-used 2-reserved*/
+	enum PP_NODE_STAT c_flag; /*sch flag linked to child*/
+	enum PP_NODE_STAT p_flag; /*sch flag linked to parent*/
 	u16 resv_idx; /* index of reserve table */
+	struct pp_node child[MAX_PP_CHILD_PER_NODE];
+	u16 child_num; /* Number of child */
+	int type; /*Node type for queue/sch/port:
+	           *sched table is not just for scheduler, also for queue/port
+	           *It is table index is based on logical node id,
+	           *not just scheduler id
+		   */
+	struct pp_node parent; /*valid for node type queue/sch*/
+};
+
+struct cqm_port_info {
+	u32 tx_pkt_credit;  /*PP port tx bytes credit */
+	u32 tx_ring_addr;  /*PP port ring address. should follow HW definition*/
+	u32 tx_ring_size; /*PP port ring size */
 };
 
+struct cqm_deq_stat {
+	enum PP_NODE_STAT flag; /*0: valid 1-used 2-reserved*/
+	u16 deq_id; /*qos dequeue port physical id. Maybe no need */
+	u16 node_id; /* qos dequeue port's node id */
+	struct pp_node child[MAX_PP_CHILD_PER_NODE];
+	u16 child_num; /* Number of child */
+};
+
+void init_qos_fn(void);
+extern int (*qos_queue_remove)(struct pp_qos_dev *qos_dev, unsigned int id);
+extern int (*qos_queue_allocate)(struct pp_qos_dev *qos_dev, unsigned int *id);
+extern int (*qos_queue_info_get)(struct pp_qos_dev *qos_dev, unsigned int id,
+				 struct pp_qos_queue_info *info);
+extern int (*qos_port_remove)(struct pp_qos_dev *qos_dev, unsigned int id);
+extern int (*qos_sched_allocate)(struct pp_qos_dev *qos_dev, unsigned int *id);
+extern int (*qos_sched_remove)(struct pp_qos_dev *qos_dev, unsigned int id);
+extern int (*qos_port_allocate)(struct pp_qos_dev *qos_dev,
+				unsigned int physical_id,
+				unsigned int *id);
+extern int (*qos_port_set)(struct pp_qos_dev *qos_dev, unsigned int id,
+		    const struct pp_qos_port_conf *conf);
+extern void (*qos_port_conf_set_default)(struct pp_qos_port_conf *conf);
+extern void (*qos_queue_conf_set_default)(struct pp_qos_queue_conf *conf);
+extern int (*qos_queue_set)(struct pp_qos_dev *qos_dev, unsigned int id,
+			    const struct pp_qos_queue_conf *conf);
+extern void (*qos_sched_conf_set_default)(struct pp_qos_sched_conf *conf);
+extern int (*qos_sched_set)(struct pp_qos_dev *qos_dev, unsigned int id,
+			    const struct pp_qos_sched_conf *conf);
+extern int (*qos_queue_conf_get)(struct pp_qos_dev *qos_dev, unsigned int id,
+				 struct pp_qos_queue_conf *conf);
+extern int (*qos_queue_flush)(struct pp_qos_dev *qos_dev, unsigned int id);
+extern int (*qos_sched_conf_get)(struct pp_qos_dev *qos_dev, unsigned int id,
+			         struct pp_qos_sched_conf *conf);
+extern int (*qos_sched_get_queues)(struct pp_qos_dev *qos_dev, unsigned int id,
+				   uint16_t *queue_ids, unsigned int size,
+				   unsigned int *queues_num);
+extern int (*qos_port_get_queues)(struct pp_qos_dev *qos_dev, unsigned int id,
+				  uint16_t *queue_ids, unsigned int size,
+				  unsigned int *queues_num);
+extern int (*qos_port_conf_get)(struct pp_qos_dev *qdev, unsigned int id,
+				   struct pp_qos_port_conf *conf);
+extern int (*qos_port_info_get)(struct pp_qos_dev *qdev, unsigned int id,
+				struct pp_qos_port_info *info);
+extern struct pp_qos_dev *(*qos_dev_open)(unsigned int id);
+extern int (*qos_dev_init)(struct pp_qos_dev *qos_dev,
+			   struct pp_qos_init_param *conf);
+
 int dp_pp_alloc_port(struct ppv4_port *info);
 int dp_pp_alloc_sched(struct ppv4_scheduler *info);
 int dp_pp_alloc_queue(struct ppv4_queue *info);
 int alloc_q_to_port(struct ppv4_q_sch_port *info, u32 flag);
 extern struct cqm_deq_stat deq_port_stat[MAX_CQM_DEQ];
 extern struct pp_queue_stat qos_queue_stat[MAX_QUEUE];
+int init_ppv4_qos(int inst, int flag);
 #endif /*DATAPATH_PPV4_H*/
 
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ppv4_api.c b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ppv4_api.c
index afabc10477c3b435b03c6550ecf7f5eda342ea3e..0b9065c1f0c6f6e6b010757514d6f87c062eac19 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ppv4_api.c
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_ppv4_api.c
@@ -1,32 +1,70 @@
 #include <net/datapath_api.h>
 #include <net/datapath_api_qos.h>
+#include <net/pp_qos_drv.h>
 #include "../datapath.h"
 #include "datapath_misc.h"
+#include <net/lantiq_cbm_api.h>
+
+enum flag {
+	DP_NODE_DEC = BIT(0), /*flag to reduce node counter*/
+	DP_NODE_INC = BIT(1), /*flag to increase node counter*/
+	DP_NODE_RST = BIT(2), /*flag to reset node counter*/
+	C_FLAG = BIT(8), /*sch flag linked to node*/
+	P_FLAG = BIT(9) /*sch flag linked to parent*/
+};
 
 int qos_platform_set(int cmd_id, void *node, int flag)
 {
+	struct dp_node_link *node_link = (struct dp_node_link *)node;
+	int inst;
+	struct hal_priv *priv;
+	
+	if (!node)
+		return DP_FAILURE;
+	inst = node_link->inst;
+	priv = HAL(inst);
+	if (!priv->qdev) {
+		PR_ERR("qdev NULL with inst=%d\n", inst);
+		return DP_FAILURE;
+	}
+	
 	switch (cmd_id) {
 	case NODE_LINK_ADD:
+		dp_node_link_add_31((struct dp_node_link *)node, flag);
 		break;
 	case NODE_LINK_GET:
+		dp_node_link_get_31((struct dp_node_link *)node, flag);
 		break;
 	case NODE_LINK_EN_GET:
+		dp_node_link_en_get_31((struct dp_node_link_enable *)node,
+				       flag);
 		break;
 	case NODE_LINK_EN_SET:
+		dp_node_link_en_set_31((struct dp_node_link_enable *)node,
+				       flag);
 		break;
 	case NODE_UNLINK:
+		dp_node_unlink_31((struct dp_node_link *)node, flag);
 		break;
 	case LINK_ADD:
+		dp_link_add_31((struct dp_qos_link *)node, flag);
 		break;
 	case LINK_GET:
+		dp_link_get_31((struct dp_qos_link *)node, flag);
 		break;
 	case LINK_PRIO_SET:
+		dp_qos_link_prio_set_31((struct dp_node_prio *)node,
+					flag);
 		break;
 	case LINK_PRIO_GET:
+		dp_qos_link_prio_get_31((struct dp_node_prio *)node,
+					flag);
 		break;
 	case QUEUE_CFG_SET:
+		dp_queue_conf_set_31((struct dp_queue_conf *)node, flag);
 		break;
 	case QUEUE_CFG_GET:
+		dp_queue_conf_get_31((struct dp_queue_conf *)node, flag);
 		break;
 	case SHAPER_SET:
 		break;
@@ -39,6 +77,7 @@ int qos_platform_set(int cmd_id, void *node, int flag)
 		dp_node_free_31((struct dp_node_alloc *)node, flag);
 		break;
 	case DEQ_PORT_RES_GET:
+		dp_deq_port_res_get_31((struct dp_dequeue_res *)node, flag);
 		break;
 	case COUNTER_MODE_SET:
 		break;
@@ -54,191 +93,2182 @@ int qos_platform_set(int cmd_id, void *node, int flag)
 	return DP_SUCCESS;
 }
 
-int dp_node_alloc_resv_31(struct dp_node_alloc *node, int flag)
+/* get_qid_by_node API
+ * checks for queue node id
+ * upon Success
+ *    return physical id of queue
+ *    else return DP_FAILURE
+ */
+static int get_qid_by_node(int inst, int node_id, int flag)
+{
+	int i;
+	struct hal_priv *priv = HAL(inst);
+
+	for (i = 0; i < MAX_QUEUE; i++) {
+		if (node_id == priv->qos_queue_stat[i].node_id)
+			return i;
+	}
+	return DP_FAILURE;
+}
+
+/* get_cqm_deq_port_by_node API
+ * checks for qos deque port
+ * upon Success
+ *    return physical cqm_deq_port id
+ *    else return DP_FAILURE
+ */
+static int get_cqm_deq_port_by_node(int inst, int node_id, int flag)
+{
+	int i;
+	struct hal_priv *priv = HAL(inst);
+
+	for (i = 0; i < MAX_CQM_DEQ; i++) {
+		if (node_id == priv->deq_port_stat[i].node_id)
+			return i;
+	}
+	return DP_FAILURE;
+}
+
+/* get_node_type_by_node_id API
+ * get node_type node_id in sch global table
+ * upon Success
+ *    return node_type of node_id
+ */
+static int get_node_type_by_node_id(int inst, int node_id, int flag)
+{
+	struct hal_priv *priv = HAL(inst);
+
+	return priv->qos_sch_stat[node_id].type;
+}
+
+/* get_free_child_idx API
+ * check free flag for child in parent's table and return index
+ * else return DP_FAILURE
+ */
+static int get_free_child_idx(int inst, int node_id, int flag)
+{
+	int i;
+	struct hal_priv *priv = HAL(inst);
+
+	for (i = 0; i <= MAX_PP_CHILD_PER_NODE; i++) {
+		if (priv->qos_sch_stat[node_id].child[i].flag == PP_NODE_FREE)
+			return i;
+	}
+	return DP_FAILURE;
+}
+
+/* get_parent_node API
+ * check parent flag in node global table if active retrun parent id
+ * else return DP_FAILURE
+ */
+static int get_parent_node(int inst, int node_id, int flag)
+{
+	struct hal_priv *priv = HAL(inst);
+
+	if (priv->qos_sch_stat[node_id].parent.flag)
+		return priv->qos_sch_stat[node_id].parent.node_id;
+	return DP_FAILURE;
+}
+
+/* get_child_idx_node_id API
+ * check free flag in parent's global table and return index
+ * else return DP_FAILURE
+ */
+static int get_child_idx_node_id(int inst, int node_id, int flag)
+{
+	struct hal_priv *priv = HAL(inst);
+	int i, p_id;
+
+	p_id = priv->qos_sch_stat[node_id].parent.node_id;
+
+	for (i = 0; i <= MAX_PP_CHILD_PER_NODE; i++) {
+		if (node_id == priv->qos_sch_stat[p_id].child[i].node_id)
+			return i;
+	}
+	return DP_FAILURE;
+}
+
+/* node_queue_dec API
+ * for queue id = node_id, flag = DP_NODE_DEC
+ * Set Queue flag from PP_NODE_ACTIVE to PP_NODE_ALLOC
+ * else return DP_FAILURE
+ */
+static int node_queue_dec(int inst, int node_id, int flag)
+{
+	struct hal_priv *priv = HAL(inst);
+	int phy_id = get_qid_by_node(inst, node_id, flag);
+
+	if (phy_id == DP_FAILURE) {
+		PR_ERR("get_qid_by_node failed\n");
+		return DP_FAILURE;
+	}
+
+	if (!(priv->qos_queue_stat[phy_id].flag & PP_NODE_ACTIVE))
+		PR_ERR("Wrong Q[%d] Stat(%d):Expect ACTIVE\n", phy_id,
+		       priv->qos_queue_stat[phy_id].flag);
+	if (!priv->qos_sch_stat[node_id].parent.flag)
+		PR_ERR("Wrong Q[%d]'s Parent Stat(%d):Expect ACTIVE\n", node_id,
+		       priv->qos_sch_stat[node_id].parent.flag);
+	priv->qos_sch_stat[node_id].parent.node_id = 0;
+	priv->qos_sch_stat[node_id].parent.type = 0;
+	priv->qos_sch_stat[node_id].parent.flag = 0;
+	priv->qos_queue_stat[phy_id].flag = PP_NODE_ALLOC;
+	return DP_SUCCESS;
+}
+
+/* node_queue_inc API
+ * for queue id = node_id, flag = DP_NODE_INC
+ * Set Queue flag from PP_NODE_ALLOC to PP_NODE_ACTIVE
+ * else return DP_FAILURE
+ */
+static int node_queue_inc(int inst, int node_id, int flag)
+{
+	struct hal_priv *priv = HAL(inst);
+	int phy_id = get_qid_by_node(inst, node_id, flag);
+
+	if (phy_id == DP_FAILURE) {
+		PR_ERR("get_qid_by_node failed\n");
+		return DP_FAILURE;
+	}
+
+	if (!(priv->qos_queue_stat[phy_id].flag & PP_NODE_ALLOC))
+		PR_ERR("Wrong Q[%d] Stat(%d):Expect ALLOC\n", phy_id,
+		       priv->qos_queue_stat[phy_id].flag);
+	priv->qos_queue_stat[phy_id].flag = PP_NODE_ACTIVE;
+	return DP_SUCCESS;
+}
+
+/* node_queue_rst API
+ * for queue id = node_id, flag = DP_NODE_RST
+ * Set Queue flag from PP_NODE_ALLOC to PP_NODE_FREE
+ * Set allocated memory free
+ * else return DP_FAILURE
+ */
+static int node_queue_rst(int inst, int node_id, int flag)
+{
+	struct hal_priv *priv = HAL(inst);
+	int phy_id = get_qid_by_node(inst, node_id, flag);
+	int resv_idx = priv->qos_queue_stat[phy_id].resv_idx;
+
+	if (phy_id == DP_FAILURE) {
+		PR_ERR("get_qid_by_node failed\n");
+		return DP_FAILURE;
+	}
+
+	if (!(priv->qos_queue_stat[phy_id].flag & PP_NODE_ALLOC))
+		PR_ERR("Wrong Q[%d] Stat(%d):Expect ALLOC\n", phy_id,
+		       priv->qos_queue_stat[phy_id].flag);
+	/* check resv_idx if valid then remove resource from resv table*/
+	if (priv->qos_queue_stat[phy_id].flag & PP_NODE_RESERVE) {
+		if (priv->resv[resv_idx].resv_q->flag != PP_NODE_ALLOC)
+			PR_ERR("Wrong Q[%d] Stat(%d):Expect ALLOC\n", phy_id,
+			       priv->resv[resv_idx].resv_q->flag);
+		/*reset flag in reserved table*/
+		priv->resv[resv_idx].resv_q->flag = PP_NODE_FREE;
+	}
+	/*Remove resource from global table*/
+	memset(&priv->qos_queue_stat[phy_id], 0,
+	       sizeof(priv->qos_queue_stat[phy_id]));
+	memset(&priv->qos_sch_stat[node_id], 0,
+	       sizeof(priv->qos_sch_stat[node_id]));
+	priv->qos_queue_stat[phy_id].resv_idx = -1;
+	return DP_SUCCESS;
+}
+
+/* node_sched_dec API
+ * for scheduler id = node_id, flag = DP_NODE_DEC
+ * Set Sched flag from PP_NODE_ACTIVE to PP_NODE_ALLOC
+ * else return DP_FAILURE
+ */
+static int node_sched_dec(int inst, int node_id, int flag)
+{
+	struct hal_priv *priv = HAL(inst);
+	int idx = get_child_idx_node_id(inst, node_id, 0);
+	if (idx == DP_FAILURE) {
+		PR_ERR("get_child_idx_node_id failed\n");
+		return DP_FAILURE;
+	}
+
+	if (flag & C_FLAG) {
+		if (!priv->qos_sch_stat[node_id].child_num ||
+		    !(priv->qos_sch_stat[node_id].c_flag & PP_NODE_ACTIVE)) {
+			PR_ERR("Wrong Sch[%d] Stat(%d)/child_num(%d):%s\n",
+			       node_id, priv->qos_sch_stat[node_id].c_flag,
+			       priv->qos_sch_stat[node_id].child_num,
+			       "Expect ACTIVE Or non-zero child_num");
+			return DP_FAILURE;
+		}
+		if (priv->qos_sch_stat[node_id].child[idx].flag) {
+			priv->qos_sch_stat[node_id].child[idx].node_id = 0;
+			priv->qos_sch_stat[node_id].child[idx].type = 0;
+			priv->qos_sch_stat[node_id].child[idx].flag = 0;
+		}
+		priv->qos_sch_stat[node_id].child_num--;
+		if (!priv->qos_sch_stat[node_id].child_num)
+			priv->qos_sch_stat[node_id].c_flag = PP_NODE_ALLOC;
+		return DP_SUCCESS;
+	} else if (flag & P_FLAG) {
+		if (!(priv->qos_sch_stat[node_id].p_flag & PP_NODE_ACTIVE))
+			PR_ERR("Wrong Sch[%d] Stat(%d):Expect ACTIVE\n",
+			       node_id, priv->qos_sch_stat[node_id].p_flag);
+		if (!priv->qos_sch_stat[node_id].parent.flag)
+			PR_ERR("Wrong Sch[%d]'s Parent Stat(%d):Expect ACTIV\n",
+			       node_id,
+			       priv->qos_sch_stat[node_id].parent.flag);
+		priv->qos_sch_stat[node_id].parent.node_id = 0;
+		priv->qos_sch_stat[node_id].parent.type = 0;
+		priv->qos_sch_stat[node_id].parent.flag = 0;
+		priv->qos_sch_stat[node_id].p_flag = PP_NODE_ALLOC;
+		return DP_SUCCESS;
+	}
+	return DP_FAILURE;
+}
+
+/* node_sched_inc API
+ * for scheduler id = node_id, flag = DP_NODE_INC
+ * Set Sched flag from PP_NODE_ALLOC to PP_NODE_ACTIVE
+ * else return DP_FAILURE
+ */
+static int node_sched_inc(int inst, int node_id, int flag)
+{
+	struct hal_priv *priv = HAL(inst);
+	
+	if (flag & C_FLAG) {
+		int idx;
+		int child_type;
+	
+		idx = get_free_child_idx(inst, node_id, 0);
+		if (idx == DP_FAILURE) {
+			PR_ERR("get_free_child_idx failed\n");
+			return DP_FAILURE;
+		}
+
+		if (priv->qos_sch_stat[node_id].child_num &&
+		    !(priv->qos_sch_stat[node_id].c_flag & PP_NODE_ACTIVE)) {
+			PR_ERR("Wrong Sch[%d] Stat(%d)/child_num(%d):%s\n",
+			       node_id, priv->qos_sch_stat[node_id].c_flag,
+			       priv->qos_sch_stat[node_id].child_num,
+			       "Expect ACTIVE And Non-Zero child_num");
+			return DP_FAILURE;
+		}
+		if (!priv->qos_sch_stat[node_id].child_num &&
+		    !(priv->qos_sch_stat[node_id].c_flag & PP_NODE_ALLOC)) {
+			PR_ERR("Wrong Sch[%d] Stat(%d)/child_num(%d):%s\n",
+			       node_id, priv->qos_sch_stat[node_id].c_flag,
+			       priv->qos_sch_stat[node_id].child_num,
+			       "Expect ALLOC And zero child_num");
+			return DP_FAILURE;
+		}
+		if (idx == DP_FAILURE) {
+			PR_ERR("get_free_child_idx failed\n");
+			return DP_FAILURE;
+		}
+		child_type = get_node_type_by_node_id(inst, node_id, 0);
+		priv->qos_sch_stat[node_id].child[idx].type = child_type;
+		priv->qos_sch_stat[node_id].child[idx].node_id = node_id;
+		priv->qos_sch_stat[node_id].child[idx].flag = PP_NODE_ACTIVE;
+		priv->qos_sch_stat[node_id].child_num++;
+		priv->qos_sch_stat[node_id].c_flag = PP_NODE_ACTIVE;
+		return DP_SUCCESS;
+	} else if (flag & P_FLAG) {
+		if (!(priv->qos_sch_stat[node_id].p_flag & PP_NODE_ALLOC)) {
+			PR_ERR("Wrong Sch[%d] Stat(%d):Expect ALLOC\n",
+			       node_id, priv->qos_sch_stat[node_id].p_flag);
+			return DP_FAILURE;
+		}
+		priv->qos_sch_stat[node_id].p_flag = PP_NODE_ACTIVE;
+		return DP_SUCCESS;
+	}
+	return DP_FAILURE;
+}
+
+/* node_sched_rst API
+ * for scheduler id = node_id, flag = DP_NODE_RST
+ * sanity check for child_num and both c and p_flag in alloc state
+ * then reset whole sched
+ * Set Sched flag from PP_NODE_ALLOC to PP_NODE_FREE
+ * else return DP_FAILURE
+ */
+static int node_sched_rst(int inst, int node_id, int flag)
+{
+	struct hal_priv *priv = HAL(inst);
+	int resv_idx = priv->qos_sch_stat[node_id].resv_idx;
+
+	/*sanity check for child_num and both c and p_flag in alloc state
+	 *then reset whole sched
+	 */
+	if (priv->qos_sch_stat[node_id].child_num ||
+	    !(priv->qos_sch_stat[node_id].c_flag & PP_NODE_ALLOC) ||
+	    !(priv->qos_sch_stat[node_id].p_flag & PP_NODE_ALLOC)) {
+		PR_ERR("Wrong Sch[%d] c_flag(%d)/p_flag(%d)/child_num(%d):%s\n",
+		       node_id, priv->qos_sch_stat[node_id].c_flag,
+		       priv->qos_sch_stat[node_id].p_flag,
+		       priv->qos_sch_stat[node_id].child_num,
+		       "Expect c_flag OR p_flag ALLOC OR Non-zero child_num");
+		return DP_FAILURE;
+	}
+	/*Free Reserved Resource*/
+	if (priv->resv[resv_idx].resv_sched->flag == PP_NODE_ALLOC) {
+		priv->resv[resv_idx].resv_sched->flag = PP_NODE_FREE;
+		priv->qos_sch_stat[node_id].resv_idx = -1;
+	}
+	/*Free Global Resource*/
+	memset(&priv->qos_sch_stat[node_id], 0,
+	       sizeof(priv->qos_sch_stat[node_id]));
+	priv->qos_sch_stat[node_id].resv_idx = -1;
+	return DP_SUCCESS;
+}
+
+/* node_port_dec API
+ * Check for child_num and active flag
+ * for port logical node_id, flag = DP_NODE_DEC
+ * Set Port flag from PP_NODE_ACTIVE to PP_NODE_ALLOC
+ * else return DP_FAILURE
+ */
+static int node_port_dec(int inst, int node_id, int flag)
+{
+	struct hal_priv *priv = HAL(inst);
+	int phy_id = get_cqm_deq_port_by_node(inst, node_id, flag);
+	int idx = get_child_idx_node_id(inst, node_id, 0);
+
+	if (idx == DP_FAILURE) {
+		PR_ERR("get_child_idx_node_id failed\n");
+		return DP_FAILURE;
+	}
+
+	if (phy_id == DP_FAILURE) {
+		PR_ERR("get_cqm_deq_port_by_node failed\n");
+		return DP_FAILURE;
+	}
+
+	if (!priv->deq_port_stat[phy_id].child_num ||
+	    !(priv->deq_port_stat[phy_id].flag & PP_NODE_ACTIVE)) {
+		PR_ERR("Wrong P[%d] Stat(%d)/child_num(%d):%s\n",
+		       phy_id, priv->deq_port_stat[phy_id].flag,
+		       priv->deq_port_stat[phy_id].child_num,
+		       "Expect ACTIVE Or non-zero child_num");
+		return DP_FAILURE;
+	}
+	if (priv->qos_sch_stat[node_id].child[idx].flag) {
+		priv->qos_sch_stat[node_id].child[idx].node_id = 0;
+		priv->qos_sch_stat[node_id].child[idx].type = 0;
+		priv->qos_sch_stat[node_id].child[idx].flag = 0;
+	}
+	priv->deq_port_stat[phy_id].child_num--;
+	if (!priv->deq_port_stat[phy_id].child_num)
+		priv->deq_port_stat[phy_id].flag = PP_NODE_ALLOC;
+	return DP_SUCCESS;
+}
+
+/* node_port_inc API
+ * for port logical node_id, flag = DP_NODE_INC
+ * Set Port flag from PP_NODE_ALLOC to PP_NODE_ACTIVE
+ * else return DP_FAILURE
+ */
+static int node_port_inc(int inst, int node_id, int flag)
+{
+	struct hal_priv *priv = HAL(inst);
+	int phy_id = get_cqm_deq_port_by_node(inst, node_id, flag);
+	int child_type = get_node_type_by_node_id(inst, node_id, 0);
+	int idx = get_free_child_idx(inst, node_id, 0);
+
+	if (phy_id == DP_FAILURE) {
+		PR_ERR("get_cqm_deq_port_by_node failed\n");
+		return DP_FAILURE;
+	}
+
+	if (idx == DP_FAILURE) {
+		PR_ERR("get_free_child_idx failed\n");
+		return DP_FAILURE;
+	}
+
+	if (priv->deq_port_stat[phy_id].child_num &&
+	    !(priv->deq_port_stat[phy_id].flag & PP_NODE_ACTIVE)) {
+		PR_ERR("Wrong P[%d] Stat(%d)/child_num(%d):%s\n", phy_id,
+		       priv->deq_port_stat[phy_id].flag,
+		       priv->deq_port_stat[phy_id].child_num,
+		       "Expect ACTIVE And Non-Zero child_num");
+		return DP_FAILURE;
+	}
+	if (!priv->deq_port_stat[phy_id].child_num &&
+	    !(priv->deq_port_stat[phy_id].flag & PP_NODE_ALLOC)) {
+		PR_ERR("Wrong P[%d] Stat(%d)/child_num(%d):%s\n", phy_id,
+		       priv->deq_port_stat[phy_id].flag,
+		       priv->deq_port_stat[phy_id].child_num,
+		       "Expect ALLOC And Zero child_num");
+		return DP_FAILURE;
+	}
+	priv->qos_sch_stat[node_id].child[idx].type = child_type;
+	priv->qos_sch_stat[node_id].child[idx].node_id = node_id;
+	priv->qos_sch_stat[node_id].child[idx].flag = PP_NODE_ACTIVE;
+	priv->qos_sch_stat[node_id].child_num++;
+	priv->deq_port_stat[phy_id].child_num++;
+	priv->deq_port_stat[phy_id].flag = PP_NODE_ACTIVE;
+	return DP_SUCCESS;
+}
+
+/* node_port_rst API
+ * Check for child_num and alloc flag
+ * for port logical node_id, flag = DP_NODE_RST
+ * Set Port flag from PP_NODE_ALLOC to PP_NODE_FREE
+ * else return DP_FAILURE
+ */
+static int node_port_rst(int inst, int node_id, int flag)
+{
+	struct hal_priv *priv = HAL(inst);
+	int phy_id = get_cqm_deq_port_by_node(inst, node_id, flag);
+
+	if (phy_id == DP_FAILURE) {
+		PR_ERR("get_cqm_deq_port_by_node failed\n");
+		return DP_FAILURE;
+	}
+
+	if (priv->deq_port_stat[phy_id].child_num ||
+	    !(priv->deq_port_stat[phy_id].flag & PP_NODE_ALLOC)) {
+		PR_ERR("Wrong P[%d] Stat(%d)/child_num(%d):%s\n", phy_id,
+		       priv->deq_port_stat[phy_id].flag,
+		       priv->deq_port_stat[phy_id].child_num,
+		       "Expect ALLOC Or non-zero child_num");
+		return DP_FAILURE;
+	}
+	memset(&priv->deq_port_stat[phy_id], 0,
+	       sizeof(priv->deq_port_stat[phy_id]));
+	memset(&priv->qos_sch_stat[node_id], 0,
+	       sizeof(priv->qos_sch_stat[node_id]));
+	return DP_SUCCESS;
+}
+
+/* node_stat_update API
+ * node_id is logical node id
+ * if flag = DP_NODE_DEC
+ *           update flag PP_NODE_ACTIVE to PP_NODE_ALLOC if needed
+ *           update child info
+ * else if flag = DP_NODE_INC
+ *           update flag PP_NODE_ALLOC to PP_NODE_ACTIVE
+ * else if flag = DP_NODE_RST
+ *           update flag PP_NODE_ALLOC to PP_NODE_FREE
+ *           reset table info
+ * else return DP_FAILURE
+ */
+static int node_stat_update(int inst, int node_id, int flag)
+{
+	int node_type = get_node_type_by_node_id(inst, node_id, 0);
+
+	if (flag & DP_NODE_DEC) {
+		if (node_type == DP_NODE_QUEUE)
+			return node_queue_dec(inst, node_id, flag);
+		else if (node_type == DP_NODE_SCH)
+			return node_sched_dec(inst, node_id, flag);
+		else if (node_type == DP_NODE_PORT)
+			return node_port_dec(inst, node_id, flag);
+		return DP_FAILURE;
+	} else if (flag & DP_NODE_INC) {
+		if (node_type == DP_NODE_QUEUE)
+			return node_queue_inc(inst, node_id, flag);
+		else if (node_type == DP_NODE_SCH) {
+			return node_sched_inc(inst, node_id, flag);
+		} else if (node_type == DP_NODE_PORT)
+			return node_port_inc(inst, node_id, flag);
+		return DP_FAILURE;
+	} else if (flag & DP_NODE_RST) {
+		if (node_type == DP_NODE_QUEUE)
+			return node_queue_rst(inst, node_id, flag);
+		else if (node_type == DP_NODE_SCH)
+			return node_sched_rst(inst, node_id, flag);
+		else if (node_type == DP_NODE_PORT)
+			return node_port_rst(inst, node_id, flag);
+		return DP_FAILURE;
+	}
+	return DP_FAILURE;
+}
+
+/* dp_link_unset API
+ * call node_stat_update with DP_NODE_DEC flag
+ * upon success unlinks node to parent and returns DP_SUCCESS
+ * else return DP_FAILURE
+ */
+static int dp_link_unset(struct dp_node_link *info, int flag)
+{
+	int node_id, p_id;
+	struct pp_qos_queue_conf queue_cfg;
+	struct pp_qos_sched_conf sched_cfg;
+	struct hal_priv *priv = HAL(info->inst);
+
+	if (info->node_type == DP_NODE_QUEUE) {
+		node_id = priv->qos_queue_stat[info->node_id.q_id].node_id;
+		if (qos_queue_conf_get(priv->qdev, node_id, &queue_cfg)) {
+			PR_ERR("failed to qos_queue_conf_get\n");
+			return DP_FAILURE;
+		}
+		if (queue_cfg.queue_child_prop.parent ==
+						*(int *)&info->p_node_id) {
+			if (qos_queue_remove(priv->qdev, node_id)) {
+				PR_ERR("failed to qos_queue_remove\n");
+				return DP_FAILURE;
+			}
+		}
+		goto EXIT;
+	} else if (info->node_type == DP_NODE_SCH) {
+		if (qos_sched_conf_get(priv->qdev, info->node_id.sch_id,
+					  &sched_cfg)) {
+			PR_ERR("failed to qos_queue_conf_get\n");
+			return DP_FAILURE;
+		}
+		if (sched_cfg.sched_child_prop.parent ==
+						*(int *)&info->p_node_id) {
+			if (qos_sched_remove(priv->qdev,
+						info->node_id.sch_id)) {
+				PR_ERR("failed to qos_sched_remove\n");
+				return DP_FAILURE;
+			}
+		}
+		goto EXIT;
+	}
+	return DP_FAILURE;
+
+EXIT:
+	/*Child flag update after unlink*/
+	node_stat_update(info->inst, *(int *)&info->node_id,
+			 DP_NODE_DEC | P_FLAG);
+	/*reduce child_num in parent's global table*/
+	if (info->p_node_type == DP_NODE_SCH)
+		node_stat_update(info->inst, PARENT(queue_cfg),
+				 DP_NODE_DEC | C_FLAG);
+	else /*convert parent to cqm_deq_port*/
+		p_id = get_cqm_deq_port_by_node(info->inst,
+						*(int *)&info->p_node_id,
+						flag);
+		node_stat_update(info->inst, p_id, DP_NODE_DEC);
+	return DP_SUCCESS;
+}
+
+/* dp_node_alloc_resv_pool API
+ * Checks for flag and input node
+ * upon success allocate resource from reserve table
+ * otherwise return failure
+ */
+static int dp_node_alloc_resv_pool(struct dp_node_alloc *node, int flag)
+{
+	int i, cnt, phy_id, node_id;
+	struct hal_priv *priv = node ? HAL(node->inst) : NULL;
+	struct resv_q *resv_q = priv->resv[node->dp_port].resv_q;
+
+	if (!node) {
+		PR_ERR("priv NULL\n");
+		return -1;
+	}
+	if (!priv) {
+		PR_ERR("priv NULL\n");
+		return -1;
+	}
+	PR_INFO("inst=%d dp_port=%d num_resv_q=%d num_resv_sched=%d\n",
+		node->inst,
+		node->dp_port,
+		priv->resv[node->dp_port].num_resv_q,
+		priv->resv[node->dp_port].num_resv_sched);
+	if (node->type == DP_NODE_QUEUE) {
+		cnt = priv->resv[node->dp_port].num_resv_q;
+		if (!cnt)
+			return DP_FAILURE;
+		PR_INFO("try to look for resv sche...\n");
+		for (i = 0; i < cnt; i++) {
+			if (resv_q[i].flag != PP_NODE_FREE)
+				continue;
+			phy_id = resv_q[i].physical_id;
+			node_id = resv_q[i].id;
+			resv_q[i].flag = PP_NODE_ALLOC;
+			priv->qos_queue_stat[phy_id].flag = PP_NODE_RESERVE |
+								PP_NODE_ALLOC;
+			priv->qos_queue_stat[phy_id].node_id = node_id;
+			priv->qos_queue_stat[phy_id].resv_idx = i;
+			priv->qos_sch_stat[node_id].type = DP_NODE_QUEUE;
+			node->id = (union dp_node_id)phy_id;
+			return DP_SUCCESS;
+		}
+	} else if (node->type == DP_NODE_SCH) {
+		struct resv_sch *resv_sched;
+		cnt = priv->resv[node->dp_port].num_resv_sched;
+		if (!cnt)
+			return DP_FAILURE;
+		resv_sched = priv->resv[node->dp_port].resv_sched;
+		for (i = 0; i < cnt; i++) {
+			if (resv_sched[i].flag != PP_NODE_FREE)
+				continue;
+			PR_INFO("try to look for resv sche...\n");
+			node_id = resv_sched[i].id;
+			resv_sched[i].flag = PP_NODE_ALLOC;
+			priv->qos_sch_stat[node_id].c_flag = PP_NODE_RESERVE |
+								PP_NODE_ALLOC;
+			priv->qos_sch_stat[node_id].p_flag = PP_NODE_RESERVE |
+								PP_NODE_ALLOC;
+			priv->qos_sch_stat[node_id].resv_idx = i;
+			priv->qos_sch_stat[node_id].child_num = 0;
+			priv->qos_sch_stat[node_id].type = DP_NODE_SCH;
+			node->id = (union dp_node_id)node_id;
+			return DP_SUCCESS;
+		}
+	}
+	return DP_FAILURE;
+}
+
+/* dp_node_alloc_global_pool API
+ * Checks for flag and input node
+ * upon success allocate resource from global table
+ * otherwise return failure
+ */
+static int dp_node_alloc_global_pool(struct dp_node_alloc *node, int flag)
+{
+	int id, phy_id;
+	struct pp_qos_queue_info *qos_queue_info;
+	struct pp_qos_queue_conf *q_conf;
+	struct hal_priv *priv = HAL(node->inst);
+
+	qos_queue_info = kzalloc(sizeof(*qos_queue_info), GFP_KERNEL);
+	q_conf = kzalloc(sizeof(*q_conf), GFP_KERNEL);
+	if (!qos_queue_info || !q_conf)
+		goto EXIT;
+	if (node->type == DP_NODE_QUEUE) {
+		if (qos_queue_allocate(priv->qdev, &id)) {
+			PR_ERR("qos_queue_allocate failed\n");
+			goto EXIT;
+		}
+		PR_INFO("qos_queue_allocate: %d\n", id);
+#define WORKAROUND_PORT_SET
+//#define WORKAROUND_DROP_PORT
+#ifdef WORKAROUND_PORT_SET /*workaround to get physcal queue id */
+		/*workarpound: in order to get queue's physical queue id,
+		 *it is a must call pp_qos_queue_set first,
+		 *then call qos_queue_info_get to get physical queue id
+		 */
+		qos_queue_conf_set_default(q_conf);
+		q_conf->wred_enable = 0;
+		q_conf->queue_wred_max_allowed = 0x400; /*max qocc in pkt */
+#ifdef WORKAROUND_DROP_PORT /*use drop port */
+		q_conf->queue_child_prop.parent = priv->ppv4_drop_p;
+#else
+		q_conf->queue_child_prop.parent = priv->ppv4_tmp_p;
+#endif /*WORKAROUND_DROP_PORT*/
+		if (qos_queue_set(priv->qdev, id, q_conf)) {
+			PR_ERR("qos_queue_set fail for queue=%d to parent=%d\n",
+			       id, q_conf->queue_child_prop.parent);
+			return -1;
+		}
+		PR_INFO("Workaround queue(/%d)-> tmp parent(/%d)\n",
+		        id, q_conf->queue_child_prop.parent);
+		/*workarpound end ---- */
+#endif /*WORKAROUND_PORT_SET */
+		if (qos_queue_info_get(priv->qdev, id, qos_queue_info)) {
+			qos_queue_remove(priv->qdev, id);
+			PR_ERR("qos_queue_info_get: %d\n", id);
+			goto EXIT;
+		}
+
+		phy_id = qos_queue_info->physical_id;
+		PR_INFO("queue info: %d/%d to parent(/%d)\n", phy_id, id,
+			q_conf->queue_child_prop.parent);
+		priv->qos_queue_stat[phy_id].flag = PP_NODE_ALLOC;
+		priv->qos_queue_stat[phy_id].node_id = id;
+		priv->qos_queue_stat[phy_id].resv_idx = -1;
+		priv->qos_sch_stat[id].type = DP_NODE_QUEUE;
+		node->id = (union dp_node_id)phy_id;
+		return DP_SUCCESS;
+	} else if (node->type == DP_NODE_SCH) {
+		if (qos_sched_allocate(priv->qdev, &id)) {
+			PR_ERR("failed to qos_sched_allocate\n");
+			qos_sched_remove(priv->qdev, id);
+			goto EXIT;
+		}
+		priv->qos_sch_stat[id].c_flag = PP_NODE_ALLOC;
+		priv->qos_sch_stat[id].p_flag = PP_NODE_ALLOC;
+		priv->qos_sch_stat[id].resv_idx = -1;
+		priv->qos_sch_stat[id].child_num = 0;
+		priv->qos_sch_stat[id].type = DP_NODE_SCH;
+		node->id = (union dp_node_id)id;
+		return DP_SUCCESS;
+	}
+
+EXIT:
+	if (!q_conf)
+		kfree(q_conf);
+	if (!qos_queue_info)
+		kfree(qos_queue_info);
+	return DP_FAILURE;
+}
+
+/* dp_alloc_qos_port API
+ * upon success returns qos_deq_port
+ * otherwise return failure
+ */
+static int dp_alloc_qos_port(struct dp_node_alloc *node, int flag)
+{
+	unsigned int qos_port;
+	int cqm_deq_port;
+	struct pp_qos_port_conf  port_cfg;
+	struct hal_priv *priv = HAL(node->inst);
+
+	if (!priv) {
+		PR_ERR("priv NULL\n");
+		goto EXIT;
+	}
+	cqm_deq_port = node->id.cqm_deq_port;
+	DP_DEBUG(DP_DBG_FLAG_QOS_DETAIL,
+		 "inst=%d dp_port=%d cqm_deq_port=%d\n",
+		 node->inst, node->dp_port, cqm_deq_port);
+	if (cqm_deq_port == DP_NODE_AUTO_ID) {
+		PR_ERR("cqm_deq_port wrong: %d\n", cqm_deq_port);
+		goto EXIT;
+	}
+	if (priv->deq_port_stat[cqm_deq_port].flag != PP_NODE_FREE) {
+		PR_INFO("cqm_deq_port[%d] alread init:\n", cqm_deq_port);
+		return priv->deq_port_stat[cqm_deq_port].node_id;
+	}
+	if (qos_port_allocate(priv->qdev, cqm_deq_port, &qos_port)) {
+		PR_ERR("failed to qos_port_allocate\n");
+		goto EXIT;
+	}
+	PR_INFO("qos_port_alloc succeed: %d/%d\n", cqm_deq_port, qos_port);
+	/*Configure QOS dequeue port*/
+	qos_port_conf_set_default(&port_cfg);
+	port_cfg.ring_address =
+		(void *)priv->deq_port_info[cqm_deq_port].tx_ring_addr;
+	port_cfg.ring_size = priv->deq_port_info[cqm_deq_port].tx_ring_size;
+	port_cfg.credit = priv->deq_port_info[cqm_deq_port].tx_pkt_credit;
+	if (port_cfg.credit)
+		port_cfg.packet_credit_enable = 1;
+
+	PR_INFO("qos_port_set parameter: %d/%d\n", cqm_deq_port, qos_port);
+	PR_INFO("  ring_address=0x%p\n", port_cfg.ring_address);
+	PR_INFO("  ring_size=%d\n", port_cfg.ring_size);
+	PR_INFO("  credit=%d\n", port_cfg.credit);
+	PR_INFO("  packet_credit_enable=%d\n", port_cfg.packet_credit_enable);
+	PR_INFO("priv->qdev=0x%p\n", priv->qdev);
+	
+	if (qos_port_set(priv->qdev, qos_port, &port_cfg)) {
+		PR_ERR("qos_port_set fail for port %d/%d\n",
+		       cqm_deq_port, qos_port);
+		qos_port_remove(priv->qdev, qos_port);
+		goto EXIT;
+	}
+	priv->deq_port_stat[cqm_deq_port].flag = PP_NODE_ALLOC;
+	priv->qos_sch_stat[qos_port].type = DP_NODE_PORT;
+	priv->deq_port_stat[cqm_deq_port].node_id = qos_port;
+	DP_DEBUG(DP_DBG_FLAG_QOS_DETAIL,
+		 "dp_alloc_qos_port ok: port=%d/%d for dp_port=%d\n",
+		 cqm_deq_port, qos_port, node->dp_port);
+	return qos_port;
+EXIT:
+	return DP_FAILURE;
+}
+
+/* dp_node_alloc_31 API
+ * Checks for flag and input node type
+ * upon success allocate node from global/reserve resource
+ * otherwise return failure
+ */
+int dp_node_alloc_31(struct dp_node_alloc *node, int flag)
+{
+	struct hal_priv *priv = HAL(node->inst);
+
+	if (!priv) {
+		PR_ERR("priv is NULL cannot proceed!!\n");
+		return DP_FAILURE;
+	}
+
+	if (flag && DP_ALLOC_RESV_ONLY) {
+	/*if can get from its reserved resource and return DP_SUCCESS.
+	 *	Otherwise return DP_FAIL;
+	 */
+		return dp_node_alloc_resv_pool(node, flag);
+	}
+	if (flag && DP_ALLOC_GLOBAL_ONLY) {
+	/* if can get from global pool and return DP_SUCCESS.
+	 *	Otherwise return DP_FAILURE;
+	 */
+		return dp_node_alloc_global_pool(node, flag);
+	}
+	if (flag && DP_ALLOC_GLOBAL_FIRST) {
+	/* if can get from the global pool, return DP_SUCCESS;
+	 * if can get from its reserved resource and return DP_SUCCESS;
+	 * return DP_FAILURE;
+	 */
+		if (dp_node_alloc_global_pool(node, flag) == DP_SUCCESS)
+			return DP_SUCCESS;
+		return dp_node_alloc_resv_pool(node, flag);
+	}
+	/*default order: reserved pool,*/
+	/* if can get from its reserved resource and return DP_SUCCESS
+	 * if can get from the global pool, return DP_SUCCESS
+	 * return DP_FAILURE
+	 */
+	if (dp_node_alloc_resv_pool(node, flag) == DP_SUCCESS)
+		return DP_SUCCESS;
+	return dp_node_alloc_global_pool(node, flag);
+}
+
+/* dp_node_free_31 API
+ * if (this node is not unlinked yet)
+ * unlink it
+ * If (this node is a  reserved node)
+ * return this node to this device’s reserved node table
+ * mark this node as Free in this device’s reserved node table
+ * else
+ * return this node to the system global table
+ * mark this node free in system global table
+ */
+int dp_node_free_31(struct dp_node_alloc *node, int flag)
+{
+	int sch_id, phy_id, node_id, parent_id, p_type;
+	struct hal_priv *priv = HAL(node->inst);
+	struct pp_qos_queue_conf queue_cfg;
+	struct pp_qos_sched_conf sched_cfg;
+
+	if (!priv) {
+		PR_ERR("priv is NULL cannot proceed!!\n");
+		return DP_FAILURE;
+	}
+
+	if (node->type == DP_NODE_QUEUE) {
+		node_id = priv->qos_queue_stat[node->id.q_id].node_id;
+
+		if (priv->qos_queue_stat[node->id.q_id].flag & PP_NODE_FREE) {
+			PR_ERR("Node Q[%d] is already Free Stat\n",
+			       node->id.q_id);
+			return DP_FAILURE;
+		}
+
+		if (qos_queue_conf_get(priv->qdev, node_id, &queue_cfg)) {
+			if (node_stat_update(node->inst, node_id, DP_NODE_RST))
+				PR_ERR("node_stat_update failed\n");
+			return DP_SUCCESS;
+		}
+		parent_id = queue_cfg.queue_child_prop.parent;
+		p_type = get_node_type_by_node_id(node->inst, parent_id, flag);
+		/*Remove Queue link*/
+		if (qos_queue_remove(priv->qdev, node_id)) {
+			PR_ERR("failed to qos_queue_remove\n");
+			return DP_FAILURE;
+		}
+		PR_INFO("Queue[%d/%d] removed\n", node->id.q_id, node_id);
+		if (node_stat_update(node->inst, node_id, DP_NODE_DEC)) {
+			PR_ERR("node_stat_update failed\n");
+			return DP_FAILURE;
+		}
+		/*call node_stat_update to update parent status*/
+		if (node_stat_update(node->inst, parent_id,
+				     DP_NODE_DEC | C_FLAG)) {
+			PR_ERR("node_stat_update failed\n");
+			return DP_FAILURE;
+		}
+		/*call node_Stat_update to free the node*/
+		if (node_stat_update(node->inst, node_id, DP_NODE_RST)) {
+			PR_ERR("node_stat_update failed\n");
+			return DP_FAILURE;
+		}
+		PR_INFO("Queue[%d/%d] removed updated\n",
+			 node->id.q_id, node_id);
+		return DP_SUCCESS;
+	} else if (node->type == DP_NODE_SCH) {
+		sch_id = node->id.sch_id;
+
+		if (priv->qos_sch_stat[sch_id].child_num)
+			return DP_FAILURE;
+
+		if (priv->qos_sch_stat[sch_id].p_flag & PP_NODE_FREE) {
+			PR_ERR("Node Sch[%d] is already Free Stat\n", sch_id);
+			return DP_FAILURE;
+		}
+
+		if (qos_sched_conf_get(priv->qdev, sch_id, &sched_cfg)) {
+			if (node_stat_update(node->inst, sch_id,
+					     DP_NODE_RST | P_FLAG))
+				PR_ERR("node_stat_update failed\n");
+			return DP_SUCCESS;
+		}
+		parent_id = sched_cfg.sched_child_prop.parent;
+		p_type = get_node_type_by_node_id(node->inst, parent_id, flag);
+		/*Remove Sched link*/
+		if (qos_sched_remove(priv->qdev, sch_id)) {
+			PR_ERR("failed to qos_sched_remove\n");
+			return DP_FAILURE;
+		}
+		if (node_stat_update(node->inst, sch_id,
+				     DP_NODE_DEC | P_FLAG)) {
+			PR_ERR("node_stat_update failed\n");
+			return DP_FAILURE;
+		}
+		/*call node_stat_update to update parent status*/
+		if (node_stat_update(node->inst, parent_id,
+				     DP_NODE_DEC | C_FLAG)) {
+			PR_ERR("node_stat_update failed\n");
+			return DP_FAILURE;
+		}
+		/*call node_stat_update to free the node*/
+		if (node_stat_update(node->inst, sch_id,
+				     DP_NODE_RST | P_FLAG)) {
+			PR_ERR("node_stat_update failed\n");
+			return DP_FAILURE;
+		}
+		return DP_SUCCESS;
+	} else if (node->type == DP_NODE_PORT) {
+		phy_id = node->id.cqm_deq_port;
+		node_id = priv->deq_port_stat[phy_id].node_id;
+
+		if (priv->deq_port_stat[phy_id].child_num)
+			return DP_FAILURE;
+		if (priv->deq_port_stat[phy_id].flag & PP_NODE_ACTIVE) {
+			if (node_stat_update(node->inst, node_id, DP_NODE_DEC))
+				PR_ERR("node_stat_update failed\n");
+		}
+		if (priv->deq_port_stat[phy_id].flag & PP_NODE_ALLOC) {
+			/*call node_stat_update to free the node*/
+			if (node_stat_update(node->inst, node_id, DP_NODE_RST))
+				PR_ERR("node_stat_update failed\n");
+			return DP_SUCCESS;
+		}
+		return DP_FAILURE;
+	}
+	return DP_FAILURE;
+}
+
+/* dp_qos_parent_chk API
+ * checks for parent type
+ * upon Success
+ *    return parent node id
+ * else return DP_FAILURE
+ */
+static int dp_qos_parent_chk(struct dp_node_link *info, int flag)
+{
+	struct dp_node_alloc node;
+
+	if (info->p_node_type == DP_NODE_SCH) {
+		if (info->p_node_id.sch_id == DP_NODE_AUTO_ID) {
+			node.inst = info->inst;
+			node.type = info->p_node_type;
+			node.dp_port = info->dp_port;
+
+			if ((dp_node_alloc_31(&node, flag)) == DP_FAILURE) {
+				PR_ERR("dp_node_alloc_31 queue alloc fail\n");
+				return DP_FAILURE;
+			}
+			info->p_node_id = node.id;
+		}
+		return info->p_node_id.sch_id;
+	} else if (info->p_node_type == DP_NODE_PORT) {
+		node.inst = info->inst;
+		node.id = info->cqm_deq_port;
+		node.type = info->p_node_type;
+		node.dp_port = info->dp_port;
+		return dp_alloc_qos_port(&node, flag);
+	}
+	return DP_FAILURE;
+}
+
+/* dp_node_link_get_31 API
+ * upon success check node link info and return DP_SUCCESS
+ * else return DP_FAILURE
+ */
+int dp_node_link_get_31(struct dp_node_link *info, int flag)
+{
+	struct pp_qos_queue_conf queue_cfg;
+	struct pp_qos_sched_conf sched_cfg;
+	struct hal_priv *priv = HAL(info->inst);
+	int node_id;
+
+	if (info->node_type == DP_NODE_QUEUE) {
+		node_id = priv->qos_queue_stat[info->node_id.q_id].node_id;
+		if (qos_queue_conf_get(priv->qdev, node_id, &queue_cfg)) {
+			PR_ERR("failed to qos_queue_conf_get\n");
+			return DP_FAILURE;
+		}
+		if (!queue_cfg.queue_child_prop.parent)
+			return DP_FAILURE;
+		if (priv->qos_queue_stat[info->node_id.q_id].flag !=
+		    PP_NODE_ACTIVE) {
+			return DP_FAILURE;
+		}
+		info->p_node_id.sch_id =
+			queue_cfg.queue_child_prop.parent;
+		info->p_node_type = get_node_type_by_node_id(info->inst,
+				queue_cfg.queue_child_prop.parent, flag);
+		info->prio_wfq = queue_cfg.queue_child_prop.priority;
+		info->arbi = 0;
+		info->leaf = 0;
+		return DP_SUCCESS;
+	} else if (info->node_type == DP_NODE_SCH) {
+		if (qos_sched_conf_get(priv->qdev, info->node_id.sch_id,
+				       &sched_cfg)) {
+			PR_ERR("failed to qos_sched_conf_get\n");
+			return DP_FAILURE;
+		}
+		if (!sched_cfg.sched_child_prop.parent)
+			return DP_FAILURE;
+		if (priv->qos_sch_stat[info->node_id.sch_id].c_flag !=
+		    PP_NODE_ACTIVE) {
+			return DP_FAILURE;
+		}
+		info->p_node_id.sch_id = sched_cfg.sched_child_prop.parent;
+		info->p_node_type = get_node_type_by_node_id(info->inst,
+				sched_cfg.sched_child_prop.parent, flag);
+		info->prio_wfq = sched_cfg.sched_child_prop.priority;
+		info->arbi = sched_cfg.sched_parent_prop.arbitration;
+		info->leaf = 0;
+		return DP_SUCCESS;
+	}
+	return DP_FAILURE;
+}
+
+/* dp_link_set API
+ * upon success links node to parent and returns DP_SUCCESS
+ * else return DP_FAILURE
+ */
+static int dp_link_set(struct dp_node_link *info, int parent_node, int flag)
+{
+	int node_id;
+	int res = DP_FAILURE;
+	int node_flag = DP_NODE_INC;
+	struct hal_priv *priv = HAL(info->inst);
+	struct pp_qos_queue_conf *queue_cfg;
+	struct pp_qos_sched_conf *sched_cfg;
+
+	queue_cfg = kzalloc(sizeof(*queue_cfg), GFP_KERNEL);
+	sched_cfg = kzalloc(sizeof(*sched_cfg), GFP_KERNEL);
+	if (!sched_cfg || !sched_cfg)
+		goto EXIT;
+	
+	if (info->node_type == DP_NODE_QUEUE) {
+		qos_queue_conf_set_default(queue_cfg);
+		queue_cfg->queue_child_prop.parent = parent_node;
+		queue_cfg->wred_enable = 0;
+		queue_cfg->queue_wred_max_allowed = 0x400;
+		queue_cfg->queue_child_prop.priority = info->prio_wfq;
+		/* convert q_id to logical node id and pass it to
+		 * low level api
+		 */
+		node_id = priv->qos_queue_stat[info->node_id.q_id].node_id;
+		PR_INFO("Try to link Q[%d/%d] to parent %d/%d]\n",
+			info->node_id.q_id,
+			node_id,
+			info->cqm_deq_port.cqm_deq_port,
+			queue_cfg->queue_child_prop.parent);
+		if (qos_queue_set(priv->qdev, node_id, queue_cfg)) {
+			PR_ERR("failed to qos_queue_set\n");
+			qos_queue_remove(priv->qdev, node_id);
+			goto ERROR_EXIT;
+		}
+		goto EXIT;
+	} else if (info->node_type == DP_NODE_SCH) {
+		qos_sched_conf_set_default(sched_cfg);
+		sched_cfg->sched_child_prop.parent = parent_node;
+		sched_cfg->sched_child_prop.priority = info->prio_wfq;
+		sched_cfg->sched_parent_prop.arbitration = info->arbi;
+		node_id = info->node_id.sch_id;
+
+		if (qos_sched_set(priv->qdev, node_id, sched_cfg)) {
+			PR_ERR("failed to qos_sched_set\n");
+			qos_sched_remove(priv->qdev, node_id);
+			goto ERROR_EXIT;
+		}
+		node_flag |= P_FLAG;
+		goto EXIT;
+	}
+	goto ERROR_EXIT;
+EXIT:
+	res = DP_SUCCESS;
+	/*fill parent info in child's global table*/
+	priv->qos_sch_stat[node_id].parent.node_id = parent_node;
+	priv->qos_sch_stat[node_id].parent.type = info->p_node_type;
+	priv->qos_sch_stat[node_id].parent.flag = PP_NODE_ACTIVE;
+	/*increase child_num in parent's global table and status*/
+	PR_INFO("node_stat_update after dp_link_set start\n");
+	node_stat_update(info->inst, node_id, node_flag);
+	node_stat_update(info->inst, parent_node, DP_NODE_INC | C_FLAG);
+	PR_INFO("node_stat_update after dp_link_set end\n");
+ERROR_EXIT:
+	if (queue_cfg)
+		kfree(queue_cfg);
+	if (sched_cfg)
+		kfree(sched_cfg);
+	return res;
+}
+
+/* dp_qos_link_prio_set_31 API
+ * set node_prio struct for link and return DP_SUCCESS
+ * else return DP_FAILURE
+ */
+int dp_qos_link_prio_set_31(struct dp_node_prio *info, int flag)
+{
+	struct pp_qos_queue_conf queue_cfg;
+	struct pp_qos_sched_conf sched_cfg;
+	struct pp_qos_port_conf port_cfg;
+	struct hal_priv *priv = HAL(info->inst);
+	int node_id;
+
+	if (!info) {
+		PR_ERR("info cannot be NULL\n");
+		return DP_FAILURE;
+	}
+
+	if (info->type == DP_NODE_QUEUE) {
+		node_id = priv->qos_queue_stat[info->id.q_id].node_id;
+		if (qos_queue_conf_get(priv->qdev, node_id, &queue_cfg)) {
+			PR_ERR("failed to qos_queue_conf_get\n");
+			return DP_FAILURE;
+		}
+		queue_cfg.queue_child_prop.priority = info->prio_wfq;
+		if (qos_queue_set(priv->qdev, node_id, &queue_cfg)) {
+			PR_ERR("failed to qos_queue_set\n");
+			return DP_FAILURE;
+		}
+		return DP_SUCCESS;
+	} else if (info->type == DP_NODE_SCH) {
+		if (qos_sched_conf_get(priv->qdev, info->id.sch_id,
+					  &sched_cfg)) {
+			PR_ERR("failed to qos_sched_conf_get\n");
+			return DP_FAILURE;
+		}
+		sched_cfg.sched_parent_prop.arbitration = info->arbi;
+		sched_cfg.sched_child_prop.priority = info->prio_wfq;
+		if (qos_sched_set(priv->qdev, node_id, &sched_cfg)) {
+			PR_ERR("failed to qos_sched_set\n");
+			return DP_FAILURE;
+		}
+		return DP_SUCCESS;
+	} else if (info->type == DP_NODE_PORT) {
+		node_id = priv->deq_port_stat[info->id.cqm_deq_port].node_id;
+		if (qos_port_conf_get(priv->qdev, node_id, &port_cfg)) {
+			PR_ERR("failed to qos_port_conf_get\n");
+			return DP_FAILURE;
+		}
+		port_cfg.port_parent_prop.arbitration = info->arbi;
+		if (qos_port_set(priv->qdev, node_id, &port_cfg)) {
+			PR_ERR("failed to qos_port_set\n");
+			return DP_FAILURE;
+		}
+		return DP_SUCCESS;
+	}
+	return DP_FAILURE;
+}
+
+/* dp_qos_link_prio_get_31 API
+ * get node_prio struct for link and return DP_SUCCESS
+ * else return DP_FAILURE
+ */
+int dp_qos_link_prio_get_31(struct dp_node_prio *info, int flag)
+{
+	struct pp_qos_queue_conf queue_cfg;
+	struct pp_qos_sched_conf sched_cfg;
+	struct pp_qos_port_conf port_cfg;
+	struct hal_priv *priv = HAL(info->inst);
+	int node_id;
+
+	if (!info) {
+		PR_ERR("info cannot be NULL\n");
+		return DP_FAILURE;
+	}
+
+	if (info->type == DP_NODE_QUEUE) {
+		node_id = priv->qos_queue_stat[info->id.q_id].node_id;
+		if (qos_queue_conf_get(priv->qdev, node_id, &queue_cfg)) {
+			PR_ERR("failed to qos_queue_conf_get\n");
+			return DP_FAILURE;
+		}
+		info->arbi = 0;
+		info->prio_wfq = queue_cfg.queue_child_prop.priority;
+		return DP_SUCCESS;
+	} else if (info->type == DP_NODE_SCH) {
+		if (qos_sched_conf_get(priv->qdev, info->id.sch_id,
+					  &sched_cfg)) {
+			PR_ERR("failed to qos_sched_conf_get\n");
+			return DP_FAILURE;
+		}
+		info->arbi = sched_cfg.sched_parent_prop.arbitration;
+		info->prio_wfq = sched_cfg.sched_child_prop.priority;
+		return DP_SUCCESS;
+	} else if (info->type == DP_NODE_PORT) {
+		node_id = priv->deq_port_stat[info->id.cqm_deq_port].node_id;
+		if (qos_port_conf_get(priv->qdev, node_id, &port_cfg)) {
+			PR_ERR("failed to qos_port_conf_get\n");
+			return DP_FAILURE;
+		}
+		info->arbi = port_cfg.port_parent_prop.arbitration;
+		info->prio_wfq = 0;
+		return DP_SUCCESS;
+	}
+	return DP_FAILURE;
+}
+
+/* dp_deq_port_res_get_31 API
+ * Remove link of attached nodes and return DP_SUCCESS
+ * else return DP_FAILURE
+ */
+int dp_deq_port_res_get_31(struct dp_dequeue_res *res, int flag)
+{
+	union local_t {
+		struct pp_qos_port_info p_info;
+		struct pp_qos_queue_info q_info;
+		struct pp_qos_queue_conf q_conf;
+		struct pp_qos_sched_conf sched_conf;
+	};
+	
+	struct hal_priv *priv = HAL(res->inst);
+	static union local_t t;
+	uint16_t q_ids[MAX_Q_PER_PORT] = {0};
+	unsigned int q_num;
+	unsigned int q_size = MAX_Q_PER_PORT;
+	int i, j, k;
+	int port_num = 1;
+	int p_id,idx;
+	struct pmac_port_info *port_info;
+
+	if (!res) {
+		PR_ERR("res cannot be NULL\n");
+		return DP_FAILURE;
+	}
+	port_info = &dp_port_info[res->inst][res->dp_port];
+	if (!port_info->deq_port_num)
+		return DP_FAILURE;
+	if (res->cqm_deq_idx == DEQ_PORT_OFFSET_ALL) {
+		port_num = port_info->deq_port_num;
+		res->cqm_deq_port = port_info->deq_port_base;
+		res->num_deq_ports = port_info->deq_port_num;
+	} else {
+		res->cqm_deq_port = port_info->deq_port_base + res->cqm_deq_idx;
+		res->num_deq_ports = 1;
+	}
+	DP_DEBUG(DP_DBG_FLAG_QOS_DETAIL,
+		 "dp_deq_port_res_get_31:dp_port=%d cqm_deq_port=(%d ~%d) %d\n",
+		 res->dp_port,
+		 res->cqm_deq_port, res->cqm_deq_port + port_num - 1,
+		 port_info->deq_port_num);
+	res->num_q = 0;
+	idx = 0;
+	for (k = res->cqm_deq_port;
+	     k < (res->cqm_deq_port + port_num);
+	     k++) {
+		if (priv->deq_port_stat[k].flag == PP_NODE_FREE)
+			continue;
+		q_num = 0;
+		if (qos_port_get_queues(priv->qdev,
+		    priv->deq_port_stat[k].node_id,
+		    q_ids, q_size, &q_num)) {
+			PR_ERR("qos_port_get_queues: port[%d/%d]\n",
+			       k,
+			       priv->deq_port_stat[k].node_id);
+			return DP_FAILURE;
+		}
+		res->num_q += q_num;
+		if (!res->q_res)
+			continue;
+		DP_DEBUG(DP_DBG_FLAG_QOS_DETAIL, "port[%d/%d] queue list\n",
+			 k, priv->deq_port_stat[k].node_id);
+		for (i = 0; i < q_num; i++)
+			DP_DEBUG(DP_DBG_FLAG_QOS_DETAIL,
+				 "  q[/%d]\n", q_ids[i]);
+		for (i = 0; (i < q_num) && (idx < res->q_res_size); i++) {
+			memset(&t.q_info, 0, sizeof(t.q_info));
+			if (qos_queue_info_get(priv->qdev,
+			    q_ids[i], &t.q_info)) {
+				PR_ERR("qos_port_info_get fail:q[/%d]\n",
+				       q_ids[i]);
+				continue;
+			}
+			res->q_res[idx].q_id = t.q_info.physical_id;
+			res->q_res[idx].q_node = q_ids[i];
+			DP_DEBUG(DP_DBG_FLAG_QOS_DETAIL, "q[%d/%d]\n",
+				 t.q_info.physical_id, q_ids[i]);
+			res->q_res[idx].sch_lvl = 0;
+			memset(&t.q_conf, 0, sizeof(t.q_conf));
+			if (qos_queue_conf_get(priv->qdev,
+			    q_ids[i], &t.q_conf)) {
+			    PR_ERR("qos_port_conf_get fail:q[/%d]\n",
+				       q_ids[i]);
+			    continue;
+			}
+			p_id = t.q_conf.queue_child_prop.parent;
+			j = 0;
+			do {
+#if 0  /*currently no scheduler yet. So parent should be port */
+				if (priv->qos_sch_stat[p_id].type !=
+				    DP_NODE_PORT) {
+					PR_ERR("why parent=%d not port type\n",
+					       p_id);
+					/*workaround */
+					priv->qos_sch_stat[p_id].type =
+						DP_NODE_PORT;
+				}
+#endif
+				if (priv->qos_sch_stat[p_id].type ==
+				    DP_NODE_SCH) {
+				 	res->q_res[idx].sch_id[j] = p_id;
+					j++;
+					res->q_res[idx].sch_lvl = j;
+				} else if (priv->qos_sch_stat[p_id].type ==
+					   DP_NODE_PORT){ /*port */
+					res->q_res[idx].qos_deq_port = p_id;
+					res->q_res[idx].cqm_deq_port = k;
+					break;
+				} else {
+					PR_ERR("wrong p[/%d] type:%d\n",
+					       p_id,
+					       priv->qos_sch_stat[p_id].type);
+					break;
+				}
+				/*get next parent */
+				if (qos_sched_conf_get(priv->qdev,
+				    p_id, &t.sched_conf)) {
+				    PR_ERR("qos_sched_conf_get fail:sch[/%d]\n",
+					   p_id);
+					break;
+				}
+				p_id = t.sched_conf.sched_child_prop.parent;
+				idx ++;
+			} while (1);
+		}
+		return DP_SUCCESS;
+	}
+	return DP_FAILURE;
+}
+
+/* dp_node_unlink_31 API
+ * check child node keep queue in blocked state
+ * flush queues and return DP_SUCCESS
+ * Else return DP_FAILURE
+ */
+int dp_node_unlink_31(struct dp_node_link *info, int flag)
+{
+	struct pp_qos_queue_conf queue_cfg;
+	struct pp_qos_sched_conf sched_cfg;
+	struct hal_priv *priv = HAL(info->inst);
+	u16 queue_buf[MAX_Q_PER_PORT] = {0};
+	int queue_size = MAX_Q_PER_PORT;
+	int queue_num = 0;
+	int i, node_id;
+
+	if (info->node_type == DP_NODE_QUEUE) {
+		node_id = priv->qos_queue_stat[info->node_id.q_id].node_id;
+		/*Need to check ACTIVE Flag*/
+		if (priv->qos_queue_stat[node_id].flag != PP_NODE_ACTIVE)
+			PR_ERR("Wrong Queue[%d] Stat(%d):Expect ACTIVE\n",
+			       node_id, priv->qos_queue_stat[node_id].flag);
+		if (qos_queue_conf_get(priv->qdev, node_id, &queue_cfg) == 0) {
+			if (queue_cfg.blocked == 0) {
+				queue_cfg.blocked = 1;/*temp disable*/
+				if (qos_queue_set(priv->qdev, node_id,
+						     &queue_cfg)) {
+					PR_ERR("qos_queue_set fail\n");
+					return DP_FAILURE;
+				}
+			}
+			/* Remap lookup table*/
+			if (qos_queue_flush(priv->qdev, node_id)) {
+				PR_ERR("qos_queue_flush fail\n");
+				return DP_FAILURE;
+			}
+		}
+	} else if (info->node_type == DP_NODE_SCH) {
+		if (priv->qos_sch_stat[info->node_id.sch_id].c_flag !=
+								PP_NODE_ACTIVE)
+			PR_ERR("Wrong Sched FLAG Expect ACTIVE\n");
+		if (qos_sched_conf_get(priv->qdev, info->node_id.sch_id,
+					  &sched_cfg))
+			return DP_FAILURE;
+		if (qos_sched_get_queues(priv->qdev, info->node_id.sch_id,
+					    queue_buf, queue_size, &queue_num))
+			return DP_FAILURE;
+		if (!queue_num)
+			PR_ERR("DP_NODE_SCH has no queues\n");
+		if (flag != DP_NODE_SMART_UNLINK) {
+			/*unlink current parent and child */
+			if (qos_queue_conf_get(priv->qdev, queue_buf[queue_num],
+						  &queue_cfg))
+				return DP_FAILURE;
+			queue_cfg.blocked = 1;/*temp disable*/
+			if (qos_queue_set(priv->qdev, queue_buf[queue_num],
+					     &queue_cfg)) {
+				PR_ERR("qos_queue_set fail\n");
+				return DP_FAILURE;
+			}
+			/* Remap lookup table*/
+			if (qos_queue_flush(priv->qdev, queue_buf[queue_num])) {
+				PR_ERR("qos_queue_flush fail\n");
+				return DP_FAILURE;
+			}
+		}
+		for (i = 0; i < queue_num; i++) {
+			if (qos_queue_conf_get(priv->qdev, queue_buf[i],
+						  &queue_cfg))
+				continue;
+			if (queue_cfg.blocked)
+				continue;
+			queue_cfg.blocked = 1;/*temp disable*/
+			if (qos_queue_set(priv->qdev, queue_buf[i],
+					     &queue_cfg)) {
+				PR_ERR("qos_queue_set fail\n");
+				continue;
+			}
+			/* Remap lookup table*/
+			if (qos_queue_flush(priv->qdev, queue_buf[i])) {
+				PR_ERR("qos_queue_flush fail\n");
+				continue;
+			}
+		}
+	}
+	return DP_SUCCESS;
+}
+
+/* dp_node_link_add_31 API
+ * check for parent type and allocate parent node
+ * then check for child type and allocate child node
+ * then call dp_link_set api to link child to parent
+ * upon success links node to given parent and return DP_SUCCESS
+ * else return DP_FAILURE
+ */
+int dp_node_link_add_31(struct dp_node_link *info, int flag)
 {
+	struct local_var {
+		struct pp_qos_queue_conf queue_cfg;
+		struct pp_qos_sched_conf sched_cfg;
+		struct dp_node_alloc node;
+		u16 queue_buf[MAX_Q_PER_PORT];
+		int q_orig_block[MAX_Q_PER_PORT];
+		int queue_size ;
+		int queue_num;
+		int node_id;
+		struct pp_node parent;
+		int f_child_free;
+		int f_parent_free;
+		int f_sch_auto_id;
+	};
 	int i;
-	int inst = node->inst;
-	int cnt;
-	struct hal_priv *priv = (struct hal_priv *)dp_port_prop[inst].priv_hal;
-	int phy_id;
-	int node_id;
-	int port = node->dp_port;
-	struct resv_q *resv_q = priv->resv[port].resv_q;
+	int res = DP_SUCCESS;
+	struct hal_priv *priv = HAL(info->inst);
+	struct local_var *t = NULL;
 
-	if (node->type == DP_NODE_QUEUE) {
-		cnt = priv->resv[node->dp_port].num_resv_q;
-		for (i = 0; i <= cnt; i++) {
-			if (resv_q[i].flag != PP_NODE_FREE)
-				continue;
-			phy_id = resv_q[i].physical_id;
-			node_id = resv_q[i].id;
-			resv_q[i].flag = PP_NODE_ALLOC;
-			priv->qos_queue_stat[phy_id].flag = PP_NODE_RESERVE |
-								PP_NODE_ALLOC;
-			priv->qos_queue_stat[phy_id].node_id = node_id;
-			priv->qos_queue_stat[phy_id].resv_idx = i;
-			node->id = (union dp_node_id)phy_id;
-			return DP_SUCCESS;
+	if (!info) {
+		PR_ERR("info NULL\n");
+		goto EXIT_ERR;
+	}
+	t = kzalloc(sizeof(*t), GFP_KERNEL);
+	if (!t) {
+		PR_ERR("fail to alloc %d bytes\n", sizeof(*t));
+		goto EXIT_ERR;
+	}
+	for (i = 0; i < ARRAY_SIZE(t->q_orig_block); i++)
+		t->q_orig_block[i] = -1;
+	t->queue_size = MAX_Q_PER_PORT;
+	
+	DP_DEBUG(DP_DBG_FLAG_QOS,
+		 "inst=%d dp_port=%d\n",
+		 info->inst, info->dp_port);
+	/*Get Parent node_id after sanity check*/
+	if (info->p_node_type == DP_NODE_SCH &&
+	    info->p_node_id.sch_id == DP_NODE_AUTO_ID)
+		t->f_sch_auto_id = 1;
+	i = dp_qos_parent_chk(info, flag);
+	if (i == DP_FAILURE) {
+		PR_ERR("dp_qos_parent_chk fail\n");
+		goto EXIT_ERR;
+	}
+	t->parent.node_id = i;
+	t->parent.type = info->p_node_type;
+	t->parent.flag = 1;
+	PR_INFO("dp_qos_parent_chk succeed: parent node %d\n",
+		t->parent.node_id);
+	/*workaround to pass parrent to queue allcoate api*/
+	priv->ppv4_tmp_p = t->parent.node_id;
+	if (t->f_sch_auto_id)
+		t->f_parent_free = 1;
+
+	/*Get Child node after sanity check*/
+	if (info->node_type == DP_NODE_QUEUE) {
+		if (info->node_id.q_id == DP_NODE_AUTO_ID) {
+			t->node.inst = info->inst;
+			t->node.dp_port = info->dp_port;
+			t->node.type = info->node_type;
+			if ((dp_node_alloc_31(&t->node, flag)) == DP_FAILURE) {
+				PR_ERR("dp_node_alloc_31 queue alloc fail\n");
+				goto EXIT_ERR;
+			}
+			info->node_id = t->node.id;
+			t->f_child_free = 1;
+		}
+		/*add check for free flag and error*/
+		if (priv->qos_queue_stat[info->node_id.q_id].flag ==
+		    PP_NODE_FREE) {
+			PR_ERR("Invalid Queue ID:%d\n", info->node_id.q_id);
+			goto EXIT_ERR;
+		}
+		/* convert q_id to logical node id and pass it to
+		 * low level api
+		 */
+		t->node_id = priv->qos_queue_stat[info->node_id.q_id].node_id;
+		if ((qos_queue_conf_get(priv->qdev, t->node_id,
+		    &t->queue_cfg) == 0) &&
+		    (t->queue_cfg.queue_child_prop.parent ==
+		     priv->ppv4_drop_p)){
+			if (t->queue_cfg.blocked == 0) {
+				t->queue_cfg.blocked = 1;/*temp disable*/
+				t->q_orig_block[0] = 0;/*flag for queue restore*/
+				t->queue_num = 1;/*queue to restore*/
+				t->queue_buf[0] = t->node_id;
+				if (qos_queue_set(priv->qdev, t->node_id,
+						  &t->queue_cfg)) {
+					PR_ERR("qos_queue_set fail\n");
+					goto EXIT_ERR;
+				}
+				PR_INFO("block queue[%d/%d]\n",
+					info->node_id.q_id, t->node_id);
+			}
+#if 0  /*tmp remove q flush */
+			DP_DEBUG(DP_DBG_FLAG_QOS,
+				 "qos_queue_flush queue[%d]\n", t->node_id);
+			if (qos_queue_flush(priv->qdev, t->node_id)) {
+				PR_ERR("qos_queue_flush fail\n");
+				goto EXIT_ERR;
+			}
+#endif
+			/*Child flag update before link*/
+			DP_DEBUG(DP_DBG_FLAG_QOS,
+				 "node_stat_update for queue[%d]\n",
+				 t->node_id);
+			if (node_stat_update(info->inst, t->node_id,
+					     DP_NODE_DEC)) {
+				PR_ERR("node_stat_update fail\n");
+				goto EXIT_ERR;
+			}
+			/*reduce child_num in parent's global table*/
+			DP_DEBUG(DP_DBG_FLAG_QOS,
+				 "node_stat_update parent %d for q[%d]\n",
+				 PARENT(t->queue_cfg), t->node_id);
+			if (node_stat_update(info->inst, PARENT(t->queue_cfg),
+					     DP_NODE_DEC | C_FLAG)) {
+				PR_ERR("node_stat_update fail\n");
+				goto EXIT_ERR;
+			}
 		}
+		/*link set*/
+		/*if parent is same, but need to fill in other parameters for
+		 *parents hence commenting below code
+		 */
+		/*if (info->p_node_id.sch_id == parent.node_id ||
+		 *    info->p_node_id.cqm_deq_port == parent.node_id)
+		 *	goto EXIT_ERR;
+		 */
+		if (dp_link_set(info, t->parent.node_id, flag)) {
+			PR_ERR("dp_link_set fail to link to parent\n");
+			goto EXIT_ERR;
+		}
+	} else if (info->node_type == DP_NODE_SCH) {
+		if (info->node_id.sch_id == DP_NODE_AUTO_ID) {
+			t->node.inst = info->inst;
+			t->node.dp_port = info->dp_port;
+			t->node.type = info->node_type;
+
+			if ((dp_node_alloc_31(&t->node, flag)) == DP_FAILURE) {
+				PR_ERR("dp_node_alloc_31 sched alloc fail\n");
+				goto EXIT_ERR;
+			}
+			info->node_id = t->node.id;
+			t->f_child_free = 1;
+		}
+		/*add check for free flag and error*/
+		if (priv->qos_sch_stat[info->node_id.sch_id].p_flag ==
+		    PP_NODE_FREE) {
+			PR_ERR("Invalid Sched ID:%d\n", info->node_id.sch_id);
+			goto EXIT_ERR;
+		}
+		if (qos_sched_conf_get(priv->qdev, info->node_id.sch_id,
+					  &t->sched_cfg) == 0) {
+			qos_sched_get_queues(priv->qdev, info->node_id.sch_id,
+						t->queue_buf, t->queue_size,
+						&t->queue_num);
+			for (i = 0; i < t->queue_num; i++) {
+				if (qos_queue_conf_get(priv->qdev,
+						       t->queue_buf[i],
+						       &t->queue_cfg))
+					continue;
+				if (t->queue_cfg.blocked)
+					continue;
+				t->queue_cfg.blocked = 1;/*temp disable*/
+				t->q_orig_block[i] = 0;/*flag for queue restore*/
+				if (qos_queue_set(priv->qdev, t->queue_buf[i],
+						  &t->queue_cfg)) {
+					PR_ERR("qos_queue_set fail\n");
+					goto EXIT_ERR;
+				}
+				if (qos_queue_flush(priv->qdev, t->queue_buf[i])) {
+					PR_ERR("qos_queue_flush fail\n");
+					goto EXIT_ERR;
+				}
+			}
+			/*update flag for sch node*/
+			if (node_stat_update(info->inst, info->node_id.sch_id,
+					     DP_NODE_DEC | P_FLAG)) {
+				PR_ERR("node_stat_update fail\n");
+				goto EXIT_ERR;
+			}
+			/*reduce child_num in parent's global table*/
+			if (node_stat_update(info->inst, PARENT_S(t->sched_cfg),
+					     DP_NODE_DEC | C_FLAG)) {
+				PR_ERR("node_stat_update fail\n");
+				goto EXIT_ERR;
+			}
+		}
+		/*if parent is same, but need to fill in other parameters for
+		 *parents hence commenting below code
+		 */
+		/*if (info->p_node_id.sch_id == parent.node_id ||
+		 *    info->p_node_id.cqm_deq_port == parent.node_id)
+		 *	goto EXIT_ERR;
+		 */
+		if (dp_link_set(info, t->parent.node_id, flag)) {
+			PR_ERR("dp_link_set failed to link to parent\n");
+			goto EXIT_ERR;
+		}
+	}
+
+EXIT:
+	for (i = 0; i <= t->queue_num; i++) {
+		if (t->q_orig_block[i] < 0)
+			continue;
+		if (qos_queue_conf_get(priv->qdev, t->queue_buf[i], &t->queue_cfg))
+			continue;
+		t->queue_cfg.blocked = t->q_orig_block[i];/*restore*/
+		qos_queue_set(priv->qdev, t->queue_buf[i], &t->queue_cfg);
+	}
+	if (t)
+		kfree(t);
+	return res;
+
+EXIT_ERR:
+	if (t->f_child_free) {
+		if (t->node.type == DP_NODE_QUEUE)
+			qos_queue_remove(priv->qdev, t->node_id);
+		else
+			qos_sched_remove(priv->qdev, t->node.id.sch_id);
+	}
+	if (t->f_parent_free) {
+		if (info->p_node_type == DP_NODE_PORT)/* condition will not
+						       * meet for port
+						       */
+			qos_port_remove(priv->qdev, t->parent.node_id);
+		else
+			qos_sched_remove(priv->qdev, t->parent.node_id);
+	}
+	if (t)
+		kfree(t);
+	res = DP_FAILURE;
+	goto EXIT;
+}
+
+/* dp_queue_conf_set_31 API
+ * Set Current Queue config and return DP_SUCCESS
+ * else return DP_FAILURE
+ */
+int dp_queue_conf_set_31(struct dp_queue_conf *cfg, int flag)
+{
+	struct pp_qos_queue_conf *conf;
+	struct hal_priv *priv = HAL(cfg->inst);
+	int node_id;
+
+	if ((cfg->q_id < 0 || cfg->q_id > MAX_QUEUE) &&
+	    (priv->qos_queue_stat[cfg->q_id].flag == PP_NODE_FREE)) {
+		PR_ERR("Invalid Queue ID:%d\n", cfg->q_id);
 		return DP_FAILURE;
-	} else if (node->type == DP_NODE_SCH) {
-		struct resv_sch *resv_sched = priv->resv[port].resv_sched;
+	}
+	node_id = priv->qos_queue_stat[cfg->q_id].node_id;
 
-		cnt = priv->resv[node->dp_port].num_resv_sched;
-		for (i = 0; i <= cnt; i++) {
-			if (resv_sched[i].flag != PP_NODE_FREE)
-				continue;
-			node_id = resv_sched[i].id;
-			resv_sched[i].flag = PP_NODE_ALLOC;
-			priv->qos_sch_stat[node_id].flag = PP_NODE_RESERVE |
-								PP_NODE_ALLOC;
-			priv->qos_sch_stat[node_id].resv_idx = i;
-			node->id = (union dp_node_id)node_id;
+	if (qos_queue_conf_get(priv->qdev, node_id, conf)) {
+		PR_ERR("qos_queue_conf_get fail:%d\n", cfg->q_id);
+		return DP_FAILURE;
+	}
+	if (flag & (cfg->act & DP_NODE_DIS))
+		conf->blocked = 1;
+	else if (flag & (cfg->act & DP_NODE_EN))
+		conf->blocked = 0;
+	if (flag & (cfg->act & DP_NODE_SUSPEND))
+		conf->common_prop.suspended = 1;
+	else if (flag & (cfg->act & DP_NODE_RESUME))
+		conf->common_prop.suspended = 0;
+	if (flag & (cfg->drop == DP_QUEUE_DROP_WRED)) {
+		conf->wred_enable = 1;
+		conf->queue_wred_max_avg_green = cfg->max_size[0];
+		conf->queue_wred_max_avg_yellow = cfg->max_size[1];
+		conf->queue_wred_min_avg_green = cfg->min_size[0];
+		conf->queue_wred_min_avg_yellow = cfg->min_size[1];
+		conf->queue_wred_slope_green = cfg->wred_slope[0];
+		conf->queue_wred_slope_yellow = cfg->wred_slope[1];
+		conf->queue_wred_min_guaranteed = cfg->wred_min_guaranteed;
+		conf->queue_wred_max_allowed = cfg->wred_max_allowed;
+	} else if (flag & (cfg->drop == DP_QUEUE_DROP_TAIL)) {
+		PR_ERR("Further check PPv4 Tail Drop Capability.\n");
+		conf->wred_enable = 0;
+		conf->queue_wred_min_avg_green = cfg->min_size[0];
+		conf->queue_wred_min_avg_yellow = cfg->min_size[1];
+		conf->queue_wred_min_guaranteed = cfg->wred_min_guaranteed;
+		conf->queue_wred_max_allowed = cfg->wred_max_allowed;
+	}
+	if (qos_queue_set(priv->qdev, node_id, conf)) {
+		PR_ERR("failed to qos_queue_set:%d\n", cfg->q_id);
+		return DP_FAILURE;
+	}
+	return DP_SUCCESS;
+}
+
+/* dp_queue_conf_get_31 API
+ * Get Current Queue config and return DP_SUCCESS
+ * else return DP_FAILURE
+ */
+int dp_queue_conf_get_31(struct dp_queue_conf *cfg, int flag)
+{
+	int node_id;
+	struct pp_qos_queue_conf *conf;
+	struct hal_priv *priv = HAL(cfg->inst);
+
+	if ((cfg->q_id < 0 || cfg->q_id > MAX_QUEUE) &&
+	    (priv->qos_queue_stat[cfg->q_id].flag == PP_NODE_FREE)) {
+		PR_ERR("Invalid Queue ID:%d\n", cfg->q_id);
+		return DP_FAILURE;
+	}
+	node_id = priv->qos_queue_stat[cfg->q_id].node_id;
+
+	if (qos_queue_conf_get(priv->qdev, node_id, conf)) {
+		PR_ERR("qos_queue_conf_get fail\n");
+		return DP_FAILURE;
+	}
+	if (conf->blocked && conf->common_prop.suspended)
+		cfg->act = DP_NODE_SUSPEND;
+	else if (!conf->blocked && conf->common_prop.suspended)
+		cfg->act = DP_NODE_RESUME;
+	else if (conf->blocked)
+		cfg->act = DP_NODE_DIS;
+	else
+		cfg->act = DP_NODE_EN;
+
+	if (conf->wred_enable) {
+		cfg->drop = DP_QUEUE_DROP_WRED;
+		cfg->wred_slope[0] = conf->queue_wred_slope_green;
+		cfg->wred_slope[1] = conf->queue_wred_slope_yellow;
+		cfg->wred_slope[2] = 0;
+		cfg->wred_max_allowed = conf->queue_wred_max_allowed;
+		cfg->wred_min_guaranteed = conf->queue_wred_min_guaranteed;
+		cfg->min_size[0] = conf->queue_wred_min_avg_green;
+		cfg->min_size[1] = conf->queue_wred_min_avg_yellow;
+		cfg->min_size[2] = 0;
+		cfg->max_size[0] = conf->queue_wred_max_avg_green;
+		cfg->max_size[1] = conf->queue_wred_max_avg_yellow;
+		cfg->max_size[2] = 0;
+		//cfg->unit = conf->max_burst;
+		return DP_SUCCESS;
+	}
+	cfg->drop = DP_QUEUE_DROP_TAIL;
+	cfg->min_size[0] = conf->queue_wred_min_avg_green;
+	cfg->min_size[1] = conf->queue_wred_min_avg_yellow;
+	cfg->max_size[0] = conf->queue_wred_max_avg_green;
+	cfg->max_size[1] = conf->queue_wred_max_avg_yellow;
+	//cfg->unit = conf->max_burst;
+	return DP_SUCCESS;
+}
+
+/* dp_node_link_en_set_31 API
+ * Enable current link node and return DP_SUCCESS
+ * else return DP_FAILURE
+ */
+int dp_node_link_en_set_31(struct dp_node_link_enable *en, int flag)
+{
+	struct hal_priv *priv = HAL(en->inst);
+	int phy_id;
+
+	if (!en) {
+		PR_ERR("en info cannot be NULL\n");
+		return DP_FAILURE;
+	}
+
+	if (en->type == DP_NODE_QUEUE) {
+		phy_id = get_qid_by_node(en->inst, en->id.q_id, 0);
+		if ((priv->qos_queue_stat[phy_id].flag &
+		    PP_NODE_ACTIVE) &&
+		    (priv->qos_sch_stat[en->id.q_id].parent.flag &
+		    PP_NODE_ACTIVE)) {
+			en->en = DP_NODE_EN;
+			return DP_SUCCESS;
+		}
+	} else if (en->type == DP_NODE_SCH) {
+		if ((priv->qos_sch_stat[en->id.sch_id].p_flag &
+		    PP_NODE_ACTIVE) &&
+		    (priv->qos_sch_stat[en->id.sch_id].parent.flag &
+		    PP_NODE_ACTIVE)) {
+			en->en = DP_NODE_EN;
+			return DP_SUCCESS;
+		}
+	} else if (en->type == DP_NODE_PORT) {
+		phy_id = get_qid_by_node(en->inst, en->id.cqm_deq_port, 0);
+		if (priv->deq_port_stat[phy_id].flag & PP_NODE_ACTIVE) {
+			en->en = DP_NODE_EN;
 			return DP_SUCCESS;
 		}
-		return DP_FAILURE;
 	}
 	return DP_FAILURE;
 }
 
-int dp_node_alloc_global_31(struct dp_node_alloc *node, int flag)
+/* dp_node_link_en_get_31 API
+ * Get status of link node and return DP_SUCCESS
+ * else return DP_FAILURE
+ */
+int dp_node_link_en_get_31(struct dp_node_link_enable *en, int flag)
 {
-	int id;
-	int inst = node->inst;
-	struct pp_qos_dev *qos_dev;
-	struct pp_qos_queue_info *qos_queue_info;
-	struct hal_priv *priv = (struct hal_priv *)dp_port_prop[inst].priv_hal;
-	int phy_id;
+	struct hal_priv *priv = HAL(en->inst);
+	static struct pp_qos_queue_conf q_conf;
+	static struct pp_qos_sched_conf sched_conf;
+	static struct pp_qos_port_conf p_conf;
 
-	if (node->type == DP_NODE_QUEUE) {
-		pp_qos_queue_allocate(qos_dev, &id);
-		if (pp_qos_queue_info_get(qos_dev, id, qos_queue_info)) {
-			pp_qos_queue_remove(qos_dev, id);
+	if (!priv ||!priv->qdev) {
+		PR_ERR("priv or priv->qdev NULL\n");
+		return DP_FAILURE;
+	}
+	if (!en) {
+		PR_ERR("en info NULL\n");
+		return DP_FAILURE;
+	}
+	PR_INFO("en->id.q_id=%d\n", en->id.q_id);
+	en->en = 0;
+	if (en->type == DP_NODE_QUEUE) {
+		memset(&q_conf, 0, sizeof(q_conf));
+		if (qos_queue_conf_get(priv->qdev,
+		    priv->qos_queue_stat[en->id.q_id].node_id,
+		    &q_conf)) {
+			PR_ERR("qos_queue_conf_get fail: q[%d]\n",
+			       en->id.q_id);
 			return DP_FAILURE;
 		}
-		phy_id = qos_queue_info->physical_id;
-		priv->qos_queue_stat[phy_id].flag = PP_NODE_ALLOC;
-		priv->qos_queue_stat[phy_id].node_id = id;
-		priv->qos_queue_stat[phy_id].resv_idx = -1;
-		node->id = (union dp_node_id)phy_id;
+		if (q_conf.blocked)
+			en->en |= DP_NODE_DIS;
+		if (q_conf.common_prop.suspended)
+			en->en |= DP_NODE_SUSPEND;
+	} else if (en->type == DP_NODE_SCH) {
+		memset(&sched_conf, 0, sizeof(sched_conf));
+		if (qos_sched_conf_get(priv->qdev,
+		    en->id.sch_id, &sched_conf)) {
+			PR_ERR("qos_sched_conf_get fail: sched[/%d]\n",
+			       en->id.sch_id);
+			return DP_FAILURE;
+		}
+		if (sched_conf.common_prop.suspended)
+			en->en |= DP_NODE_SUSPEND;
+	} else if (en->type == DP_NODE_PORT) {
+		memset(&p_conf, 0, sizeof(p_conf));
+		if (qos_port_conf_get(priv->qdev,
+		    priv->deq_port_stat[en->id.cqm_deq_port].node_id,
+		    &p_conf)) {
+			PR_ERR("qos_queue_conf_get fail: port[%d]\n",
+			       en->id.cqm_deq_port);
+			return DP_FAILURE;
+		}
+		if (p_conf.common_prop.suspended)
+			en->en |= DP_NODE_SUSPEND;
+	}
+	return DP_SUCCESS;
+}
+
+/* dp_link_get_31 API
+ * get full link based on queue and return DP_SUCCESS
+ * else return DP_FAILURE
+ */
+int dp_link_get_31(struct dp_qos_link *cfg, int flag)
+{
+	struct pp_qos_queue_conf queue_cfg;
+	struct pp_qos_sched_conf sched_cfg;
+	struct hal_priv *priv = HAL(cfg->inst);
+	int i;
+	int node_id = priv->qos_queue_stat[cfg->q_id].node_id;
+
+	if (!cfg) {
+		PR_ERR("cfg cannot be NULL\n");
+		return DP_FAILURE;
+	}
+
+	if (priv->qos_queue_stat[cfg->q_id].flag != PP_NODE_ACTIVE) {
+		PR_ERR("Incorrect queue:%d state:expect ACTIV\n", cfg->q_id);
+		return DP_FAILURE;
+	}
+
+	if (qos_queue_conf_get(priv->qdev, node_id, &queue_cfg)) {
+		PR_ERR("failed to qos_queue_conf_get\n");
+		return DP_FAILURE;
+	}
+
+	if (priv->qos_sch_stat[node_id].parent.type == DP_NODE_PORT) {
+		cfg->q_arbi = 0;
+		cfg->q_leaf = 0;
+		cfg->n_sch_lvl = 0;
+		cfg->q_prio_wfq = queue_cfg.queue_child_prop.priority;
+		cfg->cqm_deq_port = priv->qos_sch_stat[node_id].parent.node_id;
 		return DP_SUCCESS;
-	} else if (node->type == DP_NODE_SCH) {
-		pp_qos_sched_allocate(qos_dev, &id);
-		priv->qos_sch_stat[id].flag = PP_NODE_ALLOC;
-		priv->qos_sch_stat[id].resv_idx = -1;
-		node->id = (union dp_node_id)id;
+	} else if (priv->qos_sch_stat[node_id].parent.type == DP_NODE_SCH) {
+		cfg->q_arbi = 0;
+		cfg->q_leaf = 0;
+		cfg->q_prio_wfq = queue_cfg.queue_child_prop.priority;
+		cfg->sch[0].id = priv->qos_sch_stat[node_id].parent.node_id;
+		for (i = (cfg->n_sch_lvl - 1); i <= DP_MAX_SCH_LVL; i++) {
+			if (qos_sched_conf_get(priv->qdev, cfg->sch[i].id,
+						  &sched_cfg)) {
+				PR_ERR("failed to qos_sched_conf_get\n");
+				return DP_FAILURE;
+			}
+			cfg->sch[i].arbi =
+					sched_cfg.sched_parent_prop.arbitration;
+			cfg->sch[i].prio_wfq =
+					sched_cfg.sched_child_prop.priority;
+			cfg->sch[i].id =
+				priv->qos_sch_stat[i + 1].parent.node_id;
+			cfg->sch[i].leaf = 0;
+			cfg->n_sch_lvl = i;
+		}
+		cfg->cqm_deq_port = priv->qos_sch_stat[i].parent.node_id;
 		return DP_SUCCESS;
 	}
 	return DP_FAILURE;
 }
 
-int dp_node_alloc_31(struct dp_node_alloc *node, int flag)
+/* dp_link_add_31 API
+ * configure end to end link and return DP_SUCCESS
+ * else return DP_FAILURE
+ */
+int dp_link_add_31(struct dp_qos_link *cfg, int flag)
 {
-	int inst = node->inst;
-	struct hal_priv *priv = (struct hal_priv *)dp_port_prop[inst].priv_hal;
+	struct dp_node_link *info;
+	int i, node_id;
+	int f_q_free = 0;
+	int f_q_auto = 0; /*flag if node is DP_NODE_AUTO_ID*/
+	struct f {
+		u16 flag;
+		u16 sch_id;
+		u16 f_auto; /*flag if node is DP_NODE_AUTO_ID*/
+	};
+	struct f f_sch_free[DP_MAX_SCH_LVL] = {0};
 
-	if (!priv) {
-		PR_ERR("priv is NULL cannot proceed!!\n");
+	if (!cfg) {
+		PR_ERR("cfg cannot be NULL\n");
 		return DP_FAILURE;
 	}
 
-	if (flag  && DP_ALLOC_RESV_ONLY) {
-	/* if can get from its reserved resource and return DP_SUCCESS.
-	 *	Otherwise return DP_FAIL;
-	 */
-		return dp_node_alloc_resv_31(node, flag);
+	if (cfg->n_sch_lvl > DP_MAX_SCH_LVL) {
+		PR_ERR("Incorrect sched_lvl:%s(%d) > %s(%d)\n",
+		       "cfg->n_sch_lvl", cfg->n_sch_lvl,
+		       "DP_MAX_SCH_LVL", DP_MAX_SCH_LVL);
+		return DP_FAILURE;
 	}
-	if (flag  && DP_ALLOC_GLOBAL_ONLY) {
-	/* if can get from global pool and return DP_SUCCESS.
-	 *	Otherwise return DP_FAILURE;
-	 */
-		return dp_node_alloc_global_31(node, flag);
+
+	info->inst = cfg->inst;
+	info->dp_port = cfg->dp_port;
+	info->node_id.q_id = cfg->q_id;
+	info->cqm_deq_port.cqm_deq_port = cfg->cqm_deq_port;
+
+	if (cfg->q_id == DP_NODE_AUTO_ID)
+		f_q_auto = 1;
+
+	if (cfg->n_sch_lvl) {
+		/*link sched to port*/
+		if (cfg->sch[cfg->n_sch_lvl - 1].id == DP_NODE_AUTO_ID)
+			f_sch_free[cfg->n_sch_lvl - 1].f_auto = 1;
+		info->node_id.sch_id = cfg->sch[cfg->n_sch_lvl - 1].id;
+		info->node_type = DP_NODE_SCH;
+		info->p_node_id.cqm_deq_port = cfg->cqm_deq_port;
+		info->p_node_type = DP_NODE_PORT;
+		info->arbi = cfg->sch[cfg->n_sch_lvl - 1].arbi;
+		info->leaf = cfg->sch[cfg->n_sch_lvl - 1].leaf;
+		info->prio_wfq = cfg->sch[cfg->n_sch_lvl - 1].prio_wfq;
+		f_sch_free[cfg->n_sch_lvl - 1].flag = 1;
+		f_sch_free[cfg->n_sch_lvl - 1].sch_id =
+						cfg->sch[cfg->n_sch_lvl - 1].id;
+
+		if (dp_node_link_add_31(info, flag)) {
+			PR_ERR("Failed to link Sch:%d to Port:%d\n",
+			       cfg->sch[cfg->n_sch_lvl].id, cfg->cqm_deq_port);
+			goto EXIT;
+		}
+
+		/*link sched to sched*/
+		for (i = (cfg->n_sch_lvl - 2); i >= 0; i--) {
+			if (cfg->sch[i].id == DP_NODE_AUTO_ID)
+				f_sch_free[i].f_auto = 1;
+			info->node_id.sch_id = cfg->sch[i].id;
+			info->node_type = DP_NODE_SCH;
+			info->p_node_id.sch_id = cfg->sch[i + 1].id;
+			info->p_node_type = DP_NODE_SCH;
+			info->arbi = cfg->sch[i].arbi;
+			info->leaf = cfg->sch[i].leaf;
+			info->prio_wfq = cfg->sch[i].prio_wfq;
+			f_sch_free[i].flag = 1;
+			f_sch_free[i].sch_id = cfg->sch[i].id;
+
+			if (dp_node_link_add_31(info, flag)) {
+				PR_ERR("Failed to link Sch:%d to Sch:%d\n",
+				       cfg->sch[i].id, cfg->sch[i + 1].id);
+				goto EXIT;
+			}
+		}
+		/*link Queue to sched*/
+		info->node_type = DP_NODE_QUEUE;
+		info->p_node_id.sch_id = cfg->sch[0].id;
+		info->p_node_type = DP_NODE_SCH;
+		info->arbi = cfg->sch[0].arbi;
+		info->leaf = cfg->sch[0].leaf;
+		info->prio_wfq = cfg->sch[0].prio_wfq;
+		f_q_free = 1;
+
+		if (dp_node_link_add_31(info, flag)) {
+			PR_ERR("Failed to link Q:%d to Sch:%d\n",
+			       cfg->q_id, cfg->sch[0].id);
+			goto EXIT;
+		}
+	} else {
+		/*link Queue to Port*/
+		info->node_type = DP_NODE_QUEUE;
+		info->p_node_id.cqm_deq_port = cfg->cqm_deq_port;
+		info->p_node_type = DP_NODE_PORT;
+		info->arbi = cfg->q_arbi;
+		info->leaf = cfg->q_leaf;
+		info->prio_wfq = cfg->q_prio_wfq;
+		f_q_free = 1;
+
+		if (dp_node_link_add_31(info, flag)) {
+			PR_ERR("Failed to link Q:%d to Port:%d\n",
+			       cfg->q_id, cfg->cqm_deq_port);
+			goto EXIT;
+		}
 	}
-	if (flag  && DP_ALLOC_GLOBAL_FIRST) {
-	/* if can get from the global pool, return DP_SUCCESS;
-	 * if can get from its reserved resource and return DP_SUCCESS;
-	 * return DP_FAILURE;
-	 */
-		if (dp_node_alloc_global_31(node, flag) == DP_SUCCESS)
-			return DP_SUCCESS;
-		return dp_node_alloc_resv_31(node, flag);
+
+EXIT:
+	for (i = (cfg->n_sch_lvl - 1); i >= 0; i--) {
+		if (!f_sch_free[i].flag)
+			return DP_FAILURE;
+		/*sch is auto_alloc move it to FREE*/
+		if (f_sch_free[i].f_auto)
+			node_id = f_sch_free[i].sch_id;
+			dp_node_free_31((struct dp_node_alloc *)node_id,
+					flag);
+		/*sch provided by caller move it to ALLOC*/
+		node_stat_update(info->inst, f_sch_free[i].sch_id, DP_NODE_DEC);
+		return DP_FAILURE;
 	}
-	/*default order: reserved pool, */
-	/* if can get from its reserved resource and return DP_SUCCESS.
-	 * if can get from the global pool, return DP_SUCCESS
-	 * return DP_FAILURE
-	 */
-	if (dp_node_alloc_resv_31(node, flag) == DP_SUCCESS)
-		return DP_SUCCESS;
-	return dp_node_alloc_global_31(node, flag);
+	if (f_q_free) {
+		/*queue is auto_alloc move it to FREE*/
+		if (f_q_auto)
+			dp_node_free_31((struct dp_node_alloc *)cfg->q_id,
+					flag);
+		/*queue provided by caller move it to ALLOC*/
+		node_stat_update(info->inst, cfg->q_id, DP_NODE_DEC);
+		return DP_FAILURE;
+	}
+	return DP_SUCCESS;
 }
 
-int dp_node_free_31(struct dp_node_alloc *node, int flag)
-{
-/* if (this node is not unlinked yet)
- * unlink it
- * If (this node is a  reserved node)
- * return this node to this device’s reserved node table
- * mark this node as Free in this device’s reserved node table
- * else
- * return this node to the system global table
- * mark this node free in system global table
+/* dp_link_free_31 API
+ * Remove link of attached nodes and return DP_SUCCESS
+ * else return DP_FAILURE
  */
-	int sch_id;
-	struct pp_qos_dev *qos_dev;
-	int inst = node->inst;
-	struct hal_priv *priv = (struct hal_priv *)dp_port_prop[inst].priv_hal;
-	int port = node->dp_port;
-	int phy_id;
-	int node_id;
-	int resv_idx;
+static int dp_link_free_31(struct dp_qos_link *cfg, int flag)
+{
+	struct dp_node_link *info;
 
-	if (!priv) {
-		PR_ERR("priv is NULL cannot proceed!!\n");
+	if (!cfg) {
+		PR_ERR("cfg cannot be NULL\n");
 		return DP_FAILURE;
 	}
 
-	if (node->type == DP_NODE_QUEUE) {
-		struct resv_q *resv_q = priv->resv[port].resv_q;
-
-		phy_id = node->id.q_id;
-		node_id = priv->qos_queue_stat[phy_id].node_id;
-		if (!(priv->qos_queue_stat[phy_id].flag & PP_NODE_RESERVE)) {
-			/* Free to global resource */
-			pp_qos_queue_remove(qos_dev, node_id);
-			priv->qos_queue_stat[phy_id].flag = PP_NODE_FREE;
-			priv->qos_queue_stat[phy_id].node_id = 0;
-			priv->qos_queue_stat[phy_id].resv_idx = -1;
-			return DP_SUCCESS;
-		}
-		/* Return to reserved resource */
-		resv_idx = priv->qos_queue_stat[phy_id].resv_idx;
-		resv_q[resv_idx].flag = PP_NODE_FREE;
-		priv->qos_queue_stat[phy_id].flag = PP_NODE_FREE;
-		priv->qos_queue_stat[phy_id].node_id = 0;
-		priv->qos_queue_stat[phy_id].resv_idx = -1;
-		return DP_SUCCESS;
-	} else if (node->type == DP_NODE_SCH) {
-		struct resv_sch *resv_sched = priv->resv[port].resv_sched;
+	if (cfg->n_sch_lvl > DP_MAX_SCH_LVL) {
+		PR_ERR("Incorrect sched_lvl:%s(%d) > %s(%d)\n",
+		       "cfg->n_sch_lvl", cfg->n_sch_lvl,
+		       "DP_MAX_SCH_LVL", DP_MAX_SCH_LVL);
+		return DP_FAILURE;
+	}
 
-		sch_id = node->id.sch_id;
-		if (!(priv->qos_sch_stat[sch_id].flag & PP_NODE_RESERVE)) {
-			/* Free to global resource */
-			pp_qos_sched_remove(qos_dev, sch_id);
-			priv->qos_sch_stat[sch_id].flag = PP_NODE_FREE;
-			priv->qos_sch_stat[sch_id].resv_idx = -1;
-			return DP_SUCCESS;
+	info->inst = cfg->inst;
+	info->dp_port = cfg->dp_port;
+	info->node_id.q_id = cfg->q_id;
+	info->cqm_deq_port.cqm_deq_port = cfg->cqm_deq_port;
+
+	if (info->p_node_type == DP_NODE_PORT) {
+		/*unlink sched to port*/
+		if (info->node_type == DP_NODE_SCH) {
+			info->node_id.sch_id = cfg->sch[cfg->n_sch_lvl - 1].id;
+			dp_node_unlink_31(info, flag);
+			dp_link_unset(info, flag);
+		}
+		/*unlink Queue to Port*/
+		if (info->node_type == DP_NODE_QUEUE) {
+			info->node_id.q_id = cfg->q_id;
+			dp_node_unlink_31(info, flag);
+			dp_link_unset(info, flag);
 		}
-		/* Return to reserved resource */
-		resv_idx = priv->qos_sch_stat[sch_id].resv_idx;
-		resv_sched[resv_idx].flag = PP_NODE_FREE;
-		priv->qos_sch_stat[sch_id].flag = PP_NODE_FREE;
-		priv->qos_sch_stat[sch_id].resv_idx = -1;
+	} else if (info->p_node_type == DP_NODE_SCH) {
+		/*unlink sched to sched*/
+		return DP_FAILURE;
+		/*unlink Queue to sched*/
+	}
+	return DP_FAILURE;
+}
+
+int dp_shaper_conf_set_31(struct dp_shaper_conf *cfg, int flag)
+{
+	if ((cfg->cmd == DP_SHAPER_CMD_ADD) && (cfg->type == DP_NODE_QUEUE)) {
+		//if (set_lookup_qid_via_index)
+		return DP_SUCCESS;
+	} else if ((cfg->cmd == DP_SHAPER_CMD_ADD) &&
+		   (cfg->type == DP_NODE_SCH)) {
+		return DP_SUCCESS;
+	} else if ((cfg->cmd == DP_SHAPER_CMD_REMOVE) &&
+		   (cfg->type == DP_NODE_QUEUE)) {
+		return DP_SUCCESS;
+	} else if ((cfg->cmd == DP_SHAPER_CMD_REMOVE) &&
+		   (cfg->type == DP_NODE_SCH)) {
+		return DP_SUCCESS;
+	} else if ((cfg->cmd == DP_SHAPER_CMD_DISABLE) &&
+		   (cfg->type == DP_NODE_QUEUE)) {
 		return DP_SUCCESS;
+	} else if ((cfg->cmd == DP_SHAPER_CMD_DISABLE) &&
+		   (cfg->type == DP_NODE_SCH)) {
+		return DP_SUCCESS;
+	}
+	return DP_FAILURE;
+}
+
+int dp_shaper_conf_get_31(struct dp_shaper_conf *cfg, int flag)
+{
+	struct hal_priv *priv = HAL(cfg->inst);
+
+	if (cfg->type == DP_NODE_QUEUE) {
+		if (priv->qos_queue_stat[cfg->id.q_id].flag == PP_NODE_ACTIVE)
+			cfg->id.q_id =
+				priv->qos_queue_stat[cfg->id.q_id].node_id;
+	} else if (cfg->type == DP_NODE_SCH) {
+		if (priv->qos_queue_stat[cfg->id.sch_id].flag == PP_NODE_ACTIVE)
+			return cfg->id.sch_id;
 	}
 	return DP_FAILURE;
 }
 
+int dp_queue_map_get_31(struct queue_map_get *cfg, int flag)
+{
+	return DP_FAILURE;
+}
+
+int dp_queue_map_set_31(struct queue_map_set *cfg, int flag)
+{
+	return DP_FAILURE;
+}
+
+int dp_counter_mode_set_31(struct dp_counter_conf *cfg, int flag)
+{
+	return DP_FAILURE;
+}
+
+int dp_counter_mode_get_31(struct dp_counter_conf *cfg, int flag)
+{
+	return DP_FAILURE;
+}
+
 #ifdef PP_QOS_LINK_EXAMPLE
 /* Example: queue -> QOS/CQM dequeue port
  * inst: dp instance
@@ -246,7 +2276,8 @@ int dp_node_free_31(struct dp_node_alloc *node, int flag)
  * t_conf: for pon, it is used to get cqm dequeue port via t-cont index
  *         for others, its value should be 0
  * q_node: queueu node id
-*/
+ */
+
 int ppv4_queue_port_example(int inst, int dp_port, int t_cont, int q_node)
 {
 	struct pp_qos_port_conf  port_cfg;
@@ -254,45 +2285,46 @@ int ppv4_queue_port_example(int inst, int dp_port, int t_cont, int q_node)
 	int qos_port_node;
 	int rc;
 	int cqm_deq_port;
-	struct pp_qos_dev * qos_dev = NULL;
 	struct pmac_port_info *port_info;
 
 	port_info = &dp_port_info[inst][dp_port];
 	cqm_deq_port = port_info->deq_port_base + t_cont;
 
-	/*Allocate qos dequeue port's node id via cqm_deq_port */
-	rc = pp_qos_port_allocate(qos_dev, cqm_deq_port, &qos_port_node);
+	/*Allocate qos dequeue port's node id via cqm_deq_port*/
+	rc = qos_port_allocate(priv->qdev, cqm_deq_port, &qos_port_node);
 	if (rc) {
-		pr_err("failed to pp_qos_port_allocate\n");
+		PR_ERR("failed to qos_port_allocate\n");
 		return -1;
 	}
 
-	/*Configure QOS dequeue port */
-	pp_qos_port_conf_set_default(&port_cfg);
+	/*Configure QOS dequeue port*/
+	qos_port_conf_set_default(&port_cfg);
 	port_cfg.ring_address = (void *)(port_info->tx_ring_addr +
 		port_info->tx_ring_offset * t_cont);
 	port_cfg.ring_size = port_info->tx_ring_size;
 	if (port_info->tx_pkt_credit) {
 		port_cfg.packet_credit_enable = 1;
-		port_cfg.packet_credit = port_info->tx_pkt_credit;
+		port_cfg.credit = port_info->tx_pkt_credit;
 	}
-	if (port_info->tx_pkt_credit) {
+#ifdef TX_BYTE_CREDIT
+	if (port_info->tx_b_credit) {
 		port_cfg.byte_credit_enable = 1;
 		port_cfg.byte_credit = port_info->tx_pkt_credit;
 	}
+#endif
 #ifdef EXT_BW
 	port_cfg.parent.arbitration = ARBITRATION_WRR;
 	port_cfg.common.bandwidth_limit = 1000;
 #endif
-	rc = pp_qos_port_set(qos_dev, qos_port_node, &port_cfg);
+	rc = qos_port_set(priv->qdev, qos_port_node, &port_cfg);
 	if (rc) {
-		pr_err("failed to pp_qos_port_set\n");
-		pp_qos_port_remove(qos_dev, qos_port_node);
+		PR_ERR("failed to qos_port_set\n");
+		qos_port_remove(priv->qdev, qos_port_node);
 		return -1;
 	}
 
-	/*Attach queue to QoS port */
-	pp_qos_queue_conf_set_default(&queue_cfg);
+	/*Attach queue to QoS port*/
+	qos_queue_conf_set_default(&queue_cfg);
 	queue_cfg.queue_child_prop.parent = qos_port_node;
 #ifdef EXT_BW
 	queue_cfg.max_burst  = 64;
@@ -300,16 +2332,15 @@ int ppv4_queue_port_example(int inst, int dp_port, int t_cont, int q_node)
 	queue_cfg.queue_wred_min_guaranteed = 1;
 	queue_cfg.queue_wred_max_allowed = 10;
 #endif
-	rc = pp_qos_queue_set(qos_dev, q_node, &queue_cfg);
+	rc = qos_queue_set(priv->qdev, q_node, &queue_cfg);
 	if (rc) {
-		pr_err("failed to pp_qos_queue_set\n");
-		pp_qos_port_remove(qos_dev, qos_port_node);
+		PR_ERR("failed to qos_queue_set\n");
+		qos_port_remove(priv->qdev, qos_port_node);
 		return -1;
 	}
 	return 0;
 }
 
-
 /* Example: queue -> scheduler1- > scheduler 2 -> QOS/CQM dequeue port
  * inst: dp instance
  * dp_port: dp port id
@@ -318,7 +2349,7 @@ int ppv4_queue_port_example(int inst, int dp_port, int t_cont, int q_node)
  * q_node: queueu node id
  * sch_node1: schduler node which connected with queue
  * sch_node2: schduler node which connected with sch_node1
-*/
+ */
 int ppv4_queue_scheduler(int inst, int dp_port, int t_cont, int q_node,
 			 int sch_node1, int sch_node2)
 {
@@ -328,27 +2359,26 @@ int ppv4_queue_scheduler(int inst, int dp_port, int t_cont, int q_node,
 	int qos_port_node;
 	int rc;
 	int cqm_deq_port;
-	struct pp_qos_dev * qos_dev = NULL;
 	struct pmac_port_info *port_info;
 
 	port_info = &dp_port_info[inst][dp_port];
 	cqm_deq_port = port_info->deq_port_base + t_cont;
 
-	/*Allocate qos dequeue port's node id via cqm_deq_port */
-	rc = pp_qos_port_allocate(qos_dev, cqm_deq_port, &qos_port_node);
+	/*Allocate qos dequeue port's node id via cqm_deq_port*/
+	rc = qos_port_allocate(priv->qdev, cqm_deq_port, &qos_port_node);
 	if (rc) {
-		pr_err("failed to pp_qos_port_allocate\n");
+		PR_ERR("failed to qos_port_allocate\n");
 		return -1;
 	}
 
-	/*Configure QOS dequeue port */
-	pp_qos_port_conf_set_default(&port_cfg);
+	/*Configure QOS dequeue port*/
+	qos_port_conf_set_default(&port_cfg);
 	port_cfg.ring_address = (void *)(port_info->tx_ring_addr +
 		port_info->tx_ring_offset * t_cont);
 	port_cfg.ring_size = port_info->tx_ring_size;
 	if (port_info->tx_pkt_credit) {
 		port_cfg.packet_credit_enable = 1;
-		port_cfg.packet_credit = port_info->tx_pkt_credit;
+		port_cfg.credit = port_info->tx_pkt_credit;
 	}
 	if (port_info->tx_pkt_credit) {
 		port_cfg.byte_credit_enable = 1;
@@ -358,15 +2388,15 @@ int ppv4_queue_scheduler(int inst, int dp_port, int t_cont, int q_node,
 	port_cfg.parent.arbitration = ARBITRATION_WRR;
 	port_cfg.common.bandwidth_limit = 1000;
 #endif
-	rc = pp_qos_port_set(qos_dev, qos_port_node, &port_cfg);
+	rc = qos_port_set(priv->qdev, qos_port_node, &port_cfg);
 	if (rc) {
-		pr_err("failed to pp_qos_port_set\n");
-		pp_qos_port_remove(qos_dev, qos_port_node);
+		PR_ERR("failed to qos_port_set\n");
+		qos_port_remove(priv->qdev, qos_port_node);
 		return -1;
 	}
 
-	/*Attach queue to sch_node1 */
-	pp_qos_queue_conf_set_default(&queue_cfg);
+	/*Attach queue to sch_node1*/
+	qos_queue_conf_set_default(&queue_cfg);
 	queue_cfg.queue_child_prop.parent = sch_node1;
 #ifdef EXT_BW
 	queue_cfg.max_burst  = 64;
@@ -374,34 +2404,33 @@ int ppv4_queue_scheduler(int inst, int dp_port, int t_cont, int q_node,
 	queue_cfg.queue_wred_min_guaranteed = 1;
 	queue_cfg.queue_wred_max_allowed = 10;
 #endif
-	rc = pp_qos_queue_set(qos_dev, q_node, &queue_cfg);
+	rc = qos_queue_set(priv->qdev, q_node, &queue_cfg);
 	if (rc) {
-		pr_err("failed to pp_qos_queue_set\n");
-		pp_qos_port_remove(qos_dev, qos_port_node);
+		PR_ERR("failed to qos_queue_set\n");
+		qos_port_remove(priv->qdev, qos_port_node);
 		return -1;
 	}
 
-	/*Attach sch_node1 to sch_node2 */
-	pp_qos_sched_conf_set_default(&sched_cfg);
+	/*Attach sch_node1 to sch_node2*/
+	qos_sched_conf_set_default(&sched_cfg);
 	sched_cfg.sched_child_prop.parent = sch_node2;
-	rc = pp_qos_sched_set(qos_dev, sch_node1, &sched_cfg);
+	rc = qos_sched_set(priv->qdev, sch_node1, &sched_cfg);
 	if (rc) {
-		pr_err("failed to pp_qos_sched_set\n");
-		pp_qos_port_remove(qos_dev, qos_port_node);
+		PR_ERR("failed to qos_sched_set\n");
+		qos_port_remove(priv->qdev, qos_port_node);
 		return -1;
 	}
 
-	/*Attach sch_node2 to qos/cqm dequeue port */
-	pp_qos_sched_conf_set_default(&sched_cfg);
+	/*Attach sch_node2 to qos/cqm dequeue port*/
+	qos_sched_conf_set_default(&sched_cfg);
 	sched_cfg.sched_child_prop.parent = qos_port_node;
-	rc = pp_qos_sched_set(qos_dev, sch_node2, &sched_cfg);
+	rc = qos_sched_set(priv->qdev, sch_node2, &sched_cfg);
 	if (rc) {
-		pr_err("failed to pp_qos_sched_set\n");
-		pp_qos_port_remove(qos_dev, qos_port_node);
+		PR_ERR("failed to qos_sched_set\n");
+		qos_port_remove(priv->qdev, qos_port_node);
 		return -1;
 	}
-	
+
 	return 0;
 }
 #endif /* PP_QOS_LINK_EXAMPLE*/
-
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_proc.c b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_proc.c
index 7ae5cdc3b099a958c6c20e80b7030cc3149e7de7..8899a5d7eda1c6b08c028eeacab199e9aac50ed5 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_proc.c
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_proc.c
@@ -33,7 +33,6 @@
 #define PROC_PMAC  "pmac"
 #define PROC_EP "ep" /*EP/port ID info */
 #define DP_PROC_CBMLOOKUP "lookup"
-#define DP_TX_PKT "tx"
 #define DP_MIB_Q "qos_mib"
 
 struct list_head fdb_tbl_list;
@@ -148,10 +147,11 @@ ssize_t proc_parser_write(struct file *file, const char *buf,
 	char *param_list[20];
 	s8 cpu = 0, mpe1 = 0, mpe2 = 0, mpe3 = 0, flag = 0;
 	int pce_rule_id;
-	GSW_PCE_rule_t pce;
+	static GSW_PCE_rule_t pce;
 	int inst = 0;
 	struct core_ops *gsw_handle;
 
+	memset(&pce, 0, sizeof(pce));
 	gsw_handle = dp_port_prop[inst].ops[GSWIP_R];
 	len = (sizeof(str) > count) ? count : sizeof(str) - 1;
 	len -= copy_from_user(str, buf, len);
@@ -919,152 +919,6 @@ help:
 	return count;
 }
 
-/*flag: for dp_xmit
- *pool: 1-CPU
- */
-static int dp_send_packet(u8 *pdata, int len, char *devname, u32 flag,
-			  u32 pool, u32 discard)
-{
-	struct sk_buff *skb;
-	dp_subif_t subif = { 0 };
-	#define PAD  32
-
-	if (pool == 1) {
-		len += PAD;
-		if (len < ETH_ZLEN)
-			len = ETH_ZLEN;
-		skb = alloc_skb(len, GFP_ATOMIC);
-		if (skb)
-			skb_reserve(skb, PAD);
-		PR_INFO_ONCE("Allocate CPU buffer\n");
-	} else {
-		skb = cbm_alloc_skb(len + 8, GFP_ATOMIC);
-		PR_INFO_ONCE("Allocate bm buffer\n");
-	}
-
-	if (unlikely(!skb)) {
-		PR_ERR("allocate cbm buffer fail\n");
-		return -1;
-	}
-
-	skb->DW0 = 0;
-	skb->DW1 = 0;
-	skb->DW2 = 0;
-	skb->DW3 = 0;
-	if (discard) {
-		((struct dma_tx_desc_3 *)&skb->DW3)->field.dic = 1;
-		PR_INFO_ONCE("discard bit set in DW3\n");
-	}
-	memcpy(skb->data, pdata, len);
-	skb->len = 0;
-	skb_put(skb, len);
-	skb->dev = dev_get_by_name(&init_net, devname);
-
-	if (dp_get_netif_subifid(skb->dev, skb, NULL, skb->data, &subif, 0)) {
-		PR_ERR("dp_get_netif_subifid failed for %s\n",
-		       skb->dev->name);
-		dev_kfree_skb_any(skb);
-		return -1;
-	}
-
-	((struct dma_tx_desc_1 *)&skb->DW1)->field.ep = subif.port_id;
-	((struct dma_tx_desc_0 *)&skb->DW0)->field.dest_sub_if_id =
-		subif.subif;
-
-	if (dp_xmit(skb->dev, &subif, skb, skb->len, flag))
-		return -1;
-
-	return 0;
-}
-
-static u8 ipv4_plain_udp[] = {
-	0x00, 0x00, 0x01, 0x00, 0x00, 0x01, /*mac */
-	0x00, 0x10, 0x94, 0x00, 0x00, 0x02,
-	0x08, 0x00,	/*type */
-	0x45, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x11, /*ip hdr*/
-	0x3A, 0x56, 0xC0, 0x55, 0x01, 0x02, 0xC0, 0x00, 0x00, 0x01,
-	0x04, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x7A, 0x41, 0x00, 0x00, /*udp hdr*/
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00
-};
-
-static u8 ipv4_plain_tcp[1514] = {
-	0x00, 0x01, 0x01, 0x01, 0x01, 0x01, /*mac */
-	0x00, 0x10, 0x94, 0x00, 0x00, 0x02,
-	0x08, 0x00,	/*type */
-	0x45, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x06, /*ip hdr*/
-	0x3A, 0x61, 0xC0, 0x55, 0x01, 0x02, 0xC0, 0x00, 0x00, 0x01,
-	0x04, 0x00, 0x04, 0x00, 0x00, 0x01, 0xE2, 0x40, 0x00, 0x03, /*tcp hdr*/
-	0x94, 0x47, 0x50, 0x10, 0x10, 0x00, 0x9F, 0xD9, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*data */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00
-};
-
-ssize_t proc_tx_pkt(struct file *file, const char *buf,
-		    size_t count, loff_t *ppos)
-{
-	int len = 0;
-	char data[100];
-	char *param_list[10];
-	int num, pkt_num, size, times, pool = 0, disc = 0;
-	char *p;
-
-	len = (count >= sizeof(data)) ? (sizeof(data) - 1) : count;
-	DP_DEBUG(DP_DBG_FLAG_DBG, "len=%d\n", len);
-
-	if (len <= 0) {
-		PR_ERR("Wrong len value (%d)\n", len);
-		return count;
-	}
-	if (copy_from_user(data, buf, len)) {
-		PR_ERR("copy_from_user fail");
-		return count;
-	}
-	data[len - 1] = 0; /* Make string */
-	num = dp_split_buffer(data, param_list, ARRAY_SIZE(param_list));
-	if (num <= 1)
-		goto help;
-	pkt_num = dp_atoi(param_list[1]);
-	if (pkt_num <= 0)
-		pkt_num = 1;
-	if (dp_strcmpi("tcp", param_list[2]) == 0) {
-		p = ipv4_plain_tcp;
-		size = sizeof(ipv4_plain_tcp);
-		PR_INFO("send tcp packet\n");
-	} else { /*udp*/
-		p = ipv4_plain_udp;
-		size = sizeof(ipv4_plain_udp);
-		PR_INFO("send udp packet\n");
-	}
-	if (dp_strcmpi("bm", param_list[3]) == 0) {
-		PR_INFO("BM\n");
-		pool = 0;
-	} else {
-		PR_INFO("CPU buffer\n");
-		pool = 1;
-	}
-	if (dp_strcmpi("disc", param_list[4]) == 0) {
-		PR_INFO("disc\n");
-		disc = 1;
-	}
-	times = 0;
-	while (pkt_num--) {
-		if (dp_send_packet(p, size, param_list[0], 0, pool, disc))
-			break;
-		times++;
-	}
-	PR_INFO("sent %d packet already\n", times);
-	return count;
-help:   /*                        [0]         [1]         [2]     [3] [4]*/
-	PR_INFO("tx packet: echo <dev name> <packet num> <udp/tcp> %s %s\n",
-		"<pool type:cpu/bm>",
-		"<disc>");
-	return count;
-}
-
 /*in bytes*/
 int get_q_qocc(int inst, int qid, u32 *c)
 {
@@ -1190,12 +1044,15 @@ ssize_t proc_qos_mib(struct file *file, const char *buf,
 				PR_INFO("P[%03d]: 0x%08x 0x%08x\n",
 					i, gree_b, yellow_b);
 		}
-	}
+	} else
+		goto help;
 
 	return count;
 help:   /*                        [0]    [1]*/
-	PR_INFO("queue mib: echo <q> <start qid> <end qid>\n");
-	PR_INFO("port  mib: echo <p> <start port_id> <end port_id>\n");
+	PR_INFO("queue mib: echo <q> <start qid> <end qid> > %s\n",
+		"/proc/dp/" DP_MIB_Q);
+	PR_INFO("port  mib: echo <p> <start port_id> <end port_id> > %s\n",
+		"/proc/dp/" DP_MIB_Q);
 	return count;
 }
 
@@ -2548,7 +2405,6 @@ static struct dp_proc_entry dp_proc_entries[] = {
 #endif
 	{DP_PROC_CBMLOOKUP, NULL, lookup_dump31, lookup_start31,
 		proc_get_qid_via_index31},
-	{DP_TX_PKT, NULL, NULL, NULL, proc_tx_pkt},
 	{DP_MIB_Q, NULL, NULL, NULL, proc_qos_mib},
 
 	/*the last place holder */
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_switchdev.c b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_switchdev.c
index c6b88da847997e1a8704e05bb13238eedda2e85c..84491f5a0ae0715b69bfdabdb079c5004a3fb673 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_switchdev.c
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_switchdev.c
@@ -206,8 +206,7 @@ int dp_swdev_bridge_port_cfg_reset(struct br_info *br_item,
 						   gsw_handle, &brportcfg);
 				if (ret != GSW_statusOk) {
 					PR_ERR
-					("failed getting br port cfg:%s\r\n",
-					  __func__);
+					("failed getting br port cfg\r\n");
 					return -1;
 				}
 				UNSET_BP_MAP(brportcfg.nBridgePortMap, bport);
@@ -222,8 +221,7 @@ int dp_swdev_bridge_port_cfg_reset(struct br_info *br_item,
 						   .BridgePort_ConfigSet,
 						   gsw_handle, &brportcfg);
 				if (ret != GSW_statusOk) {
-					PR_ERR("Fail alloc/cfg br port %s\n",
-					       __func__);
+					PR_ERR("Fail alloc/cfg br port\n");
 					return -1;
 				}
 			}
@@ -286,3 +284,79 @@ int dp_swdev_free_brcfg(int inst, u16 fid)
 	DP_DEBUG(DP_DBG_FLAG_SWDEV, "FID(%d) freed for inst:%d\n", fid, inst);
 	return 0;
 }
+
+int dp_gswip_ext_vlan(int inst, int vap, int ep)
+{
+	struct core_ops *gsw_handle;
+	struct ext_vlan_info *vlan;
+	struct vlan_prop vlan_prop = {0};
+	struct pmac_port_info *port;
+	struct logic_dev *tmp = NULL;
+	int flag = 0, ret, i = 0;
+	int v1 = 0, v2 = 0;
+
+	gsw_handle = dp_port_prop[inst].ops[0];
+	port = &dp_port_info[inst][ep];
+	vlan = kzalloc(sizeof(*vlan), GFP_KERNEL);
+	if (!vlan) {
+		PR_ERR("failed to alloc ext_vlan of %d bytes\n", sizeof(*vlan));
+		return 0; //Need to return -1 or ??
+	}
+	vlan->vlan2_list = kzalloc(sizeof(*vlan->vlan2_list), GFP_KERNEL);
+	vlan->vlan1_list = kzalloc(sizeof(*vlan->vlan1_list), GFP_KERNEL);
+	list_for_each_entry(tmp, &dp_port_info[inst][ep].
+			    subif_info[vap].logic_dev, list) {
+		DP_DEBUG(DP_DBG_FLAG_SWDEV, "tmp dev name:%s\n",
+			 tmp->dev ? tmp->dev->name : "NULL");
+		get_vlan_via_dev(tmp->dev, &vlan_prop);
+		if (vlan_prop.num == 2) {
+			DP_DEBUG(DP_DBG_FLAG_SWDEV,
+				 "VLAN Inner proto=%x, vid=%d\n",
+				 vlan_prop.in_proto, vlan_prop.in_vid);
+			DP_DEBUG(DP_DBG_FLAG_SWDEV,
+				 "VLAN out proto=%x, vid=%d\n",
+				 vlan_prop.out_proto, vlan_prop.out_vid);
+			vlan->vlan2_list[v2].outer_vlan.vid = vlan_prop.out_vid;
+			vlan->vlan2_list[v2].outer_vlan.tpid =
+							vlan_prop.out_proto;
+			vlan->vlan2_list[v2].ether_type = 0;
+			vlan->vlan2_list[v2].inner_vlan.vid = vlan_prop.in_vid;
+			vlan->vlan2_list[v2].inner_vlan.tpid =
+							vlan_prop.in_proto;
+			vlan->vlan2_list[v2].bp = tmp->bp;
+			v2 += 1;
+		} else if (vlan_prop.num == 1) {
+			DP_DEBUG(DP_DBG_FLAG_SWDEV,
+				 "outer VLAN proto=%x, vid=%d\n",
+				 vlan_prop.out_proto, vlan_prop.out_vid);
+			vlan->vlan1_list[v1].outer_vlan.vid = vlan_prop.out_vid;
+			vlan->vlan1_list[v1].outer_vlan.tpid =
+							vlan_prop.out_proto;
+			vlan->vlan1_list[v1].bp = tmp->bp;
+			v1 += 1;
+		}
+		i += 1;
+	}
+	DP_DEBUG(DP_DBG_FLAG_SWDEV, "vlan1=%d vlan2=%d total vlan int=%d\n",
+		 v1, v2, i);
+	vlan->n_vlan1 = v1;
+	vlan->n_vlan2 = v2;
+	vlan->bp = port->subif_info[vap].bp;
+	vlan->logic_port = port->port_id;
+	vlan->subif_grp = port->subif_info[vap].subif;/*subif value*/
+
+	if (port->subif_info[vap].swdev_priv)
+		vlan->priv = port->subif_info[vap].swdev_priv;
+	else
+		vlan->priv = NULL;
+	ret = set_gswip_ext_vlan(gsw_handle, vlan, flag);
+	if (ret == 0)
+		port->subif_info[vap].swdev_priv = vlan->priv;
+	else
+		PR_ERR("set gswip ext vlan return error\n");
+	kfree(vlan->vlan1_list);
+	kfree(vlan->vlan2_list);
+	kfree(vlan);
+
+	return 0; /*return -EIO from GSWIP but later cannot fail swdev*/
+}
diff --git a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_switchdev.h b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_switchdev.h
index 9035270d72c70b161f6523d28388d6f330bc9b73..7072b241b5c5dc84a13150496fe26d344be6968b 100644
--- a/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_switchdev.h
+++ b/drivers/net/ethernet/lantiq/datapath/gswip31/datapath_switchdev.h
@@ -8,4 +8,5 @@ int dp_swdev_bridge_port_cfg_reset(struct br_info *br_item,
 				   int inst, int bport);
 int dp_swdev_bridge_cfg_set(int inst, u16 fid);
 int dp_swdev_free_brcfg(int inst, u16 fid);
+int dp_gswip_ext_vlan(int inst, int vap, int ep);
 #endif
diff --git a/drivers/net/ethernet/lantiq/ppv4/Kconfig b/drivers/net/ethernet/lantiq/ppv4/Kconfig
index e0877d495bba7c5cb3e05fd0071c8e9080e48bc0..ad99d326d1cf3e288d4e832fe7263b64c50a765c 100644
--- a/drivers/net/ethernet/lantiq/ppv4/Kconfig
+++ b/drivers/net/ethernet/lantiq/ppv4/Kconfig
@@ -10,3 +10,36 @@ config LTQ_PPV4
 	Turn on this option to enable BM and QOS driver which is a special hardware
 	present in the FALCONMX series of SoCs to manage the network buffers
 	in HW.
+
+# fallback if full driver is not included
+config LTQ_PPV4_QOS_SLIM
+	bool
+	depends on LTQ_PPV4 && !LTQ_PPV4_QOS
+	default y
+
+config LTQ_PPV4_QOS
+	tristate "QoS driver"
+	depends on LTQ_PPV4
+	---help---
+	  This is the driver for the PPv4 QoS hardware in Falcon Mountain.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called pp_qos_drv.
+
+config LTQ_PPV4_QOS_TEST
+	bool "Enable test code for QoS driver"
+	depends on LTQ_PPV4_QOS
+
+
+config LTQ_PPV4_BM_SLIM
+	bool
+	depends on LTQ_PPV4 && !LTQ_PPV4_BM
+	default y
+
+config LTQ_PPV4_BM
+	tristate "BM driver"
+	depends on LTQ_PPV4
+	---help---
+	  This is the driver for the PPv4 BM hardware in Falcon Mountain.
+	  To compile this driver as a module, choose M here. The module
+	  will be called pp_bm_drv.
diff --git a/drivers/net/ethernet/lantiq/ppv4/Makefile b/drivers/net/ethernet/lantiq/ppv4/Makefile
index c76330cdb85d513e50a835bf34201bac91deffa6..54a712a5f072ec4a5c01a52e696651e47032037f 100644
--- a/drivers/net/ethernet/lantiq/ppv4/Makefile
+++ b/drivers/net/ethernet/lantiq/ppv4/Makefile
@@ -1,6 +1,13 @@
 #
-# Makefile for BM driver.
+# Makefile for BM and QoS drivers.
 #
 
-obj-$(CONFIG_LTQ_PPV4) +=  bm_drv_slim.o qos_drv_slim.o
+# initial small drivers
+#obj-$(CONFIG_LTQ_PPV4) += bm_drv_slim.o
+obj-$(CONFIG_LTQ_PPV4_BM_SLIM) += bm_drv_slim.o
+obj-$(CONFIG_LTQ_PPV4_QOS_SLIM) += qos_drv_slim.o
 
+# full drivers
+obj-$(CONFIG_LTQ_PPV4_QOS) += qos/
+#obj-$(CONFIG_LTQ_PPV4) += bm/
+obj-$(CONFIG_LTQ_PPV4_BM) += bm/
diff --git a/drivers/net/ethernet/lantiq/ppv4/bm/Makefile b/drivers/net/ethernet/lantiq/ppv4/bm/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..87cd75f19981b7ef335ea9983984bbb033f481e7
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/bm/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for PPv4 BM driver.
+#
+
+obj-$(CONFIG_LTQ_PPV4) += ppv4_bm.o
+ppv4_bm-y 	:= pp_bm_drv.o pp_bm_debugfs.o
+#ccflags-y	+= -Iinclude/net -DNO_FW -DPP_QOS_DISABLE_CMDQ
+ccflags-y	+= -Iinclude/net -DQOS_CPU_UC_SAME_ENDIANESS
+
+#ccflags-$(CONFIG_LTQ_PPV4_QOS_TEST) += -DPP_QOS_TEST
diff --git a/drivers/net/ethernet/lantiq/ppv4/bm/pp_bm_debugfs.c b/drivers/net/ethernet/lantiq/ppv4/bm/pp_bm_debugfs.c
new file mode 100644
index 0000000000000000000000000000000000000000..0f4b7570d6ede92ca1ce766fb75bc30d2f595683
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/bm/pp_bm_debugfs.c
@@ -0,0 +1,316 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include "pp_bm_drv_internal.h"
+
+#define PP_BM_DEBUGFS_DIR "ppv4_bm"
+
+//!< debugfs dir
+static struct dentry *bm_dir;
+
+ssize_t bm_commmads_read(void *data, u64 *val)
+{
+	pr_info("commands:\n");
+
+	pr_info("1. Init buffer manager\n");
+	pr_info("2. Allocate default buffer\n");
+	pr_info("3. De-Allocate default buffer\n");
+	pr_info("4. Print DB counters\n");
+	pr_info("5. Print HW counters\n");
+
+	return 0;
+}
+
+void dump_db(struct bmgr_driver_private *pdata)
+{
+	u8	idx;
+	u8	idx2;
+	u32 num = 0;
+	u32 pool_id = 0;
+	u32 max_allowed = 0;
+	struct bmgr_policy_db_entry *policy;
+	struct bmgr_pool_db_entry *pool;
+	struct bmgr_group_db_entry	*group;
+	struct bmgr_pool_in_policy_info *pool_in_policy;
+
+	pr_info("=================================\n");
+	pr_info("====== BUFFER MANAGER DUMP ======\n");
+	pr_info("=================================\n");
+
+	// Dump all DB general counters
+	pr_info("======= GENERAL COUNTERS ========\n");
+	pr_info("Number of active pools:    %d\n",
+		pdata->driver_db.num_pools);
+	pr_info("Number of active groups:   %d\n",
+		pdata->driver_db.num_groups);
+	pr_info("Number of active policies: %d\n",
+		pdata->driver_db.num_policies);
+
+	// Dump all pools
+	pr_info("============= POOLS =============\n");
+	for (idx = 0; idx < PP_BMGR_MAX_POOLS; idx++) {
+		pool = &pdata->driver_db.pools[idx];
+
+		if (!pool->is_busy)
+			continue;
+
+		pr_info("Active pool %d:\n", idx);
+		pr_info("\t\tNum allocated buffers: %d\n",
+			pool->num_allocated_buffers);
+		pr_info("\t\tNum deallocated buffers: %d\n",
+			pool->num_deallocated_buffers);
+		pr_info("\t\tInternal table address: %x\n",
+			(phys_addr_t)pool->internal_pointers_tables);
+		pr_info("\t\tNum buffers: %d\n",
+			pool->pool_params.num_buffers);
+		pr_info("\t\tSize of buffer: %d\n",
+			pool->pool_params.size_of_buffer);
+		pr_info("\t\tGroup id: %d\n",
+			pool->pool_params.group_id);
+		pr_info("\t\tBase address low: 0x%x\n",
+			pool->pool_params.base_addr_low);
+		pr_info("\t\tBase address high: 0x%x\n",
+			pool->pool_params.base_addr_high);
+		pr_info("\t\tFlags: %d\n",
+			pool->pool_params.flags);
+	}
+
+	// Dump all groups
+	pr_info("============= GROUPS ============\n");
+	for (idx = 0; idx < PP_BMGR_MAX_GROUPS; idx++) {
+		group = &pdata->driver_db.groups[idx];
+
+		if (group->num_pools_in_group) {
+			pr_info("Active group %d:\n", idx);
+			pr_info("\t\tAvailable buffers: %d\n",
+				group->available_buffers);
+			pr_info("\t\tReserved buffers: %d\n",
+				group->reserved_buffers);
+			pr_info("\t\tPools in group:");
+			num = group->num_pools_in_group;
+			for (idx2 = 0; idx2 < num; idx2++) {
+				if (group->pools[idx2])
+					pr_info(" %d", idx2);
+			}
+			pr_info("\n");
+		}
+	}
+
+	// Dump all policies
+	pr_info("============= POLICIES ==========\n");
+	for (idx = 0; idx < PP_BMGR_MAX_POLICIES; idx++) {
+		policy = &pdata->driver_db.policies[idx];
+
+		if (!policy->is_busy)
+			continue;
+
+		pr_info("Active policy %d:\n", idx);
+		pr_info("\t\tNum allocated buffers: %d\n",
+			policy->num_allocated_buffers);
+		pr_info("\t\tNum deallocated buffers: %d\n",
+			policy->num_deallocated_buffers);
+		pr_info("\t\tMax allowed: %d\n",
+			policy->policy_params.max_allowed);
+		pr_info("\t\tMin guaranteed: %d\n",
+			policy->policy_params.min_guaranteed);
+		pr_info("\t\tGroup id: %d\n",
+			policy->policy_params.group_id);
+		pr_info("\t\tFlags: %d\n",
+			policy->policy_params.flags);
+		pr_info("\t\tPools in policy:");
+		num = policy->policy_params.num_pools_in_policy;
+		for (idx2 = 0; idx2 < num; idx2++) {
+			pool_in_policy =
+				&policy->policy_params.pools_in_policy[idx2];
+			pool_id = pool_in_policy->pool_id;
+			max_allowed = pool_in_policy->max_allowed;
+
+			pr_info("\t\t\t%d. id %d, max allowed %d\n",
+				idx2, pool_id, max_allowed);
+		}
+	}
+
+	pr_info("=================================\n");
+	pr_info("========== END OF DUMP ==========\n");
+	pr_info("=================================\n");
+}
+
+static struct bmgr_buff_info buff_info;
+
+ssize_t bm_commmads_write(void *data, u64 val)
+{
+	struct platform_device *pdev;
+	struct bmgr_driver_private *pdata;
+
+	pdev = data;
+	pdata = platform_get_drvdata(pdev);
+
+	dev_info(&pdev->dev, "command: %llu", val);
+
+	switch (val) {
+	case 1:
+		test_init_bmgr(&pdev->dev);
+		break;
+	case 2:
+		memset(&buff_info, 0x0, sizeof(buff_info));
+
+		bmgr_pop_buffer(&buff_info);
+
+		pr_info("pop buffer address 0x%x (high 0x%x) from policy %d pool %d\n",
+			buff_info.addr_low[0], buff_info.addr_high[0],
+			buff_info.policy_id, buff_info.pool_id[0]);
+		break;
+	case 3:
+		bmgr_push_buffer(&buff_info);
+
+		pr_info("push buffer address 0x%x (high 0x%x) from policy %d pool %d\n",
+			buff_info.addr_low[0], buff_info.addr_high[0],
+			buff_info.policy_id, buff_info.pool_id[0]);
+		break;
+	case 4:
+		dump_db(pdata);
+		break;
+	case 5:
+		print_hw_stats(0, 0, 0);
+		break;
+	default:
+		pr_info("unknown command\n");
+		break;
+	}
+
+	return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(bm_commmads_fops,
+			 bm_commmads_read,
+			 bm_commmads_write,
+			 "%llu\n");
+
+int bm_dbg_dev_init(struct platform_device *pdev)
+{
+	struct bmgr_driver_private *pdata;
+	struct dentry *dent;
+	int err;
+
+	if (!pdev) {
+		dev_err(&pdev->dev, "Invalid platform device\n");
+		return -ENODEV;
+	}
+
+	pdata = platform_get_drvdata(pdev);
+	if (!pdata) {
+		dev_err(&pdev->dev, "Invalid platform device data\n");
+		return -ENODEV;
+	}
+
+	pdata->debugfs_info.dir = bm_dir;
+
+	dent = debugfs_create_u32("reg_bar_offset", 0644,
+				  pdata->debugfs_info.dir,
+				  &pdata->debugfs_info.virt2phyoff);
+	if (IS_ERR_OR_NULL(dent)) {
+		err = (int)PTR_ERR(dent);
+		dev_err(&pdev->dev,
+			"debugfs_create_u32 failed creating reg_bar_offset with %d\n",
+			err);
+		return err;
+	}
+
+	dent = debugfs_create_u32("ddr_bar_offset", 0644,
+				  pdata->debugfs_info.dir,
+				  &pdata->debugfs_info.ddrvirt2phyoff);
+	if (IS_ERR_OR_NULL(dent)) {
+		err = (int)PTR_ERR(dent);
+		dev_err(&pdev->dev,
+			"debugfs_create_u32 failed creating ddr_bar_offset with %d\n",
+			err);
+		return err;
+	}
+
+	dent = debugfs_create_u32("fpga_bar_offset", 0644,
+				  pdata->debugfs_info.dir,
+				  &pdata->debugfs_info.fpga_offset);
+	if (IS_ERR_OR_NULL(dent)) {
+		err = (int)PTR_ERR(dent);
+		dev_err(&pdev->dev,
+			"debugfs_create_u32 failed creating fpga_offset with %d\n",
+			err);
+		return err;
+	}
+
+	dent = debugfs_create_file("commands",
+				   0644,
+				   pdata->debugfs_info.dir,
+				pdev,
+				&bm_commmads_fops);
+	if (IS_ERR_OR_NULL(dent)) {
+		err = (int)PTR_ERR(dent);
+		dev_err(&pdev->dev,
+			"debugfs_create_file failed creating commands with %d\n",
+			err);
+		return err;
+	}
+
+	return 0;
+}
+
+void bm_dbg_dev_clean(struct platform_device *pdev)
+{
+//	struct bmgr_driver_private *pdata;
+
+//	if (pdev) {
+//		pdata = platform_get_drvdata(pdev);
+//		if (pdata)
+//			debugfs_remove_recursive(pdata->dbg_info.dir);
+//	}
+}
+
+int bm_dbg_module_init(void)
+{
+	int rc;
+	struct dentry *dir;
+
+	dir = debugfs_create_dir(PP_BM_DEBUGFS_DIR, NULL);
+	if (IS_ERR_OR_NULL(dir)) {
+		rc = (int)PTR_ERR(dir);
+		pr_err("debugfs_create_dir failed with %d\n", rc);
+		return rc;
+	}
+
+	bm_dir = dir;
+
+	return 0;
+}
+
+void bm_dbg_module_clean(void)
+{
+	debugfs_remove_recursive(bm_dir); // NULL check occurs internally
+}
diff --git a/drivers/net/ethernet/lantiq/ppv4/bm/pp_bm_drv.c b/drivers/net/ethernet/lantiq/ppv4/bm/pp_bm_drv.c
new file mode 100644
index 0000000000000000000000000000000000000000..090cee508d37000617cc89df8001817ce05d9a25
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/bm/pp_bm_drv.c
@@ -0,0 +1,2086 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+
+//#define _FPGA_
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/dma-mapping.h>
+
+#include "pp_bm_drv.h"
+#include "pp_bm_drv_internal.h"
+#include "pp_bm_regs.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_AUTHOR("obakshe");
+MODULE_DESCRIPTION("Intel(R) PPv4 buffer_manager Driver");
+MODULE_VERSION(BMGR_DRIVER_VERSION);
+
+////////////////////
+//// PROTOTYPES ////
+////////////////////
+
+// Static function only. External function are declared in the h file
+static int buffer_manager_probe(struct platform_device *pdev);
+static int buffer_manager_remove(struct platform_device *pdev);
+
+//////////////////////////
+//// Global variables ////
+//////////////////////////
+
+#define RC_SUCCESS	(0)
+
+static const struct of_device_id bm_match[] = {
+	{ .compatible = "intel,falconmx-bm" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bm_match);
+
+//!< Platform driver
+static struct platform_driver	g_bm_platform_driver = {
+	.driver = { .name = "buffer_manager", .of_match_table = bm_match, },
+	.probe = buffer_manager_probe,
+	.remove = buffer_manager_remove,
+};
+
+//!< global pointer for private database
+#ifdef _FPGA_
+	static struct bmgr_driver_private	real_driver_private;
+	static struct bmgr_driver_private	*this = &real_driver_private;
+#else
+	static struct bmgr_driver_private	*this;
+#endif
+
+void __iomem	*bm_config_addr_base;
+void __iomem	*bm_policy_mngr_addr_base;
+
+#define BM_BASE		(bm_config_addr_base)		// (0x18B00000)
+#define BM_RAM_BASE	(bm_policy_mngr_addr_base)	// (0x18B10000)
+
+#define IO_VIRT(phy_addr)	((phy_addr) + this->debugfs_info.virt2phyoff)
+#define DDR_VIRT(phy_addr)	((phy_addr) + this->debugfs_info.ddrvirt2phyoff)
+
+//#define RD_DDR32(addr)	(*(volatile u32 *)(DDR_VIRT(addr)))
+#define WR_DDR32(addr, var)	((*(volatile u32 *)(DDR_VIRT(addr))) = var)
+
+#define RD_REG_32(addr)	__raw_readl((volatile u32 *)addr)
+#define WR_REG_32(addr, val)	__raw_writel(val, (volatile u32 *)addr)
+//#define WR_REG_32(addr, var)	((*(volatile u32 *)(IO_VIRT(addr))) = var)
+//#define RD_REG_32(addr)	(*(volatile u32 *)(IO_VIRT(addr)))
+
+//////////////
+//// APIs ////
+//////////////
+
+/**************************************************************************
+ *! \fn	bmgr_db_lock
+ **************************************************************************
+ *
+ *  \brief	This function locks the DB in a recursion-save manner
+ *
+ *  \return	void
+ *
+ **************************************************************************/
+static inline void bmgr_db_lock(void)
+{
+	spin_lock_bh(&this->driver_db.db_lock);
+}
+
+/**************************************************************************
+ *! \fn	bmgr_db_unlock
+ **************************************************************************
+ *
+ *  \brief	This function unlocks the DB in a recursion-save manner
+ *
+ *  \return	void
+ *
+ **************************************************************************/
+static inline void bmgr_db_unlock(void)
+{
+	spin_unlock_bh(&this->driver_db.db_lock);
+}
+
+/**************************************************************************
+ *! \fn	buffer_manager_db_init
+ **************************************************************************
+ *
+ *  \brief	Initialize the DB
+ *
+ *  \param	priv:	buffer_manager private data pointer
+ *
+ *  \return	0 on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 buffer_manager_db_init(struct bmgr_driver_private *priv)
+{
+	struct bmgr_driver_db	*db = &priv->driver_db;
+
+	if (!db) {
+		pr_err("buffer_manager_db_init(): db was not initialized successfuly!\n");
+		return -EINVAL;
+	}
+
+	memset(db, 0, sizeof(struct bmgr_driver_db));
+
+	spin_lock_init(&db->db_lock);
+
+	pr_info("buffer_manager_db_init(): db was initialized successfuly\n");
+
+	return 0;
+}
+
+/**************************************************************************
+ *! \fn	buffer_manager_probe
+ **************************************************************************
+ *
+ *  \brief	probe platform device hook
+ *
+ *  \param	pdev:	platform device pointer
+ *
+ *  \return	0 on success, other error code on failure
+ *
+ **************************************************************************/
+static int buffer_manager_probe(struct platform_device *pdev)
+{
+	int							ret;
+	struct bmgr_driver_private	*priv;
+	struct resource				*res[2];
+	int							i;
+
+#ifdef _FPGA_
+	priv = this;
+#else
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+#endif
+
+	platform_set_drvdata(pdev, priv);
+	priv->pdev = pdev;
+	priv->enabled = true;
+	this = priv;
+
+	ret = buffer_manager_db_init(priv);
+	if (ret) {
+		kfree(priv);
+		return -ENOMEM;
+	}
+
+	/* load the memory ranges */
+	for (i = 0; i < 2; i++) {
+		res[i] = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res[i]) {
+			pr_err("failed to get resources %d\n", i);
+			return -ENOENT;
+		}
+	}
+
+	bm_config_addr_base = devm_ioremap_resource(&pdev->dev, res[0]);
+	bm_policy_mngr_addr_base = devm_ioremap_resource(&pdev->dev, res[1]);
+
+	if (!bm_config_addr_base || !bm_policy_mngr_addr_base) {
+		pr_err("failed to request and remap io ranges\n");
+		return -ENOMEM;
+	}
+
+	bm_dbg_dev_init(pdev);
+
+	return 0;
+}
+
+/**************************************************************************
+ *! \fn	buffer_manager_remove
+ **************************************************************************
+ *
+ *  \brief	probe platform device hook
+ *
+ *  \param	pdev:	platform device pointer
+ *
+ *  \return	0 on success, other error code on failure
+ *
+ **************************************************************************/
+static int buffer_manager_remove(struct platform_device *pdev)
+{
+	struct bmgr_driver_private	*priv = platform_get_drvdata(pdev);
+
+	priv->enabled = 0;
+
+	kfree(priv);
+
+	platform_set_drvdata(pdev, NULL);
+	this = NULL;
+
+	bm_dbg_dev_clean(pdev);
+
+	pr_info("buffer_manager_remove(): remove done\n");
+
+	return 0;
+}
+
+/**************************************************************************
+ *! \fn	buffer_manager_driver_init
+ **************************************************************************
+ *
+ *  \brief	Init platform device driver
+ *
+ *  \return	0 on success, other error code on failure
+ *
+ **************************************************************************/
+static int __init buffer_manager_driver_init(void)
+{
+	int ret;
+
+	bm_dbg_module_init();
+
+	ret = platform_driver_register(&g_bm_platform_driver);
+	if (ret < 0) {
+		pr_err("platform_driver_register failed (%d)\n", ret);
+		return ret;
+	}
+
+	pr_info("buffer manager driver init done\n");
+
+	return 0;
+}
+
+/**************************************************************************
+ *! \fn	buffer_manager_driver_exit
+ **************************************************************************
+ *
+ *  \brief	Exit platform device driver
+ *
+ *  \return	0 on success, other error code on failure
+ *
+ **************************************************************************/
+static void __exit buffer_manager_driver_exit(void)
+{
+	platform_driver_unregister(&g_bm_platform_driver);
+
+	bm_dbg_module_clean();
+
+	pr_info("buffer manager driver exit done\n");
+}
+
+/*************************************************/
+/**		Module Declarations		**/
+/*************************************************/
+//module_init(buffer_manager_driver_init);
+arch_initcall(buffer_manager_driver_init);
+module_exit(buffer_manager_driver_exit);
+
+void copy_dma(u32 src, u32 dst, u32 flags)
+{
+	u32	BASE_PXP_QOS_IP_ADDRESS = 0; //0x18800000;
+	u32 MCDMA0_BASE_ADDR = BASE_PXP_QOS_IP_ADDRESS + 0x50000;
+	u32 MCDMA_SRC_OFFSET = 0;
+	u32 MCDMA_DST_OFFSET = 0x4;
+	u32 MCDMA_CONTROL_OFFSET = 0x8;
+	u32 mcdma_channel = 3;
+	u32 active_bit = (1 << 30);
+	u32 pxp_offset = 0;
+	struct timespec start_ts;
+	struct timespec end_ts;
+	u32 DMA0_SRC_ADDR = MCDMA0_BASE_ADDR +
+		MCDMA_SRC_OFFSET + 0x40 * mcdma_channel;
+	u32 DMA0_DST_ADDR = MCDMA0_BASE_ADDR +
+		MCDMA_DST_OFFSET + 0x40 * mcdma_channel;
+	u32 DMA0_CTRL_ADDR = MCDMA0_BASE_ADDR +
+		MCDMA_CONTROL_OFFSET + 0x40 * mcdma_channel;
+
+	WR_REG_32(DMA0_SRC_ADDR, src - pxp_offset); //source address
+	WR_REG_32(DMA0_DST_ADDR, dst - pxp_offset); //destination address
+	pr_info("Copying from ADDR 0x%x to ADDR 0x%x\n",
+		src - pxp_offset, dst - pxp_offset);
+	// 8 bytes burst, total size is 8 byte which is 64 bits
+	WR_REG_32(DMA0_CTRL_ADDR, flags);
+	pr_info("SLEEP\n");
+	msleep(100);
+
+	getnstimeofday(&start_ts);
+
+	// wait for Active bit 30 will be 0
+	while ((RD_REG_32(DMA0_CTRL_ADDR) & active_bit) != 0) {
+		getnstimeofday(&end_ts);
+		if ((timespec_sub(end_ts, start_ts).tv_sec) > 5) {
+			pr_err("!!!!!!! DMA TIMEOUT !!!!!!!\n");
+			return;
+		}
+	}
+
+	msleep(100);
+	pr_info("Copying DONE (control 0x%x)\n", RD_REG_32(DMA0_CTRL_ADDR));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_wait_for_init_completion
+ **************************************************************************
+ *
+ *  \brief	This function reads the init bit and waits for completion
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_wait_for_init_completion(void)
+{
+	u32	st;
+	struct timespec start_ts;
+	struct timespec end_ts;
+
+	pr_info("Waiting for operation complete....");
+
+	getnstimeofday(&start_ts);
+
+	do {
+		getnstimeofday(&end_ts);
+		if ((timespec_sub(end_ts, start_ts).tv_sec) > 5) {
+			pr_err("!!!!!!! WAIT COMPLETETION TIMEOUT !!!!!!!\n");
+			return -EINVAL;
+		}
+		st = (RD_REG_32(BMGR_STATUS_REG_ADDR(BM_BASE)) & (1));
+	} while (st);
+
+	pr_info("Done\n");
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_is_pool_params_valid
+ **************************************************************************
+ *
+ *  \brief	Check wheather pool parameters are valid
+ *
+ *  \param	pool_params:	Pool param from user
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_is_pool_params_valid(
+		const struct bmgr_pool_params * const pool_params)
+{
+	// Validity check
+	if (!pool_params) {
+		pr_err("bmgr_is_pool_params_valid: pool_params is NULL\n");
+		return -EINVAL;
+	}
+
+	if (pool_params->size_of_buffer < BMGR_MIN_POOL_BUFFER_SIZE) {
+		pr_err("bmgr_is_pool_params_valid: size_of_buffer %d should be smaller than %d\n",
+		       pool_params->size_of_buffer,
+		       BMGR_MIN_POOL_BUFFER_SIZE);
+		return -EINVAL;
+	}
+
+	if (pool_params->size_of_buffer % BMGR_MIN_POOL_BUFFER_SIZE) {
+		pr_err("bmgr_is_pool_params_valid: size_of_buffer %d must be aligned to %d bytes\n",
+		       pool_params->size_of_buffer,
+		       BMGR_MIN_POOL_BUFFER_SIZE);
+		return -EINVAL;
+	}
+
+	if (pool_params->base_addr_low & 0x3F) {
+		pr_err("bmgr_is_pool_params_valid: base_addr_low %d must be aligned to %d bytes\n",
+		       pool_params->base_addr_low,
+		       BMGR_MIN_POOL_BUFFER_SIZE);
+		return -EINVAL;
+	}
+
+	// Num_buffers can be up to 2^24
+	if (pool_params->num_buffers >= 0x1000000) {
+		pr_err("Number of buffers can be up to 0x1000000\n");
+		return -EINVAL;
+	}
+
+	if (pool_params->group_id >= PP_BMGR_MAX_GROUPS) {
+		pr_err("bmgr_is_pool_params_valid: group_id %d must be smaller than %d\n",
+		       pool_params->group_id, PP_BMGR_MAX_GROUPS);
+		return -EINVAL;
+	}
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_is_policy_params_valid
+ **************************************************************************
+ *
+ *  \brief	Check wheather policy parameters are valid
+ *
+ *  \param	policy_params:	Policy param from user
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_is_policy_params_valid(
+		const struct bmgr_policy_params * const policy_params)
+{
+	if (!policy_params) {
+		pr_err("bmgr_is_policy_params_valid: policy_params is NULL\n");
+		return -EINVAL;
+	}
+
+	if (policy_params->group_id >= PP_BMGR_MAX_GROUPS) {
+		pr_err("group_id %d >= %d\n",
+		       policy_params->group_id, PP_BMGR_MAX_GROUPS);
+		return -EINVAL;
+	}
+
+	if (policy_params->num_pools_in_policy > PP_BMGR_MAX_POOLS_IN_POLICY) {
+		pr_err("num_pools_in_policy %d should be up to %d\n",
+		       policy_params->num_pools_in_policy,
+		       PP_BMGR_MAX_POOLS_IN_POLICY);
+		return -EINVAL;
+	}
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_buffer_manager_control
+ **************************************************************************
+ *
+ *  \brief	Sets the control register
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_buffer_manager_control(void)
+{
+	// Buffer manager client enable
+	WR_REG_32(BMGR_CTRL_REG_ADDR(BM_BASE), 0x1);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_enable_min_guarantee_per_pool
+ **************************************************************************
+ *
+ *  \brief	Enables/Disables minimum guarantee per pool
+ *
+ *  \param	pool_id:	Pool ID
+ *  \param	enable:		True to enable, false to disable
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_enable_min_guarantee_per_pool(u8 pool_id, u8 enable)
+{
+	u32	value;
+	u32	mask;
+
+	// Validity check
+	if (pool_id >= PP_BMGR_MAX_POOLS) {
+		pr_err("pool_id %d out of range %d\n",
+		       pool_id, PP_BMGR_MAX_POOLS);
+		return -EINVAL;
+	}
+
+	// Read value
+	value = RD_REG_32(BMGR_POOL_MIN_GRNT_MASK_REG_ADDR(BM_BASE));
+	mask = BIT(pool_id);
+
+	if (enable) {
+		value |= mask;
+	} else {
+		mask = ~mask;
+		value &= mask;
+	}
+
+	WR_REG_32(BMGR_POOL_MIN_GRNT_MASK_REG_ADDR(BM_BASE), value);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_pool_enable
+ **************************************************************************
+ *
+ *  \brief	Enable pool
+ *
+ *  \param	pool_id:	Pool ID
+ *  \param	enable:		True to enable, false to disable
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_pool_enable(u8 pool_id, bool enable)
+{
+	u32	value;
+	u32	mask;
+
+	// Validity check
+	if (pool_id >= PP_BMGR_MAX_POOLS) {
+		pr_err("pool_id %d out of range %d\n",
+		       pool_id, PP_BMGR_MAX_POOLS);
+		return -EINVAL;
+	}
+
+	// Read value
+	value = RD_REG_32(BMGR_POOL_ENABLE_REG_ADDR(BM_BASE));
+	mask = (BIT(pool_id) << 16) | BIT(pool_id);
+
+	if (enable) {
+		// Pool Enable
+		value |= mask;
+	} else {
+		// Pool disable
+		mask = ~mask;
+		value &= mask;
+	}
+
+	WR_REG_32(BMGR_POOL_ENABLE_REG_ADDR(BM_BASE), value);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_pool_reset_fifo
+ **************************************************************************
+ *
+ *  \brief	Resets the pool fifo
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_pool_reset_fifo(u8 pool_id)
+{
+	u32	reset_reg;
+
+	// Validity check
+	if (pool_id >= PP_BMGR_MAX_POOLS) {
+		pr_err("pool_id %d out of range %d\n",
+		       pool_id, PP_BMGR_MAX_POOLS);
+		return -EINVAL;
+	}
+
+	reset_reg = RD_REG_32(BMGR_POOL_FIFO_RESET_REG_ADDR(BM_BASE));
+
+	// Set the reset bit to 0
+	reset_reg &= ~BIT(pool_id);
+
+	// Pool FIFO Reset
+	WR_REG_32(BMGR_POOL_FIFO_RESET_REG_ADDR(BM_BASE), reset_reg);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_configure_ocp_master
+ **************************************************************************
+ *
+ *  \brief	Configures the burst size and number of bursts
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_configure_ocp_master(void)
+{
+	// OCP Master burst size
+	// 64B burst for all pools
+	WR_REG_32(BMGR_OCPM_BURST_SIZE_REG_ADDR(BM_BASE), 0);
+
+	// OCP Master number of bursts
+	// 1 burst for all pools
+	WR_REG_32(BMGR_OCPM_NUM_OF_BURSTS_REG_ADDR(BM_BASE), 0);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_ocp_burst_size
+ **************************************************************************
+ *
+ *  \brief	Gets burst size
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static u32 bmgr_get_ocp_burst_size(void)
+{
+	return RD_REG_32(BMGR_OCPM_BURST_SIZE_REG_ADDR(BM_BASE));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_pool_size
+ **************************************************************************
+ *
+ *  \brief	Sets pool size
+ *
+ *  \param	pool_id:	Pool ID
+ *  \param	num_buffers:	Number of buffers in pool
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_pool_size(u8 pool_id, u32 num_buffers)
+{
+	u32	burst_size = 0;
+	u32	reg = 0;
+	u32	mask = 3 << (2 * pool_id);
+
+	if (num_buffers > 128) {
+		burst_size = 3; // 512B
+	} else if (num_buffers > 64) {
+		burst_size = 2; // 256B
+	} else if (num_buffers > 32) {
+		burst_size = 1; // 128B
+	} else if (num_buffers > 16)	{
+		burst_size = 0; // 64B
+	} else {
+		pr_err("bmgr_set_pool_size(): minimum valid num_buffers (%d) is 16\n",
+		       num_buffers);
+		return -EINVAL;
+	}
+
+	// num buffer X pointer size must be
+	// multiplier of the burst size in bytes
+	if ((num_buffers % (1 << (4 + burst_size))) != 0) {
+		pr_err("bmgr_set_pool_size(): num_buffers %d must be multiplier of %d\n",
+		       num_buffers, 1 << (4 + burst_size));
+		return -EINVAL;
+	}
+
+	reg = RD_REG_32(BMGR_OCPM_BURST_SIZE_REG_ADDR(BM_BASE));
+	burst_size <<= (2 * pool_id);
+
+	reg &= ~(mask);
+	reg |= burst_size;
+
+	// OCP Master burst size
+	WR_REG_32(BMGR_OCPM_BURST_SIZE_REG_ADDR(BM_BASE), reg);
+
+	// Sets number of buffers in pools
+	WR_REG_32(BMGR_POOL_SIZE_REG_ADDR(BM_BASE, pool_id), num_buffers);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_pool_size
+ **************************************************************************
+ *
+ *  \brief	Returns the number of buffers in pool
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	Number of buffers in pool
+ *
+ **************************************************************************/
+static u32 bmgr_get_pool_size(u8 pool_id)
+{
+	return RD_REG_32(BMGR_POOL_SIZE_REG_ADDR(BM_BASE, pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_group_available_buffers
+ **************************************************************************
+ *
+ *  \brief  Sets the available buffers in group.
+ *          This is used to for better HW performance
+ *
+ *  \param	group_id:		Group ID
+ *  \param	available_buffers:	Available buffres in group
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_group_available_buffers(u8 group_id,
+					    u32 available_buffers)
+{
+	WR_REG_32(BMGR_GROUP_AVAILABLE_BUFF_REG_ADDR(BM_BASE, group_id),
+		  available_buffers);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_group_available_buffers
+ **************************************************************************
+ *
+ *  \brief	Returns the available buffers in group
+ *
+ *  \param	group_id:	Group ID
+ *
+ *  \return	Available buffers in group
+ *
+ **************************************************************************/
+static u32 bmgr_get_group_available_buffers(u8 group_id)
+{
+	return RD_REG_32(BMGR_GROUP_AVAILABLE_BUFF_REG_ADDR(BM_BASE,
+			 group_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_group_reserved_buffers
+ **************************************************************************
+ *
+ *  \brief	Sets the number of reserved buffers in group
+ *
+ *  \param	group_id:		Group ID
+ *  \param	reserved_buffers:	reserved buffers in group
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_group_reserved_buffers(u8 group_id, u32 reserved_buffers)
+{
+	WR_REG_32(BMGR_GROUP_RESERVED_BUFF_REG_ADDR(BM_BASE, group_id),
+		  reserved_buffers);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_group_reserved_buffers
+ **************************************************************************
+ *
+ *  \brief	Returns the number of reserved buffers in group
+ *
+ *  \param	group_id:	Group ID
+ *
+ *  \return	Number of reserved buffers in group
+ *
+ **************************************************************************/
+static u32 bmgr_get_group_reserved_buffers(u8 group_id)
+{
+	return RD_REG_32(BMGR_GROUP_RESERVED_BUFF_REG_ADDR(BM_BASE,
+			 group_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_pcu_fifo_base_address
+ **************************************************************************
+ *
+ *  \brief	Sets the pcu fifo base address (In SRAM)
+ *
+ *  \param	pool_id:	Pool ID
+ *  \param	base_address:	PCU Fifo base address
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_pcu_fifo_base_address(u8 pool_id, u32 base_address)
+{
+	WR_REG_32(BMGR_POOL_PCU_FIFO_BASE_ADDR_REG_ADDR(BM_BASE, pool_id),
+		  base_address);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_pcu_fifo_base_address
+ **************************************************************************
+ *
+ *  \brief	Returns the pcu fifo base address (In SRAM)
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	PCU Fifo base address
+ *
+ **************************************************************************/
+static u32 bmgr_get_pcu_fifo_base_address(u8 pool_id)
+{
+	return RD_REG_32(BMGR_POOL_PCU_FIFO_BASE_ADDR_REG_ADDR(BM_BASE,
+			 pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_pcu_fifo_size
+ **************************************************************************
+ *
+ *  \brief	Sets the PCU fifo size
+ *
+ *  \param	pool_id:	Pool ID
+ *  \param	fifo_size:	PCU Fifo size
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_pcu_fifo_size(u8 pool_id, u32 fifo_size)
+{
+	WR_REG_32(BMGR_POOL_PCU_FIFO_SIZE_REG_ADDR(BM_BASE, pool_id),
+		  fifo_size);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_pcu_fifo_size
+ **************************************************************************
+ *
+ *  \brief	Returns the PCU fifo size
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	PCU Fifo size
+ *
+ **************************************************************************/
+static u32 bmgr_get_pcu_fifo_size(u8 pool_id)
+{
+	return RD_REG_32(BMGR_POOL_PCU_FIFO_SIZE_REG_ADDR(BM_BASE, pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_pcu_fifo_occupancy
+ **************************************************************************
+ *
+ *  \brief	Sets the PCU fifo occupancy
+ *
+ *  \param	pool_id:	Pool ID
+ *  \param	fifo_occupancy:	Occupancy of the pool
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_pcu_fifo_occupancy(u8 pool_id, u32 fifo_occupancy)
+{
+	WR_REG_32(BMGR_POOL_PCU_FIFO_OCCUPANCY_REG_ADDR(BM_BASE, pool_id),
+		  fifo_occupancy);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_pcu_fifo_occupancy
+ **************************************************************************
+ *
+ *  \brief	Returns the PCU fifo occupancy
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	Occupancy of the pool
+ *
+ **************************************************************************/
+static u32 bmgr_get_pcu_fifo_occupancy(u8 pool_id)
+{
+	return RD_REG_32(BMGR_POOL_PCU_FIFO_OCCUPANCY_REG_ADDR(BM_BASE,
+			 pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_pcu_fifo_prog_empty
+ **************************************************************************
+ *
+ *  \brief	Sets the PCU fifo empty threshold
+ *
+ *  \param	pool_id:	Pool ID
+ *  \param	threshold:	PCU fifo empty threshold
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_pcu_fifo_prog_empty(u8 pool_id, u32 threshold)
+{
+	WR_REG_32(BMGR_POOL_PCU_FIFO_PROG_EMPTY_REG_ADDR(BM_BASE, pool_id),
+		  threshold);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_pcu_fifo_prog_empty
+ **************************************************************************
+ *
+ *  \brief	Returns the PCU fifo empty threshold
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	PCU fifo empty threshold
+ *
+ **************************************************************************/
+static u32 bmgr_get_pcu_fifo_prog_empty(u8 pool_id)
+{
+	return RD_REG_32(BMGR_POOL_PCU_FIFO_PROG_EMPTY_REG_ADDR(BM_BASE,
+			 pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_pcu_fifo_prog_full
+ **************************************************************************
+ *
+ *  \brief	Sets the PCU fifo full threshold
+ *
+ *  \param	pool_id:	Pool ID
+ *  \param	threshold:	PCU fifo full threshold
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_pcu_fifo_prog_full(u8 pool_id, u32 threshold)
+{
+	WR_REG_32(BMGR_POOL_PCU_FIFO_PROG_FULL_REG_ADDR(BM_BASE, pool_id),
+		  threshold);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_pcu_fifo_prog_full
+ **************************************************************************
+ *
+ *  \brief	Returns the PCU fifo prog full threshold
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static u32 bmgr_get_pcu_fifo_prog_full(u8 pool_id)
+{
+	return RD_REG_32(BMGR_POOL_PCU_FIFO_PROG_FULL_REG_ADDR(BM_BASE,
+			 pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_ext_fifo_base_addr_low
+ **************************************************************************
+ *
+ *  \brief	Sets the external fifo base low address
+ *
+ *  \param	pool_id:	Pool ID
+ *  \param	low_address:	External fifo base low address
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_ext_fifo_base_addr_low(u8 pool_id, u32 low_address)
+{
+	WR_REG_32(BMGR_POOL_EXT_FIFO_BASE_ADDR_LOW_REG_ADDR(BM_BASE, pool_id),
+		  low_address);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_ext_fifo_base_addr_low
+ **************************************************************************
+ *
+ *  \brief	Returns the external fifo base low address
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	External fifo base low address
+ *
+ **************************************************************************/
+static u32 bmgr_get_ext_fifo_base_addr_low(u8 pool_id)
+{
+	return RD_REG_32(BMGR_POOL_EXT_FIFO_BASE_ADDR_LOW_REG_ADDR(BM_BASE,
+			 pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_ext_fifo_base_addr_high
+ **************************************************************************
+ *
+ *  \brief	Sets the external fifo base high address
+ *
+ *  \param	pool_id:	Pool ID
+ *  \param	high_address:	External fifo base high address
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_ext_fifo_base_addr_high(u8 pool_id, u32 high_address)
+{
+	WR_REG_32(BMGR_POOL_EXT_FIFO_BASE_ADDR_HIGH_REG_ADDR(BM_BASE, pool_id),
+		  high_address);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_ext_fifo_base_addr_high
+ **************************************************************************
+ *
+ *  \brief	Returns the external fifo base high address
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	External fifo base high address
+ *
+ **************************************************************************/
+static u32 bmgr_get_ext_fifo_base_addr_high(u8 pool_id)
+{
+	return RD_REG_32(BMGR_POOL_EXT_FIFO_BASE_ADDR_HIGH_REG_ADDR(BM_BASE,
+			 pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_ext_fifo_occupancy
+ **************************************************************************
+ *
+ *  \brief	Sets external fifo occupancy
+ *
+ *  \param	pool_id:	Pool ID
+ *  \param	occupancy:	External fifo occupancy
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_ext_fifo_occupancy(u8 pool_id, u32 occupancy)
+{
+	WR_REG_32(BMGR_POOL_EXT_FIFO_OCC_REG_ADDR(BM_BASE, pool_id),
+		  occupancy);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_ext_fifo_occupancy
+ **************************************************************************
+ *
+ *  \brief	Returns the external fifo occupancy
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	External fifo occupancy
+ *
+ **************************************************************************/
+static u32 bmgr_get_ext_fifo_occupancy(u8 pool_id)
+{
+	return RD_REG_32(BMGR_POOL_EXT_FIFO_OCC_REG_ADDR(BM_BASE, pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_pool_allocated_counter
+ **************************************************************************
+ *
+ *  \brief	Returns the number of allocated buffers in pool
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	Number of allocated buffers
+ *
+ **************************************************************************/
+static u32 bmgr_get_pool_allocated_counter(u8 pool_id)
+{
+	return RD_REG_32(BMGR_POOL_ALLOCATED_COUNTER_REG_ADDR(BM_BASE,
+			 pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_pool_pop_counter
+ **************************************************************************
+ *
+ *  \brief	Returns the number of pop operations on pool
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	Number of pop operations
+ *
+ **************************************************************************/
+static u32 bmgr_get_pool_pop_counter(u8 pool_id)
+{
+	return RD_REG_32(BMGR_POOL_POP_COUNTER_REG_ADDR(BM_BASE,
+			 pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_pool_push_counter
+ **************************************************************************
+ *
+ *  \brief	Returns the number of push operations on pool
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	Number of push operations
+ *
+ **************************************************************************/
+static u32 bmgr_get_pool_push_counter(u8 pool_id)
+{
+	return RD_REG_32(BMGR_POOL_PUSH_COUNTER_REG_ADDR(BM_BASE, pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_pool_burst_write_counter
+ **************************************************************************
+ *
+ *  \brief	Returns the burst write counter
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	Burst write counter
+ *
+ **************************************************************************/
+static u32 bmgr_get_pool_burst_write_counter(u8 pool_id)
+{
+	return RD_REG_32(BMGR_DDR_BURST_WRITE_COUNTER_REG_ADDR(BM_BASE,
+			 pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_pool_burst_read_counter
+ **************************************************************************
+ *
+ *  \brief	Returns the burst read counter
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	Burst read counter
+ *
+ **************************************************************************/
+static u32 bmgr_get_pool_burst_read_counter(u8 pool_id)
+{
+	return RD_REG_32(BMGR_DDR_BURST_READ_COUNTER_REG_ADDR(BM_BASE,
+			 pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_pool_watermark_low_threshold
+ **************************************************************************
+ *
+ *  \brief	Sets the watermark low threshold
+ *
+ *  \param	pool_id:	Pool ID
+ *  \param	threshold:	low threshold
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_pool_watermark_low_threshold(u8 pool_id, u32 threshold)
+{
+	WR_REG_32(BMGR_POOL_WATERMARK_LOW_THRESHOLD_REG_ADDR(BM_BASE, pool_id),
+		  threshold);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_pool_watermark_low_threshold
+ **************************************************************************
+ *
+ *  \brief	Returns the watermark low threshold
+ *
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	Low threshold
+ *
+ **************************************************************************/
+static u32 bmgr_get_pool_watermark_low_threshold(u8 pool_id)
+{
+	return RD_REG_32(BMGR_POOL_WATERMARK_LOW_THRESHOLD_REG_ADDR(BM_BASE,
+			 pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_policy_null_counter
+ **************************************************************************
+ *
+ *  \brief	Returns the policy null counter
+ *
+ *  \param	policy_id:	Policy ID
+ *
+ *  \return	Policy null counter
+ *
+ **************************************************************************/
+static u32 bmgr_get_policy_null_counter(u8 policy_id)
+{
+	return RD_REG_32(BMGR_POLICY_NULL_COUNTER_REG_ADDR(BM_BASE,
+			 policy_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_policy_max_allowed_per_policy
+ **************************************************************************
+ *
+ *  \brief	Sets policy max allowed buffers per policy
+ *
+ *  \param	policy_id:	Policy ID
+ *  \param	max_allowed:	Max allowed per this policy
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_policy_max_allowed_per_policy(u8 policy_id,
+						  u32 max_allowed)
+{
+	WR_REG_32(BMGR_POLICY_MAX_ALLOWED_ADDR(BM_RAM_BASE, policy_id),
+		  max_allowed);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_policy_max_allowed_per_policy
+ **************************************************************************
+ *
+ *  \brief	Returns the policy max allowed buffers per policy
+ *
+ *  \param	policy_id:	Policy ID
+ *
+ *  \return	Max allowed per this policy
+ *
+ **************************************************************************/
+static u32 bmgr_get_policy_max_allowed_per_policy(u8 policy_id)
+{
+	return RD_REG_32(BMGR_POLICY_MAX_ALLOWED_ADDR(BM_RAM_BASE,
+			 policy_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_policy_min_guaranteed_per_policy
+ **************************************************************************
+ *
+ *  \brief	Sets minimum guaranteed per policy
+ *
+ *  \param	min_guaranteed:	Minimum guaranteed per policy
+ *  \param	policy_id:	Policy ID
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_policy_min_guaranteed_per_policy(u8 policy_id,
+						     u32 min_guaranteed)
+{
+	WR_REG_32(BMGR_POLICY_MIN_GUARANTEED_ADDR(BM_RAM_BASE, policy_id),
+		  min_guaranteed);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_policy_min_guaranteed_per_policy
+ **************************************************************************
+ *
+ *  \brief	Returns minimum guaranteed per policy
+ *
+ *  \param	policy_id:	Policy ID
+ *
+ *  \return	Minimum guaranteed per policy
+ *
+ **************************************************************************/
+static u32 bmgr_get_policy_min_guaranteed_per_policy(u8 policy_id)
+{
+	return RD_REG_32(BMGR_POLICY_MIN_GUARANTEED_ADDR(BM_RAM_BASE,
+			 policy_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_policy_group_association
+ **************************************************************************
+ *
+ *  \brief	Maps group to policy
+ *
+ *  \param	policy_id:	Policy ID
+ *  \param	group_id:	Group ID
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_policy_group_association(u8 policy_id, u8 group_id)
+{
+	WR_REG_32(BMGR_POLICY_GROUP_ASSOCIATED_ADDR(BM_RAM_BASE, policy_id),
+		  (u32)group_id);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_policy_group_association
+ **************************************************************************
+ *
+ *  \brief	Returns the mapped group to this policy
+ *
+ *  \param	policy_id:	Policy ID
+ *
+ *  \return	The mapped group ID
+ *
+ **************************************************************************/
+static u32 bmgr_get_policy_group_association(u8 policy_id)
+{
+	return RD_REG_32(BMGR_POLICY_GROUP_ASSOCIATED_ADDR(BM_RAM_BASE,
+			 policy_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_policy_pool_mapping
+ **************************************************************************
+ *
+ *  \brief	Maps pool to policy (With priority)
+ *
+ *  \param	policy_id:	Policy ID
+ *  \param	pool_id:	Pool ID
+ *  \param	priority:	0 (highest priority) - 3 scale
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_policy_pool_mapping(u8 policy_id, u8 pool_id, u8 priority)
+{
+	u32	value;
+	u32	mask;
+
+	if (priority >= bmgr_policy_pool_priority_max)
+		pr_err("highest priority %d allowed is %d\n",
+		       priority, bmgr_policy_pool_priority_max - 1);
+
+	value = RD_REG_32(BMGR_POLICY_POOLS_MAPPING_ADDR(BM_RAM_BASE,
+							 policy_id));
+
+	// Clear relevant byte
+	mask = 0xFF << (8 * priority);
+	value &= ~mask;
+
+	// Prepare the value to be wriiten
+	value |= (pool_id << (8 * priority));
+
+	WR_REG_32(BMGR_POLICY_POOLS_MAPPING_ADDR(BM_RAM_BASE, policy_id),
+		  value);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_policy_pools_mapping
+ **************************************************************************
+ *
+ *  \brief	Returns the mapped pools to this policy
+ *
+ *  \param	policy_id:	Policy ID
+ *
+ *  \return	The mapped pool ID
+ *
+ **************************************************************************/
+static u32 bmgr_get_policy_pools_mapping(u8 policy_id)
+{
+	return RD_REG_32(BMGR_POLICY_POOLS_MAPPING_ADDR(BM_RAM_BASE,
+			 policy_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_set_policy_max_allowed_per_pool
+ **************************************************************************
+ *
+ *  \brief	Sets policy max allowed per pool
+ *
+ *  \param	policy_id:	Policy ID
+ *  \param	pool_id:	Pool ID
+ *  \param	max_allowed:	Max allowed for this pool
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+static s32 bmgr_set_policy_max_allowed_per_pool(u8 policy_id,
+						u8 pool_id,
+						u32 max_allowed)
+{
+	WR_REG_32(BMGR_POLICY_MAX_ALLOWED_PER_POOL_ADDR(BM_RAM_BASE,
+							policy_id,
+							pool_id),
+		  max_allowed);
+
+	return RC_SUCCESS;
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_policy_max_allowed_per_pool
+ **************************************************************************
+ *
+ *  \brief	Returns the max allowed per pool
+ *
+ *  \param	policy_id:	Policy ID
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	Max allowed for this pool
+ *
+ **************************************************************************/
+static u32 bmgr_get_policy_max_allowed_per_pool(u8 policy_id, u8 pool_id)
+{
+	return RD_REG_32(BMGR_POLICY_MAX_ALLOWED_PER_POOL_ADDR(BM_RAM_BASE,
+							       policy_id,
+							       pool_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_policy_number_of_allocated_buffers
+ **************************************************************************
+ *
+ *  \brief	Returns the number of allocated buffer in this policy
+ *
+ *  \param	policy_id:	Policy ID
+ *
+ *  \return	Number of allocated buffer in this policy
+ *
+ **************************************************************************/
+static u32 bmgr_get_policy_number_of_allocated_buffers(u8 policy_id)
+{
+	return RD_REG_32(BMGR_POLICY_ALLOC_BUFF_COUNTER_ADDR(BM_RAM_BASE,
+			 policy_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_get_policy_number_of_allocated_buffers_per_pool
+ **************************************************************************
+ *
+ *  \brief	Returns the number of allocated buffers per pool in this policy
+ *
+ *  \param	policy_id:	Policy ID
+ *  \param	pool_id:	Pool ID
+ *
+ *  \return	Number of allocated buffers per pool in this policy
+ *
+ **************************************************************************/
+static u32 bmgr_get_policy_number_of_allocated_buffers_per_pool(u8 policy_id,
+								u8 pool_id)
+{
+	return RD_REG_32(BMGR_POLICY_ALLOC_BUFF_PER_POOL_COUNTER_ADDR(
+			 BM_RAM_BASE, pool_id, policy_id));
+}
+
+/**************************************************************************
+ *! \fn	bmgr_pop_buffer
+ **************************************************************************
+ *
+ *  \brief	Pops a buffer from the buffer manager
+ *
+ *  \param	buff_info:	Buffer information
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+s32 bmgr_pop_buffer(struct bmgr_buff_info * const buff_info)
+{
+	u32	address = BMGR_DATAPATH_BASE;
+	//u32	dst_addr = 0x600000;
+	u32	index = 0;
+	u32	low = 0;
+	u32	high = 0;
+	u32	ptr2pop[2 * PP_BMGR_MAX_BURST_IN_POP]; // 64 bit per allocation
+
+	if (!buff_info) {
+		pr_err("bmgr_pop_buffer: buff_info is NULL\n");
+		return -EINVAL;
+	}
+
+	if (buff_info->num_allocs > PP_BMGR_MAX_BURST_IN_POP) {
+		pr_err("bmgr_pop_buffer: num_allocs %d is limited with %d\n",
+		       buff_info->num_allocs, PP_BMGR_MAX_BURST_IN_POP);
+		return -EINVAL;
+	}
+
+	// Write the Single/Burst bit
+	if (buff_info->num_allocs > 1)
+		address |= BIT(16);
+
+	// Write the Policy
+	address |= (buff_info->policy_id << 8);
+
+	copy_dma(address, (u32)&ptr2pop[0]/*dst_addr*/,
+		 (0x80100000 | (8 * buff_info->num_allocs))/*0x80100008*/);
+
+	for (index = 0; index < 2 * buff_info->num_allocs; index += 2) {
+		low = ptr2pop[index]; // RD_DDR32(dst_addr+8*index);
+		high = ptr2pop[index + 1]; // RD_DDR32(dst_addr+4+8*index);
+
+		pr_info("POP ======> 0x%x ; 0x%x\n", low, high);
+
+		buff_info->addr_low[index] = low;
+		buff_info->addr_high[index] = high & 0xF;
+		buff_info->pool_id[index] = (high & 0xFF000000) >> 24;
+
+		pr_info("bmgr_pop_buffer: ---> pop buffer from address %p (pool %d, addr low %p, addr high %p)\n",
+			(void *)address, buff_info->pool_id[index],
+			(void *)buff_info->addr_low[index],
+			(void *)buff_info->addr_high[index]);
+
+		if (buff_info->pool_id[index] >= PP_BMGR_MAX_POOLS) {
+			this->driver_db.policies[buff_info->policy_id].
+				num_allocated_buffers += index;
+			pr_info("Can't pop from policy %d\n",
+				buff_info->policy_id);
+			return -ENOSPC;
+		}
+
+		this->driver_db.pools[buff_info->pool_id[index]].
+			num_allocated_buffers++;
+	}
+
+	this->driver_db.policies[buff_info->policy_id].
+		num_allocated_buffers += buff_info->num_allocs;
+
+	return RC_SUCCESS;
+}
+EXPORT_SYMBOL(bmgr_pop_buffer);
+
+/**************************************************************************
+ *! \fn	bmgr_push_buffer
+ **************************************************************************
+ *
+ *  \brief	Pushes a buffer back to the buffer manager
+ *
+ *  \param	buff_info:	Buffer information
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+s32 bmgr_push_buffer(struct bmgr_buff_info * const buff_info)
+{
+	u32	address = BMGR_DATAPATH_BASE;
+	//u32	src_addr = 0x600000;
+	u32	value = 0;
+	u32	index = 0;
+	u32	ptr2push[2 * PP_BMGR_MAX_BURST_IN_POP]; // 64 bit per allocation
+
+	if (!buff_info) {
+		pr_err("bmgr_push_buffer: buff_info is NULL\n");
+		return -EINVAL;
+	}
+
+	if (buff_info->num_allocs > PP_BMGR_MAX_BURST_IN_POP) {
+		pr_err("bmgr_push_buffer: num_allocs %d is limited with %d\n",
+		       buff_info->num_allocs, PP_BMGR_MAX_BURST_IN_POP);
+		return -EINVAL;
+	}
+
+	// Write the Single/Burst bit
+	if (buff_info->num_allocs > 1)
+		address |= BIT(16);
+
+	// Write the Policy
+	address |= (buff_info->policy_id << 8);
+
+	// write to ddr
+	for (index = 0; index < 2 * buff_info->num_allocs; index += 2) {
+		ptr2push[index] = buff_info->addr_low[index];
+		//WR_DDR32(src_addr+8*index, buff_info->addr_low[index]);
+		value = (buff_info->addr_high[index] & 0xF) |
+			 ((buff_info->pool_id[index] & 0xFF) << 24);
+		ptr2push[index + 1] = value;
+		//WR_DDR32(src_addr + 4 + 8 * index, value);
+
+		pr_info("bmgr_push_buffer: <--- push buffer to address %p (pool %d, addr low %p, addr high %p, value %d)\n",
+			(void *)address, buff_info->pool_id[index],
+			(void *)buff_info->addr_low[index],
+			(void *)buff_info->addr_high[index], value);
+
+		this->driver_db.pools[buff_info->pool_id[index]].
+			num_deallocated_buffers++;
+	}
+
+	copy_dma((u32)&ptr2push[0]/*src_addr*/, address,
+		 (0x80100000 | (8 * buff_info->num_allocs))/*0x80100008*/);
+
+	this->driver_db.policies[buff_info->policy_id].
+		num_deallocated_buffers += buff_info->num_allocs;
+
+	return RC_SUCCESS;
+}
+EXPORT_SYMBOL(bmgr_push_buffer);
+
+/**************************************************************************
+ *! \fn	bmgr_driver_init
+ **************************************************************************
+ *
+ *  \brief  Initializes the buffer manager driver.
+ *          Must be the first driver's function to be called
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+s32 bmgr_driver_init(void)
+{
+	u8 index;
+
+	pr_info("Buffer Manager driver is initializing....");
+
+	// @lock
+	bmgr_db_lock();
+
+	bmgr_set_buffer_manager_control();
+	bmgr_configure_ocp_master();
+
+	// Reset group reserved buffers
+	for (index = 0; index < PP_BMGR_MAX_GROUPS; index++)
+		bmgr_set_group_reserved_buffers(index, 0);
+
+	// @unlock
+	bmgr_db_unlock();
+
+	pr_info("Done\n");
+
+	return RC_SUCCESS;
+}
+EXPORT_SYMBOL(bmgr_driver_init);
+
+/**************************************************************************
+ *! \fn	bmgr_pool_configure
+ **************************************************************************
+ *
+ *  \brief	Configure a Buffer Manager pool
+ *
+ *  \param	pool_params:	Pool param from user
+ *  \param	pool_id[OUT]:	Pool ID
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+s32 bmgr_pool_configure(const struct bmgr_pool_params * const pool_params,
+			u8 * const pool_id)
+{
+	s32		status = RC_SUCCESS;
+	void	*pointers_table = NULL;
+	u32		index = 0;
+	u32		*temp_pointers_table_ptr = NULL;
+	u64		user_array_ptr;
+	u32		phy_ll_base;
+#ifdef _FPGA_
+	//u32	fpga_ddr_address = 0x500000;
+#endif
+
+	pr_info("Configuring buffer manager pool...");
+
+	// @lock
+	bmgr_db_lock();
+
+	// Validity check
+	status = bmgr_is_pool_params_valid(pool_params);
+	if (status != RC_SUCCESS)
+		goto unlock;
+
+	*pool_id = 0;
+
+	// Find next available slot in pools db
+	for (index = 0; index < PP_BMGR_MAX_POOLS; index++) {
+		if (this->driver_db.pools[index].is_busy == 0) {
+			*pool_id = index;
+			break;
+		}
+	}
+
+	// If not found (Can be done also using num_pools)
+	if (index == PP_BMGR_MAX_POOLS) {
+		pr_err("bmgr_pool_configure: pools DB is full!");
+		status = -EIO;
+
+		goto unlock;
+	}
+
+	// Allocate pool_param->pool_num_of_buff * POINTER_SIZE bytes array
+#ifdef _FPGA_
+	pointers_table = (void *)(pool_params->base_addr_low +
+		pool_params->num_buffers * pool_params->size_of_buffer +
+		0x1000);//(void *)fpga_ddr_address;
+#else
+	pointers_table = devm_kzalloc(&this->pdev->dev,
+				      sizeof(u32) * pool_params->num_buffers,
+				      GFP_KERNEL);
+#endif
+	if (!pointers_table) {
+		pr_err("bmgr_pool_configure: Failed to allocate pointers_table, num_buffers %d",
+		       pool_params->num_buffers);
+		status = -ENOMEM;
+		goto unlock;
+	}
+
+#ifdef _FPGA_
+	temp_pointers_table_ptr = (u32 *)((u32)pointers_table +
+			this->debugfs_info.ddrvirt2phyoff);
+#else
+	temp_pointers_table_ptr = (u32 *)pointers_table;
+#endif
+	user_array_ptr = (pool_params->base_addr_low) |
+			((u64)pool_params->base_addr_high << 32);
+
+	for (index = 0; index < pool_params->num_buffers; index++) {
+		u32 temp = user_array_ptr >> 6;
+		// for debugging ...
+		if (index == 0 || index == pool_params->num_buffers - 1)
+			pr_info("bmgr_pool_configure: index %d) writing 0x%x to 0x%x\n",
+				index, temp, (u32)temp_pointers_table_ptr);
+
+		*temp_pointers_table_ptr = user_array_ptr >> 6;
+		temp_pointers_table_ptr++;
+		user_array_ptr += pool_params->size_of_buffer;
+	}
+
+	phy_ll_base = dma_map_single(&this->pdev->dev,
+				     (void *)pointers_table,
+				     (pool_params->num_buffers * 4),
+				     DMA_TO_DEVICE);
+
+	status = bmgr_set_pool_size(*pool_id, pool_params->num_buffers);
+	if (status != RC_SUCCESS)
+		goto free_memory;
+
+	status = bmgr_set_ext_fifo_base_addr_low(*pool_id, phy_ll_base);
+	if (status != RC_SUCCESS)
+		goto free_memory;
+
+	status = bmgr_set_ext_fifo_base_addr_high(*pool_id, 0);
+	if (status != RC_SUCCESS)
+		goto free_memory;
+
+	status = bmgr_set_ext_fifo_occupancy(*pool_id,
+					     pool_params->num_buffers);
+	if (status != RC_SUCCESS)
+		goto free_memory;
+
+	// Verify group is not full
+	index = this->driver_db.groups[pool_params->group_id].
+				num_pools_in_group;
+	if (index >= PP_BMGR_MAX_POOLS_IN_GROUP) {
+		pr_err("bmgr_pool_configure: Group %d is full. num_pools_in_group %d",
+		       pool_params->group_id, index);
+		status = -EIO;
+
+		goto free_memory;
+	}
+
+	// The group was unused
+	if (index == 0)
+		this->driver_db.num_groups++;
+
+	this->driver_db.groups[pool_params->group_id].pools[index] = *pool_id;
+	this->driver_db.groups[pool_params->group_id].available_buffers +=
+		pool_params->num_buffers;
+	this->driver_db.groups[pool_params->group_id].num_pools_in_group++;
+	// Group's reserved buffers will be updated when configuring the policy
+
+	status = bmgr_set_group_available_buffers(pool_params->group_id,
+						  this->driver_db.groups[
+				pool_params->group_id].available_buffers);
+	if (status != RC_SUCCESS)
+		goto free_memory;
+
+	status = bmgr_set_pcu_fifo_base_address(*pool_id,
+						BMGR_START_PCU_FIFO_SRAM_ADDR +
+						(*pool_id *
+					BMGR_DEFAULT_PCU_FIFO_SIZE));
+	if (status != RC_SUCCESS)
+		goto free_memory;
+
+	status = bmgr_set_pcu_fifo_size(*pool_id, BMGR_DEFAULT_PCU_FIFO_SIZE);
+	if (status != RC_SUCCESS)
+		goto free_memory;
+
+	status = bmgr_set_pcu_fifo_occupancy(*pool_id, 0);
+	if (status != RC_SUCCESS)
+		goto free_memory;
+
+	status = bmgr_set_pcu_fifo_prog_empty(*pool_id,
+			BMGR_DEFAULT_PCU_FIFO_LOW_THRESHOLD);
+	if (status != RC_SUCCESS)
+		goto free_memory;
+
+	status = bmgr_set_pcu_fifo_prog_full(*pool_id,
+			BMGR_DEFAULT_PCU_FIFO_HIGH_THRESHOLD);
+	if (status != RC_SUCCESS)
+		goto free_memory;
+
+	status = bmgr_set_pool_watermark_low_threshold(*pool_id,
+			BMGR_DEFAULT_WATERMARK_LOW_THRESHOLD);
+	if (status != RC_SUCCESS)
+		goto free_memory;
+
+	if (pool_params->flags & POOL_ENABLE_FOR_MIN_GRNT_POLICY_CALC) {
+		status = bmgr_enable_min_guarantee_per_pool(*pool_id, 1);
+		if (status != RC_SUCCESS)
+			goto free_memory;
+	}
+
+	status = bmgr_pool_reset_fifo(*pool_id);
+	if (status != RC_SUCCESS)
+		goto free_memory;
+
+	status = bmgr_pool_enable(*pool_id, 1);
+	if (status != RC_SUCCESS)
+		goto free_memory;
+
+	// Update pool's DB
+	memcpy(&this->driver_db.pools[*pool_id].pool_params,
+	       pool_params, sizeof(struct bmgr_pool_params));
+	this->driver_db.pools[*pool_id].is_busy = 1;
+	this->driver_db.pools[*pool_id].internal_pointers_tables =
+			temp_pointers_table_ptr;
+	this->driver_db.num_pools++;
+
+	bmgr_wait_for_init_completion();
+
+	// @unlock
+	bmgr_db_unlock();
+
+	pr_info("Done");
+
+	// OK
+	return status;
+
+free_memory:
+	// free pointers_table
+	#ifndef _FPGA_
+		kfree(pointers_table);
+	#endif
+unlock:
+	// @unlock
+	bmgr_db_unlock();
+
+	return status;
+}
+EXPORT_SYMBOL(bmgr_pool_configure);
+
+/**************************************************************************
+ *! \fn	bmgr_policy_configure
+ **************************************************************************
+ *
+ *  \brief	Configure a Buffer Manager policy
+ *
+ *  \param	policy_params:	Policy param from user
+ *  \param	policy_id[OUT]:	Policy ID
+ *
+ *  \return	RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+s32 bmgr_policy_configure(const struct bmgr_policy_params * const policy_params,
+			  u8 * const policy_id)
+{
+	s32	status = RC_SUCCESS;
+	u8	index = 0;
+
+	pr_info("Configuring buffer manager policy...");
+
+	// @lock
+	bmgr_db_lock();
+
+	// Validity check
+	status = bmgr_is_policy_params_valid(policy_params);
+	if (status != RC_SUCCESS)
+		goto unlock;
+
+	*policy_id = 0;
+
+	// Find next available slot in policy db
+	for (index = 0; index < PP_BMGR_MAX_POLICIES; index++) {
+		if (this->driver_db.policies[index].is_busy == 0) {
+			*policy_id = index;
+			break;
+		}
+	}
+
+	// If not found (Can be done also using num_policies)
+	if (index == PP_BMGR_MAX_POLICIES) {
+		pr_err("No free policy!");
+		status = -EIO;
+
+		goto unlock;
+	}
+
+	status = bmgr_set_policy_group_association(*policy_id,
+						   policy_params->group_id);
+	if (status != RC_SUCCESS)
+		goto unlock;
+
+	status = bmgr_set_policy_max_allowed_per_policy(*policy_id,
+						policy_params->max_allowed);
+	if (status != RC_SUCCESS)
+		goto unlock;
+
+	status = bmgr_set_policy_min_guaranteed_per_policy(*policy_id,
+						policy_params->min_guaranteed);
+	if (status != RC_SUCCESS)
+		goto unlock;
+
+	// Set the group's reserved buffers
+	this->driver_db.groups[policy_params->group_id].reserved_buffers =
+		bmgr_get_group_reserved_buffers(policy_params->group_id);
+	this->driver_db.groups[policy_params->group_id].
+		reserved_buffers += policy_params->min_guaranteed;
+
+	status = bmgr_set_group_reserved_buffers(policy_params->group_id,
+						 this->driver_db.groups[
+				policy_params->group_id].reserved_buffers);
+	if (status != RC_SUCCESS)
+		goto unlock;
+
+	for (index = 0; index < policy_params->num_pools_in_policy; index++) {
+		status = bmgr_set_policy_max_allowed_per_pool(*policy_id,
+			policy_params->pools_in_policy[index].pool_id,
+			policy_params->pools_in_policy[index].max_allowed);
+		if (status != RC_SUCCESS)
+			goto unlock;
+
+		status = bmgr_set_policy_pool_mapping(*policy_id,
+			policy_params->pools_in_policy[index].pool_id, index);
+		if (status != RC_SUCCESS)
+			goto unlock;
+	}
+
+	// Update Policy DB
+	this->driver_db.num_policies++;
+	this->driver_db.policies[*policy_id].is_busy = 1;
+	memcpy(&this->driver_db.policies[*policy_id].policy_params,
+	       policy_params, sizeof(struct bmgr_policy_params));
+
+	bmgr_wait_for_init_completion();
+
+	// @unlock
+	bmgr_db_unlock();
+
+	pr_info("Done");
+
+	// OK
+	return status;
+
+unlock:
+	// @unlock
+	bmgr_db_unlock();
+
+	// Failure
+	return status;
+}
+EXPORT_SYMBOL(bmgr_policy_configure);
+
+void test_init_bmgr(struct device *dev)
+{
+	struct bmgr_pool_params	pool_params;
+	struct bmgr_policy_params	policy_params;
+	u8					pool_id;
+	u8					policy_id;
+	u8					num_buffers = 10;
+	u8					size_of_buffer = 64;
+	void				*ptr = NULL;
+
+	if (bmgr_driver_init() != RC_SUCCESS) {
+		pr_err("commands_store(): bmgr_driver_init failed\n");
+		return;
+	}
+
+	#ifdef _FPGA_
+		pool_params.base_addr_low = 0x400000;
+	#else
+		ptr = devm_kzalloc(dev,
+				   size_of_buffer * num_buffers,
+				   GFP_KERNEL);
+		if (!ptr)
+			return;
+
+		pool_params.base_addr_low = (u32)ptr;
+	#endif
+
+	pool_params.base_addr_high = 0;
+	pool_params.size_of_buffer = size_of_buffer;
+	pool_params.num_buffers = num_buffers;
+	pool_params.group_id = 0;
+	pool_params.flags = 0;
+	if (bmgr_pool_configure(&pool_params, &pool_id) != RC_SUCCESS) {
+		pr_err("commands_store(): bmgr_pool_configure failed\n");
+		return;
+	}
+
+	pr_info("test_init_bmgr(): configured pool_id %d with %d buffers (of %d), group id 0, address 0x%x\n",
+		pool_id, num_buffers, size_of_buffer, (u32)ptr);
+
+	policy_params.flags = 0;
+	policy_params.group_id = 0;
+	policy_params.max_allowed = num_buffers / 2;
+	policy_params.min_guaranteed = num_buffers / 5;
+	policy_params.num_pools_in_policy = 1;
+	policy_params.pools_in_policy[0].max_allowed = num_buffers;
+	policy_params.pools_in_policy[0].pool_id = 0;
+	if (bmgr_policy_configure(&policy_params, &policy_id) != RC_SUCCESS) {
+		pr_err("test_init_bmgr(): bmgr_policy_configure failed\n");
+		return;
+	}
+
+	pr_info("test_init_bmgr(): configured policy_id %d with max allowed %d, min guaranteed %d, pool 0 (max allowed %d) group 0\n",
+		policy_id, num_buffers / 2, num_buffers / 5, num_buffers);
+}
+
+void print_hw_stats(u8 policy_id, u8 group_id, u8 pool_id)
+{
+	u32	counter;
+
+	counter = bmgr_get_pool_pop_counter(pool_id);
+	pr_info("Pop counter (pool %d) = %d\n", pool_id, counter);
+
+	counter = bmgr_get_pool_push_counter(pool_id);
+	pr_info("Push counter (pool %d) = %d\n", pool_id, counter);
+
+	counter = bmgr_get_pool_allocated_counter(pool_id);
+	pr_info("Pool %d allocated counter = %d\n", pool_id, counter);
+
+	counter = bmgr_get_pool_size(pool_id);
+	pr_info("Pool %d size = %d\n", pool_id, counter);
+
+	counter = bmgr_get_policy_number_of_allocated_buffers(policy_id);
+	pr_info("Policy %d num allocated = %d\n", policy_id, counter);
+
+	counter = bmgr_get_policy_number_of_allocated_buffers_per_pool(
+				policy_id, pool_id);
+	pr_info("Policy %d num allocated per pool %d = %d\n",
+		policy_id, pool_id, counter);
+
+	counter = bmgr_get_policy_group_association(policy_id);
+	pr_info("Policy %d group association = %d\n", policy_id, counter);
+
+	counter = bmgr_get_policy_max_allowed_per_policy(policy_id);
+	pr_info("Policy %d max allowed = %d\n", policy_id, counter);
+
+	counter = bmgr_get_policy_max_allowed_per_pool(policy_id, pool_id);
+	pr_info("Policy %d max allowed per pool %d = %d\n",
+		policy_id, pool_id, counter);
+
+	counter = bmgr_get_policy_min_guaranteed_per_policy(policy_id);
+	pr_info("Policy %d min guaranteed = %d\n", policy_id, counter);
+
+	counter = bmgr_get_policy_null_counter(policy_id);
+	pr_info("Policy %d null counter = %d\n", policy_id, counter);
+
+	counter = bmgr_get_group_available_buffers(group_id);
+	pr_info("Group %d available buffers = %d\n", group_id, counter);
+
+	counter = bmgr_get_group_reserved_buffers(group_id);
+	pr_info("Group %d reserved buffers = %d\n", group_id, counter);
+
+	{
+		// Just to ignore compilation warnings
+		bmgr_get_ocp_burst_size();
+		bmgr_get_pcu_fifo_base_address(0);
+		bmgr_get_pcu_fifo_size(0);
+		bmgr_get_pcu_fifo_occupancy(0);
+		bmgr_get_pcu_fifo_prog_empty(0);
+		bmgr_get_pcu_fifo_prog_full(0);
+		bmgr_get_ext_fifo_base_addr_low(0);
+		bmgr_get_ext_fifo_base_addr_high(0);
+		bmgr_get_ext_fifo_occupancy(0);
+		bmgr_get_pool_burst_write_counter(0);
+		bmgr_get_pool_burst_read_counter(0);
+		bmgr_get_pool_watermark_low_threshold(0);
+		bmgr_get_policy_pools_mapping(0);
+	}
+}
+
diff --git a/drivers/net/ethernet/lantiq/ppv4/bm/pp_bm_drv.h b/drivers/net/ethernet/lantiq/ppv4/bm/pp_bm_drv.h
new file mode 100644
index 0000000000000000000000000000000000000000..b2dc147cab219bfb3aa84939a5b508a090ceffe4
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/bm/pp_bm_drv.h
@@ -0,0 +1,265 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+
+#ifndef _BMGR_H_
+#define _BMGR_H_
+
+/**********************************
+ **********************************
+ ************ DEFINES *************
+ **********************************
+ **********************************/
+
+#define FALCON_SOC
+
+#ifdef FALCON_SOC
+	/*! \def PP_BMGR_MAX_POOLS
+	 *       Max supported pools
+	 */
+	#define PP_BMGR_MAX_POOLS		(4)
+
+	/*! \def PP_BMGR_MAX_POOLS_IN_GROUP
+	 *       Max pools in group
+	 */
+	#define PP_BMGR_MAX_POOLS_IN_GROUP	(4)
+
+	/*! \def PP_BMGR_MAX_GROUPS
+	 *       Max supported groups
+	 */
+	#define PP_BMGR_MAX_GROUPS		(2)
+
+	/*! \def PP_BMGR_MAX_POLICIES
+	 *       Max supported policies
+	 */
+	#define PP_BMGR_MAX_POLICIES		(32)
+#else /* PPv4 */
+	/*! \def PP_BMGR_MAX_POOLS
+	 *       Max supported pools
+	 */
+	#define PP_BMGR_MAX_POOLS		(16)
+
+	/*! \def PP_BMGR_MAX_POOLS_IN_GROUP
+	 *       Max pools in group
+	 */
+	#define PP_BMGR_MAX_POOLS_IN_GROUP	(4)
+
+	/*! \def PP_BMGR_MAX_GROUPS
+	 *       Max supported groups
+	 */
+	#define PP_BMGR_MAX_GROUPS		(16)
+
+	/*! \def PP_BMGR_MAX_POLICIES
+	 *       Max supoorted policies
+	 */
+	#define PP_BMGR_MAX_POLICIES		(256)
+#endif
+
+/*! \def POOL_ENABLE_FOR_MIN_GRNT_POLICY_CALC
+ *       bmgr pools flags (Used in bmgr_pool_params.pool_flags)
+ *       When set pool will be take part in
+ *       policy minimum guaranteed calculation
+ */
+#define POOL_ENABLE_FOR_MIN_GRNT_POLICY_CALC	BIT(0)
+
+/**************************************************************************
+ *! \struct	bmgr_pool_params
+ **************************************************************************
+ *
+ * \brief This structure is used in bmgr_pool_configure API in parameter
+ *
+ **************************************************************************/
+struct bmgr_pool_params {
+	//!< Pool flags
+	u16	flags;
+	//!< Group index which the pool belong to
+	u8	group_id;
+	//!< Amount of buffers in pool
+	u32	num_buffers;
+	//!< Buffer size for this pool (in bytes). Minimum is 64 bytes
+	u32	size_of_buffer;
+	//!< Base address of the pool (low)
+	u32	base_addr_low;
+	//!< Base address of the pool (high)
+	u32	base_addr_high;
+};
+
+/**************************************************************************
+ *! \struct	bmgr_group_params
+ **************************************************************************
+ *
+ * \brief This structure is used for buffer manager database
+ *
+ **************************************************************************/
+struct bmgr_group_params {
+	//!< available buffers in group
+	u32	available_buffers;
+	//!< reserved buffers in this group
+	u32	reserved_buffers;
+	//!< Pools in policy
+	u8	pools[PP_BMGR_MAX_POOLS];
+};
+
+/**************************************************************************
+ *! \struct	bmgr_pool_in_policy_info
+ **************************************************************************
+ *
+ * \brief	This structure is used in policy_params struct and holds
+ *			the information about the pools in policy
+ *
+ **************************************************************************/
+struct bmgr_pool_in_policy_info {
+	//!< Pool id
+	u8	pool_id;
+	//!< Max allowed per pool per policy
+	u32	max_allowed;
+};
+
+/*! \def POLICY_FLAG_RESERVED1
+ *       bmgr policy flags (Used in bmgr_policy_param.policy_flags)
+ */
+#define POLICY_FLAG_RESERVED1	BIT(0)
+
+/**************************************************************************
+ *! \struct	bmgr_policy_params
+ **************************************************************************
+ *
+ * \brief This structure is used in bmgr_policy_configure API in parameter
+ *
+ **************************************************************************/
+struct bmgr_policy_params {
+	//!< Policy flags
+	u16		flags;
+	//!< Group index
+	u8		group_id;
+	//!< Policy maximum allowed
+	u32		max_allowed;
+	//!< Policy minimum guaranteed
+	u32		min_guaranteed;
+	//!< Pools information. Sorted from high priority (index 0) to lowest
+	struct bmgr_pool_in_policy_info
+		pools_in_policy[4/*PP_BMGR_MAX_POOLS_IN_POLICY*/];
+	//!< Number of pools in pools_in_policy
+	u8		num_pools_in_policy;
+};
+
+#define PP_BMGR_MAX_BURST_IN_POP	(32)
+/**************************************************************************
+ *! \struct	bmgr_buff_info
+ **************************************************************************
+ *
+ * \brief This structure is used for allocate and deallocate buffer
+ *
+ **************************************************************************/
+struct bmgr_buff_info {
+	//!< [Out] buffer pointer low
+	u32	addr_low[PP_BMGR_MAX_BURST_IN_POP];
+	//!< [Out] buffer pointer high
+	u32	addr_high[PP_BMGR_MAX_BURST_IN_POP];
+	//!< policy to allocate from
+	u8	policy_id;
+	//!< pool for deallocate buffer back
+	u8	pool_id[PP_BMGR_MAX_BURST_IN_POP];
+	//!< number of pointers to allocate (up to 32 pointers)
+	u8	num_allocs;
+};
+
+/**********************************
+ **********************************
+ *********** PROTOTYPES ***********
+ **********************************
+ **********************************/
+
+/**************************************************************************
+ *! \fn	bmgr_driver_init
+ **************************************************************************
+ *
+ *  \brief	Initializes the buffer manager driver.
+ *			Must be the first driver's function to be called
+ *
+ *  \return	PP_RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+s32 bmgr_driver_init(void);
+
+/**************************************************************************
+ *! \fn	bmgr_pool_configure
+ **************************************************************************
+ *
+ *  \brief	Configure a Buffer Manager pool
+ *
+ *  \param	pool_params:	Pool param from user
+ *  \param	pool_id[OUT]:	Pool ID
+ *
+ *  \return	PP_RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+s32 bmgr_pool_configure(const struct bmgr_pool_params * const pool_params,
+			u8 * const pool_id);
+
+/**************************************************************************
+ *! \fn	bmgr_policy_configure
+ **************************************************************************
+ *
+ *  \brief	Configure a Buffer Manager policy
+ *
+ *  \param	policy_params:	Policy param from user
+ *  \param	policy_id[OUT]:	Policy ID
+ *
+ *  \return	PP_RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+s32 bmgr_policy_configure(
+		const struct bmgr_policy_params * const policy_params,
+		u8 * const policy_id);
+
+/**************************************************************************
+ *! \fn	bmgr_pop_buffer
+ **************************************************************************
+ *
+ *  \brief	Pops a buffer from the buffer manager
+ *
+ *  \param	buff_info:	Buffer information
+ *
+ *  \return	PP_RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+s32 bmgr_pop_buffer(struct bmgr_buff_info * const buff_info);
+
+/**************************************************************************
+ *! \fn	bmgr_push_buffer
+ **************************************************************************
+ *
+ *  \brief	Pushes a buffer back to the buffer manager
+ *
+ *  \param	buff_info:	Buffer information
+ *
+ *  \return	PP_RC_SUCCESS on success, other error code on failure
+ *
+ **************************************************************************/
+s32 bmgr_push_buffer(struct bmgr_buff_info * const buff_info);
+
+#endif /* _BMGR_H_ */
diff --git a/drivers/net/ethernet/lantiq/ppv4/bm/pp_bm_drv_internal.h b/drivers/net/ethernet/lantiq/ppv4/bm/pp_bm_drv_internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..45c0cbffcbf9f288754546778f285589409847f9
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/bm/pp_bm_drv_internal.h
@@ -0,0 +1,212 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+
+#ifndef _BMGR_DRV_INTERNAL_H_
+#define _BMGR_DRV_INTERNAL_H_
+
+#include <linux/debugfs.h>
+#include "pp_bm_drv.h"
+
+/*! \def BMGR_DRIVER_VERSION */
+#define BMGR_DRIVER_VERSION			"1.0.0"
+
+/*! \def BMGR_MIN_POOL_BUFFER_SIZE
+ *       Minimum buffer size in configured pool
+ */
+#define BMGR_MIN_POOL_BUFFER_SIZE		(64)
+
+/*! \def BMGR_START_PCU_SRAM_ADDR
+ *       Start PCU address in SRAM. Used in confiure pool
+ */
+#define BMGR_START_PCU_FIFO_SRAM_ADDR		(0)
+
+/*! \def BMGR_DEFAULT_PCU_FIFO_SIZE
+ *       PCU fifo size
+ */
+#define BMGR_DEFAULT_PCU_FIFO_SIZE		(0x80)
+
+/*! \def BMGR_DEFAULT_PCU_FIFO_LOW_THRESHOLD
+ *       PCU fifo low threshold
+ */
+#define BMGR_DEFAULT_PCU_FIFO_LOW_THRESHOLD	(1)
+
+/*! \def BMGR_DEFAULT_PCU_FIFO_HIGH_THRESHOLD
+ *       PCU fifo high threshold
+ */
+#define BMGR_DEFAULT_PCU_FIFO_HIGH_THRESHOLD	(0x70)
+
+/*! \def BMGR_DEFAULT_WATERMARK_LOW_THRESHOLD
+ *       Watermark low threshold
+ */
+#define BMGR_DEFAULT_WATERMARK_LOW_THRESHOLD	(0x200)
+
+/**********************************
+ **********************************
+ *********** STRUCTURE ************
+ **********************************
+ **********************************/
+
+/**************************************************************************
+ *! \enum	bmgr_policy_pools_priority_e
+ **************************************************************************
+ *
+ * \brief enum to describe the pool's priority
+ *
+ **************************************************************************/
+enum bmgr_policy_pools_priority_e {
+	bmgr_policy_pool_priority_high,		//!< High priority
+	bmgr_policy_pool_priority_mid_high,	//!< Mid-High priority
+	bmgr_policy_pool_priority_mid_low,	//!< Mid-Low priority
+	bmgr_policy_pool_priority_low,		//!< Low priority
+	bmgr_policy_pool_priority_max		//!< Last priority
+};
+
+/**************************************************************************
+ *! \struct	bmgr_pool_db_entry
+ **************************************************************************
+ *
+ * \brief This structure holds the pool database
+ *
+ **************************************************************************/
+struct bmgr_pool_db_entry {
+	//!< Pool params
+	struct bmgr_pool_params	pool_params;
+	//!< Number of allocated buffers
+	u32						num_allocated_buffers;
+	//!< Number of deallocated buffers
+	u32						num_deallocated_buffers;
+	//!< Is entry in used
+	u8						is_busy;
+	//!< Pointers table to be used in HW
+	void					*internal_pointers_tables;
+};
+
+/**************************************************************************
+ *! \struct	bmgr_group_db_entry
+ **************************************************************************
+ *
+ * \brief This structure holds the group database
+ *
+ **************************************************************************/
+struct bmgr_group_db_entry {
+	//!< available buffers in group
+	u32	available_buffers;
+	//!< reserved buffers in this group
+	u32	reserved_buffers;
+	//!< Pools in policy (if set, pool is part of this group)
+	u8	pools[PP_BMGR_MAX_POOLS_IN_GROUP];
+	//!< Number of pools in group
+	u8	num_pools_in_group;
+};
+
+/**************************************************************************
+ *! \struct	bmgr_policy_db_entry
+ **************************************************************************
+ *
+ * \brief This structure holds the policy database
+ *
+ **************************************************************************/
+struct bmgr_policy_db_entry {
+	//!< Policy params
+	struct bmgr_policy_params	policy_params;
+	//!< Number of allocated buffers
+	u32		num_allocated_buffers;
+	//!< Number of deallocated buffers
+	u32		num_deallocated_buffers;
+	//!< Is entry in used
+	u8		is_busy;
+};
+
+/**************************************************************************
+ *! \struct	bmgr_driver_db
+ **************************************************************************
+ *
+ * \brief This structure holds the buffer manager database
+ *
+ **************************************************************************/
+struct bmgr_driver_db {
+	//!< Pools information
+	struct bmgr_pool_db_entry	pools[PP_BMGR_MAX_POOLS];
+	//!< Groups information
+	struct bmgr_group_db_entry	groups[PP_BMGR_MAX_GROUPS];
+	//!< Policies information
+	struct bmgr_policy_db_entry	policies[PP_BMGR_MAX_POLICIES];
+
+	// general counters
+	//!< Number of active pools
+	u32				num_pools;
+	//!< Number of active groups
+	u32				num_groups;
+	//!< Number of active policies
+	u32				num_policies;
+
+	//!< spinlock
+	spinlock_t		db_lock;
+};
+
+/**************************************************************************
+ *! \struct	bmgr_driver_db
+ **************************************************************************
+ *
+ * \brief This structure holds the buffer manager database
+ *
+ **************************************************************************/
+struct bmgr_debugfs_info {
+	//!< Debugfs dir
+	struct dentry	*dir;
+	u32				virt2phyoff;
+	u32				ddrvirt2phyoff;
+	u32				fpga_offset;
+};
+
+/**************************************************************************
+ *! \struct	bmgr_driver_private
+ **************************************************************************
+ *
+ * \brief This struct defines the driver's private data
+ *
+ **************************************************************************/
+struct bmgr_driver_private {
+	//!< Platform device pointer
+	struct platform_device		*pdev;
+	//!< Is driver enabled
+	int							enabled;
+	//!< Platform device DB
+	struct bmgr_driver_db		driver_db;
+	//!< Debugfs info
+	struct bmgr_debugfs_info	debugfs_info;
+};
+
+void test_init_bmgr(struct device *dev);
+void print_hw_stats(u8 policy_id, u8 group_id, u8 pool_id);
+
+int bm_dbg_dev_init(struct platform_device *pdev);
+void bm_dbg_dev_clean(struct platform_device *pdev);
+int bm_dbg_module_init(void);
+void bm_dbg_module_clean(void);
+
+#endif /* _BMGR_DRV_INTERNAL_H_ */
diff --git a/drivers/net/ethernet/lantiq/ppv4/qos/Makefile b/drivers/net/ethernet/lantiq/ppv4/qos/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..4241e056237c3aa481d0877faaf7b6542e39f489
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/qos/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for PPv4 QoS driver.
+#
+
+obj-$(CONFIG_LTQ_PPV4_QOS) += pp_qos_drv.o
+pp_qos_drv-y 	:= pp_qos_linux.o pp_qos_main.o pp_qos_utils.o pp_qos_fw.o pp_qos_tests.o pp_qos_debugfs.o
+ccflags-y	+= -Iinclude/net -DQOS_CPU_UC_SAME_ENDIANESS
+
+ccflags-$(CONFIG_LTQ_PPV4_QOS_TEST) += -DPP_QOS_TEST
diff --git a/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_common.h b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_common.h
new file mode 100644
index 0000000000000000000000000000000000000000..4fa22b718aaad3b9ff776650acbb0d7163b9fcf4
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_common.h
@@ -0,0 +1,180 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+#ifndef PP_QOS_COMMON_H
+#define PP_QOS_COMMON_H
+
+#ifdef __KERNEL__
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/stringify.h>
+#else
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "list.h"
+#endif
+
+/* Logs */
+#ifndef __KERNEL__
+#define BIT(x) ((uint32_t) (1U << (x)))
+#define QOS_LOG_CRIT(format, arg...)	printf(format, ##arg)
+#define QOS_LOG_ERR(format, arg...)	printf(format, ##arg)
+#define QOS_LOG_INFO(format, arg...)	printf(format, ##arg)
+#define QOS_LOG_DEBUG(format, arg...)	printf(format, ##arg)
+#else
+extern struct device *cur_dev;
+#define QOS_LOG_CRIT(format, arg...) \
+do { \
+	if (cur_dev) \
+		dev_crit(cur_dev, format, ##arg); \
+	else \
+		pr_crit(format, ##arg); \
+} while (0)
+#define QOS_LOG_ERR(format, arg...) \
+do { \
+	if (cur_dev) \
+		dev_err(cur_dev, format, ##arg); \
+	else \
+		pr_err(format, ##arg); \
+} while (0)
+#define QOS_LOG_INFO(format, arg...) \
+do { \
+	if (cur_dev) \
+		dev_info(cur_dev, format, ##arg); \
+	else \
+		pr_info(format, ##arg); \
+} while (0)
+#define QOS_LOG_DEBUG(format, arg...) \
+do { \
+	if (cur_dev) \
+		dev_dbg(cur_dev, format, ##arg); \
+	else \
+		pr_debug(format, ##arg); \
+} while (0)
+
+#endif
+
+#ifndef __KERNEL__
+#define max(a, b)		\
+	({ typeof(a) _a = (a);	\
+	typeof(b) _b = (b);	\
+	_a > _b ? _a : _b; })
+
+#define min(a, b)		\
+	({ typeof(a) _a = (a);	\
+	 typeof(b) _b = (b);	\
+	 _a < _b ? _a : _b; })
+#endif
+
+/* Memory allocation */
+#ifdef __KERNEL__
+#define QOS_MALLOC(size)	vmalloc(size)
+#define QOS_FREE(p)		vfree(p)
+#else
+#define QOS_MALLOC(size)	malloc(size)
+#define QOS_FREE(p)		free(p)
+#endif
+
+/* Locking */
+#ifdef __KERNEL__
+#define LOCK spinlock_t
+#define QOS_LOCK_INIT(qdev)	spin_lock_init(&qdev->lock)
+#define QOS_LOCK(qdev)		spin_lock(&qdev->lock)
+#define QOS_UNLOCK(qdev)	spin_unlock(&qdev->lock)
+#define QOS_SPIN_IS_LOCKED(qdev) spin_is_locked(&qdev->lock)
+#else
+#define LOCK int
+#define QOS_LOCK_INIT(qdev)	(qdev->lock = 0)
+#define QOS_LOCK(qdev)		do {QOS_ASSERT(qdev->lock == 0,\
+				"Lock already taken\n");\
+				qdev->lock++; } while (0)
+#define QOS_UNLOCK(qdev)	do {QOS_ASSERT(qdev->lock == 1,\
+				"Lock not taken\n");\
+				qdev->lock--; } while (0)
+#define QOS_SPIN_IS_LOCKED(qdev) (qdev->lock)
+#endif
+
+/* MMIO */
+#ifdef __KERNEL__
+#else
+#define __iomem
+#define iowrite32(val, addr) (*((uint32_t *)(addr)) = (val))
+#endif
+
+/* TODO not clean
+ * There might be other mapping on platform different
+ * than the FPGA I am currently testing on
+ */
+#ifdef CONFIG_OF
+#define TO_QOS_ADDR(x) (x)
+#define FW_OK_OFFSET (0x25e10000U)
+#else
+#define FW_OK_OFFSET (0x6ffff8U)
+#define PCI_DDR_BAR_START 0xd2000000
+#define TO_QOS_ADDR(x) ((x) - PCI_DDR_BAR_START)
+#endif
+
+/* Sleep */
+#ifdef __KERNEL__
+#define qos_sleep(t) msleep((t))
+#else
+#define qos_sleep(t) usleep((t) * 1000)
+#endif
+
+/* Endianess */
+#ifndef __KERNEL__
+#define cpu_to_le32(x) (x)
+#define le32_to_cpu(x) (x)
+#endif
+
+#ifdef QOS_CPU_UC_SAME_ENDIANESS
+#define qos_u32_to_uc(val)	(val)
+#define qos_u32_from_uc(val)  (val)
+#else
+#define qos_u32_to_uc(val)	(cpu_to_le32((val)))
+#define qos_u32_from_uc(val)	(le32_to_cpu((val)))
+#endif
+
+/* Creating enums and enums strings */
+#ifndef __KERNEL__
+#define __stringify(x)		#x
+#endif
+
+#define GEN_ENUM(enumerator)    enumerator,
+#define GEN_STR(str)		__stringify(str),
+
+#endif /* PP_QOS_COMMON_H */
diff --git a/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_debugfs.c b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_debugfs.c
new file mode 100644
index 0000000000000000000000000000000000000000..1e93e73ae400bb64dd447624031a2c80f96ee37b
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_debugfs.c
@@ -0,0 +1,660 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include "pp_qos_common.h"
+#include "pp_qos_utils.h"
+#include "pp_qos_fw.h"
+#include "pp_qos_kernel.h"
+
+/* TODO is this the common way for driver's not device specific data */
+static struct {
+	struct dentry *dir;
+} dbg_data = {NULL, };
+
+#define PP_QOS_DEBUGFS_DIR "ppv4_qos"
+
+static int pp_qos_dbg_node_show(struct seq_file *s, void *unused)
+{
+	struct platform_device *pdev;
+	struct pp_qos_dev *qdev;
+	struct pp_qos_drv_data *pdata;
+	const char *typename;
+	unsigned int phy;
+	unsigned int id;
+	unsigned int i;
+	static const char *const types[] = {"Port", "Sched", "Queue",
+		"Unknown"};
+	static const char *const yesno[] = {"No", "Yes"};
+	int rc;
+	struct pp_qos_node_info info;
+
+	pdev = s->private;
+	dev_info(&pdev->dev, "node_show called\n");
+	if (pdev) {
+		pdata = platform_get_drvdata(pdev);
+		qdev = pdata->qdev;
+		if (!qdev->initialized) {
+			seq_puts(s, "Device is not initialized !!!!\n");
+			return 0;
+		}
+
+		id = pdata->dbg.node;
+		phy = get_phy_from_id(qdev->mapping, id);
+		if (!QOS_PHY_VALID(phy)) {
+			seq_printf(s, "Invalid id %u\n", id);
+			return 0;
+		}
+		rc = pp_qos_get_node_info(qdev, id, &info);
+		if (rc) {
+			seq_printf(s, "Could not get info for node %u!!!!\n",
+					id);
+			return 0;
+		}
+
+		if (info.type >=  PPV4_QOS_NODE_TYPE_PORT &&
+				info.type <= PPV4_QOS_NODE_TYPE_QUEUE)
+			typename = types[info.type];
+		else
+			typename = types[3];
+
+		seq_printf(s, "%u(%u) - %s: suspended(%s) internal node(%s)\n",
+				id, phy,
+				typename,
+				yesno[!!info.is_suspended],
+				yesno[!!info.is_internal]);
+
+		if (info.preds[0].phy != PPV4_QOS_INVALID) {
+			seq_printf(s, "%u(%u)", id, phy);
+			for (i = 0; i < 6; ++i) {
+				if (info.preds[i].phy == PPV4_QOS_INVALID)
+					break;
+				seq_printf(s, " ==> %u(%u)",
+						info.preds[i].id,
+						info.preds[i].phy);
+			}
+			seq_puts(s, "\n");
+		}
+
+		if (info.children[0].phy != PPV4_QOS_INVALID) {
+			for (i = 0; i < 8; ++i) {
+				if (info.children[i].phy == PPV4_QOS_INVALID)
+					break;
+				seq_printf(s, "%u(%u) ",
+						info.children[i].id,
+						info.children[i].phy);
+			}
+			seq_puts(s, "\n");
+		}
+
+		if (info.type == PPV4_QOS_NODE_TYPE_QUEUE)  {
+			seq_printf(s, "Physical queue: %u\n",
+					info.queue_physical_id);
+			seq_printf(s, "Port: %u\n", info.port);
+		}
+
+		seq_printf(s, "Bandwidth: %u Kbps\n", info.bw_limit);
+	}
+	return 0;
+}
+
+static int pp_qos_dbg_node_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pp_qos_dbg_node_show, inode->i_private);
+}
+
+static const struct file_operations debug_node_fops = {
+	.open = pp_qos_dbg_node_open,
+	.read = seq_read,
+	.release = single_release,
+};
+
+static int pp_qos_dbg_stat_show(struct seq_file *s, void *unused)
+{
+	struct platform_device *pdev;
+	struct pp_qos_dev *qdev;
+	struct pp_qos_drv_data *pdata;
+	struct pp_qos_queue_stat qstat;
+	struct pp_qos_port_stat pstat;
+	struct qos_node *node;
+	unsigned int phy;
+	unsigned int id;
+
+	pdev = s->private;
+	dev_info(&pdev->dev, "node_show called\n");
+	if (pdev) {
+		pdata = platform_get_drvdata(pdev);
+		qdev = pdata->qdev;
+		if (!qdev->initialized) {
+			seq_puts(s, "Device is not initialized !!!!\n");
+			return 0;
+		}
+
+		id = pdata->dbg.node;
+		phy = get_phy_from_id(qdev->mapping, id);
+		if (!QOS_PHY_VALID(phy)) {
+			seq_printf(s, "Invalid id %u\n", id);
+			return 0;
+		}
+
+		node = get_node_from_phy(qdev->nodes, phy);
+		if (node_used(node)) {
+			seq_printf(s, "%u(%u) - ", id, phy);
+			if (node_queue(node)) {
+				seq_puts(s, "Queue\n");
+				memset(&qstat, 0, sizeof(qstat));
+				if (pp_qos_queue_stat_get(qdev, id, &qstat)
+						== 0) {
+					seq_printf(s, "queue_packets_occupancy:%u\n",
+						qstat.queue_packets_occupancy);
+					seq_printf(s, "queue_bytes_occupancy:%u\n",
+						qstat.queue_bytes_occupancy);
+					seq_printf(s, "total_packets_accepted:%u\n",
+						qstat.total_packets_accepted);
+					seq_printf(s, "total_packets_dropped:%u\n",
+						qstat.total_packets_dropped);
+					seq_printf(
+						s,
+						"total_packets_red_dropped:%u\n",
+						qstat.total_packets_red_dropped
+						);
+					seq_printf(s, "total_bytes_accepted:%llu\n",
+						qstat.total_bytes_accepted);
+					seq_printf(s, "total_bytes_dropped:%llu\n",
+						qstat.total_bytes_dropped);
+				} else {
+					seq_puts(s, "Could not obtained statistics\n");
+				}
+			} else if (node_port(node)) {
+				seq_puts(s, "Port\n");
+				memset(&pstat, 0, sizeof(pstat));
+				if (pp_qos_port_stat_get(qdev, id, &pstat)
+						== 0) {
+					seq_printf(
+						s,
+						"total_green_bytes in port's queues:%u\n",
+						pstat.total_green_bytes);
+					seq_printf(
+						s,
+						"total_yellow_bytes in port's queues:%u\n",
+						pstat.total_yellow_bytes);
+				} else {
+					seq_puts(s, "Could not obtained statistics\n");
+				}
+			} else {
+					seq_puts(s, "Node is not a queue or port, no statistics\n");
+			}
+		} else {
+			seq_printf(s, "Node %u is unused\n", id);
+		}
+	}
+	return 0;
+}
+
+static int pp_qos_dbg_stat_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pp_qos_dbg_stat_show, inode->i_private);
+}
+
+static const struct file_operations debug_stat_fops = {
+	.open = pp_qos_dbg_stat_open,
+	.read = seq_read,
+	.release = single_release,
+};
+
+static int pp_qos_dbg_gen_show(struct seq_file *s, void *unused)
+{
+	unsigned int i;
+	struct platform_device *pdev;
+	struct pp_qos_drv_data *pdata;
+	const struct qos_node *node;
+	struct pp_qos_dev *qdev;
+	unsigned int ports;
+	unsigned int queues;
+	unsigned int scheds;
+	unsigned int internals;
+	unsigned int used;
+	unsigned int major;
+	unsigned int minor;
+	unsigned int build;
+
+	pdev = s->private;
+	if (pdev) {
+		pdata = platform_get_drvdata(pdev);
+		qdev = pdata->qdev;
+		if (qdev->initialized) {
+			ports = 0;
+			scheds = 0;
+			queues = 0;
+			internals = 0;
+			used = 0;
+			node = get_node_from_phy(qdev->nodes, 0);
+			for (i = 0; i < NUM_OF_NODES; ++i) {
+				if (node_used(node)) {
+					++used;
+					if (node_port(node))
+						++ports;
+					else if (node_queue(node))
+						++queues;
+					else if (node_internal(node))
+						++internals;
+					else if (node_sched(node))
+						++scheds;
+				}
+				++node;
+			}
+
+			seq_printf(s, "Driver version: %s\n", PPV4_QOS_DRV_VER);
+			if (pp_qos_get_fw_version(
+						qdev,
+						&major,
+						&minor,
+						&build) == 0)
+				seq_printf(s, "FW version:\tmajor(%u) minor(%u) build(%u)\n",
+						major, minor, build);
+			else
+				seq_puts(s, "Could not obtain FW version\n");
+
+			seq_printf(s, "Used nodes:\t%u\nPorts:\t\t%u\nScheds:\t\t%u\nQueues:\t\t%u\nInternals:\t%u\n",
+					used, ports, scheds, queues, internals);
+		} else {
+			seq_puts(s, "Device is not initialized !!!!\n");
+		}
+
+	} else {
+		pr_err("Error, platform device was not found\n");
+	}
+
+	return 0;
+}
+
+static int pp_qos_dbg_gen_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pp_qos_dbg_gen_show, inode->i_private);
+}
+
+static const struct file_operations debug_gen_fops = {
+	.open = pp_qos_dbg_gen_open,
+	.read = seq_read,
+	.release = single_release,
+};
+
+
+static int dbg_cmd_open(struct inode *inode, struct file *filep)
+{
+	filep->private_data = inode->i_private;
+	return 0;
+}
+
+#define MAX_CMD_LEN 0x200
+static ssize_t dbg_cmd_write(struct file *fp, const char __user *user_buffer,
+			     size_t cnt, loff_t *pos)
+{
+	int rc;
+	int i;
+	uint8_t cmd[MAX_CMD_LEN];
+	struct platform_device *pdev;
+	struct pp_qos_drv_data *pdata;
+	struct pp_qos_dev *qdev;
+	uint32_t *dst;
+	uint32_t *src;
+
+	pdev = (struct platform_device *)(fp->private_data);
+	pdata = platform_get_drvdata(pdev);
+	qdev = pdata->qdev;
+
+	pr_info("qos drv address is %p\n", qdev);
+
+	if (cnt > MAX_CMD_LEN) {
+		dev_err(&pdev->dev, "Illegal length %zu\n", cnt);
+		return -EINVAL;
+	}
+
+	rc =  simple_write_to_buffer(cmd, MAX_CMD_LEN, pos, user_buffer, cnt);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "Write failed with %d\n", rc);
+		return rc;
+	}
+
+	dst = (uint32_t *)(qdev->fwcom.cmdbuf);
+	src = (uint32_t *)cmd;
+	dev_info(&pdev->dev, "Writing %d bytes into\n", rc);
+	for (i = 0; i < rc / 4; ++i) {
+		*dst++ = qos_u32_to_uc(*src++);
+		dev_info(&pdev->dev, "Wrote 0x%08X\n", dst[-1]);
+	}
+
+	signal_uc(qdev);
+
+	return rc;
+}
+
+static const struct file_operations debug_cmd_fops = {
+	.open = dbg_cmd_open,
+	.write = dbg_cmd_write,
+};
+
+static void swap_msg(char *msg)
+{
+	unsigned int i;
+	uint32_t *cur;
+
+	cur = (uint32_t *)msg;
+
+	for (i = 0; i < 32; ++i)
+		cur[i] = le32_to_cpu(cur[i]);
+}
+
+static void print_fw_log(struct platform_device *pdev)
+{
+	char		msg[128];
+	unsigned int	num;
+	unsigned int    i;
+	uint32_t	*addr;
+	uint32_t	read;
+	char		*cur;
+	struct device	*dev;
+	struct pp_qos_drv_data *pdata;
+
+	pdata = platform_get_drvdata(pdev);
+	addr = (uint32_t *)(pdata->dbg.fw_logger_addr);
+	num = qos_u32_from_uc(*addr);
+	read = qos_u32_from_uc(addr[1]);
+	dev = &pdev->dev;
+	cur = (char *)(pdata->dbg.fw_logger_addr + 8);
+
+	dev_info(dev, "addr is 0x%08X num of messages is %u, read index is %u",
+		 (unsigned int)(uintptr_t)cur,
+		 num,
+		 read);
+
+	for (i = read; i < num; ++i) {
+		memcpy((char *)msg, (char *)(cur + 128 * i), 128);
+		swap_msg(msg);
+		msg[127] = '\0';
+		dev_info(dev, "[ARC]: %s\n", msg);
+	}
+
+	addr[1] = num;
+}
+
+static int ctrl_set(void *data, u64 val)
+{
+	struct platform_device *pdev;
+	struct pp_qos_drv_data *pdata;
+
+	pdev = data;
+	dev_info(&pdev->dev, "ctrl got %llu", val);
+	pdata = platform_get_drvdata(pdev);
+
+	switch (val) {
+#ifdef PP_QOS_TEST
+	case 0:
+		QOS_LOG_INFO("running basic tests\n");
+		basic_tests();
+		break;
+	case 1:
+		QOS_LOG_INFO("running advance tests\n");
+		advance_tests();
+		break;
+	case 2:
+		QOS_LOG_INFO("running all tests\n");
+		tests();
+		break;
+	case 7:
+		QOS_LOG_INFO("running falcon test\n");
+		falcon_test();
+		break;
+	case 8:
+		QOS_LOG_INFO("running simple test\n");
+		stat_test();
+		break;
+	case 9:
+		QOS_LOG_INFO("running load fw test\n");
+		load_fw_test();
+		break;
+	case 10:
+		QOS_LOG_INFO("running stat test\n");
+		stat_test();
+		break;
+	case 11:
+		QOS_LOG_INFO("running info test\n");
+		info_test();
+		break;
+
+	case 14:
+		QOS_LOG_INFO("printing logger\n");
+		print_fw_log(pdev);
+		break;
+
+#endif
+
+	default:
+		QOS_LOG_INFO("unknown test\n");
+		break;
+	}
+
+	return 0;
+}
+
+static int phy2id_get(void *data, u64 *val)
+{
+	uint16_t id;
+	struct platform_device *pdev;
+	struct pp_qos_drv_data *pdata;
+	struct pp_qos_dev *qdev;
+
+	pdev = data;
+	pdata = platform_get_drvdata(pdev);
+	qdev = pdata->qdev;
+	if (!qdev->initialized) {
+		dev_err(&pdev->dev, "Device is not initialized\n");
+		id =  QOS_INVALID_ID;
+		goto out;
+	}
+
+	id = get_id_from_phy(qdev->mapping, pdata->dbg.node);
+out:
+	*val = id;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(dbg_ctrl_fops, NULL, ctrl_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(dbg_phy2id_fops, phy2id_get, NULL, "%llu\n");
+
+#define MAX_DIR_NAME 11
+int qos_dbg_dev_init(struct platform_device *pdev)
+{
+
+	struct pp_qos_drv_data *pdata;
+	char   dirname[MAX_DIR_NAME];
+	struct dentry *dent;
+	int err;
+
+	if (!pdev) {
+		dev_err(&pdev->dev, "Invalid platform device\n");
+		return -ENODEV;
+	}
+
+	pdata = platform_get_drvdata(pdev);
+
+	snprintf(dirname, MAX_DIR_NAME, "qos%d", pdata->id);
+	dent = debugfs_create_dir(dirname, dbg_data.dir);
+	if (IS_ERR_OR_NULL(dent)) {
+		err = (int) PTR_ERR(dent);
+		dev_err(&pdev->dev, "debugfs_create_dir failed with %d\n", err);
+		return err;
+	}
+
+	pdata->dbg.dir = dent;
+	dent = debugfs_create_file(
+			"nodeinfo",
+			0400,
+			pdata->dbg.dir,
+			pdev,
+			&debug_node_fops
+			);
+
+	if (IS_ERR_OR_NULL(dent)) {
+		err = (int) PTR_ERR(dent);
+		dev_err(&pdev->dev,
+			"debugfs_create_file failed creating nodeinfo with %d\n",
+			err);
+		goto fail;
+	}
+
+	dent = debugfs_create_file(
+			"stat",
+			0400,
+			pdata->dbg.dir,
+			pdev,
+			&debug_stat_fops
+			);
+
+	if (IS_ERR_OR_NULL(dent)) {
+		err = (int) PTR_ERR(dent);
+		dev_err(&pdev->dev,
+			"debugfs_create_file failed creating stat with %d\n",
+			err);
+		goto fail;
+	}
+
+	dent = debugfs_create_u16("node",
+			0600,
+			pdata->dbg.dir,
+			&pdata->dbg.node);
+	if (IS_ERR_OR_NULL(dent)) {
+		err = (int) PTR_ERR(dent);
+		dev_err(&pdev->dev,
+			"debugfs_create_u16 failed creating nodeinfo with %d\n",
+			err);
+		goto fail;
+	}
+
+	dent = debugfs_create_file(
+			"ctrl",
+			0200,
+			pdata->dbg.dir,
+			pdev,
+			&dbg_ctrl_fops
+			);
+	if (IS_ERR_OR_NULL(dent)) {
+		err = (int) PTR_ERR(dent);
+		dev_err(&pdev->dev,
+			"debugfs_create_file failed creating ctrl with %d\n",
+			err);
+		goto fail;
+	}
+
+	dent = debugfs_create_file(
+			"phy2id",
+			0400,
+			pdata->dbg.dir,
+			pdev,
+			&dbg_phy2id_fops
+			);
+	if (IS_ERR_OR_NULL(dent)) {
+		err = (int) PTR_ERR(dent);
+		dev_err(&pdev->dev,
+			"debugfs_create_file failed creating phy2id with %d\n",
+			err);
+		goto fail;
+	}
+
+	dent = debugfs_create_file(
+			"geninfo",
+			0400,
+			pdata->dbg.dir,
+			pdev,
+			&debug_gen_fops
+			);
+
+	if (IS_ERR_OR_NULL(dent)) {
+		err = (int) PTR_ERR(dent);
+		dev_err(&pdev->dev,
+			"debugfs_create_file failed creating geninfo with %d\n",
+			err);
+		goto fail;
+	}
+
+	dent = debugfs_create_file(
+			"cmd",
+			0200,
+			pdata->dbg.dir,
+			pdev,
+			&debug_cmd_fops
+			);
+
+	if (IS_ERR_OR_NULL(dent)) {
+		err = (int) PTR_ERR(dent);
+		dev_err(&pdev->dev,
+			"debugfs_create_file failed creating cmds with %d\n",
+			err);
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	debugfs_remove_recursive(pdata->dbg.dir);
+	return err;
+
+}
+
+void qos_dbg_dev_clean(struct platform_device *pdev)
+{
+	struct pp_qos_drv_data *pdata;
+
+	if (pdev) {
+		pdata = platform_get_drvdata(pdev);
+		if (pdata)
+			debugfs_remove_recursive(pdata->dbg.dir);
+	}
+}
+
+int qos_dbg_module_init(void)
+{
+	int rc;
+	struct dentry *dir;
+
+	dir = debugfs_create_dir(PP_QOS_DEBUGFS_DIR, NULL);
+	if (IS_ERR_OR_NULL(dir)) {
+		rc = (int) PTR_ERR(dir);
+		pr_err("debugfs_create_dir failed with %d\n", rc);
+		return rc;
+	}
+	dbg_data.dir = dir;
+	return 0;
+}
+
+void qos_dbg_module_clean(void)
+{
+	debugfs_remove_recursive(dbg_data.dir);
+}
diff --git a/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_fw.c b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_fw.c
new file mode 100644
index 0000000000000000000000000000000000000000..4c4b849b3c94f24ffd026481bda1f039e96fd2b6
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_fw.c
@@ -0,0 +1,2373 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+#include "pp_qos_common.h"
+#include "pp_qos_utils.h"
+#include "pp_qos_uc_wrapper.h"
+#include "pp_qos_fw.h"
+
+
+#ifdef __LP64__
+#define GET_ADDRESS_HIGH(addr) ((((uintptr_t)(addr)) >> 32) & 0xFFFFFFFF)
+#else
+#define GET_ADDRESS_HIGH(addr) (0)
+#endif
+
+#ifndef PP_QOS_DISABLE_CMDQ
+
+#define CMD_FLAGS_WRAP_SUSPEND_RESUME 1
+#define CMD_FLAGS_WRAP_PARENT_SUSPEND_RESUME 2
+#define CMD_FLAGS_POST_PROCESS	4
+
+
+#define FW_CMDS(OP) \
+	OP(CMD_TYPE_INIT_LOGGER)		\
+	OP(CMD_TYPE_INIT_QOS)			\
+	OP(CMD_TYPE_MOVE)			\
+	OP(CMD_TYPE_ADD_PORT)			\
+	OP(CMD_TYPE_SET_PORT)			\
+	OP(CMD_TYPE_REMOVE_PORT)		\
+	OP(CMD_TYPE_ADD_SCHED)			\
+	OP(CMD_TYPE_SET_SCHED)			\
+	OP(CMD_TYPE_REMOVE_SCHED)		\
+	OP(CMD_TYPE_ADD_QUEUE)			\
+	OP(CMD_TYPE_SET_QUEUE)			\
+	OP(CMD_TYPE_REMOVE_QUEUE)		\
+	OP(CMD_TYPE_UPDATE_PREDECESSORS)	\
+	OP(CMD_TYPE_PARENT_CHANGE)		\
+	OP(CMD_TYPE_REMOVE_NODE)		\
+	OP(CMD_TYPE_GET_QUEUE_STATS)		\
+	OP(CMD_TYPE_GET_PORT_STATS)		\
+	OP(CMD_TYPE_ADD_SHARED_GROUP)		\
+	OP(CMD_TYPE_PUSH_DESC)			\
+	OP(CMD_TYPE_GET_NODE_INFO)		\
+	OP(CMD_TYPE_REMOVE_SHARED_GROUP)	\
+	OP(CMD_TYPE_SET_SHARED_GROUP)
+
+enum cmd_type {
+	FW_CMDS(GEN_ENUM)
+};
+
+static const char *const cmd_str[] = {
+	FW_CMDS(GEN_STR)
+};
+
+struct ppv4_qos_fw_hdr {
+	uint32_t major;
+	uint32_t minor;
+	uint32_t build;
+};
+
+struct ppv4_qos_fw_sec {
+	uint32_t dst;
+	uint32_t size;
+};
+
+#define FW_OK_SIGN (0xCAFECAFEU)
+#define FW_DDR_LOWEST (0x400000U)
+
+static void copy_section(void *_dst, const void *_src, unsigned int size)
+{
+	unsigned int i;
+	const uint32_t *src;
+	uint32_t *dst;
+
+	src = (uint32_t *)_src;
+	dst = (uint32_t *)_dst;
+
+	for (i = size; i > 0; i -= 4)
+		*dst++ = cpu_to_le32(*src++);
+}
+
+/*
+ * This function loads the firmware.
+ * The firmware is built from a header which holds the major, minor
+ * and build numbers.
+ * Following the header are sections. Each section is composed of
+ * header which holds the memory destination where this section's
+ * data should be copied and the size of this section in bytes.
+ * After the header comes section's data which is a stream of uint32
+ * words.
+ * The memory destination on section header designates offset relative
+ * to either ddr (a.k.a external) or qos (a.k.a) spaces. Offsets higher
+ * than FW_DDR_LOWEST refer to ddr space.
+ *
+ * Firmware is little endian.
+ *
+ * When firmware runs it writes 0xCAFECAFE to offset FW_OK_OFFSET of ddr
+ * space.
+ */
+int do_load_firmware(
+		struct pp_qos_dev *qdev,
+		const struct ppv4_qos_fw *fw,
+		void *ddr_base,
+		void *qos_base,
+		void *data)
+{
+	size_t size;
+	struct ppv4_qos_fw_hdr *hdr;
+	const uint8_t *cur;
+	const uint8_t *last;
+	void *dst;
+	struct ppv4_qos_fw_sec *sec;
+	uint32_t val;
+
+	size = fw->size;
+	hdr = (struct ppv4_qos_fw_hdr *)(fw->data);
+	hdr->major = le32_to_cpu(hdr->major);
+	hdr->minor = le32_to_cpu(hdr->minor);
+	hdr->build = le32_to_cpu(hdr->build);
+	QOS_LOG_INFO("Firmware size(%zu) major(%u) minor(%u) build(%u)\n",
+			size,
+			hdr->major,
+			hdr->minor,
+			hdr->build);
+
+	if (hdr->major != UC_VERSION_MAJOR || hdr->minor != UC_VERSION_MINOR) {
+		QOS_LOG_ERR("mismatch major %u of minor %u\n",
+				UC_VERSION_MAJOR, UC_VERSION_MINOR);
+		return -EINVAL;
+	}
+
+	qdev->fwver.major = hdr->major;
+	qdev->fwver.minor = hdr->minor;
+	qdev->fwver.build = hdr->build;
+
+	last = fw->data + size - 1;
+	cur = (uint8_t *)(hdr + 1);
+	while (cur < last) {
+		sec = (struct ppv4_qos_fw_sec *)cur;
+		sec->dst = le32_to_cpu(sec->dst);
+		sec->size = le32_to_cpu(sec->size);
+		cur = (uint8_t *)(sec + 1);
+
+		if (sec->dst >= FW_DDR_LOWEST)
+			dst = ddr_base + sec->dst;
+		else
+			dst = qos_base + sec->dst;
+
+		QOS_LOG_DEBUG("Copying %u bytes (0x%08X) <-- (0x%08X)\n",
+				sec->size,
+				(unsigned int)(uintptr_t)(dst),
+				(unsigned int)(uintptr_t)(cur));
+
+		copy_section(dst, cur, sec->size);
+		cur += sec->size;
+	}
+
+	wake_uc(data);
+	QOS_LOG_DEBUG("waked fw\n");
+	qos_sleep(10);
+	val = *((uint32_t *)(ddr_base + FW_OK_OFFSET));
+	if (val != FW_OK_SIGN) {
+		QOS_LOG_ERR("FW OK value is 0x%08X, instead got 0x%08X\n",
+				FW_OK_SIGN, val);
+		return  -ENODEV;
+	}
+	QOS_LOG_INFO("FW is running :)\n");
+	*((uint32_t *)(ddr_base + FW_OK_OFFSET)) = 0;
+	return 0;
+}
+
+/******************************************************************************/
+/*                         Driver commands structures	                      */
+/******************************************************************************/
+struct cmd {
+	unsigned int id;
+	unsigned int fw_id;
+	unsigned int flags;
+	enum cmd_type  type;
+	size_t len;
+	uint32_t *pos;
+};
+
+struct cmd_init_logger {
+	struct cmd base;
+	unsigned int	addr;
+	int mode;
+	int level;
+	unsigned int num_of_msgs;
+};
+
+struct cmd_init_qos {
+	struct cmd base;
+	unsigned int qm_ddr_start;
+	unsigned int qm_num_pages;
+	unsigned int wred_total_avail_resources;
+	unsigned int wred_prioritize_pop;
+	unsigned int wred_avg_q_size_p;
+	unsigned int wred_max_q_size;
+	unsigned int num_of_ports;
+};
+
+struct cmd_move {
+	struct cmd base;
+	int      node_type;
+	uint16_t src;
+	uint16_t dst;
+	unsigned int rlm;
+	uint16_t dst_port;
+	uint16_t preds[6];
+};
+
+struct cmd_remove_node {
+	struct cmd base;
+	unsigned int phy;
+	unsigned int data; /* rlm in queue, otherwise irrlevant */
+};
+
+struct cmd_update_preds {
+	struct cmd base;
+	int node_type;
+	uint16_t preds[6];
+	unsigned int phy;
+};
+
+struct port_properties {
+	struct pp_qos_common_node_properties common;
+	struct pp_qos_parent_node_properties parent;
+	void *ring_addr;
+	size_t ring_size;
+	uint8_t  packet_credit_enable;
+	unsigned int credit;
+};
+
+struct cmd_add_port {
+	struct cmd base;
+	unsigned int phy;
+	struct port_properties prop;
+};
+
+struct cmd_set_port {
+	struct cmd base;
+	unsigned int phy;
+	struct port_properties prop;
+	uint32_t modified;
+};
+
+struct sched_properties {
+	struct pp_qos_common_node_properties common;
+	struct pp_qos_parent_node_properties parent;
+	struct pp_qos_child_node_properties  child;
+};
+
+struct cmd_add_sched {
+	struct cmd base;
+	unsigned int phy;
+	unsigned int parent;
+	uint16_t preds[6];
+	struct sched_properties prop;
+};
+
+struct cmd_set_sched {
+	struct cmd base;
+	unsigned int phy;
+	unsigned int parent;
+	struct sched_properties prop;
+	uint32_t modified;
+};
+
+struct queue_properties {
+	struct pp_qos_common_node_properties common;
+	struct pp_qos_child_node_properties  child;
+	uint8_t  blocked;
+	uint8_t  wred_enable;
+	uint8_t  fixed_drop_prob_enable;
+	unsigned int max_burst;
+	unsigned int queue_wred_min_avg_green;
+	unsigned int queue_wred_max_avg_green;
+	unsigned int queue_wred_slope_green;
+	unsigned int queue_wred_min_avg_yellow;
+	unsigned int queue_wred_max_avg_yellow;
+	unsigned int queue_wred_slope_yellow;
+	unsigned int queue_wred_min_guaranteed;
+	unsigned int queue_wred_max_allowed;
+	unsigned int queue_wred_fixed_drop_prob_green;
+	unsigned int queue_wred_fixed_drop_prob_yellow;
+	unsigned int      rlm;
+};
+
+struct cmd_add_queue {
+	struct cmd base;
+	unsigned int phy;
+	unsigned int parent;
+	unsigned int port;
+	uint16_t preds[6];
+	struct queue_properties prop;
+};
+
+struct cmd_set_queue {
+	struct cmd base;
+	unsigned int phy;
+	struct queue_properties prop;
+	uint32_t modified;
+};
+
+struct cmd_parent_change {
+	struct cmd base;
+	unsigned int phy;
+	int type;
+	int arbitration;
+	int first;
+	unsigned int num;
+};
+
+struct cmd_get_queue_stats {
+	struct cmd base;
+	unsigned int phy;
+	unsigned int rlm;
+	unsigned int addr;
+	struct pp_qos_queue_stat *stat;
+};
+
+struct cmd_get_port_stats {
+	struct cmd base;
+	unsigned int phy;
+	unsigned int addr;
+	struct pp_qos_port_stat *stat;
+};
+
+struct cmd_push_desc {
+	struct cmd base;
+	unsigned int queue;
+	unsigned int size;
+	unsigned int color;
+	unsigned int addr;
+};
+
+struct cmd_get_node_info {
+	struct cmd base;
+	unsigned int phy;
+	unsigned int addr;
+	struct pp_qos_node_info *info;
+};
+
+struct stub_cmd {
+	struct cmd cmd;
+	uint8_t data;
+};
+
+struct cmd_set_shared_group {
+	struct cmd base;
+	unsigned int id;
+	unsigned int limit;
+};
+
+struct cmd_remove_shared_group {
+	struct cmd base;
+	unsigned int id;
+};
+
+union driver_cmd {
+	struct cmd	 cmd;
+	struct stub_cmd  stub;
+	struct cmd_init_logger init_logger;
+	struct cmd_init_qos  init_qos;
+	struct cmd_move  move;
+	struct cmd_update_preds update_preds;
+	struct cmd_remove_node remove_node;
+	struct cmd_add_port add_port;
+	struct cmd_set_port set_port;
+	struct cmd_add_sched add_sched;
+	struct cmd_set_sched set_sched;
+	struct cmd_add_queue add_queue;
+	struct cmd_set_queue set_queue;
+	struct cmd_parent_change parent_change;
+	struct cmd_get_queue_stats queue_stats;
+	struct cmd_get_port_stats port_stats;
+	struct cmd_set_shared_group set_shared_group;
+	struct cmd_remove_shared_group remove_shared_group;
+	struct cmd_push_desc	pushd;
+	struct cmd_get_node_info node_info;
+};
+
+/******************************************************************************/
+/*                         Driver functions                                   */
+/******************************************************************************/
+
+/*
+ * Following functions creates commands in driver fromat to be stored at
+ * drivers queues before sending to firmware
+ */
+
+/*
+ * Extract ancestors of node from driver's DB
+ */
+static void fill_preds(
+		const struct pp_nodes *nodes,
+		unsigned int phy,
+		uint16_t *preds,
+		size_t size)
+{
+	unsigned int i;
+	const struct qos_node *node;
+
+	i = 0;
+	memset(preds, 0x0, size * sizeof(uint16_t));
+	node = get_const_node_from_phy(nodes, phy);
+	while (node_child(node) && (i < size)) {
+		preds[i] = node->child_prop.parent_phy;
+		node = get_const_node_from_phy(nodes,
+				node->child_prop.parent_phy);
+		i++;
+	}
+}
+
+static void cmd_init(
+		const struct pp_qos_dev *qdev,
+		struct cmd *cmd,
+		enum cmd_type type,
+		size_t len,
+		unsigned int flags)
+{
+	cmd->flags = flags;
+	cmd->type = type;
+	cmd->len = len;
+	cmd->id = qdev->drvcmds.cmd_id;
+	cmd->fw_id = qdev->drvcmds.cmd_fw_id;
+}
+
+/* TODO - make less hard code */
+void create_init_logger_cmd(struct pp_qos_dev *qdev)
+{
+	struct cmd_init_logger cmd;
+
+	cmd_init(qdev, &(cmd.base), CMD_TYPE_INIT_LOGGER, sizeof(cmd), 0);
+	cmd.addr = qdev->hwconf.fw_logger_start;
+	cmd.mode = UC_LOGGER_MODE_WRITE_HOST_MEM;
+	cmd.level = UC_LOGGER_LEVEL_DEBUG;
+	cmd.num_of_msgs = PPV4_QOS_LOGGER_BUF_SIZE / PPV4_QOS_LOGGER_MSG_SIZE;
+	QOS_LOG_INFO("cmd %u:%u CMD_TYPE_INIT_LOGGER\n",
+			qdev->drvcmds.cmd_id,
+			qdev->drvcmds.cmd_fw_id);
+	cmd_queue_put(qdev->drvcmds.cmdq, (uint8_t *)&cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+
+void create_init_qos_cmd(struct pp_qos_dev *qdev)
+{
+	struct cmd_init_qos cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	cmd_init(qdev, &(cmd.base), CMD_TYPE_INIT_QOS, sizeof(cmd), 0);
+	cmd.qm_ddr_start = qdev->hwconf.qm_ddr_start;
+	cmd.qm_num_pages = qdev->hwconf.qm_num_pages;
+	cmd.wred_total_avail_resources =
+		qdev->hwconf.wred_total_avail_resources;
+	cmd.wred_prioritize_pop = qdev->hwconf.wred_prioritize_pop;
+	cmd.wred_avg_q_size_p = qdev->hwconf.wred_const_p;
+	cmd.wred_max_q_size = qdev->hwconf.wred_max_q_size;
+	cmd.num_of_ports = qdev->max_port + 1;
+	QOS_LOG_INFO("cmd %u:%u CMD_TYPE_INIT_QOS\n",
+			qdev->drvcmds.cmd_id,
+			qdev->drvcmds.cmd_fw_id);
+	cmd_queue_put(qdev->drvcmds.cmdq, (uint8_t *)&cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+
+void create_move_cmd(
+		struct pp_qos_dev *qdev,
+		uint16_t dst,
+		uint16_t src,
+		uint16_t dst_port)
+{
+	struct cmd_move cmd;
+	const struct qos_node *node;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	node = get_const_node_from_phy(qdev->nodes, dst);
+
+	cmd_init(qdev, &(cmd.base), CMD_TYPE_MOVE, sizeof(cmd), 0);
+	cmd.src = src;
+	cmd.dst = dst;
+	cmd.dst_port = dst_port;
+	cmd.node_type = node->type;
+	if (node->type == TYPE_QUEUE)
+		cmd.rlm = node->data.queue.rlm;
+	else
+		cmd.rlm = -1;
+
+	fill_preds(qdev->nodes, dst, cmd.preds, 6);
+	QOS_LOG_INFO("cmd %u:%u CMD_TYPE_MOVE %u-->%u type:%d, rlm:%d, port:%u\n",
+			qdev->drvcmds.cmd_id,
+			qdev->drvcmds.cmd_fw_id,
+			src,
+			dst,
+			node->type,
+			cmd.rlm,
+			dst_port);
+	cmd_queue_put(qdev->drvcmds.cmdq, (uint8_t *)&cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+
+void create_remove_node_cmd(
+		struct pp_qos_dev *qdev,
+		enum node_type ntype,
+		unsigned int phy,
+		unsigned int data)
+{
+	struct cmd_remove_node cmd;
+	enum cmd_type ctype;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	switch (ntype) {
+	case TYPE_PORT:
+		ctype = CMD_TYPE_REMOVE_PORT;
+		break;
+	case TYPE_SCHED:
+		ctype = CMD_TYPE_REMOVE_SCHED;
+		break;
+	case TYPE_QUEUE:
+		ctype = CMD_TYPE_REMOVE_QUEUE;
+		break;
+	case TYPE_UNKNOWN:
+		QOS_ASSERT(0, "Unexpected unknow type\n");
+		ctype = CMD_TYPE_REMOVE_NODE;
+		break;
+	default:
+		QOS_LOG_INFO("illegal node type %d\n", ntype);
+		return;
+	}
+
+	cmd_init(qdev, &(cmd.base), ctype, sizeof(cmd), 0);
+	cmd.phy = phy;
+	cmd.data = data;
+
+	QOS_LOG_INFO("cmd %u:%u %s %u rlm %u\n",
+			qdev->drvcmds.cmd_id,
+			qdev->drvcmds.cmd_fw_id,
+			cmd_str[ctype], phy, data);
+	cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+
+void create_update_preds_cmd(struct pp_qos_dev *qdev, unsigned int phy)
+{
+	const struct qos_node *node;
+	struct cmd_update_preds cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd_init(
+			qdev,
+			&(cmd.base),
+			CMD_TYPE_UPDATE_PREDECESSORS,
+			sizeof(cmd),
+			0);
+	cmd.phy = phy;
+	fill_preds(qdev->nodes, phy, cmd.preds, 6);
+	node = get_const_node_from_phy(qdev->nodes, phy);
+	cmd.node_type = node->type;
+
+	QOS_LOG_INFO(
+			"cmd %u:%u CMD_TYPE_UPDATE_PREDECESSORS %u:%u-->%u-->%u-->%u-->%u-->%u\n",
+			qdev->drvcmds.cmd_id,
+			qdev->drvcmds.cmd_fw_id,
+			phy,
+			cmd.preds[0], cmd.preds[1], cmd.preds[2],
+			cmd.preds[3], cmd.preds[4], cmd.preds[5]);
+	cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+
+static void set_cmd_port_properties(
+		struct port_properties *prop,
+		const struct pp_qos_port_conf *conf)
+{
+	prop->common = conf->common_prop;
+	prop->parent = conf->port_parent_prop;
+	prop->packet_credit_enable = !!conf->packet_credit_enable;
+	prop->ring_addr = conf->ring_address;
+	prop->ring_size = conf->ring_size;
+	prop->credit = conf->credit;
+}
+
+static void create_add_port_cmd(
+		struct pp_qos_dev *qdev,
+		const struct pp_qos_port_conf *conf,
+		unsigned int phy)
+{
+	struct cmd_add_port cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd_init(qdev, &(cmd.base), CMD_TYPE_ADD_PORT, sizeof(cmd), 0);
+	cmd.phy = phy;
+	set_cmd_port_properties(&cmd.prop, conf);
+
+	QOS_LOG_INFO("cmd %u:%u CMD_TYPE_ADD_PORT %u\n",
+			qdev->drvcmds.cmd_id,
+			qdev->drvcmds.cmd_fw_id,
+			phy);
+	cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+
+void create_set_port_cmd(
+		struct pp_qos_dev *qdev,
+		const struct pp_qos_port_conf *conf,
+		unsigned int phy,
+		uint32_t modified)
+{
+	struct cmd_set_port cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_NODE_TYPE)) {
+		create_add_port_cmd(qdev, conf, phy);
+	} else {
+		memset(&cmd, 0, sizeof(cmd));
+		cmd_init(qdev, &(cmd.base), CMD_TYPE_SET_PORT, sizeof(cmd), 0);
+		cmd.phy = phy;
+		set_cmd_port_properties(&cmd.prop, conf);
+		cmd.modified = modified;
+		QOS_LOG_INFO("cmd %u:%u CMD_TYPE_SET_PORT %u\n",
+				qdev->drvcmds.cmd_id,
+				qdev->drvcmds.cmd_fw_id,
+				phy);
+		cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+		qdev->drvcmds.cmd_fw_id++;
+	}
+}
+
+static void set_cmd_sched_properties(
+		struct sched_properties *prop,
+		const struct pp_qos_sched_conf *conf)
+{
+	prop->common = conf->common_prop;
+	prop->parent = conf->sched_parent_prop;
+	prop->child = conf->sched_child_prop;
+}
+
+static void create_add_sched_cmd(
+		struct pp_qos_dev *qdev,
+		const struct pp_qos_sched_conf *conf,
+		unsigned int phy,
+		unsigned int parent)
+{
+	struct cmd_add_sched cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd_init(qdev, &(cmd.base), CMD_TYPE_ADD_SCHED, sizeof(cmd), 0);
+	cmd.phy = phy;
+	cmd.parent = parent;
+	fill_preds(qdev->nodes, phy, cmd.preds, 6);
+	set_cmd_sched_properties(&cmd.prop, conf);
+
+	QOS_LOG_INFO("cmd %u:%u CMD_TYPE_ADD_SCHED %u\n",
+			qdev->drvcmds.cmd_id,
+			qdev->drvcmds.cmd_fw_id, phy);
+	cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+
+void create_set_sched_cmd(
+		struct pp_qos_dev *qdev,
+		const struct pp_qos_sched_conf *conf,
+		unsigned int phy,
+		unsigned int parent,
+		uint32_t modified)
+{
+	struct cmd_set_sched cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_NODE_TYPE)) {
+		create_add_sched_cmd(qdev, conf, phy, parent);
+	} else {
+		memset(&cmd, 0, sizeof(cmd));
+		cmd_init(qdev, &(cmd.base), CMD_TYPE_SET_SCHED, sizeof(cmd), 0);
+		cmd.phy = phy;
+		set_cmd_sched_properties(&cmd.prop, conf);
+		cmd.modified = modified;
+		QOS_LOG_INFO("cmd %u:%u CMD_TYPE_SET_SCHED %u\n",
+				qdev->drvcmds.cmd_id,
+				qdev->drvcmds.cmd_fw_id, phy);
+		cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+		qdev->drvcmds.cmd_fw_id++;
+	}
+}
+
+static void set_cmd_queue_properties(
+		struct queue_properties *prop,
+		const struct pp_qos_queue_conf *conf,
+		unsigned int rlm)
+{
+	prop->common = conf->common_prop;
+	prop->child = conf->queue_child_prop;
+	prop->blocked = !!conf->blocked;
+	prop->wred_enable = !!conf->wred_enable;
+	prop->fixed_drop_prob_enable = !!conf->wred_fixed_drop_prob_enable;
+	prop->max_burst =  conf->max_burst;
+	prop->queue_wred_min_avg_green = conf->queue_wred_min_avg_green;
+	prop->queue_wred_max_avg_green = conf->queue_wred_max_avg_green;
+	prop->queue_wred_slope_green = conf->queue_wred_slope_green;
+	prop->queue_wred_min_avg_yellow = conf->queue_wred_min_avg_yellow;
+	prop->queue_wred_max_avg_yellow = conf->queue_wred_max_avg_yellow;
+	prop->queue_wred_slope_yellow = conf->queue_wred_slope_yellow;
+	prop->queue_wred_min_guaranteed = conf->queue_wred_min_guaranteed;
+	prop->queue_wred_max_allowed = conf->queue_wred_max_allowed;
+	prop->queue_wred_fixed_drop_prob_green =
+		conf->queue_wred_fixed_drop_prob_green;
+	prop->queue_wred_fixed_drop_prob_yellow =
+		conf->queue_wred_fixed_drop_prob_yellow;
+	prop->rlm = rlm;
+}
+
+static void create_add_queue_cmd(
+		struct pp_qos_dev *qdev,
+		const struct pp_qos_queue_conf *conf,
+		unsigned int phy,
+		unsigned int parent,
+		unsigned int rlm)
+{
+	struct cmd_add_queue cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd_init(
+			qdev,
+			&(cmd.base),
+			CMD_TYPE_ADD_QUEUE,
+			sizeof(cmd),
+			CMD_FLAGS_WRAP_PARENT_SUSPEND_RESUME);
+	cmd.phy = phy;
+	cmd.parent = parent;
+
+	cmd.port = get_port(qdev->nodes, phy);
+
+	fill_preds(qdev->nodes, phy, cmd.preds, 6);
+	set_cmd_queue_properties(&cmd.prop, conf, rlm);
+
+	QOS_LOG_INFO("cmd %u:%u CMD_TYPE_ADD_QUEUE %u\n",
+			qdev->drvcmds.cmd_id,
+			qdev->drvcmds.cmd_fw_id,
+			phy);
+	cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+
+}
+
+void create_set_queue_cmd(
+		struct pp_qos_dev *qdev,
+		const struct pp_qos_queue_conf *conf,
+		unsigned int phy,
+		unsigned int parent,
+		unsigned int rlm,
+		uint32_t modified)
+{
+	struct cmd_set_queue cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_NODE_TYPE)) {
+		create_add_queue_cmd(qdev, conf, phy, parent, rlm);
+	} else {
+		memset(&cmd, 0, sizeof(cmd));
+		cmd_init(
+				qdev,
+				&(cmd.base),
+				CMD_TYPE_SET_QUEUE,
+				sizeof(cmd),
+				CMD_FLAGS_WRAP_SUSPEND_RESUME |
+				CMD_FLAGS_WRAP_PARENT_SUSPEND_RESUME);
+		cmd.phy = phy;
+		set_cmd_queue_properties(&cmd.prop, conf, rlm);
+		cmd.modified = modified;
+		QOS_LOG_INFO("cmd %u:%u CMD_TYPE_SET_QUEUE %u\n",
+				qdev->drvcmds.cmd_id,
+				qdev->drvcmds.cmd_fw_id, phy);
+		cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+		qdev->drvcmds.cmd_fw_id++;
+	}
+}
+
+void create_parent_change_cmd(struct pp_qos_dev *qdev, unsigned int phy)
+{
+	struct cmd_parent_change cmd;
+	const struct qos_node *node;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	node = get_const_node_from_phy(qdev->nodes, phy);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd_init(qdev, &(cmd.base), CMD_TYPE_PARENT_CHANGE, sizeof(cmd), 0);
+	cmd.phy = phy;
+	cmd.type = node->type;
+	cmd.arbitration = node->parent_prop.arbitration;
+	cmd.first = node->parent_prop.first_child_phy;
+	cmd.num = node->parent_prop.num_of_children;
+	QOS_LOG_INFO("cmd %u:%u CMD_TYPE_PARENT_CHANGE %u first:%u num:%d\n",
+			qdev->drvcmds.cmd_id,
+			qdev->drvcmds.cmd_fw_id,
+			phy,
+			cmd.first,
+			cmd.num);
+	cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+
+void create_get_port_stats_cmd(
+		struct pp_qos_dev *qdev,
+		unsigned int phy,
+		unsigned int addr,
+		struct pp_qos_port_stat *pstat)
+{
+	struct cmd_get_port_stats cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd_init(
+			qdev,
+			&(cmd.base),
+			CMD_TYPE_GET_PORT_STATS,
+			sizeof(cmd),
+			CMD_FLAGS_POST_PROCESS);
+	cmd.phy = phy;
+	cmd.addr =  addr;
+	cmd.stat = pstat;
+	QOS_LOG_INFO("cmd %u:%u CMD_TYPE_GET_PORT_STATS %u\n",
+			qdev->drvcmds.cmd_id,
+			qdev->drvcmds.cmd_fw_id,
+			phy);
+	cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+
+void create_get_queue_stats_cmd(
+		struct pp_qos_dev *qdev,
+		unsigned int phy,
+		unsigned int rlm,
+		unsigned int addr,
+		struct pp_qos_queue_stat *qstat)
+{
+	struct cmd_get_queue_stats cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd_init(
+			qdev,
+			&(cmd.base),
+			CMD_TYPE_GET_QUEUE_STATS,
+			sizeof(cmd),
+			CMD_FLAGS_POST_PROCESS);
+	cmd.phy = phy;
+	cmd.rlm = rlm;
+	cmd.addr =  addr;
+	cmd.stat = qstat;
+	QOS_LOG_INFO("cmd %u:%u CMD_TYPE_GET_QUEUE_STATS %u\n",
+			qdev->drvcmds.cmd_id,
+			qdev->drvcmds.cmd_fw_id,
+			phy);
+	cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+
+void create_get_node_info_cmd(
+		struct pp_qos_dev *qdev,
+		unsigned int phy,
+		unsigned int addr,
+		struct pp_qos_node_info *info)
+{
+	struct cmd_get_node_info cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd_init(
+			qdev,
+			&(cmd.base),
+			CMD_TYPE_GET_NODE_INFO,
+			sizeof(cmd),
+			CMD_FLAGS_POST_PROCESS);
+	cmd.phy = phy;
+	cmd.addr =  addr;
+	cmd.info = info;
+	QOS_LOG_INFO("cmd %u:%u CMD_TYPE_GET_NODE_INFO %u\n",
+			qdev->drvcmds.cmd_id,
+			qdev->drvcmds.cmd_fw_id,
+			phy);
+	cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+
+static void _create_set_shared_group_cmd(struct pp_qos_dev *qdev,
+		enum cmd_type ctype,
+		unsigned int id,
+		unsigned int limit)
+{
+	struct cmd_set_shared_group cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	cmd_init(qdev, &(cmd.base), ctype, sizeof(cmd), 0);
+	cmd.id = id;
+	cmd.limit = limit;
+	QOS_LOG("cmd %u:%u %s id %u limit %u\n",
+		qdev->drvcmds.cmd_id,
+		qdev->drvcmds.cmd_fw_id,
+		cmd_str[ctype],
+		id, limit);
+	cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+
+void create_add_shared_group_cmd(struct pp_qos_dev *qdev,
+		unsigned int id,
+		unsigned int limit)
+{
+	_create_set_shared_group_cmd(qdev, CMD_TYPE_ADD_SHARED_GROUP,
+			id, limit);
+}
+
+void create_set_shared_group_cmd(struct pp_qos_dev *qdev,
+		unsigned int id,
+		unsigned int limit)
+{
+	_create_set_shared_group_cmd(qdev, CMD_TYPE_SET_SHARED_GROUP,
+			id, limit);
+}
+
+void create_remove_shared_group_cmd(struct pp_qos_dev *qdev,
+		unsigned int id)
+{
+	struct cmd_remove_shared_group cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	cmd_init(
+			qdev,
+			&(cmd.base),
+			CMD_TYPE_REMOVE_SHARED_GROUP,
+			sizeof(cmd), 0);
+	cmd.id = id;
+	QOS_LOG_INFO("cmd %u:%u CMD_TYPE_REMOVE_SHARED_GROUP id %u\n",
+			qdev->drvcmds.cmd_id,
+			qdev->drvcmds.cmd_fw_id,
+			id);
+	cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+
+void create_push_desc_cmd(struct pp_qos_dev *qdev, unsigned int queue,
+		unsigned int size, unsigned int color, unsigned int addr)
+{
+	struct cmd_push_desc cmd;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	cmd_init(qdev, &(cmd.base), CMD_TYPE_PUSH_DESC, sizeof(cmd), 0);
+	cmd.queue = queue;
+	cmd.size = size;
+	cmd.color = color;
+	cmd.addr = addr;
+	cmd_queue_put(qdev->drvcmds.cmdq, &cmd, sizeof(cmd));
+	qdev->drvcmds.cmd_fw_id++;
+}
+/******************************************************************************/
+/*                                 FW CMDS                                    */
+/******************************************************************************/
+
+struct fw_set_common {
+	uint32_t valid;
+	int suspend;
+	unsigned int bw_limit;
+	unsigned int shared_bw_group;
+};
+
+struct fw_set_parent {
+	uint32_t valid;
+	int best_effort_enable;
+	uint16_t first;
+	uint16_t last;
+	uint16_t first_wrr;
+};
+
+struct fw_set_child {
+	uint32_t valid;
+	uint32_t bw_share;
+	uint16_t preds[6];
+};
+
+struct fw_set_port {
+	uint32_t valid;
+	void	 *ring_addr;
+	size_t	 ring_size;
+};
+
+struct fw_set_sched {
+	uint32_t valid;
+};
+
+struct fw_set_queue {
+	uint32_t valid;
+	unsigned int rlm;
+	int active;
+	uint32_t disable;
+	unsigned int queue_wred_min_avg_green;
+	unsigned int queue_wred_max_avg_green;
+	unsigned int queue_wred_slope_green;
+	unsigned int queue_wred_min_avg_yellow;
+	unsigned int queue_wred_max_avg_yellow;
+	unsigned int queue_wred_slope_yellow;
+	unsigned int queue_wred_min_guaranteed;
+	unsigned int queue_wred_max_allowed;
+	unsigned int queue_wred_fixed_drop_prob_green;
+	unsigned int queue_wred_fixed_drop_prob_yellow;
+};
+
+struct fw_internal {
+	struct fw_set_common common;
+	struct fw_set_parent parent;
+	struct fw_set_child  child;
+	union {
+		struct fw_set_port port;
+		struct fw_set_sched sched;
+		struct fw_set_queue queue;
+	} type_data;
+	unsigned int	pushed;
+};
+
+/******************************************************************************/
+/*                         FW write functions                                 */
+/******************************************************************************/
+
+int init_fwdata_internals(struct pp_qos_dev *qdev)
+{
+	qdev->fwbuf = QOS_MALLOC(sizeof(struct fw_internal));
+	if (qdev->fwbuf) {
+		memset(qdev->fwbuf, 0, sizeof(struct fw_internal));
+		return 0;
+	}
+	return -EBUSY;
+}
+
+void clean_fwdata_internals(struct pp_qos_dev *qdev)
+{
+	if (qdev->fwbuf)
+		QOS_FREE(qdev->fwbuf);
+}
+
+/*
+ * Following functions translate driver commands to firmware
+ * commands
+ */
+static uint32_t *fw_write_init_logger_cmd(
+		uint32_t *buf,
+		const struct cmd_init_logger *cmd,
+		uint32_t flags)
+{
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_INIT_UC_LOGGER);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(4);
+	*buf++ = qos_u32_to_uc((uintptr_t)cmd->addr & 0xFFFFFFFF);
+	*buf++ = qos_u32_to_uc(cmd->mode);
+	*buf++ = qos_u32_to_uc(cmd->level);
+	*buf++ = qos_u32_to_uc(cmd->num_of_msgs);
+	return buf;
+}
+
+static uint32_t *fw_write_init_qos_cmd(
+		uint32_t *buf,
+		const struct cmd_init_qos *cmd,
+		uint32_t flags)
+{
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_INIT_QOS);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(7);
+	*buf++ = qos_u32_to_uc(cmd->qm_ddr_start & 0xFFFFFFFF);
+	*buf++ = qos_u32_to_uc(cmd->qm_num_pages);
+	*buf++ = qos_u32_to_uc(cmd->wred_total_avail_resources);
+	*buf++ = qos_u32_to_uc(cmd->wred_prioritize_pop);
+	*buf++ = qos_u32_to_uc(cmd->wred_avg_q_size_p);
+	*buf++ = qos_u32_to_uc(cmd->wred_max_q_size);
+	*buf++ = qos_u32_to_uc(cmd->num_of_ports);
+	return buf;
+}
+
+static uint32_t *fw_write_add_port_cmd(
+		uint32_t *buf,
+		const struct cmd_add_port *cmd,
+		uint32_t flags)
+{
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_ADD_PORT);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(13);
+	*buf++ = qos_u32_to_uc(cmd->phy);
+	*buf++ = qos_u32_to_uc(!!cmd->prop.common.suspended);
+	*buf++ = qos_u32_to_uc(0);
+	*buf++ = qos_u32_to_uc(0);
+	*buf++ = qos_u32_to_uc(cmd->prop.common.bandwidth_limit);
+	*buf++ = qos_u32_to_uc(!!cmd->prop.parent.best_effort_enable);
+	*buf++ = qos_u32_to_uc(0);
+	*buf++ = qos_u32_to_uc(cmd->prop.common.shared_bandwidth_group);
+	*buf++ = qos_u32_to_uc(cmd->prop.packet_credit_enable);
+	*buf++ = qos_u32_to_uc(cmd->prop.ring_size);
+	*buf++ = qos_u32_to_uc(GET_ADDRESS_HIGH(cmd->prop.ring_addr));
+	*buf++ = qos_u32_to_uc(((uintptr_t)cmd->prop.ring_addr) & 0xFFFFFFFF);
+	*buf++ = qos_u32_to_uc(cmd->prop.credit);
+	return buf;
+}
+
+static uint32_t *fw_write_set_port_cmd(
+		uint32_t *buf,
+		unsigned int phy,
+		uint32_t flags,
+		const struct fw_set_common *common,
+		const struct fw_set_parent *parent,
+		const struct fw_set_port *port)
+{
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_SET_PORT);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(13);
+	*buf++ = qos_u32_to_uc(phy);
+	*buf++ = qos_u32_to_uc(common->valid | parent->valid | port->valid);
+	*buf++ = qos_u32_to_uc(common->suspend);
+	*buf++ = qos_u32_to_uc(parent->first);
+	*buf++ = qos_u32_to_uc(parent->last);
+	*buf++ = qos_u32_to_uc(common->bw_limit);
+	*buf++ = qos_u32_to_uc(parent->best_effort_enable);
+	*buf++ = qos_u32_to_uc(parent->first_wrr);
+	*buf++ = qos_u32_to_uc(common->shared_bw_group);
+	*buf++ = qos_u32_to_uc(port->valid);
+	*buf++ = qos_u32_to_uc(port->ring_size);
+	*buf++ = qos_u32_to_uc(GET_ADDRESS_HIGH(port->ring_addr));
+	*buf++ = qos_u32_to_uc(((uintptr_t)port->ring_addr) & 0xFFFFFFFF);
+	return buf;
+}
+
+static uint32_t *fw_write_add_sched_cmd(
+		uint32_t *buf,
+		const struct cmd_add_sched *cmd,
+		uint32_t flags)
+{
+	unsigned int i;
+
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_ADD_SCHEDULER);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(14);
+	*buf++ = qos_u32_to_uc(cmd->phy);
+	*buf++ = qos_u32_to_uc(!!cmd->prop.common.suspended);
+	*buf++ = qos_u32_to_uc(0);
+	*buf++ = qos_u32_to_uc(0);
+	*buf++ = qos_u32_to_uc(cmd->prop.common.bandwidth_limit);
+	*buf++ = qos_u32_to_uc(!!cmd->prop.parent.best_effort_enable);
+	*buf++ = qos_u32_to_uc(0);
+	*buf++ = qos_u32_to_uc(cmd->prop.common.shared_bandwidth_group);
+	for (i = 0; i < 6; ++i)
+		*buf++ = qos_u32_to_uc(cmd->preds[i]);
+
+	return buf;
+}
+
+static uint32_t *fw_write_set_sched_cmd(
+		uint32_t *buf,
+		unsigned int phy,
+		uint32_t flags,
+		const struct fw_set_common *common,
+		const struct fw_set_parent *parent,
+		const struct fw_set_child *child,
+		const struct fw_set_sched *sched)
+{
+	unsigned int i;
+
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_SET_SCHEDULER);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(15);
+	*buf++ = qos_u32_to_uc(phy);
+	*buf++ = qos_u32_to_uc(common->valid | parent->valid |
+			child->valid | sched->valid);
+	*buf++ = qos_u32_to_uc(common->suspend);
+	*buf++ = qos_u32_to_uc(parent->first);
+	*buf++ = qos_u32_to_uc(parent->last);
+	*buf++ = qos_u32_to_uc(common->bw_limit);
+	*buf++ = qos_u32_to_uc(parent->best_effort_enable);
+	*buf++ = qos_u32_to_uc(parent->first_wrr);
+	*buf++ = qos_u32_to_uc(common->shared_bw_group);
+
+	for (i = 0; i < 6; ++i)
+		*buf++ = qos_u32_to_uc(child->preds[i]);
+
+	return buf;
+}
+
+static uint32_t *fw_write_add_queue_cmd(
+		uint32_t *buf,
+		const struct cmd_add_queue *cmd,
+		uint32_t flags)
+{
+	unsigned int i;
+	uint32_t disable;
+
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_ADD_QUEUE);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(24);
+	*buf++ = qos_u32_to_uc(cmd->phy);
+	*buf++ = qos_u32_to_uc(cmd->port);
+	*buf++ = qos_u32_to_uc(cmd->prop.rlm);
+	*buf++ = qos_u32_to_uc(!!cmd->prop.common.suspended);
+	*buf++ = qos_u32_to_uc(cmd->prop.common.bandwidth_limit);
+	*buf++ = qos_u32_to_uc(cmd->prop.common.shared_bandwidth_group);
+	for (i = 0; i < 6; ++i)
+		*buf++ = qos_u32_to_uc(cmd->preds[i]);
+	*buf++ = qos_u32_to_uc(!cmd->prop.blocked);
+
+	disable = 0;
+	if (!cmd->prop.wred_enable)
+		QOS_BITS_SET(disable, 1);
+	if (cmd->prop.fixed_drop_prob_enable)
+		QOS_BITS_SET(disable, 8);
+	*buf++ = qos_u32_to_uc(disable);
+
+	*buf++ = qos_u32_to_uc(cmd->prop.queue_wred_fixed_drop_prob_green);
+	*buf++ = qos_u32_to_uc(cmd->prop.queue_wred_fixed_drop_prob_yellow);
+	*buf++ = qos_u32_to_uc(cmd->prop.queue_wred_min_avg_yellow);
+	*buf++ = qos_u32_to_uc(cmd->prop.queue_wred_max_avg_yellow);
+	*buf++ = qos_u32_to_uc(cmd->prop.queue_wred_slope_yellow);
+	*buf++ = qos_u32_to_uc(cmd->prop.queue_wred_min_avg_green);
+	*buf++ = qos_u32_to_uc(cmd->prop.queue_wred_max_avg_green);
+	*buf++ = qos_u32_to_uc(cmd->prop.queue_wred_slope_green);
+	*buf++ = qos_u32_to_uc(cmd->prop.queue_wred_min_guaranteed);
+	*buf++ = qos_u32_to_uc(cmd->prop.queue_wred_max_allowed);
+	return buf;
+}
+
+static uint32_t *fw_write_set_queue_cmd(
+		uint32_t *buf,
+		unsigned int phy,
+		uint32_t flags,
+		const struct fw_set_common *common,
+		const struct fw_set_child *child,
+		const struct fw_set_queue *queue)
+{
+	unsigned int i;
+
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_SET_QUEUE);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(25);
+	*buf++ = qos_u32_to_uc(phy);
+	*buf++ = qos_u32_to_uc(queue->rlm);
+	*buf++ = qos_u32_to_uc(common->valid | child->valid);
+	*buf++ = qos_u32_to_uc(common->suspend);
+	*buf++ = qos_u32_to_uc(common->bw_limit);
+	*buf++ = qos_u32_to_uc(common->shared_bw_group);
+	for (i = 0; i < 6; ++i)
+		*buf++ = qos_u32_to_uc(child->preds[i]);
+	*buf++ = qos_u32_to_uc(queue->valid);
+	*buf++ = qos_u32_to_uc(queue->active);
+	*buf++ = qos_u32_to_uc(queue->disable);
+
+	*buf++ = qos_u32_to_uc(queue->queue_wred_fixed_drop_prob_green);
+	*buf++ = qos_u32_to_uc(queue->queue_wred_fixed_drop_prob_yellow);
+	*buf++ = qos_u32_to_uc(queue->queue_wred_min_avg_yellow);
+	*buf++ = qos_u32_to_uc(queue->queue_wred_max_avg_yellow);
+	*buf++ = qos_u32_to_uc(queue->queue_wred_slope_yellow);
+	*buf++ = qos_u32_to_uc(queue->queue_wred_min_avg_green);
+	*buf++ = qos_u32_to_uc(queue->queue_wred_max_avg_green);
+	*buf++ = qos_u32_to_uc(queue->queue_wred_slope_green);
+	*buf++ = qos_u32_to_uc(queue->queue_wred_min_guaranteed);
+	*buf++ = qos_u32_to_uc(queue->queue_wred_max_allowed);
+
+	return buf;
+}
+
+static uint32_t *fw_write_move_sched_cmd(
+		uint32_t *buf,
+		const struct cmd_move *cmd,
+		uint32_t flags)
+{
+	unsigned int i;
+
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_MOVE_SCHEDULER);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(8);
+	*buf++ = qos_u32_to_uc(cmd->src);
+	*buf++ = qos_u32_to_uc(cmd->dst);
+
+	for (i = 0; i < 6; ++i)
+		*buf++ = qos_u32_to_uc(cmd->preds[i]);
+
+	return buf;
+}
+
+static uint32_t *fw_write_move_queue_cmd(
+		uint32_t *buf,
+		const struct cmd_move *cmd,
+		uint32_t flags)
+{
+	unsigned int i;
+
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_MOVE_QUEUE);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(10);
+	*buf++ = qos_u32_to_uc(cmd->src);
+	*buf++ = qos_u32_to_uc(cmd->dst);
+	*buf++ = qos_u32_to_uc(cmd->dst_port);
+	*buf++ = qos_u32_to_uc(cmd->rlm);
+
+	for (i = 0; i < 6; ++i)
+		*buf++ = qos_u32_to_uc(cmd->preds[i]);
+
+	return buf;
+}
+
+static uint32_t *fw_write_remove_queue_cmd(
+		uint32_t *buf,
+		const struct cmd_remove_node *cmd,
+		uint32_t flags)
+{
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_REMOVE_QUEUE);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(2);
+	*buf++ = qos_u32_to_uc(cmd->phy);
+	*buf++ = qos_u32_to_uc(cmd->data);
+	return buf;
+}
+
+static uint32_t *fw_write_remove_sched_cmd(
+		uint32_t *buf,
+		const struct cmd_remove_node *cmd,
+		uint32_t flags)
+{
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_REMOVE_SCHEDULER);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(1);
+	*buf++ = qos_u32_to_uc(cmd->phy);
+	return buf;
+}
+
+static uint32_t *fw_write_remove_port_cmd(
+		uint32_t *buf,
+		const struct cmd_remove_node *cmd,
+		uint32_t flags)
+{
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_REMOVE_PORT);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(1);
+	*buf++ = qos_u32_to_uc(cmd->phy);
+	return buf;
+}
+
+static uint32_t *fw_write_get_queue_stats(
+		uint32_t *buf,
+		const struct cmd_get_queue_stats *cmd,
+		uint32_t flags)
+{
+	uint32_t reset;
+
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_GET_QUEUE_STATS);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(4);
+	*buf++ = qos_u32_to_uc(cmd->phy);
+	*buf++ = qos_u32_to_uc(cmd->rlm);
+	*buf++ = qos_u32_to_uc((uintptr_t)cmd->addr & 0xFFFFFFFF);
+	if (cmd->stat->reset)
+		reset = QUEUE_STATS_CLEAR_Q_AVG_SIZE_BYTES |
+			QUEUE_STATS_CLEAR_DROP_P_YELLOW |
+			QUEUE_STATS_CLEAR_DROP_P_GREEN |
+			QUEUE_STATS_CLEAR_TOTAL_BYTES_ADDED |
+			QUEUE_STATS_CLEAR_TOTAL_ACCEPTS |
+			QUEUE_STATS_CLEAR_TOTAL_DROPS |
+			QUEUE_STATS_CLEAR_TOTAL_DROPPED_BYTES |
+			QUEUE_STATS_CLEAR_TOTAL_RED_DROPS;
+	else
+		reset = QUEUE_STATS_CLEAR_NONE;
+	*buf++ = qos_u32_to_uc(reset);
+
+	return buf;
+}
+
+static uint32_t *fw_write_get_port_stats(
+		uint32_t *buf,
+		const struct cmd_get_port_stats *cmd,
+		uint32_t flags)
+{
+	uint32_t reset;
+
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_GET_PORT_STATS);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(3);
+	*buf++ = qos_u32_to_uc(cmd->phy);
+	*buf++ = qos_u32_to_uc((uintptr_t)cmd->addr & 0xFFFFFFFF);
+	if (cmd->stat->reset)
+		reset = PORT_STATS_CLEAR_ALL;
+	else
+		reset = PORT_STATS_CLEAR_NONE;
+	*buf++ = qos_u32_to_uc(reset);
+	return buf;
+}
+
+static uint32_t *fw_write_set_shared_group(
+		uint32_t *buf,
+		enum cmd_type ctype,
+		const struct cmd_set_shared_group *cmd,
+		uint32_t flags)
+{
+	uint32_t uc_cmd;
+
+	if (ctype == CMD_TYPE_ADD_SHARED_GROUP)
+		uc_cmd = UC_QOS_COMMAND_ADD_SHARED_BW_LIMIT_GROUP;
+	else
+		uc_cmd = UC_QOS_COMMAND_SET_SHARED_BW_LIMIT_GROUP;
+
+	*buf++ = qos_u32_to_uc(uc_cmd);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(2);
+	*buf++ = qos_u32_to_uc(cmd->id);
+	*buf++ = qos_u32_to_uc(cmd->limit);
+	return buf;
+}
+
+static uint32_t *fw_write_remove_shared_group(uint32_t *buf,
+		const struct cmd_remove_shared_group *cmd,
+		uint32_t flags)
+{
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_REMOVE_SHARED_BW_LIMIT_GROUP);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(1);
+	*buf++ = qos_u32_to_uc(cmd->id);
+	return buf;
+}
+
+static uint32_t *fw_write_push_desc(
+		uint32_t *buf,
+		const struct cmd_push_desc *cmd,
+		uint32_t flags)
+{
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_DEBUG_PUSH_DESC);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(6);
+	*buf++ = qos_u32_to_uc(cmd->queue);
+	*buf++ = qos_u32_to_uc(cmd->size);
+	*buf++ = qos_u32_to_uc(cmd->color);
+	*buf++ = qos_u32_to_uc(cmd->addr);
+	*buf++ = qos_u32_to_uc(0);
+	*buf++ = qos_u32_to_uc(0);
+	return buf;
+}
+
+static uint32_t *fw_write_get_node_info(
+		uint32_t *buf,
+		const struct cmd_get_node_info *cmd,
+		uint32_t flags)
+{
+	*buf++ = qos_u32_to_uc(UC_QOS_COMMAND_GET_NODE_INFO);
+	*buf++ = qos_u32_to_uc(flags);
+	*buf++ = qos_u32_to_uc(2);
+	*buf++ = qos_u32_to_uc(cmd->phy);
+	*buf++ = qos_u32_to_uc(cmd->addr);
+	return buf;
+}
+/******************************************************************************/
+/*                                FW wrappers                                 */
+/******************************************************************************/
+
+static void set_common(
+		const struct pp_qos_common_node_properties *conf,
+		struct fw_set_common *common,
+		uint32_t modified)
+{
+	uint32_t valid;
+
+	valid = 0;
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_SUSPENDED)) {
+		QOS_BITS_SET(valid, TSCD_NODE_CONF_SUSPEND_RESUME);
+		common->suspend = conf->suspended;
+	}
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_BANDWIDTH_LIMIT)) {
+		QOS_BITS_SET(valid, TSCD_NODE_CONF_BW_LIMIT);
+		common->bw_limit = conf->bandwidth_limit;
+	}
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_SHARED_GROUP_LIMIT)) {
+		QOS_BITS_SET(valid, TSCD_NODE_CONF_BW_LIMIT);
+		common->shared_bw_group = conf->shared_bandwidth_group;
+	}
+	common->valid = valid;
+}
+
+static void set_parent(
+		const struct pp_qos_parent_node_properties *conf,
+		struct fw_set_parent *parent,
+		uint32_t modified)
+{
+	uint32_t valid;
+
+	valid = 0;
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_BEST_EFFORT)) {
+		QOS_BITS_SET(valid, TSCD_NODE_CONF_BEST_EFFORT_ENABLE);
+		parent->best_effort_enable = conf->best_effort_enable;
+	}
+	parent->valid = valid;
+}
+
+static void set_child(
+		const struct pp_qos_child_node_properties *conf,
+		struct fw_set_child *child,
+		uint32_t modified)
+{
+	uint32_t valid;
+
+	valid = 0;
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_VIRT_BW_SHARE)) {
+		QOS_BITS_SET(valid, TSCD_NODE_CONF_SHARED_BWL_GROUP);
+		child->bw_share = conf->bandwidth_share;
+	}
+	child->valid = valid;
+}
+
+static void set_port_specific(
+		const struct port_properties *conf,
+		struct fw_set_port *port,
+		uint32_t modified)
+{
+	uint32_t valid;
+
+	valid = 0;
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_RING_ADDRESS)) {
+		QOS_BITS_SET(valid,
+				PORT_CONF_RING_ADDRESS_HIGH |
+				PORT_CONF_RING_ADDRESS_LOW);
+		port->ring_addr = conf->ring_addr;
+	}
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_RING_SIZE)) {
+		QOS_BITS_SET(valid, PORT_CONF_RING_SIZE);
+		port->ring_size = conf->ring_size;
+	}
+	port->valid = valid;
+}
+
+static uint32_t *set_port_cmd_wrapper(
+		struct fw_internal *fwdata,
+		uint32_t *buf,
+		const struct cmd_set_port *cmd,
+		uint32_t flags)
+{
+	uint32_t modified;
+
+	modified = cmd->modified;
+	set_common(&cmd->prop.common, &fwdata->common, modified);
+	set_parent(&cmd->prop.parent, &fwdata->parent, modified);
+	set_port_specific(&cmd->prop, &fwdata->type_data.port, modified);
+	fwdata->type_data.port.valid = 0;
+
+	return fw_write_set_port_cmd(
+			buf,
+			cmd->phy,
+			flags,
+			&fwdata->common,
+			&fwdata->parent,
+			&fwdata->type_data.port);
+}
+
+static uint32_t *set_sched_cmd_wrapper(
+		struct fw_internal *fwdata,
+		uint32_t *buf,
+		const struct cmd_set_sched *cmd,
+		uint32_t flags)
+{
+	uint32_t modified;
+
+	modified = cmd->modified;
+	set_common(&cmd->prop.common, &fwdata->common, modified);
+	set_parent(&cmd->prop.parent, &fwdata->parent, modified);
+	set_child(&cmd->prop.child, &fwdata->child, modified);
+	fwdata->type_data.sched.valid = 0;
+	return fw_write_set_sched_cmd(
+			buf,
+			cmd->phy,
+			flags,
+			&fwdata->common,
+			&fwdata->parent,
+			&fwdata->child,
+			&fwdata->type_data.sched);
+}
+
+/*
+ * Topologic changes like first/last child change or change of predecessors
+ * will not be manifested through this path. They will be manifested through
+ * CMD_TYPE_PARENT_CHANGE and CMD_TYPE_UPDATE_PREDECESSORS driver commands
+ * which will call fw_write_set_node_cmd.
+ * So the only think that needs to use fw_write_set_node_cmd in this path is
+ * modify of suspend/resume
+ *
+ */
+static uint32_t *set_queue_cmd_wrapper(
+		struct fw_internal *fwdata,
+		uint32_t *buf,
+		const struct cmd_set_queue *cmd,
+		uint32_t flags)
+{
+	uint32_t modified;
+	uint32_t valid;
+	uint32_t disable;
+	struct fw_set_queue *queue;
+
+	queue = &fwdata->type_data.queue;
+	modified = cmd->modified;
+	set_common(&cmd->prop.common, &fwdata->common, modified);
+	set_child(&cmd->prop.child, &fwdata->child, modified);
+
+	valid = 0;
+	queue->rlm = cmd->prop.rlm;
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_BLOCKED)) {
+		QOS_BITS_SET(valid, WRED_QUEUE_CONF_ACTIVE_Q);
+		queue->active = !cmd->prop.blocked;
+	}
+
+	disable = 0;
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_WRED_ENABLE)) {
+		QOS_BITS_SET(valid, WRED_QUEUE_CONF_DISABLE);
+		if (!cmd->prop.wred_enable)
+			QOS_BITS_SET(disable, BIT(0));
+	}
+	if (QOS_BITS_IS_SET(
+				modified,
+				QOS_MODIFIED_WRED_FIXED_DROP_PROB_ENABLE)) {
+		QOS_BITS_SET(valid, WRED_QUEUE_CONF_DISABLE);
+		if (cmd->prop.fixed_drop_prob_enable)
+			QOS_BITS_SET(disable, BIT(3));
+	}
+	queue->disable = disable;
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_WRED_FIXED_GREEN_PROB)) {
+		QOS_BITS_SET(valid, WRED_QUEUE_CONF_FIXED_GREEN_DROP_P);
+		queue->queue_wred_fixed_drop_prob_green =
+			cmd->prop.queue_wred_fixed_drop_prob_green;
+	}
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_WRED_FIXED_YELLOW_PROB)) {
+		QOS_BITS_SET(valid, WRED_QUEUE_CONF_FIXED_YELLOW_DROP_P);
+		queue->queue_wred_fixed_drop_prob_yellow =
+			cmd->prop.queue_wred_fixed_drop_prob_yellow;
+	}
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_WRED_MIN_YELLOW)) {
+		QOS_BITS_SET(valid, WRED_QUEUE_CONF_MIN_AVG_YELLOW);
+		queue->queue_wred_min_avg_yellow =
+			cmd->prop.queue_wred_min_avg_yellow;
+	}
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_WRED_MAX_YELLOW)) {
+		QOS_BITS_SET(valid, WRED_QUEUE_CONF_MAX_AVG_YELLOW);
+		queue->queue_wred_max_avg_yellow =
+			cmd->prop.queue_wred_max_avg_yellow;
+	}
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_WRED_SLOPE_YELLOW)) {
+		QOS_BITS_SET(valid, WRED_QUEUE_CONF_SLOPE_YELLOW);
+		queue->queue_wred_slope_yellow =
+			cmd->prop.queue_wred_slope_yellow;
+	}
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_WRED_MIN_GREEN)) {
+		QOS_BITS_SET(valid, WRED_QUEUE_CONF_MIN_AVG_GREEN);
+		queue->queue_wred_min_avg_green =
+			cmd->prop.queue_wred_min_avg_green;
+	}
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_WRED_MAX_GREEN)) {
+		QOS_BITS_SET(valid, WRED_QUEUE_CONF_MAX_AVG_GREEN);
+		queue->queue_wred_max_avg_green =
+			cmd->prop.queue_wred_max_avg_green;
+	}
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_WRED_SLOPE_GREEN)) {
+		QOS_BITS_SET(valid, WRED_QUEUE_CONF_SLOPE_GREEN);
+		queue->queue_wred_slope_green =
+			cmd->prop.queue_wred_slope_green;
+	}
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_WRED_MIN_GUARANTEED)) {
+		QOS_BITS_SET(valid, WRED_QUEUE_CONF_MIN_GUARANTEED);
+		queue->queue_wred_min_guaranteed =
+			cmd->prop.queue_wred_min_guaranteed;
+	}
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_WRED_MAX_ALLOWED)) {
+		QOS_BITS_SET(valid, WRED_QUEUE_CONF_MAX_ALLOWED);
+		queue->queue_wred_max_allowed =
+			cmd->prop.queue_wred_max_allowed;
+	}
+
+	queue->valid = valid;
+	return fw_write_set_queue_cmd(
+			buf,
+			cmd->phy,
+			flags,
+			&fwdata->common,
+			&fwdata->child,
+			queue);
+}
+
+static uint32_t *parent_change_cmd_wrapper(
+		struct fw_internal *fwdata,
+		uint32_t *buf,
+		const struct cmd_parent_change *cmd,
+		uint32_t flags)
+{
+	fwdata->parent.valid =
+		TSCD_NODE_CONF_FIRST_CHILD |
+		TSCD_NODE_CONF_LAST_CHILD |
+		TSCD_NODE_CONF_FIRST_WRR_NODE;
+	fwdata->parent.first = cmd->first;
+	fwdata->parent.last = cmd->first + cmd->num - 1;
+	if (cmd->arbitration == PP_QOS_ARBITRATION_WSP)
+		fwdata->parent.first_wrr = 0;
+	else
+		fwdata->parent.first_wrr = cmd->first;
+
+	fwdata->common.valid = 0;
+	if (cmd->type == TYPE_PORT) {
+		fwdata->type_data.port.valid  = 0;
+		return fw_write_set_port_cmd(
+				buf,
+				cmd->phy,
+				flags,
+				&fwdata->common,
+				&fwdata->parent,
+				&fwdata->type_data.port);
+	} else {
+		fwdata->child.valid = 0;
+		fwdata->type_data.sched.valid = 0;
+		return fw_write_set_sched_cmd(
+				buf,
+				cmd->phy,
+				flags,
+				&fwdata->common,
+				&fwdata->parent,
+				&fwdata->child,
+				&fwdata->type_data.sched);
+	}
+}
+
+static uint32_t *update_preds_cmd_wrapper(
+		struct fw_internal *fwdata,
+		uint32_t *buf,
+		const struct cmd_update_preds *cmd,
+		uint32_t flags)
+{
+	unsigned int i;
+
+	fwdata->common.valid = 0;
+	fwdata->child.valid = TSCD_NODE_CONF_PREDECESSOR_0 |
+		TSCD_NODE_CONF_PREDECESSOR_1 |
+		TSCD_NODE_CONF_PREDECESSOR_2 |
+		TSCD_NODE_CONF_PREDECESSOR_3 |
+		TSCD_NODE_CONF_PREDECESSOR_4 |
+		TSCD_NODE_CONF_PREDECESSOR_5;
+	for (i = 0; i < 6; ++i)
+		fwdata->child.preds[i] = cmd->preds[i];
+
+	if (cmd->node_type == TYPE_SCHED) {
+		fwdata->type_data.sched.valid  = 0;
+		fwdata->parent.valid = 0;
+		return fw_write_set_sched_cmd(
+				buf,
+				cmd->phy,
+				flags,
+				&fwdata->common,
+				&fwdata->parent,
+				&fwdata->child,
+				&fwdata->type_data.sched);
+	} else {
+		fwdata->type_data.queue.valid = 0;
+		return fw_write_set_queue_cmd(
+				buf,
+				cmd->phy,
+				flags,
+				&fwdata->common,
+				&fwdata->child,
+				&fwdata->type_data.queue);
+	}
+}
+
+/*
+ * Signal firmware to read and executes commands from cmd
+ * buffer.
+ * This is done by using the mailbox bundle.
+ * Refer to driver's design document for further information
+ * Since this is the only signal that is sent from driver to firmware
+ * the value of DRV_SIGNAL is insignificant
+ */
+#define DRV_SIGNAL (2U)
+void signal_uc(struct pp_qos_dev *qdev)
+{
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+#ifndef NO_FW
+	iowrite32(DRV_SIGNAL, qdev->fwcom.mbx_to_uc + 4);
+	QOS_LOG("signal uc was called\n");
+#endif
+}
+
+/******************************************************************************/
+/*                                Engine                                      */
+/******************************************************************************/
+
+/*
+ * Translation to user format and sanity checks on node info
+ * obtained from firmware
+ */
+static void post_process_get_node_info(
+		struct pp_qos_dev *qdev,
+		struct cmd_get_node_info *cmd)
+{
+	struct pp_qos_node_info *info;
+	struct hw_node_info_s *fw_info;
+	struct qos_node *node;
+	struct qos_node *child;
+	uint16_t preds[6];
+	uint32_t *fw_preds;
+	unsigned int first;
+	unsigned int phy;
+	unsigned int id;
+	unsigned int i;
+	unsigned int num;
+	unsigned int port;
+	int reached_port;
+
+	port = PPV4_QOS_INVALID;
+	node = get_node_from_phy(qdev->nodes, cmd->phy);
+	QOS_ASSERT(node_used(node), "Node %u is not used\n", cmd->phy);
+	fw_info = (struct hw_node_info_s *)(qdev->stat);
+	info = cmd->info;
+	memset(info, 0xFF, sizeof(*info));
+
+	QOS_ASSERT(node->type != TYPE_UNKNOWN,
+			"Node %u has unknown type\n",
+			cmd->phy);
+	info->type = node->type - 1;
+	info->is_internal = node_internal(node);
+	QOS_ASSERT(node_suspended(node) == fw_info->is_suspended,
+			"Node %u suspend status according to driver is %d and according to HW is %d\n",
+			cmd->phy, node_suspended(node), fw_info->is_suspended);
+	info->is_suspended = fw_info->is_suspended;
+
+	if (node_parent(node)) {
+		first = fw_info->first_child;
+		if (first == 0) {
+			first = QOS_INVALID_PHY;
+			num = 0;
+		} else {
+			num = fw_info->last_child - first + 1;
+			child = get_node_from_phy(qdev->nodes, first);
+		}
+		QOS_ASSERT(node->parent_prop.first_child_phy == first,
+				"Driver has %u as the phy of node's %u first child, while HW has %u\n",
+				node->parent_prop.first_child_phy,
+				cmd->phy,
+				first);
+
+		QOS_ASSERT(node->parent_prop.num_of_children == num,
+				"Driver has %u as the number of children of node %u, while HW has %u\n",
+				node->parent_prop.num_of_children,
+				cmd->phy,
+				num);
+
+		for (i = 0; i < num; ++i) {
+			phy = i + first;
+			id = get_id_from_phy(qdev->mapping, phy);
+			QOS_ASSERT(QOS_ID_VALID(id),
+					"Child of %u with phy %u has no valid id\n",
+					cmd->phy, phy);
+			QOS_ASSERT(node_used(child),
+					"Child node with phy %u and id %u is not used\n",
+					phy,
+					id);
+			info->children[i].phy = phy;
+			info->children[i].id = id;
+			++child;
+		}
+	}
+
+	if (!node_port(node)) {
+		fill_preds(qdev->nodes, cmd->phy, preds, 6);
+		fw_preds = &(fw_info->predecessor0);
+		reached_port = 0;
+		for (i = 0; i < 6; ++i) {
+			QOS_ASSERT(preds[i] == *fw_preds,
+					"Driver has %u as the %u predecessor of node %u, while HW has %u\n",
+					preds[i],
+					i,
+					cmd->phy,
+					*fw_preds);
+
+			if (!reached_port) {
+				info->preds[i].phy = preds[i];
+				id = get_id_from_phy(qdev->mapping, preds[i]);
+				QOS_ASSERT(QOS_ID_VALID(id),
+						"Pred with phy %u has no valid id\n",
+						preds[i]);
+				info->preds[i].id = id;
+				if (preds[i] <= qdev->max_port) {
+					reached_port = 1;
+					port = preds[i];
+				}
+			} else {
+				info->preds[i].phy = PPV4_QOS_INVALID;
+			}
+			++fw_preds;
+		}
+	}
+
+	if (node_queue(node)) {
+		QOS_ASSERT(node->data.queue.rlm == fw_info->queue_physical_id,
+				"Node %u physical queue is %u according to driver and %u according to HW\n",
+				cmd->phy, node->data.queue.rlm,
+				fw_info->queue_physical_id);
+		QOS_ASSERT(port == fw_info->queue_port,
+				"Driver has %u as %u port, while HW has %u\n",
+				port,
+				cmd->phy,
+				fw_info->queue_physical_id);
+
+		info->queue_physical_id = fw_info->queue_physical_id;
+		info->port = fw_info->queue_port;
+	}
+
+	QOS_ASSERT(fw_info->bw_limit == node->bandwidth_limit,
+			"Driver has %u as node's %u bandwidth limit, while HW has %u\n",
+			node->bandwidth_limit,
+			cmd->phy,
+			fw_info->bw_limit);
+
+	info->bw_limit = fw_info->bw_limit;
+}
+
+/*
+ * Commands that are marked with POST_PROCESS reach
+ * here for further processing before return to client
+ */
+static void post_process(struct pp_qos_dev *qdev, union driver_cmd *dcmd)
+{
+	enum cmd_type  type;
+	struct pp_qos_queue_stat *qstat;
+	struct pp_qos_port_stat *pstat;
+	struct queue_stats_s *fw_qstat;
+	struct port_stats_s *fw_pstat;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	type = dcmd->cmd.type;
+	switch (type) {
+	case CMD_TYPE_GET_QUEUE_STATS:
+		fw_qstat = (struct queue_stats_s *)(qdev->stat);
+		qstat = dcmd->queue_stats.stat;
+		qstat->queue_packets_occupancy = fw_qstat->queue_size_entries;
+		qstat->queue_bytes_occupancy = fw_qstat->queue_size_bytes;
+		qstat->total_packets_accepted = fw_qstat->total_accepts;
+		qstat->total_packets_dropped = fw_qstat->total_drops;
+		qstat->total_packets_red_dropped = fw_qstat->total_red_dropped;
+		qstat->total_bytes_accepted =
+			(((uint64_t)fw_qstat->total_bytes_added_high) << 32)
+			| fw_qstat->total_bytes_added_low;
+		qstat->total_bytes_dropped =
+			(((uint64_t)fw_qstat->total_dropped_bytes_high) << 32)
+			| fw_qstat->total_dropped_bytes_low;
+		QOS_ASSERT(fw_qstat->queue_size_entries ==
+				fw_qstat->qmgr_num_queue_entries,
+				"wred (%u) and qm (%u) reports differnet number of queue entries for queue %u\n",
+				fw_qstat->queue_size_entries,
+				fw_qstat->qmgr_num_queue_entries,
+				dcmd->queue_stats.rlm);
+		break;
+
+	case CMD_TYPE_GET_PORT_STATS:
+		fw_pstat = (struct port_stats_s *)(qdev->stat);
+		pstat = dcmd->port_stats.stat;
+		pstat->total_green_bytes = fw_pstat->total_green_bytes;
+		pstat->total_yellow_bytes = fw_pstat->total_yellow_bytes;
+		break;
+
+	case CMD_TYPE_GET_NODE_INFO:
+		post_process_get_node_info(qdev, &dcmd->node_info);
+		break;
+
+	default:
+		QOS_ASSERT(0, "Unexpected cmd %d for post process\n", type);
+		return;
+
+	}
+}
+
+#define MAX_FW_CMD_SIZE 120U
+#define MS_SLEEP_BETWEEN_POLL 50U
+#define NUM_OF_POLLS	100U
+
+/*
+ * Go over all commands on pending queue until cmd id
+ * is changed or queue is empty
+ * (refer to driver design document to learn more about cmd id).
+ * On current implmentation it is expected that pending queue contain
+ * firmware commands for a single client command, therfore queue should
+ * become empty before cmd id is changed.
+ *
+ * For each command wait until firmware signals
+ * completion before continue to next command.
+ * Completion status for each command is polled NUM_OF_POLLS
+ * times. And the function sleeps between pools.
+ * If command have not completed after all that polls -
+ * function asserts.
+ *
+ */
+void check_completion(struct pp_qos_dev *qdev)
+{
+	union driver_cmd dcmd;
+
+	volatile uint32_t *pos;
+	uint32_t	val;
+	size_t len;
+	unsigned int idcur;
+	unsigned int idnext;
+	int first_cmd;
+	int rc;
+	unsigned int i;
+	unsigned int popped;
+	struct fw_internal *internals;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	popped = 0;
+	idcur = 0;
+	first_cmd = 1;
+	while (cmd_queue_peek(
+			      qdev->drvcmds.pendq,
+			      &dcmd.cmd,
+			      sizeof(struct cmd)) == 0) {
+		idnext = dcmd.cmd.id;
+		if (!first_cmd && (idnext != idcur))
+			break;
+		pos = dcmd.stub.cmd.pos;
+		len = dcmd.cmd.len;
+		++pos;
+#ifndef NO_FW
+		i = 0;
+		val = qos_u32_from_uc(*pos);
+		while ((val &
+			(UC_CMD_FLAG_UC_DONE | UC_CMD_FLAG_UC_ERROR)) == 0) {
+			val = qos_u32_from_uc(*pos);
+			qos_sleep(MS_SLEEP_BETWEEN_POLL);
+			++i;
+			if (i == NUM_OF_POLLS) {
+				QOS_ASSERT(
+					0,
+					"FW is not responding, polling offset 0x%04tX for cmd type %s\n",
+					(void *)pos -
+					(void *)(qdev->fwcom.cmdbuf),
+					cmd_str[dcmd.cmd.type]);
+				return;
+			}
+		}
+		if (val & UC_CMD_FLAG_UC_ERROR) {
+			QOS_ASSERT(0,
+				   "FW signaled error, polling offset 0x%04tX, cmd type %s\n",
+				   (void *)pos - (void *)(qdev->fwcom.cmdbuf),
+				   cmd_str[dcmd.cmd.type]);
+			return;
+		}
+#endif
+		rc = cmd_queue_get(qdev->drvcmds.pendq, &dcmd.stub, len);
+		QOS_ASSERT(rc == 0,
+			   "Command queue does not contain a full command\n");
+		if (dcmd.cmd.flags & CMD_FLAGS_POST_PROCESS)
+			post_process(qdev, &dcmd);
+		++popped;
+		idcur = idnext;
+		first_cmd = 0;
+	}
+
+	internals = qdev->fwbuf;
+	QOS_ASSERT(popped == internals->pushed,
+		   "Expected to pop %u msgs from pending queue but popped %u\n",
+		   internals->pushed, popped);
+	QOS_ASSERT(cmd_queue_is_empty(qdev->drvcmds.cmdq),
+		   "Driver's cmd queue is not empty\n");
+	QOS_ASSERT(cmd_queue_is_empty(qdev->drvcmds.pendq),
+		   "Driver's pending queue is not empty\n");
+}
+
+#define FW_CMD_BUFFER_DCCM_START 0xF0006000
+
+/*
+ * Take all commands from driver cmd queue, translate them to
+ * firmware format and put them on firmware queue.
+ * When finish signal firmware.
+ */
+void enqueue_cmds(struct pp_qos_dev *qdev)
+{
+	size_t len;
+	int rc;
+	uint32_t *cur;
+	uint32_t *prev;
+	uint32_t *start;
+	size_t remain;
+	uint32_t flags;
+	union driver_cmd dcmd;
+	struct fw_internal *internals;
+	unsigned int pushed;
+
+	if (PP_QOS_DEVICE_IS_ASSERT(qdev))
+		return;
+
+	start = qdev->fwcom.cmdbuf;
+	remain = qdev->fwcom.cmdbuf_sz;
+
+	pushed = 0;
+	cur = start;
+	prev = start;
+	*cur++ = qos_u32_to_uc(UC_QOS_COMMAND_MULTIPLE_COMMANDS);
+	*cur++ = qos_u32_to_uc(UC_CMD_FLAG_IMMEDIATE);
+	*cur++ = qos_u32_to_uc(1);
+	*cur = qos_u32_to_uc(((uintptr_t)(cur) - (uintptr_t)start +
+				4 + FW_CMD_BUFFER_DCCM_START) & 0xFFFFFFFF);
+	++cur;
+
+	internals = qdev->fwbuf;
+	remain -= 16;
+	flags = UC_CMD_FLAG_IMMEDIATE;
+	while ((remain >= MAX_FW_CMD_SIZE) &&
+			cmd_queue_peek(
+				qdev->drvcmds.cmdq,
+				&dcmd.cmd,
+				sizeof(struct cmd)) == 0) {
+		len = dcmd.cmd.len;
+		rc = cmd_queue_get(qdev->drvcmds.cmdq, &dcmd.stub, len);
+		QOS_ASSERT(rc == 0,
+				"Command queue does not contain a full command\n");
+		prev = cur;
+		dcmd.stub.cmd.pos = cur;
+		cmd_queue_put(
+				qdev->drvcmds.pendq,
+				&dcmd.stub,
+				dcmd.stub.cmd.len);
+		switch (dcmd.cmd.type) {
+		case CMD_TYPE_INIT_LOGGER:
+			cur = fw_write_init_logger_cmd(
+					prev,
+					&dcmd.init_logger,
+					flags);
+			break;
+
+		case CMD_TYPE_INIT_QOS:
+			cur = fw_write_init_qos_cmd(
+					prev,
+					&dcmd.init_qos,
+					flags);
+			break;
+
+		case CMD_TYPE_MOVE:
+			if (dcmd.move.node_type == TYPE_QUEUE)
+				cur = fw_write_move_queue_cmd(
+						prev,
+						&dcmd.move,
+						flags);
+			else
+				cur = fw_write_move_sched_cmd(
+						prev,
+						&dcmd.move,
+						flags);
+			break;
+
+		case CMD_TYPE_PARENT_CHANGE:
+			cur = parent_change_cmd_wrapper(
+					internals,
+					prev,
+					&dcmd.parent_change,
+					flags);
+			break;
+
+		case CMD_TYPE_UPDATE_PREDECESSORS:
+			cur = update_preds_cmd_wrapper(
+					internals,
+					prev,
+					&dcmd.update_preds,
+					flags);
+			break;
+
+		case CMD_TYPE_ADD_PORT:
+			cur = fw_write_add_port_cmd(
+					prev,
+					&dcmd.add_port,
+					flags);
+			break;
+
+		case CMD_TYPE_SET_PORT:
+			cur = set_port_cmd_wrapper(
+					internals,
+					prev,
+					&dcmd.set_port,
+					flags);
+			break;
+
+		case CMD_TYPE_REMOVE_PORT:
+			cur = fw_write_remove_port_cmd(
+					prev,
+					&dcmd.remove_node,
+					flags);
+			break;
+
+		case CMD_TYPE_ADD_SCHED:
+			cur = fw_write_add_sched_cmd(
+					prev,
+					&dcmd.add_sched,
+					flags);
+			break;
+
+		case CMD_TYPE_ADD_QUEUE:
+			cur = fw_write_add_queue_cmd(
+					prev,
+					&dcmd.add_queue,
+					flags);
+			break;
+
+		case CMD_TYPE_REMOVE_QUEUE:
+			cur = fw_write_remove_queue_cmd(
+					prev,
+					&dcmd.remove_node,
+					flags);
+			break;
+
+		case CMD_TYPE_REMOVE_SCHED:
+			cur = fw_write_remove_sched_cmd(
+					prev,
+					&dcmd.remove_node,
+					flags);
+			break;
+
+		case CMD_TYPE_SET_SCHED:
+			cur = set_sched_cmd_wrapper(
+					internals,
+					prev,
+					&dcmd.set_sched,
+					flags);
+			break;
+
+		case CMD_TYPE_SET_QUEUE:
+			cur = set_queue_cmd_wrapper(
+					internals,
+					prev,
+					&dcmd.set_queue,
+					flags);
+			break;
+
+		case CMD_TYPE_REMOVE_NODE:
+			QOS_ASSERT(0,
+					"Did not expect CMD_TYPE_REMOVE_NODE\n");
+			break;
+
+		case CMD_TYPE_GET_QUEUE_STATS:
+			cur = fw_write_get_queue_stats(
+					prev, &dcmd.queue_stats, flags);
+			break;
+
+		case CMD_TYPE_GET_PORT_STATS:
+			cur = fw_write_get_port_stats(
+					prev, &dcmd.port_stats, flags);
+			break;
+
+		case CMD_TYPE_ADD_SHARED_GROUP:
+		case CMD_TYPE_SET_SHARED_GROUP:
+			cur = fw_write_set_shared_group(
+					prev,
+					dcmd.cmd.type,
+					&dcmd.set_shared_group,
+					flags);
+			break;
+
+		case CMD_TYPE_REMOVE_SHARED_GROUP:
+			cur = fw_write_remove_shared_group(
+					prev,
+					&dcmd.remove_shared_group,
+					flags);
+			break;
+		case CMD_TYPE_PUSH_DESC:
+			cur = fw_write_push_desc(
+					prev,
+					&dcmd.pushd,
+					flags);
+			break;
+
+		case CMD_TYPE_GET_NODE_INFO:
+			cur = fw_write_get_node_info(
+					prev,
+					&dcmd.node_info,
+					flags);
+			break;
+
+		default:
+			QOS_ASSERT(0, "Unexpected msg type %d\n",
+					dcmd.cmd.type);
+			return;
+		}
+		++pushed;
+		remain -= (uintptr_t)cur - (uintptr_t)prev;
+	}
+	QOS_ASSERT(remain >= MAX_FW_CMD_SIZE,
+			"Remain size on command buffer is not enought\n");
+
+	if (prev != start) {
+		prev += 1;
+		flags = qos_u32_from_uc(*prev);
+		QOS_BITS_SET(flags, UC_CMD_FLAG_MULTIPLE_COMMAND_LAST);
+		*prev = qos_u32_to_uc(flags);
+	}
+	internals->pushed = pushed;
+
+	if (prev != start)
+		signal_uc(qdev);
+}
+#endif
diff --git a/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_fw.h b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_fw.h
new file mode 100644
index 0000000000000000000000000000000000000000..df51fdde4d148219b39485827f9000d46e18ffb9
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_fw.h
@@ -0,0 +1,156 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+#ifndef PP_QOS_FW_H
+#define PP_QOS_FW_H
+
+#include "pp_qos_utils.h"
+#include "pp_qos_common.h"
+#include "pp_qos_uc_wrapper.h"
+
+struct ppv4_qos_fw {
+	size_t size;
+	const uint8_t *data;
+};
+
+int load_firmware(struct pp_qos_dev *qdev, const char *name);
+
+#ifndef PP_QOS_DISABLE_CMDQ
+void create_move_cmd(struct pp_qos_dev *qdev, uint16_t dst, uint16_t src,
+		     uint16_t dst_port);
+void create_set_port_cmd(struct pp_qos_dev *qdev,
+			 const struct pp_qos_port_conf *conf, unsigned int phy,
+			 uint32_t modified);
+void create_set_queue_cmd(struct pp_qos_dev *qdev,
+			  const struct pp_qos_queue_conf *conf,
+			  unsigned int phy,
+			  unsigned int parent,
+			  unsigned int rlm, uint32_t modified);
+void create_set_sched_cmd(struct pp_qos_dev *qdev,
+			  const struct pp_qos_sched_conf *conf,
+			  unsigned int phy,
+			  unsigned int parent, uint32_t modified);
+void create_remove_node_cmd(struct pp_qos_dev *qdev, enum node_type type,
+			    unsigned int phy, unsigned int data);
+void create_parent_change_cmd(struct pp_qos_dev *qdev, unsigned int phy);
+void create_update_preds_cmd(struct pp_qos_dev *qdev, unsigned int phy);
+void create_init_qos_cmd(struct pp_qos_dev *qdev);
+void enqueue_cmds(struct pp_qos_dev *qdev);
+void check_completion(struct pp_qos_dev *qdev);
+void create_get_queue_stats_cmd(
+		struct pp_qos_dev *qdev,
+		unsigned int phy,
+		unsigned int rlm,
+		unsigned int addr,
+		struct pp_qos_queue_stat *qstat);
+void create_get_port_stats_cmd(
+		struct pp_qos_dev *qdev,
+		unsigned int phy,
+		unsigned int addr,
+		struct pp_qos_port_stat *pstat);
+int init_fwdata_internals(struct pp_qos_dev *qdev);
+void clean_fwdata_internals(struct pp_qos_dev *qdev);
+void create_init_logger_cmd(struct pp_qos_dev *qdev);
+void create_add_shared_group_cmd(struct pp_qos_dev *qdev,
+		unsigned int id,
+		unsigned int limit);
+void create_remove_shared_group_cmd(struct pp_qos_dev *qdev,
+		unsigned int id);
+
+void create_set_shared_group_cmd(struct pp_qos_dev *qdev,
+		unsigned int id,
+		unsigned int limit);
+
+void create_push_desc_cmd(struct pp_qos_dev *qdev, unsigned int queue,
+		unsigned int size, unsigned int color, unsigned int addr);
+
+void create_get_node_info_cmd(
+		struct pp_qos_dev *qdev,
+		unsigned int phy,
+		unsigned int addr,
+		struct pp_qos_node_info *info);
+
+int do_load_firmware(
+		struct pp_qos_dev *qdev,
+		const struct ppv4_qos_fw *fw,
+		void *ddr_base,
+		void *ivt_base,
+		void *data);
+
+void signal_uc(struct pp_qos_dev *qdev);
+#elif defined(PRINT_CREATE_CMD)
+#define create_move_cmd(qdev, dst, src, dst_port)\
+	QOS_LOG_DEBUG("MOVE: %u ==> %u\n", src, dst)
+#define create_set_port_cmd(qdev, conf, phy, modified)\
+	QOS_LOG_DEBUG("SET PORT: %u\n", phy)
+#define create_set_sched_cmd(qdev, conf, phy, parent, modified)\
+	QOS_LOG_DEBUG("SET SCH: %u\n", phy)
+#define create_set_queue_cmd(qdev, conf, phy, parent, rlm, modified)\
+	QOS_LOG_DEBUG("SET QUEUE: %u\n", phy)
+#define create_remove_node_cmd(qdev, type, phy, data)\
+	QOS_LOG_DEBUG("REMOVE: %u(%u)\n", phy, type)
+#define create_parent_change_cmd(qdev, phy)\
+	QOS_LOG_DEBUG("PARENT_CHANGE: %u\n", phy)
+#define create_update_preds_cmd(qdev, phy)\
+	QOS_LOG_DEBUG("UPDATE_PREDS: %u\n", phy)
+#define create_get_queue_stats_cmd(qdev, phy, rlm, addr, qstat)
+#define create_init_qos_cmd(qdev)
+#define enqueue_cmds(qdev)
+#define check_completion(qdev)
+#define init_fwdata_internals(qdev) 0
+#define clean_fwdata_internals(qdev)
+#define create_init_logger_cmd(qdev)
+#define create_add_shared_group_cmd(qdev, id, limit)
+#define create_set_shared_group_cmd(qdev, id, limit)
+#define create_remove_shared_group_cmd(qdev, id)
+#define create_get_queue_stats_cmd(qdev, phy, rlm, addr, qstat)
+#define create_get_port_stats_cmd(qdev, phy, addr, pstat)
+#define create_get_node_info_cmd(qdev, phy, addr, info)
+#define create_push_desc_cmd(qdev, queue, size, color, addr)
+#else
+#define create_move_cmd(qdev, dst, src, dst_port)
+#define create_set_port_cmd(qdev, conf, phy, modified)
+#define create_set_sched_cmd(qdev, conf, phy, parent, modified)
+#define create_set_queue_cmd(qdev, conf, phy, parent, rlm, modified)
+#define create_remove_node_cmd(qdev, type, phy, data)
+#define create_parent_change_cmd(qdev, phy)
+#define create_update_preds_cmd(qdev, phy)
+#define create_get_queue_stats_cmd(qdev, phy, rlm, addr, qstat)
+#define create_init_qos_cmd(qdev)
+#define enqueue_cmds(qdev)
+#define check_completion(qdev)
+#define init_fwdata_internals(qdev) 0
+#define clean_fwdata_internals(qdev)
+#define create_init_logger_cmd(qdev)
+#define create_add_shared_group_cmd(qdev, id, limit)
+#define create_set_shared_group_cmd(qdev, id, limit)
+#define create_remove_shared_group_cmd(qdev, id)
+#define create_get_queue_stats_cmd(qdev, phy, rlm, addr, qstat)
+#define create_get_port_stats_cmd(qdev, phy, addr, pstat)
+#define create_get_node_info_cmd(qdev, phy, addr, info)
+#define create_push_desc_cmd(qdev, queue, size, color, addr)
+#endif
+#endif
diff --git a/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_kernel.h b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_kernel.h
new file mode 100644
index 0000000000000000000000000000000000000000..fe1d38b81036d31959b8de0e937a4008aaa2ba1b
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_kernel.h
@@ -0,0 +1,75 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+#ifndef _PP_QOS_KERNEL_H
+#define _PP_QOS_KERNEL_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+
+int qos_dbg_dev_init(struct platform_device *pdev);
+void qos_dbg_dev_clean(struct platform_device *pdev);
+int qos_dbg_module_init(void);
+void qos_dbg_module_clean(void);
+
+struct pp_qos_dbg_data {
+	struct dentry *dir;
+	uint16_t	node;
+	void		*fw_logger_addr;
+};
+
+struct pp_qos_drv_data {
+	int	id;
+	struct pp_qos_dev *qdev;
+	struct pp_qos_dbg_data dbg;
+	void *ddr;
+	void *dccm;
+	void *ivt;
+	void __iomem *wakeuc;
+	resource_size_t ddr_phy_start;
+
+};
+
+#ifndef __BIG_ENDIAN
+#define ENDIANESS_MATCH(endianess) (endianess == 0)
+#else
+#define ENDIANESS_MATCH(endianess) (endianess != 0)
+#endif
+
+#ifdef CONFIG_OF
+#define PPV4_QOS_MANUAL_ADD(rc)
+#define PPV4_QOS_MANUAL_REMOVE()
+#else
+#define PPV4_QOS_MANUAL_ADD(rc)		\
+do {					\
+	if (rc == 0)			\
+		rc = add_qos_dev();	\
+} while (0)
+#define PPV4_QOS_MANUAL_REMOVE() remove_qos_dev()
+#endif
+
+#endif
diff --git a/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_linux.c b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_linux.c
new file mode 100644
index 0000000000000000000000000000000000000000..4d833b1a364151db3b8ed0ad2108257a78c3e185
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_linux.c
@@ -0,0 +1,536 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/firmware.h>
+#include <linux/of_address.h>
+#include <linux/dma-mapping.h>
+#include "pp_qos_kernel.h"
+#include "pp_qos_common.h"
+#include "pp_qos_utils.h"
+#include "pp_qos_fw.h"
+
+/*
+ * TODO - this obstruct multi instances but helps debug
+ * at this phase
+ */
+struct device *cur_dev;
+
+#define PPV4_QOS_CMD_BUF_SIZE (0x1000)
+#define PPV4_QOS_CMD_BUF_OFFSET (0x6000U)
+#define MAX_CMD_SIZE 150
+
+void stop_run(void)
+{
+	struct pp_qos_drv_data *pdata;
+
+	if (cur_dev) {
+		dev_crit(cur_dev, "!!!!! Qos driver in unstable mode !!!!!\n");
+		pdata = dev_get_drvdata(cur_dev);
+		QOS_BITS_SET(pdata->qdev->flags, PP_QOS_FLAGS_ASSERT);
+	}
+}
+
+void wake_uc(void *data)
+{
+	struct pp_qos_drv_data *pdata;
+
+	pdata = (struct pp_qos_drv_data *)data;
+	iowrite32(4, pdata->wakeuc);
+}
+
+int load_firmware(struct pp_qos_dev *qdev, const char *name)
+{
+	int err;
+	const struct firmware *firmware;
+	struct ppv4_qos_fw fw;
+	struct pp_qos_drv_data *pdata;
+	struct device *dev;
+	struct platform_device *pdev;
+
+	pdev = (struct platform_device *)(qdev->pdev);
+	dev = &pdev->dev;
+	pdata = platform_get_drvdata(pdev);
+	err = request_firmware(&firmware, name, dev);
+	if (err < 0) {
+		dev_err(dev, "Failed loading firmware ret is %d\n", err);
+		return err;
+	}
+
+	fw.size = firmware->size;
+	fw.data = firmware->data;
+	err = do_load_firmware(qdev,
+			&fw,
+			pdata->ddr - pdata->ddr_phy_start,
+			pdata->ivt - PPV4_QOS_IVT_START,
+			pdata);
+
+	release_firmware(firmware);
+	return err;
+}
+
+static const struct of_device_id pp_qos_match[] = {
+	{ .compatible = "intel,falconmx-ppv4qos" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, pp_qos_match);
+
+static struct resource *get_resource(
+		struct platform_device *pdev,
+		const char *name,
+		unsigned int type,
+		size_t size)
+{
+	struct resource *r;
+	size_t sz;
+	struct device *dev;
+
+	dev = &pdev->dev;
+
+	r = platform_get_resource_byname(pdev, type, name);
+	if (!r) {
+		dev_err(dev, "Could not get %s resource\n", name);
+		return NULL;
+	}
+
+	sz = resource_size(r);
+	if (size && sz != size) {
+		dev_err(dev, "Illegal size %zu for %s resource expected %zu\n",
+				sz, name, size);
+		return NULL;
+	}
+
+	return r;
+}
+
+static void print_resource(
+		struct device *dev,
+		const char *name,
+		struct resource *r)
+{
+
+	dev_info(dev, "%s memory resource: start(0x%08zX), size(%zu)\n",
+			name,
+			(size_t)(uintptr_t)r->start,
+			(size_t)(uintptr_t)resource_size(r));
+}
+
+static void *map_mem_resource(
+		struct platform_device *pdev,
+		const char *name,
+		unsigned int type,
+		unsigned int size)
+{
+	struct resource *r;
+	void *addr;
+	struct device *dev;
+	int err;
+
+	dev = &pdev->dev;
+
+	r = get_resource(
+			pdev,
+			name,
+			type,
+			size);
+	if (!r)
+		return NULL;
+
+	print_resource(dev, name, r);
+	addr = devm_memremap(dev, r->start, resource_size(r), MEMREMAP_WT);
+	if (IS_ERR_OR_NULL(addr)) {
+		err = (int) PTR_ERR(addr);
+		dev_err(dev,
+			"devm_memremap on resource %s failed with %d\n",
+			name,
+			err);
+		return NULL;
+	}
+	dev_info(dev, "%s memory mapped to %p\n", name, addr);
+
+	return addr;
+}
+
+static void __iomem *map_reg_resource(
+		struct platform_device *pdev,
+		const char *name,
+		unsigned int type,
+		unsigned int size)
+{
+	struct resource *r;
+	void __iomem *addr;
+
+	r = get_resource(
+			pdev,
+			name,
+			type,
+			size);
+
+	if (!r)
+		return NULL;
+
+	print_resource(&pdev->dev, name, r);
+
+	addr = devm_ioremap_resource(&pdev->dev, r);
+	if (!addr)
+		dev_err(&pdev->dev, "Map of resource %s failed\n", name);
+	else
+		dev_info(&pdev->dev, "%s register mapped to %p\n", name, addr);
+
+	return addr;
+}
+
+static int pp_qos_get_resources(
+		struct platform_device *pdev,
+		struct qos_dev_init_info *info)
+{
+	int err;
+	struct pp_qos_drv_data *pdata;
+	struct device *dev;
+	void __iomem  *regaddr;
+	void *memaddr;
+
+	dev = &pdev->dev;
+	pdata = platform_get_drvdata(pdev);
+
+	/* Cmd buffer and dccm */
+	memaddr = map_mem_resource(pdev, "dccm", IORESOURCE_MEM, 0);
+	if (!memaddr)
+		return -ENODEV;
+	pdata->dccm = memaddr;
+	info->fwcom.cmdbuf = memaddr + PPV4_QOS_CMD_BUF_OFFSET;
+	info->fwcom.cmdbuf_sz = PPV4_QOS_CMD_BUF_SIZE;
+
+	memaddr = map_mem_resource(pdev, "ivt", IORESOURCE_MEM, 0);
+	if (!memaddr)
+		return -ENODEV;
+	pdata->ivt = memaddr;
+
+	/* Mbx from uc */
+	regaddr = map_reg_resource(pdev, "mbx-from-uc", IORESOURCE_MEM, 24);
+	if (!regaddr)
+		return -ENODEV;
+	info->fwcom.mbx_from_uc = regaddr;
+
+	/* Mbx to uc */
+	regaddr = map_reg_resource(pdev, "mbx-to-uc", IORESOURCE_MEM, 24);
+	if (!regaddr)
+		return -ENODEV;
+	info->fwcom.mbx_to_uc = regaddr;
+
+	regaddr = map_reg_resource(pdev, "wake-uc", IORESOURCE_MEM, 4);
+	if (!regaddr)
+		return -ENODEV;
+	pdata->wakeuc = regaddr;
+
+	err = platform_get_irq(pdev, 0);
+	if (err < 0) {
+		dev_err(dev,
+			"Could not retrieve irqline from platform err is %d\n",
+			err);
+		return err;
+	}
+	info->fwcom.irqline = err;
+	dev_info(dev, "irq is %d\n", err);
+
+	return 0;
+}
+
+static int pp_qos_config_from_of_node(
+		struct platform_device *pdev,
+		struct ppv4_qos_platform_data *pdata,
+		struct pp_qos_drv_data *pdrvdata)
+{
+	int err;
+	uint32_t val;
+	struct resource r;
+	struct device_node *node;
+	struct device *dev;
+	void *addr;
+	dma_addr_t dma;
+
+	dev = &pdev->dev;
+	node = pdev->dev.of_node;
+	dev_info(&pdev->dev, "Using device tree info to init platform data\n");
+	err = of_alias_get_id(node, "qos");
+	if (err < 0) {
+		dev_err(dev, "failed to get alias id, errno %d\n", err);
+		return err;
+	}
+	pdata->id = err;
+
+	err = of_property_read_u32(node, "intel,qos-max-port", &val);
+	if (err) {
+		dev_err(dev,
+			"Could not get max port from DT, error is %d\n",
+			err);
+		return -ENODEV;
+	}
+	pdata->max_port = val;
+
+	err = of_property_read_u32(
+			node,
+			"intel,wred-prioritize",
+			&val);
+	if (err) {
+		dev_err(dev,
+			"Could not get wred pop prioritize from DT, error is %d\n",
+			err);
+		return -ENODEV;
+	}
+	pdata->wred_prioritize_pop = val;
+
+	/* Get reserved memory region */
+	node = of_parse_phandle(node, "memory-region", 0);
+	if (!node) {
+		dev_err(dev, "No memory-region specified\n");
+		return -ENODEV;
+	}
+	err = of_address_to_resource(node, 0, &r);
+	if (err) {
+		dev_err(dev, "No memory address assigned to the region\n");
+		return err;
+	}
+
+	print_resource(dev, "ddr", &r);
+	pdrvdata->ddr_phy_start = r.start;
+	pdrvdata->ddr = devm_memremap(
+			dev,
+			r.start,
+			resource_size(&r),
+			MEMREMAP_WT);
+	if (IS_ERR_OR_NULL(pdrvdata->ddr)) {
+		err = (int) PTR_ERR(pdrvdata->ddr);
+		dev_err(dev, "devm_memremap failed mapping ddr with %d\n", err);
+		return err;
+	}
+	dev_info(dev, "DDR memory mapped to %p\n", pdrvdata->ddr);
+
+	addr = dmam_alloc_coherent(dev, PPV4_QOS_QM_BUF_SIZE, &dma, GFP_KERNEL);
+	if (addr == NULL) {
+		dev_err(dev,
+				"Could not allocate %u bytes for queue manager\n",
+				PPV4_QOS_QM_BUF_SIZE);
+		return -ENOMEM;
+	}
+	pdata->qm_num_pages =  PPV4_QOS_QM_BUF_SIZE / PPV4_QOS_PAGE_SIZE;
+	pdata->qm_ddr_start = (unsigned int)(dma);
+
+	dev_info(dev, "Dma allocated %u bytes for queue manager, bus address is 0x%08X\n",
+		 PPV4_QOS_QM_BUF_SIZE,
+		 pdata->qm_ddr_start);
+
+	addr = dmam_alloc_coherent(
+			dev,
+			PPV4_QOS_LOGGER_BUF_SIZE + PPV4_QOS_STAT_SIZE,
+			&dma,
+			GFP_KERNEL);
+	if (addr == NULL) {
+		dev_err(dev,
+				"Could not allocate %u bytes for logger buffer\n",
+				PPV4_QOS_LOGGER_BUF_SIZE);
+		return -ENOMEM;
+	}
+	pdata->fw_logger_start = (unsigned int)(dma);
+	pdata->fw_stat = pdata->fw_logger_start + PPV4_QOS_LOGGER_BUF_SIZE;
+	pdrvdata->dbg.fw_logger_addr = addr;
+
+	dev_info(dev, "Dma allocated %u bytes for fw logger, bus address is 0x%08X, virtual addr is %p\n",
+		 PPV4_QOS_LOGGER_BUF_SIZE,
+		 pdata->fw_logger_start,
+		 pdrvdata->dbg.fw_logger_addr);
+
+	return 0;
+}
+
+static int pp_qos_config_from_platform_data(
+		struct platform_device *pdev,
+		struct ppv4_qos_platform_data *pdata,
+		struct pp_qos_drv_data *pdrvdata
+		)
+{
+	struct ppv4_qos_platform_data *psrc;
+	void *memaddr;
+
+	dev_info(&pdev->dev, "Using platform info to init platform data\n");
+	psrc = (struct ppv4_qos_platform_data *)dev_get_platdata(&pdev->dev);
+	if (!psrc) {
+		dev_err(&pdev->dev, "Device contain no platform data\n");
+		return -ENODEV;
+	}
+	pdata->id = psrc->id;
+	pdata->max_port = psrc->max_port;
+	pdata->wred_prioritize_pop = psrc->wred_prioritize_pop;
+
+	/* DDR */
+	pdrvdata->ddr_phy_start = 0;
+	memaddr = map_mem_resource(pdev, "ddr", IORESOURCE_MEM, 0);
+	if (!memaddr)
+		return -ENODEV;
+	pdrvdata->ddr = memaddr;
+
+	pdata->qm_ddr_start = psrc->qm_ddr_start;
+	pdata->qm_num_pages = psrc->qm_num_pages;
+	pdata->fw_logger_start = psrc->fw_logger_start;
+	pdata->fw_stat = pdata->fw_logger_start + PPV4_QOS_LOGGER_BUF_SIZE;
+	pdrvdata->dbg.fw_logger_addr = pdrvdata->ddr + pdata->fw_logger_start;
+	return 0;
+}
+
+static int pp_qos_probe(struct platform_device *pdev)
+{
+	const struct device_node *of_node = pdev->dev.of_node;
+	struct qos_dev_init_info init_info = {};
+	const struct of_device_id *match;
+	struct pp_qos_dev *qdev;
+	int err;
+	struct pp_qos_drv_data *pdata;
+	struct device *dev;
+
+	dev = &pdev->dev;
+	dev_info(dev, "Probing...\n");
+
+	/* there is no devm_vmalloc so using dev_kzalloc */
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, pdata);
+
+	match = of_match_device(of_match_ptr(pp_qos_match), dev);
+	if (match && of_node) {
+		err = pp_qos_config_from_of_node(
+				pdev,
+				&init_info.pl_data,
+				pdata);
+		if (err)
+			return err;
+	} else if (dev_get_platdata(dev)) {
+		err = pp_qos_config_from_platform_data(
+				pdev,
+				&init_info.pl_data,
+				pdata);
+		if (err)
+			return err;
+	} else {
+		dev_err(dev, "Could not get qos configuration\n");
+		return -ENODEV;
+	}
+
+	dev_info(dev, "id(%d), max_port(%u), pop_prioritize(%u)\n",
+			init_info.pl_data.id,
+			init_info.pl_data.max_port,
+			init_info.pl_data.wred_prioritize_pop
+			);
+
+	pdata->id = init_info.pl_data.id;
+	err = pp_qos_get_resources(pdev, &init_info);
+	if (err)
+		return err;
+
+	qdev = create_qos_dev_desc(&init_info);
+	if (!qdev)
+		return -ENODEV;
+	qdev->pdev = pdev;
+	pdata->qdev = qdev;
+	qdev->stat = pdata->dbg.fw_logger_addr + PPV4_QOS_LOGGER_BUF_SIZE;
+
+	err = qos_dbg_dev_init(pdev);
+	if (err)
+		goto fail;
+
+	dev_info(dev, "Probe completed\n");
+	cur_dev = dev;
+	return 0;
+
+fail:
+	_qos_clean(qdev);
+	return err;
+}
+
+static int pp_qos_remove(struct platform_device *pdev)
+{
+	struct pp_qos_drv_data *pdata;
+
+	dev_err(&pdev->dev, "Removing...\n");
+	pdata = platform_get_drvdata(pdev);
+	remove_qos_instance(pdata->id);
+	qos_dbg_dev_clean(pdev);
+	/* TODO !!! How to cleanup? */
+	return 0;
+}
+
+static struct platform_driver pp_qos_driver = {
+	.probe = pp_qos_probe,
+	.remove = pp_qos_remove,
+	.driver = {
+		.name = "pp-qos",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_OF
+		.of_match_table = pp_qos_match,
+#endif
+	},
+};
+
+static int __init pp_qos_mod_init(void)
+{
+	int rc;
+
+	qos_module_init();
+	qos_dbg_module_init();
+	rc = platform_driver_register(&pp_qos_driver);
+	PPV4_QOS_MANUAL_ADD(rc);
+	pr_info("pp_qos_driver init, status %d\n", rc);
+	return rc;
+}
+
+static void __exit pp_qos_mod_exit(void)
+{
+	PPV4_QOS_MANUAL_REMOVE();
+	platform_driver_unregister(&pp_qos_driver);
+
+	qos_dbg_module_clean();
+	pr_info("pp_qos_driver exit\n");
+}
+
+//device_initcall(pp_qos_mod_init);
+// TODO ask Thomas
+arch_initcall(pp_qos_mod_init);
+module_exit(pp_qos_mod_exit);
+
+MODULE_VERSION(PPV4_QOS_DRV_VER);
+MODULE_AUTHOR("Intel CHD");
+MODULE_DESCRIPTION("PPv4 QoS driver");
+MODULE_LICENSE("GPL v2");
+MODULE_FIRMWARE(FIRMWARE_FILE);
diff --git a/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_main.c b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_main.c
new file mode 100644
index 0000000000000000000000000000000000000000..23383b59d0039ccdcc59457d11bf13839e8e7c04
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_main.c
@@ -0,0 +1,2191 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+#include "pp_qos_common.h"
+#include "pp_qos_utils.h"
+#include "pp_qos_fw.h"
+#include "pp_qos_drv.h"
+
+#define PP_QOS_ENTER_FUNC()		QOS_LOG_DEBUG("%s <--\n", __func__)
+#define PP_QOS_EXIT_FUNC()		QOS_LOG_DEBUG("%s -->\n", __func__)
+
+STATIC_UNLESS_TEST void update_cmd_id(struct driver_cmds *drvcmds)
+{
+	drvcmds->cmd_id++;
+	drvcmds->cmd_fw_id = 0;
+}
+
+STATIC_UNLESS_TEST void transmit_cmds(struct pp_qos_dev *qdev)
+{
+	enqueue_cmds(qdev);
+	check_completion(qdev);
+}
+
+static struct pp_qos_dev *qos_devs[MAX_QOS_INSTANCES];
+
+/******************************************************************************/
+/*                                      PORTS                                 */
+/******************************************************************************/
+static int set_port_specific_prop(struct pp_qos_dev *qdev,
+				  struct qos_node *node,
+				  const struct pp_qos_port_conf *conf,
+				  uint32_t *modified)
+{
+	if (node->data.port.ring_address != conf->ring_address) {
+		node->data.port.ring_address = conf->ring_address;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_RING_ADDRESS);
+	}
+
+	if (node->data.port.ring_size != conf->ring_size) {
+		node->data.port.ring_size = conf->ring_size;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_RING_SIZE);
+	}
+
+	if (!!(conf->packet_credit_enable) !=
+			!!QOS_BITS_IS_SET(node->flags,
+				QOS_NODE_FLAGS_PORT_PACKET_CREDIT_ENABLE)) {
+		QOS_BITS_TOGGLE(node->flags,
+				QOS_NODE_FLAGS_PORT_PACKET_CREDIT_ENABLE);
+		QOS_BITS_SET(*modified, QOS_MODIFIED_BEST_EFFORT);
+	}
+
+	if (node->data.port.credit != conf->credit) {
+		node->data.port.credit = conf->credit;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_CREDIT);
+	}
+
+	return 0;
+}
+
+STATIC_UNLESS_TEST
+int port_cfg_valid(
+		const struct pp_qos_dev *qdev,
+		const struct qos_node *node,
+		const struct qos_node *orig_node)
+{
+	if (!node_port(node)) {
+		QOS_LOG_ERR("Node is not a port\n");
+		return 0;
+	}
+
+	if (node->data.port.ring_address == NULL ||
+			node->data.port.ring_size == 0) {
+		QOS_LOG_ERR("Invalid ring address %p or ring size %zu\n",
+				node->data.port.ring_address,
+				node->data.port.ring_size);
+		return 0;
+	}
+
+	return node_cfg_valid(qdev, node, orig_node, QOS_INVALID_PHY);
+}
+
+static
+struct qos_node *get_conform_node(const struct pp_qos_dev *qdev,
+		unsigned int id,
+		int (*conform)(const struct qos_node *node))
+{
+	struct qos_node *node;
+	unsigned int phy;
+
+	phy = get_phy_from_id(qdev->mapping, id);
+	if (!QOS_PHY_VALID(phy)) {
+		QOS_LOG_ERR("Illegal id %u\n", id);
+		return NULL;
+	}
+	node = get_node_from_phy(qdev->nodes, phy);
+	if (conform && !conform(node)) {
+		QOS_LOG_ERR("Illegal id %u\n", id);
+		return NULL;
+	}
+
+	return node;
+}
+
+/******************************************************************************/
+/*                                 API                                        */
+/******************************************************************************/
+static int _pp_qos_port_set(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		const struct pp_qos_port_conf *conf);
+static int
+_pp_qos_port_conf_get(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		struct pp_qos_port_conf *conf);
+
+void pp_qos_port_conf_set_default(struct pp_qos_port_conf *conf)
+{
+	memset(conf, 0, sizeof(struct pp_qos_port_conf));
+	conf->common_prop.bandwidth_limit = QOS_NO_BANDWIDTH_LIMIT;
+	conf->common_prop.shared_bandwidth_group =
+		QOS_NO_SHARED_BANDWIDTH_GROUP;
+	conf->port_parent_prop.arbitration = PP_QOS_ARBITRATION_WSP;
+	conf->packet_credit_enable = 1;
+}
+
+int pp_qos_port_allocate(
+		struct pp_qos_dev *qdev,
+		unsigned int physical_id,
+		unsigned int *_id)
+{
+	unsigned int phy;
+	int rc;
+	unsigned int id;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (physical_id == ALLOC_PORT_ID) {
+		phy = pp_pool_get(qdev->portsphys);
+		if (!QOS_PHY_VALID(phy)) {
+			rc = -EBUSY;
+			goto out;
+		}
+	} else if (!QOS_PHY_VALID(physical_id) ||
+			!qdev->reserved_ports[physical_id]) {
+		QOS_LOG(
+				"requested physical id %u is not reserved or out of range\n",
+				physical_id);
+		rc = -EINVAL;
+		goto out;
+	} else if (node_used(get_const_node_from_phy(qdev->nodes,
+					physical_id))) {
+		QOS_LOG("port %u already used\n", physical_id);
+		rc = -EBUSY;
+		goto out;
+	} else {
+		phy = physical_id;
+	}
+
+	node_init(qdev, get_node_from_phy(qdev->nodes, phy), 1, 1, 0);
+	nodes_modify_used_status(qdev, phy, 1, 1);
+
+	id = pp_pool_get(qdev->ids);
+	QOS_ASSERT(QOS_ID_VALID(id), "got illegal id %u\n", id);
+	map_id_phy(qdev->mapping, id, phy);
+	*_id = id;
+	rc = 0;
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+int pp_qos_port_suspend(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+	struct pp_qos_port_conf conf;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = _pp_qos_port_conf_get(qdev, id, &conf);
+	if (rc)
+		goto out;
+	conf.common_prop.suspended = 1;
+	rc =  _pp_qos_port_set(qdev, id, &conf);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+
+}
+
+int pp_qos_port_resume(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+	struct pp_qos_port_conf conf;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = _pp_qos_port_conf_get(qdev, id, &conf);
+	if (rc)
+		goto out;
+	conf.common_prop.suspended = 0;
+	rc =  _pp_qos_port_set(qdev, id, &conf);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+
+}
+
+int pp_qos_port_block(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+	const struct qos_node *node;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	node = get_conform_node(qdev, id, node_port);
+	if (!node) {
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = tree_modify_blocked_status(
+			qdev,
+			get_phy_from_id(qdev->mapping, id), 1);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+
+}
+
+int pp_qos_port_unblock(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+	const struct qos_node *node;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	node = get_conform_node(qdev, id, node_port);
+	if (!node) {
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = tree_modify_blocked_status(
+			qdev,
+			get_phy_from_id(qdev->mapping, id), 0);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+
+}
+
+int pp_qos_port_flush(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+	const struct qos_node *node;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	node = get_conform_node(qdev, id, node_port);
+	if (!node) {
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = tree_flush(qdev, get_phy_from_id(qdev->mapping, id));
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+int pp_qos_port_remove(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+	const struct qos_node *node;
+	unsigned int phy;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	node = get_conform_node(qdev, id, node_port);
+	if (!node) {
+		rc = -EINVAL;
+		goto out;
+	}
+	phy = get_phy_from_node(qdev->nodes, node);
+	rc = tree_remove(qdev, phy);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+static int _pp_qos_port_conf_get(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		struct pp_qos_port_conf *conf)
+{
+	const struct qos_node *node;
+
+	if (conf == NULL)
+		return -EINVAL;
+
+	node = get_conform_node(qdev, id, node_port);
+	if (!node)
+		return -EINVAL;
+
+	conf->ring_address = node->data.port.ring_address;
+	conf->ring_size = node->data.port.ring_size;
+	conf->packet_credit_enable = !!QOS_BITS_IS_SET(node->flags,
+			QOS_NODE_FLAGS_PORT_PACKET_CREDIT_ENABLE);
+	conf->credit = node->data.port.credit;
+	return  get_node_prop(
+			qdev,
+			node,
+			&conf->common_prop,
+			&conf->port_parent_prop,
+			NULL);
+}
+
+int pp_qos_port_conf_get(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		struct pp_qos_port_conf *conf)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = _pp_qos_port_conf_get(qdev, id, conf);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+int pp_qos_port_info_get(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		struct pp_qos_port_info *info)
+{
+	int rc;
+	const struct qos_node *node;
+	unsigned int phy;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (info == NULL) {
+		rc = -EINVAL;
+		goto out;
+	}
+	node = get_conform_node(qdev, id, node_port);
+	if (!node) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	phy = get_phy_from_node(qdev->nodes, node);
+	info->physical_id = phy;
+	get_node_queues(qdev, phy, NULL, 0, &info->num_of_queues);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+	rc = 0;
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+int pp_qos_port_get_queues(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		uint16_t *queue_ids,
+		unsigned int size,
+		unsigned int *queues_num)
+{
+	int rc;
+	unsigned int phy;
+	const struct qos_node *node;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	node = get_conform_node(qdev, id, node_port);
+	if (!node) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	phy = get_phy_from_node(qdev->nodes, node);
+	get_node_queues(qdev, phy, queue_ids, size, queues_num);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+	rc = 0;
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+static int _pp_qos_port_set(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		const struct pp_qos_port_conf *conf)
+{
+	int rc;
+	uint32_t modified;
+	struct qos_node node;
+	struct qos_node *nodep;
+	uint16_t phy;
+
+	modified = 0;
+
+	nodep = get_conform_node(qdev, id, NULL);
+	if (!nodep)
+		return -EINVAL;
+	memcpy(&node, nodep, sizeof(node));
+
+	if (node.type != TYPE_PORT) {
+		node.type = TYPE_PORT;
+		QOS_BITS_SET(modified, QOS_MODIFIED_NODE_TYPE);
+	}
+
+	rc = set_node_prop(
+			qdev,
+			&node,
+			&conf->common_prop,
+			&conf->port_parent_prop,
+			NULL,
+			&modified);
+	if (rc)
+		return rc;
+
+	rc = set_port_specific_prop(qdev, &node, conf, &modified);
+	if (rc)
+		return rc;
+
+	if (!port_cfg_valid(qdev, &node, nodep))
+		return -EINVAL;
+
+	memcpy(nodep, &node, sizeof(struct qos_node));
+
+	if (modified) {
+		phy = get_phy_from_node(qdev->nodes, nodep);
+		create_set_port_cmd(qdev, conf, phy, modified);
+	}
+
+	return 0;
+}
+
+int pp_qos_port_set(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		const struct pp_qos_port_conf *conf)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = _pp_qos_port_set(qdev, id, conf);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+/**
+ * pp_qos_port_stat_get() - Get port's statistics
+ * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
+ * @id:	  queue's id obtained from queue_allocate
+ * @stat: pointer to struct to be filled with queue's statistics
+ *
+ * Return: 0 on success
+ */
+int pp_qos_port_stat_get(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		struct pp_qos_port_stat *stat)
+{
+	int rc;
+	struct qos_node *node;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	node = get_conform_node(qdev, id, node_port);
+	if (!node) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	create_get_port_stats_cmd(
+			qdev,
+			get_phy_from_node(qdev->nodes, node),
+			qdev->hwconf.fw_stat,
+			stat);
+
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+
+	rc = 0;
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+
+/******************************************************************************/
+/*                                     QUEUES                                 */
+/******************************************************************************/
+static int _pp_qos_queue_set(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		const struct pp_qos_queue_conf *conf);
+static int _pp_qos_queue_conf_get(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		struct pp_qos_queue_conf *conf);
+
+static void node_queue_init(struct pp_qos_dev *qdev, struct qos_node *node)
+{
+	node_init(qdev, node, 1, 0, 1);
+	memset(&(node->data.queue), 0x0, sizeof(struct _queue));
+	node->type = TYPE_QUEUE;
+}
+
+static int set_queue_specific_prop(struct pp_qos_dev *qdev,
+				  struct qos_node *node,
+				  const struct pp_qos_queue_conf *conf,
+				  uint32_t *modified)
+{
+	if (node->data.queue.max_burst != conf->max_burst) {
+		node->data.queue.max_burst = conf->max_burst;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_MAX_BURST);
+	}
+
+	if (node->data.queue.green_min != conf->queue_wred_min_avg_green) {
+		node->data.queue.green_min = conf->queue_wred_min_avg_green;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_WRED_MIN_GREEN);
+	}
+
+	if (node->data.queue.green_max != conf->queue_wred_max_avg_green) {
+		node->data.queue.green_max = conf->queue_wred_max_avg_green;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_WRED_MAX_GREEN);
+	}
+
+	if (node->data.queue.green_slope != conf->queue_wred_slope_green) {
+		node->data.queue.green_slope = conf->queue_wred_slope_green;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_WRED_SLOPE_GREEN);
+	}
+
+	if (node->data.queue.yellow_min != conf->queue_wred_min_avg_yellow) {
+		node->data.queue.yellow_min = conf->queue_wred_min_avg_yellow;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_WRED_MIN_YELLOW);
+	}
+
+	if (node->data.queue.yellow_max != conf->queue_wred_max_avg_yellow) {
+		node->data.queue.yellow_max = conf->queue_wred_max_avg_yellow;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_WRED_MAX_YELLOW);
+	}
+
+	if (node->data.queue.yellow_slope != conf->queue_wred_slope_yellow) {
+		node->data.queue.yellow_slope = conf->queue_wred_slope_yellow;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_WRED_SLOPE_YELLOW);
+	}
+
+	if (node->data.queue.max_burst != conf->max_burst) {
+		node->data.queue.max_burst = conf->max_burst;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_MAX_BURST);
+	}
+
+	if (node->data.queue.max_allowed != conf->queue_wred_max_allowed) {
+		node->data.queue.max_allowed = conf->queue_wred_max_allowed;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_WRED_MAX_ALLOWED);
+	}
+
+	if (node->data.queue.min_guaranteed !=
+			conf->queue_wred_min_guaranteed) {
+		node->data.queue.min_guaranteed =
+			conf->queue_wred_min_guaranteed;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_WRED_MIN_GUARANTEED);
+	}
+
+	if (!!(conf->wred_enable) !=
+			!!QOS_BITS_IS_SET(node->flags,
+				QOS_NODE_FLAGS_QUEUE_WRED_ENABLE)) {
+		QOS_BITS_TOGGLE(node->flags, QOS_NODE_FLAGS_QUEUE_WRED_ENABLE);
+		QOS_BITS_SET(*modified, QOS_MODIFIED_WRED_ENABLE);
+	}
+
+	if (!!(conf->wred_fixed_drop_prob_enable) !=
+			!!QOS_BITS_IS_SET(node->flags,
+			QOS_NODE_FLAGS_QUEUE_WRED_FIXED_DROP_PROB_ENABLE)) {
+		QOS_BITS_TOGGLE(node->flags,
+			QOS_NODE_FLAGS_QUEUE_WRED_FIXED_DROP_PROB_ENABLE);
+		QOS_BITS_SET(*modified,
+			QOS_MODIFIED_WRED_FIXED_DROP_PROB_ENABLE);
+	}
+
+	if (node->data.queue.fixed_green_prob !=
+			conf->queue_wred_fixed_drop_prob_green) {
+		node->data.queue.fixed_green_prob =
+			conf->queue_wred_fixed_drop_prob_green;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_WRED_FIXED_GREEN_PROB);
+	}
+
+	if (node->data.queue.fixed_yellow_prob !=
+			conf->queue_wred_fixed_drop_prob_yellow) {
+		node->data.queue.fixed_yellow_prob =
+			conf->queue_wred_fixed_drop_prob_yellow;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_WRED_FIXED_YELLOW_PROB);
+	}
+
+	if (!!(conf->blocked) !=
+			!!QOS_BITS_IS_SET(node->flags,
+				QOS_NODE_FLAGS_QUEUE_BLOCKED)) {
+		QOS_BITS_TOGGLE(node->flags, QOS_NODE_FLAGS_QUEUE_BLOCKED);
+		QOS_BITS_SET(*modified, QOS_MODIFIED_BLOCKED);
+	}
+	return 0;
+}
+
+STATIC_UNLESS_TEST int queue_cfg_valid(
+		const struct pp_qos_dev *qdev,
+		const struct qos_node *node,
+		const struct qos_node *orig_node,
+		unsigned int prev_virt_parent_phy)
+{
+	if (!node_queue(node)) {
+		QOS_LOG("Node is not a queue\n");
+		return 0;
+	}
+
+	return node_cfg_valid(qdev, node, orig_node, prev_virt_parent_phy);
+}
+
+static int check_queue_conf_validity(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		const struct pp_qos_queue_conf *conf,
+		struct qos_node *node,
+		uint32_t *modified)
+{
+	unsigned int phy;
+	int rc;
+	struct qos_node *nodep;
+
+	/*
+	 * The phy of the current first ancesstor which is not an
+	 * internal scheduler QOS_INVALID_PHY if it is a new queue
+	 */
+	unsigned int prev_virt_parent_phy;
+
+	/* Check if node id is valid */
+	phy = get_phy_from_id(qdev->mapping, id);
+	if (!QOS_PHY_VALID(phy)) {
+		if (!QOS_PHY_UNKNOWN(phy)) {
+			QOS_LOG_ERR("Id %u is not a node\n", id);
+			return -EINVAL;
+		}
+		nodep = NULL;
+
+		/* New queue which has id, but no phy was allocated for it */
+		node_queue_init(qdev, node);
+		node->data.queue.rlm = pp_pool_get(qdev->rlms);
+		if (node->data.queue.rlm == QOS_INVALID_RLM) {
+			QOS_LOG_ERR("Can't get free rlm\n");
+			return  -EBUSY;
+		}
+		QOS_BITS_SET(node->flags, QOS_NODE_FLAGS_USED);
+		QOS_BITS_SET(*modified,
+			     QOS_MODIFIED_NODE_TYPE |
+			     QOS_MODIFIED_SUSPENDED |
+			     QOS_MODIFIED_BANDWIDTH_LIMIT |
+			     QOS_MODIFIED_PRIORITY |
+			     QOS_MODIFIED_VIRT_BW_SHARE |
+			     QOS_MODIFIED_PARENT |
+			     QOS_MODIFIED_MAX_BURST |
+			     QOS_MODIFIED_BLOCKED |
+			     QOS_MODIFIED_WRED_ENABLE |
+			     QOS_MODIFIED_WRED_FIXED_DROP_PROB_ENABLE |
+			     QOS_MODIFIED_WRED_FIXED_GREEN_PROB |
+			     QOS_MODIFIED_WRED_FIXED_YELLOW_PROB |
+			     QOS_MODIFIED_WRED_MIN_GREEN |
+			     QOS_MODIFIED_WRED_MAX_GREEN |
+			     QOS_MODIFIED_WRED_SLOPE_GREEN |
+			     QOS_MODIFIED_WRED_MIN_YELLOW |
+			     QOS_MODIFIED_WRED_MAX_YELLOW |
+			     QOS_MODIFIED_WRED_SLOPE_YELLOW |
+			     QOS_MODIFIED_WRED_MAX_ALLOWED |
+			     QOS_MODIFIED_WRED_MIN_GUARANTEED |
+			     QOS_MODIFIED_RLM);
+		prev_virt_parent_phy = QOS_INVALID_PHY;
+	} else {
+		nodep = get_node_from_phy(qdev->nodes, phy);
+		if (!node_queue(nodep)) {
+			QOS_LOG("Id %u is not a queue\n", id);
+			rc = -EINVAL;
+		}
+		memcpy(node, nodep, sizeof(struct qos_node));
+		prev_virt_parent_phy = get_virtual_parent_phy(
+				qdev->nodes,
+				node);
+	}
+
+	/*
+	 * Before calling set_node_prop:
+	 * If new node
+	 *	node.child.parent.phy = INVALID_PHY
+	 *	prev_virt_parent_phy = INVALID_PHY
+	 * Else
+	 *	node.child.parent.phy = actual parent
+	 *	prev_virt_parent_phy = virtual parent
+	 *	(i.e. first non internal ancestor)
+	 *
+	 * When returning:
+	 * If new node
+	 *     node.child.parent.phy == virtual parent phy
+	 * Else
+	 *     If map_id_to_phy(conf.parent) != prev_virt_parent_phy
+	 *		node.child.parent.phy = map_id_to_phy(conf.parent)
+	 *     Else
+	 *		node.child.parent.phy = actual parent (no change)
+	 *
+	 */
+	rc = set_node_prop(
+			qdev,
+			node,
+			&conf->common_prop,
+			NULL,
+			&conf->queue_child_prop,
+			modified);
+	if (rc)
+		return rc;
+
+	rc = set_queue_specific_prop(qdev, node, conf, modified);
+	if (rc)
+		return rc;
+
+	if (!queue_cfg_valid(qdev, node, nodep, prev_virt_parent_phy))
+		return -EINVAL;
+
+	return 0;
+}
+
+void pp_qos_queue_conf_set_default(struct pp_qos_queue_conf *conf)
+{
+	memset(conf, 0, sizeof(struct pp_qos_queue_conf));
+	conf->common_prop.bandwidth_limit = QOS_NO_BANDWIDTH_LIMIT;
+	conf->common_prop.shared_bandwidth_group =
+		QOS_NO_SHARED_BANDWIDTH_GROUP;
+}
+
+int pp_qos_queue_allocate(struct pp_qos_dev *qdev, unsigned int *id)
+{
+	int rc;
+	uint16_t _id;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	_id = pp_pool_get(qdev->ids);
+	QOS_ASSERT(QOS_ID_VALID(_id), "got illegal id %u\n", _id);
+	*id = _id;
+	map_id_reserved(qdev->mapping, _id);
+	rc = 0;
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+static int _pp_qos_queue_conf_get(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		struct pp_qos_queue_conf *conf)
+{
+	const struct qos_node *node;
+
+	if (conf == NULL)
+		return -EINVAL;
+
+	node = get_conform_node(qdev, id, node_queue);
+	if (!node)
+		return -EINVAL;
+
+	conf->max_burst = node->data.queue.max_burst;
+	conf->queue_wred_min_avg_green = node->data.queue.green_min;
+	conf->queue_wred_max_avg_green = node->data.queue.green_max;
+	conf->queue_wred_slope_green = node->data.queue.green_slope;
+	conf->queue_wred_min_avg_yellow = node->data.queue.yellow_min;
+	conf->queue_wred_max_avg_yellow = node->data.queue.yellow_max;
+	conf->queue_wred_slope_yellow = node->data.queue.yellow_slope;
+	conf->queue_wred_max_allowed = node->data.queue.max_allowed;
+	conf->queue_wred_min_guaranteed = node->data.queue.min_guaranteed;
+	conf->queue_wred_fixed_drop_prob_green =
+		node->data.queue.fixed_green_prob;
+	conf->queue_wred_fixed_drop_prob_yellow =
+		node->data.queue.fixed_yellow_prob;
+	conf->wred_enable =
+		!!QOS_BITS_IS_SET(node->flags,
+				QOS_NODE_FLAGS_QUEUE_WRED_ENABLE);
+	conf->wred_fixed_drop_prob_enable =
+		!!QOS_BITS_IS_SET(node->flags,
+			QOS_NODE_FLAGS_QUEUE_WRED_FIXED_DROP_PROB_ENABLE);
+	conf->blocked =
+		!!QOS_BITS_IS_SET(node->flags,
+				QOS_NODE_FLAGS_QUEUE_BLOCKED);
+	return get_node_prop(
+			qdev,
+			node,
+			&conf->common_prop,
+			NULL,
+			&conf->queue_child_prop);
+}
+
+int pp_qos_queue_conf_get(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		struct pp_qos_queue_conf *conf)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = _pp_qos_queue_conf_get(qdev, id, conf);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+static int _pp_qos_queue_remove(struct pp_qos_dev *qdev, int id)
+{
+	struct qos_node *node;
+	int rc;
+
+	node = get_conform_node(qdev, id, node_queue);
+	if (!node)
+		return -EINVAL;
+
+	rc  = node_remove(qdev, node);
+	return rc;
+}
+
+/**
+ * pp_qos_queue_remove() -	Remove a queue
+ * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
+ * @id:   queue's id obtained from queue_allocate
+ *
+ * Note: client should make sure that queue is empty and
+ * that new packets are not enqueued, by calling
+ *       pp_qos_queue_disable and pp_qos_queue_flush
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_remove(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = _pp_qos_queue_remove(qdev, id);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+
+/**
+ * pp_qos_queue_set() - Set queue configuration
+ * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
+ * @id:	  queue's id obtained from queue_allocate
+ * @conf: new configuration for the queue
+ *
+ * Return: 0 on success
+ */
+static int _pp_qos_queue_set(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		const struct pp_qos_queue_conf *conf)
+{
+	int rc;
+	unsigned int phy;
+	unsigned int prev_phy;
+	struct qos_node *parent;
+	struct qos_node node;
+	struct qos_node *nodep;
+	uint32_t modified;
+	int parent_changed;
+	unsigned int dst_port;
+
+	modified = 0;
+	nodep = NULL;
+
+	rc = check_queue_conf_validity(qdev, id, conf, &node, &modified);
+	parent_changed = QOS_BITS_IS_SET(modified, QOS_MODIFIED_PARENT);
+	if (rc)
+		goto out;
+
+	if (parent_changed) {
+		parent = get_node_from_phy(
+				qdev->nodes,
+				node.child_prop.parent_phy);
+		phy = phy_alloc_by_parent(
+				qdev,
+				parent,
+				conf->queue_child_prop.priority);
+		if (!QOS_PHY_VALID(phy)) {
+			rc = -EINVAL;
+			goto out;
+		}
+		nodep = get_node_from_phy(qdev->nodes, phy);
+		node.child_prop.parent_phy = nodep->child_prop.parent_phy;
+		memcpy(nodep, &node, sizeof(struct qos_node));
+
+		/* If this is not a new queue - delete previous node */
+		if (!QOS_BITS_IS_SET(modified, QOS_MODIFIED_NODE_TYPE)) {
+			prev_phy = get_phy_from_id(qdev->mapping, id);
+			dst_port = get_port(qdev->nodes, phy);
+			create_move_cmd(qdev, phy, prev_phy, dst_port);
+			map_invalidate_id(qdev->mapping, id);
+			map_id_phy(qdev->mapping, id, phy);
+			node_phy_delete(qdev, prev_phy);
+			phy = get_phy_from_id(qdev->mapping, id);
+			nodep = get_node_from_phy(qdev->nodes, phy);
+		} else {
+			map_id_phy(qdev->mapping, id, phy);
+		}
+
+		parent = get_node_from_phy(
+				qdev->nodes,
+				nodep->child_prop.parent_phy);
+		if (nodep->child_prop.virt_bw_share && node_internal(parent))
+			update_internal_bandwidth(qdev, parent);
+	} else {
+		phy = get_phy_from_id(qdev->mapping, id);
+		nodep = get_node_from_phy(qdev->nodes, phy);
+		memcpy(nodep, &node, sizeof(struct qos_node));
+	}
+
+	if (modified) {
+		create_set_queue_cmd(
+				qdev,
+				conf,
+				phy,
+				nodep->child_prop.parent_phy,
+				nodep->data.queue.rlm,
+				modified);
+		create_update_preds_cmd(qdev, phy);
+	}
+out:
+	if (rc) {
+		if (parent_changed) {
+			if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_RLM))
+				release_rlm(qdev->rlms, node.data.queue.rlm);
+		}
+	}
+	return rc;
+}
+
+int pp_qos_queue_set(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		const struct pp_qos_queue_conf *conf)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = _pp_qos_queue_set(qdev, id, conf);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+static int _pp_qos_queue_suspend(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+	struct pp_qos_queue_conf conf;
+
+	rc = _pp_qos_queue_conf_get(qdev, id, &conf);
+	if (rc)
+		return rc;
+	conf.common_prop.suspended = 1;
+	return _pp_qos_queue_set(qdev, id, &conf);
+}
+
+/**
+ * pp_qos_queue_suspend() - Remove queue from scheduling (doesn't get bandwidth)
+ * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
+ * @id:	  queue's id obtained from queue_allocate
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_suspend(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = _pp_qos_queue_suspend(qdev, id);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+
+static int _pp_qos_queue_resume(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+	struct pp_qos_queue_conf conf;
+
+	rc = _pp_qos_queue_conf_get(qdev, id, &conf);
+	if (rc)
+		return rc;
+	conf.common_prop.suspended = 0;
+	return _pp_qos_queue_set(qdev, id, &conf);
+}
+
+/**
+ * pp_qos_queue_resume() -	Return queue to be scheduleable
+ * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
+ * @id:   queue's id obtained from queue_allocate
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_resume(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = _pp_qos_queue_resume(qdev, id);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+int _pp_qos_queue_block(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+	struct pp_qos_queue_conf conf;
+
+	rc = _pp_qos_queue_conf_get(qdev, id, &conf);
+	if (rc)
+		return rc;
+	conf.blocked = 1;
+	return _pp_qos_queue_set(qdev, id, &conf);
+}
+
+/**
+ * pp_qos_queue_block() - All new packets enqueue to this queue will be dropped
+ * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
+ * @id:   queue's id obtained from queue_allocate
+ *
+ * Note	- already enqueued descriptors will be transmitted
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_block(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = _pp_qos_queue_block(qdev, id);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+int _pp_qos_queue_unblock(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+	struct pp_qos_queue_conf conf;
+
+	rc = _pp_qos_queue_conf_get(qdev, id, &conf);
+	if (rc)
+		return rc;
+
+	conf.blocked = 0;
+	return _pp_qos_queue_set(qdev, id, &conf);
+}
+
+/**
+ * pp_qos_queue_unblock() - Unblock enqueuing of new packets
+ * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
+ * @id:	  queue's id obtained from queue_allocate
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_unblock(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = _pp_qos_queue_unblock(qdev, id);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+
+int _pp_qos_queue_flush(struct pp_qos_dev *qdev, unsigned int id)
+{
+	struct qos_node *node;
+
+	node = get_conform_node(qdev, id, node_queue);
+	if (!node)
+		return -EINVAL;
+	return node_flush(qdev, node);
+}
+
+/**
+ * pp_qos_queue_flush() - Drop all enqueued packets
+ * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
+ * @id:	  queue's id obtained from queue_allocate
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_flush(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = _pp_qos_queue_flush(qdev, id);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+
+/**
+ * pp_qos_queue_info_get() - Get information about queue
+ * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
+ * @id:	  queue's id obtained from queue_allocate
+ * @info: pointer to struct to be filled with queue's info
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_info_get(struct pp_qos_dev *qdev, unsigned int id,
+			  struct pp_qos_queue_info *info)
+{
+	int rc;
+	struct qos_node *node;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (info == NULL) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	node = get_conform_node(qdev, id, node_queue);
+
+	if (!node) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	info->physical_id = node->data.queue.rlm;
+	info->port_id = get_port(
+			qdev->nodes,
+			get_phy_from_node(qdev->nodes, node));
+	rc = 0;
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+/**
+ * pp_qos_queue_stat_get() - Get queue's statistics
+ * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
+ * @id:	  queue's id obtained from queue_allocate
+ * @stat: pointer to struct to be filled with queue's statistics
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_stat_get(struct pp_qos_dev *qdev, unsigned int id,
+			  struct pp_qos_queue_stat *stat)
+{
+	int rc;
+	struct qos_node *node;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	node = get_conform_node(qdev, id, node_queue);
+	if (!node) {
+		rc = -EINVAL;
+		goto out;
+	}
+	create_get_queue_stats_cmd(
+			qdev,
+			get_phy_from_node(qdev->nodes, node),
+			node->data.queue.rlm,
+			qdev->hwconf.fw_stat,
+			stat);
+
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+
+	rc = 0;
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+/******************************************************************************/
+/*                                 Schedulers                                 */
+/******************************************************************************/
+static int _pp_qos_sched_set(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		const struct pp_qos_sched_conf *conf);
+static int _pp_qos_sched_conf_get(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		struct pp_qos_sched_conf *conf);
+
+static void node_sched_init(struct pp_qos_dev *qdev, struct qos_node *node)
+{
+	node_init(qdev, node, 1, 1, 1);
+	node->type = TYPE_SCHED;
+}
+
+STATIC_UNLESS_TEST int sched_cfg_valid(
+		const struct pp_qos_dev *qdev,
+		const struct qos_node *node,
+		const struct qos_node *orig_node,
+		unsigned int prev_virt_parent_phy)
+{
+	if (!node_sched(node)) {
+		QOS_LOG_ERR("Node is not a sched\n");
+		return 0;
+	}
+
+	return node_cfg_valid(qdev, node, orig_node, prev_virt_parent_phy);
+}
+
+static int check_sched_conf_validity(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		const struct pp_qos_sched_conf *conf,
+		struct qos_node *node,
+		uint32_t *modified)
+{
+	unsigned int phy;
+	int rc;
+	struct qos_node *nodep;
+	unsigned int prev_virt_parent_phy_phy;
+
+	/* Check if node id is valid */
+	phy = get_phy_from_id(qdev->mapping, id);
+	if (!QOS_PHY_VALID(phy)) {
+		if (!QOS_PHY_UNKNOWN(phy)) {
+			QOS_LOG_ERR("Id %u is not a node\n", id);
+			return -EINVAL;
+		}
+
+		/* New sched which has id, but no phy was allocated for it */
+		node_sched_init(qdev, node);
+		QOS_BITS_SET(node->flags, QOS_NODE_FLAGS_USED);
+		QOS_BITS_SET(*modified,
+			     QOS_MODIFIED_NODE_TYPE |
+			     QOS_MODIFIED_SUSPENDED |
+			     QOS_MODIFIED_SHARED_GROUP_LIMIT |
+			     QOS_MODIFIED_BANDWIDTH_LIMIT |
+			     QOS_MODIFIED_PRIORITY |
+			     QOS_MODIFIED_VIRT_BW_SHARE |
+			     QOS_MODIFIED_PARENT |
+			     QOS_MODIFIED_ARBITRATION |
+			     QOS_MODIFIED_BEST_EFFORT);
+
+		nodep = NULL;
+		prev_virt_parent_phy_phy = QOS_INVALID_PHY;
+	} else {
+		nodep = get_node_from_phy(qdev->nodes, phy);
+		if (!node_sched(nodep)) {
+			QOS_LOG_ERR("Id %u is not a sched\n", id);
+			rc = -EINVAL;
+		}
+		memcpy(node, nodep, sizeof(struct qos_node));
+		prev_virt_parent_phy_phy = get_virtual_parent_phy(
+				qdev->nodes,
+				node);
+	}
+
+	rc = set_node_prop(qdev,
+			node,
+			&conf->common_prop,
+			&conf->sched_parent_prop,
+			&conf->sched_child_prop,
+			modified);
+	if (rc)
+		return rc;
+
+	if (!sched_cfg_valid(qdev, node, nodep, prev_virt_parent_phy_phy))
+		return -EINVAL;
+
+	return 0;
+}
+
+void pp_qos_sched_conf_set_default(struct pp_qos_sched_conf *conf)
+{
+	memset(conf, 0, sizeof(struct pp_qos_sched_conf));
+	conf->common_prop.bandwidth_limit = QOS_NO_BANDWIDTH_LIMIT;
+	conf->common_prop.shared_bandwidth_group =
+		QOS_NO_SHARED_BANDWIDTH_GROUP;
+	conf->sched_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+}
+
+int pp_qos_sched_allocate(struct pp_qos_dev *qdev, unsigned int *id)
+{
+	uint16_t _id;
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	_id = pp_pool_get(qdev->ids);
+	QOS_ASSERT(QOS_ID_VALID(_id), "got illegal id %u\n", _id);
+	*id = _id;
+	map_id_reserved(qdev->mapping, _id);
+	rc = 0;
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+int pp_qos_sched_remove(struct pp_qos_dev *qdev, unsigned int id)
+{
+	struct qos_node *node;
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	node = get_conform_node(qdev, id, node_sched);
+	if (!node)  {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = tree_remove(qdev, get_phy_from_node(qdev->nodes, node));
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+static int _pp_qos_sched_set(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		const struct pp_qos_sched_conf *conf)
+{
+	int rc;
+	unsigned int phy;
+	unsigned int prev_phy;
+	struct qos_node *parent;
+	struct qos_node node;
+	struct qos_node *nodep;
+	struct qos_node *oldnode;
+	uint32_t modified;
+	unsigned int dst_port;
+
+	modified = 0;
+
+	rc = check_sched_conf_validity(qdev, id, conf, &node, &modified);
+	if (rc)
+		return rc;
+
+	if (QOS_BITS_IS_SET(modified, QOS_MODIFIED_PARENT)) {
+		parent = get_node_from_phy(
+				qdev->nodes,
+				node.child_prop.parent_phy);
+		phy = phy_alloc_by_parent(
+				qdev,
+				parent,
+				conf->sched_child_prop.priority);
+		if (!QOS_PHY_VALID(phy))
+			return -EINVAL;
+
+		/*
+		 * nodep's parent_phy holds value of actual parent, node's
+		 * parent_phy holds phy of virtual parent
+		 */
+		nodep = get_node_from_phy(qdev->nodes, phy);
+		node.child_prop.parent_phy = nodep->child_prop.parent_phy;
+		memcpy(nodep, &node, sizeof(struct qos_node));
+
+		/* If this is not a new sched - delete previous node */
+		if (!QOS_BITS_IS_SET(modified, QOS_MODIFIED_NODE_TYPE)) {
+			prev_phy = get_phy_from_id(qdev->mapping, id);
+			dst_port = get_port(qdev->nodes, phy);
+			create_move_cmd(qdev, phy, prev_phy, dst_port);
+			node_update_children(qdev, prev_phy, phy);
+			map_invalidate_id(qdev->mapping, id);
+			map_id_phy(qdev->mapping, id, phy);
+			oldnode = get_node_from_phy(qdev->nodes, prev_phy);
+			nodep->parent_prop.first_child_phy =
+				oldnode->parent_prop.first_child_phy;
+			nodep->parent_prop.num_of_children =
+				oldnode->parent_prop.num_of_children;
+			oldnode->parent_prop.first_child_phy = QOS_INVALID_PHY;
+			oldnode->parent_prop.num_of_children = 0;
+			node_phy_delete(qdev, prev_phy);
+			phy = get_phy_from_id(qdev->mapping, id);
+			nodep = get_node_from_phy(qdev->nodes, phy);
+			tree_update_predecessors(qdev, phy);
+		} else {
+			map_id_phy(qdev->mapping, id, phy);
+		}
+
+		parent = get_node_from_phy(
+				qdev->nodes,
+				nodep->child_prop.parent_phy);
+		if (nodep->child_prop.virt_bw_share && node_internal(parent))
+			update_internal_bandwidth(qdev, parent);
+	} else {
+		phy = get_phy_from_id(qdev->mapping, id);
+		nodep = get_node_from_phy(qdev->nodes, phy);
+		memcpy(nodep, &node, sizeof(struct qos_node));
+	}
+
+	if (modified) {
+		create_set_sched_cmd(
+				qdev,
+				conf,
+				phy,
+				nodep->child_prop.parent_phy,
+				modified);
+		create_update_preds_cmd(qdev, phy);
+	}
+	return 0;
+}
+
+int pp_qos_sched_set(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		const struct pp_qos_sched_conf *conf)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = _pp_qos_sched_set(qdev, id, conf);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+static int _pp_qos_sched_conf_get(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		struct pp_qos_sched_conf *conf)
+{
+	const struct qos_node *node;
+
+	if (conf == NULL)
+		return -EINVAL;
+
+	node = get_conform_node(qdev, id, node_sched);
+	if (!node)
+		return -EINVAL;
+
+	return get_node_prop(
+			qdev,
+			node,
+			&conf->common_prop,
+			&conf->sched_parent_prop,
+			&conf->sched_child_prop);
+}
+
+int pp_qos_sched_conf_get(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		struct pp_qos_sched_conf *conf)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = _pp_qos_sched_conf_get(qdev, id, conf);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+int pp_qos_sched_suspend(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+	struct pp_qos_sched_conf conf;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = _pp_qos_sched_conf_get(qdev, id, &conf);
+	if (rc)
+		goto out;
+	conf.common_prop.suspended = 1;
+	rc =  _pp_qos_sched_set(qdev, id, &conf);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+
+}
+
+int pp_qos_sched_resume(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+	struct pp_qos_sched_conf conf;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = _pp_qos_sched_conf_get(qdev, id, &conf);
+	if (rc)
+		goto out;
+	conf.common_prop.suspended = 0;
+	rc = _pp_qos_sched_set(qdev, id, &conf);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+int pp_qos_sched_info_get(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		struct pp_qos_sched_info *info)
+{
+	int rc;
+	struct qos_node *node;
+	unsigned int phy;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (info == NULL) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	node = get_conform_node(qdev, id, node_sched);
+
+	if (!node) {
+		rc = -EINVAL;
+		goto out;
+	}
+	phy = get_phy_from_node(qdev->nodes, node);
+	info->port_id = get_port(
+			qdev->nodes,
+			get_phy_from_node(qdev->nodes, node));
+	get_node_queues(qdev, phy, NULL, 0, &info->num_of_queues);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+	rc = 0;
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+int pp_qos_sched_get_queues(struct pp_qos_dev *qdev, unsigned int id,
+			    uint16_t *queue_ids, unsigned int size,
+			    unsigned int *queues_num)
+{
+	int rc;
+	unsigned int phy;
+	const struct qos_node *node;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	node = get_conform_node(qdev, id, node_sched);
+	if (!node) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	phy = get_phy_from_node(qdev->nodes, node);
+	get_node_queues(qdev, phy, queue_ids, size, queues_num);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+	rc = 0;
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+int pp_qos_get_fw_version(
+		struct pp_qos_dev *qdev,
+		unsigned int *major,
+		unsigned int *minor,
+		unsigned int *build)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	*major = qdev->fwver.major;
+	*minor = qdev->fwver.minor;
+	*build = qdev->fwver.build;
+	rc = 0;
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+/******************************************************************************/
+/*                                 Node                                       */
+/******************************************************************************/
+int pp_qos_get_node_info(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		struct pp_qos_node_info *info)
+{
+	int rc;
+	struct qos_node *node;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	node = get_conform_node(qdev, id, node_used);
+	if (!node) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	create_get_node_info_cmd(
+			qdev,
+			get_phy_from_node(qdev->nodes, node),
+			qdev->hwconf.fw_stat,
+			info);
+
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+
+	rc = 0;
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+
+}
+
+/******************************************************************************/
+/*                                 SHARED_LIMIT                               */
+/******************************************************************************/
+static int _pp_qos_shared_limit_group_get_members(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		uint16_t *members,
+		unsigned int size,
+		unsigned int *members_num);
+
+int pp_qos_shared_limit_group_add(
+		struct pp_qos_dev *qdev,
+		unsigned int limit,
+		unsigned int *id)
+{
+	unsigned int i;
+	int rc;
+	struct shared_bandwidth_group *grp;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	grp = qdev->groups + 1;
+	for (i = 1; i <= QOS_MAX_SHARED_BANDWIDTH_GROUP; ++grp, ++i) {
+		if (!grp->used)
+			break;
+	}
+
+	if (grp->used) {
+		QOS_LOG_ERR("No free shared groups\n");
+		rc = -EBUSY;
+		goto out;
+	}
+
+	grp->used = 1;
+	grp->limit = limit;
+	*id = i;
+
+	create_add_shared_group_cmd(qdev, i, limit);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+	rc = 0;
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+int pp_qos_shared_limit_group_remove(struct pp_qos_dev *qdev, unsigned int id)
+{
+	int rc;
+	unsigned int num;
+	uint16_t tmp;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	if (QOS_BW_GRP_VALID(id) && (qdev->groups[id].used)) {
+		_pp_qos_shared_limit_group_get_members(
+				qdev, id, &tmp, 1, &num);
+		if (num) {
+			QOS_LOG_ERR(
+					"Shared group %u has members can't remove\n",
+					id);
+			rc = -EBUSY;
+			goto out;
+		}
+		qdev->groups[id].used = 0;
+		create_remove_shared_group_cmd(qdev, id);
+		update_cmd_id(&qdev->drvcmds);
+		transmit_cmds(qdev);
+		rc = 0;
+	} else {
+		QOS_LOG_ERR("Shared group %u is not used\n", id);
+		rc = -EINVAL;
+	}
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+int pp_qos_shared_limit_group_modify(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		unsigned int limit)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (QOS_BW_GRP_VALID(id) && (qdev->groups[id].used)) {
+		if (qdev->groups[id].limit != limit) {
+			create_set_shared_group_cmd(qdev, id, limit);
+			update_cmd_id(&qdev->drvcmds);
+			transmit_cmds(qdev);
+		}
+		rc = 0;
+	} else {
+		QOS_LOG_ERR("Shared group %u is not used\n", id);
+		rc = -EINVAL;
+	}
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+static int _pp_qos_shared_limit_group_get_members(
+		struct pp_qos_dev *qdev, unsigned int id,
+		uint16_t *members,
+		unsigned int size,
+		unsigned int *members_num)
+{
+	unsigned int phy;
+	unsigned int total;
+	unsigned int tmp;
+	const struct qos_node *node;
+
+	total = 0;
+	for (phy = 0; (phy <= qdev->max_port) && (size > 0); ++phy) {
+		node = get_const_node_from_phy(qdev->nodes, phy);
+		if (node_used(node)) {
+			get_bw_grp_members_under_node(
+					qdev,
+					id,
+					phy,
+					members,
+					size,
+					&tmp);
+			total += tmp;
+			members += tmp;
+			if (tmp < size)
+				size -= tmp;
+			else
+				size = 0;
+		}
+	}
+
+	*members_num = total;
+	return 0;
+}
+
+int pp_qos_shared_limit_group_get_members(
+		struct pp_qos_dev *qdev,
+		unsigned int id,
+		uint16_t *members,
+		unsigned int size,
+		unsigned int *members_num)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (!qdev->initialized) {
+		QOS_LOG_ERR("Device was not initialized\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = _pp_qos_shared_limit_group_get_members(
+			qdev, id, members, size, members_num);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+out:
+	QOS_UNLOCK(qdev);
+	return rc;
+}
+
+struct pp_qos_dev *pp_qos_dev_open(unsigned int id)
+{
+	if (id < MAX_QOS_INSTANCES)
+		return qos_devs[id];
+
+	QOS_LOG_ERR("Illegal qos instance %u\n", id);
+	return NULL;
+}
+
+int pp_qos_dev_init(struct pp_qos_dev *qdev, struct pp_qos_init_param *conf)
+{
+	int rc;
+
+	QOS_LOCK(qdev);
+	PP_QOS_ENTER_FUNC();
+	if (qdev->initialized) {
+		QOS_LOG_ERR(
+				"Device already initialized, can't initialize again\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	if ((qdev->max_port + 1) & 7) {
+		QOS_LOG_ERR("Given max port %u is not last node of an octet\n",
+				qdev->max_port);
+		rc = -EINVAL;
+		goto out;
+	}
+	qdev->portsphys = free_ports_phys_init(
+			qdev->reserved_ports,
+			qdev->max_port,
+			conf->reserved_ports,
+			MAX_PORTS);
+
+	qdev->hwconf.wred_total_avail_resources =
+		conf->wred_total_avail_resources;
+	if (conf->wred_p_const > 1024) {
+		QOS_LOG_ERR("wred_p_const should be not greater than 1024\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	qdev->hwconf.wred_const_p = conf->wred_p_const;
+	qdev->hwconf.wred_max_q_size = conf->wred_max_q_size;
+
+	rc = load_firmware(qdev, FIRMWARE_FILE);
+	if (rc)
+		goto out;
+
+	create_init_logger_cmd(qdev);
+	create_init_qos_cmd(qdev);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+
+	qdev->initialized = 1;
+	rc = 0;
+out:
+	QOS_UNLOCK(qdev);
+	QOS_LOG_DEBUG("pp_qos_dev_init completed with %d\n", rc);
+	return rc;
+}
+
+
+struct pp_qos_dev *create_qos_dev_desc(struct qos_dev_init_info *initinfo)
+{
+	struct pp_qos_dev *qdev;
+	int rc;
+	unsigned int id;
+
+	id = initinfo->pl_data.id;
+	if (id >= MAX_QOS_INSTANCES) {
+		QOS_LOG_ERR("Illegal qos instance %u\n", id);
+		return NULL;
+	}
+
+	if (qos_devs[id]) {
+		QOS_LOG_ERR("qos instance %u already exists\n", id);
+		return NULL;
+	}
+
+	qdev = _qos_init(initinfo->pl_data.max_port);
+	if (qdev) {
+		qdev->hwconf.wred_prioritize_pop =
+			initinfo->pl_data.wred_prioritize_pop;
+		qdev->hwconf.qm_ddr_start = initinfo->pl_data.qm_ddr_start;
+		qdev->hwconf.qm_num_pages = initinfo->pl_data.qm_num_pages;
+		qdev->hwconf.fw_logger_start =
+			initinfo->pl_data.fw_logger_start;
+		qdev->hwconf.fw_stat = initinfo->pl_data.fw_stat;
+		memcpy(&qdev->fwcom, &initinfo->fwcom, sizeof(struct fw_com));
+		rc = init_fwdata_internals(qdev);
+		if (rc)
+			goto err;
+		qos_devs[id] = qdev;
+		QOS_LOG_INFO("Initialized qos instance\nmax_port:\t\t%u\n",
+				qdev->max_port);
+		QOS_LOG_INFO("qm_ddr_start:\t\t0x%08X\n",
+				qdev->hwconf.qm_ddr_start);
+		QOS_LOG_INFO("qm_num_of_pages\t\t%u\n",
+				qdev->hwconf.qm_num_pages);
+		QOS_LOG_INFO("fw_logger_start:\t0x%08X\n",
+				qdev->hwconf.fw_logger_start);
+		QOS_LOG_INFO("fw_stat:\t\t0x%08X\n",
+				qdev->hwconf.fw_stat);
+		QOS_LOG_INFO("cmdbuf:\t\t0x%08X\ncmdbuf size:\t\t%zu\n",
+				(unsigned int)(uintptr_t)qdev->fwcom.cmdbuf,
+				qdev->fwcom.cmdbuf_sz);
+	} else {
+		QOS_LOG_CRIT("Failed creating qos instance %u\n", id);
+	}
+
+	return qdev;
+err:
+	_qos_clean(qdev);
+	QOS_LOG_CRIT("Failed creating qos instance %u\n", id);
+	return NULL;
+}
+
+void remove_qos_instance(unsigned int id)
+{
+	if (id >= MAX_QOS_INSTANCES) {
+		QOS_LOG_ERR("Illegal qos instance %u\n", id);
+		return;
+	}
+
+	if (qos_devs[id] == NULL) {
+		QOS_LOG_ERR("qos instance %u not exists\n", id);
+		return;
+	}
+
+	_qos_clean(qos_devs[id]);
+	qos_devs[id] = NULL;
+	QOS_LOG_INFO("removed qos instance %u\n", id);
+}
+
+void qos_module_init(void)
+{
+	unsigned int i;
+
+	for (i = 0 ; i < MAX_QOS_INSTANCES; ++i)
+		qos_devs[i] = NULL;
+
+	QOS_LOG_INFO("qos_module_init completed\n");
+}
diff --git a/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_tests.c b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_tests.c
new file mode 100644
index 0000000000000000000000000000000000000000..d4fe2a64380501f4fdc83bafeb53b6bf60bdbf09
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_tests.c
@@ -0,0 +1,2574 @@
+#ifdef PP_QOS_TEST
+#include "pp_qos_fw.h"
+#include "pp_qos_utils.h" 
+
+#define QOS_INVALID_PRIORITY   0xF
+
+/*
+ * Check following for each octet:
+ * Number of nodes marked as used on each octet matches octet usage
+ * Ports' octets are not enqueued
+ * Non ports' octets are enqueued on a list which match their usage count
+ * No unused node interleaves sequence of used nodes
+ *
+ */
+static void check_octets(struct pp_qos_dev *qdev)
+{
+	int i;
+	int j;
+	int unused_seen;
+	uint8_t usage;
+	int last;
+	struct qos_node *node;
+
+	last = octet_of_phy(qdev->max_port);
+
+	for (i = 0; i < NUM_OF_OCTETS; ++i) {
+		node = get_node_from_phy(qdev->nodes, 8 * i);
+		usage = 0;
+		unused_seen = 0;
+		for (j = 0; j < 8; ++j) { 
+			if (node_used(node)) {
+				if (i > last)
+					QOS_ASSERT(!unused_seen, "Node %u is used after previous node in same octet was unused\n", i * 8 + j);
+				usage++;
+			} else {
+				unused_seen = 1;
+			}
+			node++;
+		}
+		debug_verify_octet_usage(qdev->octets, i, usage);
+	}
+}
+
+/*
+ * Check the following for each id:
+ *   If id is mapped to a valid phy
+ *	- Node designated by this phy is marked as used
+ *	- The inverse mapping from phy maps to the same id
+ *
+ * Check the following for each phy:
+ *   If phy designates a used node
+ *     - It is mapped to valid id
+ *     - The inverse mapping from id maps to the same phy
+ *
+ */
+static void check_mapping(struct pp_qos_dev *qdev)
+{
+	uint16_t phy;
+	uint16_t id;
+	struct qos_node *node;
+	unsigned i;
+
+	for (i = 0; i < NUM_OF_NODES; ++i) {
+		phy = get_phy_from_id(qdev->mapping, i);
+		if (QOS_PHY_VALID(phy)) {
+			node = get_node_from_phy(qdev->nodes, phy);
+			QOS_ASSERT(
+				   node_used(node),
+				   "Id %u is mapped to unused node %u\n", i, phy);
+			id = get_id_from_phy(qdev->mapping, phy);
+			QOS_ASSERT(
+				   id == i,
+				   "Id %u is mapped to phy %u, but the latter is mapped to %u\n", i, phy, id);
+		}
+
+		node = get_node_from_phy(qdev->nodes, i);
+		id = get_id_from_phy(qdev->mapping, i);
+		QOS_ASSERT(!node_used(node) || QOS_ID_VALID(id), "Node %u is used but has invalid id\n", i);
+		if (QOS_ID_VALID(id)) {
+			phy = get_phy_from_id(qdev->mapping, id);
+			QOS_ASSERT(
+				   phy == i,
+				   "Phy %u is mapped to id %u, but the latter is mapped to %u\n", i, id, phy);
+		}
+	}
+}
+
+struct pp_pool {
+	int capacity;
+	int top;
+	uint16_t invalid;
+	uint16_t data[1];
+};
+static uint8_t ids[NUM_OF_NODES];
+static uint8_t rlms[NUM_OF_QUEUES];
+static void check_resources_usage(struct pp_qos_dev *qdev)
+{
+	int i;
+	int id;
+	int rlm;
+	struct qos_node *node;
+	memset(ids, 0, NUM_OF_NODES);
+	memset(rlms, 0, NUM_OF_QUEUES);
+
+	node = get_node_from_phy(qdev->nodes, 0);
+	for (i = 0; i < NUM_OF_NODES; ++i) {
+		if (node_used(node)) {
+			id = get_id_from_phy(qdev->mapping, i);
+			QOS_ASSERT(ids[id] == 0, "Id %d of phy %d already found\n", id ,i);
+			ids[id] = 1;
+			if (node->type == TYPE_QUEUE) {
+				rlm = node->data.queue.rlm;
+				QOS_ASSERT(rlms[rlm] == 0, "Rlm %d of phy %d already found\n", rlm ,i);
+				rlms[rlm] = 1;
+			}
+		}
+		
+		if (qdev->ids->top > i) {
+			id = qdev->ids->data[i];
+			QOS_ASSERT(ids[id] == 0, "Id %d on free ids pool already found\n", id);
+			ids[id] = 1;
+		}
+
+		if (qdev->rlms->top > i) {
+			rlm = qdev->rlms->data[i];
+			QOS_ASSERT(rlms[rlm] == 0, "Rlm %d on free rlms pool already found\n", rlm);
+			rlms[rlm] = 1;
+		}
+
+		++node;
+	}
+
+	for (i = 0; i < NUM_OF_NODES; ++i) {
+		QOS_ASSERT(ids[i], "Id %d was not found\n", i);
+		QOS_ASSERT(i >= NUM_OF_QUEUES || rlms[i], "Rlm %d was not found\n", i);
+	}
+}
+
+
+ /* 
+  * Check following tests for each node:
+  * If node is a parent
+  *	- All the nodes it claims are its children, are indeed children and have it as their
+  *	  parent
+  *	- If its a WSP parent then its children are ordered correctly
+  *	- The sum of share of its children does not exceed 100
+  *
+  * If node is a child
+  *     - It is indeed recognized by its claimed parent as a child
+  *
+  */
+static void check_parent_children(struct pp_qos_dev *qdev)
+{
+	int phy;
+	int i;
+	int check_priorities;
+	int priority;
+	struct qos_node *node;
+	struct qos_node *cur;
+	int first_child_phy;
+	int last_child_phy;
+	int share;
+
+	for (phy = 0; phy < NUM_OF_NODES; ++phy) {
+		node = get_node_from_phy(qdev->nodes, phy);
+		if (node_parent(node)) {
+			i = node->parent_prop.num_of_children;
+			QOS_ASSERT(i >= 0, "Illegal number of children %d for node %d\n", i, phy);
+			check_priorities = (node->parent_prop.arbitration == PP_QOS_ARBITRATION_WSP);
+			priority = -1;
+			if (i)
+				cur = get_node_from_phy(qdev->nodes, node->parent_prop.first_child_phy);
+			for (; i > 0; --i) {
+				QOS_ASSERT(node_child(cur), 
+					   "Node %u claims that %u is its child but the latter is not a child (or marked unused)\n", phy, get_phy_from_node(qdev->nodes, cur));
+				QOS_ASSERT(cur->child_prop.parent_phy == phy, 
+					   "Node %d has node %u as a child, but the latter has node %u as its parent\n", 
+					   phy, get_phy_from_node(qdev->nodes, cur), cur->child_prop.parent_phy) ;
+				QOS_ASSERT(
+					   !check_priorities || (cur->child_prop.priority > priority),
+					   "Child %u of wsp parent %u has priority %u while previous child priority is %u\n", 
+					   get_phy_from_node(qdev->nodes, cur), phy, cur->child_prop.priority, priority);
+
+				if (check_priorities)
+					priority = cur->child_prop.priority;
+
+				++cur;
+			}
+
+			//share = get_virt_children_bandwidth_share(qdev, node);
+			share = get_children_bandwidth_share(qdev, node);
+			QOS_ASSERT(share <= 100, "Bandwidth share of %d children is %d\n", phy, share);
+			if (node_internal(node)) {
+				share = get_children_bandwidth_share(qdev, node);
+				QOS_ASSERT(share == node->child_prop.virt_bw_share, "iInternal scheduler: sum bandwidth children is %d while parent is %d\n", share, node->child_prop.virt_bw_share);
+			}
+		} 
+
+		if (node_child(node)) {
+			cur = get_node_from_phy(qdev->nodes, node->child_prop.parent_phy);
+			QOS_ASSERT(node_parent(cur), "Node %u claims that %u is its parent, but the latter is not a parent (or marked unused)\n", phy, get_phy_from_node(qdev->nodes, cur));
+			first_child_phy = cur->parent_prop.first_child_phy;
+			last_child_phy = first_child_phy + cur->parent_prop.num_of_children - 1;
+			QOS_ASSERT((phy >= first_child_phy) && (phy <= last_child_phy),
+				   "Node %d has node %u as a parent, but the latter children are %u..%u\n", 
+				   phy, get_phy_from_node(qdev->nodes, cur), first_child_phy, last_child_phy);
+		}
+		++node;
+	}
+}
+
+static void check_consistency(struct pp_qos_dev *qdev)
+{
+	QOS_ASSERT(!QOS_SPIN_IS_LOCKED(qdev), "Lock is taken\n");
+	check_octets(qdev);
+	check_parent_children(qdev);
+	check_mapping(qdev);
+}
+
+static void check_consistency_with_resources(struct pp_qos_dev *qdev)
+{
+	check_consistency(qdev);
+	check_resources_usage(qdev);
+}
+
+static void create_nodes(struct pp_qos_dev *qdev, uint16_t start_phy, int count)
+{
+	int i;
+	uint16_t id;
+	struct qos_node *node;
+
+	nodes_modify_used_status(qdev, start_phy, count, 1);
+	node = get_node_from_phy(qdev->nodes, start_phy);
+	for (i = start_phy; i < start_phy + count; ++i) {
+		id = pp_pool_get(qdev->ids);
+		map_id_phy(qdev->mapping, id, i);	
+		node->type = TYPE_UNKNOWN;
+		++node;
+	}
+}
+
+static void destroy_nodes(struct pp_qos_dev *qdev, uint16_t start_phy, int count)
+{
+	int i;
+	uint16_t id;
+
+	nodes_modify_used_status(qdev, start_phy, count, 0);
+
+	for (i = start_phy; i < start_phy + count; ++i) {
+		id = get_id_from_phy(qdev->mapping, i);
+		map_invalidate_id(qdev->mapping, id);
+		pp_pool_put(qdev->ids, id);
+	}
+}
+
+static void config_parent_node(struct pp_qos_dev *qdev, uint16_t phy, enum node_type type, enum pp_qos_arbitration arb, uint16_t first_child, int num)
+{
+	struct qos_node *node;
+
+	node = get_node_from_phy(qdev->nodes, phy);
+	node->type = type;
+	node->parent_prop.arbitration = arb;
+	node->parent_prop.first_child_phy = first_child;
+	node->parent_prop.num_of_children = num;
+}
+
+static void config_child_node(struct pp_qos_dev *qdev, uint16_t phy, enum node_type type, uint16_t parent_phy, int priority)
+{
+	struct qos_node *node;
+
+	node = get_node_from_phy(qdev->nodes, phy);
+	node->type = type;
+
+	if (QOS_PHY_VALID(parent_phy))
+		node->child_prop.parent_phy =parent_phy;
+
+	if (priority != QOS_INVALID_PRIORITY)
+		node->child_prop.priority = priority;
+}
+
+/*
+ */
+static void test_modify_used_status(struct pp_qos_dev *qdev)
+{
+	debug_verify_octet_usage(qdev->octets, 2, 0);
+	debug_verify_octet_usage(qdev->octets, 3, 0);
+	debug_verify_octet_usage(qdev->octets, 4, 0);
+
+	create_nodes(qdev, 18, 15);
+	debug_verify_octet_usage(qdev->octets, 2, 6);
+	debug_verify_octet_usage(qdev->octets, 3, 8);
+	debug_verify_octet_usage(qdev->octets, 4, 1);
+
+	destroy_nodes(qdev, 25, 2);
+	debug_verify_octet_usage(qdev->octets, 2, 6);
+	debug_verify_octet_usage(qdev->octets, 3, 6);
+	debug_verify_octet_usage(qdev->octets, 4, 1);
+
+	destroy_nodes(qdev, 18, 7);
+	debug_verify_octet_usage(qdev->octets, 2, 0);
+	debug_verify_octet_usage(qdev->octets, 3, 5);
+	debug_verify_octet_usage(qdev->octets, 4, 1);
+
+	destroy_nodes(qdev, 27, 6);
+	debug_verify_octet_usage(qdev->octets, 2, 0);
+	debug_verify_octet_usage(qdev->octets, 3, 0);
+	debug_verify_octet_usage(qdev->octets, 4, 0);
+	check_consistency(qdev);
+}
+
+static void test_move_nodes(struct pp_qos_dev *qdev)
+{
+	debug_verify_octet_usage(qdev->octets, 2, 0);
+
+	create_nodes(qdev, 18, 3);
+	debug_verify_octet_usage(qdev->octets, 2, 3);
+
+	octet_nodes_shift(qdev, 18, 2, -2); 
+	debug_verify_octet_usage(qdev->octets, 2, 3);
+
+	octet_nodes_shift(qdev, 16, 2, 2); 
+	debug_verify_octet_usage(qdev->octets, 2, 3);
+
+	octet_nodes_shift(qdev, 19, 2, 3); 
+	debug_verify_octet_usage(qdev->octets, 2, 3);
+
+	create_nodes(qdev, 26, 4);
+	debug_verify_octet_usage(qdev->octets, 2, 3);
+	debug_verify_octet_usage(qdev->octets, 3, 4);
+
+	nodes_move(qdev, 30, 22, 2);
+	debug_verify_octet_usage(qdev->octets, 2, 1);
+	debug_verify_octet_usage(qdev->octets, 3, 6);
+
+	destroy_nodes(qdev, 18, 1);
+	destroy_nodes(qdev, 26, 6);
+	debug_verify_octet_usage(qdev->octets, 2, 0);
+	debug_verify_octet_usage(qdev->octets, 3, 0);
+
+	check_consistency(qdev);
+}
+
+static void test_phy_allocation_not_full_octet(struct pp_qos_dev *qdev)
+{
+	struct qos_node *base;
+	uint16_t phy;
+	uint16_t expected_phy;
+	uint16_t id;
+
+	create_nodes(qdev, 0, 2);
+	create_nodes(qdev, 16, 6);
+
+	base = get_node_from_phy(qdev->nodes, 0);
+
+	// Port (Node 1)
+	config_parent_node(qdev, 1, TYPE_PORT, PP_QOS_ARBITRATION_WRR, 16, 2);
+
+	config_parent_node(qdev, 16, TYPE_SCHED, PP_QOS_ARBITRATION_WSP, 18, 2);
+	config_child_node(qdev, 16, TYPE_SCHED, 1, 0);
+	config_parent_node(qdev, 17, TYPE_SCHED, PP_QOS_ARBITRATION_WRR, 20, 2);
+	config_child_node(qdev, 17, TYPE_SCHED, 1, 0);
+
+	// 2 Queues of first sched (Nodes, 18, 19)
+	//
+	config_child_node(qdev, 18, TYPE_QUEUE, 16, 3);
+	config_child_node(qdev, 19, TYPE_QUEUE, 16, 5);
+
+	// 2 Queues of second sched (Nodes, 20, 21)
+	config_child_node(qdev, 20, TYPE_QUEUE, 17, 3);
+	config_child_node(qdev, 21, TYPE_QUEUE, 17, 5);
+	check_consistency(qdev);
+
+	expected_phy = 18;
+	phy = phy_alloc_by_parent(qdev, base + 16, 1);
+	QOS_ASSERT(phy == expected_phy, "Expected phy for new node %d but got %d\n", expected_phy, phy);
+	config_child_node(qdev, phy, TYPE_QUEUE, QOS_INVALID_PHY, 1);
+	id = pp_pool_get(qdev->ids);
+	map_id_phy(qdev->mapping, id, phy);
+	check_consistency(qdev);
+	destroy_nodes(qdev, phy, 1);
+	octet_nodes_shift(qdev, expected_phy + 1, 4, -1);
+	check_consistency(qdev);
+
+	expected_phy = 19;
+	phy = phy_alloc_by_parent(qdev, base + 16, 4);
+	QOS_ASSERT(phy == expected_phy, "Expected phy for new node %d but got %d\n", expected_phy, phy);
+	config_child_node(qdev, phy, TYPE_QUEUE, QOS_INVALID_PHY, 4);
+	id = pp_pool_get(qdev->ids);
+	map_id_phy(qdev->mapping, id, phy);
+	check_consistency(qdev);
+	destroy_nodes(qdev, phy, 1);
+	octet_nodes_shift(qdev, expected_phy + 1, 3, -1);
+	check_consistency(qdev);
+	
+	expected_phy = 20;
+	phy = phy_alloc_by_parent(qdev, base + 16, 6);
+	QOS_ASSERT(phy == expected_phy, "Expected phy for new node %d but got %d\n", expected_phy, phy);
+	config_child_node(qdev, phy, TYPE_QUEUE, QOS_INVALID_PHY, 6);
+	id = pp_pool_get(qdev->ids);
+	map_id_phy(qdev->mapping, id, phy);
+	check_consistency(qdev);
+	destroy_nodes(qdev, phy, 1);
+	config_parent_node(qdev, 16, TYPE_SCHED, PP_QOS_ARBITRATION_WSP, 18, 2);
+	octet_nodes_shift(qdev, expected_phy + 1, 2, -1);
+	check_consistency(qdev);
+
+	expected_phy = 22;
+	phy = phy_alloc_by_parent(qdev, base + 17, 1);
+	QOS_ASSERT(phy == expected_phy, "Expected phy for new node %d but got %d\n", expected_phy, phy);
+	id = pp_pool_get(qdev->ids);
+	map_id_phy(qdev->mapping, id, phy);
+	check_consistency(qdev);
+
+	destroy_nodes(qdev, 0, 2);
+	destroy_nodes(qdev, 16, 7);
+	check_consistency(qdev);
+}
+
+static void test_phy_allocation_full_octet(struct pp_qos_dev *qdev)
+{
+	struct qos_node *base;
+	uint16_t phy;
+	uint16_t sched;
+	uint16_t sched2;
+	uint16_t expected_phy;
+	uint16_t id;
+	struct qos_node *node;
+
+	create_nodes(qdev, 0, 2);
+	create_nodes(qdev, 16, 8);
+	base = get_node_from_phy(qdev->nodes, 0);
+
+	// Port (Node 1) and 2 scheds - 16(WSP), 17(WRR)
+	config_parent_node(qdev, 1, TYPE_PORT, PP_QOS_ARBITRATION_WRR, 16, 2);
+	config_parent_node(qdev, 16, TYPE_SCHED, PP_QOS_ARBITRATION_WSP, 18, 3);
+	config_child_node(qdev, 16, TYPE_SCHED, 1, 0);
+	config_parent_node(qdev, 17, TYPE_SCHED, PP_QOS_ARBITRATION_WRR, 21, 3);
+	config_child_node(qdev, 17, TYPE_SCHED, 1, 0);
+
+	// 3 Queues of first sched (Nodes, 18, 19, 20)
+	config_child_node(qdev, 18, TYPE_QUEUE, 16, 1);
+	config_child_node(qdev, 19, TYPE_QUEUE, 16, 3);
+	config_child_node(qdev, 20, TYPE_QUEUE, 16, 5);
+
+	// 3 Queues of second sched (Nodes, 21, 22, 23)
+	config_child_node(qdev, 23, TYPE_QUEUE, 17, 0);
+	config_child_node(qdev, 21, TYPE_QUEUE, 17, 0);
+	config_child_node(qdev, 22, TYPE_QUEUE, 17, 0);
+	check_consistency(qdev);
+
+	sched = get_id_from_phy(qdev->mapping, 16);
+	sched2 = get_id_from_phy(qdev->mapping, 17);
+
+	expected_phy = 17;
+	phy = phy_alloc_by_parent(qdev, base + 16, 2);
+	QOS_ASSERT(phy == expected_phy, "Expected phy for new node %d but got %d\n", expected_phy, phy);
+	config_child_node(qdev, phy, TYPE_QUEUE, QOS_INVALID_PHY, 2);
+	id = pp_pool_get(qdev->ids);
+	map_id_phy(qdev->mapping, id, phy);
+	check_consistency(qdev);
+	destroy_nodes(qdev, phy, 1);
+	octet_nodes_shift(qdev, expected_phy + 1, 5, -1);
+	check_consistency(qdev);
+	octet_nodes_shift(qdev, 16, 6, 2);
+	phy = get_phy_from_id(qdev->mapping, sched); 
+	nodes_move(qdev, 16, phy, 2);
+	check_consistency(qdev);
+
+	expected_phy = 18;
+	phy = phy_alloc_by_parent(qdev, base + 16, 4);
+	QOS_ASSERT(phy == expected_phy, "Expected phy for new node %d but got %d\n", expected_phy, phy);
+	config_child_node(qdev, phy, TYPE_QUEUE, QOS_INVALID_PHY, 4);
+	id = pp_pool_get(qdev->ids);
+	map_id_phy(qdev->mapping, id, phy);
+	check_consistency(qdev);
+	destroy_nodes(qdev, phy, 1);
+	octet_nodes_shift(qdev, expected_phy + 1, 4, -1);
+	check_consistency(qdev);
+	octet_nodes_shift(qdev, 16, 6, 2);
+	phy = get_phy_from_id(qdev->mapping, sched); 
+	nodes_move(qdev, 16, phy, 2);
+	check_consistency(qdev);
+	
+	expected_phy = 16;
+	phy = phy_alloc_by_parent(qdev, base + 16, 0);
+	QOS_ASSERT(phy == expected_phy, "Expected phy for new node %d but got %d\n", expected_phy, phy);
+	config_child_node(qdev, phy, TYPE_QUEUE, QOS_INVALID_PHY, 0);
+	id = pp_pool_get(qdev->ids);
+	map_id_phy(qdev->mapping, id, phy);
+	check_consistency(qdev);
+	destroy_nodes(qdev, phy, 1);
+	octet_nodes_shift(qdev, expected_phy + 1, 6, -1);
+	check_consistency(qdev);
+	octet_nodes_shift(qdev, 16, 6, 2);
+	phy = get_phy_from_id(qdev->mapping, sched); 
+	nodes_move(qdev, 16, phy, 2);
+	check_consistency(qdev);
+
+
+	expected_phy = 19;
+	phy = phy_alloc_by_parent(qdev, base + 16, 6);
+	QOS_ASSERT(phy == expected_phy, "Expected phy for new node %d but got %d\n", expected_phy, phy);
+	config_child_node(qdev, phy, TYPE_QUEUE, QOS_INVALID_PHY, 6);
+	id = pp_pool_get(qdev->ids);
+	map_id_phy(qdev->mapping, id, phy);
+	check_consistency(qdev);
+	node = get_node_from_phy(qdev->nodes, get_phy_from_id(qdev->mapping, sched));
+	node->parent_prop.num_of_children--;
+	destroy_nodes(qdev, phy, 1);
+	octet_nodes_shift(qdev, expected_phy + 1, 3, -1);
+	check_consistency(qdev);
+
+	octet_nodes_shift(qdev, 16, 6, 2);
+	phy = get_phy_from_id(qdev->mapping, sched); 
+	nodes_move(qdev, 16, phy, 2);
+	check_consistency(qdev);
+
+	expected_phy = 22;
+	phy = phy_alloc_by_parent(qdev, base + 17, 0);
+	QOS_ASSERT(phy == expected_phy, "Expected phy for new node %d but got %d\n", expected_phy, phy);
+	id = pp_pool_get(qdev->ids);
+	map_id_phy(qdev->mapping, id, phy);
+	check_consistency(qdev);
+	node = get_node_from_phy(qdev->nodes, get_phy_from_id(qdev->mapping, sched2));
+	node->parent_prop.num_of_children--;
+	destroy_nodes(qdev, phy, 1);
+	octet_nodes_shift(qdev, 16, 6, 2);
+	phy = get_phy_from_id(qdev->mapping, sched); 
+	nodes_move(qdev, 16, phy, 2);
+	check_consistency(qdev);
+
+	destroy_nodes(qdev, 16, 8);
+	destroy_nodes(qdev, 0, 2);
+	check_consistency(qdev);
+}
+
+static void test_phy_allocation_full_octet_2(struct pp_qos_dev *qdev)
+{
+	struct qos_node *base;
+	uint16_t phy;
+	uint16_t queue;
+	uint16_t expected_phy;
+	uint16_t id;
+
+	create_nodes(qdev, 0, 2);
+	create_nodes(qdev, 16, 8);
+	base = get_node_from_phy(qdev->nodes, 0);
+
+	// Port (Node 1) and 2 scheds - 16(WSP), 17(WRR)
+	config_parent_node(qdev, 1, TYPE_PORT, PP_QOS_ARBITRATION_WRR, 16, 2);
+	config_parent_node(qdev, 16, TYPE_SCHED, PP_QOS_ARBITRATION_WSP, 18, 5);
+	config_child_node(qdev, 16, TYPE_SCHED, 1, 0);
+	config_parent_node(qdev, 17, TYPE_SCHED, PP_QOS_ARBITRATION_WRR, 23, 1);
+	config_child_node(qdev, 17, TYPE_SCHED, 1, 0);
+
+	// 4 Queues of first sched (Nodes, 18, 19, 20, 21, 22)
+	config_child_node(qdev, 18, TYPE_QUEUE, 16, 1);
+	config_child_node(qdev, 19, TYPE_QUEUE, 16, 3);
+	config_child_node(qdev, 20, TYPE_QUEUE, 16, 5);
+	config_child_node(qdev, 21, TYPE_QUEUE, 16, 6);
+	config_child_node(qdev, 22, TYPE_QUEUE, 16, 7);
+
+	// 1 Queues of second sched (Node 23)
+	config_child_node(qdev, 23, TYPE_QUEUE, 17, 0);
+	queue = get_id_from_phy(qdev->mapping, 23);
+	check_consistency(qdev);
+
+	expected_phy = 18;
+	phy = phy_alloc_by_parent(qdev, base + 16, 0);
+	QOS_ASSERT(phy == expected_phy, "Expected phy for new node %d but got %d\n", expected_phy, phy);
+	config_child_node(qdev, phy, TYPE_QUEUE, QOS_INVALID_PHY, 0);
+	id = pp_pool_get(qdev->ids);
+	map_id_phy(qdev->mapping, id, phy);
+	destroy_nodes(qdev, phy, 1);
+	octet_nodes_shift(qdev, expected_phy + 1, 5, -1);
+	check_consistency(qdev);
+	phy = get_phy_from_id(qdev->mapping, queue); 
+	nodes_move(qdev, 23, phy, 1);
+	check_consistency(qdev);
+
+	//
+	// change config to 3 schedulers, first has 1 child, second 4 and third
+	// none
+	//
+	config_parent_node(qdev, 1, TYPE_PORT, PP_QOS_ARBITRATION_WRR, 16, 3);
+	config_parent_node(qdev, 16, TYPE_SCHED, PP_QOS_ARBITRATION_WSP, 19, 1);
+	config_parent_node(qdev, 17, TYPE_SCHED, PP_QOS_ARBITRATION_WRR, 20, 4);
+	config_child_node(qdev, 18, TYPE_SCHED, 1, 0);
+	config_child_node(qdev, 19, TYPE_QUEUE, 16, 3);
+	config_child_node(qdev, 23, TYPE_QUEUE, 17, 0);
+	config_child_node(qdev, 20, TYPE_QUEUE, 17, 0);
+	config_child_node(qdev, 21, TYPE_QUEUE, 17, 0);
+	config_child_node(qdev, 22, TYPE_QUEUE, 17, 0);
+	check_consistency(qdev);
+
+	queue = get_id_from_phy(qdev->mapping, 19);
+	phy = phy_alloc_by_parent(qdev, base + 16, 0);
+	expected_phy = get_phy_from_id(qdev->mapping, queue) - 1;
+	QOS_ASSERT(phy ==  expected_phy, "Expected phy for new node %d but got %d\n", expected_phy, phy);
+	config_child_node(qdev, phy, TYPE_QUEUE, QOS_INVALID_PHY, 0);
+	id = pp_pool_get(qdev->ids);
+	map_id_phy(qdev->mapping, id, phy);
+	destroy_nodes(qdev, phy, 1);
+	octet_nodes_shift(qdev, phy + 1, 1, -1);
+	check_consistency(qdev);
+
+	destroy_nodes(qdev, 16, 7);
+	destroy_nodes(qdev, 0, 2);
+	destroy_nodes(qdev, phy, 1);
+	check_consistency(qdev);
+}
+
+static void test_internal_scheduler(struct pp_qos_dev *qdev)
+{
+	uint16_t phy;
+	struct qos_node *base;
+	int i;
+	uint16_t id;
+
+	base = get_node_from_phy(qdev->nodes, 0);
+	create_nodes(qdev, 0, 2);
+	create_nodes(qdev, 16, 8);
+	config_parent_node(qdev, 1, TYPE_PORT, PP_QOS_ARBITRATION_WRR, 16, 8);
+	config_child_node(qdev, 16, TYPE_QUEUE, 1, 0);
+	config_child_node(qdev, 17, TYPE_QUEUE, 1, 0);
+	config_child_node(qdev, 18, TYPE_QUEUE, 1, 0);
+	config_child_node(qdev, 19, TYPE_QUEUE, 1, 0);
+	config_child_node(qdev, 20, TYPE_QUEUE, 1, 0);
+	config_child_node(qdev, 21, TYPE_QUEUE, 1, 0);
+	config_child_node(qdev, 22, TYPE_QUEUE, 1, 0);
+	config_child_node(qdev, 23, TYPE_QUEUE, 1, 0);
+	check_consistency(qdev);
+
+	for (i = 0 ; i < 200; ++i) {
+		phy = phy_alloc_by_parent(qdev, base + 1, 0);
+		id = pp_pool_get(qdev->ids);
+		map_id_phy(qdev->mapping, id, phy);
+		config_child_node(qdev, phy, TYPE_QUEUE, QOS_INVALID_PHY, QOS_INVALID_PRIORITY);
+		check_consistency(qdev);
+	}
+
+}
+
+static void expected_id_phy(const struct pp_qos_dev *qdev, int id, int eid, int ephy)
+{
+	int phy;
+
+	phy = get_phy_from_id(qdev->mapping, id);
+	QOS_ASSERT(id == eid, "Got id %d expected %d\n", id, eid);
+	QOS_ASSERT(phy == ephy, "Got phy %d expected %d\n", phy, ephy);
+}
+
+static void test_ports(struct pp_qos_dev *qdev)
+{
+	struct pp_qos_port_conf conf;
+	unsigned int id1;
+	unsigned int id2;
+	int tmp;
+	struct qos_node *node;
+	struct pp_qos_port_info info;
+	uint16_t ids[5];
+	unsigned tmp2;
+	unsigned firstnonport;
+
+	QOS_LOG_INFO("starting ports tests\n");	
+	firstnonport = qdev->max_port + 1;
+
+	/* Allocate port with arbitrary phy */
+	tmp = pp_qos_port_allocate(qdev, ALLOC_PORT_ID, &id1);
+	QOS_ASSERT(tmp == 0, "could not allocate qos port\n");
+	expected_id_phy(qdev, id1, 0, 0);
+
+	pp_qos_port_conf_set_default(&conf); 
+	conf.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	conf.ring_address = (void *)1;
+	conf.ring_size = 1;
+	QOS_ASSERT(pp_qos_port_set(qdev, id1, &conf) == 0, "Could not set port\n");
+
+	node = get_node_from_phy(qdev->nodes, get_phy_from_id(qdev->mapping, id1));
+	conf.ring_size = 3;
+	QOS_ASSERT(pp_qos_port_set(qdev, id1, &conf) == 0, "Could not set port\n");
+	QOS_ASSERT(port_cfg_valid(qdev, node, node), "Configuration not valid\n");
+
+	conf.ring_size = 0;
+	QOS_ASSERT(pp_qos_port_set(qdev, id1, &conf) == -EINVAL, "Port setting should have failed\n");
+	QOS_ASSERT(port_cfg_valid(qdev, node, node), "Configuration not valid\n");
+
+	/* Allocate port with certain phy */ 
+	tmp = pp_qos_port_allocate(qdev, 10, &id2);
+	QOS_ASSERT(tmp == -EINVAL, "Port allocation should have failed\n");
+	tmp = pp_qos_port_allocate(qdev, 12, &id2);
+	QOS_ASSERT(tmp == 0, "Port allocation failed\n");
+	expected_id_phy(qdev, id2, 1, 12);
+	tmp = pp_qos_port_allocate(qdev, 12, &id2);
+	QOS_ASSERT(tmp == -EBUSY, "Port allocation should have failed\n");
+	create_nodes(qdev, firstnonport, 3);
+	config_child_node(qdev, firstnonport, TYPE_QUEUE, 12, 0);
+	config_child_node(qdev, firstnonport + 1, TYPE_QUEUE, 12, 0);
+	config_child_node(qdev, firstnonport + 2, TYPE_QUEUE, 12, 0);
+	config_parent_node(qdev, 12, TYPE_PORT, PP_QOS_ARBITRATION_WRR, firstnonport, 3);
+	pp_qos_port_info_get(qdev, id2, &info);
+	QOS_ASSERT(info.num_of_queues == 3 && info.physical_id == 12, "Number of queues %d or phy %d is not what expected\n", info.num_of_queues, info.physical_id);
+
+	pp_qos_port_get_queues(qdev, id2, ids, 2, &tmp2);
+	QOS_ASSERT((tmp2 == 3) && (ids[0] == 2) && (ids[1] == 3), "Number of queues %d or ids %d %d are not expected\n", tmp2, ids[0], ids[1]);
+
+	pp_qos_port_remove(qdev, id1);
+	pp_qos_port_remove(qdev, id2);
+
+
+	check_consistency(qdev);
+	QOS_LOG_INFO("ports tests completed successfully :)\n");	
+}
+
+static void expected_queues(struct pp_qos_dev *qdev, int phy, unsigned exp)
+{
+	unsigned num;
+
+	get_node_queues(qdev, phy, NULL, 0, &num);
+	QOS_ASSERT(exp == num, "Expected %u queues on phy %d but got %u\n", exp, phy, num); 
+}
+
+static void test_queues1(struct pp_qos_dev *qdev)
+{
+	int tmp;
+	struct pp_qos_queue_conf confq;
+	struct pp_qos_port_conf confp;
+	struct qos_node node;
+	struct qos_node *nodep;
+	unsigned int p1;
+	unsigned int p7;
+	unsigned int q[100];
+	unsigned int j;
+	unsigned int i;
+	unsigned firstnonport;
+
+	QOS_LOG_INFO("starting queues1 tests\n");	
+	firstnonport = qdev->max_port + 1;
+
+	/* Allocate port 1  */ 
+	pp_qos_port_conf_set_default(&confp); 
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_address = (void *)1;
+	confp.ring_size = 1;
+	tmp = pp_qos_port_allocate(qdev, 1, &p1);
+	expected_id_phy(qdev, p1, 0, 1);
+	QOS_ASSERT(pp_qos_port_set(qdev, p1, &confp) == 0, "Could not set port\n");
+	check_consistency_with_resources(qdev);
+
+	/* Allocate first queue */
+	pp_qos_queue_conf_set_default(&confq); 
+	confq.queue_child_prop.parent = p1;
+	tmp = pp_qos_queue_allocate(qdev, &q[0]);
+	pp_qos_queue_set(qdev, q[0], &confq);
+	expected_id_phy(qdev, q[0], 1, firstnonport);
+	check_consistency_with_resources(qdev);
+
+
+	/* Allocate 7 more queues */
+	for (i = 1; i < 8; ++ i) {
+		tmp = pp_qos_queue_allocate(qdev, &q[i]);
+		confq.queue_wred_max_allowed = i;
+		pp_qos_queue_set(qdev, q[i], &confq);
+		expected_id_phy(qdev, q[i], i + 1, firstnonport + i);
+		check_consistency_with_resources(qdev);
+	}
+
+	/* Allocate 64 more queues */
+	for (i = 8; i < 72; ++i) {
+		tmp = pp_qos_queue_allocate(qdev, &q[i]);
+		confq.queue_wred_max_allowed = i;
+		pp_qos_queue_set(qdev, q[i], &confq);
+		check_consistency_with_resources(qdev);
+	}
+
+	/* change setting without parent */
+	tmp = get_phy_from_id(qdev->mapping, q[7]);
+	nodep = get_node_from_phy(qdev->nodes, tmp);
+	memcpy(&node, nodep, sizeof(struct qos_node)); 
+	QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[7], &confq) == 0, "pp_qos_queue_conf_get failed\n");
+	confq.queue_wred_max_allowed = 77; 
+	pp_qos_queue_set(qdev, q[7], &confq);
+	QOS_ASSERT(memcmp(&node, nodep, offsetof(struct qos_node, data.queue.max_allowed)) == 0, "Unexpected change\n");
+	QOS_ASSERT(nodep->data.queue.max_allowed == 77, "Set max allowed did not work\n");
+	QOS_ASSERT(memcmp(&(node.data.queue.min_guaranteed), &(nodep->data.queue.min_guaranteed), sizeof(struct qos_node) - offsetof(struct qos_node, data.queue.min_guaranteed)) == 0, "Unexpected change\n");
+	check_consistency_with_resources(qdev);
+
+	/* change setting with parent */
+	tmp = pp_qos_port_allocate(qdev, 7, &p7);
+	QOS_ASSERT(pp_qos_port_set(qdev, p7, &confp) == 0, "Could not set port\n");
+	
+	tmp = get_phy_from_id(qdev->mapping, q[14]);
+	nodep = get_node_from_phy(qdev->nodes, tmp);
+	memcpy(&node, nodep, sizeof(struct qos_node)); 
+
+	QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[14], &confq) == 0, "pp_qos_queue_conf_get failed\n");
+	confq.queue_child_prop.parent = p7;
+	confq.queue_wred_max_allowed = 777; 
+	pp_qos_queue_set(qdev, q[14], &confq);
+	tmp = get_phy_from_id(qdev->mapping, q[14]);
+	nodep = get_node_from_phy(qdev->nodes, tmp);
+	QOS_ASSERT(nodep->data.queue.max_allowed == 777, "Set max allowed not work\n");
+	QOS_ASSERT(nodep->child_prop.parent_phy == get_phy_from_id(qdev->mapping, p7), "Set of parent did not work has %d instead of %d\n",
+		   nodep->child_prop.parent_phy,  get_phy_from_id(qdev->mapping, p7));
+	QOS_ASSERT(memcmp(&node, nodep, offsetof(struct qos_node, child_prop.parent_phy)) == 0, "Unexpected change\n");
+	QOS_ASSERT(memcmp(&node, nodep, offsetof(struct qos_node, child_prop.parent_phy)) == 0, "Unexpected change\n");
+	QOS_ASSERT(memcmp(&(node.child_prop.priority), &(nodep->child_prop.priority), offsetof(struct qos_node, data.queue.max_allowed) - offsetof(struct qos_node, child_prop.priority)) == 0, "Unexpected change\n");
+	QOS_ASSERT(memcmp(&(node.data.queue.min_guaranteed), &(nodep->data.queue.min_guaranteed), sizeof(struct qos_node) - offsetof(struct qos_node, data.queue.min_guaranteed)) == 0, "Unexpected change\n");
+
+	check_consistency_with_resources(qdev);
+
+	for (j = 0 ; j < 100; ++j) {
+		for (i = 20; i < 50; ++i) {
+			QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[i], &confq) == 0, "pp_qos_queue_conf_get failed on %d iteration\n", i);
+			confq.queue_wred_max_allowed = 300 + i;
+			confq.queue_child_prop.parent = p7;
+			QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+			check_consistency_with_resources(qdev);
+		}
+
+		for (i = 20; i < 50; ++i) {
+			QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[i], &confq) == 0, "pp_qos_queue_conf_get failed on %d iteration\n", i);
+			confq.queue_wred_max_allowed = 400 + i;
+			confq.queue_child_prop.parent = p1;
+			QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+			check_consistency_with_resources(qdev);
+		}
+	}
+	QOS_LOG_INFO("queue1 tests completed successfully :)\n");	
+}
+static void test_queues2(struct pp_qos_dev *qdev)
+{
+	int tmp;
+	struct pp_qos_queue_conf confq;
+	struct pp_qos_port_conf confp;
+	struct qos_node node;
+	struct qos_node *nodep;
+	unsigned int p1;
+	unsigned int p7;
+	unsigned int p12;
+	unsigned int q[100];
+	unsigned int j;
+	unsigned int i;
+	unsigned tmp1;
+	unsigned tmp2;
+	unsigned tmp3;
+	unsigned tmp4;
+	unsigned firstnonport;
+
+	QOS_LOG_INFO("starting queues2 tests\n");	
+	firstnonport = qdev->max_port + 1;
+		
+
+	/* Allocate port 1  */ 
+	pp_qos_port_conf_set_default(&confp); 
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_address = (void *)1;
+	confp.ring_size = 1;
+	tmp = pp_qos_port_allocate(qdev, 1, &p1);
+	expected_id_phy(qdev, p1, 0, 1);
+	QOS_ASSERT(pp_qos_port_set(qdev, p1, &confp) == 0, "Could not set port\n");
+	check_consistency_with_resources(qdev);
+
+	/* Allocate first queue */
+	pp_qos_queue_conf_set_default(&confq); 
+	confq.queue_child_prop.parent = p1;
+	tmp = pp_qos_queue_allocate(qdev, &q[0]);
+	pp_qos_queue_set(qdev, q[0], &confq);
+	expected_id_phy(qdev, q[0], 1, firstnonport);
+	check_consistency_with_resources(qdev);
+
+
+	/* Allocate 7 more queues */
+	for (i = 1; i < 8; ++ i) {
+		tmp = pp_qos_queue_allocate(qdev, &q[i]);
+		confq.queue_wred_max_allowed = i;
+		pp_qos_queue_set(qdev, q[i], &confq);
+		expected_id_phy(qdev, q[i], i + 1, firstnonport + i);
+		check_consistency_with_resources(qdev);
+	}
+
+	/* Allocate 64 more queues */
+	for (i = 8; i < 100; ++i) {
+		tmp = pp_qos_queue_allocate(qdev, &q[i]);
+		confq.queue_wred_max_allowed = i;
+		confq.queue_child_prop.bandwidth_share = 1;
+		pp_qos_queue_set(qdev, q[i], &confq);
+		check_consistency_with_resources(qdev);
+	}
+
+	/* change setting without parent */
+	tmp = get_phy_from_id(qdev->mapping, q[7]);
+	nodep = get_node_from_phy(qdev->nodes, tmp);
+	memcpy(&node, nodep, sizeof(struct qos_node)); 
+	QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[7], &confq) == 0, "pp_qos_queue_conf_get failed\n");
+	confq.queue_wred_max_allowed = 77; 
+	pp_qos_queue_set(qdev, q[7], &confq);
+	QOS_ASSERT(memcmp(&node, nodep, offsetof(struct qos_node, data.queue.max_allowed)) == 0, "Unexpected change\n");
+	QOS_ASSERT(nodep->data.queue.max_allowed == 77, "Set max allowed did not work\n");
+	QOS_ASSERT(memcmp(&(node.data.queue.min_guaranteed), &(nodep->data.queue.min_guaranteed), sizeof(struct qos_node) - offsetof(struct qos_node, data.queue.min_guaranteed)) == 0, "Unexpected change\n");
+	check_consistency_with_resources(qdev);
+
+	/* allocate port 7 and port 12 */
+	tmp = pp_qos_port_allocate(qdev, 7, &p7);
+	QOS_ASSERT(pp_qos_port_set(qdev, p7, &confp) == 0, "Could not set port\n");
+	tmp = pp_qos_port_allocate(qdev, 12, &p12);
+	QOS_ASSERT(pp_qos_port_set(qdev, p12, &confp) == 0, "Could not set port\n");
+	
+	/* change setting with parent */
+	tmp = get_phy_from_id(qdev->mapping, q[14]);
+	nodep = get_node_from_phy(qdev->nodes, tmp);
+	memcpy(&node, nodep, sizeof(struct qos_node)); 
+
+	QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[14], &confq) == 0, "pp_qos_queue_conf_get failed\n");
+	confq.queue_child_prop.parent = p7;
+	confq.queue_wred_max_allowed = 777; 
+	pp_qos_queue_set(qdev, q[14], &confq);
+	tmp = get_phy_from_id(qdev->mapping, q[14]);
+	nodep = get_node_from_phy(qdev->nodes, tmp);
+	QOS_ASSERT(nodep->data.queue.max_allowed == 777, "Set max allowed not work\n");
+	QOS_ASSERT(nodep->child_prop.parent_phy == get_phy_from_id(qdev->mapping, p7), "Set of parent did not work has %d instead of %d\n",
+		   nodep->child_prop.parent_phy,  get_phy_from_id(qdev->mapping, p7));
+	QOS_ASSERT(memcmp(&node, nodep, offsetof(struct qos_node, child_prop.parent_phy)) == 0, "Unexpected change\n");
+	QOS_ASSERT(memcmp(&node, nodep, offsetof(struct qos_node, child_prop.parent_phy)) == 0, "Unexpected change\n");
+	QOS_ASSERT(memcmp(&(node.child_prop.priority), &(nodep->child_prop.priority), offsetof(struct qos_node, data.queue.max_allowed) - offsetof(struct qos_node, child_prop.priority)) == 0, "Unexpected change\n");
+	QOS_ASSERT(memcmp(&(node.data.queue.min_guaranteed), &(nodep->data.queue.min_guaranteed), sizeof(struct qos_node) - offsetof(struct qos_node, data.queue.min_guaranteed)) == 0, "Unexpected change\n");
+
+	check_consistency_with_resources(qdev);
+
+	tmp = get_phy_from_id(qdev->mapping, q[21]);
+	nodep = get_node_from_phy(qdev->nodes, tmp);
+	memcpy(&node, nodep, sizeof(struct qos_node)); 
+	QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[21], &confq) == 0, "pp_qos_queue_conf_get failed\n");
+	confq.queue_child_prop.parent = p12;
+	confq.queue_wred_max_allowed = 2121; 
+	pp_qos_queue_set(qdev, q[21], &confq);
+	tmp = get_phy_from_id(qdev->mapping, q[21]);
+	nodep = get_node_from_phy(qdev->nodes, tmp);
+	QOS_ASSERT(nodep->data.queue.max_allowed == 2121, "Set max allowed not work\n");
+	QOS_ASSERT(nodep->child_prop.parent_phy == get_phy_from_id(qdev->mapping, p12), "Set of parent did not work has %d instead of %d\n",
+		   nodep->child_prop.parent_phy,  get_phy_from_id(qdev->mapping, p12));
+	QOS_ASSERT(memcmp(&node, nodep, offsetof(struct qos_node, child_prop.parent_phy)) == 0, "Unexpected change\n");
+	QOS_ASSERT(memcmp(&node, nodep, offsetof(struct qos_node, child_prop.parent_phy)) == 0, "Unexpected change\n");
+	QOS_ASSERT(memcmp(&(node.child_prop.priority), &(nodep->child_prop.priority), offsetof(struct qos_node, data.queue.max_allowed) - offsetof(struct qos_node, child_prop.priority)) == 0, "Unexpected change\n");
+	QOS_ASSERT(memcmp(&(node.data.queue.min_guaranteed), &(nodep->data.queue.min_guaranteed), sizeof(struct qos_node) - offsetof(struct qos_node, data.queue.min_guaranteed)) == 0, "Unexpected change\n");
+
+
+	check_consistency_with_resources(qdev);
+	expected_queues(qdev, 1, 98);
+	expected_queues(qdev, 7, 1);
+	expected_queues(qdev, 12, 1);
+	for (i = 25; i < 50; ++i) {
+		QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[i], &confq) == 0, "pp_qos_queue_conf_get failed on %d iteration\n", i);
+		confq.queue_wred_max_allowed = 300 + i;
+		confq.queue_child_prop.parent = p12;
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+		check_consistency_with_resources(qdev);
+	}
+	expected_queues(qdev, 1, 73);
+	expected_queues(qdev, 7, 1);
+	expected_queues(qdev, 12, 26);
+
+	for (i = 50; i < 70; ++i) {
+		QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[i], &confq) == 0, "pp_qos_queue_conf_get failed on %d iteration\n", i);
+		confq.queue_wred_max_allowed = 400 + i;
+		confq.queue_child_prop.parent = p7;
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+		check_consistency_with_resources(qdev);
+	}
+	expected_queues(qdev, 1, 53);
+	expected_queues(qdev, 7, 21);
+	expected_queues(qdev, 12, 26);
+
+	for (i = 25; i < 45; ++i) {
+		QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[i], &confq) == 0, "pp_qos_queue_conf_get failed on %d iteration\n", i);
+		confq.queue_wred_max_allowed = 500 + i;
+		confq.queue_child_prop.parent = p7;
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+		check_consistency_with_resources(qdev);
+	}
+
+	expected_queues(qdev, 1, 53);
+	expected_queues(qdev, 7, 41);
+	expected_queues(qdev, 12, 6);
+	for (i = 45; i < 60; ++i) {
+		QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[i], &confq) == 0, "pp_qos_queue_conf_get failed on %d iteration\n", i);
+		confq.queue_wred_max_allowed = 600 + i;
+		confq.queue_child_prop.parent = p12;
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+		check_consistency_with_resources(qdev);
+	}
+	expected_queues(qdev, 1, 53);
+	expected_queues(qdev, 7, 31);
+	expected_queues(qdev, 12, 16);
+
+	for (i = 60; i < 70; ++i) {
+		QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[i], &confq) == 0, "pp_qos_queue_conf_get failed on %d iteration\n", i);
+		confq.queue_wred_max_allowed = 700 + i;
+		confq.queue_child_prop.parent = p1;
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+		check_consistency_with_resources(qdev);
+	}
+	expected_queues(qdev, 1, 63);
+	expected_queues(qdev, 7, 21);
+	expected_queues(qdev, 12, 16);
+	for (j = 0 ; j < 100; ++j) {
+		for (i = 50; i < 70; ++i) {
+			QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[i], &confq) == 0, "pp_qos_queue_conf_get failed on %d iteration\n", i);
+			confq.queue_wred_max_allowed = 400 + i;
+			confq.queue_child_prop.parent = p7;
+			QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+			check_consistency_with_resources(qdev);
+		}
+
+		for (i = 25; i < 45; ++i) {
+			QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[i], &confq) == 0, "pp_qos_queue_conf_get failed on %d iteration\n", i);
+			confq.queue_wred_max_allowed = 500 + i;
+			confq.queue_child_prop.parent = p7;
+			QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+			check_consistency_with_resources(qdev);
+		}
+
+		for (i = 45; i < 60; ++i) {
+			QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[i], &confq) == 0, "pp_qos_queue_conf_get failed on %d iteration\n", i);
+			confq.queue_wred_max_allowed = 600 + i;
+			confq.queue_child_prop.parent = p12;
+			QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+			check_consistency_with_resources(qdev);
+		}
+
+		for (i = 60; i < 70; ++i) {
+			QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[i], &confq) == 0, "pp_qos_queue_conf_get failed on %d iteration\n", i);
+			confq.queue_wred_max_allowed = 700 + i;
+			confq.queue_child_prop.parent = p1;
+			QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+			check_consistency_with_resources(qdev);
+		}
+	}
+
+
+	get_node_queues(qdev, 1, NULL, 0, &tmp1);
+	get_node_queues(qdev, 7, NULL, 0, &tmp2);
+	get_node_queues(qdev, 12, NULL, 0, &tmp3);
+	tmp4 = tmp1 + tmp2 + tmp3;
+	QOS_ASSERT(tmp4 == 100, "Number of queues expected to be 100 but it is %u\n", tmp4);
+	
+	QOS_LOG_INFO("queue2 tests completed successfully :)\n");	
+	
+}
+
+static void test_queues3(struct pp_qos_dev *qdev)
+{
+	struct pp_qos_queue_conf confq;
+	struct pp_qos_port_conf confp;
+	unsigned int p1;
+	unsigned int q[100];
+	unsigned int i;
+	int tmp;
+	unsigned int bw[] = { 13, 0, 20, 17, 0, 0, 0, 8 };
+	unsigned firstnonport;
+
+	QOS_LOG_INFO("starting queues3 tests\n");	
+	firstnonport = qdev->max_port + 1;
+
+	/* Allocate port 1  */ 
+	pp_qos_port_conf_set_default(&confp); 
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_address = (void *)1;
+	confp.ring_size = 1;
+	tmp = pp_qos_port_allocate(qdev, 1, &p1);
+	expected_id_phy(qdev, p1, 0, 1);
+	QOS_ASSERT(pp_qos_port_set(qdev, p1, &confp) == 0, "Could not set port\n");
+	check_consistency_with_resources(qdev);
+
+	pp_qos_queue_conf_set_default(&confq); 
+	confq.queue_child_prop.parent = p1;
+	
+	/* Allocate 7 queues */
+	for (i = 0; i < 7; ++ i) {
+		tmp = pp_qos_queue_allocate(qdev, &q[i]);
+		QOS_ASSERT(tmp == 0, "Could not allocate queue\n");
+		confq.queue_wred_max_allowed = i;
+		confq.queue_child_prop.bandwidth_share = 13;
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Could not set queue\n");
+	}
+	check_consistency_with_resources(qdev);
+
+	/* Try to add a new queue with a share that cross 100 */
+	tmp = pp_qos_queue_allocate(qdev, &q[7]);
+	QOS_ASSERT(tmp == 0, "Could not allocate queue\n");
+	confq.queue_wred_max_allowed = 8;
+	confq.queue_child_prop.bandwidth_share = 10;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[7], &confq) != 0, "Set should have failed due to over bandwidth\n");
+	pp_pool_put(qdev->ids, q[7]);
+	check_consistency_with_resources(qdev);
+
+	
+	/* Change setting on existing node */
+	QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[6], &confq) == 0, "pp_qos_queue_conf_get failed\n");
+	confq.queue_child_prop.bandwidth_share = 15;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[6], &confq) == 0, "Set failed\n");
+	
+
+	/* Add a new queue that does not cross 100קד*/
+	tmp = pp_qos_queue_allocate(qdev, &q[7]);
+	QOS_ASSERT(tmp == 0, "Could not allocate queue\n");
+	confq.queue_wred_max_allowed = 8;
+	confq.queue_child_prop.bandwidth_share = 6;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[7], &confq) == 0, "Set have failed\n");
+	check_consistency_with_resources(qdev);
+
+	for (i = 0; i < 8; ++ i) {
+		QOS_ASSERT(pp_qos_queue_conf_get(qdev, q[i], &confq) == 0, "pp_qos_queue_conf_get failed\n");
+		QOS_ASSERT(tmp == 0, "Could not allocate queue\n");
+		confq.queue_child_prop.bandwidth_share = bw[i];
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Could not set queue\n");
+	}
+
+	tmp = pp_qos_queue_allocate(qdev, &q[8]);
+	QOS_ASSERT(tmp == 0, "Could not allocate queue\n");
+	confq.queue_child_prop.bandwidth_share = 10;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[8], &confq) == 0, "Could not set queue\n");
+	check_consistency_with_resources(qdev);
+
+	for (i = 9; i < 64; ++ i) {
+		tmp = pp_qos_queue_allocate(qdev, &q[i]);
+		QOS_ASSERT(tmp == 0, "Could not allocate queue\n");
+		confq.queue_child_prop.bandwidth_share = 0;
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Could not set queue\n");
+		check_consistency_with_resources(qdev);
+	}
+
+	tmp = pp_qos_queue_allocate(qdev, &q[64]);
+	QOS_ASSERT(tmp == 0, "Could not allocate queue\n");
+	confq.queue_child_prop.bandwidth_share = 15;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[64], &confq) == 0, "Could not set queue\n");
+
+	pp_qos_queue_remove(qdev, q[64]);
+	check_consistency_with_resources(qdev);
+
+	tree_remove(qdev, firstnonport); 
+	check_consistency_with_resources(qdev);
+
+	QOS_LOG_INFO("queue3 tests completed successfully :)\n");	
+}
+
+
+static void reposition_internal_test(struct pp_qos_dev *qdev)
+{
+	struct pp_qos_queue_conf confq;
+	struct pp_qos_port_conf confp;
+	struct pp_qos_sched_conf confs;
+	
+	unsigned int p89;
+	unsigned int p97;
+	unsigned int p105;
+	unsigned int p7;
+	unsigned int q[200];
+	unsigned int s[5];
+	unsigned int i;
+	int tmp;
+
+	QOS_LOG_INFO("reposition test started\n");
+
+	qdev->reserved_ports[89] = 1;
+	qdev->reserved_ports[97] = 1;
+	qdev->reserved_ports[105] = 1;
+	tmp = pp_qos_port_allocate(qdev, 7, &p7);
+	QOS_ASSERT(tmp == 0, "could not allocate qos port\n");
+
+	tmp = pp_qos_port_allocate(qdev, 89, &p89);
+	QOS_ASSERT(tmp == 0, "could not allocate qos port\n");
+
+	tmp = pp_qos_port_allocate(qdev, 97, &p97);
+	QOS_ASSERT(tmp == 0, "could not allocate qos port\n");
+
+	tmp = pp_qos_port_allocate(qdev, 105, &p105);
+	QOS_ASSERT(tmp == 0, "could not allocate qos port\n");
+
+	pp_qos_port_conf_set_default(&confp);
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_size = 1;
+	confp.ring_address = (void *)950000;
+	QOS_ASSERT(pp_qos_port_set(qdev, p7, &confp) == 0, "Could not set port\n");
+
+	confp.ring_address = (void *)950600;
+	QOS_ASSERT(pp_qos_port_set(qdev, p89, &confp) == 0, "Could not set port\n");
+
+	confp.ring_address = (void *)950700;
+	QOS_ASSERT(pp_qos_port_set(qdev, p97, &confp) == 0, "Could not set port\n");
+
+	confp.ring_address = (void *)950800;
+	QOS_ASSERT(pp_qos_port_set(qdev, p105, &confp) == 0, "Could not set port\n");
+
+	pp_qos_queue_conf_set_default(&confq);
+	confq.queue_child_prop.parent = p89;
+	for (i = 0; i < 200; ++ i) {
+		tmp = pp_qos_queue_allocate(qdev, &q[i]);
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "q set failed\n");
+	}
+
+	/* moving queues from p89 to p7 */ 
+	confq.queue_child_prop.parent = p7;
+	for (i = 0; i < 200; ++i)
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "q set failed\n");
+	
+	check_consistency_with_resources(qdev);
+
+	for (i = 0; i < 195; ++i)
+		QOS_ASSERT(pp_qos_queue_remove(qdev, q[i]) == 0, "q remove failed\n");
+	check_consistency_with_resources(qdev);
+
+	pp_qos_sched_conf_set_default(&confs);
+	for (i = 0; i < 5; ++i) {
+		QOS_ASSERT(pp_qos_sched_allocate(qdev, &s[i]) == 0, "Could not allocate sched\n");
+		if (i == 0)
+			confs.sched_child_prop.parent = p97;
+		else
+			confs.sched_child_prop.parent = s[i - 1];
+		QOS_ASSERT(pp_qos_sched_set(qdev, s[i], &confs) == 0, "Could not set sched\n");
+	}
+	
+	check_consistency_with_resources(qdev);
+
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q[0]) == 0, "Could not allocate queue\n");
+	confq.queue_child_prop.parent = s[4];
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[0], &confq) == 0, "Could not set queue\n");
+	check_consistency_with_resources(qdev);
+
+	confs.sched_child_prop.parent = p97;
+	QOS_ASSERT(pp_qos_sched_set(qdev, s[3], &confs) == 0, "Could not set sched\n");
+	check_consistency_with_resources(qdev);
+
+	confs.sched_child_prop.parent = p105;
+	QOS_ASSERT(pp_qos_sched_set(qdev, s[4], &confs) == 0, "Could not set sched\n");
+	check_consistency_with_resources(qdev);
+	QOS_LOG_INFO("reposition test completed successfully :)\n");
+	
+}
+
+static struct pp_qos_dev *test_open_and_init_instance(unsigned int instance)
+{
+	int rc;
+	struct pp_qos_init_param initp;
+	struct pp_qos_dev *qdev;
+
+	qdev = pp_qos_dev_open(instance);
+	if (qdev) {
+		if (!qdev->initialized) {
+			memset(&initp, 0, sizeof(initp));
+			initp.wred_total_avail_resources = 0x10000;
+			initp.wred_p_const = 512;
+			initp.wred_max_q_size = 10000;
+			initp.reserved_ports[1] = 1;
+			initp.reserved_ports[7] = 1;
+			initp.reserved_ports[12] = 1;
+			rc = pp_qos_dev_init(qdev, &initp);
+			QOS_ASSERT(rc == 0, "Init of instance 0 failed\n");
+		} else {
+			QOS_LOG_INFO("Device %u already initialized\n", instance);
+		}
+	} else {
+		QOS_LOG_ERR("Could not open device %u\n", instance);
+	}
+	return qdev;
+}
+
+
+static void test_shared_group(struct pp_qos_dev *qdev)
+{
+	int rc;
+	unsigned int id1;
+	unsigned int id2;
+	unsigned int p;
+	unsigned int q[10];
+	unsigned int phy;
+	unsigned int gid;
+	uint16_t members[5];
+	unsigned int members_num;
+	int i;
+	struct qos_node *node;
+	struct pp_qos_queue_conf confq;
+	struct pp_qos_port_conf confp;
+
+	QOS_LOG_INFO("starting shared group tests\n");	
+
+	rc = pp_qos_shared_limit_group_add(qdev, 100, &id1);
+	QOS_ASSERT(rc == 0 && id1 == 1, "Return code is %d id is %u expected 1\n", rc ,id1);
+
+	rc = pp_qos_shared_limit_group_add(qdev, 200, &id2);
+	QOS_ASSERT(rc == 0 && id2 == 2, "Return code is %d id is %u expected 2\n", rc ,id2);
+
+	rc = pp_qos_shared_limit_group_remove(qdev, 3);
+	QOS_ASSERT(rc == -EINVAL, "Removing not existent group should have failed\n");
+
+	rc = pp_qos_shared_limit_group_remove(qdev, id2);
+	QOS_ASSERT(rc == 0, "Removing failed with %d\n", rc);
+
+	rc = pp_qos_shared_limit_group_modify(qdev, id2, 500);
+	QOS_ASSERT(rc == -EINVAL, "Modifying not existent group should have failed\n");
+
+	rc = pp_qos_shared_limit_group_modify(qdev, id1, 100);
+	QOS_ASSERT(rc == 0, "Modifying group failed with %d\n", rc);
+
+	pp_qos_port_conf_set_default(&confp); 
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_address = (void *)1;
+	confp.ring_size = 1;
+	rc = pp_qos_port_allocate(qdev, 1, &p);
+	QOS_ASSERT(pp_qos_port_set(qdev, p, &confp) == 0, "Could not set port\n");
+	node = get_node_from_phy(qdev->nodes, 1);
+	QOS_ASSERT(node->shared_bandwidth_group ==  QOS_NO_SHARED_BANDWIDTH_GROUP, "shared bandwidth group shoud be %u but it is %u\n", QOS_NO_SHARED_BANDWIDTH_GROUP,
+			node->shared_bandwidth_group);
+	
+	pp_qos_queue_conf_set_default(&confq); 
+	confq.queue_child_prop.parent = p;
+	
+	/* Allocate 7 queues */
+	for (i = 0; i < 7; ++ i) {
+		rc = pp_qos_queue_allocate(qdev, &q[i]);
+		QOS_ASSERT(rc == 0, "Could not allocate queue\n");
+
+		if (i > 3) 
+			confq.common_prop.shared_bandwidth_group = id1;
+		else
+			confq.common_prop.shared_bandwidth_group = 0;
+
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Could not set queue\n");
+	}
+
+	for (i = 0; i < 7; ++i) {
+		phy = get_phy_from_id(qdev->mapping, q[i]);
+		node = get_node_from_phy(qdev->nodes, phy);
+		gid = node->shared_bandwidth_group;
+		if (i > 3)
+			QOS_ASSERT(gid == id1, "shared group id is %u expected %u\n", gid, id1);
+		else
+
+			QOS_ASSERT(gid == QOS_NO_SHARED_BANDWIDTH_GROUP, "shared group id is %u expected %u\n", gid, QOS_NO_SHARED_BANDWIDTH_GROUP);
+	}
+
+	rc = pp_qos_queue_allocate(qdev, &q[8]);
+	QOS_ASSERT(rc == 0, "Could not allocate queue\n");
+	confq.common_prop.shared_bandwidth_group = 10;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[8], &confq) == -EINVAL, "Illegal shared group, should have failed\n");
+	pp_pool_put(qdev->ids, q[8]);
+	
+
+
+	rc = pp_qos_shared_limit_group_get_members(qdev, id1, members, 5, &members_num);
+	QOS_ASSERT(rc == 0 && members_num == 3, "get_members returned %d, expected number of members to be %u but it is %u\n",
+			rc, 3 , members_num);
+
+	QOS_ASSERT(members[0] == q[4] && members[1] == q[5] && members[2] == q[6], "Unexpected members %u %u %u\n", members[0], members[1], members[2]);
+
+	/* Block removing of queue with members */
+	rc = pp_qos_shared_limit_group_remove(qdev, id1);
+	QOS_ASSERT(rc == -EBUSY, "Removing group with members should fail\n");
+
+	confq.common_prop.shared_bandwidth_group = 0;
+
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[4], &confq) == 0, "Could not set queue\n");
+	rc = pp_qos_shared_limit_group_remove(qdev, id1);
+	QOS_ASSERT(rc == -EBUSY, "Removing group with members should fail\n");
+	
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[5], &confq) == 0, "Could not set queue\n");
+	rc = pp_qos_shared_limit_group_remove(qdev, id1);
+	QOS_ASSERT(rc == -EBUSY, "Removing group with members should fail\n");
+
+	check_consistency_with_resources(qdev);
+
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[6], &confq) == 0, "Could not set queue\n");
+	rc = pp_qos_shared_limit_group_remove(qdev, id1);
+	QOS_ASSERT(rc == 0, "Removing group failed\n");
+
+
+	check_consistency_with_resources(qdev);
+	QOS_LOG_INFO("shared group tests completed successfully :)\n");	
+}
+
+
+/*
+ *       p1                       p7
+ *   s0      s1                   q3
+ * q0  s2    q1 
+ *     q2
+ */
+void test_cmd_queue(void)
+{
+	struct pp_qos_dev *qdev;
+	struct pp_qos_port_conf confp;
+	struct pp_qos_sched_conf confs;
+	struct pp_qos_queue_conf confq;
+	unsigned int p1;
+	unsigned int p7;
+	unsigned int s0;
+	unsigned int s1;
+	unsigned int s2;
+	unsigned int q0;
+	unsigned int q1;
+	unsigned int q2;
+	unsigned int q3;
+	unsigned int q[10];
+	unsigned int i;
+	unsigned firstnonport;
+
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	firstnonport = qdev->max_port + 1;
+	QOS_LOG_INFO("starting cmd queue tests\n");
+	// Add ports 1 and 7 
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 1, &p1) == 0, "Could not allocate port\n");
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 7, &p7) == 0, "Could not allocate port\n");
+	pp_qos_port_conf_set_default(&confp); 
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_address = (void *)1;
+	confp.ring_size = 1;
+	QOS_ASSERT(pp_qos_port_set(qdev, p1, &confp) == 0, "Could not set port\n");
+	QOS_ASSERT(pp_qos_port_set(qdev, p7, &confp) == 0, "Could not set port\n");
+
+	// Add schedulers
+	QOS_ASSERT(pp_qos_sched_allocate(qdev, &s0) == 0, "Could not allocate sched\n");
+	QOS_ASSERT(pp_qos_sched_allocate(qdev, &s1) == 0, "Could not allocate sched\n");
+	QOS_ASSERT(pp_qos_sched_allocate(qdev, &s2) == 0, "Could not allocate sched\n");
+	pp_qos_sched_conf_set_default(&confs); 
+	confs.sched_child_prop.parent = p1;
+	QOS_ASSERT(pp_qos_sched_set(qdev, s0, &confs) == 0, "Could not set sched\n");
+	QOS_ASSERT(pp_qos_sched_set(qdev, s1, &confs) == 0, "Could not set sched\n");
+	confs.sched_child_prop.parent = s0;
+	confs.sched_child_prop.bandwidth_share = 7;
+	QOS_ASSERT(pp_qos_sched_set(qdev, s2, &confs) == 0, "Could not set sched\n");
+
+	// Add queues
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q0) == 0, "Could not allocate queue\n");
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q1) == 0, "Could not allocate queue\n");
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q2) == 0, "Could not allocate queue\n");
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q3) == 0, "Could not allocate queue\n");
+	pp_qos_queue_conf_set_default(&confq); 
+	confq.queue_child_prop.parent = s0;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q0, &confq) == 0, "Could not set queue\n");
+	confq.queue_child_prop.parent = s1;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q1, &confq) == 0, "Could not set queue\n");
+	confq.queue_child_prop.parent = s2;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q2, &confq) == 0, "Could not set queue\n");
+	confq.queue_child_prop.parent = p7;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q3, &confq) == 0, "Could not set queue\n");
+	
+	check_consistency_with_resources(qdev);
+	nodes_move(qdev, 32, firstnonport, 7);
+	check_consistency_with_resources(qdev);
+	
+
+	/* s0 has 2 children, adding 5 more */
+	confq.queue_child_prop.parent = s0;
+	confq.queue_child_prop.bandwidth_share = 7;
+	for (i = 0; i < 5; ++i) {
+		QOS_ASSERT(pp_qos_queue_allocate(qdev, &q[i]) == 0, "Could not allocate queue\n");
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Could not set queue\n");
+	}
+	
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q[5]) == 0, "Could not allocate queue\n");
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[5], &confq) == 0, "Could not set queue\n");
+
+	/* This should call create internal scheduler */
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q[6]) == 0, "Could not allocate queue\n");
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[6], &confq) == 0, "Could not set queue\n");
+	
+	check_consistency_with_resources(qdev);
+
+	//transmit_cmds(qdev);
+
+#if 0
+	// Modify port arbitration
+	confp.common_prop.bandwidth_limit = 10;
+	QOS_ASSERT(pp_qos_port_set(qdev, p0, &confp) == 0, "Could not set port\n");
+
+
+	// Add queue under port
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q0) == 0, "Could not allocate queue\n");
+	pp_qos_queue_conf_set_default(&confq); 
+	confq.queue_child_prop.priority = 0;
+	confq.queue_child_prop.parent = p0;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q0, &confq) == 0, "Could not set queue\n");
+	check_consistency_with_resources(qdev);
+
+	// Modify queue
+	confq.queue_child_prop.bandwidth_share = 10;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q0, &confq) == 0, "Could not set queue\n");
+
+	for (i = 0; i < 7; ++i) {
+		QOS_ASSERT(pp_qos_queue_allocate(qdev, q + i) == 0, "Could not allocate queue\n");
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Could not set queue\n");
+	}
+
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, q + 7) == 0, "Could not allocate queue\n");
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[7], &confq) == 0, "Could not set queue\n");
+	// Remove port 
+	QOS_ASSERT(pp_qos_port_remove(qdev, p0) == 0, "Could not remove port\n");
+	check_consistency_with_resources(qdev);
+#endif
+
+	QOS_LOG_INFO("cmd queue tests completed successfully :)\n");
+}
+
+struct pp_mapping {
+	uint16_t id2phy[NUM_OF_NODES];
+	uint16_t phy2id[NUM_OF_NODES];
+};
+struct octet_info {
+	struct list_head list;
+	uint8_t usage;
+};
+struct pp_octets {
+	int last_port_octet;
+	struct octet_info info[NUM_OF_OCTETS];
+	struct list_head lists[9];
+};
+struct pp_nodes {
+	struct qos_node nodes[NUM_OF_NODES];
+};
+static void reset_qos_dev(struct pp_qos_dev *dst, struct pp_qos_dev *src)
+{
+
+	memcpy(dst->groups, src->groups, sizeof(dst->groups));
+	*(dst->ids) = *(src->ids);
+	memcpy(dst->ids->data, src->ids->data, dst->ids->capacity * sizeof(dst->ids->data[0]));
+	*(dst->rlms) = *(src->rlms);
+	memcpy(dst->rlms->data, src->rlms->data, dst->rlms->capacity * sizeof(dst->rlms->data[0]));
+	*(dst->portsphys) = *(src->portsphys);
+	memcpy(dst->portsphys->data, src->portsphys->data, dst->portsphys->capacity * sizeof(dst->portsphys->data[0]));
+
+	memcpy(dst->nodes, src->nodes, sizeof(struct pp_nodes));
+	memcpy(dst->mapping, src->mapping, sizeof(struct pp_mapping));
+	octets_clean(dst->octets);
+	dst->octets = octets_init(octet_of_phy(dst->max_port));
+}
+
+static struct pp_qos_dev *init_clone(struct pp_qos_dev *qdev)
+{
+	struct pp_qos_dev *clone;
+
+	clone = _qos_init(qdev->max_port);
+	clone->portsphys = free_ports_phys_init(clone->reserved_ports, qdev->max_port, qdev->reserved_ports, MAX_PORTS);
+
+
+	return clone;
+}
+
+void basic_tests(void)
+{
+	struct pp_qos_dev *qdev;
+	struct pp_qos_dev *clone;
+
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	QOS_LOG_INFO("starting basic tests :)\n");
+	clone = init_clone(qdev);
+	QOS_ASSERT(clone, "Could not create clone\n");
+
+
+	test_modify_used_status(qdev);
+	test_phy_allocation_not_full_octet(qdev);
+	test_phy_allocation_full_octet(qdev);
+	test_phy_allocation_full_octet_2(qdev);
+	test_internal_scheduler(qdev);
+	
+	reset_qos_dev(qdev, clone);
+	_qos_clean(clone);
+	QOS_LOG_INFO("basic tests completed successfully :)\n");
+}
+
+void advance_tests(void)
+{
+	struct pp_qos_dev *qdev;
+	struct pp_qos_dev *clone;
+
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	QOS_LOG_INFO("starting advance tests :)\n");
+	if (qdev->max_port < 15) {
+		QOS_LOG_ERR("Advance test requires that max port will be at least 15 !!!!\n");
+		return;
+	}
+	clone = init_clone(qdev);
+	QOS_ASSERT(clone, "Could not create clone\n");
+
+	test_ports(qdev);
+	reset_qos_dev(qdev, clone);
+
+	test_queues1(qdev);
+	reset_qos_dev(qdev, clone);
+
+	test_queues2(qdev);
+	reset_qos_dev(qdev, clone);
+
+	test_queues3(qdev);
+	reset_qos_dev(qdev, clone);
+
+	reposition_internal_test(qdev);
+	reset_qos_dev(qdev, clone);
+
+	test_shared_group(qdev);
+	reset_qos_dev(qdev, clone);
+
+	_qos_clean(clone);
+	QOS_LOG_INFO("advance tests completed successfully :)\n");
+}
+
+void tests(void)
+{
+	/* 
+	 * An old test that is not working but want to keep.
+	 * So compiler will not shout of unused function i
+	 */ 
+	struct pp_qos_dev *qdev;
+	if (0)
+		test_move_nodes(qdev);
+
+	basic_tests();
+	advance_tests();
+	QOS_LOG_INFO("all tests completed successfully :)\n");
+}
+
+#define RING_ADDRESS 0x247000
+#define RING_ADDRESS_0 0x240000
+#define RING_ADDRESS_7 0x240700
+#define RING_ADDRESS_26 0x241A00
+#define RING_ADDRESS_89 0x245900
+
+#if 0
+void falcon_test(void)
+{
+	struct pp_qos_dev *qdev;
+	unsigned int p89;
+	unsigned int p26;
+	unsigned int p7;
+	unsigned int p0;
+	unsigned int q[10];
+	struct pp_qos_port_conf confp;
+	struct pp_qos_queue_conf confq;
+
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	qdev->reserved_ports[0] = 1;
+	qdev->reserved_ports[26] = 1;
+	qdev->reserved_ports[89] = 1;
+
+	pp_qos_port_conf_set_default(&confp); 
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_size = 1;
+	pp_qos_queue_conf_set_default(&confq); 
+	confq.queue_wred_max_allowed = 0x400;
+
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 89, &p89) == 0, "Could not allocate port\n");
+	confp.ring_address = (void *)RING_ADDRESS_89; 
+	QOS_ASSERT(pp_qos_port_set(qdev, p89, &confp) == 0, "Could not set port\n");
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q[0]) == 0, "Could not allocate queue\n");
+	confq.queue_child_prop.parent = p89;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[0], &confq) == 0, "Setting failed\n");
+
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 0, &p0) == 0, "Could not allocate port\n");
+	confp.ring_address = (void *)RING_ADDRESS_0; 
+	QOS_ASSERT(pp_qos_port_set(qdev, p0, &confp) == 0, "Could not set port\n");
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q[1]) == 0, "Could not allocate queue\n");
+	confq.queue_child_prop.parent = p0;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[1], &confq) == 0, "Setting failed");
+
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 7, &p7) == 0, "Could not allocate port\n");
+	confp.ring_address = (void *)RING_ADDRESS_7; 
+	QOS_ASSERT(pp_qos_port_set(qdev, p7, &confp) == 0, "Could not set port\n");
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q[2]) == 0, "Could not allocate queue\n");
+	confq.queue_child_prop.parent = p7;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[2], &confq) == 0, "Setting failed\n");
+
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 26, &p26) == 0, "Could not allocate port\n");
+	confp.ring_address = (void *)RING_ADDRESS_26; 
+	QOS_ASSERT(pp_qos_port_set(qdev, p26, &confp) == 0, "Could not set port\n");
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q[3]) == 0, "Could not allocate queue\n");
+	confq.queue_child_prop.parent = p26;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q[3], &confq) == 0, "Setting failed");
+
+	QOS_ASSERT(pp_qos_queue_remove(qdev, q[2]) == 0, "removing failed\n");
+}
+#endif
+
+#if 0
+void falcon_test(void)
+{
+	unsigned int i;
+	void *address;
+	struct pp_qos_dev *qdev;
+	unsigned int p[3];
+	unsigned int q[10];
+	struct pp_qos_port_conf confp;
+	struct pp_qos_queue_conf confq;
+	unsigned int rlms[] = {14, 74, 30, 87, 235, 42, 242, 190, 119, 103};
+	unsigned int ring_address[] = {RING_ADDRESS_0, RING_ADDRESS_7, RING_ADDRESS_26};
+
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	qdev->reserved_ports[0] = 1;
+	qdev->reserved_ports[26] = 1;
+
+	/* Hacking rlms array to give rlm that the slim driver currently uses */
+	for (i = 0; i < sizeof(rlms) / sizeof(rlms[0]); ++i) {
+		qdev->rlms->data[NUM_OF_QUEUES - 1 - i] = rlms[i];
+		qdev->rlms->data[NUM_OF_QUEUES - 1 - rlms[i]] = i;
+	}
+	
+	/* Configure ports 0, 7, 26 */
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 0, &p[0]) == 0, "Could not allocate port\n");
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 7, &p[1]) == 0, "Could not allocate port\n");
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 26, &p[2]) == 0, "Could not allocate port\n");
+	pp_qos_port_conf_set_default(&confp); 
+
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_size = 1;
+	for (i = 0 ; i < 3; ++i) {
+		confp.ring_address = (void *)(ring_address[i]); 
+		if (i == 0)
+			confp.credit = 2;
+		else
+			confp.credit = 8;
+		QOS_ASSERT(pp_qos_port_set(qdev, p[i], &confp) == 0, "Could not set port\n");
+	}
+
+	pp_qos_queue_conf_set_default(&confq); 
+	confq.queue_wred_max_allowed = 0x400;
+	for (i = 0; i < 10; ++i) {
+		QOS_ASSERT(pp_qos_queue_allocate(qdev, q + i) == 0, "Could not allocate queue\n");
+		if (i < 4)
+			confq.queue_child_prop.parent = p[0];
+		else if (i < 7)
+			confq.queue_child_prop.parent = p[1];
+		else 
+			confq.queue_child_prop.parent = p[2];
+
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+	}
+
+	QOS_LOG_INFO("Falcon test completed successfully :)\n");
+}
+#endif
+
+#if 1
+void falcon_test(void)
+{
+	unsigned int i;
+	struct pp_qos_dev *qdev;
+	unsigned int p[3];
+	unsigned int p89;
+	unsigned int q[10];
+	struct pp_qos_port_conf confp;
+	struct pp_qos_queue_conf confq;
+	struct pp_qos_node_info info;
+	unsigned int rlms[] = {14, 74, 30, 87, 235, 42, 242, 190, 119, 103};
+	unsigned int ring_address[] = {RING_ADDRESS_0, RING_ADDRESS_7, RING_ADDRESS_26, RING_ADDRESS_89};
+
+	QOS_LOG_INFO("Falcon move test started\n");
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	qdev->reserved_ports[0] = 1;
+	qdev->reserved_ports[26] = 1;
+	qdev->reserved_ports[89] = 1;
+
+	/* Hacking rlms array to give rlm that the slim driver currently uses */
+	for (i = 0; i < sizeof(rlms) / sizeof(rlms[0]); ++i) {
+		qdev->rlms->data[NUM_OF_QUEUES - 1 - i] = rlms[i];
+		qdev->rlms->data[NUM_OF_QUEUES - 1 - rlms[i]] = i;
+	}
+	
+	/* Configure ports 0, 7, 26 */
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 0, &p[0]) == 0, "Could not allocate port\n");
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 7, &p[1]) == 0, "Could not allocate port\n");
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 26, &p[2]) == 0, "Could not allocate port\n");
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 89, &p89) == 0, "Could not allocate port\n");
+	pp_qos_port_conf_set_default(&confp); 
+
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_size = 1;
+	for (i = 0 ; i < 3; ++i) {
+		confp.ring_address = (void *)(uintptr_t)(ring_address[i]); 
+		if (i == 0)
+			confp.credit = 2;
+		else
+			confp.credit = 8;
+		QOS_ASSERT(pp_qos_port_set(qdev, p[i], &confp) == 0, "Could not set port\n");
+	}
+
+	QOS_ASSERT(pp_qos_port_set(qdev, p89, &confp) == 0, "Could not set port\n");
+	pp_qos_queue_conf_set_default(&confq); 
+	confq.queue_wred_max_allowed = 0x400;
+	confq.queue_child_prop.parent = p89;
+	for (i = 0; i < 10; ++i) {
+		QOS_ASSERT(pp_qos_queue_allocate(qdev, q + i) == 0, "Could not allocate queue\n");
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+	}
+
+	for (i = 0; i < 10; ++i) {
+		if (i < 4)
+			confq.queue_child_prop.parent = p[0];
+		else if (i < 7)
+			confq.queue_child_prop.parent = p[1];
+		else 
+			confq.queue_child_prop.parent = p[2];
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+	}
+
+	check_consistency_with_resources(qdev);
+
+	QOS_ASSERT(pp_qos_get_node_info(qdev, p89, &info) == 0, "Could not get node info\n");
+	for (i = 0; i < 3; ++i)
+		QOS_ASSERT(pp_qos_get_node_info(qdev, p[i], &info) == 0, "Could not get node info\n");
+
+	for (i = 0; i < 10; ++i)
+		QOS_ASSERT(pp_qos_get_node_info(qdev, q[i], &info) == 0, "Could not get node info\n");
+
+	QOS_LOG_INFO("Falcon move test completed successfully :)\n");
+}
+#endif
+
+#if 0
+void falcon_test(void)
+{
+	unsigned int i;
+	struct pp_qos_dev *qdev;
+	unsigned int p26;
+	unsigned int q1;
+	unsigned int q2;
+	struct pp_qos_port_conf confp;
+	struct pp_qos_queue_conf confq;
+	unsigned int rlms[] = {14, 74, 30, 87, 235, 42, 242, 190, 119, 103};
+	unsigned int ring_address[] = {RING_ADDRESS_0, RING_ADDRESS_26};
+
+	QOS_LOG_INFO("Falcon test started\n");
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	qdev->reserved_ports[26] = 1;
+
+	/* Hacking rlms array to give rlm that the slim driver currently uses */
+	for (i = 0; i < sizeof(rlms) / sizeof(rlms[0]); ++i) {
+		qdev->rlms->data[NUM_OF_QUEUES - 1 - i] = rlms[i];
+		qdev->rlms->data[NUM_OF_QUEUES - 1 - rlms[i]] = i;
+	}
+	
+	/* Configure port 26 */
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 26, &p26) == 0, "Could not allocate port\n");
+	pp_qos_port_conf_set_default(&confp); 
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_size = 1;
+	confp.ring_address = (void *)(RING_ADDRESS_26); 
+	confp.credit = 8;
+	QOS_ASSERT(pp_qos_port_set(qdev, p26, &confp) == 0, "Could not set port\n");
+
+	pp_qos_queue_conf_set_default(&confq); 
+	confq.queue_child_prop.parent = p26;
+	confq.queue_wred_max_allowed = 0x400;
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q1) == 0, "Could not allocate queue\n");
+	QOS_ASSERT(pp_qos_queue_set(qdev, q1, &confq) == 0, "Setting queue fail\n");
+	QOS_ASSERT(pp_qos_queue_remove(qdev, q1) == 0, "Remove queue failed\n");
+
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q2) == 0, "Could not allocate queue\n");
+	QOS_ASSERT(pp_qos_queue_set(qdev, q2, &confq) == 0, "Setting queue fail\n");
+	QOS_LOG_INFO("Falcon test completed successfully :)\n");
+}
+#endif
+#if 0
+/* 
+ * p(0) -> 14 
+ * p(7) -> s(a) -> s(b) -> s(c) -> s(d) -> s(e) -> q(235)
+ */
+void falcon_test(void)
+{
+	unsigned int i;
+	struct pp_qos_dev *qdev;
+	unsigned int p1;
+	unsigned int p7;
+	unsigned int s[5];
+	unsigned int q;
+	struct pp_qos_port_conf confp;
+	struct pp_qos_queue_conf confq;
+	struct pp_qos_sched_conf confs;
+
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	pp_qos_port_conf_set_default(&confp); 
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_size = 1;
+
+	/* add port 0 */
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 1, &p1) == 0, "Could not allocate port 0\n");
+	confp.credit = 2;
+	confp.ring_address = (void *)RING_ADDRESS_0; 
+	QOS_ASSERT(pp_qos_port_set(qdev, p1, &confp) == 0, "Could not set port 0\n");
+
+	/* add port 7 */
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 7, &p7) == 0, "Could not allocate port 0\n");
+	confp.credit = 8;
+	confp.ring_address = (void *)RING_ADDRESS_7; 
+	QOS_ASSERT(pp_qos_port_set(qdev, p7, &confp) == 0, "Could not set port 7\n");
+
+	/* Allocate 5 scheduler each is a child of its predecessor */
+	pp_qos_sched_conf_set_default(&confs);
+	for (i = 0; i < 5; ++i) {
+		QOS_ASSERT(pp_qos_sched_allocate(qdev, &s[i]) == 0, "Could not allocate sched\n");
+		if (i == 0)
+			confs.sched_child_prop.parent = p7;
+		else
+			confs.sched_child_prop.parent = s[i - 1];
+		QOS_ASSERT(pp_qos_sched_set(qdev, s[i], &confs) == 0, "Could not set sched\n");
+	}
+
+	pp_qos_queue_conf_set_default(&confq);
+	confq.queue_wred_max_allowed = 0x400;
+
+	/* Add q */
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q) == 0, "Could not allocate queue 235\n");
+	confq.queue_child_prop.parent = s[4];
+	QOS_ASSERT(pp_qos_queue_set(qdev, q, &confq) == 0, "Could not set queue 235\n");
+
+
+	check_consistency_with_resources(qdev);
+	QOS_LOG_INFO("Deep configuration completed\n");
+
+	confs.sched_child_prop.parent = p7;
+	QOS_ASSERT(pp_qos_sched_set(qdev, s[3], &confs) == 0, "Could not set sched\n");
+	check_consistency_with_resources(qdev);
+}
+#endif
+
+#if 0
+/*
+ * p(0) -> q(14)
+ * p(7) -> all other queues
+ */
+static unsigned int q[256];
+void falcon_test(void)
+{
+	unsigned int i;
+	struct pp_qos_dev *qdev;
+	unsigned int p7;
+	unsigned int p0;
+	struct pp_qos_port_conf confp;
+	struct pp_qos_queue_conf confq;
+#if 0
+	unsigned int q14;
+	unsigned int rlms[] = {14};
+#endif
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	qdev->reserved_ports[0] = 1;
+	qdev->reserved_ports[26] = 1;
+
+#if 0
+	/* Hacking rlms array to give rlm that the slim driver currently uses */
+	for (i = 0; i < sizeof(rlms) / sizeof(rlms[0]); ++i) {
+		qdev->rlms->data[NUM_OF_QUEUES - 1 - i] = rlms[i];
+		qdev->rlms->data[NUM_OF_QUEUES - 1 - rlms[i]] = i;
+	}
+#endif
+	
+	pp_qos_port_conf_set_default(&confp); 
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_size = 1;
+
+	/* add port 0 */
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 0, &p0) == 0, "Could not allocate port 0\n");
+	confp.credit = 2;
+	confp.ring_address = (void *)RING_ADDRESS_0; 
+	QOS_ASSERT(pp_qos_port_set(qdev, p0, &confp) == 0, "Could not set port 0\n");
+
+	/* add port 7 */
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 7, &p7) == 0, "Could not allocate port 0\n");
+	confp.credit = 8;
+	confp.ring_address = (void *)RING_ADDRESS_7; 
+	QOS_ASSERT(pp_qos_port_set(qdev, p7, &confp) == 0, "Could not set port 7\n");
+
+	pp_qos_queue_conf_set_default(&confq);
+	confq.queue_wred_max_allowed = 0x200;
+
+#if 0
+	/* Add q14 under port 0 */
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q14) == 0, "Could not allocate queuei 14\n");
+	confq.queue_child_prop.parent = p0;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q14, &confq) == 0, "Could not set queue 14\n");
+#endif
+
+	/* Add other 255 queues under p7 */
+	confq.queue_child_prop.parent = p7;
+	for (i = 0; i < 256 ; ++i) {
+		QOS_ASSERT(pp_qos_queue_allocate(qdev, &q[i]) == 0, "Could not allocate queue\n");
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Could not set queue\n");
+	}
+
+	QOS_LOG_INFO("All queues test configuration completed\n");
+}
+#endif
+
+#if 0
+void falcon_test(void)
+{
+	unsigned int i;
+	struct pp_qos_dev *qdev;
+	unsigned int p[3];
+	unsigned int q[10];
+	struct pp_qos_port_conf confp;
+	struct pp_qos_queue_conf confq;
+	unsigned int rlms[] = {14, 74, 30, 87, 235, 42, 242, 190, 119, 103};
+	unsigned int ring_address[] = {RING_ADDRESS_0, RING_ADDRESS_7, RING_ADDRESS_26};
+
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	qdev->reserved_ports[0] = 1;
+	qdev->reserved_ports[26] = 1;
+
+	/* Hacking
+	 * rlms
+	 * array
+	 * to
+	 * give
+	 * rlm
+	 * that
+	 * the
+	 * slim
+	 * driver
+	 * currently
+	 * uses
+	 * */
+	for (i = 0; i < sizeof(rlms) / sizeof(rlms[0]); ++i) {
+		qdev->rlms->data[NUM_OF_QUEUES - 1 - i] = rlms[i];
+		qdev->rlms->data[NUM_OF_QUEUES - 1 - rlms[i]] = i;
+	}
+
+	/* Configure
+	 * ports
+	 * 0,
+	 * 7,
+	 * 26
+	 * */
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 0, &p[0]) == 0, "Could not allocate port\n");
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 7, &p[1]) == 0, "Could not allocate port\n");
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 26, &p[2]) == 0, "Could not allocate port\n");
+	pp_qos_port_conf_set_default(&confp);
+
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_size = 1;
+	for (i = 0 ; i < 3; ++i) {
+		confp.ring_address = (void *)(uintptr_t)(ring_address[i]);
+		if (i == 0)
+			confp.credit = 2;
+		else
+			confp.credit = 8;
+		confp.common_prop.bandwidth_limit = 0;
+		if (i==1)
+		{
+			confp.common_prop.bandwidth_limit = 1;
+		}
+
+		QOS_ASSERT(pp_qos_port_set(qdev, p[i], &confp) == 0, "Could not set port\n");
+	}
+
+	pp_qos_queue_conf_set_default(&confq);
+	confq.queue_wred_max_allowed = 0x400;
+	for (i = 0; i < 10; ++i) {
+		QOS_ASSERT(pp_qos_queue_allocate(qdev, q + i) == 0, "Could not allocate queue\n");
+		if (i < 4)
+			confq.queue_child_prop.parent = p[0];
+		else if (i < 7)
+			confq.queue_child_prop.parent = p[1];
+		else
+			confq.queue_child_prop.parent = p[2];
+
+		QOS_ASSERT(pp_qos_queue_set(qdev, q[i], &confq) == 0, "Setting failed on %d iteration\n", i);
+	}
+
+	QOS_LOG_INFO("Falcon test completed successfully :)\n");
+}
+#endif
+
+
+#if 1
+void stat_test(void)
+{
+	struct pp_qos_dev *qdev;
+	unsigned int p;
+	unsigned int q1;
+	unsigned int q2;
+	struct pp_qos_port_conf confp;
+	struct pp_qos_queue_conf confq;
+	struct pp_qos_queue_stat qstat; 
+	struct pp_qos_port_stat pstat; 
+
+	QOS_LOG_INFO("statistics test started\n");
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 1, &p) == 0, "Could not allocate port\n");
+	pp_qos_port_conf_set_default(&confp); 
+
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_size = 1;
+	confp.ring_address = (void *)RING_ADDRESS;
+	QOS_ASSERT(pp_qos_port_set(qdev, p, &confp) == 0, "Could not set port\n");
+
+	pp_qos_queue_conf_set_default(&confq); 
+	confq.queue_wred_max_allowed = 1000;
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q1) == 0, "Could not allocate queue\n");
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q2) == 0, "Could not allocate queue\n");
+	confq.queue_child_prop.parent = p;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q1, &confq) == 0, "Could not set queue\n");
+	QOS_ASSERT(pp_qos_queue_set(qdev, q2, &confq) == 0, "Could not set queue\n");
+
+	memset(&pstat, 0, sizeof(pstat));
+	QOS_ASSERT(pp_qos_port_stat_get(qdev, p, &pstat) == 0, "Could not get port statistics\n");
+
+	memset(&qstat, 0, sizeof(qstat));
+	QOS_ASSERT(pp_qos_queue_stat_get(qdev, q1, &qstat) == 0, "Could not get queue statistics\n");
+	QOS_ASSERT(
+			qstat.reset == 0 &&
+			qstat.queue_packets_occupancy == 0 &&
+			qstat.queue_bytes_occupancy == 0 &&
+			qstat.total_packets_accepted == 0 &&
+			qstat.total_packets_dropped == 0 &&
+			qstat.total_packets_red_dropped == 0 &&
+			qstat.total_bytes_accepted == 0 &&
+			qstat.total_bytes_dropped == 0, "Some field of q1 stats is not 0\n");
+
+	memset(&qstat, 0, sizeof(qstat));
+	QOS_ASSERT(pp_qos_queue_stat_get(qdev, q2, &qstat) == 0, "Could not get queue statistics\n");
+	QOS_ASSERT(
+			qstat.reset == 0 &&
+			qstat.queue_packets_occupancy == 0 &&
+			qstat.queue_bytes_occupancy == 0 &&
+			qstat.total_packets_accepted == 0 &&
+			qstat.total_packets_dropped == 0 &&
+			qstat.total_packets_red_dropped == 0 &&
+			qstat.total_bytes_accepted == 0 &&
+			qstat.total_bytes_dropped == 0, "Some field of q2 stats is not 0\n");
+
+	memset(&pstat, 0, sizeof(pstat));
+	QOS_ASSERT(pp_qos_port_stat_get(qdev, p, &pstat) == 0, "Could not get port statistics\n");
+	QOS_ASSERT(
+			pstat.reset == 0 &&
+			pstat.total_green_bytes == 0 &&
+			pstat.total_yellow_bytes == 0, "Some field of p stats is not 0\n");
+
+	create_push_desc_cmd(qdev, 0, 128, 1, 0x600000);
+	create_push_desc_cmd(qdev, 0, 256, 2, 0x600000);
+	create_push_desc_cmd(qdev, 1, 100, 1, 0x600000);
+	create_push_desc_cmd(qdev, 1, 200, 2, 0x600000);
+	update_cmd_id(&qdev->drvcmds);
+	transmit_cmds(qdev);
+
+	memset(&qstat, 0, sizeof(qstat));
+	QOS_ASSERT(pp_qos_queue_stat_get(qdev, q1, &qstat) == 0, "Could not get queue statistics\n");
+	QOS_ASSERT(
+			qstat.reset == 0 &&
+			qstat.queue_packets_occupancy == 2 &&
+			qstat.queue_bytes_occupancy == 384 &&
+			qstat.total_packets_accepted == 2 &&
+			qstat.total_packets_dropped == 0 &&
+			qstat.total_packets_red_dropped == 0 &&
+			qstat.total_bytes_accepted == 384 &&
+			qstat.total_bytes_dropped == 0, "Some fields of q1 stats are not expected\n");
+
+	memset(&qstat, 0, sizeof(qstat));
+	qstat.reset = 1;
+	QOS_ASSERT(pp_qos_queue_stat_get(qdev, q2, &qstat) == 0, "Could not get queue statistics\n");
+	QOS_ASSERT(
+			qstat.reset == 1 &&
+			qstat.queue_packets_occupancy == 2 &&
+			qstat.queue_bytes_occupancy == 300 &&
+			qstat.total_packets_accepted == 2 &&
+			qstat.total_packets_dropped == 0 &&
+			qstat.total_packets_red_dropped == 0 &&
+			qstat.total_bytes_accepted == 300 &&
+			qstat.total_bytes_dropped == 0, "Some fields of q2 are not expected\n");
+
+	memset(&pstat, 0, sizeof(pstat));
+	QOS_ASSERT(pp_qos_port_stat_get(qdev, p, &pstat) == 0, "Could not get port statistics\n");
+	QOS_ASSERT(
+			pstat.reset == 0 &&
+			pstat.total_green_bytes == 228 &&
+			pstat.total_yellow_bytes == 456, "Some fields of p stats are not expected\n");
+
+	create_push_desc_cmd(qdev, 0, 100, 1, 0x600000);
+	create_push_desc_cmd(qdev, 1, 300, 1, 0x600000);
+
+	memset(&qstat, 0, sizeof(qstat));
+	QOS_ASSERT(pp_qos_queue_stat_get(qdev, q1, &qstat) == 0, "Could not get queue statistics\n");
+	QOS_ASSERT(
+			qstat.reset == 0 &&
+			qstat.queue_packets_occupancy == 3 &&
+			qstat.queue_bytes_occupancy == 484 &&
+			qstat.total_packets_accepted == 3 &&
+			qstat.total_packets_dropped == 0 &&
+			qstat.total_packets_red_dropped == 0 &&
+			qstat.total_bytes_accepted == 484 &&
+			qstat.total_bytes_dropped == 0, "Some field of q1 stats are not expected\n");
+
+	QOS_ASSERT(pp_qos_queue_stat_get(qdev, q2, &qstat) == 0, "Could not get queue statistics\n");
+	QOS_ASSERT(
+			qstat.reset == 0 &&
+			qstat.queue_packets_occupancy == 3 &&
+			qstat.queue_bytes_occupancy == 600 &&
+			qstat.total_packets_accepted == 1 &&
+			qstat.total_packets_dropped == 0 &&
+			qstat.total_packets_red_dropped == 0 &&
+			qstat.total_bytes_accepted == 300 &&
+			qstat.total_bytes_dropped == 0, "Some field of q2 stats is not 0\n");
+
+	memset(&pstat, 0, sizeof(pstat));
+	pstat.reset = 1;
+	QOS_ASSERT(pp_qos_port_stat_get(qdev, p, &pstat) == 0, "Could not get port statistics\n");
+	QOS_ASSERT(
+			pstat.reset == 1 &&
+			pstat.total_green_bytes == 628 &&
+			pstat.total_yellow_bytes == 456, "Some fields of p stats are not expected\n");
+
+	
+	create_push_desc_cmd(qdev, 0, 100, 2, 0x600000);
+	memset(&pstat, 0, sizeof(pstat));
+	QOS_ASSERT(pp_qos_port_stat_get(qdev, p, &pstat) == 0, "Could not get port statistics\n");
+	QOS_ASSERT(
+			pstat.reset == 0 &&
+			pstat.total_green_bytes == 0 &&
+			pstat.total_yellow_bytes == 100, "Some fields of p stats are not expected\n");
+
+	QOS_LOG_INFO("statistics test completed successfully :)\n");
+
+}
+#endif
+
+#if 0
+void falcon_test(void)
+{
+	struct pp_qos_dev *qdev;
+	unsigned int p;
+	unsigned int s;
+	unsigned int q;
+	struct pp_qos_queue_info qinfo;
+	struct pp_qos_sched_info sinfo;
+	struct pp_qos_port_info pinfo;
+	int rc;
+
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	QOS_ASSERT(pp_qos_port_allocate(qdev, ALLOC_PORT_ID, &p) == 0, "Could not allocate port\n");
+	QOS_ASSERT(pp_qos_sched_allocate(qdev, &s) == 0, "Could not allocate sched\n");
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q) == 0, "Could not allocate queue 0\n");
+	rc = pp_qos_port_info_get(qdev, p, &pinfo);
+	rc = pp_qos_sched_info_get(qdev, s, &sinfo);
+	rc = pp_qos_queue_info_get(qdev, q, &qinfo);
+}
+#endif
+
+#if 0
+void falcon_test(void)
+{
+	struct pp_qos_dev *qdev;
+	unsigned int p7;
+	unsigned int q0;
+	unsigned int q1;
+	struct pp_qos_port_conf confp;
+	struct pp_qos_queue_conf confq;
+
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	pp_qos_port_conf_set_default(&confp); 
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_size = 1;
+
+	/* add port 7 */
+	QOS_ASSERT(pp_qos_port_allocate(qdev, 7, &p7) == 0, "Could not allocate port 7\n");
+	confp.credit = 8;
+	confp.ring_address = (void *)RING_ADDRESS_7; 
+	QOS_ASSERT(pp_qos_port_set(qdev, p7, &confp) == 0, "Could not set port 7\n");
+	QOS_ASSERT(pp_qos_port_suspend(qdev, p7) == 0, "Could not suspend port 7\n");
+
+	pp_qos_queue_conf_set_default(&confq);
+	confq.queue_child_prop.parent = p7;
+	confq.queue_wred_min_guaranteed = 0;
+	confq.queue_wred_max_allowed = 25;
+	confq.wred_enable = 1;
+	confq.wred_fixed_drop_prob_enable = 1;
+
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q0) == 0, "Could not allocate queue 0\n");
+	confq.queue_wred_min_avg_green = 5;
+	confq.queue_wred_max_avg_green = 15;
+	confq.queue_wred_fixed_drop_prob_green = 20;
+	confq.queue_wred_min_avg_yellow = 10;
+	confq.queue_wred_max_avg_yellow = 20;
+	confq.queue_wred_fixed_drop_prob_yellow = 80;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q0, &confq) == 0, "Could not set queue 0\n");
+
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q1) == 0, "Could not allocate queue 1\n");
+	confq.queue_wred_min_avg_green = 12;
+	confq.queue_wred_max_avg_green = 22;
+	confq.queue_wred_fixed_drop_prob_green = 0;
+	confq.queue_wred_min_avg_yellow = 15;
+	confq.queue_wred_max_avg_yellow = 25;
+	confq.queue_wred_fixed_drop_prob_yellow = 100;
+	QOS_ASSERT(pp_qos_queue_set(qdev, q1, &confq) == 0, "Could not set queue 1\n");
+
+	QOS_LOG_INFO("WRED configuration completed\n");
+}
+#endif
+
+void reposition_test(void) 
+{
+	unsigned int s[5];
+	unsigned int q;
+	unsigned int p1;
+	unsigned int p7;
+	int tmp;
+	unsigned int i;
+	struct pp_qos_port_conf confp;
+	struct pp_qos_sched_conf confs;
+	struct pp_qos_queue_conf confq;
+	struct pp_qos_dev *qdev;
+	struct pp_qos_node_info info;
+
+	QOS_LOG_INFO("reposition test started\n");
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	tmp = pp_qos_port_allocate(qdev, 1, &p1);
+	QOS_ASSERT(tmp == 0, "could not allocate qos port\n");
+
+	tmp = pp_qos_port_allocate(qdev, 7, &p7);
+	QOS_ASSERT(tmp == 0, "could not allocate qos port\n");
+
+	pp_qos_port_conf_set_default(&confp);
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_size = 1;
+
+	confp.ring_address = (void *)950000;
+	QOS_ASSERT(pp_qos_port_set(qdev, p1, &confp) == 0, "Could not set port\n");
+
+	confp.ring_address = (void *)950600;
+	QOS_ASSERT(pp_qos_port_set(qdev, p7, &confp) == 0, "Could not set port\n");
+
+	pp_qos_sched_conf_set_default(&confs);
+	for (i = 0; i < 5; ++i) {
+		QOS_ASSERT(pp_qos_sched_allocate(qdev, &s[i]) == 0, "Could not allocate sched\n");
+		if (i == 0)
+			confs.sched_child_prop.parent = p1;
+		else
+			confs.sched_child_prop.parent = s[i - 1];
+		QOS_ASSERT(pp_qos_sched_set(qdev, s[i], &confs) == 0, "Could not set sched\n");
+	}
+	QOS_ASSERT(pp_qos_queue_allocate(qdev, &q) == 0, "Could not allocate queue\n");
+	pp_qos_queue_conf_set_default(&confq);
+	confq.queue_child_prop.parent = s[4];
+	QOS_ASSERT(pp_qos_queue_set(qdev, q, &confq) == 0, "Could not set queue\n");
+
+	confs.sched_child_prop.parent = p1;
+	QOS_ASSERT(pp_qos_sched_set(qdev, s[3], &confs) == 0, "Could not set sched\n");
+
+	confs.sched_child_prop.parent = p7;
+	QOS_ASSERT(pp_qos_sched_set(qdev, s[4], &confs) == 0, "Could not set sched\n");
+	check_consistency_with_resources(qdev);
+
+	QOS_ASSERT(pp_qos_get_node_info(qdev, p1, &info) == 0, "Could not get node info\n");
+	QOS_ASSERT(pp_qos_get_node_info(qdev, p7, &info) == 0, "Could not get node info\n");
+	QOS_ASSERT(pp_qos_get_node_info(qdev, q, &info) == 0, "Could not get node info\n");
+	for (i = 0; i < 5; ++i)
+		QOS_ASSERT(pp_qos_get_node_info(qdev, s[i], &info) == 0, "Could not get node info\n");
+
+	QOS_LOG_INFO("reposition test completed successfully :)\n");
+}
+
+void info_test(void)
+{
+	struct pp_qos_queue_conf confq;
+	struct pp_qos_port_conf confp;
+	struct pp_qos_dev *qdev;
+	unsigned int p1;
+	unsigned int q[100];
+	unsigned int i;
+	struct pp_qos_node_info info;
+
+	QOS_LOG_INFO("info test started\n");
+		
+	qdev = test_open_and_init_instance(0);
+	if (!qdev)
+		return;
+
+	/* Allocate port 1  */ 
+	pp_qos_port_conf_set_default(&confp); 
+	confp.port_parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	confp.ring_address = (void *)1;
+	confp.ring_size = 1;
+	pp_qos_port_allocate(qdev, 1, &p1);
+	QOS_ASSERT(pp_qos_port_set(qdev, p1, &confp) == 0, "Could not set port\n");
+	check_consistency_with_resources(qdev);
+	QOS_ASSERT(pp_qos_get_node_info(qdev, p1, &info) == 0, "Could not get node info\n");
+
+	pp_qos_queue_conf_set_default(&confq); 
+	confq.queue_child_prop.parent = p1;
+	//confq.common_prop.bandwidth_limit = 77;
+	/* Allocate 8 queues */
+	for (i = 0; i < 8; ++ i) {
+		pp_qos_queue_allocate(qdev, &q[i]);
+		confq.queue_wred_max_allowed = i;
+		pp_qos_queue_set(qdev, q[i], &confq);
+	}
+	QOS_ASSERT(pp_qos_get_node_info(qdev, p1, &info) == 0, "Could not get node info\n");
+	QOS_ASSERT(info.type == PPV4_QOS_NODE_TYPE_PORT &&
+		   info.children[0].phy == 128 &&
+		   info.children[1].phy == 129 &&
+		   info.children[2].phy == 130 &&
+		   info.children[3].phy == 131 &&
+		   info.children[4].phy == 132 &&
+		   info.children[5].phy == 133 &&
+		   info.children[6].phy == 134 &&
+		   info.children[7].phy == 135 &&
+		   info.children[0].id == 1 &&
+		   info.children[1].id == 2 &&
+		   info.children[2].id == 3 &&
+		   info.children[3].id == 4 &&
+		   info.children[4].id == 5 &&
+		   info.children[5].id == 6 &&
+		   info.children[6].id == 7 &&
+		   info.children[7].id == 8 &&
+		   info.is_suspended == 0 &&
+		   info.is_internal == 0 &&
+		   info.bw_limit == 0 &&
+		   (info.preds[0].phy == info.preds[0].id &&  
+		   info.preds[1].phy == info.preds[1].id && 
+		   info.preds[2].phy == info.preds[2].id && 
+		   info.preds[3].phy == info.preds[3].id && 
+		   info.preds[4].phy == info.preds[4].id && 
+		   info.preds[5].phy == info.preds[5].id && 
+		   info.port == info.queue_physical_id),
+		   "Unexpected value from node get info\n");
+
+	QOS_ASSERT(pp_qos_get_node_info(qdev, q[7], &info) == 0, "Could not get node info\n");
+	QOS_ASSERT(info.type == PPV4_QOS_NODE_TYPE_QUEUE &&
+		   info.children[0].phy == PPV4_QOS_INVALID &&
+		   info.children[1].phy == PPV4_QOS_INVALID &&
+		   info.children[2].phy == PPV4_QOS_INVALID &&
+		   info.children[3].phy == PPV4_QOS_INVALID &&
+		   info.children[4].phy == PPV4_QOS_INVALID &&
+		   info.children[5].phy == PPV4_QOS_INVALID &&
+		   info.children[6].phy == PPV4_QOS_INVALID &&
+		   info.children[7].phy == PPV4_QOS_INVALID &&
+		   info.children[0].id == PPV4_QOS_INVALID &&
+		   info.children[1].id == PPV4_QOS_INVALID &&
+		   info.children[2].id == PPV4_QOS_INVALID &&
+		   info.children[3].id == PPV4_QOS_INVALID &&
+		   info.children[4].id == PPV4_QOS_INVALID &&
+		   info.children[5].id == PPV4_QOS_INVALID &&
+		   info.children[6].id == PPV4_QOS_INVALID &&
+		   info.children[7].id == PPV4_QOS_INVALID &&
+		   info.is_suspended == 0 &&
+		   info.is_internal == 0 &&
+		   info.bw_limit == 0 &&
+		   info.preds[0].phy == 1 && 
+		    info.preds[0].id == 0 &&  
+		   info.preds[1].phy == info.preds[1].id && 
+		   info.preds[2].phy == info.preds[2].id && 
+		   info.preds[3].phy == info.preds[3].id && 
+		   info.preds[4].phy == info.preds[4].id && 
+		   info.preds[5].phy == info.preds[5].id && 
+		   info.port == 1 &&
+		   info.queue_physical_id == 7,
+		   "Unexpected value from node get info\n");
+
+	/* Allocate 64 more queues */
+	for (i = 8; i < 100; ++i) {
+		pp_qos_queue_allocate(qdev, &q[i]);
+		pp_qos_queue_set(qdev, q[i], &confq);
+	}
+	QOS_ASSERT(pp_qos_get_node_info(qdev, q[7], &info) == 0, "Could not get node info\n");
+	QOS_ASSERT(info.type == PPV4_QOS_NODE_TYPE_QUEUE &&
+		   info.children[0].phy == PPV4_QOS_INVALID &&
+		   info.children[1].phy == PPV4_QOS_INVALID &&
+		   info.children[2].phy == PPV4_QOS_INVALID &&
+		   info.children[3].phy == PPV4_QOS_INVALID &&
+		   info.children[4].phy == PPV4_QOS_INVALID &&
+		   info.children[5].phy == PPV4_QOS_INVALID &&
+		   info.children[6].phy == PPV4_QOS_INVALID &&
+		   info.children[7].phy == PPV4_QOS_INVALID &&
+		   info.children[0].id == PPV4_QOS_INVALID &&
+		   info.children[1].id == PPV4_QOS_INVALID &&
+		   info.children[2].id == PPV4_QOS_INVALID &&
+		   info.children[3].id == PPV4_QOS_INVALID &&
+		   info.children[4].id == PPV4_QOS_INVALID &&
+		   info.children[5].id == PPV4_QOS_INVALID &&
+		   info.children[6].id == PPV4_QOS_INVALID &&
+		   info.children[7].id == PPV4_QOS_INVALID &&
+		   info.is_suspended == 0 &&
+		   info.is_internal == 0 &&
+		   info.bw_limit == 0 &&
+		   info.preds[0].phy == 135 && 
+		   info.preds[0].id == 66 && 
+		   info.preds[1].phy == 1 && 
+		   info.preds[1].id == 0 &&  
+		   info.preds[2].phy == info.preds[2].id && 
+		   info.preds[3].phy == info.preds[3].id && 
+		   info.preds[4].phy == info.preds[4].id && 
+		   info.preds[5].phy == info.preds[5].id && 
+		   info.port == 1 &&
+		   info.queue_physical_id == 7,
+		   "Unexpected value from node get info\n");
+
+	QOS_ASSERT(pp_qos_get_node_info(qdev, 66, &info) == 0, "Could not get node info\n");
+	QOS_ASSERT(info.type == PPV4_QOS_NODE_TYPE_SCHED &&
+		   info.children[0].phy == 192 &&
+		   info.children[1].phy == 193 &&
+		   info.children[2].phy == 194 &&
+		   info.children[3].phy == 195 &&
+		   info.children[4].phy == 196 &&
+		   info.children[5].phy == 197 &&
+		   info.children[6].phy == 198 &&
+		   info.children[7].phy == 199 &&
+		   info.children[0].id == 8 &&
+		   info.children[1].id == 65 &&
+		   info.children[2].id == 67 &&
+		   info.children[3].id == 68 &&
+		   info.children[4].id == 69 &&
+		   info.children[5].id == 70 &&
+		   info.children[6].id == 71 &&
+		   info.children[7].id == 72 &&
+		   info.is_suspended == 0 &&
+		   info.is_internal == 1 &&
+		   info.bw_limit == 0 &&
+		   info.preds[0].phy == 1 && 
+		   info.preds[0].id == 0 &&  
+		   info.preds[1].phy == info.preds[1].id && 
+		   info.preds[2].phy == info.preds[2].id && 
+		   info.preds[3].phy == info.preds[3].id && 
+		   info.preds[4].phy == info.preds[4].id && 
+		   info.preds[5].phy == info.preds[5].id && 
+		   info.port == PPV4_QOS_INVALID &&
+		   info.queue_physical_id == PPV4_QOS_INVALID,
+		   "Unexpected value from node get info\n");
+	check_consistency_with_resources(qdev);
+	QOS_LOG_INFO("info test completed successfully :)\n");
+}
+
+void load_fw_test(void)
+{
+	test_open_and_init_instance(0);
+}
+
+#endif
diff --git a/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_uc_defs.h b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_uc_defs.h
new file mode 100644
index 0000000000000000000000000000000000000000..4445817eccf5a1eac0bab5123a89e220338b08d4
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_uc_defs.h
@@ -0,0 +1,516 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+/*
+ * uc_host_defs.h
+ *
+ *  Created on: Dec 17, 2017
+ *      Author: obakshe
+ */
+
+#ifndef SRC_UC_HOST_DEFS_H_
+#define SRC_UC_HOST_DEFS_H_
+
+// UC version
+#define UC_VERSION_MAJOR	(1)
+#define UC_VERSION_MINOR	(0)
+#define UC_VERSION_BUILD	(0)
+
+/**************************************************************************
+ *! @enum	UC_STATUS
+ **************************************************************************
+ *
+ * @brief UC general status enum
+ *
+ **************************************************************************/
+enum uc_status {
+	//!< Status OK
+	UC_STATUS_OK,
+
+	//!< General failure
+	UC_STATUS_GENERAL_FAILURE,
+
+	//!< Invalid user input
+	UC_STATUS_INVALID_INPUT,
+};
+
+/**************************************************************************
+ *! @enum	UC_LOGGER_LEVEL
+ **************************************************************************
+ *
+ * @brief UC Logger level enum
+ *
+ **************************************************************************/
+enum uc_logger_level {
+	//!< FATAL error occurred. SW will probably fail to proceed
+	UC_LOGGER_LEVEL_FATAL,
+
+	//!< General ERROR occurred.
+	UC_LOGGER_LEVEL_ERROR,
+
+	//!< WARNING
+	UC_LOGGER_LEVEL_WARNING,
+
+	//!< Information print to the user
+	UC_LOGGER_LEVEL_INFO,
+
+	//!< Debug purposes level
+	UC_LOGGER_LEVEL_DEBUG,
+};
+
+/**************************************************************************
+ *! @enum	UC_LOGGER_MODE
+ **************************************************************************
+ *
+ * @brief UC Logger operation mode
+ *
+ **************************************************************************/
+enum uc_logger_mode {
+	//!< Logger is disabled
+	UC_LOGGER_MODE_NONE,
+
+	//!< Messages are written to the standard output
+	UC_LOGGER_MODE_STDOUT,
+
+	//!< Local file. N/A
+//	UC_LOGGER_MODE_LOCAL_FILE,
+
+	//!< Messages are written to the host allocated memory
+	UC_LOGGER_MODE_WRITE_HOST_MEM,
+};
+
+/**************************************************************************
+ *! \enum	TSCD_NODE_CONF
+ **************************************************************************
+ *
+ * \brief TSCD node configuration valid bits. Used in modify existing node
+ *
+ **************************************************************************/
+enum tscd_node_conf {
+	//!< None
+	TSCD_NODE_CONF_NONE					=	0x0000,
+
+	//!< Suspend/Resume node
+	TSCD_NODE_CONF_SUSPEND_RESUME		=	0x0001,
+
+	//!< first child (Not relevant for queue)
+	TSCD_NODE_CONF_FIRST_CHILD			=	0x0002,
+
+	//!< last child (Not relevant for queue)
+	TSCD_NODE_CONF_LAST_CHILD			=	0x0004,
+
+	//!< 0 - BW Limit disabled >0 - define BW
+	TSCD_NODE_CONF_BW_LIMIT				=	0x0008,
+
+	//!< Best Effort enable
+	TSCD_NODE_CONF_BEST_EFFORT_ENABLE	=	0x0010,
+
+	//!< First Weighted-Round-Robin node (Not relevant for queue)
+	TSCD_NODE_CONF_FIRST_WRR_NODE		=	0x0020,
+
+	//!< Update predecessor 0 (Not relevant for port)
+	TSCD_NODE_CONF_PREDECESSOR_0		=	0x0040,
+
+	//!< Update predecessor 1 (Not relevant for port)
+	TSCD_NODE_CONF_PREDECESSOR_1		=	0x0080,
+
+	//!< Update predecessor 2 (Not relevant for port)
+	TSCD_NODE_CONF_PREDECESSOR_2		=	0x0100,
+
+	//!< Update predecessor 3 (Not relevant for port)
+	TSCD_NODE_CONF_PREDECESSOR_3		=	0x0200,
+
+	//!< Update predecessor 4 (Not relevant for port)
+	TSCD_NODE_CONF_PREDECESSOR_4		=	0x0400,
+
+	//!< Update predecessor 5 (Not relevant for port)
+	TSCD_NODE_CONF_PREDECESSOR_5		=	0x0800,
+
+	//!< Shared BW limit group (0: no shared BW limit, 1-511: group ID)
+	TSCD_NODE_CONF_SHARED_BWL_GROUP		=	0x1000,
+
+	//!< All flags are set
+	TSCD_NODE_CONF_ALL					=	0xFFFF
+};
+
+/**************************************************************************
+ *! \enum	WRED_QUEUE_CONF
+ **************************************************************************
+ *
+ * \brief WRED queue configuration valid bits. Used in modify existing queue
+ *
+ **************************************************************************/
+enum wred_queue_conf {
+	//!< None
+	WRED_QUEUE_CONF_NONE				=	0x0000,
+
+	//!< Q is active
+	WRED_QUEUE_CONF_ACTIVE_Q			=	0x0001,
+
+	//!< Disable flags valid
+	WRED_QUEUE_CONF_DISABLE				=	0x0002,
+
+	//!< Use fixed green drop probability
+	WRED_QUEUE_CONF_FIXED_GREEN_DROP_P	=	0x0004,
+
+	//!< Use fixed yellow drop probability
+	WRED_QUEUE_CONF_FIXED_YELLOW_DROP_P	=	0x0008,
+
+	//!< Min average yellow
+	WRED_QUEUE_CONF_MIN_AVG_YELLOW		=	0x0010,
+
+	//!< Max average yellow
+	WRED_QUEUE_CONF_MAX_AVG_YELLOW		=	0x0020,
+
+	//!< Slope yellow
+	WRED_QUEUE_CONF_SLOPE_YELLOW		=	0x0040,
+
+	//!< INTERNAL CONFIGURATION. SHOULD NOT BE SET BY HOST
+	WRED_QUEUE_CONF_SHIFT_AVG_YELLOW	=	0x0080,
+
+	//!< Min average green
+	WRED_QUEUE_CONF_MIN_AVG_GREEN		=	0x0100,
+
+	//!< Max average green
+	WRED_QUEUE_CONF_MAX_AVG_GREEN		=	0x0200,
+
+	//!< Slope green
+	WRED_QUEUE_CONF_SLOPE_GREEN			=	0x0400,
+
+	//!< INTERNAL CONFIGURATION. SHOULD NOT BE SET BY HOST
+	WRED_QUEUE_CONF_SHIFT_AVG_GREEN		=	0x0800,
+
+	//!< Min guaranteed
+	WRED_QUEUE_CONF_MIN_GUARANTEED		=	0x1000,
+
+	//!< max allowed
+	WRED_QUEUE_CONF_MAX_ALLOWED			=	0x2000,
+
+	//!< All flags are set
+	WRED_QUEUE_CONF_ALL					=	0xFFFF
+};
+
+/**************************************************************************
+ *! \enum	PORT_CONF
+ **************************************************************************
+ *
+ * \brief Port configuration valid bits. Used in modify existing port
+ *
+ **************************************************************************/
+enum port_conf {
+	//!< None
+	PORT_CONF_NONE					=	0x0000,
+
+	//!< Ring Size
+	PORT_CONF_RING_SIZE				=	0x0001,
+
+	//!< Ring address high
+	PORT_CONF_RING_ADDRESS_HIGH		=	0x0002,
+
+	//!< Ring address low
+	PORT_CONF_RING_ADDRESS_LOW		=	0x0004,
+
+	//!< All flags are set
+	PORT_CONF_ALL					=	0xFFFF
+};
+
+/**************************************************************************
+ *! \struct	port_stats_s
+ **************************************************************************
+ *
+ * \brief Port stats
+ *
+ **************************************************************************/
+struct port_stats_s {
+	u32	total_green_bytes;
+	u32	total_yellow_bytes;
+
+	// Following stats can not be reset
+	u32	debug_back_pressure_status;
+};
+
+/**************************************************************************
+ *! \struct	hw_node_info_s
+ **************************************************************************
+ *
+ * \brief HW node info
+ *
+ **************************************************************************/
+struct hw_node_info_s {
+	u32	first_child;
+	u32	last_child;
+	u32	is_suspended;
+	u32	bw_limit;
+	u32	predecessor0;
+	u32	predecessor1;
+	u32	predecessor2;
+	u32	predecessor3;
+	u32	predecessor4;
+	u32	predecessor5;
+	u32	queue_physical_id;
+	u32	queue_port;
+};
+
+/**************************************************************************
+ *! \enum	PORT_STATS_CLEAR_FLAGS
+ **************************************************************************
+ *
+ * \brief	port stats clear flags.
+ *			Used in get port stats command to set which stats
+ *			will be reset after read
+ *
+ **************************************************************************/
+enum port_stats_clear_flags {
+	//!< None
+	PORT_STATS_CLEAR_NONE					=	0x0000,
+
+	//!< Clear port total green bytes stats
+	PORT_STATS_CLEAR_TOTAL_GREEN_BYTES		=	0x0001,
+
+	//!< Clear port total yellow bytes stats
+	PORT_STATS_CLEAR_TOTAL_YELLOW_BYTES		=	0x0002,
+
+	//!< All above stats will be cleared
+	PORT_STATS_CLEAR_ALL					=	0xFFFF,
+};
+
+/**************************************************************************
+ *! \struct	queue_stats_s
+ **************************************************************************
+ *
+ * \brief Queue stats
+ *
+ **************************************************************************/
+struct queue_stats_s {
+	u32	queue_size_bytes;
+	u32	queue_average_size_bytes;
+	u32	queue_size_entries;
+	u32	drop_p_yellow;
+	u32	drop_p_green;
+	u32	total_bytes_added_low;
+	u32	total_bytes_added_high;
+	u32	total_accepts;
+	u32	total_drops;
+	u32	total_dropped_bytes_low;
+	u32	total_dropped_bytes_high;
+	u32	total_red_dropped;
+
+	// Following stats can not be reset
+	u32	qmgr_num_queue_entries;
+	u32	qmgr_null_pop_queue_counter;
+	u32	qmgr_empty_pop_queue_counter;
+	u32	qmgr_null_push_queue_counter;
+};
+
+/**************************************************************************
+ *! \enum	QUEUE_STATS_CLEAR_FLAGS
+ **************************************************************************
+ *
+ * \brief	queue stats clear flags.
+ *			Used in get queue stats command to set which stats
+ *			will be reset after read
+ *
+ **************************************************************************/
+enum queue_stats_clear_flags {
+	//!< None
+	QUEUE_STATS_CLEAR_NONE					=	0x0000,
+
+	//!< Clear queue size bytes stats
+	QUEUE_STATS_CLEAR_Q_SIZE_BYTES			=	0x0001,
+
+	//!< Clear queue average size bytes stats
+	QUEUE_STATS_CLEAR_Q_AVG_SIZE_BYTES		=	0x0002,
+
+	//!< Clear queue size entries stats
+	QUEUE_STATS_CLEAR_Q_SIZE_ENTRIES		=	0x0004,
+
+	//!< Clear drop probability yellow stats
+	QUEUE_STATS_CLEAR_DROP_P_YELLOW			=	0x0008,
+
+	//!< Clear drop probability green stats
+	QUEUE_STATS_CLEAR_DROP_P_GREEN			=	0x0010,
+
+	//!< Clear total bytes added stats
+	QUEUE_STATS_CLEAR_TOTAL_BYTES_ADDED		=	0x0020,
+
+	//!< Clear total accepts stats
+	QUEUE_STATS_CLEAR_TOTAL_ACCEPTS			=	0x0040,
+
+	//!< Clear total drops stats
+	QUEUE_STATS_CLEAR_TOTAL_DROPS			=	0x0080,
+
+	//!< Clear total dropped bytes stats
+	QUEUE_STATS_CLEAR_TOTAL_DROPPED_BYTES	=	0x0100,
+
+	//!< Clear total RED drops stats
+	QUEUE_STATS_CLEAR_TOTAL_RED_DROPS		=	0x0200,
+
+	//!< All above stats will be cleared
+	QUEUE_STATS_CLEAR_ALL					=	0xFFFF,
+};
+
+/**************************************************************************
+ *! \struct	system_stats_s
+ **************************************************************************
+ *
+ * \brief system stats
+ *
+ **************************************************************************/
+struct system_stats_s {
+	u32	qmgr_cache_free_pages_counter;
+	u32	qmgr_sm_current_state;
+	u32	qmgr_cmd_machine_busy;
+	u32	qmgr_cmd_machine_pop_busy;
+	u32	qmgr_null_pop_counter;
+	u32	qmgr_empty_pop_counter;
+	u32	qmgr_null_push_counter;
+	u32	qmgr_ddr_stop_push_low_threshold;
+	u32	qmgr_fifo_error_register;
+	u32	qmgr_ocp_error_register;
+	u32	qmgr_cmd_machine_sm_current_state_0;
+	u32	qmgr_cmd_machine_sm_current_state_1;
+	u32	qmgr_cmd_machine_sm_current_state_2;
+	u32	qmgr_cmd_machine_sm_current_state_3;
+	u32	qmgr_cmd_machine_sm_current_state_4;
+	u32	qmgr_cmd_machine_sm_current_state_5;
+	u32	qmgr_cmd_machine_sm_current_state_6;
+	u32	qmgr_cmd_machine_sm_current_state_7;
+	u32	qmgr_cmd_machine_sm_current_state_8;
+	u32	qmgr_cmd_machine_sm_current_state_9;
+	u32	qmgr_cmd_machine_sm_current_state_10;
+	u32	qmgr_cmd_machine_sm_current_state_11;
+	u32	qmgr_cmd_machine_sm_current_state_12;
+	u32	qmgr_cmd_machine_sm_current_state_13;
+	u32	qmgr_cmd_machine_sm_current_state_14;
+	u32	qmgr_cmd_machine_sm_current_state_15;
+	u32	qmgr_cmd_machine_queue_0;
+	u32	qmgr_cmd_machine_queue_1;
+	u32	qmgr_cmd_machine_queue_2;
+	u32	qmgr_cmd_machine_queue_3;
+	u32	qmgr_cmd_machine_queue_4;
+	u32	qmgr_cmd_machine_queue_5;
+	u32	qmgr_cmd_machine_queue_6;
+	u32	qmgr_cmd_machine_queue_7;
+	u32	qmgr_cmd_machine_queue_8;
+	u32	qmgr_cmd_machine_queue_9;
+	u32	qmgr_cmd_machine_queue_10;
+	u32	qmgr_cmd_machine_queue_11;
+	u32	qmgr_cmd_machine_queue_12;
+	u32	qmgr_cmd_machine_queue_13;
+	u32	qmgr_cmd_machine_queue_14;
+	u32	qmgr_cmd_machine_queue_15;
+};
+
+/**************************************************************************
+ *! @enum	UC_QOS_COMMAND
+ **************************************************************************
+ *
+ * @brief UC QOS command enum. Must be synced with the Host definition
+ *
+ **************************************************************************/
+enum uc_qos_command {
+	UC_QOS_COMMAND_GET_FW_VERSION,
+	UC_QOS_COMMAND_MULTIPLE_COMMANDS,
+	UC_QOS_COMMAND_INIT_UC_LOGGER,
+	UC_QOS_COMMAND_INIT_QOS,
+	UC_QOS_COMMAND_ADD_PORT,
+	UC_QOS_COMMAND_REMOVE_PORT,
+	UC_QOS_COMMAND_ADD_SCHEDULER,
+	UC_QOS_COMMAND_REMOVE_SCHEDULER,
+	UC_QOS_COMMAND_ADD_QUEUE,
+	UC_QOS_COMMAND_REMOVE_QUEUE,
+	UC_QOS_COMMAND_FLUSH_QUEUE,
+	UC_QOS_COMMAND_SET_PORT,
+	UC_QOS_COMMAND_SET_SCHEDULER,
+	UC_QOS_COMMAND_SET_QUEUE,
+	UC_QOS_COMMAND_MOVE_SCHEDULER,
+	UC_QOS_COMMAND_MOVE_QUEUE,
+	UC_QOS_COMMAND_GET_PORT_STATS,
+	UC_QOS_COMMAND_GET_QUEUE_STATS,
+	UC_QOS_COMMAND_GET_SYSTEM_STATS,
+	UC_QOS_COMMAND_ADD_SHARED_BW_LIMIT_GROUP,
+	UC_QOS_COMMAND_REMOVE_SHARED_BW_LIMIT_GROUP,
+	UC_QOS_COMMAND_SET_SHARED_BW_LIMIT_GROUP,
+	UC_QOS_COMMAND_GET_NODE_INFO,
+	UC_QOS_COMMAND_DEBUG_READ_NODE,
+	UC_QOS_COMMAND_DEBUG_PUSH_DESC,
+	UC_QOS_COMMAND_DEBUG_ADD_CREDIT_TO_PORT,
+};
+
+/**************************************************************************
+ *! @struct	uc_qos_cmd_s
+ **************************************************************************
+ *
+ * @brief UC commands.
+ * This structure defines the Host <-->UC interface
+ *
+ **************************************************************************/
+struct uc_qos_cmd_s {
+	//!< Type of command (UC_QOS_COMMAND)
+	u32			type;
+
+	//!< Commands flags
+	u32			flags;
+#define	UC_CMD_FLAG_IMMEDIATE				BIT(0)
+#define	UC_CMD_FLAG_BATCH_FIRST				BIT(1)
+#define	UC_CMD_FLAG_BATCH_LAST				BIT(2)
+#define	UC_CMD_FLAG_MULTIPLE_COMMAND_LAST	BIT(3)
+#define	UC_CMD_FLAG_UC_DONE					BIT(4)
+#define	UC_CMD_FLAG_UC_ERROR				BIT(5)
+
+	//!< Number of 32bit parameters available for this command.
+	// must be synced between the host and uc!
+	u32			num_params;
+
+	u32			param0;
+	u32			param1;
+	u32			param2;
+	u32			param3;
+	u32			param4;
+	u32			param5;
+	u32			param6;
+	u32			param7;
+	u32			param8;
+	u32			param9;
+	u32			param10;
+	u32			param11;
+	u32			param12;
+	u32			param13;
+	u32			param14;
+	u32			param15;
+	u32			param16;
+	u32			param17;
+	u32			param18;
+	u32			param19;
+	u32			param20;
+	u32			param21;
+	u32			param22;
+	u32			param23;
+	u32			param24;
+	u32			param25;
+};
+
+#endif /* SRC_UC_HOST_DEFS_H_ */
diff --git a/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_uc_wrapper.h b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_uc_wrapper.h
new file mode 100644
index 0000000000000000000000000000000000000000..24c375248649fe9960bb82e06edcb0a466b5bdfc
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_uc_wrapper.h
@@ -0,0 +1,34 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+#ifndef PP_QOS_UC_H
+#define PP_QOS_UC_H
+
+typedef uint32_t u32;
+
+#include "pp_qos_uc_defs.h"
+
+#endif
diff --git a/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_utils.c b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_utils.c
new file mode 100644
index 0000000000000000000000000000000000000000..e342db32496891d74c0ca6e69a17086dc27ba96a
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_utils.c
@@ -0,0 +1,2518 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+#include "pp_qos_common.h"
+#include "pp_qos_fw.h"
+#include "pp_qos_utils.h"
+
+//#define VERY_VERBOSE_TESTS
+#ifdef VERY_VERBOSE_TESTS
+
+#define ISSUE_BW_CMD(phy, numinator, denominator) do {  \
+if (denominator)					\
+QOS_LOG("Issue bw change for phy %u: %u : %u\n", phy, numinator, denominator);\
+} while (0)
+
+#define ISSUE_DELETE_NODE(phy) QOS_LOG("Issue node %u delete\n", phy)
+
+#define ISSUE_FLUSH_NODE(phy) QOS_LOG("Issue node %u flush\n", phy)
+
+#else
+#define ISSUE_BW_CMD(phy, numinator, denominator)
+
+#define ISSUE_DELETE_NODE(phy)
+
+#define ISSUE_FLUSH_NODE(phy)
+
+#endif
+
+#define QOS_INVALID_PRIORITY   0xF
+
+/******************************************************************************/
+/*                                 OCTETS                                     */
+/******************************************************************************/
+struct octet_info {
+	struct list_head list;
+	uint8_t usage;
+};
+
+struct pp_octets {
+	unsigned int last_port_octet;
+	struct octet_info info[NUM_OF_OCTETS];
+	struct list_head lists[9];
+};
+
+static unsigned int octet_get_use_count(const struct pp_octets *octets,
+					unsigned int octet)
+{
+	return octets->info[octet].usage;
+}
+
+unsigned int octet_get_with_at_least_free_entries(struct pp_octets *octets,
+						  unsigned int count)
+{
+	unsigned int id;
+	struct list_head *list;
+
+	for (list = octets->lists + 8 - count; list >= octets->lists; --list)  {
+		if (!list_empty(list)) {
+			id = list_entry(list->next, struct octet_info, list) -
+				octets->info;
+			list_del_init(list->next);
+			return id;
+		}
+	}
+
+	return QOS_INVALID_OCTET;
+}
+
+unsigned int  octet_get_least_free_entries(struct pp_octets *octets)
+{
+	return octet_get_with_at_least_free_entries(octets, 1);
+}
+
+static void octet_set_use_count(struct pp_octets *octets,
+				unsigned int octet,
+				unsigned int usage)
+{
+	struct list_head *list;
+
+	QOS_ASSERT(QOS_OCTET_VALID(octet), "Illegal octet %u\n", octet);
+	QOS_ASSERT(usage <= 8, "Illegal usage %u\n", usage);
+	octets->info[octet].usage = usage;
+	if (octet > octets->last_port_octet) {
+		list = octets->lists + usage;
+		list_move_tail(&(octets->info[octet].list), list);
+	}
+}
+
+STATIC_UNLESS_TEST struct pp_octets *octets_init(unsigned int last_port_octet)
+{
+	unsigned int i;
+	struct octet_info *info;
+	struct pp_octets *octets;
+
+	octets = QOS_MALLOC(sizeof(struct pp_octets));
+	if (octets) {
+		for (i = 0; i < 9; ++i)
+			INIT_LIST_HEAD(octets->lists + i);
+
+		info = octets->info;
+		for (i = 0; i < NUM_OF_OCTETS; ++i) {
+			info->usage = 0;
+			if (i > last_port_octet)
+				list_add_tail(&info->list, octets->lists);
+			else
+				INIT_LIST_HEAD(&info->list);
+
+			++info;
+		}
+		octets->last_port_octet = last_port_octet;
+	}
+	return octets;
+}
+
+STATIC_UNLESS_TEST void octets_clean(struct pp_octets *octets)
+{
+	if (octets)
+		QOS_FREE(octets);
+}
+
+#ifdef PP_QOS_TEST
+STATIC_UNLESS_TEST void debug_verify_octet_usage(struct pp_octets *octets,
+						 unsigned int octet,
+						 unsigned int usage)
+{
+	struct list_head *list;
+	struct list_head *pos;
+	unsigned int tmp;
+
+	tmp = octet_get_use_count(octets, octet);
+	QOS_ASSERT(tmp == usage, "Octet %u count is %u and not %u\n", octet,
+		   tmp, usage);
+
+	list = &(octets->info[octet].list);
+	if (octet > octets->last_port_octet) {
+		for (pos = list->next; pos != list; pos = pos->next) {
+			if (pos >= octets->lists && pos <= octets->lists + 8) {
+				tmp = (pos - octets->lists);
+				QOS_ASSERT(tmp == usage,
+					   "Octet is on list %u but should be on %u\n",
+					   tmp, usage);
+			}
+		}
+	} else {
+		QOS_ASSERT(list_empty(list),
+			"Octet %u is on a list though its a port octet\n",
+			octet);
+	}
+}
+#endif
+
+/******************************************************************************/
+/*                        Ids, Rlms and Port phys pools                       */
+/******************************************************************************/
+struct pp_pool {
+	unsigned int capacity;
+	unsigned int top;
+	uint16_t invalid;
+	uint16_t data[1];
+};
+
+static struct pp_pool *pp_pool_init(unsigned int capacity, uint16_t invalid)
+{
+	struct pp_pool *tmp;
+
+	tmp = QOS_MALLOC(sizeof(struct pp_pool) +
+			(capacity - 1) * sizeof(uint16_t));
+	if (tmp) {
+		tmp->capacity = capacity;
+		tmp->top = 0;
+		tmp->invalid = invalid;
+	}
+	return tmp;
+}
+
+uint16_t pp_pool_get(struct pp_pool *pool)
+{
+	uint16_t tmp;
+	unsigned int top;
+
+	top = pool->top;
+	if (top > 0) {
+		--top;
+		tmp = pool->data[top];
+		pool->top = top;
+		return tmp;
+	}
+	return pool->invalid;
+}
+
+int pp_pool_put(struct pp_pool *pool, uint16_t data)
+{
+	unsigned int top;
+
+	top = pool->top;
+	if (top < pool->capacity) {
+		pool->data[top] = data;
+		pool->top = top + 1;
+		return 0;
+	}
+	return -1;
+}
+
+static void pp_pool_clean(struct pp_pool *pool)
+{
+	if (pool)
+		QOS_FREE(pool);
+}
+
+static struct pp_pool *free_id_init(void)
+{
+	unsigned int i;
+	struct pp_pool *tmp;
+
+	tmp  = pp_pool_init(NUM_OF_NODES, QOS_INVALID_ID);
+	if (tmp)
+		for (i = NUM_OF_NODES; i > 0; --i)
+			pp_pool_put(tmp, i - 1);
+
+	return tmp;
+}
+
+static struct pp_pool *free_rlm_init(void)
+{
+	unsigned int i;
+	struct pp_pool *tmp;
+
+	tmp  = pp_pool_init(NUM_OF_QUEUES, QOS_INVALID_ID);
+	if (tmp)
+		for (i = NUM_OF_QUEUES; i > 0; --i)
+			pp_pool_put(tmp, i - 1);
+
+	return tmp;
+}
+
+
+struct pp_pool *free_ports_phys_init(unsigned int *reserved,
+				     unsigned int max_port,
+				     const unsigned int *reserved_ports,
+				     unsigned int size)
+{
+	unsigned int i;
+	unsigned int res;
+	unsigned int tmp;
+	struct pp_pool *pool;
+
+	res = 0;
+	tmp = min(size, max_port + 1);
+	memcpy(reserved, reserved_ports, tmp * sizeof(unsigned int));
+
+	for (i = 0; i < tmp; ++i)
+		if (reserved[i] == 1)
+			++res;
+
+	tmp = max_port + 1 - res;
+	pool  = pp_pool_init(tmp, QOS_INVALID_PHY);
+	if (pool)
+		for (i = max_port + 1; i > 0; --i)
+			if (reserved[i - 1] == 0)
+				pp_pool_put(pool, i - 1);
+	return pool;
+}
+
+/******************************************************************************/
+/*                                 Queue                                      */
+/******************************************************************************/
+struct q_item {
+	struct list_head list;
+	uint16_t data;
+};
+
+struct pp_queue {
+	unsigned int capacity;
+	struct list_head used;
+	struct list_head free;
+	struct q_item items[1];
+};
+
+uint16_t pp_queue_dequeue(struct pp_queue *queue)
+{
+	struct q_item *item;
+	int rc;
+
+	if (!list_empty(&queue->used)) {
+		item = list_entry(queue->used.next, struct q_item, list);
+		rc = item->data;
+		list_move_tail(&item->list, &queue->free);
+	} else {
+		QOS_LOG("queue is empty\n");
+		rc = QOS_INVALID_ID;
+	}
+	return rc;
+}
+
+int pp_queue_enqueue(struct pp_queue *queue, uint16_t data)
+{
+	struct q_item *item;
+
+	if (!list_empty(&queue->free)) {
+		item = list_entry(queue->free.next, struct q_item, list);
+		item->data = data;
+		list_move_tail(&item->list, &queue->used);
+		return 0;
+	}
+	QOS_LOG("queue is full\n");
+	return -1;
+}
+
+static int queue_is_reset(struct pp_queue *queue)
+{
+	unsigned int i;
+	struct list_head *pos;
+
+	if (!list_empty(&queue->used))
+		return 0;
+
+	i = 0;
+	list_for_each(pos, &queue->free) ++i;
+
+	return (i == queue->capacity);
+}
+
+void pp_queue_reset(struct pp_queue *queue)
+{
+	list_splice_tail_init(&queue->used, &queue->free);
+	QOS_ASSERT(queue_is_reset(queue), "Queue is not reset\n");
+}
+
+static void pp_queue_clean(struct pp_queue *queue)
+{
+	if (queue)
+		QOS_FREE(queue);
+}
+
+static struct pp_queue *pp_queue_init(unsigned int capacity)
+{
+	struct pp_queue *queue;
+	unsigned int i;
+
+	queue = QOS_MALLOC(sizeof(struct pp_queue) +
+			   sizeof(struct q_item) * (capacity - 1));
+	if (queue) {
+		queue->capacity = capacity;
+		INIT_LIST_HEAD(&(queue->free));
+		INIT_LIST_HEAD(&(queue->used));
+		for (i = 0; i < queue->capacity; ++i)
+			list_add_tail(&(queue->items[i].list), &(queue->free));
+	}
+	return queue;
+}
+
+/******************************************************************************/
+/*                             Cmd Queue                                      */
+/******************************************************************************/
+#define CMD_QUEUE_SIZE 16384LU
+struct cmd_queue {
+	size_t read;  /* next index to read */
+	size_t write; /* next free index to write */
+	size_t count; /* how many bytes are in */
+	uint8_t data[CMD_QUEUE_SIZE];
+};
+
+static struct cmd_queue *cmd_queue_init(void)
+{
+	struct cmd_queue *q;
+
+	q = QOS_MALLOC(sizeof(struct cmd_queue));
+	if (q) {
+		q->read = 0;
+		q->write = 0;
+		q->count = 0;
+	}
+	return q;
+}
+
+static void cmd_queue_clean(struct cmd_queue *q)
+{
+	if (q)
+		QOS_FREE(q);
+}
+
+int cmd_queue_put(struct cmd_queue *q, void *_cmd, size_t size)
+{
+	unsigned int toend;
+	uint8_t *cmd;
+
+	cmd = _cmd;
+
+	if (CMD_QUEUE_SIZE - q->count < size) {
+		QOS_LOG_ERR("%lu bytes free, can't accommodate %zu bytes\n",
+				CMD_QUEUE_SIZE - q->count, size);
+		return -1;
+	}
+
+	toend = CMD_QUEUE_SIZE - q->write;
+	if (toend >= size) {
+		memcpy(q->data + q->write, cmd, size);
+		q->write += size;
+	} else {
+		memcpy(q->data + q->write, cmd, toend);
+		memcpy(q->data, cmd + toend, size - toend);
+		q->write = size - toend;
+	}
+
+	q->count += size;
+
+	return 0;
+}
+
+static int cmd_queue_read(struct cmd_queue *q,
+		void *_cmd,
+		size_t size,
+		int remove)
+{
+	unsigned int toend;
+	uint8_t *cmd;
+
+	cmd = _cmd;
+
+	if (q->count < size) {
+		QOS_LOG_DEBUG("has only %zu bytes, can't retrieve %zu bytes\n",
+				q->count, size);
+		return -1;
+	}
+
+	toend = CMD_QUEUE_SIZE - q->read;
+	if (toend >= size) {
+		memcpy(cmd, q->data + q->read, size);
+		if (remove)
+			q->read += size;
+	} else {
+		memcpy(cmd, q->data + q->read, toend);
+		memcpy(cmd + toend, q->data, size - toend);
+		if (remove)
+			q->read = size - toend;
+	}
+
+	if (remove)
+		q->count -= size;
+
+	return 0;
+}
+
+int cmd_queue_get(struct cmd_queue *q, void *_cmd, size_t size)
+{
+	return cmd_queue_read(q, _cmd, size, 1);
+}
+
+int cmd_queue_peek(struct cmd_queue *q, void *_cmd, size_t size)
+{
+	return cmd_queue_read(q, _cmd, size, 0);
+}
+
+int cmd_queue_is_empty(struct cmd_queue *q)
+{
+	return (q->count == 0);
+}
+
+/******************************************************************************/
+/*                                 Nodes                                      */
+/******************************************************************************/
+struct pp_nodes {
+	struct qos_node nodes[NUM_OF_NODES];
+};
+
+static struct pp_nodes *pp_nodes_init(void)
+{
+	struct pp_nodes *nodes;
+
+	nodes = QOS_MALLOC(sizeof(struct pp_nodes));
+	if (nodes)
+		memset(nodes, 0, sizeof(struct pp_nodes));
+
+	return nodes;
+}
+
+unsigned int get_phy_from_node(const struct pp_nodes *nodes,
+		const struct qos_node *node)
+{
+	QOS_ASSERT(node >= nodes->nodes && node <= nodes->nodes + NUM_OF_NODES,
+		   "invalid node pointer\n");
+	return node - nodes->nodes;
+}
+
+struct qos_node *get_node_from_phy(struct pp_nodes *nodes, unsigned int phy)
+{
+	QOS_ASSERT(QOS_PHY_VALID(phy), "invalid phy %u\n", phy);
+	return nodes->nodes + phy;
+}
+
+const struct qos_node *get_const_node_from_phy(const struct pp_nodes *nodes,
+					       unsigned int phy)
+{
+	QOS_ASSERT(QOS_PHY_VALID(phy), "invalid phy %u\n", phy);
+	return nodes->nodes + phy;
+}
+
+static void pp_nodes_clean(struct pp_nodes *nodes)
+{
+	if (nodes)
+		QOS_FREE(nodes);
+}
+
+
+/******************************************************************************/
+/*                                 Mapping                                    */
+/******************************************************************************/
+struct pp_mapping {
+	uint16_t id2phy[NUM_OF_NODES];
+	uint16_t phy2id[NUM_OF_NODES];
+};
+
+unsigned int get_id_from_phy(const struct pp_mapping *map, unsigned int phy)
+{
+	QOS_ASSERT(QOS_PHY_VALID(phy), "invalid phy %u\n", phy);
+	return map->phy2id[phy];
+}
+
+unsigned int get_phy_from_id(const struct pp_mapping *map, unsigned int id)
+{
+	QOS_ASSERT(QOS_ID_VALID(id), "invalid id %u\n", id);
+	return map->id2phy[id];
+}
+
+void map_id_phy(struct pp_mapping *map, unsigned int id, unsigned int phy)
+{
+	QOS_ASSERT(QOS_ID_VALID(id), "invalid id %u\n", id);
+	QOS_ASSERT(QOS_PHY_VALID(phy), "invalid phy %u\n", phy);
+	map->id2phy[id] = phy;
+	map->phy2id[phy] = id;
+}
+
+void map_id_reserved(struct pp_mapping *map, unsigned int id)
+{
+	QOS_ASSERT(QOS_ID_VALID(id), "invalid id %u\n", id);
+	map->id2phy[id] = QOS_UNKNOWN_PHY;
+}
+
+static struct pp_mapping *pp_mapping_init(void)
+{
+	unsigned int i;
+	struct pp_mapping *map;
+
+	map = QOS_MALLOC(sizeof(struct pp_mapping));
+	if (map) {
+		for (i = 0; i < NUM_OF_NODES; ++i) {
+			map->id2phy[i] = QOS_INVALID_PHY;
+			map->phy2id[i] = QOS_INVALID_ID;
+		}
+	}
+	return map;
+}
+
+static void pp_mapping_clean(struct pp_mapping *map)
+{
+	if (map)
+		QOS_FREE(map);
+}
+
+void map_invalidate_id(struct pp_mapping *map, unsigned int id)
+{
+	unsigned int phy;
+
+	QOS_ASSERT(QOS_ID_VALID(id), "invalid id %u\n", id);
+	phy = get_phy_from_id(map, id);
+	QOS_ASSERT(QOS_PHY_VALID(phy), "invalid phy is mapped to id %u\n", id);
+
+	map->id2phy[id] = QOS_INVALID_PHY;
+	map->phy2id[phy] = QOS_INVALID_ID;
+}
+
+/******************************************************************************/
+/*                                 Moving                                     */
+/******************************************************************************/
+#define MAX_MOVING_NODES 8
+/*
+ * Return 1 if used status of all count nodes starting from first_phy equals
+ * status
+ */
+static int is_all_nodes_used_status(const struct pp_qos_dev *qdev,
+		unsigned int first_phy, unsigned int count, unsigned int status)
+{
+	const struct qos_node *cur;
+	unsigned int used;
+
+	cur = get_const_node_from_phy(qdev->nodes, first_phy);
+	for (; count; --count) {
+		used = !!QOS_BITS_IS_SET(cur->flags, QOS_NODE_FLAGS_USED);
+		if (used != status)
+			return 0;
+		cur++;
+	}
+	return 1;
+}
+
+/* is child_phy a child of parent_phy */
+static int node_child_of(struct pp_nodes *nodes,
+		unsigned int child_phy, unsigned int parent_phy)
+{
+	const struct qos_node *parent;
+
+	parent = get_const_node_from_phy(nodes, parent_phy);
+
+	return (child_phy >= parent->parent_prop.first_child_phy &&
+		child_phy <= parent->parent_prop.first_child_phy +
+		parent->parent_prop.num_of_children - 1);
+}
+
+/**
+ * node_update_children_internal() - Update children's parent
+ *
+ * @nodes:     original nodes (qdev->nodes)
+ * @tmp_nodes: a window (buffer) holding a copy of some nodes from
+ *	       the original nodes
+ * @first:     The phy that the first node of tmp_nodes
+ *             represents
+ * @count:     How many children should be updated on tmp_nodes
+ * @phy:       original phy of parent
+ * @new_phy:   new phy of parent
+ *
+ * Does not create update predecessor cmds.
+ * The first count children of parent are updated on tmp_nodes
+ * the rest on nodes
+ */
+static void node_update_children_internal(
+				   struct pp_nodes *nodes,
+				   struct qos_node *tmp_nodes,
+				   unsigned int first,
+				   unsigned int count,
+				   unsigned int phy,
+				   unsigned int new_phy)
+
+{
+	unsigned int last;
+	unsigned int cur;
+	struct qos_node *child;
+	struct qos_node *parent;
+
+	parent = get_node_from_phy(nodes, phy);
+	cur = parent->parent_prop.first_child_phy;
+	last = cur + parent->parent_prop.num_of_children - 1;
+	for (; cur <= last; ++cur) {
+		if (cur >= first && cur < first + count)
+			child = tmp_nodes + cur - first;
+		else
+			child = get_node_from_phy(nodes, cur);
+		child->child_prop.parent_phy = new_phy;
+	}
+}
+
+/*
+ * Update the children of a parent which is moving from phy to new_phy
+ * Children parent_phy's is updated
+ */
+void node_update_children(
+			  struct pp_qos_dev *qdev,
+			  unsigned int phy,
+			  unsigned int new_phy)
+{
+	unsigned int num;
+	struct qos_node *child;
+	struct qos_node *parent;
+
+	parent = get_node_from_phy(qdev->nodes, phy);
+	child = get_node_from_phy(
+			qdev->nodes,
+			parent->parent_prop.first_child_phy);
+	num =  parent->parent_prop.num_of_children;
+	for (; num; --num)  {
+		child->child_prop.parent_phy = new_phy;
+		++child;
+	}
+}
+
+
+/*
+ * Update parent's first child phy and num of children, given that count nodes
+ * starting from src_phy are moving to dst_phy
+ *
+ * Note number of children is calculated as last_child - first_child + 1
+ */
+static int node_update_parent(struct pp_qos_dev *qdev,
+		struct qos_node *tmpnodes, unsigned int src_first,
+		unsigned int size, unsigned int src_phy, unsigned int dst_phy,
+		unsigned int count)
+{
+	unsigned int first;
+	unsigned int last;
+	unsigned int num;
+	unsigned int parent_phy;
+	unsigned int moving;
+	struct qos_node *parent;
+	struct qos_node *child;
+	struct pp_nodes *nodes;
+
+	nodes = qdev->nodes;
+	child = get_node_from_phy(nodes, src_phy);
+	parent_phy = child->child_prop.parent_phy;
+
+	if (parent_phy >= src_first && parent_phy < src_first + size)
+		parent = tmpnodes + parent_phy - src_first;
+	else
+		parent = get_node_from_phy(nodes, parent_phy);
+
+	QOS_ASSERT(node_parent(parent),
+			"Node %u suppose to be a parent but is not\n",
+			get_phy_from_node(nodes, parent));
+
+	QOS_ASSERT(node_child_of(nodes, src_phy, parent_phy),
+			"%u is not child of %u\n",
+			src_phy, parent_phy);
+
+	first = parent->parent_prop.first_child_phy;
+	num = parent->parent_prop.num_of_children;
+	last = first + num - 1;
+	QOS_ASSERT(same_octet(first, last),
+			"source nodes %u and %u are not in the same octet\n",
+			first, last);
+
+	/* Number of children going to move */
+	moving = min(count, num - (src_phy - first));
+	QOS_ASSERT(same_octet(dst_phy, dst_phy + moving - 1),
+			"destination nodes %u and %u are not in the same octet\n",
+			dst_phy, dst_phy + moving - 1);
+
+	if (moving == num) { /* all children are moving */
+		parent->parent_prop.first_child_phy = dst_phy;
+	} else {
+		QOS_ASSERT(same_octet(dst_phy, src_phy),
+				"src phy %u and dst phy %u are not in same octet\n",
+				src_phy, dst_phy);
+		if (first != src_phy) /* first is not moving */
+			first = min(first, dst_phy);
+		else   /* first is moving */
+			first = min(first + moving, dst_phy);
+
+		if (last != src_phy + moving - 1)  /* last is not moving */
+			last = max(last, dst_phy + moving - 1);
+		else  /* last is moving */
+			last = max(last - moving, dst_phy + moving - 1);
+
+		QOS_ASSERT(same_octet(first, last),
+				"%u and %u are in different octets\n",
+				first, last);
+		parent->parent_prop.first_child_phy = first;
+		parent->parent_prop.num_of_children = last - first + 1;
+	}
+
+	return moving;
+}
+
+/*
+ * Given count nodes starting at src_phy [src_phy..src_phy + count - 1],
+ * that are going to move to [dst_phy..dst_phy + count - 1]:
+ *
+ * Update id<->phy mapping for each node that is moved
+ *
+ * For each node that is a parent node
+ *   Update parent_phy of each of its children
+ *
+ * For each group of children that have the same parent
+ *   Update parent's first_child_phy and num of children
+ *
+ */
+static void nodes_update_stake_holders(struct pp_qos_dev *qdev,
+		unsigned int src_phy, unsigned int dst_phy, unsigned int count)
+{
+	unsigned int i;
+	unsigned int tmp;
+	struct qos_node *next_updated_parent;
+	struct qos_node *node;
+	struct pp_mapping *map;
+	struct qos_node tmp_nodes[MAX_MOVING_NODES];
+	unsigned int tmp_map[MAX_MOVING_NODES];
+	unsigned int updated_parents[MAX_MOVING_NODES];
+	unsigned int index;
+
+	QOS_ASSERT(count < MAX_MOVING_NODES,
+			"Trying to update %u nodes but the maximum is %u\n",
+			count, MAX_MOVING_NODES);
+	map = qdev->mapping;
+	index = 0;
+
+	memcpy(&tmp_nodes, qdev->nodes->nodes + src_phy,
+			sizeof(struct qos_node) * count);
+
+	/*
+	 * Invalidate current mapping, update children and parents of
+	 * moved nodes
+	 */
+	node = get_node_from_phy(qdev->nodes, src_phy);
+	next_updated_parent = node;
+	for (i = src_phy; i < src_phy + count; ++i) {
+		tmp = get_id_from_phy(map, i);
+		tmp_map[i - src_phy] = tmp;
+		map_invalidate_id(map, tmp);
+		if (node_parent(node))
+			node_update_children_internal(
+					qdev->nodes,
+					tmp_nodes,
+					src_phy,
+					count,
+					i,
+					dst_phy + i - src_phy);
+
+		if (node_child(node) && (node >= next_updated_parent)) {
+			next_updated_parent =  node +
+				node_update_parent(qdev, tmp_nodes,
+						src_phy, count,
+						i, dst_phy + i - src_phy,
+						count - (i - src_phy));
+			updated_parents[index++] = node->child_prop.parent_phy;
+		}
+
+		node++;
+	}
+
+	/* map all previous invalidated ids to their new phy */
+	for (i = dst_phy; i < dst_phy + count; ++i) {
+		tmp = tmp_map[i - dst_phy];
+		QOS_ASSERT(QOS_ID_VALID(tmp), "Invalid id %u on phy %u\n",
+				tmp, i);
+		map_id_phy(map, tmp, i);
+	}
+
+	memcpy(qdev->nodes->nodes + src_phy, tmp_nodes,
+	       sizeof(struct qos_node) * count);
+
+	for (i = 0; i < index; ++i)
+		create_parent_change_cmd(qdev, updated_parents[i]);
+}
+
+/*
+ * For small arrays this is probably quicker than
+ * the heap sort kernel is using
+ */
+static unsigned int remove_duplicates(unsigned int *data, unsigned int size)
+{
+	unsigned int i;
+	unsigned int j;
+
+	QOS_ASSERT(size <= MAX_MOVING_NODES,
+			"This function intends for array with size up to %d\n",
+			MAX_MOVING_NODES);
+
+	for (i = 0; i < size; ++i) {
+		for (j = i + 1; j < size; ++j) {
+			if (data[i] == data[j]) {
+				--size;
+				data[j] = data[size];
+				--j;
+			}
+		}
+	}
+
+	return size;
+}
+
+/*
+ * Given a group A of count nodes starting at start, find a group B which
+ * satisfies:
+ *
+ * - Each element in B is a direct parent of an element from A
+ * - B has no duplicates
+ * - If (external)
+ *	- Each element in B does not belong to A
+ *	- Every element on A is a decendant of some element on B
+ *   Else
+ *	- Each element in B belongs to A
+ *	- The parent of each element is B does not belong to A
+ *	- Every element on A is either on B or has ancestor on B
+ *
+ *   B is stored on data and the function returns the size of B
+ *
+ *   Return number of elements on B
+ */
+static unsigned int parents_span(struct pp_nodes *nodes, unsigned int external,
+		unsigned int start, unsigned int count,
+		unsigned int *data, unsigned int size)
+{
+	unsigned int i;
+	unsigned int parent_phy;
+	unsigned int cur_phy;
+	const struct qos_node *cur;
+
+	QOS_ASSERT(size >= count,
+			"Array size %u is smaller than number of moved nodes %u\n",
+			size, count);
+	i = 0;
+	cur = get_const_node_from_phy(nodes, start);
+	for (cur_phy = start; cur_phy < start + count; ++cur_phy) {
+		QOS_ASSERT((cur->type == TYPE_UNKNOWN) ||
+				node_child(cur), "Node is not a child\n");
+		parent_phy = cur->child_prop.parent_phy;
+		/* parent not moving */
+		if ((parent_phy < start) ||
+				(parent_phy >= start + count)) {
+			if (external)
+				data[i] = parent_phy;
+			else
+				data[i] = cur_phy;
+			++i;
+		}
+		++cur;
+	}
+
+	return remove_duplicates(data, i);
+}
+
+
+/*
+ * If the src and dst region don't overlap then we can use
+ * either strategy of "move last src first" or "move first src first"
+ * If they overlap and the move is forward (src < dst) we will use
+ * "move last src first".
+ * If they overlap and the move is backward (src > dst) we will use
+ * "move last src first"
+ */
+static void create_multiple_move_cmds(struct pp_qos_dev *qdev,
+		unsigned int dst_phy,
+		unsigned int src_phy,
+		unsigned int count)
+{
+	unsigned int dst_port;
+	unsigned int i;
+	unsigned int dst;
+	unsigned int src;
+	unsigned int delta;
+
+	if (src_phy < dst_phy) {
+		src = src_phy + count - 1;
+		dst = dst_phy + count - 1;
+		delta = ~0;
+	} else {
+		src = src_phy;
+		dst = dst_phy;
+		delta = 1;
+	}
+
+	for (i = 0; i < count; ++i) {
+		dst_port = get_port(qdev->nodes, dst);
+		create_move_cmd(qdev, dst, src, dst_port);
+		src += delta;
+		dst += delta;
+	}
+}
+
+
+/**
+ * nodes_move() - Move nodes
+ *
+ * Implement the core functionality of moving nodes to different phy.
+ * This involves updating the stake holders nodes e.g. parents and children
+ * of the moved nodes, and updating the id<->phy mapping
+ *
+ * @qdev:
+ * @dst_phy: Dest phy of first node
+ * @src_phy: Source phy of first node
+ * @count: Number of nodes to move
+ *
+ * Notes:
+ * - All src nodes must be used, all dst nodes which don't overlap src
+ *   nodes must be unused
+ * - Number of moving nodes should be smaller than 8
+ * - If not all children of parent are moving then the move
+ *   must be within octet boundries - e.g. a shift
+ *
+ */
+STATIC_UNLESS_TEST void nodes_move(struct pp_qos_dev *qdev,
+		unsigned int dst_phy,
+		unsigned int src_phy,
+		unsigned int count)
+{
+	unsigned int i;
+#if 0
+	unsigned int suspend_size;
+	unsigned int suspend[MAX_MOVING_NODES];
+#endif
+	unsigned int ances_size;
+	unsigned int ancestors[MAX_MOVING_NODES];
+#if 0
+	const struct qos_node *node;
+#endif
+
+	QOS_ASSERT(src_phy != dst_phy,
+			"src and dst are the same %u\n",
+			src_phy);
+	QOS_ASSERT(count < MAX_MOVING_NODES, "Can't move %u nodes, max is %u\n",
+			count, MAX_MOVING_NODES);
+	if (count) {
+	#if 0
+		suspend_size = parents_span(qdev->nodes, 1,
+				src_phy, count, suspend, MAX_MOVING_NODES);
+		for (i = 0; i < suspend_size; ++i)
+			create_suspend_cmd(qdev, suspend[i]);
+	#endif
+
+		nodes_update_stake_holders(qdev, src_phy, dst_phy, count);
+		nodes_modify_used_status(qdev, src_phy, count, 0);
+		QOS_ASSERT(is_all_nodes_used_status(qdev, dst_phy, count, 0),
+			   "Some of the destination nodes are in used\n");
+		memmove(get_node_from_phy(qdev->nodes, dst_phy),
+				get_node_from_phy(qdev->nodes, src_phy),
+				count * sizeof(struct qos_node));
+		nodes_modify_used_status(qdev, dst_phy, count, 1);
+
+		create_multiple_move_cmds(qdev, dst_phy, src_phy, count);
+
+#if 0
+		/* FW will delete the src node on a move command */
+		/* Issue delete node cmd to each node */
+		node = get_const_node_from_phy(qdev->nodes, src_phy);
+		for (i = 0; i < count; ++i) {
+			if (!node_used(node))
+				create_remove_node_cmd(qdev,
+						TYPE_UNKNOWN,
+						i + src_phy, 0);
+			++node;
+		}
+#endif
+
+		/* Issue update preds each node whose ancestor moved */
+		ances_size = parents_span(qdev->nodes, 0, dst_phy, count,
+				ancestors, MAX_MOVING_NODES);
+		for (i = 0; i < ances_size; ++i)
+			tree_update_predecessors(qdev, ancestors[i]);
+	#if 0
+		for (i = 0; i < suspend_size; ++i)
+			create_resume_cmd(qdev, suspend[i]);
+	#endif
+	}
+}
+
+/******************************************************************************/
+/*                                 Generic                                    */
+/******************************************************************************/
+
+struct qos_node *octet_get_min_sibling_group(
+		const struct pp_qos_dev *qdev,
+		unsigned int octet,
+		const struct qos_node *special_parent,
+		unsigned int *num_of_children)
+{
+	unsigned int min_size;
+	unsigned int phy;
+	unsigned int last_phy;
+	unsigned int num_children;
+	const struct qos_node *cur;
+	struct qos_node *cur_parent;
+	struct qos_node *min_parent;
+
+	min_size = 9;
+	min_parent = NULL;
+
+	phy = octet * 8;
+	last_phy = phy + octet_get_use_count(qdev->octets, octet);
+	while (phy < last_phy) {
+		cur = get_const_node_from_phy(qdev->nodes, phy);
+		cur_parent = get_node_from_phy(qdev->nodes,
+				cur->child_prop.parent_phy);
+		num_children = cur_parent->parent_prop.num_of_children;
+		if ((cur_parent != special_parent) &&
+				(num_children < min_size)) {
+			min_size = num_children;
+			min_parent = cur_parent;
+		} else if ((cur_parent == special_parent) &&
+				(num_children + 1 < min_size)) {
+			min_size = num_children + 1;
+			min_parent = cur_parent;
+		}
+		phy += cur_parent->parent_prop.num_of_children;
+	}
+	*num_of_children = min_size;
+	return min_parent;
+}
+
+static void update_octet_usage(struct pp_octets *octets, unsigned int phy,
+		unsigned int delta, unsigned int status)
+{
+	unsigned int octet;
+	unsigned int usage;
+
+	octet = octet_of_phy(phy);
+	usage = octet_get_use_count(octets, octet);
+	if (status == 0)
+		usage -= delta;
+	else
+		usage += delta;
+	octet_set_use_count(octets, octet, usage);
+}
+
+/*
+ * Set used status of count nodes starting from first_phy to status
+ * Verify that current used status is different from the value to be set
+ */
+void nodes_modify_used_status(struct pp_qos_dev *qdev, unsigned int first_phy,
+		unsigned int count, unsigned int status)
+{
+	struct qos_node *cur;
+	unsigned int phy;
+	unsigned int delta;
+
+	QOS_ASSERT(is_all_nodes_used_status(qdev, first_phy, count, !status),
+		   "some nodes used status is already %u\n", status);
+	delta = 0;
+	for (phy = first_phy; phy < first_phy + count; ++phy) {
+		cur = get_node_from_phy(qdev->nodes, phy);
+		QOS_BITS_TOGGLE(cur->flags, QOS_NODE_FLAGS_USED);
+		++delta;
+		if (octet_phy_offset(phy) == 7) {
+			update_octet_usage(qdev->octets, phy, delta, status);
+			delta = 0;
+		}
+	}
+
+	if (delta)
+		update_octet_usage(qdev->octets, phy - 1, delta, status);
+}
+
+
+/**
+ * octet_nodes_shift() - Shift nodes whithin octet
+ * @qdev:
+ * @first_phy: Phy of first node to be shifted
+ * @count: Number of nodes to shift
+ * @shift: Number of places to shift Negative indicates shift left,
+ *	   positive shift right
+ */
+STATIC_UNLESS_TEST void octet_nodes_shift(struct pp_qos_dev *qdev,
+		unsigned int first_phy,
+		unsigned int count,
+		int shift)
+{
+	if (count != 0 && shift != 0) {
+		QOS_ASSERT(same_octet(first_phy, first_phy + count - 1) &&
+			   same_octet(first_phy, first_phy + shift) &&
+			   same_octet(first_phy, first_phy + shift + count - 1)
+			   ,
+			   "shift %d places of %u nodes from %u crosses octet boundaries\n",
+			   shift, count, first_phy);
+		nodes_move(qdev, first_phy + shift, first_phy, count);
+	}
+}
+
+/*
+ *
+ */
+void node_phy_delete(struct pp_qos_dev *qdev, unsigned int phy)
+{
+	unsigned int usage;
+	unsigned int reminder;
+	struct qos_node *node;
+	struct qos_node *parent;
+	unsigned int id;
+	unsigned int parent_phy;
+	unsigned int update_bw;
+
+	ISSUE_DELETE_NODE(phy);
+	update_bw = 0;
+	usage = octet_get_use_count(qdev->octets, octet_of_phy(phy));
+	node = get_node_from_phy(qdev->nodes, phy);
+
+	QOS_ASSERT(!node_parent(node) || node->parent_prop.num_of_children == 0,
+			"Try to delete node %u that has children\n", phy);
+
+	if (node_child(node)) {
+		parent_phy = node->child_prop.parent_phy;
+		parent = get_node_from_phy(qdev->nodes, parent_phy);
+		if (node->child_prop.virt_bw_share && node_internal(parent)) {
+			update_bw = 1;
+			id = get_id_from_phy(qdev->mapping, parent_phy);
+		}
+
+		/*
+		 * If this is the last child of a parent than shift
+		 * operation will not update the parent, since its children
+		 * are not moving - we have to update it manually
+		 */
+		if (phy == parent->parent_prop.first_child_phy +
+				parent->parent_prop.num_of_children - 1) {
+			--parent->parent_prop.num_of_children;
+			create_parent_change_cmd(qdev, parent_phy);
+		}
+	}
+	nodes_modify_used_status(qdev, phy, 1, 0);
+	reminder = usage - (octet_phy_offset(phy) + 1);
+	if (octet_of_phy(phy) > octet_of_phy(qdev->max_port))
+		octet_nodes_shift(qdev, phy + 1, reminder, -1);
+
+	if (update_bw) {
+		phy = get_phy_from_id(qdev->mapping, id);
+		parent = get_node_from_phy(qdev->nodes, phy);
+		update_internal_bandwidth(qdev, parent);
+	}
+}
+
+void release_rlm(struct pp_pool *rlms, unsigned int rlm)
+{
+	pp_pool_put(rlms, rlm);
+}
+
+static void release_node_id(struct pp_qos_dev *qdev, unsigned int phy)
+{
+	unsigned int id;
+
+	id = get_id_from_phy(qdev->mapping, phy);
+	QOS_LOG_DEBUG("Deleting id %u phy %u\n", id, phy);
+	QOS_ASSERT(QOS_ID_VALID(id), "Invalid id for phy %u\n", phy);
+	map_invalidate_id(qdev->mapping, id);
+	pp_pool_put(qdev->ids, id);
+}
+
+int node_remove(struct pp_qos_dev *qdev, struct qos_node *node)
+{
+	unsigned int phy;
+	enum node_type type;
+	unsigned int rlm;
+
+	phy = get_phy_from_node(qdev->nodes, node);
+	type = node->type;
+	QOS_ASSERT(type != TYPE_UNKNOWN, "Unknown node type of phy %u\n",
+			phy);
+
+	if (type == TYPE_QUEUE)
+		rlm  = node->data.queue.rlm;
+	else
+		rlm = 0;
+	create_remove_node_cmd(qdev, type, phy, rlm);
+	release_node_id(qdev, phy);
+	if (node_queue(node))
+		release_rlm(qdev->rlms, node->data.queue.rlm);
+
+	node_phy_delete(qdev, get_phy_from_node(qdev->nodes, node));
+	return 0;
+}
+
+int node_flush(struct pp_qos_dev *qdev, struct qos_node *node)
+{
+	ISSUE_FLUSH_NODE(get_phy_from_node(qdev->nodes, node));
+	return 0;
+}
+
+STATIC_UNLESS_TEST unsigned int get_children_bandwidth_share(
+		const struct pp_qos_dev *qdev,
+		const struct qos_node *parent);
+void update_internal_bandwidth(const struct pp_qos_dev *qdev,
+		struct qos_node *parent)
+{
+	unsigned int share;
+	const struct qos_node *child;
+	struct qos_node *tmp;
+	unsigned int cnt;
+	unsigned int phy;
+	struct qos_node *internals[10];
+	unsigned int index;
+	unsigned int parent_share;
+
+	tmp = parent;
+	index = 0;
+	do {
+		QOS_ASSERT(node_internal(tmp), "Node is not internal\n");
+		share = get_children_bandwidth_share(qdev, tmp);
+		tmp->child_prop.virt_bw_share = share;
+		internals[index++] = tmp;
+		phy = tmp->child_prop.parent_phy;
+		tmp = get_node_from_phy(qdev->nodes, phy);
+	} while (node_internal(tmp));
+
+	--index;
+	tmp = internals[index];
+	ISSUE_BW_CMD(get_phy_from_node(qdev->nodes, tmp),
+			tmp->child_prop.virt_bw_share, 1U);
+	do {
+		QOS_ASSERT(node_internal(tmp), "Node is not internal\n");
+		parent_share = tmp->child_prop.virt_bw_share;
+		//TODO remove when parent share is used and compiler
+		//does not shout
+		parent_share = parent_share;
+
+		child = get_const_node_from_phy(qdev->nodes,
+				tmp->parent_prop.first_child_phy);
+		cnt = tmp->parent_prop.num_of_children;
+		for (; cnt; --cnt) {
+			QOS_ASSERT(node_child(child), "Node is not a child\n");
+			if (child->child_prop.virt_bw_share)
+				ISSUE_BW_CMD(
+					get_phy_from_node(
+						qdev->nodes,
+						child),
+					child->child_prop.virt_bw_share *
+					10000U,
+					parent_share * 100);
+			++child;
+		}
+
+		if (index > 0) {
+			--index;
+			tmp = internals[index];
+		} else {
+			break;
+		}
+	} while (1);
+}
+
+/**
+ * link_with_parent() - Link a new node to a parent
+ * @qdev:
+ * @phy:	The phy of the node
+ * @parent_id:  Id of a parent to linked with
+ *
+ * Note node is marked as used
+ */
+static void link_with_parent(
+		struct pp_qos_dev *qdev,
+		unsigned int phy,
+		unsigned int parent_id)
+{
+	struct qos_node *node;
+	struct qos_node *parent;
+	unsigned int first;
+	unsigned int last;
+	unsigned int parent_phy;
+	unsigned int num;
+
+	parent_phy = get_phy_from_id(qdev->mapping, parent_id);
+	parent = get_node_from_phy(qdev->nodes, parent_phy);
+	node = get_node_from_phy(qdev->nodes, phy);
+	node->child_prop.parent_phy = parent_phy;
+
+	num = parent->parent_prop.num_of_children;
+	first = parent->parent_prop.first_child_phy;
+	last = first + num - 1;
+
+	if (num == 0 || phy < first)
+		first = phy;
+
+	if (num == 0 || phy > last)
+		last = phy;
+
+	parent->parent_prop.num_of_children = last - first + 1;
+	parent->parent_prop.first_child_phy = first;
+	nodes_modify_used_status(qdev, phy, 1, 1);
+	create_parent_change_cmd(qdev, parent_phy);
+
+}
+
+struct pp_qos_dev *_qos_init(unsigned int max_port)
+{
+	struct pp_qos_dev *qdev;
+	unsigned int i;
+
+	qdev = QOS_MALLOC(sizeof(struct pp_qos_dev));
+	if (qdev) {
+		memset(qdev, 0, sizeof(struct pp_qos_dev));
+		qdev->max_port = max_port;
+
+		qdev->octets = octets_init(octet_of_phy(max_port));
+		if (qdev->octets == NULL)
+			goto fail;
+
+		qdev->nodes = pp_nodes_init();
+		if (qdev->nodes == NULL)
+			goto fail;
+
+		qdev->ids = free_id_init();
+		if (qdev->ids == NULL)
+			goto fail;
+
+		qdev->rlms = free_rlm_init();
+		if (qdev->rlms == NULL)
+			goto fail;
+
+		qdev->mapping = pp_mapping_init();
+		if (qdev->mapping == NULL)
+			goto fail;
+
+		qdev->queue = pp_queue_init(1024);
+		if (qdev->queue == NULL)
+			goto fail;
+
+		qdev->drvcmds.cmdq = cmd_queue_init();
+		if (qdev->drvcmds.cmdq == NULL)
+			goto fail;
+
+		qdev->drvcmds.pendq = cmd_queue_init();
+		if (qdev->drvcmds.pendq == NULL)
+			goto fail;
+
+		for (i = 0; i <= QOS_MAX_SHARED_BANDWIDTH_GROUP; ++i)
+			qdev->groups[i].used = 0;
+		QOS_LOCK_INIT(qdev);
+	}
+	return qdev;
+fail:
+	_qos_clean(qdev);
+	return NULL;
+}
+
+void _qos_clean(struct pp_qos_dev *qdev)
+{
+	if (qdev) {
+		clean_fwdata_internals(qdev);
+		cmd_queue_clean(qdev->drvcmds.pendq);
+		cmd_queue_clean(qdev->drvcmds.cmdq);
+		pp_queue_clean(qdev->queue);
+		pp_mapping_clean(qdev->mapping);
+		pp_pool_clean(qdev->portsphys);
+		pp_pool_clean(qdev->ids);
+		pp_nodes_clean(qdev->nodes);
+		octets_clean(qdev->octets);
+		QOS_FREE(qdev);
+	}
+}
+
+
+/******************************************************************************/
+/*                           Tree traversal                                   */
+/******************************************************************************/
+/**
+ * post_order_travers_tree() - Traverse subtree post order - children first
+ * followed by parents and apply operation on each conformed node
+ *
+ * @qdev:
+ * @root:	Phy of sub tree's root node
+ * @conform:    Function to see if the node we reach is conform
+ * @cdata:	Data to supply to conform
+ * @operation:  Operation to apply upon each conformed node
+ * @odata:      Data to supply to operation
+ * Return:	Sum of the returned values on all operations applied at the
+ * subtree
+ *
+ * Note - though operation is allowed to modify qdev, it is important that it
+ * won't do operation that modifies tree topology (e.g. move/shift/delete/add
+ * node), since this will mess the iteration process
+ */
+static int post_order_travers_tree(struct pp_qos_dev *qdev,
+				    int root,
+				    int (*conform)(
+					    const struct pp_qos_dev *qdev,
+					    const struct qos_node *node,
+					    void *cdata),
+				    void *cdata,
+				    int (*operation)(
+					    struct pp_qos_dev *qdev,
+					    const struct qos_node *node,
+					    void *odata),
+				    void *odata)
+{
+	unsigned int i;
+	unsigned int phy;
+	unsigned int total;
+	struct qos_node *node;
+
+	total = 0;
+	node = get_node_from_phy(qdev->nodes, root);
+	QOS_ASSERT(node_used(node), "Unused node\n");
+
+	if (node_parent(node)) {
+		for (i = 0; i < node->parent_prop.num_of_children; ++i) {
+			phy = node->parent_prop.first_child_phy + i;
+			total += post_order_travers_tree(qdev, phy, conform,
+					cdata, operation, odata);
+		}
+	}
+	if (conform(qdev, node, cdata))
+		total += operation(qdev, node, odata);
+
+	return total;
+}
+
+struct ids_container_metadata {
+	unsigned int next;
+	uint16_t *ids;
+	unsigned int size;
+};
+
+static int update_ids_container(struct pp_qos_dev *qdev,
+		const struct qos_node *node, void *data)
+{
+	struct ids_container_metadata *ids;
+	unsigned int phy;
+	uint16_t id;
+
+	ids = (struct ids_container_metadata *)data;
+	phy = get_phy_from_node(qdev->nodes, node);
+	id = get_id_from_phy(qdev->mapping, phy);
+
+	if (ids->next < ids->size) {
+		ids->ids[ids->next] = id;
+		ids->next++;
+	}
+
+	return 1;
+}
+
+static int node_queue_wrapper(const struct pp_qos_dev *qdev,
+		const struct qos_node *node, void *data)
+{
+	return node_used(node) && (node->type == TYPE_QUEUE);
+}
+
+void get_node_queues(struct pp_qos_dev *qdev,
+		unsigned int phy, uint16_t *queue_ids,
+		unsigned int size, unsigned int *queues_num)
+{
+	struct ids_container_metadata data = {0, queue_ids, size};
+
+	if (queue_ids == NULL)
+		data.size = 0;
+	*queues_num = post_order_travers_tree(qdev, phy,
+			node_queue_wrapper, NULL,
+			update_ids_container, &data);
+}
+
+static int node_in_grp(const struct pp_qos_dev *qdev,
+		const struct qos_node *node, void *data)
+{
+	return node_used(node) &&
+		(node->shared_bandwidth_group == (uintptr_t)data);
+}
+
+void get_bw_grp_members_under_node(struct pp_qos_dev *qdev, unsigned int id,
+		unsigned int phy, uint16_t *ids,
+		unsigned int size, unsigned int *ids_num)
+{
+	struct ids_container_metadata data = {0, ids, size};
+
+	if (ids == NULL)
+		data.size = 0;
+	*ids_num = post_order_travers_tree(qdev, phy, node_in_grp,
+			(void *)(uintptr_t)id, update_ids_container, &data);
+}
+
+static int update_predecessors(struct pp_qos_dev *qdev,
+		const struct qos_node *node, void *data)
+{
+	create_update_preds_cmd(qdev, get_phy_from_node(qdev->nodes, node));
+	return 1;
+}
+
+static int node_child_wrapper(const struct pp_qos_dev *qdev,
+		const struct qos_node *node, void *data)
+{
+	return node_child(node);
+}
+
+void tree_update_predecessors(struct pp_qos_dev *qdev, unsigned int phy)
+{
+	post_order_travers_tree(qdev, phy, node_child_wrapper,
+			NULL, update_predecessors, NULL);
+}
+
+#if 0
+static int node_virtual_child_of(const struct pp_qos_dev *qdev,
+		const struct qos_node *node, void *data)
+{
+	return node_child(node) && !node_internal(node) &&
+		((uintptr_t)data == get_virtual_parent_phy(qdev->nodes, node));
+}
+
+static int add_bandwidth_share(struct pp_qos_dev *qdev,
+		const struct qos_node *node,
+		void *data)
+{
+	QOS_ASSERT(node_child(node), "Node is not a child\n");
+	return node->child_prop.virt_bw_share;
+}
+
+
+/*
+ * Return the sum of bandwidth share of all desendants
+ * whose virtual parent is parent
+ * Return 0 if parent is internal
+ */
+STATIC_UNLESS_TEST unsigned int get_virt_children_bandwidth_share(
+		const struct pp_qos_dev *qdev,
+		const struct qos_node *parent)
+{
+	int phy;
+	int total;
+	struct pp_qos_dev *_qdev;
+
+	total = 0;
+	if (node_parent(parent) && !node_internal(parent)) {
+		_qdev = (struct pp_qos_dev *)qdev;
+		phy = get_phy_from_node(qdev->nodes, parent);
+		total = post_order_travers_tree(_qdev, phy,
+				node_virtual_child_of,
+				(void *)(uintptr_t)phy,
+				add_bandwidth_share, NULL);
+	}
+	return total;
+}
+#endif
+
+/*
+ * Return the sum of bandwidth share of all direct children of parent
+ */
+STATIC_UNLESS_TEST unsigned int get_children_bandwidth_share(
+		const struct pp_qos_dev *qdev,
+		const struct qos_node *parent)
+{
+	unsigned int total;
+	unsigned int num;
+	const struct qos_node *child;
+
+	total = 0;
+	if (node_parent(parent)) {
+		num = parent->parent_prop.num_of_children;
+		if (num > 0)
+			child = get_const_node_from_phy(qdev->nodes,
+					parent->parent_prop.first_child_phy);
+		for (; num; --num) {
+			total += child->child_prop.virt_bw_share;
+			++child;
+		}
+	}
+	return total;
+}
+
+static int node_remove_wrapper(
+		struct pp_qos_dev *qdev,
+		const struct qos_node *node, void *data)
+{
+	uint16_t phy;
+	uint16_t id;
+	int rc;
+
+	phy = get_phy_from_node(qdev->nodes, node);
+	id = get_id_from_phy(qdev->mapping, phy);
+	rc = pp_queue_enqueue(qdev->queue, id);
+	QOS_ASSERT(rc == 0, "Could not enqueue\n");
+	return rc;
+}
+
+static int node_flush_wrapper(
+		struct pp_qos_dev *qdev,
+		const struct qos_node *node, void *data)
+{
+	uint16_t phy;
+	uint16_t id;
+	int rc;
+
+	phy = get_phy_from_node(qdev->nodes, node);
+	id = get_id_from_phy(qdev->mapping, phy);
+	rc = _pp_qos_queue_flush(qdev, id);
+	QOS_ASSERT(rc == 0, "Could not enqueue\n");
+	return rc;
+}
+
+static int node_modify_blocked_status(
+		struct pp_qos_dev *qdev,
+		const struct qos_node *node, void *data)
+{
+	uint16_t phy;
+	uint16_t id;
+	unsigned int status;
+	int rc;
+
+	status = (unsigned int)(uintptr_t)data;
+	phy = get_phy_from_node(qdev->nodes, node);
+	id = get_id_from_phy(qdev->mapping, phy);
+	if (status)
+		rc = _pp_qos_queue_block(qdev, id);
+	else
+		rc = _pp_qos_queue_unblock(qdev, id);
+	QOS_ASSERT(rc == 0, "Could not block queue\n");
+	return rc;
+}
+
+static int node_used_wrapper(
+		const struct pp_qos_dev *qdev,
+		const struct qos_node *node, void *data)
+{
+	return node_used(node);
+}
+
+int tree_remove(struct pp_qos_dev *qdev, unsigned int phy)
+{
+	struct qos_node *node;
+	unsigned int id;
+	unsigned int tmp;
+	int rc;
+
+	pp_queue_reset(qdev->queue);
+	rc = post_order_travers_tree(qdev, phy, node_used_wrapper, NULL,
+			node_remove_wrapper, NULL);
+	if (rc) {
+		QOS_LOG("Error while trying to delete subtree whose root is %u\n",
+				phy);
+		return -EBUSY;
+	}
+	id = pp_queue_dequeue(qdev->queue);
+	while (QOS_ID_VALID(id)) {
+		tmp = get_phy_from_id(qdev->mapping, id);
+		node =	get_node_from_phy(qdev->nodes, tmp);
+		node_remove(qdev, node);
+		id = pp_queue_dequeue(qdev->queue);
+	}
+
+	return 0;
+}
+
+int tree_flush(struct pp_qos_dev *qdev, unsigned int phy)
+{
+	int rc;
+
+	rc = post_order_travers_tree(qdev, phy, node_queue_wrapper,
+			NULL, node_flush_wrapper, NULL);
+	if (rc) {
+		QOS_LOG("Unexpected error while flush subtree root is %u\n",
+				phy);
+		return -EBUSY;
+	}
+	return 0;
+}
+
+int tree_modify_blocked_status(
+		struct pp_qos_dev *qdev,
+		unsigned int phy,
+		unsigned int status)
+{
+	int rc;
+
+	rc = post_order_travers_tree(qdev,
+			phy, node_queue_wrapper,
+			NULL, node_modify_blocked_status,
+			(void *)(uintptr_t)status);
+	if (rc) {
+		QOS_LOG_ERR("Error when change blocked status to %u on tree with root %u\n",
+				status, phy);
+		rc =  -EBUSY;
+	}
+	return rc;
+}
+
+/******************************************************************************/
+/*                           Configuration                                    */
+/******************************************************************************/
+
+#ifdef MAY_USE_IN_THE_FUTURE
+static int shared_group_defined(
+		const struct pp_qos_dev *qdev,
+		unsigned int group_id)
+{
+	QOS_ASSERT(group_id <= QOS_MAX_SHARED_BANDWIDTH_GROUP,
+			"illegal shared group %u\n",
+		   group_id);
+	return (qdev->groups[group_id].limit != QOS_NO_BANDWIDTH_LIMIT);
+}
+#endif
+
+static int common_cfg_valid(
+		const struct pp_qos_dev *qdev,
+		const struct qos_node *node)
+{
+	unsigned int shared;
+
+	if (!(node->bandwidth_limit == QOS_NO_BANDWIDTH_LIMIT ||
+				node->bandwidth_limit <=
+				QOS_MAX_BANDWIDTH_LIMIT)) {
+		QOS_LOG("Invalid bandwidth limit %u\n", node->bandwidth_limit);
+		return 0;
+	}
+
+	shared = node->shared_bandwidth_group;
+	if (!(
+				(shared == QOS_NO_SHARED_BANDWIDTH_GROUP) ||
+				(shared <= QOS_MAX_SHARED_BANDWIDTH_GROUP &&
+				qdev->groups[shared].used)
+	     )) {
+		QOS_LOG("Invalid shared bandwidth group %u\n",
+				node->shared_bandwidth_group);
+		return 0;
+	}
+	return 1;
+}
+
+/*
+ * If new node
+ *     node.child.parent.phy == virtual parent phy
+ * Else
+ *     node.child.parent.phy is either virtual parent phy (if user is changing
+ *     parent) or actual parent (if user is not changing parent)
+ */
+static int child_cfg_valid(
+		const struct pp_qos_dev *qdev,
+		const struct qos_node *node,
+		const struct qos_node *orig_node,
+		unsigned int prev_virt_parent_phy)
+{
+	const struct qos_node *parent;
+	unsigned int tmp;
+	struct qos_node *child;
+	unsigned int parent_phy;
+	unsigned int i;
+	unsigned int bw;
+	unsigned int cur_virt_parent_phy;
+
+	QOS_ASSERT(node_child(node), "node is not a child\n");
+	parent_phy = node->child_prop.parent_phy;
+	if (parent_phy > NUM_OF_NODES - 1) {
+		QOS_LOG("Illegal parent %u\n", parent_phy);
+		return 0;
+	}
+
+	parent =  get_const_node_from_phy(qdev->nodes, parent_phy);
+	if (!node_parent(parent)) {
+		QOS_LOG("Node's parent %u is not a parent\n", parent_phy);
+		return 0;
+	}
+
+	if (parent->parent_prop.arbitration == PP_QOS_ARBITRATION_WSP) {
+		tmp = node->child_prop.priority;
+		if (tmp > QOS_MAX_CHILD_PRIORITY) {
+			QOS_LOG("Illegal node priority %u\n", tmp);
+			return 0;
+		}
+		i = parent->parent_prop.num_of_children;
+
+		if (i == 8) {
+			QOS_LOG("WSP parent can have upto 8 children\n");
+			return 0;
+		} else if (i > 0) {
+			child = get_node_from_phy(
+					qdev->nodes,
+					parent->parent_prop.first_child_phy);
+			for (; i > 0; --i, ++child) {
+				if ((tmp == child->child_prop.priority) &&
+						(orig_node != child)) {
+					QOS_LOG_ERR("Child prio %u exists\n",
+							tmp);
+					return 0;
+				}
+			}
+		}
+	}
+
+	/* Find current virtual parent and bandwidth of its direct children */
+	if (!node_internal(parent))
+		cur_virt_parent_phy = parent_phy;
+	else
+		cur_virt_parent_phy = get_virtual_parent_phy(
+				qdev->nodes,
+				parent);
+
+	bw = get_children_bandwidth_share(qdev,
+			get_node_from_phy(qdev->nodes, cur_virt_parent_phy));
+
+	/*
+	 * If child does not changing its virtual parent than need
+	 * to subtract its bandwidth share, so it will not calculated twice
+	 */
+	if (cur_virt_parent_phy == prev_virt_parent_phy)
+		bw -= node->child_prop.virt_bw_share;
+
+	if (bw + node->child_prop.virt_bw_share  > 100) {
+		QOS_LOG_ERR("Parent already gave %u bandwidth, can't add %u\n",
+			bw, node->child_prop.virt_bw_share);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int parent_cfg_valid(
+		const struct pp_qos_dev *qdev,
+		const struct qos_node *node)
+{
+	unsigned int tmp;
+
+	QOS_ASSERT(node_parent(node), "node is not a parent\n");
+	if (node->parent_prop.num_of_children > 8) {
+		QOS_LOG("node has %u children but max allowed is 8\n",
+				node->parent_prop.num_of_children);
+		return 0;
+	}
+	tmp = node->parent_prop.first_child_phy;
+	if ((node->parent_prop.num_of_children > 0) &&
+	    (tmp <= qdev->max_port || tmp > NUM_OF_NODES - 1)) {
+		QOS_LOG("node has %u children but first child %u is illegal\n",
+			node->parent_prop.num_of_children, tmp);
+		return 0;
+	}
+	return 1;
+}
+
+int node_cfg_valid(
+		const struct pp_qos_dev *qdev,
+		const struct qos_node *node,
+		const struct qos_node *orig_node,
+		unsigned int prev_virt_parent_phy)
+{
+	if (!common_cfg_valid(qdev, node))
+		return 0;
+	if (node_parent(node) && !parent_cfg_valid(qdev, node))
+		return 0;
+	if (node_child(node) &&
+			!child_cfg_valid(qdev, node,
+				orig_node, prev_virt_parent_phy))
+		return 0;
+	return 1;
+}
+
+unsigned int get_virtual_parent_phy(
+		const struct pp_nodes *nodes,
+		const struct qos_node *child)
+{
+	const struct qos_node *tmp;
+	unsigned int phy;
+
+	tmp = child;
+	do {
+		QOS_ASSERT(node_child(tmp), "Node is not a child\n");
+		phy = tmp->child_prop.parent_phy;
+		tmp = get_const_node_from_phy(nodes, phy);
+	} while (node_internal(tmp));
+	return phy;
+}
+
+int get_node_prop(const struct pp_qos_dev *qdev,
+		  const struct qos_node *node,
+		  struct pp_qos_common_node_properties *common,
+		  struct pp_qos_parent_node_properties *parent,
+		  struct pp_qos_child_node_properties *child)
+{
+
+	QOS_ASSERT(node_used(node), "Node is not used\n");
+
+	if (common) {
+		common->suspended =
+			!!QOS_BITS_IS_SET(node->flags,
+					QOS_NODE_FLAGS_SUSPENDED);
+		common->bandwidth_limit = node->bandwidth_limit;
+		common->shared_bandwidth_group = node->shared_bandwidth_group;
+	}
+
+	if (parent) {
+		parent->arbitration = node->parent_prop.arbitration;
+		parent->best_effort_enable =
+			!!QOS_BITS_IS_SET(node->flags,
+					QOS_NODE_FLAGS_PARENT_BEST_EFFORT_ENABLE
+					);
+	}
+
+	if (child) {
+		/*
+		 * Internal schedulers are tranparent to clients. Clients see
+		 * only virtual parent - the first parent in hierarchy which is
+		 * not internal scheduler
+		 */
+		child->parent = get_id_from_phy(qdev->mapping,
+				get_virtual_parent_phy(qdev->nodes, node));
+		child->priority = node->child_prop.priority;
+
+		child->bandwidth_share = node->child_prop.virt_bw_share;
+	}
+
+	return 0;
+}
+
+static int set_common(struct pp_qos_dev *qdev,
+		      struct qos_node *node,
+		      const struct pp_qos_common_node_properties *common,
+		      uint32_t *modified)
+{
+	unsigned int grp_id;
+
+	if (!!(common->suspended) !=
+			!!QOS_BITS_IS_SET(node->flags,
+				QOS_NODE_FLAGS_SUSPENDED)) {
+		QOS_BITS_TOGGLE(node->flags, QOS_NODE_FLAGS_SUSPENDED);
+		QOS_BITS_SET(*modified, QOS_MODIFIED_SUSPENDED);
+	}
+
+	if (node->bandwidth_limit != common->bandwidth_limit) {
+		node->bandwidth_limit = common->bandwidth_limit;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_BANDWIDTH_LIMIT);
+	}
+
+	grp_id = common->shared_bandwidth_group;
+	if (grp_id != node->shared_bandwidth_group) {
+		node->shared_bandwidth_group = grp_id;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_SUSPENDED);
+	}
+	return 0;
+}
+
+static int set_parent(struct pp_qos_dev *qdev,
+		      struct qos_node *node,
+		      const struct pp_qos_parent_node_properties *parent,
+		      uint32_t *modified)
+{
+	if (node->parent_prop.arbitration != parent->arbitration) {
+		node->parent_prop.arbitration = parent->arbitration;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_ARBITRATION);
+	}
+
+	if (!!(parent->best_effort_enable) !=
+			!!QOS_BITS_IS_SET(node->flags,
+				QOS_NODE_FLAGS_PARENT_BEST_EFFORT_ENABLE)) {
+		QOS_BITS_TOGGLE(node->flags,
+				QOS_NODE_FLAGS_PARENT_BEST_EFFORT_ENABLE);
+		QOS_BITS_SET(*modified, QOS_MODIFIED_BEST_EFFORT);
+	}
+	return 0;
+}
+
+
+static int set_child(struct pp_qos_dev *qdev,
+		     struct qos_node *node,
+		     const struct pp_qos_child_node_properties *child,
+		     uint32_t *modified)
+{
+	unsigned int conf_parent_phy;
+	unsigned int virt_parent_phy;
+
+	/* Equals to virtual parent phy since client is not aware of internal
+	 * schedulers, they are transparent to him
+	 */
+	conf_parent_phy = get_phy_from_id(qdev->mapping, child->parent);
+	virt_parent_phy = node->child_prop.parent_phy;
+
+	if (QOS_PHY_VALID(virt_parent_phy))
+		virt_parent_phy = get_virtual_parent_phy(qdev->nodes, node);
+
+	if (virt_parent_phy != conf_parent_phy) {
+		node->child_prop.parent_phy = conf_parent_phy;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_PARENT);
+	}
+
+	if (node->child_prop.priority != child->priority) {
+		node->child_prop.priority = child->priority;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_PRIORITY);
+	}
+
+	if (node->child_prop.virt_bw_share != child->bandwidth_share) {
+		node->child_prop.virt_bw_share = child->bandwidth_share;
+		QOS_BITS_SET(*modified, QOS_MODIFIED_VIRT_BW_SHARE);
+	}
+
+	return 0;
+}
+
+int set_node_prop(struct pp_qos_dev *qdev,
+		  struct qos_node *node,
+		  const struct pp_qos_common_node_properties *common,
+		  const struct pp_qos_parent_node_properties *parent,
+		  const struct pp_qos_child_node_properties *child,
+		  uint32_t *modified)
+{
+	int rc;
+
+	if (common) {
+		rc = set_common(qdev, node, common, modified);
+		if (rc)
+			return rc;
+	}
+	if (parent) {
+		rc = set_parent(qdev, node, parent, modified);
+		if (rc)
+			return rc;
+	}
+	if (child)
+		return set_child(qdev, node, child, modified);
+
+	return 0;
+}
+
+static void node_parent_init(struct qos_node *node)
+{
+	node->parent_prop.first_child_phy = QOS_INVALID_PHY;
+	node->parent_prop.num_of_children = 0;
+	node->parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+}
+
+static void node_child_init(struct qos_node *node)
+{
+	node->child_prop.parent_phy = QOS_INVALID_PHY;
+	node->child_prop.priority = 0;
+	node->child_prop.virt_bw_share = 0;
+}
+
+static void node_common_init(struct qos_node *node)
+{
+	node->flags = 0;
+	node->bandwidth_limit = QOS_NO_BANDWIDTH_LIMIT;
+	node->shared_bandwidth_group = QOS_NO_SHARED_BANDWIDTH_GROUP;
+}
+
+void node_init(const struct pp_qos_dev *qdev,
+	       struct qos_node *node,
+	       unsigned int common,
+	       unsigned int parent,
+	       unsigned int child)
+{
+	memset(node, 0, sizeof(struct qos_node));
+
+	node->type = TYPE_UNKNOWN;
+	if (common)
+		node_common_init(node);
+
+	if (parent)
+		node_parent_init(node);
+
+	if (child)
+		node_child_init(node);
+}
+
+
+/******************************************************************************/
+/*                              ALLOC PHY                                     */
+/******************************************************************************/
+
+
+/**
+ * Return phy where a child whose priority is child_priority should be placed.
+ * If parent is WRR than priority is ignored and the new child will
+ * be given a phy after the current last child
+ *
+ * Assumption: parent's children are held on a non full octet
+ */
+static unsigned int calculate_new_child_location(
+		struct pp_qos_dev *qdev,
+		struct qos_node *parent,
+		unsigned int child_priority)
+{
+	unsigned int phy;
+	struct qos_node *cur;
+	unsigned int i;
+
+	QOS_ASSERT(node_parent(parent), "node is not a parent\n");
+	if (parent->parent_prop.arbitration == PP_QOS_ARBITRATION_WRR) {
+		phy = parent->parent_prop.first_child_phy +
+			parent->parent_prop.num_of_children;
+	} else {
+		i = parent->parent_prop.num_of_children;
+		cur = get_node_from_phy(qdev->nodes,
+				parent->parent_prop.first_child_phy);
+		while ((i > 0) && (cur->child_prop.priority < child_priority)) {
+			--i;
+			++cur;
+		}
+		QOS_ASSERT((i == 0) ||
+				(cur->child_prop.priority != child_priority),
+			   "Trying to add a child with existing priority %u to wsp parent %u\n",
+			   child_priority,
+			   get_phy_from_node(qdev->nodes, parent));
+		phy = get_phy_from_node(qdev->nodes, cur);
+	}
+	return phy;
+}
+
+/**
+ * children_on_non_full_octet() - Allocate a phy for a new child whose siblings
+ * are held on a non full octet.
+ * @qdev:
+ * @parent:
+ * @usage:	    Number of used nodes on children's octet
+ * @child_priority: New child priority (relevant only for WSP parent)
+ * Return:	    New allocated phy
+ */
+static unsigned int children_on_non_full_octet(
+		struct pp_qos_dev *qdev,
+		struct qos_node *parent,
+		unsigned int usage,
+		unsigned int child_priority)
+{
+	unsigned int phy;
+
+	phy = calculate_new_child_location(qdev, parent, child_priority);
+	octet_nodes_shift(qdev, phy, usage - octet_phy_offset(phy), 1);
+	return phy;
+}
+
+static unsigned int children_on_non_full_octet_wrapper(
+		struct pp_qos_dev *qdev,
+		struct qos_node *parent,
+		unsigned int child_priority)
+{
+	unsigned int usage;
+	unsigned int octet;
+
+	QOS_ASSERT(node_parent(parent),
+			"Node %u is not a parent\n",
+			get_phy_from_node(qdev->nodes, parent));
+	octet = octet_of_phy(parent->parent_prop.first_child_phy);
+	usage = octet_get_use_count(qdev->octets, octet);
+	QOS_ASSERT(usage < 8, "Octet is full\n");
+	return children_on_non_full_octet(qdev, parent, usage, child_priority);
+}
+
+/**
+ * has_less_than_8_children_on_full_octet() - Allocate a phy for a new child
+ * are held on a full octet.
+ * @qdev:
+ * @parent:
+ * @children_octet:
+ * @child_priority:
+ * Return: New allocated phy
+ */
+static unsigned int has_less_than_8_children_on_full_octet(
+		struct pp_qos_dev *qdev,
+		struct qos_node *parent,
+		uint8_t children_octet,
+		unsigned int child_priority)
+{
+	struct qos_node *min_parent;
+	unsigned int octet;
+	unsigned int phy;
+	unsigned int num_of_required_entries;
+	unsigned int num_of_nodes_to_move;
+	unsigned int dst_phy;
+	unsigned int src_phy;
+	unsigned int parent_id;
+
+	parent_id = get_id_from_phy(qdev->mapping,
+			get_phy_from_node(qdev->nodes, parent));
+	QOS_ASSERT(octet_get_use_count(qdev->octets, children_octet) == 8,
+			"Octet %d is not full\n", children_octet);
+	min_parent =  octet_get_min_sibling_group(qdev, children_octet,
+			parent, &num_of_required_entries);
+	QOS_ASSERT(min_parent != NULL, "Can't find min_parent for octet %d\n",
+			children_octet);
+	octet = octet_get_with_at_least_free_entries(
+			qdev->octets,
+			num_of_required_entries);
+	if (!QOS_OCTET_VALID(octet)) {
+		QOS_LOG("could not find free octet\n");
+		return QOS_INVALID_PHY;
+	}
+
+	if (parent == min_parent)
+		num_of_nodes_to_move = num_of_required_entries - 1;
+	else
+		num_of_nodes_to_move = num_of_required_entries;
+
+	/* move children of min_parent to new octet */
+	dst_phy = 8 * octet + octet_get_use_count(qdev->octets, octet);
+	src_phy =  min_parent->parent_prop.first_child_phy;
+	nodes_move(qdev, dst_phy, src_phy, num_of_nodes_to_move);
+
+
+	/*
+	 * shift original octet if necessary i.e. if last moved
+	 * node was not last node on octet
+	 */
+	src_phy += num_of_nodes_to_move;
+	if (octet_phy_offset(src_phy - 1) != 7)
+		octet_nodes_shift(qdev, src_phy,
+				8 - octet_phy_offset(src_phy),
+				-num_of_nodes_to_move);
+
+	//min_parent->parent_prop.first_child_phy = dst_phy;
+
+	parent = get_node_from_phy(qdev->nodes,
+			get_phy_from_id(qdev->mapping, parent_id));
+	phy = children_on_non_full_octet_wrapper(qdev, parent, child_priority);
+	return phy;
+}
+
+/**
+ * phy_alloc_parent_has_less_than_8_children() - Allocate a phy
+ * for a new child whose parent has less than 8 children
+ * @qdev:
+ * @parent:
+ * @child_priority:
+ * Return:
+ */
+static unsigned int phy_alloc_parent_has_less_than_8_children(
+		struct pp_qos_dev *qdev,
+		struct qos_node *parent,
+		unsigned int child_priority)
+{
+	unsigned int phy;
+	unsigned int octet;
+	unsigned int usage;
+	unsigned int parent_id;
+
+	QOS_ASSERT(node_parent(parent) &&
+			(parent->parent_prop.num_of_children < 8),
+		   "Node %u is not a parent with less than 8 children\n",
+		   get_phy_from_node(qdev->nodes, parent));
+
+	parent_id = get_id_from_phy(qdev->mapping,
+			get_phy_from_node(qdev->nodes, parent));
+	if (parent->parent_prop.num_of_children == 0) {
+		octet = octet_get_with_at_least_free_entries(qdev->octets, 1);
+		if (!QOS_OCTET_VALID(octet)) {
+			QOS_LOG("could not find free octet\n");
+			return QOS_INVALID_PHY;
+		}
+		phy = octet * 8 + octet_get_use_count(qdev->octets, octet);
+	} else {
+		octet = octet_of_phy(parent->parent_prop.first_child_phy);
+		usage = octet_get_use_count(qdev->octets, octet);
+		if (usage < 8)
+			phy = children_on_non_full_octet(
+					qdev,
+					parent,
+					usage,
+					child_priority);
+		else
+			phy = has_less_than_8_children_on_full_octet(
+					qdev,
+					parent,
+					octet,
+					child_priority);
+	}
+	if (QOS_PHY_VALID(phy))
+		link_with_parent(qdev, phy, parent_id);
+	return phy;
+}
+
+/**
+ * create_internal_scheduler_on_node() - Create internal scheduler
+ * The original node is moved to another octet (which has at least 2 free slots
+ * and can accommodate the original node and a new child) and becomes a child of
+ * the created internal scheduler
+ * @qdev:
+ * @node: The node where the internal scheduler should be placed
+ * Return:
+ */
+static unsigned int create_internal_scheduler_on_node(
+		struct pp_qos_dev *qdev,
+		struct qos_node *node)
+{
+	struct qos_node *new_node;
+	unsigned int octet;
+	unsigned int new_phy;
+	unsigned int phy;
+	unsigned int id;
+	uint32_t modified;
+	struct pp_qos_sched_conf conf;
+
+	octet = octet_get_with_at_least_free_entries(qdev->octets, 2);
+	if (!QOS_OCTET_VALID(octet)) {
+		QOS_LOG("could not find free octet\n");
+		return  QOS_INVALID_PHY;
+	}
+
+	/*
+	 * The assertion on nodes_move especially the one that states
+	 * that if a child is moved to another octet than its siblings must
+	 * move also, prevents using move in this clone scenario
+	 */
+
+	/* find a place for a new node */
+	new_phy = octet * 8 + octet_get_use_count(qdev->octets, octet);
+	QOS_ASSERT(QOS_PHY_VALID(new_phy + 1),
+			"%u is not a valid phy\n", new_phy + 1);
+	new_node = get_node_from_phy(qdev->nodes, new_phy);
+	QOS_ASSERT(!node_used(new_node), "Node is used\n");
+	nodes_modify_used_status(qdev, new_phy, 1, 1);
+
+	/* update children to point to new node */
+	phy = get_phy_from_node(qdev->nodes, node);
+	id = get_id_from_phy(qdev->mapping, phy);
+	map_id_phy(qdev->mapping, id, new_phy);
+	if (node_parent(node))
+		node_update_children(qdev,
+				get_phy_from_node(qdev->nodes, node),
+				new_phy);
+	memcpy(new_node, node, sizeof(struct qos_node));
+	new_node->child_prop.parent_phy = phy;
+	create_move_cmd(qdev, new_phy, phy, get_port(qdev->nodes, new_phy));
+
+	/* virtual bw share and parent_phy remain */
+	node->flags = 0;
+	QOS_BITS_SET(node->flags,
+			QOS_NODE_FLAGS_USED | QOS_NODE_FLAGS_INTERNAL);
+	node->type = TYPE_SCHED;
+	node->parent_prop.arbitration = PP_QOS_ARBITRATION_WRR;
+	node->parent_prop.num_of_children = 1;
+	node->parent_prop.first_child_phy = new_phy;
+	id = pp_pool_get(qdev->ids);
+	QOS_ASSERT(QOS_ID_VALID(id), "Got invalid id\n");
+	map_id_phy(qdev->mapping, id, phy);
+
+	get_node_prop(qdev, node, &conf.common_prop,
+			&conf.sched_parent_prop,
+			&conf.sched_child_prop);
+	modified = 0;
+	QOS_BITS_SET(modified,
+			QOS_MODIFIED_NODE_TYPE | QOS_MODIFIED_SUSPENDED |
+			QOS_MODIFIED_BANDWIDTH_LIMIT |
+			QOS_MODIFIED_SHARED_GROUP_LIMIT |
+			QOS_MODIFIED_PRIORITY | QOS_MODIFIED_VIRT_BW_SHARE |
+			QOS_MODIFIED_PARENT | QOS_MODIFIED_ARBITRATION |
+			QOS_MODIFIED_BEST_EFFORT);
+
+	create_set_sched_cmd(qdev, &conf, phy,
+			node->child_prop.parent_phy, modified);
+
+	/* The new node will be put right after the moved node */
+	++new_phy;
+	link_with_parent(qdev, new_phy, id);
+
+	tree_update_predecessors(qdev, phy);
+
+	return new_phy;
+}
+
+/**
+ * phy_alloc_for_new_child_parent_has_8_children() - Allocate a phy for a new
+ * child whose parent has 8 children
+ * @qdev:
+ * @parent:
+ * Return:
+ */
+static unsigned int phy_alloc_for_new_child_parent_has_8_children(
+		struct pp_qos_dev *qdev,
+		struct qos_node *parent)
+{
+	unsigned int first_phy;
+	struct qos_node *child;
+	struct qos_node *last_child;
+	unsigned int phy;
+	unsigned int parent_phy;
+	unsigned int i;
+
+	phy = QOS_INVALID_PHY;
+
+	QOS_ASSERT(node_parent(parent) &&
+		   (parent->parent_prop.num_of_children == 8) &&
+		   (parent->parent_prop.arbitration == PP_QOS_ARBITRATION_WRR),
+		   "Node %u is not a WRR parent with 8 children\n",
+		   get_phy_from_node(qdev->nodes, parent));
+
+	first_phy = parent->parent_prop.first_child_phy;
+	child = get_node_from_phy(qdev->nodes, first_phy);
+	last_child = child + 7;
+	for (; child <= last_child; ++child) {
+		if (node_internal(child) &&
+				(child->parent_prop.num_of_children < 8)) {
+			return
+				phy_alloc_parent_has_less_than_8_children(
+					qdev,
+					child,
+					QOS_INVALID_PRIORITY);
+		}
+	}
+
+	child = get_node_from_phy(qdev->nodes, first_phy);
+	while (child < last_child && node_internal(child))
+		++child;
+	if (!node_internal(child))
+		return create_internal_scheduler_on_node(qdev, child);
+
+	/*
+	 * If we reach this point all children are full internal schedulers
+	 * We will do a breadth first traversal on the tree i.e. look for a
+	 * place for the child under the internal schedulers children of the
+	 * parent. For this we will need a queue
+	 */
+	for (i = 0; i < 8; ++i) {
+		if (pp_queue_enqueue(qdev->queue, first_phy + i)) {
+			QOS_LOG("Queue is full\n");
+			return QOS_INVALID_PHY;
+		}
+	}
+
+	parent_phy = pp_queue_dequeue(qdev->queue);
+	while (QOS_PHY_VALID(parent_phy)) {
+		phy = phy_alloc_for_new_child_parent_has_8_children(
+				qdev,
+				get_node_from_phy(qdev->nodes, parent_phy));
+		if (QOS_PHY_VALID(phy))
+			return phy;
+	}
+
+	return phy;
+}
+
+unsigned int phy_alloc_by_parent(
+		struct pp_qos_dev *qdev,
+		struct qos_node *parent,
+		unsigned int child_priority)
+{
+	unsigned int phy;
+
+	if (parent->parent_prop.num_of_children < 8) {
+		phy =  phy_alloc_parent_has_less_than_8_children(
+				qdev,
+				parent,
+				child_priority);
+	} else {
+		pp_queue_reset(qdev->queue);
+		phy =  phy_alloc_for_new_child_parent_has_8_children(qdev,
+				parent);
+	}
+
+	return phy;
+}
+
diff --git a/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_utils.h b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_utils.h
new file mode 100644
index 0000000000000000000000000000000000000000..5572940fbb176f5f2bcb17e171f8b4f2085c2e42
--- /dev/null
+++ b/drivers/net/ethernet/lantiq/ppv4/qos/pp_qos_utils.h
@@ -0,0 +1,675 @@
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+#ifndef PP_QOS_UTILS_H
+#define PP_QOS_UTILS_H
+
+#include "pp_qos_common.h"
+#include "pp_qos_drv.h"
+
+/******************************************************************************/
+/*                              CONF                                          */
+/******************************************************************************/
+#define PPV4_QOS_DRV_VER "1.0.0-fl"
+
+#define NUM_OF_NODES	2048U
+#define NUM_OF_QUEUES	256U
+#define NUM_OF_OCTETS (NUM_OF_NODES / 8)
+#define QOS_MAX_SHARED_BW_GRP QOS_MAX_SHARED_BANDWIDTH_GROUP
+
+#define MAX_QOS_INSTANCES 1U
+
+/* for calculating number of ddr pages for qm from resource size */
+#define PPV4_QOS_PAGE_SIZE (4096U)
+#define PPV4_QOS_QM_BUF_SIZE (PPV4_QOS_PAGE_SIZE * 100)
+
+#define PPV4_QOS_LOGGER_MSG_SIZE (128U)
+#define PPV4_QOS_LOGGER_BUF_SIZE (PPV4_QOS_LOGGER_MSG_SIZE * 1024U)
+#define PPV4_QOS_STAT_SIZE	(1024U)
+
+#define PPV4_QOS_IVT_START (0x48000U)
+
+#define FIRMWARE_FILE "ppv4-qos-fw.bin"
+/******************************************************************************/
+/*                              DEFINES                                       */
+/******************************************************************************/
+
+#define QOS_INVALID_OCTET   0xFFFFU
+#define QOS_INVALID_ID      0xFFFFU
+#define QOS_INVALID_RLM     0xFFFFU
+#define QOS_INVALID_PHY     0xFFFFU
+#define QOS_UNKNOWN_PHY     0xFFFEU
+
+#define QOS_OCTET_VALID(octet)	((octet) < NUM_OF_OCTETS)
+#define QOS_ID_VALID(id)	((id) < NUM_OF_NODES)
+#define QOS_PHY_VALID(phy)	((phy) < NUM_OF_NODES)
+#define QOS_PHY_UNKNOWN(phy)	((phy) == QOS_UNKNOWN_PHY)
+#define QOS_BW_GRP_VALID(id)	((id) && ((id) <= QOS_MAX_SHARED_BW_GRP))
+
+#define QOS_MODIFIED_NODE_TYPE			BIT(0)
+#define QOS_MODIFIED_SUSPENDED			BIT(1)
+#define QOS_MODIFIED_BANDWIDTH_LIMIT		BIT(2)
+#define QOS_MODIFIED_SHARED_GROUP_LIMIT		BIT(3)
+#define QOS_MODIFIED_ARBITRATION		BIT(5)
+#define QOS_MODIFIED_BEST_EFFORT		BIT(6)
+#define QOS_MODIFIED_PRIORITY			BIT(7)
+#define QOS_MODIFIED_VIRT_BW_SHARE		BIT(8)
+#define QOS_MODIFIED_PARENT			BIT(9)
+#define QOS_MODIFIED_RING_ADDRESS		BIT(10)
+#define QOS_MODIFIED_RING_SIZE			BIT(11)
+#define QOS_MODIFIED_CREDIT			BIT(12)
+#define QOS_MODIFIED_MAX_BURST			BIT(15)
+#define QOS_MODIFIED_BLOCKED			BIT(16)
+#define QOS_MODIFIED_WRED_ENABLE		BIT(17)
+#define QOS_MODIFIED_WRED_MIN_GREEN		BIT(18)
+#define QOS_MODIFIED_WRED_MAX_GREEN		BIT(19)
+#define QOS_MODIFIED_WRED_SLOPE_GREEN		BIT(20)
+#define QOS_MODIFIED_WRED_MIN_YELLOW		BIT(21)
+#define QOS_MODIFIED_WRED_MAX_YELLOW		BIT(22)
+#define QOS_MODIFIED_WRED_SLOPE_YELLOW		BIT(23)
+#define QOS_MODIFIED_WRED_MAX_ALLOWED		BIT(24)
+#define QOS_MODIFIED_WRED_MIN_GUARANTEED	BIT(25)
+#define QOS_MODIFIED_RLM			BIT(26)
+#define QOS_MODIFIED_WRED_FIXED_DROP_PROB_ENABLE	BIT(27)
+#define QOS_MODIFIED_WRED_FIXED_GREEN_PROB	BIT(28)
+#define QOS_MODIFIED_WRED_FIXED_YELLOW_PROB	BIT(29)
+
+
+/******************************************************************************/
+/*                              TYPES                                         */
+/******************************************************************************/
+
+#define NODE_TYPE(OP)		\
+	OP(TYPE_UNKNOWN)	\
+	OP(TYPE_PORT)		\
+	OP(TYPE_SCHED)		\
+	OP(TYPE_QUEUE)
+
+enum node_type {
+	NODE_TYPE(GEN_ENUM)
+};
+
+struct child_node_properties {
+	uint16_t	parent_phy;
+	uint8_t		priority;
+	uint8_t		virt_bw_share;
+};
+
+struct parent_node_properties {
+	enum pp_qos_arbitration		arbitration;
+	uint16_t			first_child_phy;
+	uint8_t				num_of_children;
+};
+
+struct qos_node {
+	enum node_type			type;
+	uint16_t			bandwidth_limit;
+	uint16_t			shared_bandwidth_group;
+	struct child_node_properties	child_prop;
+	struct parent_node_properties	parent_prop;
+	union _data {
+		struct {
+			void		*ring_address;
+			size_t		ring_size;
+			unsigned int	credit;
+		} port;
+		struct {
+		} sched;
+		struct _queue {
+			uint32_t	green_min;
+			uint32_t	green_max;
+			uint32_t	yellow_min;
+			uint32_t	yellow_max;
+			uint32_t	max_allowed;
+			uint32_t	min_guaranteed;
+			uint32_t	fixed_green_prob;
+			uint32_t	fixed_yellow_prob;
+			uint16_t	max_burst;
+			uint16_t	rlm;
+			uint8_t		green_slope;
+			uint8_t		yellow_slope;
+		} queue;
+	} data;
+
+#define QOS_NODE_FLAGS_USED					BIT(0)
+#define QOS_NODE_FLAGS_INTERNAL					BIT(1)
+#define QOS_NODE_FLAGS_SUSPENDED				BIT(3)
+#define QOS_NODE_FLAGS_PARENT_BEST_EFFORT_ENABLE		BIT(4)
+#define QOS_NODE_FLAGS_PORT_PACKET_CREDIT_ENABLE		BIT(7)
+#define QOS_NODE_FLAGS_PORT_BYTE_CREDIT_ENABLE			BIT(8)
+#define QOS_NODE_FLAGS_QUEUE_WRED_ENABLE			BIT(10)
+#define QOS_NODE_FLAGS_QUEUE_BLOCKED				BIT(11)
+#define QOS_NODE_FLAGS_QUEUE_WRED_FIXED_DROP_PROB_ENABLE	BIT(12)
+	uint16_t	flags;
+};
+
+
+struct shared_bandwidth_group {
+	uint8_t		used;
+	uint8_t		reserved;
+	uint16_t	limit;
+};
+
+struct driver_cmds {
+	struct cmd_queue	*cmdq;
+	struct cmd_queue	*pendq;
+	unsigned int		cmd_id;
+	unsigned int		cmd_fw_id;
+};
+
+/* Communication to/from FW */
+struct fw_com {
+	void		*cmdbuf;
+	size_t		cmdbuf_sz;
+	uint32_t	*mems;
+	size_t		mems_size;
+	void __iomem	*mbx_to_uc;
+	void __iomem	*mbx_from_uc;
+	unsigned int	irqline;
+};
+
+/* HW configuration */
+struct hw_conf {
+	unsigned int	wred_total_avail_resources;
+	unsigned int	wred_prioritize_pop;
+	unsigned int	wred_const_p;
+	unsigned int	wred_max_q_size;
+	unsigned int	qm_ddr_start;
+	unsigned int	qm_num_pages;
+	unsigned int	fw_logger_start;
+	unsigned int	fw_stat;
+};
+
+struct fw_ver {
+	unsigned int major;
+	unsigned int minor;
+	unsigned int build;
+};
+
+struct pp_qos_dev {
+	LOCK				lock;
+	int				initialized;
+	unsigned int			max_port;
+	unsigned int			reserved_ports[MAX_PORTS];
+	struct shared_bandwidth_group	groups[QOS_MAX_SHARED_BW_GRP + 1];
+	struct pp_pool			*ids;
+	struct pp_pool			*rlms;
+	struct pp_pool			*portsphys;
+	struct pp_nodes			*nodes;
+	struct pp_mapping		*mapping;
+	struct pp_octets		*octets;
+	struct pp_queue			*queue;
+	struct driver_cmds		drvcmds;
+	struct fw_com			fwcom;
+	struct fw_ver			fwver;
+	void				*fwbuf;
+	struct hw_conf			hwconf;
+	void				*pdev;
+	void				*stat;
+#define PP_QOS_FLAGS_ASSERT		0x1U
+	unsigned int			flags;
+};
+
+#define PP_QOS_DEVICE_IS_ASSERT(qdev)\
+	(QOS_BITS_IS_SET((qdev)->flags, PP_QOS_FLAGS_ASSERT))
+
+/* Info from platform statically or device tree */
+struct ppv4_qos_platform_data  {
+	int		id;
+	unsigned int	max_port;
+	unsigned int	wred_prioritize_pop;
+	unsigned int	qm_ddr_start;
+	unsigned int	qm_num_pages;
+	unsigned int	fw_logger_start;
+	unsigned int	fw_stat;
+};
+
+/* Info needed to create descriptor */
+struct qos_dev_init_info {
+	struct ppv4_qos_platform_data pl_data;
+	struct fw_com fwcom;
+};
+
+
+/******************************************************************************/
+/*                              UTILS                                         */
+/******************************************************************************/
+#define QOS_LOG(format, arg...) QOS_LOG_DEBUG(format, ##arg)
+void stop_run(void);
+#define QOS_ASSERT(condition, format, arg...)				\
+do {									\
+	if (!(condition)) {						\
+		QOS_LOG_CRIT("!!! Assertion failed !!! on %s:%d: " format,\
+		__func__, __LINE__, ##arg);				\
+		stop_run();						\
+	}								\
+} while (0)
+
+#define QOS_BITS_SET(flags, bits)	((flags) |= (bits))
+#define QOS_BITS_CLEAR(flags, bits)	((flags) &= ~(bits))
+#define QOS_BITS_TOGGLE(flags, bits)	((flags) ^= (bits))
+#define QOS_BITS_IS_SET(flags, bits)	((flags) & (bits))
+
+
+/*
+ * Phy octet mapping
+ */
+static inline int octet_of_phy(unsigned int phy)
+{
+	QOS_ASSERT(QOS_PHY_VALID(phy), "Invalid phy %u\n", phy);
+	return (phy >> 3);
+}
+
+/*
+ * Offset of phy on octet (0..7)
+ */
+static inline int octet_phy_offset(unsigned int phy)
+{
+	QOS_ASSERT(QOS_PHY_VALID(phy), "Invalid phy %u\n", phy);
+	return (phy & 0x7);
+}
+
+/*
+ * Return true iff both phys are on same octet
+ */
+static inline int same_octet(unsigned int first_phy, unsigned int second_phy)
+{
+	return octet_of_phy(first_phy) == octet_of_phy(second_phy);
+}
+
+/*
+ * Predicates on nodes
+ */
+static inline int node_used(const struct qos_node *node)
+{
+	return QOS_BITS_IS_SET(node->flags, QOS_NODE_FLAGS_USED);
+}
+
+static inline int node_internal(const struct qos_node *node)
+{
+	return node_used(node) && QOS_BITS_IS_SET(node->flags,
+						  QOS_NODE_FLAGS_INTERNAL);
+}
+
+static inline int node_suspended(const struct qos_node *node)
+{
+	return node_used(node) && QOS_BITS_IS_SET(node->flags,
+			QOS_NODE_FLAGS_SUSPENDED);
+}
+
+static inline int node_child(const struct qos_node *node)
+{
+	return node_used(node) && (node->type == TYPE_SCHED ||
+				   node->type == TYPE_QUEUE);
+}
+
+static inline int node_parent(const struct qos_node *node)
+{
+	return node_used(node) && (node->type == TYPE_SCHED ||
+				   node->type == TYPE_PORT);
+}
+
+static inline int node_port(const struct qos_node *node)
+{
+	return node_used(node) && (node->type == TYPE_PORT);
+}
+
+static inline int node_sched(const struct qos_node *node)
+{
+	return node_used(node) && (node->type == TYPE_SCHED);
+}
+
+static inline int node_queue(const struct qos_node *node)
+{
+	return node_used(node) && (node->type == TYPE_QUEUE);
+}
+
+/*
+ * Id and phy mapping
+ */
+unsigned int get_id_from_phy(const struct pp_mapping *map, unsigned int phy);
+unsigned int get_phy_from_id(const struct pp_mapping *map, unsigned int id);
+
+/* Map id <==> phy */
+void map_id_phy(struct pp_mapping *map, unsigned int id, unsigned int phy);
+
+/* Map id ==>  QOS_UNKNOWN_PHY */
+void map_id_reserved(struct pp_mapping *map, unsigned int id);
+
+/* Invalidate both the id and the phy that is currently mapped to it */
+void map_invalidate_id(struct pp_mapping *map, unsigned int id);
+
+/*
+ * Phy node mapping
+ */
+struct qos_node *get_node_from_phy(struct pp_nodes *nodes, unsigned int phy);
+const struct qos_node *get_const_node_from_phy(const struct pp_nodes *nodes,
+					       unsigned int phy);
+unsigned int get_phy_from_node(const struct pp_nodes *nodes,
+		      const struct qos_node *node);
+
+/*
+ * Queue of uint16_t data.
+ * Data is dequeued from queue's head and enqueued into its tail
+ */
+/* return head of queue or QOS_INVALID_ID if queue is empty */
+uint16_t pp_queue_dequeue(struct pp_queue *queue);
+
+/* return 0 on success -1 if queue is full */
+int pp_queue_enqueue(struct pp_queue *queue, uint16_t data);
+
+/* empty queue */
+void pp_queue_reset(struct pp_queue *queue);
+
+/*
+ * Pool (stack) of uint16_t data
+ */
+uint16_t pp_pool_get(struct pp_pool *pool);
+int pp_pool_put(struct pp_pool *pool, uint16_t data);
+
+/*
+ * Cyclic buffer
+ */
+/*
+ * Copy size bytes from buffer to command,
+ * return 0 on success, -1 if there are less than size bytes
+ * in buffer.
+ * get remove read bytes from buffer while peek not
+ */
+int cmd_queue_get(struct cmd_queue *q, void *cmd, size_t size);
+int cmd_queue_peek(struct cmd_queue *q, void *_cmd, size_t size);
+int cmd_queue_is_empty(struct cmd_queue *q);
+
+/*
+ * Copy size bytes into cyclic buffer
+ * return 0 on success, -1 if buffer has no for size bytes
+ */
+int cmd_queue_put(struct cmd_queue *q, void *cmd, size_t size);
+
+/*
+ * Octets manipulation
+ */
+
+/**
+ * octet_get_with_at_least_free_entries() - find an octet with free entries.
+ * @octets:
+ * @count: The minimum number of free entries the octet should have
+ * Return: an octet which satisfies the following:
+ *  - It has at least count free entries
+ *  - No other octet that satisfies the previous condition has less free entries
+ *    than this octet
+ *
+ * If no such octet is found QOS_INVALID_OCTET is returned
+ *
+ * Note octet is removed from container, user should call
+ * to octet_set_use_count (or nodes_move/octet_nodes_shift which call it) to
+ * return it
+ */
+unsigned int octet_get_with_at_least_free_entries(struct pp_octets *octets,
+						  unsigned int count);
+
+/**
+ * octet_get_least_free_entries() - The octet that has the least free entries
+ * @octets:
+ * Return:
+ *
+ * Note octet is removed from container, user should call
+ * to octet_set_use_count (or nodes_move/octet_nodes_shift which call it) to
+ * return it
+ */
+unsigned int octet_get_least_free_entries(struct pp_octets *octets);
+
+/*
+ * Initialize qos dev, max port designates phy of highest port
+ */
+struct pp_qos_dev *_qos_init(unsigned int max_port);
+void _qos_clean(struct pp_qos_dev *qdev);
+
+/*
+ * Create qos dev with hardware parameters
+ */
+struct pp_qos_dev *create_qos_dev_desc(struct qos_dev_init_info *initinfo);
+
+/**
+ * octet_get_min_sibling_group() - Find "min parent" - a parent with least
+ * children on octet
+ * @qdev:
+ * @octet:
+ * @spc_parent:      The number of children for this parent is increased by one
+ *                   only for the sake of finding the "min parent"
+ * @num_of_children: Holds the number of children of "min parent"
+ * Return:	     The min parent, or NULL if octet is empty
+ *
+ * Note If several parents hold the same number of children on the octet the
+ * first is returned
+ *
+ */
+struct qos_node *octet_get_min_sibling_group(const struct pp_qos_dev *qdev,
+					     unsigned int octet,
+					     const struct qos_node *spc_parent,
+					     unsigned int *num_of_children);
+
+/**
+ * nodes_modify_used_status() - Set/Clear node's use status
+ * @qdev:
+ * @first_phy: First node's phy
+ * @count:     Number of nodes
+ * @status:    Desired status (0/1)
+ */
+void nodes_modify_used_status(struct pp_qos_dev *qdev, unsigned int first_phy,
+			      unsigned int count, unsigned int status);
+
+
+/*
+ * Remove node
+ */
+/* remove node and free its resources, assume node has no children */
+int node_remove(struct pp_qos_dev *qdev, struct qos_node *node);
+/*
+ * mark the node unused, update parents, id and rlm are not freed.
+ * assume node has no children
+ */
+void node_phy_delete(struct pp_qos_dev *qdev, unsigned int phy);
+
+void release_rlm(struct pp_pool *rlms, unsigned int rlm);
+
+int node_flush(struct pp_qos_dev *qdev, struct qos_node *node);
+
+/**
+ * node_cfg_valid() - check if node configuration is valid
+ * The process of modifying a node involves cloning orig node to
+ * temporary node, making the modification on this temporary node
+ * according to new configuration requested by user
+ * and check the validity of the result, if its valid than copy temporary node
+ * to orig node.
+ *
+ * @qdev:
+ * @node: The temporary node whose configuration should be checked
+ * @orig_node: original node from which node was copied from, NULL if new node
+ * @prev_virt_parenti_phy: phy of prev virtual parent
+ * Return: 1 if configuration is valid, 0 if not
+ */
+int node_cfg_valid(const struct pp_qos_dev *qdev,
+		   const struct qos_node *node,
+		   const struct qos_node *orig_node,
+		   unsigned int prev_virt_parent_phy);
+
+int get_node_prop(const struct pp_qos_dev *qdev,
+		  const struct qos_node *node,
+		  struct pp_qos_common_node_properties *common,
+		  struct pp_qos_parent_node_properties *parent,
+		  struct pp_qos_child_node_properties *child);
+
+int set_node_prop(struct pp_qos_dev *qdev,
+		  struct qos_node *node,
+		  const struct pp_qos_common_node_properties *common,
+		  const struct pp_qos_parent_node_properties *parent,
+		  const struct pp_qos_child_node_properties *child,
+		  uint32_t *modified);
+
+/*
+ * Init node with default values
+ * common, parent and child dictate which
+ * components of node should be initialized
+ */
+void node_init(const struct pp_qos_dev *qdev,
+	       struct qos_node *node,
+	       unsigned int common,
+	       unsigned int parent,
+	       unsigned int child);
+/**
+ * get_node_queues() - Return all queues on a subtree
+ * @qdev:
+ * @phy:       Phy of subtree's node
+ * @queue_ids: Array to store the queues ids - may be NULL
+ * @size:      Size of array - may be 0
+ * @queues_num: The number of queues on the subtree
+ */
+void get_node_queues(struct pp_qos_dev *qdev, unsigned int phy,
+		     uint16_t *queue_ids,
+		     unsigned int size, unsigned int *queues_num);
+
+/**
+ * phy_alloc_by_parent() - Allocate new phy for a node
+ * @qdev:
+ * @parent:          Node's parent
+ * @child_priority:  Relevant only for WSP parent
+ * Return:
+ */
+unsigned int phy_alloc_by_parent(struct pp_qos_dev *qdev,
+				 struct qos_node *parent,
+				 unsigned int child_priority);
+
+/* Return the first non internal ancestor of a node */
+unsigned int get_virtual_parent_phy(const struct pp_nodes *nodes,
+				    const struct qos_node *child);
+
+void node_update_children(struct pp_qos_dev *qdev,
+				 unsigned int phy,
+				 unsigned int new_phy);
+
+void tree_update_predecessors(struct pp_qos_dev *qdev, unsigned int phy);
+/*
+ * Assume that sched is internal scheduler
+ * 1. Update sched's virtual bandwidth share to be the sum of its
+ *    children's share.
+ * 2. If sched's parent is also internal scheduler
+ *    update its virtual bandwidth share also to be the update
+ *    bw share sum of its children. And keep doing that
+ *    up the tree hirarchy so long parent is an internal scheduler
+ * 3. For each
+ */
+void update_internal_bandwidth(const struct pp_qos_dev *qdev,
+			       struct qos_node *sched);
+
+/* Remove all nodes (including root) of a subtree */
+int tree_remove(struct pp_qos_dev *qdev, unsigned int phy);
+
+/* Flush all nodes (including root) of a subtree */
+int tree_flush(struct pp_qos_dev *qdev, unsigned int phy);
+
+/* Modify blocked status of queues on a subtree */
+int tree_modify_blocked_status(struct pp_qos_dev *qdev,
+			       unsigned int phy,
+			       unsigned int status);
+void get_bw_grp_members_under_node(struct pp_qos_dev *qdev, unsigned int id,
+				   unsigned int phy, uint16_t *ids,
+				   unsigned int size,
+				   unsigned int *ids_num);
+
+/* Creates pool of free ports phys */
+struct pp_pool *free_ports_phys_init(unsigned int *reserved,
+				     unsigned int max_port,
+				     const unsigned int *reserved_ports,
+				     unsigned int size);
+
+/* return the port ancestor of a node */
+static inline unsigned int get_port(const struct pp_nodes *nodes,
+				    unsigned int phy)
+{
+	const struct qos_node *node;
+
+	node = get_const_node_from_phy(nodes, phy);
+	while (node_child(node))
+		node = get_const_node_from_phy(nodes,
+					       node->child_prop.parent_phy);
+
+	QOS_ASSERT(node_port(node), "Did not reach port node for phy %u\n",
+		   phy);
+	return get_phy_from_node(nodes, node);
+}
+
+void qos_module_init(void);
+void remove_qos_instance(unsigned int id);
+int _pp_qos_queue_block(struct pp_qos_dev *qdev, unsigned int id);
+int _pp_qos_queue_unblock(struct pp_qos_dev *qdev, unsigned int id);
+int _pp_qos_queue_flush(struct pp_qos_dev *qdev, unsigned int id);
+void wake_uc(void *data);
+
+#ifdef PP_QOS_TEST
+void test_cmd_queue(void);
+void basic_tests(void);
+void advance_tests(void);
+void reposition_test(void);
+void falcon_test(void);
+void simple_test(void);
+void stat_test(void);
+void info_test(void);
+void load_fw_test(void);
+void tests(void);
+void test_init_instance(struct pp_qos_dev *qdev);
+int add_qos_dev(void);
+void remove_qos_dev(void);
+int port_cfg_valid(const struct pp_qos_dev *qdev, const struct qos_node *node,
+		   const struct qos_node *orig_node);
+int queue_cfg_valid(const struct pp_qos_dev *qdev, const struct qos_node *node,
+		    const struct qos_node *orig_node,
+		    unsigned int prev_virt_parent_phy);
+int sched_cfg_valid(const struct pp_qos_dev *qdev, const struct qos_node *node,
+		    const struct qos_node *orig_node,
+		    unsigned int prev_virt_parent_phy);
+struct pp_octets *octets_init(unsigned int last_port_octet);
+void octets_clean(struct pp_octets *octets);
+void debug_verify_octet_usage(struct pp_octets *octets, unsigned int octet,
+			      unsigned int usage);
+void nodes_move(struct pp_qos_dev *qdev, unsigned int dst_phy,
+		unsigned int src_phy, unsigned int count);
+void octet_nodes_shift(struct pp_qos_dev *qdev, unsigned int first_phy,
+		       unsigned int count, int shift);
+unsigned int get_children_bandwidth_share(const struct pp_qos_dev *qdev,
+					  const struct qos_node *parent);
+unsigned int get_virt_children_bandwidth_share(const struct pp_qos_dev *qdev,
+					       const struct qos_node *parent);
+unsigned int get_children_bandwidth_share(const struct pp_qos_dev *qdev,
+					  const struct qos_node *parent);
+void transmit_cmds(struct pp_qos_dev *qdev);
+void update_cmd_id(struct driver_cmds *drvcmds);
+#define STATIC_UNLESS_TEST
+#else
+#define STATIC_UNLESS_TEST static
+#endif
+
+#endif
diff --git a/include/net/datapath_api.h b/include/net/datapath_api.h
index f7d58ae1a6d3b2869940bd62ade2181ff1ab5b83..61e6d54aeff043df1d625c31bd879ede05fba353 100644
--- a/include/net/datapath_api.h
+++ b/include/net/datapath_api.h
@@ -26,6 +26,7 @@
 #include <net/switch_api/lantiq_gsw_flow.h>
 #include <net/switch_api/lantiq_gsw.h>
 #include <net/switch_api/gsw_dev.h>
+#include <net/switch_api/gsw_flow_ops.h>
 #ifdef CONFIG_LTQ_DATAPATH_CPUFREQ
 #include <linux/cpufreq.h>
 #include <cpufreq/ltq_cpufreq.h>
@@ -247,6 +248,13 @@ typedef struct dp_subif {
 
 typedef dp_subif_t PPA_SUBIF; /*!< @brief structure type dp_subif PPA_SUBIF*/
 
+struct vlan_prop {
+	u8 num;
+	u16 out_proto, out_vid;
+	u16 in_proto, in_vid;
+	struct net_device *base;
+};
+
 /*! @brief struct for dp_drv_mib */
 typedef struct dp_drv_mib {
 	u64 rx_drop_pkts;  /*!< rx drop pkts */
@@ -560,7 +568,7 @@ enum DP_SUBIF_DATA_FLAG {
 
 /*! @brief struct dp_subif_data */
 struct dp_subif_data {
-	s8 deq_port_idx;  /*!< [in]
+	s8 deq_port_idx;  /*!< [in] range: 0 ~ its max deq_port_num - 1
 			   *  For PON, it is tcont_idx,
 			   *  For other device, normally its value is zero
 			   */
diff --git a/include/net/datapath_api_qos.h b/include/net/datapath_api_qos.h
index a765d8c6103510f84d1b11356aacfeffefe5d73d..80312f0bca92238c8969a5f13abff9496aaa0764 100644
--- a/include/net/datapath_api_qos.h
+++ b/include/net/datapath_api_qos.h
@@ -326,7 +326,7 @@
 #ifndef DP_QOS_API_H
 #define DP_QOS_API_H
 
-#define DP_MAX_SCH_LVL  4 /*!< @brief max number of hierarchy QOS layers
+#define DP_MAX_SCH_LVL  3 /*!< @brief max number of hierarchy QOS layers
 			   *   supported.
 			   *  can change MACRO for more layers
 			   */
@@ -340,9 +340,10 @@
 
 /*! @brief QOS Link Node Type: Queue, scheduler and dequeue port*/
 enum dp_node_type {
-	DP_NODE_QUEUE = 0, /*!< queue node*/
+	DP_NODE_UNKNOWN = 0,  /*!< Unallocated node*/
+	DP_NODE_QUEUE,  /*!< queue node*/
 	DP_NODE_SCH,   /*!< scheduler node*/
-	DP_NODE_PORT,   /*!< port node*/
+	DP_NODE_PORT   /*!< port node*/
 };
 
 /*! @brief QOS Link Node ID:
@@ -361,9 +362,18 @@ union dp_node_id {
 
 /*! @brief node flag to enable/disable/keep current setting */
 enum dp_node_en {
-	DP_NODE_DIS = 0,  /*!< disable node */
-	DP_NODE_EN,       /*!< enable node */
-	DP_NODE_NO_CHANGE /*!< keep exiting enable status */
+	DP_NODE_DIS = BIT(0),     /*!< disable node:drop new incoming pkt
+				   *   for ppv4, valid queue/port only
+				   */
+	DP_NODE_EN = BIT(1),      /*!< enable node:allow to enqueue
+				   *   for ppv4, valid queue/port only
+				   */
+	DP_NODE_SUSPEND = BIT(2), /*!< Suspend this node no scheduling:Not for TMU
+				   *   for ppv4, valid queue/sched/port
+				   */
+	DP_NODE_RESUME = BIT(3)   /*!< Resume scheduling for this node:Not for TMU
+				   *   for ppv4, valid queue/sched/port
+				   */
 };
 
 /*! @brief arbitration method used for the node in its parents scheduler/ports*/
@@ -432,7 +442,7 @@ struct dp_node_link {
 	union dp_node_id node_id; /*!< input node id.
 				   *  if id == DP_NODE_AUTO_ID, DP will
 				   *  allocate a free node from the reserved
-				   *  pool or global pool
+				   *  pool or global pool and set node id
 				   */
 
 	enum dp_arbitate arbi;  /*!< <PRE>arbitration method used in its parents
@@ -460,9 +470,19 @@ struct dp_node_link {
 					 *  for dp_node_unlink: no use</PRE>
 					 */
 	union dp_node_id p_node_id; /*!< <PRE>parent id
-				     * for dp_node_link_add: it is in  input
-				     * for dp_node_link_get: it is in  output
-				     * for dp_node_unlink: no use</PRE>
+				     * for dp_node_link_add: it is in input
+				     *   if type is scheduler
+				     *     if id == DP_NODE_AUTO_ID
+				     *        DP will allocate a free node
+				     *        from the reserved or global pool
+				     *        and set p_node_id
+				     *     else use user specified parent id
+				     *   else type is port
+				     *        User must provide valid
+				     *        cqm_deq_port value
+				     * for dp_node_link_get: it is in output
+				     * for dp_node_unlink: no use
+				     * </PRE>
 				     */
 	union dp_node_id cqm_deq_port; /*!< <PRE>input/optional:
 					*  for TMU queue link setup, it is
@@ -508,18 +528,18 @@ int dp_node_link_add(struct dp_node_link *info, int flag);
  *  @note It is used to unlink a specified node or including its full path
  *        depends on the flag set
  * <PRE>
- *  1) if it is to unlik a queue node, DP will do necessary work as below:
+ *  1) if it is to unlink a queue node, DP will do necessary work as below:
  *        re-map the lookup entry to a drop queue
  *        flushing the queue: not including those already dequeue by CQM
  *        disable the queue
- *        unlink the queue node as specified from its parent
- *  2) if it is to unlik a scheduler node, DP will do necessary work as below:
+ *        unlink the queue node as specified from its parent== Not needed?
+ *  2) if it is to unlink a scheduler node, DP will do necessary work as below:
  *       a) if there is still child linked to this scheduler yet
  *             i) without flag DP_NODE_SMART_UNLINK set:
  *                   return DP_FAILURE
  *             ii) with flag DP_NODE_SMART_UNLINK set:
- *                   unlink its all child first,
- *                   then unlink this node as specified.
+ *                   unlink its all child first,== Not needed?
+ *                   then unlink this node as specified.== Not needed?
  *  Note:
        a) This API only unlik the node from the QOS setup by default, but the
  *        node itself is not freed.
@@ -712,7 +732,7 @@ enum dp_q_size_unit {
 struct dp_queue_conf {
 	int inst; /*!< input: dp instance. For SOC side, it is always zero */
 	int q_id; /*!< input: q_id */
-	enum dp_node_en act;  /*!< enable/disable/ queue */
+	enum dp_node_en act;  /*!< enable/disable/suspend/resume queue */
 	enum dp_q_drop_mode drop; /*!< TMU: wred/tail drop, how about PP?? */
 	enum dp_q_size_unit unit; /*!< queue size unit:packet/bytes */
 	u32 min_size[DP_MAX_COLORS]; /*!< queue minimal size, If QOCC less than
@@ -747,9 +767,9 @@ int dp_queue_conf_get(struct dp_queue_conf *cfg, int flag);
 
 /*! @brief enum dp_shaper_cmd */
 enum dp_shaper_cmd {
-	dp_shaper_cmd_ADD = 0, /*!< add shaper */
-	dp_shaper_cmd_REMOVE,  /*!< remove shaper */
-	dp_shaper_cmd_DISABLE, /*!< disable the shaper: no limit*/
+	DP_SHAPER_CMD_ADD = 0, /*!< add shaper */
+	DP_SHAPER_CMD_REMOVE,  /*!< remove shaper */
+	DP_SHAPER_CMD_DISABLE, /*!< disable the shaper: no limit*/
 };
 
 /*! @brief dp_shaper_conf */
@@ -797,7 +817,7 @@ struct dp_node_alloc {
 			       *  its reserved pool
 			       *  otherwise provided by the caller itself.</PRE>
 			       */
-	int cqm_dq_port; /*Added for qos slim driver only*/
+	//int cqm_dq_port; /*Added for qos slim driver only*/
 };
 
 /*! \ingroup APIs_dp_node_alloc
@@ -821,6 +841,7 @@ int dp_node_free(struct dp_node_alloc *node, int flag);
 /*! @brief dp_queue_res */
 struct dp_queue_res {
 	int q_id; /*!< queue id */
+	int q_node; /*!< queue logica node id. For debugging only */
 	int sch_lvl; /*!< number of scheduler layers configured for this queue*/
 	int sch_id[DP_MAX_SCH_LVL]; /*!< Scheduler information.
 				     *  @note the scheduler of sch_id[0] is the
@@ -830,7 +851,7 @@ struct dp_queue_res {
 	int leaf[DP_MAX_SCH_LVL]; /*!< leaf information.
 				   *
 				   */
-	int cqm_deq_port; /*!< cqm dequeue port */
+	int cqm_deq_port; /*!< cqm dequeue port: absolute port id */
 	int qos_deq_port; /*!< qos dequeue port: Normally user no need to know*/
 };
 
@@ -846,8 +867,8 @@ struct dp_dequeue_res {
 	int dp_port;  /*!< input: if DEV NULL, dp_port must be valid,
 		       *  otherwise no use
 		       */
-	int cqm_deq_port; /*!< <PRE>get resource as specified dequeue port
-			   *  offset
+	int cqm_deq_idx; /*!< <PRE>get resource as specified dequeue port
+			   *  offset (relative)
 			   *  If it is DEQ_PORT_OFFSET_ALL, it means
 			   *  get all resource under that dev/dep_port
 			   *  related device.
@@ -856,6 +877,16 @@ struct dp_dequeue_res {
 			   *  For pon case, cqm_deq_port is like tcont idx
 			   * </PRE>
 			   */
+	int cqm_deq_port; /*!< <PRE>get resource as specified dequeue port
+			      *  absolution dequeue port
+			      *  output only: 
+			      *    for cqm_deq_idx, cqm_deq_port is 
+			      *           matched absolute cqm dequeue port
+			      	   if cqm_deq_idx == DEQ_PORT_OFFSET_ALL,
+			      *            it is the base of cqm dequeue port
+			      * </PRE>
+			      */
+
 	int num_deq_ports; /*!< <PRE>output: The number of dequeue port this
 			    *    dev have.
 			    *    Normally this value should be 1.
@@ -865,6 +896,7 @@ struct dp_dequeue_res {
 			    *    64.</PRE>
 			    */
 	int num_q; /*!< output: the number of queues*/
+	int q_res_size; /*!< input: to indicate q num can be stored in q_res*/
 	struct dp_queue_res *q_res;/*!< output: resource output.
 				    *  @note caller should allocate the memory.
 				    *  <PRE>Procedure:
diff --git a/include/net/datapath_inst.h b/include/net/datapath_inst.h
index 91b69d8a3b9c3191d2460f5584580af72edc2aa6..0acc3b756671ffc340e42304499a59717fe3f811 100644
--- a/include/net/datapath_inst.h
+++ b/include/net/datapath_inst.h
@@ -44,6 +44,7 @@ struct dp_inst_info {
 	enum DP_HW_CAP_VER ver;  /*! HE version */
 	struct core_ops *ops[DP_MAX_GSW_HANDLE]; /*! GSWIP ops handler*/
 	int cbm_inst;  /*! CBM instance for this DP instance*/
+	int qos_inst; /*! QOS instance for this DP instance*/
 };
 
 struct inst_info {
@@ -110,6 +111,7 @@ struct inst_info {
 					   int inst, int bport);
 	int (*dp_mac_set)(int bport, int fid, int inst, u8 *addr);
 	int (*dp_mac_reset)(int bport, int fid, int inst, u8 *addr);
+	int (*dp_cfg_vlan)(int inst, int vap, int ep);
 #endif
 };
 
@@ -130,6 +132,7 @@ struct inst_property {
 	/*driver should know which HW to configure, esp for PCIe case */
 	struct core_ops *ops[DP_MAX_GSW_HANDLE];
 	int cbm_inst;
+	int qos_inst;
 	void *priv_hal; /*private data per HAL */
 };
 
diff --git a/include/net/datapath_proc_api.h b/include/net/datapath_proc_api.h
index 51a7fda3b9f6936d447436d093befb6b312f4239..774ef05e7bb1567222dabaec169c66438183a58f 100644
--- a/include/net/datapath_proc_api.h
+++ b/include/net/datapath_proc_api.h
@@ -17,10 +17,10 @@
 #include <linux/uaccess.h>	/*copy_from_user */
 
 #define set_ltq_dbg_flag(v, e, f) do {;\
-	if (e > 0)\
-		v |= (uint32_t)(f);\
+	if ((e) > 0)\
+		(v) |= (uint32_t)(f);\
 	else\
-		v &= (uint32_t)(~f); } \
+		(v) &= (uint32_t)(~f); } \
 	while (0)
 
 typedef void (*dp_proc_single_callback_t) (struct seq_file *);
@@ -46,6 +46,9 @@ struct dp_proc_entry {
 	struct file_operations ops;
 };
 
+int dp_getopt(char *cmd[], int cmd_size, int *cmd_offset,
+	      char **optarg, const char* optstring);
+
 void dp_proc_entry_create(struct proc_dir_entry *parent_node,
 			  struct dp_proc_entry *proc_entry);
 
diff --git a/include/net/pp_bm_regs.h b/include/net/pp_bm_regs.h
index 0debb1342d69b9ce7b2ffd30ef171e1a4fd05fdd..83d6e94c3199c1caeafe9fd93f6bfc48c44ed550 100755
--- a/include/net/pp_bm_regs.h
+++ b/include/net/pp_bm_regs.h
@@ -38,48 +38,48 @@
 #define PP_BMGR_MAX_POOLS_IN_POLICY					(4)
 
 
-#define BMGR_OFFSET_OF_POLICY(policy)					((policy) * (int)0x4)
-#define BMGR_OFFSET_OF_POOL(pool)					((pool) * (int)0x4)
-#define BMGR_OFFSET_OF_GROUP(group)					((group) * (int)0x4)
-#define BMGR_OFFSET_OF_POOL_IN_POLICY(pool, policy)			((BMGR_OFFSET_OF_POLICY(policy) * PP_BMGR_MAX_POOLS_IN_POLICY) + BMGR_OFFSET_OF_POOL(pool))
+#define BMGR_OFFSET_OF_POLICY(policy)										((policy) * (int)0x4)
+#define BMGR_OFFSET_OF_POOL(pool)											((pool) * (int)0x4)
+#define BMGR_OFFSET_OF_GROUP(group)											((group) * (int)0x4)
+#define BMGR_OFFSET_OF_POOL_IN_POLICY(pool, policy)							((BMGR_OFFSET_OF_POLICY(policy) * PP_BMGR_MAX_POOLS_IN_POLICY) + BMGR_OFFSET_OF_POOL(pool))
 // Regs
-#define BMGR_CTRL_REG_ADDR(BMGR_REG_BASE)						(BMGR_REG_BASE + 0x000)
-#define BMGR_POOL_MIN_GRNT_MASK_REG_ADDR(BMGR_REG_BASE)				(BMGR_REG_BASE + 0x004)
-#define BMGR_POOL_ENABLE_REG_ADDR(BMGR_REG_BASE)					(BMGR_REG_BASE + 0x008)
-#define BMGR_POOL_FIFO_RESET_REG_ADDR(BMGR_REG_BASE)					(BMGR_REG_BASE + 0x00C)
-#define BMGR_OCPM_BURST_SIZE_REG_ADDR(BMGR_REG_BASE)					(BMGR_REG_BASE + 0x010)
-#define BMGR_OCPM_NUM_OF_BURSTS_REG_ADDR(BMGR_REG_BASE)				(BMGR_REG_BASE + 0x014)
-#define BMGR_STATUS_REG_ADDR(BMGR_REG_BASE)						(BMGR_REG_BASE + 0x018)
-#define BMGR_POOL_SIZE_REG_ADDR(BMGR_REG_BASE, pool)					(BMGR_REG_BASE + 0x020 + BMGR_OFFSET_OF_POOL(pool))
+#define BMGR_CTRL_REG_ADDR(BMGR_REG_BASE)									(BMGR_REG_BASE + 0x000)
+#define BMGR_POOL_MIN_GRNT_MASK_REG_ADDR(BMGR_REG_BASE)						(BMGR_REG_BASE + 0x004)
+#define BMGR_POOL_ENABLE_REG_ADDR(BMGR_REG_BASE)							(BMGR_REG_BASE + 0x008)
+#define BMGR_POOL_FIFO_RESET_REG_ADDR(BMGR_REG_BASE)						(BMGR_REG_BASE + 0x00C)
+#define BMGR_OCPM_BURST_SIZE_REG_ADDR(BMGR_REG_BASE)						(BMGR_REG_BASE + 0x010)
+#define BMGR_OCPM_NUM_OF_BURSTS_REG_ADDR(BMGR_REG_BASE)						(BMGR_REG_BASE + 0x014)
+#define BMGR_STATUS_REG_ADDR(BMGR_REG_BASE)									(BMGR_REG_BASE + 0x018)
+#define BMGR_POOL_SIZE_REG_ADDR(BMGR_REG_BASE, pool)						(BMGR_REG_BASE + 0x020 + BMGR_OFFSET_OF_POOL(pool))
 #define BMGR_GROUP_AVAILABLE_BUFF_REG_ADDR(BMGR_REG_BASE, group)			(BMGR_REG_BASE + 0x100 + BMGR_OFFSET_OF_GROUP(group))
-#define BMGR_GROUP_RESERVED_BUFF_REG_ADDR(BMGR_REG_BASE, group)			(BMGR_REG_BASE + 0x200 + BMGR_OFFSET_OF_GROUP(group))
+#define BMGR_GROUP_RESERVED_BUFF_REG_ADDR(BMGR_REG_BASE, group)				(BMGR_REG_BASE + 0x200 + BMGR_OFFSET_OF_GROUP(group))
 #define BMGR_POOL_PCU_FIFO_BASE_ADDR_REG_ADDR(BMGR_REG_BASE, pool)			(BMGR_REG_BASE + 0x400 + BMGR_OFFSET_OF_POOL(pool))
 #define BMGR_POOL_PCU_FIFO_SIZE_REG_ADDR(BMGR_REG_BASE, pool)				(BMGR_REG_BASE + 0x440 + BMGR_OFFSET_OF_POOL(pool))
 #define BMGR_POOL_PCU_FIFO_OCCUPANCY_REG_ADDR(BMGR_REG_BASE, pool)			(BMGR_REG_BASE + 0x480 + BMGR_OFFSET_OF_POOL(pool))
 #define BMGR_POOL_PCU_FIFO_PROG_EMPTY_REG_ADDR(BMGR_REG_BASE, pool)			(BMGR_REG_BASE + 0x4C0 + BMGR_OFFSET_OF_POOL(pool))
 #define BMGR_POOL_PCU_FIFO_PROG_FULL_REG_ADDR(BMGR_REG_BASE, pool)			(BMGR_REG_BASE + 0x500 + BMGR_OFFSET_OF_POOL(pool))
 #define BMGR_POOL_EXT_FIFO_OCC_REG_ADDR(BMGR_REG_BASE, pool)				(BMGR_REG_BASE + 0x5C0 + BMGR_OFFSET_OF_POOL(pool))
-#define BMGR_POOL_EXT_FIFO_BASE_ADDR_LOW_REG_ADDR(BMGR_REG_BASE, pool)			(BMGR_REG_BASE + 0x540 + BMGR_OFFSET_OF_POOL(pool))
+#define BMGR_POOL_EXT_FIFO_BASE_ADDR_LOW_REG_ADDR(BMGR_REG_BASE, pool)		(BMGR_REG_BASE + 0x540 + BMGR_OFFSET_OF_POOL(pool))
 #define BMGR_POOL_EXT_FIFO_BASE_ADDR_HIGH_REG_ADDR(BMGR_REG_BASE, pool)		(BMGR_REG_BASE + 0x580 + BMGR_OFFSET_OF_POOL(pool))
 #define BMGR_POOL_ALLOCATED_COUNTER_REG_ADDR(BMGR_REG_BASE, pool)			(BMGR_REG_BASE + 0x600 + BMGR_OFFSET_OF_POOL(pool))
-#define BMGR_POOL_POP_COUNTER_REG_ADDR(BMGR_REG_BASE, pool)				(BMGR_REG_BASE + 0x640 + BMGR_OFFSET_OF_POOL(pool))
+#define BMGR_POOL_POP_COUNTER_REG_ADDR(BMGR_REG_BASE, pool)					(BMGR_REG_BASE + 0x640 + BMGR_OFFSET_OF_POOL(pool))
 #define BMGR_POOL_PUSH_COUNTER_REG_ADDR(BMGR_REG_BASE, pool)				(BMGR_REG_BASE + 0x680 + BMGR_OFFSET_OF_POOL(pool))
 #define BMGR_DDR_BURST_WRITE_COUNTER_REG_ADDR(BMGR_REG_BASE, pool)			(BMGR_REG_BASE + 0x6C0 + BMGR_OFFSET_OF_POOL(pool))
 #define BMGR_DDR_BURST_READ_COUNTER_REG_ADDR(BMGR_REG_BASE, pool)			(BMGR_REG_BASE + 0x700 + BMGR_OFFSET_OF_POOL(pool))
 #define BMGR_POOL_WATERMARK_LOW_THRESHOLD_REG_ADDR(BMGR_REG_BASE, pool)		(BMGR_REG_BASE + 0x740 + BMGR_OFFSET_OF_POOL(pool))
-#define BMGR_POOL_WATERMARK_LOW_COUNTER_REG_ADDR(BMGR_REG_BASE, pool)			(BMGR_REG_BASE + 0x780 + BMGR_OFFSET_OF_POOL(pool))
+#define BMGR_POOL_WATERMARK_LOW_COUNTER_REG_ADDR(BMGR_REG_BASE, pool)		(BMGR_REG_BASE + 0x780 + BMGR_OFFSET_OF_POOL(pool))
 #define BMGR_POLICY_NULL_COUNTER_REG_ADDR(BMGR_REG_BASE, policy)			(BMGR_REG_BASE + 0x800 + BMGR_OFFSET_OF_POLICY(policy))
 // Ram
-#define BMGR_POLICY_MAX_ALLOWED_ADDR(BMGR_RAM_BASE, policy)				(BMGR_RAM_BASE + 0x0000 + BMGR_OFFSET_OF_POLICY(policy))
+#define BMGR_POLICY_MAX_ALLOWED_ADDR(BMGR_RAM_BASE, policy)					(BMGR_RAM_BASE + 0x0000 + BMGR_OFFSET_OF_POLICY(policy))
 #define BMGR_POLICY_MIN_GUARANTEED_ADDR(BMGR_RAM_BASE, policy)				(BMGR_RAM_BASE + 0x1000 + BMGR_OFFSET_OF_POLICY(policy))
 #define BMGR_POLICY_GROUP_ASSOCIATED_ADDR(BMGR_RAM_BASE, policy)			(BMGR_RAM_BASE + 0x2000 + BMGR_OFFSET_OF_POLICY(policy))
 #define BMGR_POLICY_POOLS_MAPPING_ADDR(BMGR_RAM_BASE, policy)				(BMGR_RAM_BASE + 0x3000 + BMGR_OFFSET_OF_POLICY(policy))
-#define BMGR_POLICY_MAX_ALLOWED_PER_POOL_ADDR(BMGR_RAM_BASE, policy, pool)		(BMGR_RAM_BASE + 0x4000 + BMGR_OFFSET_OF_POLICY(policy) + (pool * 0x1000))
+#define BMGR_POLICY_MAX_ALLOWED_PER_POOL_ADDR(BMGR_RAM_BASE, policy, pool)	(BMGR_RAM_BASE + 0x4000 + BMGR_OFFSET_OF_POLICY(policy) + (pool * 0x1000))
 #define BMGR_POLICY_ALLOC_BUFF_COUNTER_ADDR(BMGR_RAM_BASE, policy)			(BMGR_RAM_BASE + 0xA000 + BMGR_OFFSET_OF_POLICY(policy))
 #define BMGR_POLICY_ALLOC_BUFF_PER_POOL_COUNTER_ADDR(BMGR_RAM_BASE, pool, policy)	(BMGR_RAM_BASE + 0xB000 + BMGR_OFFSET_OF_POOL_IN_POLICY(pool, policy))
 
 // Data
-#define BMGR_DATAPATH_BASE						(0x3c0000)
+#define BMGR_DATAPATH_BASE						(0x18BC0000)
 
 #endif // _PP_BMGR_REGS_H_
 
diff --git a/include/net/pp_qos_drv.h b/include/net/pp_qos_drv.h
index 0dab8b5090fc56b9a73b0c5f1de2e91fa05481b0..8b2985fefe6c252204d833aa9a30ad70fc281602 100644
--- a/include/net/pp_qos_drv.h
+++ b/include/net/pp_qos_drv.h
@@ -1,830 +1,954 @@
-/*
- * GPL LICENSE SUMMARY
- *
- *  Copyright(c) 2017 Intel Corporation.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of version 2 of the GNU General Public License 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.
- *
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *  The full GNU General Public License is included in this distribution
- *  in the file called LICENSE.GPL.
- *
- *  Contact Information:
- *  Intel Corporation
- *  2200 Mission College Blvd.
- *  Santa Clara, CA  97052
- */
-#ifndef _PP_QOS_API_H
-#define _PP_QOS_API_H
-
-#ifdef __KERNEL__
-#include <linux/types.h>
-#else
-#include <stdint.h>
-#endif
-
-
-/******************************************************************************/
-/*                                 GENERAL                                    */
-/******************************************************************************/
-
-/**
- * DOC: Calling context
- *
- * The API exported by this driver, must be called only from a thread context.
- * Calling them from either interrupt/tasklet/buttom half is not allowed and
- * will result in unexpexted behaviour.
- */
-
-/**
- * DOC: Scheduling model
- *
- * Ports, schedulers and queues are modeled as a scheduling tree's nodes.
- * Each such node properties are classified to the following categories:
- * - Common properties - relevant to all nodes
- * - Parent properties - relevant only to parent nodes e.g. arbitration scheme
- *                       between children
- * - Children properties - relevant only to child nodes e.g. node's parent
- *
- * Note some nodes can be both parents and children e.g. schedulers
- */
-
-/**
- * DOC: Arbitration
- *
- * The way a parent arbitrates between its children can be either strict prioriy
- * or round robin.
- *
- * A WRR parent round robin its children - each child gets its turn - as if all
- * children have the same priority. The number of children for this parent type
- * is limited only by the number of nodes (> 1024)
- *
- * A WSP parent employs strict priorityi arbitration on its children - a child
- * will get scheduled only if there is no other sibling with higher priority
- * that can be scheduled. A WSP parent can have 8 direct children at most, each
- * child must have a different priority. To configure more that 8 children for
- * a WSP parent, or to have several children with the same priority,
- * intermediate schedulers should be use.
- *
- * Example of 5 queues q0, q1, q2, q3, q4 with priorities 0, 1, 2, 3, 3
- *
- *                     Port arbitrating WSP
- *                     /   |    |     \
- *                    q0   q1  q2  Sched arbitrating WRR
- *                                         |	      |
- *                                        q3          q4
- *
- *
- * Example of 16 queues q0 to q15, each with a different priority
- *
- *		      Port arbitrating WSP
- *		         |	       |
- *	    Sched0 arbitrating WSP   Sched1 arbitrating WSP
- *	       /               \       /                   \
- *	   q0 q1 q2 q3 q4 q5 q6 q7  q8 q9 q10 q11 q12 q13 q4 q15
- */
-
-/**
- * enum pp_qos_arbitration - parent method for arbitrating its children on tree.
- * @PP_QOS_ARBITRATION_WSP: strict priority
- * @PP_QOS_ARBITRATION_WRR: round robin
- * @PP_QOS_ARBITRATION_WFQ:
- */
-enum pp_qos_arbitration {
-	PP_QOS_ARBITRATION_WSP,
-	PP_QOS_ARBITRATION_WRR,
-	PP_QOS_ARBITRATION_WFQ,
-};
-
-
-/**
- * struct pp_qos_common_node_properties - Properties common to all nodes
- * @suspended:		    is node scheduling suspended
- * @bandwidth_limit:	    bandwidth limit in Mbps
- * @shared_bandwidth_group: shared bandwidth group
- */
-struct pp_qos_common_node_properties {
-	int	 suspended;
-
-        #define QOS_NO_BANDWIDTH_LIMIT          0
-	#define QOS_MAX_BANDWIDTH_LIMIT         0xFFFE
-	unsigned bandwidth_limit;
-
-	#define QOS_NO_SHARED_BANDWIDTH_GROUP   0xFFFF
-        #define QOS_MAX_SHARED_BANDWIDTH_GROUP  511
-	int shared_bandwidth_group;
-};
-
-
-/**
- * @struct pp_qos_parent_node_properties - Properties relevant for parent node
- * @arbitration:	how parent node arbitrates between its children
- * @best_effort_enable: whether best effort scheduling is enabled for this
- *                      node's children.
- */
-struct pp_qos_parent_node_properties {
-	enum pp_qos_arbitration arbitration;
-	int  best_effort_enable;
-};
-
-
-/**
- * @struct pp_qos_child_node_properties - Properties relevant for child node
- * @parent:		parent's id
- * @priority:		strict priority, relevant only if parent uses wsp
- *                      arbitration
- * @bandwidth_share:	bandwidth precentage from parent
- */
-struct pp_qos_child_node_properties {
-	int		parent;
-	#define QOS_MAX_CHILD_PRIORITY 7
-	unsigned	priority;
-	unsigned	bandwidth_share;
-};
-
-
-struct pp_qos_dev;
-
-/******************************************************************************/
-/*                                      PORTS                                 */
-/******************************************************************************/
-
-/* TODO */
-struct pp_qos_port_stat {
-};
-
-/**
- * @struct pp_qos_port_conf - Configuration structure for port
- * @common_prop:		common properties
- * @port_parent_prop:		properties as a parent
- * @ring_address:		address of ring.
- * @ring_size:			size of ring.
- * @packet_credit_enable:	support packet credit.
- * @byte_credit_enable:		support byte credit.
- * @packet_credit:		amount of packets credit to add to the port.
- * @byte_credit:                amount of bytes credit to add to the port.
- */
-struct pp_qos_port_conf {
-	struct pp_qos_common_node_properties common_prop;
-	struct pp_qos_parent_node_properties port_parent_prop;
-
-	void     *ring_address;
-	unsigned ring_size;
-	int      packet_credit_enable;
-	int      byte_credit_enable;
-	unsigned packet_credit;
-	unsigned byte_credit;
-};
-
-
-/**
- * @struct pp_qos_port_info -  Port's information
- * @physical_id:   node id on scheduling tree.
- * @num_of_queues: number of queues feeds this port.
- */
-struct pp_qos_port_info {
-	unsigned physical_id;
-	unsigned num_of_queues;
-};
-
-
-/**
- * pp_qos_port_conf_set_default() - Init port configuration with default values
- * @conf: pointer to client allocated struct. This struct will be filled with
- * default values.
- *
- * Defaults values:
- *    suspended - no
- *    bandwidth_limit - QOS_NO_BANDWIDTH_LIMIT
- *    shared_bandwidth_limit - QOS_NO_SHARED_BANDWIDTH_GROUP
- *    arbitration - WSP
- *    best_effort_enable - no
- *    packet_credit_enable - yes
- *    byte_credit_enable - no
- *    packet_credit - 0
- *    byte_credit - 0
- *    ring_size - 0
- *    ring_address - 0
- */
-void pp_qos_port_conf_set_default(struct pp_qos_port_conf *conf);
-
-
-#define ALLOC_PORT_ID 0xFFFF
-/**
- * pp_qos_port_allocate() - Allocate a resource for a new port
- * @qos_dev:     handle to qos device instance obtained previously
- *               from qos_dev_init
- * @physical_id: if equal ALLOC_PORT_ID then library allocates
- *               a free port id for the new port, otherwise must
- *               be one of the reserved ports ids that were
- *               configured at qos_init
- * @id:          upon success holds new port's id
- *
- * @Return:  0 on success.
- */
-int pp_qos_port_allocate(struct pp_qos_dev *qos_dev, int physical_id, int *id);
-
-
-/**
- * pp_qos_port_remove() - Remove port
- * @qos_dev: handle to qos hardware instance.
- * @id: port's id obtained from port_allocate
- *
- * @Return: 0 on success.
- */
-int pp_qos_port_remove(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_port_set() - Set port configuration
- * @qos_dev:   handle to qos device instance obtained previously from
- *         qos_dev_init
- * @id:    port's id obtained from port_allocate
- * @conf:  port configuration.
- *
- * @Return: 0 on success
- */
-int pp_qos_port_set(struct pp_qos_dev *qos_dev, int id,
-		    const struct pp_qos_port_conf *conf);
-
-
-/**
- * pp_qos_port_suspend() - Remove port desendants from scheduling
- * @qos_dev: handle to qos hardware instance.
- * @id:  port's id obtained from port_allocate
- *
- * @Return: 0 on success
- */
-int pp_qos_port_suspend(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_port_resume() - Resume port and its decendants scheduling
- * @qos_dev: handle to qos hardware instance.
- * @id:  port's id obtained from port_allocate
- *
- * @Return: 0 on success
- */
-int pp_qos_port_resume(struct pp_qos_dev *qos_dev, int id);
-
-/**
- * pp_qos_port_block() - All new packets enqueued to queues feeding this port
- *                    will be dropped
- * @qos_dev: handle to qos hardware instance.
- * @id:  port's id obtained from port_allocate
- *
- * Note	- already enportd descriptors will be transmitted
- *
- * Return: 0 on success
- */
-int pp_qos_port_block(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_port_unblock() - Unblock enqueuing of new packets to queues that feeds
- *                      this port
- * @qos_dev: handle to qos hardware instance.
- * @id:	 port's id obtained from port_allocate
- *
- * Return: 0 on success
- */
-int pp_qos_port_unblock(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_port_flush() - Drop all enqueued packets on queues under this port
- * @qos_dev: handle to qos hardware instance.
- * @id:	 port's id obtained from port_allocate
- *
- * Return: 0 on success
- */
-int pp_qos_port_flush(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_port_conf_get() - Get port configuration
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * id:	  port's id obtained from port_allocate
- * @conf: pointer to struct to be filled with port's configuration
- *
- * Return: 0 on success
- */
-
-int pp_qos_port_conf_get(struct pp_qos_dev *qos_dev, int id,
-			 struct pp_qos_port_conf *conf);
-
-
-/**
- * pp_qos_port_info_get() - Get extra information about port
- * id:	  port's id obtained from port_allocate
- * @info: pointer to struct to be filled with port's info
- *
- * Return: 0 on success
- */
-int pp_qos_port_info_get(struct pp_qos_dev *qos_dev, int id,
-			 struct pp_qos_port_info *info);
-
-
-/**
- * pp_qos_port_get_queues() - Get all port's queues
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	        scheduler's id obtained from sched_allocate
- * @queue_ids:  client allocated array that will hold queues ids
- * @size:       size of queue_ids
- * @queues_num: holds the number of queues
- *
- * Note queues_num can be bigger than size
- *
- * Return: 0 on success
- */
-int pp_qos_port_get_queues(struct pp_qos_dev *qos_dev, int id,
-			   uint16_t *queue_ids, unsigned size,
-			   unsigned *queues_num);
-
-
-/**
- * pp_qos_port_stat_get() - Get port's statistics
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	  port's id obtained from port_allocate
- * @stat: pointer to struct to be filled with port's statistics
- *
- * Return: 0 on success
- */
-int pp_qos_port_stat_get(struct pp_qos_dev *qos_dev, int id,
-			 struct pp_qos_port_stat *stat);
-
-
-/******************************************************************************/
-/*                                    QUEUES                                  */
-/******************************************************************************/
-
-/* TODO */
-struct pp_qos_queue_stat {
-};
-
-/**
- * @struct pp_qos_queue_conf - Configuration structure for queue
- * @common_prop:		common properties
- * @queue_child_prop:           properties as a child node
- * @max_burst:		        max burst in Kbps
- * @blocked:			queue will drop new enqueued packets
- * @wred_enable:		WRED is applied on this queue, otherwise only
- *                              min and max values are used
- * @queue_wred_min_avg_green:
- * @queue_wred_max_avg_green:
- * @queue_wred_slope_green:
- * @queue_wred_min_avg_yellow:
- * @queue_wred_max_avg_yellow:
- * @queue_wred_slope_yellow:
- * @queue_wred_min_guaranteed:
- * @queue_wred_max_allowed:
- */
-struct pp_qos_queue_conf {
-	struct pp_qos_common_node_properties common_prop;
-	struct pp_qos_child_node_properties  queue_child_prop;
-	unsigned max_burst;
-	int      blocked;
-	int	 wred_enable;
-	unsigned queue_wred_min_avg_green;
-	unsigned queue_wred_max_avg_green;
-	unsigned queue_wred_slope_green;
-	unsigned queue_wred_min_avg_yellow;
-	unsigned queue_wred_max_avg_yellow;
-	unsigned queue_wred_slope_yellow;
-	unsigned queue_wred_min_guaranteed;
-	unsigned queue_wred_max_allowed;
-};
-
-
-/**
- * @struct pp_qos_queue_info - Queue information struct
- * @port_id:	 port fed by this queue
- * @physical_id: queue (ready list) number
- */
-struct pp_qos_queue_info {
-	int port_id;
-	int physical_id;
-};
-
-
-/**
- * pp_qos_queue_conf_set_default() - Init configuration with default values
- * @conf: pointer to client allocated struct. This struct will be filled with
- * default values.
- *
- * Defaults values:
- *    suspended - no
- *    max_burst - 0
- *    bandwidth_limit - 0
- *    shared_bandwidth_limit - 0
- *    parent - 0
- *    priority - 0
- *    bandwidth_share - 0
- *    wred_enable - no
- *    ALL wred params - 0
- */
-void pp_qos_queue_conf_set_default(struct pp_qos_queue_conf *conf);
-
-
-/**
- * pp_qos_queue_allocate() - Allocate aresouirce for a new queue
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:   upon success hold's new queue id
- *
- * Return:  0 on success.
- */
-int pp_qos_queue_allocate(struct pp_qos_dev *qos_dev, int *id);
-
-
-/**
- * pp_qos_queue_remove() -	Remove a queue
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:   queue's id obtained from queue_allocate
- *
- * Note: client should make sure that queue is empty and
- *       that new packets are not enqueued, by calling
- *       pp_qos_queue_disable and pp_qos_queue_flush
- *
- * Return: 0 on success
- */
-int pp_qos_queue_remove(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_queue_set() - Set queue configuration
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	  queue's id obtained from queue_allocate
- * @conf: new configuration for the queue
- *
- * Return: 0 on success
- */
-int pp_qos_queue_set(struct pp_qos_dev *qos_dev, int id,
-		     const struct pp_qos_queue_conf *conf);
-
-
-/**
- * pp_qos_queue_suspend() - Remove queue from scheduling (doesn't get bandwidth)
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	  queue's id obtained from queue_allocate
- *
- * Return: 0 on success
- */
-int pp_qos_queue_suspend(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_queue_resume() -	Return queue to be scheduleable
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:   queue's id obtained from queue_allocate
- *
- * Return: 0 on success
- */
-int pp_qos_queue_resume(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_queue_block() - All new packets enqueue to this queue will be dropped
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:   queue's id obtained from queue_allocate
- *
- * Note	- already enqueued descriptors will be transmitted
- *
- * Return: 0 on success
- */
-int pp_qos_queue_block(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_queue_unblock() - Unblock enqueuing of new packets
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	  queue's id obtained from queue_allocate
- *
- * Return: 0 on success
- */
-int pp_qos_queue_unblock(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_queue_flush() - Drop all enqueued packets
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	  queue's id obtained from queue_allocate
- *
- * Return: 0 on success
- */
-int pp_qos_queue_flush(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_queue_conf_get() - Get queue current configuration
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * id:	  port's id obtained from queue_allocate
- * @conf: pointer to struct to be filled with queue's configuration
- *
- * Return: 0 on success
- */
-int pp_qos_queue_conf_get(struct pp_qos_dev *qos_dev, int id,
-			  struct pp_qos_queue_conf *conf);
-
-
-/**
- * pp_qos_queue_info_get() - Get information about queue
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	  queue's id obtained from queue_allocate
- * @info: pointer to struct to be filled with queue's info
- *
- * Return: 0 on success
- */
-int pp_qos_queue_info_get(struct pp_qos_dev *qos_dev, int id,
-			  struct pp_qos_queue_info *info);
-
-
-/**
- * pp_qos_queue_stat_get() - Get queue's statistics
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	  queue's id obtained from queue_allocate
- * @stat: pointer to struct to be filled with queue's statistics
- *
- * Return: 0 on success
- */
-int pp_qos_queue_stat_get(struct pp_qos_dev *qos_dev, int id,
-		       struct pp_qos_queue_stat *stat);
-
-
-/******************************************************************************/
-/*                                 SCHEDULER                                  */
-/******************************************************************************/
-
-/* TODO */
-struct pp_qos_sched_stat {
-};
-
-/**
- * @struct pp_qos_sched_conf - Configuration structure for scheduler
- * @qos_dev:               handle to qos device instance obtained
- *                     previously from qos_dev_init
- * @common_prop:       common properties as a node
- * @sched_parent_prop: properties as a parent node
- * @sched_child_node:  properties as a child node
- */
-struct pp_qos_sched_conf {
-	struct pp_qos_common_node_properties common_prop;
-	struct pp_qos_parent_node_properties sched_parent_prop;
-	struct pp_qos_child_node_properties  sched_child_prop;
-};
-
-
-/**
- * @struct pp_qos_sched_info - Scheduler information struct
- * @qos_dev:                    handle to qos device instance obtained
- *                          previously from qos_dev_init
- * @port_id:		    port fed by this scheduler
- * @physical_id:	    node id on scheduling tree
- */
-struct pp_qos_sched_info {
-	int port_id;
-	int physical_id;
-};
-
-
-/**
- * pp_qos_sched_conf_set_default() - Init scheduler config with defaults
- * @conf: pointer to client allocated struct which will be filled with
- *        default values
- *
- * Defaults values:
- *    suspended - no
- *    bandwidth_limit - 0
- *    shared_bandwidth_limit - 0
- *    arbitration - WSP
- *    best_effort_enable - no
- *    parent - 0
- *    priority - 0
- *    bandwidth_share - 0
- */
-void pp_qos_sched_conf_set_default(struct pp_qos_sched_conf *conf);
-
-
-/**
- * pp_qos_sched_allocate() - Allocate a resource for a new scheduler
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:   upon success - holds new scheduler's id
- *
- * Return:  0 on success.
- */
-int pp_qos_sched_allocate(struct pp_qos_dev *qos_dev, int *id);
-
-
-/**
- * pp_qos_sched_remove() -	Remove scheduler
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	  scheduler's id obtained from sched_allocate
- *
- * Return:	0 on success
- */
-int pp_qos_sched_remove(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_sched_set() - Set scheduler configuration
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	  scheduler's id obtained from sched_allocate
- * @conf: new configuration for the scheduler
- *
- * Note: must init conf by pp_qos_sched_conf_init before calling
- *       this function.
- *
- * Return: 0 on success
- */
-int pp_qos_sched_set(struct pp_qos_dev *qos_dev, int id,
-		     const struct pp_qos_sched_conf *conf);
-
-
-/**
- * pp_qos_sched_suspend() - Remove scheduler from scheduling
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	  scheduler's id obtained from sched_allocate
- *
- * Return: 0 on success
- */
-int pp_qos_sched_suspend(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_sched_resume() - Return scheduler and its decendants scheduleable
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:   scheduler's id obtained from sched_allocate
- *
- * Return: 0 on success
- */
-int pp_qos_sched_resume(struct pp_qos_dev *qos_dev, int id);
-
-
-/**
- * pp_qos_sched_conf_get() - Get sched current configuration
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * id:	  port's id obtained from port_allocate
- * @conf: pointer to struct to be filled with sched's configuration
- *
- * Return: 0 on success
- */
-int pp_qos_sched_conf_get(struct pp_qos_dev *qos_dev, int id,
-		       struct pp_qos_sched_conf *conf);
-
-
-/**
- * pp_qos_sched_info_get() - Get information about scheduler
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	  scheduler's id obtained from sched_allocate
- * @info: pointer to struct to be filled with scheduler's info
- *
- * Return: 0 on success
- */
-int pp_qos_sched_info_get(struct pp_qos_dev *qos_dev, int id,
-			  struct pp_qos_sched_info *info);
-
-
-/**
- * pp_qos_sched_get_queues() - Get all scheduler's queues
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	        scheduler's id obtained from sched_allocate
- * @queue_ids:  client allocated array that will hold queues ids
- * @size:       size of queue_ids
- * @queues_num: holds the number of queues
- *
- * Note queues_num can be bigger than size
- *
- * Return: 0 on success
- */
-int pp_qos_sched_get_queues(struct pp_qos_dev *qos_dev, int id,
-			    uint16_t *queue_ids, unsigned size,
-			    unsigned *queues_num);
-
-
-/**
- * pp_qos_sched_stat_get() - Get scheduler's statistics
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	  scheduler's id obtained from sched_allocate
- * @info: pointer to struct to be filled with scheduler's statistics
- *
- * Return:
- */
-int pp_qos_sched_stat_get(struct pp_qos_dev *qos_dev, int id,
-			  struct pp_qos_sched_stat *stat);
-
-
-/******************************************************************************/
-/*                                 SHARED_LIMIT                               */
-/******************************************************************************/
-
-/**
- * qos_shared_limit_group_add() - Add new shared bandwidth group
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @limit: bandwidth limit in Mbps
- * @id:    upon success, new group's id
- *
- * Return: 0 on success
- */
-int qos_shared_limit_group_add(struct pp_qos_dev *qos_dev, unsigned limit,
-			       unsigned *id);
-
-
-/**
- * qos_shared_limit_group_remove() - Remove shared bandwidth group
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id: group's id previously obtained when adding group
- *
- * Return: 0 on success
- */
-int qos_shared_limit_group_remove(struct pp_qos_dev *qos_dev, unsigned id);
-
-
-/**
- * qos_shared_limit_group_modify() - Modify shared bandwidth group
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id: group's id previously obtained when adding group
- * @limit: bandwidth limit in Mbps
- *
- * Return: 0 on success
- */
-int qos_shared_limit_group_modify(struct pp_qos_dev *qos_dev,
-				  unsigned id, unsigned limit);
-
-
-/**
- * qos_shared_limit_group_get_members() - Get group's members
- * @qos_dev: handle to qos device instance obtained previously from qos_dev_init
- * @id:	         scheduler's id obtained from sched_allocate
- * @queue_ids:   client allocated array that will hold queues ids
- * @size:        size of queue_ids
- * @members_num: holds the number of queues
- *
- * Note members num can be bigger than size
- *
- * Return: 0 on success
- */
-int qos_shared_limit_group_get_nodes(struct pp_qos_dev *qos_dev, int id,
-				     uint16_t *queue_ids, unsigned size,
-				     unsigned *members_num);
-
-
-
-/******************************************************************************/
-/*                                  INIT	                              */
-/******************************************************************************/
-
-/**
- * @struct pp_qos_init_param - qos subsystem initialization struct
- * @max_port:             highest port number that should be used by this
- *                        system.
- * @qm_base_addr:         start address of DDR memory for saving packets
- *                        descriptors
- * @qm_num_of_pages:      number of  DDR memory pages
- * @wred_prioritized_pop: 1 - give strict priority to pop indications over push
- *                        requests.
- *                        0 - round robin between the two
- * @wred_p_const:         WRED algorithm p, used for calculating avg queue depth
- *	                  avg = (old_avg*(1-p)) + (curr_avg*p)
- *	                  p is taken to b wred_p_const / 1023
- *	                  wred_p_const should be in the range 0..1023
- * @reserved_ports:       These ports are reserved for client to explicity
- *                        select the physical_port ithat will be used when
- *                        adding a new port. All other non reserved ports are
- *                        managed by the system, i.e. when client adds a new
- *                        port system will select a new free port from the
- *                        unreserved ports.
- *                        To reserve a port its value on the array should be
- *                        not 0
- */
-struct pp_qos_init_param {
-	unsigned max_port;
-	void	*qm_base_addr;
-	unsigned qm_num_of_pages;
-	unsigned wred_prioritized_pop;
-	unsigned wred_p_const;
-	#define MAX_PORTS    128
-	uint8_t reserved_ports[MAX_PORTS];
-};
-
-
-/**
- * qos_dev_init() -	Initialize of a qos device
- * @conf: Initialization configuration
- *
- * Return: on success handle to qos device
- *         NULL otherwise
- */
-struct pp_qos_dev *qos_dev_init(struct pp_qos_init_param *conf);
-
-
-#endif
-
+/*
+ * GPL LICENSE SUMMARY
+ *
+ *  Copyright(c) 2017 Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *  The full GNU General Public License is included in this distribution
+ *  in the file called LICENSE.GPL.
+ *
+ *  Contact Information:
+ *  Intel Corporation
+ *  2200 Mission College Blvd.
+ *  Santa Clara, CA  97052
+ */
+#ifndef _PP_QOS_API_H
+#define _PP_QOS_API_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+
+
+/******************************************************************************/
+/*                                 GENERAL                                    */
+/******************************************************************************/
+
+/**
+ * DOC: Calling context
+ *
+ * The API exported by this driver, must be called only from a thread context.
+ * Calling them from either interrupt/tasklet/buttom half is not allowed and
+ * will result in unexpexted behaviour.
+ */
+
+/**
+ * DOC: Scheduling model
+ *
+ * Ports, schedulers and queues are modeled as a scheduling tree's nodes.
+ * Each such node properties are classified to the following categories:
+ * - Common properties - relevant to all nodes
+ * - Parent properties - relevant only to parent nodes e.g. arbitration scheme
+ *                       between children
+ * - Children properties - relevant only to child nodes e.g. node's parent
+ *
+ * Note some nodes can be both parents and children e.g. schedulers
+ */
+
+/**
+ * DOC: Arbitration
+ *
+ * The way a parent arbitrates between its children can be either strict prioriy
+ * or round robin.
+ *
+ * A WRR parent round robin its children - each child gets its turn - as if all
+ * children have the same priority. The number of children for this parent type
+ * is limited only by the number of nodes (> 1024)
+ *
+ * A WSP parent employs strict priorityi arbitration on its children - a child
+ * will get scheduled only if there is no other sibling with higher priority
+ * that can be scheduled. A WSP parent can have 8 direct children at most, each
+ * child must have a different priority. To configure more that 8 children for
+ * a WSP parent, or to have several children with the same priority,
+ * intermediate schedulers should be use.
+ *
+ * Example of 5 queues q0, q1, q2, q3, q4 with priorities 0, 1, 2, 3, 3
+ *
+ *                     Port arbitrating WSP
+ *                     /   |    |     \
+ *                    q0   q1  q2  Sched arbitrating WRR
+ *                                         |	      |
+ *                                        q3          q4
+ *
+ *
+ * Example of 16 queues q0 to q15, each with a different priority
+ *
+ *		      Port arbitrating WSP
+ *		         |	       |
+ *	    Sched0 arbitrating WSP   Sched1 arbitrating WSP
+ *	       /               \       /                   \
+ *	   q0 q1 q2 q3 q4 q5 q6 q7  q8 q9 q10 q11 q12 q13 q4 q15
+ */
+
+/**
+ * enum pp_qos_arbitration - parent method for arbitrating its children on tree.
+ * @PP_QOS_ARBITRATION_WSP: strict priority
+ * @PP_QOS_ARBITRATION_WRR: round robin
+ * @PP_QOS_ARBITRATION_WFQ:
+ */
+enum pp_qos_arbitration {
+	PP_QOS_ARBITRATION_WSP,
+	PP_QOS_ARBITRATION_WRR,
+	PP_QOS_ARBITRATION_WFQ,
+};
+
+
+/**
+ * struct pp_qos_common_node_properties - Properties common to all nodes
+ * @suspended:		    is node scheduling suspended
+ * @bandwidth_limit:	    bandwidth limit in Mbps
+ * @shared_bandwidth_group: shared bandwidth group
+ */
+struct pp_qos_common_node_properties {
+	int	 suspended;
+
+	#define QOS_NO_BANDWIDTH_LIMIT          0
+	#define QOS_MAX_BANDWIDTH_LIMIT         0xFFFF
+	unsigned int bandwidth_limit;
+
+	#define QOS_NO_SHARED_BANDWIDTH_GROUP   0x0
+	#define QOS_MAX_SHARED_BANDWIDTH_GROUP  511
+	unsigned int shared_bandwidth_group;
+};
+
+
+/**
+ * @struct pp_qos_parent_node_properties - Properties relevant for parent node
+ * @arbitration:	how parent node arbitrates between its children
+ * @best_effort_enable: whether best effort scheduling is enabled for this
+ *                      node's children.
+ */
+struct pp_qos_parent_node_properties {
+	enum pp_qos_arbitration arbitration;
+	int  best_effort_enable;
+};
+
+
+/**
+ * @struct pp_qos_child_node_properties - Properties relevant for child node
+ * @parent:		parent's id
+ * @priority:		strict priority, relevant only if parent uses wsp
+ *                      arbitration
+ * @bandwidth_share:	bandwidth precentage from parent
+ */
+struct pp_qos_child_node_properties {
+	unsigned int	parent;
+	#define QOS_MAX_CHILD_PRIORITY 7
+	unsigned int	priority;
+	unsigned int	bandwidth_share;
+};
+
+
+struct pp_qos_dev;
+
+/******************************************************************************/
+/*                                      PORTS                                 */
+/******************************************************************************/
+
+/**
+ * @struct pp_qos_port_stat - Statistics per port
+ * @total_green_bytes - total green bytes currently in all queues
+ *			feeding this port
+ * @total_yellow_bytes - total yellow bytes currently in all queues
+ *			 feeding this port
+ */
+struct pp_qos_port_stat {
+	int reset;
+	unsigned int total_green_bytes;
+	unsigned int total_yellow_bytes;
+};
+
+/**
+ * @struct pp_qos_port_conf - Configuration structure for port
+ * @common_prop:		common properties
+ * @port_parent_prop:		properties as a parent
+ * @ring_address:		address of ring.
+ * @ring_size:			size of ring.
+ * @packet_credit_enable:	packet credit mode (byte credit disabled).
+ * @credit:		        amount of credit to add to the port.
+ *                              when packet_credit is enabled this designates
+ *                              packet credit, otherwise byte credit
+ */
+struct pp_qos_port_conf {
+	struct pp_qos_common_node_properties common_prop;
+	struct pp_qos_parent_node_properties port_parent_prop;
+	void     *ring_address;
+	unsigned int ring_size;
+	int      packet_credit_enable;
+	unsigned int credit;
+};
+
+
+/**
+ * @struct pp_qos_port_info -  Port's information
+ * @physical_id:   node id on scheduling tree.
+ * @num_of_queues: number of queues feeds this port.
+ */
+struct pp_qos_port_info {
+	unsigned int physical_id;
+	unsigned int num_of_queues;
+};
+
+
+/**
+ * pp_qos_port_conf_set_default() - Init port configuration with default values
+ * @conf: pointer to client allocated struct. This struct will be filled with
+ * default values.
+ *
+ * Defaults values:
+ *    suspended - no
+ *    bandwidth_limit - QOS_NO_BANDWIDTH_LIMIT
+ *    shared_bandwidth_limit - QOS_NO_SHARED_BANDWIDTH_GROUP
+ *    arbitration - WSP
+ *    best_effort_enable - no
+ *    packet_credit_enable - yes
+ *    byte_credit_enable - no
+ *    packet_credit - 0
+ *    byte_credit - 0
+ *    ring_size - 0
+ *    ring_address - 0
+ */
+void pp_qos_port_conf_set_default(struct pp_qos_port_conf *conf);
+
+
+#define ALLOC_PORT_ID 0xFFFF
+/**
+ * pp_qos_port_allocate() - Allocate a resource for a new port
+ * @qos_dev:     handle to qos device instance obtained previously
+ *               from pp_qos_dev_open
+ * @physical_id: if equal ALLOC_PORT_ID then library allocates
+ *               a free port id for the new port, otherwise must
+ *               be one of the reserved ports ids that were
+ *               configured at qos_init
+ * @id:          upon success holds new port's id
+ *
+ * @Return:  0 on success.
+ */
+int pp_qos_port_allocate(struct pp_qos_dev *qos_dev, unsigned int physical_id,
+			 unsigned int *id);
+
+
+/**
+ * pp_qos_port_remove() - Remove port
+ * @qos_dev: handle to qos hardware instance.
+ * @id: port's id obtained from port_allocate
+ *
+ * @Return: 0 on success.
+ */
+int pp_qos_port_remove(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_port_set() - Set port configuration
+ * @qos_dev:   handle to qos device instance obtained previously from
+ *         qos_dev_init
+ * @id:    port's id obtained from port_allocate
+ * @conf:  port configuration.
+ *
+ * @Return: 0 on success
+ */
+int pp_qos_port_set(struct pp_qos_dev *qos_dev, unsigned int id,
+		    const struct pp_qos_port_conf *conf);
+
+
+/**
+ * pp_qos_port_suspend() - Remove port desendants from scheduling
+ * @qos_dev: handle to qos hardware instance.
+ * @id:  port's id obtained from port_allocate
+ *
+ * @Return: 0 on success
+ */
+int pp_qos_port_suspend(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_port_resume() - Resume port and its decendants scheduling
+ * @qos_dev: handle to qos hardware instance.
+ * @id:  port's id obtained from port_allocate
+ *
+ * @Return: 0 on success
+ */
+int pp_qos_port_resume(struct pp_qos_dev *qos_dev, unsigned int id);
+
+/**
+ * pp_qos_port_block() - All new packets enqueued to queues feeding this port
+ *                    will be dropped
+ * @qos_dev: handle to qos hardware instance.
+ * @id:  port's id obtained from port_allocate
+ *
+ * Note	- already enportd descriptors will be transmitted
+ *
+ * Return: 0 on success
+ */
+int pp_qos_port_block(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_port_unblock() - Unblock enqueuing of new packets to queues that feeds
+ *                      this port
+ * @qos_dev: handle to qos hardware instance.
+ * @id:	 port's id obtained from port_allocate
+ *
+ * Return: 0 on success
+ */
+int pp_qos_port_unblock(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_port_flush() - Drop all enqueued packets on queues under this port
+ * @qos_dev: handle to qos hardware instance.
+ * @id:	 port's id obtained from port_allocate
+ *
+ * Return: 0 on success
+ */
+int pp_qos_port_flush(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_port_conf_get() - Get port configuration
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * id:	  port's id obtained from port_allocate
+ * @conf: pointer to struct to be filled with port's configuration
+ *
+ * Return: 0 on success
+ */
+
+int pp_qos_port_conf_get(struct pp_qos_dev *qos_dev, unsigned int id,
+			 struct pp_qos_port_conf *conf);
+
+
+/**
+ * pp_qos_port_info_get() - Get extra information about port
+ * id:	  port's id obtained from port_allocate
+ * @info: pointer to struct to be filled with port's info
+ *
+ * Return: 0 on success
+ */
+int pp_qos_port_info_get(struct pp_qos_dev *qos_dev, unsigned int id,
+			 struct pp_qos_port_info *info);
+
+
+/**
+ * pp_qos_port_get_queues() - Get all port's queues
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	        scheduler's id obtained from sched_allocate
+ * @queue_ids:  client allocated array that will hold queues ids
+ * @size:       size of queue_ids
+ * @queues_num: holds the number of queues
+ *
+ * Note queues_num can be bigger than size
+ *
+ * Return: 0 on success
+ */
+int pp_qos_port_get_queues(struct pp_qos_dev *qos_dev, unsigned int id,
+			   uint16_t *queue_ids, unsigned int size,
+			   unsigned int *queues_num);
+
+
+/**
+ * pp_qos_port_stat_get() - Get port's statistics
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	  port's id obtained from port_allocate
+ * @stat: pointer to struct to be filled with port's statistics
+ *
+ * Return: 0 on success
+ */
+int pp_qos_port_stat_get(struct pp_qos_dev *qos_dev, unsigned int id,
+			 struct pp_qos_port_stat *stat);
+
+
+/******************************************************************************/
+/*                                    QUEUES                                  */
+/******************************************************************************/
+
+/**
+ * @struct pp_qos_queue_stat - Statistics per queue
+ * @reset:		       Should statistics be reset after reading
+ * @queue_packets_occupancy:   Packetes currently in queue
+ * @queue_bytes_occupancy:     Bytes currently in queue
+ * @total_packets_accepted:    Packets accepted by WRED
+ * @total_packets_dropped:     Packets dropped by WRED due any reason
+ * @total_packets_red_dropped: Packets dropped by WRED due to being red
+ * @total_bytes_accepted:      Bytes accepted by WRED
+ * @total_bytes_dropped:       Bytes dropped by WRED
+ */
+struct pp_qos_queue_stat {
+	int reset;
+	unsigned int	queue_packets_occupancy;
+	unsigned int	queue_bytes_occupancy;
+	unsigned int	total_packets_accepted;
+	unsigned int	total_packets_dropped;
+	unsigned int	total_packets_red_dropped;
+	uint64_t	total_bytes_accepted;
+	uint64_t	total_bytes_dropped;
+};
+
+/**
+ * @struct pp_qos_queue_conf - Configuration structure for queue
+ * @common_prop:		common properties
+ * @queue_child_prop:           properties as a child node
+ * @max_burst:		        max burst in Kbps
+ * @blocked:			queue will drop new enqueued packets
+ * @aliased:			queue will be aliased by another queue
+ * @wred_enable:		WRED is applied on this queue, otherwise only
+ *                              min and max values are used
+ * @wred_fixed_drop_prob_enable:use fixed drop probability for WRED instead of
+ *                              slope
+ * @queue_wred_min_avg_green:
+ * @queue_wred_max_avg_green:
+ * @queue_wred_slope_green:
+ * @queue_wred_fixed_drop_prob_green:
+ * @queue_wred_min_avg_yellow:
+ * @queue_wred_max_avg_yellow:
+ * @queue_wred_slope_yellow:
+ * @queue_wred_fixed_drop_prob_yellow:
+ * @queue_wred_min_guaranteed:
+ * @queue_wred_max_allowed:
+ */
+struct pp_qos_queue_conf {
+	struct pp_qos_common_node_properties common_prop;
+	struct pp_qos_child_node_properties  queue_child_prop;
+	unsigned int max_burst;
+	int      blocked;
+	int      aliased;
+	int	 wred_enable;
+	int      wred_fixed_drop_prob_enable;
+	unsigned int queue_wred_min_avg_green;
+	unsigned int queue_wred_max_avg_green;
+	unsigned int queue_wred_slope_green;
+	unsigned int queue_wred_fixed_drop_prob_green;
+	unsigned int queue_wred_min_avg_yellow;
+	unsigned int queue_wred_max_avg_yellow;
+	unsigned int queue_wred_slope_yellow;
+	unsigned int queue_wred_fixed_drop_prob_yellow;
+	unsigned int queue_wred_min_guaranteed;
+	unsigned int queue_wred_max_allowed;
+};
+
+
+/**
+ * @struct pp_qos_queue_info - Queue information struct
+ * @port_id:	 port fed by this queue
+ * @physical_id: queue (ready list) number
+ * @alias_master_id: Id of the queue which is aliased by this queue,
+ *                   PP_QOS_INVALID_ID if this queue does not alias any queue
+ * @alias_slave_id: Id of the queue aliasing this queue, PP_QOS_INVALID_ID
+ *                  if this queue is not aliased by any queue.
+ *
+ */
+#define PP_QOS_INVALID_ID 0xFFFF
+struct pp_qos_queue_info {
+	unsigned int port_id;
+	unsigned int physical_id;
+	unsigned int alias_slave_id;
+	unsigned int alias_master_id;
+};
+
+
+/**
+ * pp_qos_queue_conf_set_default() - Init configuration with default values
+ * @conf: pointer to client allocated struct. This struct will be filled with
+ * default values.
+ *
+ * Defaults values:
+ *    suspended - no
+ *    max_burst - 0
+ *    bandwidth_limit - 0
+ *    shared_bandwidth_limit - 0
+ *    parent - 0
+ *    priority - 0
+ *    bandwidth_share - 0
+ *    wred_enable - no
+ *    ALL wred params - 0
+ */
+void pp_qos_queue_conf_set_default(struct pp_qos_queue_conf *conf);
+
+
+/**
+ * pp_qos_queue_allocate() - Allocate aresouirce for a new queue
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:   upon success hold's new queue id
+ *
+ * Return:  0 on success.
+ */
+int pp_qos_queue_allocate(struct pp_qos_dev *qos_dev, unsigned int *id);
+
+
+/**
+ * pp_qos_queue_remove() -	Remove a queue
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:   queue's id obtained from queue_allocate
+ *
+ * Note: client should make sure that queue is empty and
+ *       that new packets are not enqueued, by calling
+ *       pp_qos_queue_disable and pp_qos_queue_flush
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_remove(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_queue_set() - Set queue configuration
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	  queue's id obtained from queue_allocate
+ * @conf: new configuration for the queue
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_set(struct pp_qos_dev *qos_dev, unsigned int id,
+		     const struct pp_qos_queue_conf *conf);
+
+
+/**
+ * pp_qos_queue_suspend() - Remove queue from scheduling (doesn't get bandwidth)
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	  queue's id obtained from queue_allocate
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_suspend(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_queue_resume() -	Return queue to be scheduleable
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:   queue's id obtained from queue_allocate
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_resume(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_queue_block() - All new packets enqueue to this queue will be dropped
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:   queue's id obtained from queue_allocate
+ *
+ * Note	- already enqueued descriptors will be transmitted
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_block(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_queue_unblock() - Unblock enqueuing of new packets
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	  queue's id obtained from queue_allocate
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_unblock(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_queue_flush() - Drop all enqueued packets
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	  queue's id obtained from queue_allocate
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_flush(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_queue_conf_get() - Get queue current configuration
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * id:	  port's id obtained from queue_allocate
+ * @conf: pointer to struct to be filled with queue's configuration
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_conf_get(struct pp_qos_dev *qos_dev, unsigned int id,
+			  struct pp_qos_queue_conf *conf);
+
+
+/**
+ * pp_qos_queue_info_get() - Get information about queue
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	  queue's id obtained from queue_allocate
+ * @info: pointer to struct to be filled with queue's info
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_info_get(struct pp_qos_dev *qos_dev, unsigned int id,
+			  struct pp_qos_queue_info *info);
+
+
+/**
+ * pp_qos_queue_stat_get() - Get queue's statistics
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	  queue's id obtained from queue_allocate
+ * @stat: pointer to struct to be filled with queue's statistics
+ *
+ * Return: 0 on success
+ */
+int pp_qos_queue_stat_get(struct pp_qos_dev *qos_dev, unsigned int id,
+			  struct pp_qos_queue_stat *stat);
+
+
+/******************************************************************************/
+/*                                 SCHEDULER                                  */
+/******************************************************************************/
+
+/**
+ * @struct pp_qos_sched_conf - Configuration structure for scheduler
+ * @qos_dev:               handle to qos device instance obtained
+ *                     previously from pp_qos_dev_open
+ * @common_prop:       common properties as a node
+ * @sched_parent_prop: properties as a parent node
+ * @sched_child_node:  properties as a child node
+ */
+struct pp_qos_sched_conf {
+	struct pp_qos_common_node_properties common_prop;
+	struct pp_qos_parent_node_properties sched_parent_prop;
+	struct pp_qos_child_node_properties  sched_child_prop;
+};
+
+
+/**
+ * @struct pp_qos_sched_info - Scheduler information struct
+ * @qos_dev:                    handle to qos device instance obtained
+ *                          previously from pp_qos_dev_open
+ * @port_id:		    port fed by this scheduler
+ * @num_of_queues:	    number of queues feed this scheduler.
+ */
+struct pp_qos_sched_info {
+	unsigned int port_id;
+	unsigned int num_of_queues;
+};
+
+
+/**
+ * pp_qos_sched_conf_set_default() - Init scheduler config with defaults
+ * @conf: pointer to client allocated struct which will be filled with
+ *        default values
+ *
+ * Defaults values:
+ *    suspended - no
+ *    bandwidth_limit - 0
+ *    shared_bandwidth_limit - 0
+ *    arbitration - WSP
+ *    best_effort_enable - no
+ *    parent - 0
+ *    priority - 0
+ *    bandwidth_share - 0
+ */
+void pp_qos_sched_conf_set_default(struct pp_qos_sched_conf *conf);
+
+
+/**
+ * pp_qos_sched_allocate() - Allocate a resource for a new scheduler
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:   upon success - holds new scheduler's id
+ *
+ * Return:  0 on success.
+ */
+int pp_qos_sched_allocate(struct pp_qos_dev *qos_dev, unsigned int *id);
+
+
+/**
+ * pp_qos_sched_remove() -	Remove scheduler
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	  scheduler's id obtained from sched_allocate
+ *
+ * Return:	0 on success
+ */
+int pp_qos_sched_remove(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_sched_set() - Set scheduler configuration
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	  scheduler's id obtained from sched_allocate
+ * @conf: new configuration for the scheduler
+ *
+ * Note: must init conf by pp_qos_sched_conf_init before calling
+ *       this function.
+ *
+ * Return: 0 on success
+ */
+int pp_qos_sched_set(struct pp_qos_dev *qos_dev, unsigned int id,
+		     const struct pp_qos_sched_conf *conf);
+
+
+/**
+ * pp_qos_sched_suspend() - Remove scheduler from scheduling
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	  scheduler's id obtained from sched_allocate
+ *
+ * Return: 0 on success
+ */
+int pp_qos_sched_suspend(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_sched_resume() - Return scheduler and its decendants scheduleable
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:   scheduler's id obtained from sched_allocate
+ *
+ * Return: 0 on success
+ */
+int pp_qos_sched_resume(struct pp_qos_dev *qos_dev, unsigned int id);
+
+
+/**
+ * pp_qos_sched_conf_get() - Get sched current configuration
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * id:	  port's id obtained from port_allocate
+ * @conf: pointer to struct to be filled with sched's configuration
+ *
+ * Return: 0 on success
+ */
+int pp_qos_sched_conf_get(struct pp_qos_dev *qos_dev, unsigned int id,
+			  struct pp_qos_sched_conf *conf);
+
+
+/**
+ * pp_qos_sched_info_get() - Get information about scheduler
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	  scheduler's id obtained from sched_allocate
+ * @info: pointer to struct to be filled with scheduler's info
+ *
+ * Return: 0 on success
+ */
+int pp_qos_sched_info_get(struct pp_qos_dev *qos_dev, unsigned int id,
+			  struct pp_qos_sched_info *info);
+
+
+/**
+ * pp_qos_sched_get_queues() - Get all scheduler's queues
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	        scheduler's id obtained from sched_allocate
+ * @queue_ids:  client allocated array that will hold queues ids
+ * @size:       size of queue_ids
+ * @queues_num: holds the number of queues
+ *
+ * Note queues_num can be bigger than size
+ *
+ * Return: 0 on success
+ */
+int pp_qos_sched_get_queues(struct pp_qos_dev *qos_dev, unsigned int id,
+			    uint16_t *queue_ids, unsigned int size,
+			    unsigned int *queues_num);
+
+/******************************************************************************/
+/*                                 SHARED_LIMIT                               */
+/******************************************************************************/
+
+/**
+ * qos_shared_limit_group_add() - Add new shared bandwidth group
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @limit: bandwidth limit in Mbps
+ * @id:    upon success, new group's id
+ *
+ * Return: 0 on success
+ */
+int pp_qos_shared_limit_group_add(struct pp_qos_dev *qos_dev,
+				  unsigned int limit, unsigned int *id);
+
+
+/**
+ * pp_qos_shared_limit_group_remove() - Remove shared bandwidth group
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id: group's id previously obtained when adding group
+ *
+ * Return: 0 on success
+ */
+int pp_qos_shared_limit_group_remove(struct pp_qos_dev *qos_dev,
+				     unsigned int id);
+
+
+/**
+ * pp_qos_shared_limit_group_modify() - Modify shared bandwidth group
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id: group's id previously obtained when adding group
+ * @limit: bandwidth limit in Mbps
+ *
+ * Return: 0 on success
+ */
+int pp_qos_shared_limit_group_modify(struct pp_qos_dev *qos_dev,
+				     unsigned int id, unsigned int limit);
+
+
+/**
+ * pp_qos_shared_limit_group_get_members() - Get group's members
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @id:	   shared bandwidth group id
+ * @members:   client allocated array that will hold ids members
+ * @size:        size of ids
+ * @members_num: holds the number of members
+ *
+ * Notes:
+ * members_num can be bigger than size
+ * function iterates over tree so it is rather slow
+ *
+ * Return: 0 on success
+ */
+int pp_qos_shared_limit_group_get_members(struct pp_qos_dev *qos_dev,
+					  unsigned int id, uint16_t *members,
+					  unsigned int size,
+					  unsigned int *members_num);
+
+
+
+/******************************************************************************/
+/*                                  INIT	                              */
+/******************************************************************************/
+
+/**
+ * pp_qos_dev_open() -	Initialize of a qos device
+ * @id: Identify the requested qos instance (same id that
+ *      designates the instance in the device tree)
+ *
+ * Return: on success handle to qos device
+ *         NULL otherwise
+ */
+struct pp_qos_dev *pp_qos_dev_open(unsigned int id);
+
+
+/**
+ * @struct pp_qos_init_param - qos subsystem initialization struct
+ * @wred_total_avail_resources: upper bound for the sum of bytes on all queues
+ * @wred_p_const:         WRED algorithm p, used for calculating avg queue depth
+ *                        avg = (old_avg*(1-p)) + (curr_avg*p)
+ *                        p is taken to b wred_p_const / 1023
+ *                        wred_p_const should be in the range 0..1023
+ * @wred_max_q_size:      maximum size on bytes of any queue
+ * @reserved_ports:       These ports are reserved for client to explicity
+ *                        select the physical_port ithat will be used when
+ *                        adding a new port. All other non reserved ports are
+ *                        managed by the system, i.e. when client adds a new
+ *                        port system will select a new free port from the
+ *                        unreserved ports.
+ *                        To reserve a port its value on the array should be
+ *                        not 0
+ */
+struct pp_qos_init_param {
+	unsigned int wred_total_avail_resources;
+	unsigned int wred_p_const;
+	unsigned int wred_max_q_size;
+	#define MAX_PORTS    128
+	unsigned int reserved_ports[MAX_PORTS];
+};
+
+
+/**
+ * pp_qos_dev_init() - set qos system wide configuration
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @conf:
+ *
+ * Note
+ * All other functions except pp_qos_dev_open will failed if called
+ * before this function
+ *
+ * Return: 0 on success
+ */
+int pp_qos_dev_init(struct pp_qos_dev *qos_dev, struct pp_qos_init_param *conf);
+
+/**
+ * pp_qos_dev_clean() - clean resources.
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ *
+ * Note:
+ *   qos_dev is invalid after this call
+ */
+void pp_qos_dev_clean(struct pp_qos_dev *qos_dev);
+
+
+/**
+ * pp_qos_get_fw_version () - get fw version
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @major: storage for major part of version
+ * @minor: storage for minor part of version
+ * @build: storage for build part of version
+ */
+int pp_qos_get_fw_version(
+		struct pp_qos_dev *qos_dev,
+		unsigned int *major,
+		unsigned int *minor,
+		unsigned int *build);
+
+
+enum pp_qos_node_type {
+	PPV4_QOS_NODE_TYPE_PORT,
+	PPV4_QOS_NODE_TYPE_SCHED,
+	PPV4_QOS_NODE_TYPE_QUEUE,
+};
+
+#define PPV4_QOS_INVALID (-1U)
+
+
+struct pp_qos_node_num {
+	/*
+	 * Physical node on scheduler's
+	 * node table
+	 */
+	unsigned int phy;
+
+	/*
+	 * Logical id seen by client
+	 */
+	unsigned int id;
+};
+
+/**
+ * struct pp_qos_node_info () -
+ * @ppv4_qos_node_type:
+ * @preds:		Ansectors of node (irrelevant to PORT)
+ * @num_of_children:    Number of direct children (irrelevant to QUEUE)
+ * @children:		Direct children of node (irrelevant to QUEUE)
+ * @is_suspended:	Is node suspended
+ * @is_internal:	Is it internal node
+ * @queue_physical_id:	Relevant only for QUEUE
+ * @bw_limit:		In Kbps
+ * @port:		The port (phy) that is fed from this queue
+ *                      (relevant only for QUEUE)
+ *
+ * Note:
+ * Since 0 is a valid value for some of the fields. PPV4_QOS_INVALID will
+ * be used to mark field value as irrelevant
+ *
+ * All above values except from type, is_internal and logical id
+ * are taken from HW and not from driver DB
+ */
+struct pp_qos_node_info {
+	enum pp_qos_node_type type;
+	struct pp_qos_node_num preds[6];
+	struct pp_qos_node_num children[8];
+	int is_suspended;
+	int is_internal;
+	unsigned int queue_physical_id;
+	unsigned int bw_limit;
+	unsigned int port;
+};
+
+/**
+ * pp_qos_get_node_info () - Obtain node's info
+ * @qos_dev: handle to qos device instance obtained from pp_qos_dev_open
+ * @info: Storage for info
+ * Return: 0 on success
+ */
+int pp_qos_get_node_info(
+		struct pp_qos_dev *qos_dev,
+		unsigned int id,
+		struct pp_qos_node_info *info);
+
+
+
+#endif
diff --git a/include/net/pp_qos_drv_slim.h b/include/net/pp_qos_drv_slim.h
index 0bf722e58663face4fa2d1e1dfb18a593f5cd25d..9ee7de4b73687c4621b42b8a5df310e4c015c8b1 100644
--- a/include/net/pp_qos_drv_slim.h
+++ b/include/net/pp_qos_drv_slim.h
@@ -302,14 +302,4 @@ s32 qos_node_get_stats(struct qos_node_stats *param);
  **/
 s32 qos_init_subsystem(struct qos_init_param *param);
 
-
-struct pp_qos_dev {
-	int dq_port;
-};
-
-//int pp_qos_queue_remove(struct pp_qos_dev *qos_dev, int id);
-int pp_qos_port_remove(struct pp_qos_dev *qos_dev, int id);
-
-
-
 #endif /* PPQOSDRV_H_ */