#include "rtl867x_8367b_qos.h"
#include "rtl867x_8367b_acl.h"
#include "../../rtl8367b/port.h"
#include "../../../../net/bridge/br_private.h"
#include "../../rtl8367b/rtl8367b_asicdrv_acl_para.h"
#include <net/rtl/rtl_nic.h>

static int rtl8367b_iprange_uesd[RL6000_ACLRANGERULENUM];
static int rtl8367b_portrange_uesd[RL6000_ACLRANGERULENUM];

#define rtl8367b_UPSTREAM_Quene_NUM		4
#define rtl8367b_Queue_NOT_Create		-1


struct list_head rtl8367b_qosRuleHead;

typedef struct rtl8367b_aclpriority_mapping_data_s
{
	uint8 valid;
	uint8 Qid;
	uint32 ref_count;
} rtl8367b_aclpriority_mapping_data_t;

static rtl8367b_aclpriority_mapping_data_t 	rtl8367b_priority_mapping[RTK_MAX_NUM_OF_PRIORITY];
static int32 							rtl8367b_priority_default =-1;
static uint32 						rtl8367b_hwQid2swQid_Mapping[RTK_MAX_NUM_OF_QUEUE] = {0};

/* 
	input : 
		is_dest  :    0: ipv4 source ip    1 : ipv4 destnation ip
	return :
		ip_range's index ,  if -1 : error 
*/
static int _rtl867x_8367b_add_iprange(uint32 ip_start,uint32 ip_end,int is_dest)
{	
	rtk_api_ret_t	ret_val;
	int candidate_index=-1;
	int i;

	if(ip_end<ip_start)
	{			
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		return -1;
	}	

	for(i=0;i<RL6000_ACLRANGERULENUM;i++)
	{
		if(!rtl8367b_iprange_uesd[i])
		{
			candidate_index = i;
			break;
		}
	}
	
	if(candidate_index == -1)
	{			
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		return -1;
	}		
	ret_val = rtk_filter_iprange_set(candidate_index, is_dest? IPRANGE_IPV4_DIP : IPRANGE_IPV4_SIP, ip_end, ip_start);
	if(ret_val!=RT_ERR_OK)
    {
		DBG_8367B_QOS_PRK("Leave %s @ %d rtk_filter_iprange_set failed!\n",__func__,__LINE__);	
		return -1;
    }
	else
	{
		rtl8367b_iprange_uesd[candidate_index] = 1;
		return candidate_index;
	}
}

static void _rtl867x_8367b_del_iprange(uint32 bitmask)
{	
	int index;

	for(index=0;index<RL6000_ACLRANGERULENUM;index++)
	{
		if( (1<<index) & bitmask)
		{
			rtk_filter_iprange_set(index, IPRANGE_UNUSED, 0, 0);
			rtl8367b_iprange_uesd[index]=0;
		}
	}
}

/* 
	input : 
		is_dest  :    0: L4 source port    1 : L4 destnation port
	return :
		ip_range's index ,  if -1 : error 
*/
static int _rtl867x_8367b_add_portrange(uint16 port_start,uint16 port_end,int is_dest)
{	
	rtk_api_ret_t	ret_val;
	int candidate_index=-1;
	int i;

	DBG_8367B_QOS_PRK("Enter %s(port_start:%d   port_end:%d   is_dest:%d)\n",__func__,port_start,port_end,is_dest);

	if(port_end<port_start)
	{			
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		return -1;
	}	

	for(i=0;i<RL6000_ACLRANGERULENUM;i++)
	{
		if(!rtl8367b_portrange_uesd[i])
		{
			candidate_index = i;
			break;
		}
	}
	
	if(candidate_index == -1)
	{			
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		return -1;
	}
	ret_val = rtk_filter_portrange_set(candidate_index, is_dest? PORTRANGE_DPORT : PORTRANGE_SPORT, port_end, port_start);
	if(ret_val!=RT_ERR_OK)
    {
		DBG_8367B_QOS_PRK("Leave %s @ %d rtk_filter_portrange_set failed!\n",__func__,__LINE__);	
		return -1;
    }
	else
	{
		rtl8367b_portrange_uesd[candidate_index] = 1;
		return candidate_index;
	}
}

static void _rtl867x_8367b_del_portrange(uint32 bitmask)
{	
	int index;

	for(index=0;index<RL6000_ACLRANGERULENUM;index++)
	{
		if( (1<<index) & bitmask)
		{
			rtk_filter_portrange_set(index, IPRANGE_UNUSED, 0, 0);
			rtl8367b_portrange_uesd[index]=0;
		}
	}
}

int _rtl867x_8367b_set_port_priority(int port, int priority)
{
	if(rtk_qos_portPri_set(port, priority)!=RT_ERR_OK)
	{
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		return FAILED;
	}
	return SUCCESS;
}



static int my_gcd(int numA, int numB)
{
	int	tmp;
	int	divisor;

	if (numA<numB)
	{
		tmp = numA;
		numA = numB;
		numB = tmp;
	}

	divisor = numA%numB;
	while(divisor)
	{
		numA = numB;
		numB = divisor;
		divisor = numA%numB;
	}

	return numB;
}


static void _rtl867x_8367b_qosArrangeQueue(int ceil[],int rate[],uint32 bands_num)
{	
	int	i; 		
	

	#ifdef DBG_8367B_QOS
	DBG_8367B_QOS_PRK("Enter %s\n",__func__);		
	DBG_8367B_QOS_PRK("(%s)------------Before--------------------\n",__func__);
	for(i=0; i<bands_num; i++)
		DBG_8367B_QOS_PRK("(%s) [Queue %d] bandwidth:%d(bits)  ceil:%d\n",__func__,i,rate[i],ceil[i]);		
	DBG_8367B_QOS_PRK("-------------------------------------------------------------\n");
	#endif	

	
	/* bandwidth
		only can be set as 1~128 ,  if the maxBandwidth>128 ..... 

		 ex. bandwidth_0 = 3  , bandwidth_1 = 254 , bandwidth_2 = 257
		 we shift right these value until  the maxBandwidth/divisor <= 128   */
	
	do
	{
		int	divisor;
		int	maxBandwidth;
		
		for(i=0; i<bands_num; i++)
		{		
			if(rate[i]==0)
				rate[i] = 1;			
		}

		/* calculate gcd */
		divisor = rate[0];
		for(i=1; i<bands_num; i++)				
			divisor = my_gcd(rate[i], divisor);		
		
		for(i=0; i<bands_num; i++)				
			rate[i] = rate[i]/divisor;		

		/* maxBandwidth has to <= 128*/
		maxBandwidth = 0;
		for(i=0; i<bands_num; i++)
		{		
			if(maxBandwidth<rate[i])
				maxBandwidth = rate[i];		
		}
		if(maxBandwidth<=QOS_WEIGHT_MAX)
			break;

		/* start right shift .. */
		for(i=0; i<bands_num; i++)				
			rate[i] = rate[i]>>1 ;		
		
	}while(1);



	#ifdef DBG_8367B_QOS	
	DBG_8367B_QOS_PRK("(%s)------------After--------------------\n",__func__);
	for(i=0; i<bands_num; i++)
		DBG_8367B_QOS_PRK("(%s) [Queue %d] bandwidth:%d(bits)  ceil:%d\n",__func__,i,rate[i],ceil[i]);		
	DBG_8367B_QOS_PRK("-------------------------------------------------------------\n");	
	DBG_8367B_QOS_PRK("Leave %s\n",__func__);
	#endif


	
	
}

static int _rtl867x_8367b_qos_setQueueInfo(int sp_queue_num, int wrr_queue_num,int queue_number,int ceil[],int rate[])
{
	/*   Start  to set Queue scheduling ..  
		8676 embeded switch 	: set queue's number /  set queue's scheduling info / enable remark

		ex. if sp_queue_num=1 , wrr_queue_num=2   queue_number=4

			hw_qid : 0   1   2   3   4   5 
			sw_qid:  1   2   -1   0  -1   -1

			we only use the first 4 hw Queues 
			set hw_Queue 0 & 1 as WRR type
			set the remainging hw_Queue 2 & 3 as SP type (we will not use hw_Queue 2)
	*/		
	rtk_qos_queue_weights_t qweights;
	int queue_idx;
	memset(&qweights,0,sizeof(rtk_qos_queue_weights_t));

	if(sp_queue_num+wrr_queue_num >queue_number)
		return FAILED;
	
	/* 2.1	set queue's number	*/
	if(rtk_qos_init(queue_number)!=RT_ERR_OK) /* all ports uses 4 queues */
		return FAILED;

	/* 2.2	set queue's scheduling info  */ 			
	for (queue_idx=0;queue_idx<queue_number;queue_idx++)
	{
		if(queue_idx < wrr_queue_num) /* wrr */ 
			qweights.weights[queue_idx] = rate[queue_idx]; 		
		else /* sp */
			qweights.weights[queue_idx] = 0;									
	}	
	
	if(rtk_qos_schedulingQueue_set(RL6000_CPU_PORT,&qweights)!=RT_ERR_OK)	
		return FAILED;	


	return SUCCESS;
}

/* Get hw_Qid */
static int32 _rtl867x_8367b_qosQIDMappingGet( uint32 sw_Qidx)
{
	int	i;

	for(i=0; i < RTK_MAX_NUM_OF_QUEUE; i++)
	{
		if (rtl8367b_hwQid2swQid_Mapping[i] == sw_Qidx)
		{
			return i;
		}
	}

	return -1;
}


static int _rtl867x_8367b_qosQIDMappingSet(int32 Qidmapping[RTK_MAX_NUM_OF_QUEUE])
{		
	memcpy(rtl8367b_hwQid2swQid_Mapping,Qidmapping,RTK_MAX_NUM_OF_QUEUE*sizeof(int));	
	return SUCCESS;
}


static void _rtl867x_8367b_qosQIDMappingClear(void)
{	
	int i;		
	for(i=0;i<RTK_MAX_NUM_OF_QUEUE;i++)
		rtl8367b_hwQid2swQid_Mapping[i] = rtl8367b_Queue_NOT_Create;	
	
}

static int _rtl867x_8367b_qosPriorityMappingTakeEffect(void)
{	
	int32  i;	

	rtk_qos_pri2queue_t pri2qid;
	memset(&pri2qid,0,sizeof(rtk_qos_pri2queue_t));

	for(i=0;i<RTK_MAX_NUM_OF_PRIORITY;i++)		
	{
		pri2qid.pri2queue[i] = rtl8367b_priority_mapping[i].Qid;
	}
	
	if(rtk_qos_priMap_set(rtl8367b_UPSTREAM_Quene_NUM,&pri2qid)!=RT_ERR_OK)
		return FAILED;	

	return SUCCESS;	
}


static void _rtl867x_8367b_qosPriorityMappingDeRef(uint32 priority)	
{

	if(priority<0 || priority>=RTK_MAX_NUM_OF_PRIORITY)
		return;

	rtl8367b_priority_mapping[priority].ref_count--;
	if(rtl8367b_priority_mapping[priority].ref_count==0)
	{
		memset(&rtl8367b_priority_mapping[priority], 0,sizeof(rtl8367b_aclpriority_mapping_data_t));
		if(_rtl867x_8367b_qosPriorityMappingTakeEffect()!=SUCCESS)
		{
			printk("%s@ %d(return FAILED)\n",__func__,__LINE__);
			DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);		
		}
	}		

}

/* return ...     -1:   no avaliable acl priority mapping   others: acl priority 
	Note. At the same time ,ref_count ++ */
static int _rtl867x_8367b_qosPriorityMappingGet(uint32 sw_Qidx)
{
	int32  i,empty_idx,hw_queue_idx;	

	DBG_8367B_QOS_PRK("Enter %s (sw_Qidx:%d)\n"	,__func__,sw_Qidx); 
	
	hw_queue_idx = _rtl867x_8367b_qosQIDMappingGet(sw_Qidx);
	if(hw_queue_idx==-1)
	{
		DBG_8367B_QOS_PRK("Leave %s @ %d\n",__func__,__LINE__);	
		return -1;	
	}

	DBG_8367B_QOS_PRK("(%s)  hw_queue_idx=%d \n",__func__,hw_queue_idx);	
	

	for(i=0;i<RTK_MAX_NUM_OF_PRIORITY;i++)
	{
		if( rtl8367b_priority_mapping[i].valid 
			&& rtl8367b_priority_mapping[i].Qid == hw_queue_idx)
		{

			rtl8367b_priority_mapping[i].ref_count++;		
			DBG_8367B_QOS_PRK("Leave %s (return existed priority %d, ref:%d)\n",__func__,i,rtl8367b_priority_mapping[i].ref_count);
			return i;
		}
	}

	/* cannot find out matching entry, create the new one*/
	empty_idx = -1;
	for(i=0;i<RTK_MAX_NUM_OF_PRIORITY;i++)
	{
		if(rtl8367b_priority_mapping[i].valid==0)
		{
			empty_idx = i;
			break;
		}
	}
	if(empty_idx==-1)
	{
		DBG_8367B_QOS_PRK("Leave %s (return %d)\n",__func__,-1);
		return -1; /* no empty entry */
	}

	rtl8367b_priority_mapping[empty_idx].valid 			= 1	;
	rtl8367b_priority_mapping[empty_idx].Qid 			= hw_queue_idx;
	rtl8367b_priority_mapping[empty_idx].ref_count		= 1	;


	/*  let new acl_priority mapping take effect */
	if(_rtl867x_8367b_qosPriorityMappingTakeEffect()!=SUCCESS)
	{
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		return FAILED;
	}	

	DBG_8367B_QOS_PRK("Leave %s (return new priority %d, ref:%d)\n",__func__,i,rtl8367b_priority_mapping[i].ref_count);
	return empty_idx;
	
}


int32 rtl867x_8367b_enableQos(int sp_queue_num, int wrr_queue_num, int ceil[],int rate[] ,int32 default_sw_qid)
{

	int total_queue_num = sp_queue_num + wrr_queue_num;
	int Qidmapping[RTK_MAX_NUM_OF_QUEUE];
	rtk_priority_select_t priDec;	
	int i;

	DBG_8367B_QOS_PRK("Enter %s (sp_queue_num:%d   wrr_queue_num:%d   default_sw_qid:%d)\n"
		,__func__,sp_queue_num,wrr_queue_num,default_sw_qid);

	/* 1. check queue number */
	if (sp_queue_num<0 || wrr_queue_num<0 )
	{
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED) \n",__func__,__LINE__);
		return FAILED;	
	}
	
	if( total_queue_num<1 || total_queue_num>rtl8367b_UPSTREAM_Quene_NUM)
	{
		printk("(%s)Warning!! rtl8367b switch only support 1~%d outputqueues in upstream (Your input is %d) \n"
			,__func__,rtl8367b_UPSTREAM_Quene_NUM,total_queue_num);
		return FAILED;	
	}
	
	if (default_sw_qid<0 || default_sw_qid>=total_queue_num)
	{
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED) \n",__func__,__LINE__);
		return FAILED;	
	}

	/* 2.  Re-adjust qosinfo's para  */
	if(wrr_queue_num>0)
	{
		if(ceil==NULL || rate==NULL)
		{
			DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED) \n",__func__,__LINE__);
			return FAILED;	

		}

		_rtl867x_8367b_qosArrangeQueue(ceil,rate,wrr_queue_num);
	}


	/* 3.  set QueueID mapping
		ex. if we create 4 queues (2 is priority , 2 is wrr )
			sw_qid ==>	0 : the highest priority 
						1 : the second priority 
						2 : 1st wrr queue
						3 : 2nd wrr queue
			
			hw_qid : 0   1   2   3    4     5   6    7    8
			sw_qid:  2   3    1   0  -1   -1  -1   -1   -1 

		ex. if we create 3 queues (1 is priority , 2 is wrr )
			sw_qid ==>	0 : the highest priority 					
						1 : 1st wrr queue
						2 : 2nd wrr queue
			
			hw_qid : 0   1   2   3   4     5    6    7    8
			sw_qid:  1   2   -1   0  -1   -1  -1  -1   -1 
	*/	
	for(i=0;i<RTK_MAX_NUM_OF_QUEUE;i++)
		Qidmapping[i] = rtl8367b_Queue_NOT_Create;

	for(i=0;i<sp_queue_num;i++)		
		Qidmapping[rtl8367b_UPSTREAM_Quene_NUM-1-i] = i;
	
	for(i=0;i<wrr_queue_num;i++)	
		Qidmapping[i] = sp_queue_num+i;
	
	if(_rtl867x_8367b_qosQIDMappingSet(Qidmapping)!=SUCCESS)
	{			
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		return FAILED;
	}

	/*  4. Start  to set Queue scheduling ..  */
	if(_rtl867x_8367b_qos_setQueueInfo(sp_queue_num,wrr_queue_num,rtl8367b_UPSTREAM_Quene_NUM,ceil,rate)!=SUCCESS)
	{
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		return FAILED;
	}

	/*  5. set default acl priority mapping  */
	rtl8367b_priority_default = _rtl867x_8367b_qosPriorityMappingGet(default_sw_qid);
	if(rtl8367b_priority_default==-1)
	{			
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		return FAILED;
	}


	/*  6. init priority setting except fot ACL based in hw 
		RL6000	: port-based (for default priority)
	*/	
	for(i=0; i<RTK_MAX_NUM_OF_PORT; i++)
		_rtl867x_8367b_set_port_priority(i,rtl8367b_priority_default);
	
	
	/*  7.  set  priority  between different qos based 
		RL6000	: ACL-based > port based
	*/	
	memset(&priDec,0,sizeof(rtk_priority_select_t));
	priDec.acl_pri   	= 7;
	priDec.port_pri 	= 6;		
	priDec.dot1q_pri 	= 0;	
	priDec.dscp_pri 	= 0;		
	priDec.cvlan_pri 	= 0;
	priDec.svlan_pri 	= 0;
	priDec.dmac_pri 	= 0;
	priDec.smac_pri 	= 0;
	if(rtk_qos_priSel_set(&priDec)!=RT_ERR_OK )
		return FAILED;


	DBG_8367B_QOS_PRK("Leave %s\n",__func__);
	return SUCCESS;
	
}


int32 rtl867x_8367b_closeQos(void)
{	
	uint32	i;

	DBG_8367B_QOS_PRK("Enter %s\n",__func__);

	/* 1.  clear Qid  mapping and acl priotiy mapping */
	_rtl867x_8367b_qosQIDMappingClear();	

	/*  2. flush all sw qos rules */	
	rtl867x_8367b_flush_qosrule();

	/*  3. clear default acl priority */
	_rtl867x_8367b_qosPriorityMappingDeRef(rtl8367b_priority_default);
	
	/* 4. check whether all ref count reaches zero ? */
	for(i=0;i<RTK_MAX_NUM_OF_PRIORITY;i++)
	{
		if( rtl8367b_priority_mapping[i].valid)
		{			
			printk("(%s)!!!!BUG!!!!  @%d (return %d, ref:%d)\n",__func__,__LINE__,i,rtl8367b_priority_mapping[i].ref_count);		
		}
	}
	
	/*  5. Start  to set Queue scheduling .. (back to number 1)  */
	if(_rtl867x_8367b_qos_setQueueInfo(1,0,1,NULL,NULL)!=SUCCESS)
	{
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		return FAILED;
	}

	DBG_8367B_QOS_PRK("Leave %s\n",__func__);
	return SUCCESS;
}



/* Create a complete 8367b cfg & act  from 8367b SW QoS Rule */
static rtk_filter_action_t* __rtl867x_8367b_qosCreateACLrule(rtl867x_8367b_qos_rule_t* input_rule)
{

	rtk_filter_action_t* act;
	
	act = kmalloc(sizeof(rtk_filter_action_t),GFP_KERNEL);
	if(!act)
		return NULL;

   	memset(act, 0x00, sizeof(rtk_filter_action_t));

	
	act->actEnable[FILTER_ENACT_PRIORITY] = TRUE;
	act->filterPriority 			= input_rule->priority;
	
	return act;

}


/*  	
	FUNC 	: _rtl865x_qosAddRule()
	USAGE	: Add a new sw_qos entry into sw_qos_list , and add asic acl rule 
		
	Note.  
		1. It is caller's respnsibility to promise that all fileds  (except for linking list) in input_rule has been assigned correctly
		2. You have to get priority first. (Ref priority)	
*/

static int _rtl867x_8367b_qosAddRule(rtl867x_8367b_qos_rule_t* input_rule)
{
	rtk_filter_action_t*			rule_act;

	rule_act = __rtl867x_8367b_qosCreateACLrule(input_rule);
	if(!rule_act)
		return FAILED;	

	if (rtl867x_rtl8367b_addacl(input_rule->rule_cfg, rule_act,RL6000_ACL_CHAIN_QOS) != RT_ERR_OK)
	{
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		kfree(rule_act);
		return FAILED;
	}	

	kfree(rule_act); /* add_acl will memcpy */
	INIT_LIST_HEAD(&input_rule->qos_rule_list);
	list_add_tail(&input_rule->qos_rule_list , &rtl8367b_qosRuleHead);
	
	return SUCCESS;
}

static void _rtl867x_8367b_qosrule_free_cfg(rtl867x_8367b_qos_rule_t* sw_qos_rule)	
{
	 if(sw_qos_rule)
	 {
		/* free rule_cfg */
		if(sw_qos_rule->rule_cfg && sw_qos_rule->rule_cfg->fieldHead)
	 	{
	 		rtl867x_rtl8367b_acl_fieldData_free(&sw_qos_rule->rule_cfg->fieldHead);
	 	}

		if(sw_qos_rule->rule_cfg)
		{
			kfree(sw_qos_rule->rule_cfg);
			sw_qos_rule->rule_cfg = NULL;
		}

		
	 }
}

static void _rtl867x_8367b_qosrule_free_rangeMask(rtl867x_8367b_qos_rule_t* sw_qos_rule)	
{
	if(sw_qos_rule)
	{
		/* release index of iprange_use_bitmask, portrange_use_bitmask */
		if(sw_qos_rule->iprange_use_bitmask!=0)
		{		
			_rtl867x_8367b_del_iprange(sw_qos_rule->iprange_use_bitmask);
			sw_qos_rule->iprange_use_bitmask = 0;
		}

		if(sw_qos_rule->portrange_use_bitmask!=0)
		{
			
			_rtl867x_8367b_del_portrange(sw_qos_rule->portrange_use_bitmask);
			sw_qos_rule->portrange_use_bitmask = 0;
		}
	}
}

/* Convert RTL867x IPQoS Format to rtl8367b acl format 	
*/
static int _rtl867x_8367b_qosConvertDataForamt(rtl867x_hwnat_qos_rule_t* input_rule,rtl867x_8367b_qos_rule_t*	sw_qosRule)
{
	rtk_filter_cfg_t* 	output_cfg=NULL;
	rtk_filter_field_t*	field_smac=NULL;
	rtk_filter_field_t*	field_dmac=NULL;
	rtk_filter_field_t*	field_ctag=NULL;
	rtk_filter_field_t*	field_ethtype=NULL;
	rtk_filter_field_t*	field_scrIP=NULL;
	rtk_filter_field_t*	field_dstIP=NULL;
	rtk_filter_field_t*	field_ipRange=NULL;
	rtk_filter_field_t*	field_tos=NULL;
	rtk_filter_field_t*	field_ipProto=NULL;
	rtk_filter_field_t*	field_portRange=NULL;
	rtk_filter_field_t*	field_always_match=NULL;
	int physical_port=-1;
	int add_field = 0;

	if(!sw_qosRule || !input_rule)
		goto convert_fail;
	output_cfg = kmalloc(sizeof(rtk_filter_cfg_t),GFP_KERNEL);
	if(!output_cfg)
		goto convert_fail;

	/* initialize */
	memset(output_cfg, 0x00, sizeof(rtk_filter_cfg_t));
	sw_qosRule->iprange_use_bitmask = 0;
	sw_qosRule->portrange_use_bitmask = 0;

	/*   Physical port  */
	if(input_rule->rule_type != RTL867x_IPQos_Format_srcPort_setMask && input_rule->match_field.PHY._lan_netifname[0]!='\0')
	{	
		struct net_device *dev = re865x_get_netdev_by_name(input_rule->match_field.PHY._lan_netifname);
		
		/*  check whether this interface is  under br0 */
		if(dev)
		{
			struct net_bridge_port *br_port = dev->br_port;
			if(br_port && !strcmp(dev->br_port->br->dev->name,RTL_DRV_LAN_NETIF_NAME))
			{
				int port_idx =0 ;	

				for(port_idx=0;port_idx<RL6000_CPU_PORT;port_idx++)
				{
					if((1<<port_idx)&((struct dev_priv *)dev->priv)->portmask)

					{
						physical_port=(1<<port_idx);
						break;
					}
				}					
			}
		}
	}
	else if(input_rule->rule_type == RTL867x_IPQos_Format_srcPort_setMask && input_rule->match_field.PHY._lan_portmask!=0)
	{
		physical_port=input_rule->match_field.PHY._lan_portmask;
	}
	
	/* Source MAC */
	if(input_rule->match_field.L2._srcMacMask.octet[0]	|| input_rule->match_field.L2._srcMacMask.octet[1]
		|| input_rule->match_field.L2._srcMacMask.octet[2] || input_rule->match_field.L2._srcMacMask.octet[3]
		|| input_rule->match_field.L2._srcMacMask.octet[4] || input_rule->match_field.L2._srcMacMask.octet[5])
	{	
		field_smac = kmalloc(sizeof(rtk_filter_field_t),GFP_KERNEL);
   		memset(field_smac, 0x00, sizeof(rtk_filter_field_t));	

		field_smac->fieldType = FILTER_FIELD_SMAC;
		field_smac->filter_pattern_union.smac.dataType = FILTER_FIELD_DATA_MASK;
		memcpy(field_smac->filter_pattern_union.smac.value.octet,input_rule->match_field.L2._srcMac.octet,ETHER_ADDR_LEN);
		memcpy(field_smac->filter_pattern_union.smac.mask.octet,input_rule->match_field.L2._srcMacMask.octet,ETHER_ADDR_LEN);

		if( rtk_filter_igrAcl_field_add(output_cfg, field_smac) != RT_ERR_OK)
			goto convert_fail;		

		add_field = 1;
	}

	/* Destination  MAC */
	if(input_rule->match_field.L2._dstMacMask.octet[0]	|| input_rule->match_field.L2._dstMacMask.octet[1]
		|| input_rule->match_field.L2._dstMacMask.octet[2] || input_rule->match_field.L2._dstMacMask.octet[3]
		|| input_rule->match_field.L2._dstMacMask.octet[4] || input_rule->match_field.L2._dstMacMask.octet[5])
	{	
		field_dmac = kmalloc(sizeof(rtk_filter_field_t),GFP_KERNEL);
   		memset(field_dmac, 0x00, sizeof(rtk_filter_field_t));	

		field_dmac->fieldType = FILTER_FIELD_DMAC;
		field_dmac->filter_pattern_union.dmac.dataType = FILTER_FIELD_DATA_MASK;
		memcpy(field_dmac->filter_pattern_union.dmac.value.octet,input_rule->match_field.L2._dstMac.octet,ETHER_ADDR_LEN);
		memcpy(field_dmac->filter_pattern_union.dmac.mask.octet,input_rule->match_field.L2._dstMacMask.octet,ETHER_ADDR_LEN);

		if( rtk_filter_igrAcl_field_add(output_cfg, field_dmac) != RT_ERR_OK)
			goto convert_fail;	

		add_field = 1;
	}

	/* VLAN ID , 802.1p  */
	if(input_rule->match_field.L2._vlanidMask || input_rule->match_field.L2._8021pMask)
	{
		field_ctag = kmalloc(sizeof(rtk_filter_field_t),GFP_KERNEL);
		memset(field_ctag, 0x00, sizeof(rtk_filter_field_t));

		field_ctag->fieldType = FILTER_FIELD_CTAG;
		
		if(input_rule->match_field.L2._vlanidMask)
		{
			field_ctag->filter_pattern_union.ctag.vid.dataType = FILTER_FIELD_DATA_MASK;
			field_ctag->filter_pattern_union.ctag.vid.value = input_rule->match_field.L2._vlanid;
			field_ctag->filter_pattern_union.ctag.vid.mask = input_rule->match_field.L2._vlanidMask;
		}

		if(input_rule->match_field.L2._8021pMask)
		{
			field_ctag->filter_pattern_union.ctag.pri.dataType = FILTER_FIELD_DATA_MASK;
			field_ctag->filter_pattern_union.ctag.pri.value = input_rule->match_field.L2._8021p;
			field_ctag->filter_pattern_union.ctag.pri.mask = input_rule->match_field.L2._8021pMask;
		}

		if( rtk_filter_igrAcl_field_add(output_cfg, field_ctag) != RT_ERR_OK)
			goto convert_fail;	

		add_field = 1;
	}

	/* Ether Type  */
	if(input_rule->match_field.L2._ethTypeMask)
	{
		field_ethtype = kmalloc(sizeof(rtk_filter_field_t),GFP_KERNEL);
		memset(field_ethtype, 0x00, sizeof(rtk_filter_field_t));

		field_ethtype->fieldType = FILTER_FIELD_ETHERTYPE;
		field_ethtype->filter_pattern_union.etherType.dataType = FILTER_FIELD_DATA_MASK;
		field_ethtype->filter_pattern_union.etherType.value = input_rule->match_field.L2._ethType;
		field_ethtype->filter_pattern_union.etherType.mask = input_rule->match_field.L2._ethTypeMask;

		if( rtk_filter_igrAcl_field_add(output_cfg, field_ethtype) != RT_ERR_OK)
			goto convert_fail;	

		add_field = 1;
	}

	/* Source IP  */	
	if(	(	input_rule->rule_type == RTL867x_IPQos_Format_IP 
		|| 	input_rule->rule_type == RTL867x_IPQos_Format_TCP
		|| 	input_rule->rule_type == RTL867x_IPQos_Format_UDP
		|| 	input_rule->rule_type == RTL867x_IPQos_Format_srcFilter
		|| 	input_rule->rule_type == RTL867x_IPQos_Format_8367Ext_IPMask	)
	
		&& (input_rule->match_field.L3.ip.mask._sipMask))
	{
		field_scrIP = kmalloc(sizeof(rtk_filter_field_t),GFP_KERNEL);
		memset(field_scrIP, 0x00, sizeof(rtk_filter_field_t));

		field_scrIP->fieldType = FILTER_FIELD_IPV4_SIP;
		field_scrIP->filter_pattern_union.sip.dataType = FILTER_FIELD_DATA_MASK;
		field_scrIP->filter_pattern_union.sip.value = input_rule->match_field.L3.ip.mask._sip;
		field_scrIP->filter_pattern_union.sip.mask = input_rule->match_field.L3.ip.mask._sipMask;

		if( rtk_filter_igrAcl_field_add(output_cfg, field_scrIP) != RT_ERR_OK)
			goto convert_fail;	

		add_field = 1;
	}

	/* Destination  IP  */
	if(	(	input_rule->rule_type == RTL867x_IPQos_Format_IP 
		|| 	input_rule->rule_type == RTL867x_IPQos_Format_TCP
		|| 	input_rule->rule_type == RTL867x_IPQos_Format_UDP
		|| 	input_rule->rule_type == RTL867x_IPQos_Format_srcFilter
		|| 	input_rule->rule_type == RTL867x_IPQos_Format_8367Ext_IPMask	)
	
		&& (input_rule->match_field.L3.ip.mask._dipMask))
	{
		field_dstIP = kmalloc(sizeof(rtk_filter_field_t),GFP_KERNEL);
		memset(field_dstIP, 0x00, sizeof(rtk_filter_field_t));

		field_dstIP->fieldType = FILTER_FIELD_IPV4_DIP;
		field_dstIP->filter_pattern_union.dip.dataType = FILTER_FIELD_DATA_MASK;
		field_dstIP->filter_pattern_union.dip.value = input_rule->match_field.L3.ip.mask._dip;
		field_dstIP->filter_pattern_union.dip.mask = input_rule->match_field.L3.ip.mask._dipMask;

		if( rtk_filter_igrAcl_field_add(output_cfg, field_dstIP) != RT_ERR_OK)
			goto convert_fail;	

		add_field = 1;
	}	
	
	/* Source IP (Range) , Destination  IP(Range) */
	if(	(	input_rule->rule_type == RTL867x_IPQos_Format_IP_Range 
		|| 	input_rule->rule_type == RTL867x_IPQos_Format_TCP_Range
		|| 	input_rule->rule_type == RTL867x_IPQos_Format_UDP_Range
		|| 	input_rule->rule_type == RTL867x_IPQos_Format_srcFilter_Range
		|| 	input_rule->rule_type == RTL867x_IPQos_Format_8367Ext_IPRange	)
		&& ((input_rule->match_field.L3.ip.range._sip_start!=0 && input_rule->match_field.L3.ip.range._sip_end!=0)
			||(input_rule->match_field.L3.ip.range._dip_start!=0 && input_rule->match_field.L3.ip.range._dip_end!=0)))
	{
		int ip_range_bitmask = 0;
		field_ipRange = kmalloc(sizeof(rtk_filter_field_t),GFP_KERNEL);
		memset(field_ipRange, 0x00, sizeof(rtk_filter_field_t));
		
		if(input_rule->match_field.L3.ip.range._sip_start!=0 && input_rule->match_field.L3.ip.range._sip_end!=0)
		{
			int sip_range_idx = _rtl867x_8367b_add_iprange(input_rule->match_field.L3.ip.range._sip_start
														,input_rule->match_field.L3.ip.range._sip_end,0);

			if(sip_range_idx!=-1)
				ip_range_bitmask |= (1<<sip_range_idx);
			else
				goto convert_fail;
		}

		if(input_rule->match_field.L3.ip.range._dip_start!=0 && input_rule->match_field.L3.ip.range._dip_end!=0)
		{
			int dip_range_idx = _rtl867x_8367b_add_iprange(input_rule->match_field.L3.ip.range._dip_start
														,input_rule->match_field.L3.ip.range._dip_end,1);

			if(dip_range_idx!=-1)
				ip_range_bitmask |= (1<<dip_range_idx);
			else
				goto convert_fail;
		}		

		field_ipRange->fieldType = FILTER_FIELD_IP_RANGE;
		field_ipRange->filter_pattern_union.inData.dataType = FILTER_FIELD_DATA_MASK; 
		field_ipRange->filter_pattern_union.inData.value = ip_range_bitmask;
		field_ipRange->filter_pattern_union.inData.mask = 0xFFFFFFFF;
		sw_qosRule->iprange_use_bitmask = ip_range_bitmask;

		if( rtk_filter_igrAcl_field_add(output_cfg, field_ipRange) != RT_ERR_OK)
			goto convert_fail;	

		add_field = 1;
	}

	/* TOS  */
	if(input_rule->match_field.L3._tosMask)
	{
		field_tos = kmalloc(sizeof(rtk_filter_field_t),GFP_KERNEL);
		memset(field_tos, 0x00, sizeof(rtk_filter_field_t));

		field_tos->fieldType = FILTER_FIELD_IPV4_TOS;
		field_tos->filter_pattern_union.ipTos.dataType = FILTER_FIELD_DATA_MASK;
		field_tos->filter_pattern_union.ipTos.value = input_rule->match_field.L3._tos;
		field_tos->filter_pattern_union.ipTos.mask = input_rule->match_field.L3._tosMask;

		if( rtk_filter_igrAcl_field_add(output_cfg, field_tos) != RT_ERR_OK)
			goto convert_fail;	

		add_field = 1;
	}

	/*  L4 Protocol  */
	if(input_rule->match_field.L3._ipProtoMask)
	{
		field_ipProto = kmalloc(sizeof(rtk_filter_field_t),GFP_KERNEL);
		memset(field_ipProto, 0x00, sizeof(rtk_filter_field_t));

		field_ipProto->fieldType = FILTER_FIELD_IPV4_PROTOCOL;
		field_ipProto->filter_pattern_union.protocol.dataType = FILTER_FIELD_DATA_MASK;
		field_ipProto->filter_pattern_union.protocol.value = input_rule->match_field.L3._ipProto;
		field_ipProto->filter_pattern_union.protocol.mask = input_rule->match_field.L3._ipProtoMask;

		if( rtk_filter_igrAcl_field_add(output_cfg, field_ipProto) != RT_ERR_OK)
			goto convert_fail;	

		add_field = 1;
	}

	/*  TCP/UDP Port  */
	if((input_rule->match_field.L4._sport_start!=0 && input_rule->match_field.L4._sport_end!=0) 
		|| (input_rule->match_field.L4._dport_start!=0 && input_rule->match_field.L4._dport_end!=0))
	{	
		int port_range_bitmask = 0;
		field_portRange = kmalloc(sizeof(rtk_filter_field_t),GFP_KERNEL);
		memset(field_portRange, 0x00, sizeof(rtk_filter_field_t));

		
		if(input_rule->match_field.L4._sport_start!=0 && input_rule->match_field.L4._sport_end!=0)
		{
			int sport_range_idx = _rtl867x_8367b_add_portrange(input_rule->match_field.L4._sport_start
														,input_rule->match_field.L4._sport_end,0);

			if(sport_range_idx!=-1)
				port_range_bitmask |= (1<<sport_range_idx);
		}

		if(input_rule->match_field.L4._dport_start!=0 && input_rule->match_field.L4._dport_end!=0)
		{
			int dport_range_idx = _rtl867x_8367b_add_portrange(input_rule->match_field.L4._dport_start
														,input_rule->match_field.L4._dport_end,1);

			if(dport_range_idx!=-1)
				port_range_bitmask |= (1<<dport_range_idx);
		}			

		field_portRange->fieldType = FILTER_FIELD_PORT_RANGE;
		field_portRange->filter_pattern_union.inData.dataType = FILTER_FIELD_DATA_MASK; 
		field_portRange->filter_pattern_union.inData.value = port_range_bitmask;
		field_portRange->filter_pattern_union.inData.mask = 0xFFFFFFFF;
		sw_qosRule->portrange_use_bitmask = port_range_bitmask;

		if( rtk_filter_igrAcl_field_add(output_cfg, field_portRange) != RT_ERR_OK)
			goto convert_fail;

		add_field = 1;
	}


	/*  If there's no field added into cfg, create a dump always match field */
	if(add_field == 0)
	{	
		DBG_8367B_QOS_PRK("(%s)no field added into cfg, create a dump always match field\n",__func__);
	
		field_always_match = kmalloc(sizeof(rtk_filter_field_t),GFP_KERNEL);
   		memset(field_always_match, 0x00, sizeof(rtk_filter_field_t));	

		field_always_match->fieldType = FILTER_FIELD_SMAC;
		field_always_match->filter_pattern_union.smac.dataType = FILTER_FIELD_DATA_MASK;	

		if( rtk_filter_igrAcl_field_add(output_cfg, field_always_match) != RT_ERR_OK)
			goto convert_fail;	

		add_field = 1;
	}


	output_cfg->activeport.dataType = FILTER_FIELD_DATA_MASK;

  	if(physical_port!=-1) 
   		output_cfg->activeport.value    = (physical_port); /* active on specific lan port  */
	else
		output_cfg->activeport.value    = RL6000_LAN_PORT_BITMAP; /* active on all LAN ports  */

   	output_cfg->activeport.mask	= 0xFF;
   	output_cfg->invert 			= FALSE;

	sw_qosRule->rule_cfg = output_cfg;
	return SUCCESS;
convert_fail:	
	_rtl867x_8367b_qosrule_free_cfg(sw_qosRule);	
	_rtl867x_8367b_qosrule_free_rangeMask(sw_qosRule);	
	return FAILED;
		
}


/* Note.
	1. This function will copy the data in input_qos_rule , the caller can free input_qos_rule after calling function

	TODO : I do not do duplicate check in this fuction 
*/
int rtl867x_8367b_add_qosrule(rtl867x_hwnat_qos_rule_t *input_qos_rule ,int q_index,int* return_index)
{
	rtl867x_8367b_qos_rule_t*	new_qosRule = NULL;
	int priority;
	unsigned int	candidate_index;

	DBG_8367B_QOS_PRK("Enter %s\n",__func__);	

	
	/* Step1. Create a new sw ipqos rule entry  */
	new_qosRule = kmalloc(sizeof(rtl867x_8367b_qos_rule_t), GFP_ATOMIC);
	if(!new_qosRule)
	{
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		goto add_fail;	
	}
	memset(new_qosRule,0,sizeof(rtl867x_8367b_qos_rule_t));	


	/* Step2. convert input rule to 8676 acl rule */
	if(_rtl867x_8367b_qosConvertDataForamt(input_qos_rule,new_qosRule)!=SUCCESS)
	{
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		goto add_fail;
	}	
	

	/* Step3. Setup IPQoS policy  (At the same time, if we found the same qos rule, delete older one) */
	new_qosRule->swQid	= ((q_index>=0)?	q_index: rtl8367b_priority_mapping[rtl8367b_priority_default].Qid);


	/* 	Step3.2  Get acl priority */
	priority = _rtl867x_8367b_qosPriorityMappingGet(new_qosRule->swQid);
	if(priority==-1)
	{
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		goto add_fail;
	}	
	else
		new_qosRule->priority 	= priority;		


	/* Step 4. find an available unique index */
	candidate_index=0;	
	while(1)
	{
		int 	findout = 1;			
		rtl867x_8367b_qos_rule_t	*qosRule_entry;	

		list_for_each_entry(qosRule_entry,&rtl8367b_qosRuleHead,qos_rule_list)
		{
			if(candidate_index==qosRule_entry->index)
			{
				findout = 0;
				break;
			}
		}

		if(findout)
		{
			new_qosRule->index = candidate_index;
			break;
		}
		else		
			candidate_index++;
		
	}

	
	/* Step 5. Finally, start to add acl rule*/	
	if(_rtl867x_8367b_qosAddRule(new_qosRule)!=SUCCESS)	
		goto add_fail_deref_prio;


	*return_index = new_qosRule->index;
	DBG_8367B_QOS_PRK("Leave %s\n",__func__);	
	return SUCCESS;

add_fail_deref_prio:
	_rtl867x_8367b_qosPriorityMappingDeRef(priority);
add_fail:
	if(new_qosRule)
	{
		_rtl867x_8367b_qosrule_free_cfg(new_qosRule);	
		_rtl867x_8367b_qosrule_free_rangeMask(new_qosRule);
		kfree(new_qosRule);
	}
	DBG_8367B_QOS_PRK("Leave %s @ %d\n",__func__,__LINE__);	
	return FAILED;
}

static int _rtl867x_8367b_del_qosrule(rtl867x_8367b_qos_rule_t*	del_qosRule)
{
	rtk_filter_action_t*	temp_qosRule_act = NULL;
	int del_success = 0;
	
	temp_qosRule_act = __rtl867x_8367b_qosCreateACLrule(del_qosRule);
	if(!temp_qosRule_act)
	{
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		goto exit_and_free_data;
	}	

	if(rtl867x_rtl8367b_delacl(del_qosRule->rule_cfg,temp_qosRule_act,RL6000_ACL_CHAIN_QOS)!=SUCCESS)
	{
		DBG_8367B_QOS_PRK("Leave %s@ %d(return FAILED)\n",__func__,__LINE__);
		goto exit_and_free_data;
	}

	_rtl867x_8367b_qosPriorityMappingDeRef(del_qosRule->priority);
	_rtl867x_8367b_qosrule_free_cfg(del_qosRule);	
	_rtl867x_8367b_qosrule_free_rangeMask(del_qosRule);	
	list_del(&del_qosRule->qos_rule_list);		
	kfree(del_qosRule);
	del_success = 1;

exit_and_free_data:
	if(temp_qosRule_act)
		kfree(temp_qosRule_act);	

	if(del_success)
		return SUCCESS;
	else
		return FAILED;
}

int rtl867x_8367b_del_qosrule(int index)
{
	rtl867x_8367b_qos_rule_t	*qosRule_entry;
	rtl867x_8367b_qos_rule_t	*qosRule_nxt;
	
	DBG_8367B_QOS_PRK(" Enter %s\n",__func__);
	

	list_for_each_entry_safe(qosRule_entry, qosRule_nxt,&rtl8367b_qosRuleHead,qos_rule_list) 
	{		 
		if(qosRule_entry->index == index)
		{
			return _rtl867x_8367b_del_qosrule(qosRule_entry);			
		}
	}

	return SUCCESS;
}

void rtl867x_8367b_flush_qosrule(void)
{
	rtl867x_8367b_qos_rule_t	*qosRule_entry;
	rtl867x_8367b_qos_rule_t	*qosRule_nxt;
	
	DBG_8367B_QOS_PRK(" Enter %s\n",__func__);
	

	list_for_each_entry_safe(qosRule_entry, qosRule_nxt,&rtl8367b_qosRuleHead,qos_rule_list) {		 
		_rtl867x_8367b_del_qosrule(qosRule_entry);
	}
}

static int __init rtl867x_8367b_qos_init(void)
{
	int i;	

	/* Init some sw_data (sw_priority_mapping , sw_qosrule .. ) */
	rtl867x_rtl8367b_register_aclchain(RL6000_ACL_CHAIN_QOS,0);
	rtl8367b_priority_default = -1;
	memset(rtl8367b_priority_mapping, 0, RTK_MAX_NUM_OF_PRIORITY*sizeof(rtl8367b_aclpriority_mapping_data_t));
	
	for(i=0;i<RTK_MAX_NUM_OF_QUEUE;i++)
	{			
		rtl8367b_hwQid2swQid_Mapping[i] = rtl8367b_Queue_NOT_Create;			
	}	

	for(i=0;i<RL6000_ACLRANGERULENUM;i++)
	{			
		rtl8367b_iprange_uesd[i] = 0;			
		rtl8367b_portrange_uesd[i] = 0;	
	}	
	

	INIT_LIST_HEAD(&rtl8367b_qosRuleHead);

	
	return SUCCESS;
}

void rtl867x_8367b_qosShowDebugInfo(void)
{
	int i;
	
	printk("Queue hwIdx <----> swIdx : ");
	for(i=0;i<RTK_MAX_NUM_OF_QUEUE;i++)
		printk("[HwQid_%d]0x%08X  ",i,rtl8367b_hwQid2swQid_Mapping[i]);
	printk("\n");

	printk("acl priority <----> \tQueue hwIdx  \tref_count\n");
	for(i=0;i<TOTAL_VLAN_PRIORITY_NUM;i++)
		printk("%d[%s] \t\t\t%d \t\t%d\n"
		,i,rtl8367b_priority_mapping[i].valid?"Y":"N"
		,rtl8367b_priority_mapping[i].Qid
		,rtl8367b_priority_mapping[i].ref_count);

	printk("def acl priority : %d\n",rtl8367b_priority_default);


	printk("IP range used mappint table \n");
	for(i=0;i<RL6000_ACLRANGERULENUM;i++)
		printk("%d[%s] \n",i,rtl8367b_iprange_uesd[i]?"Y":"N");


	printk("Port range used mappint table \n");
	for(i=0;i<RL6000_ACLRANGERULENUM;i++)
		printk("%d[%s] \n",i,rtl8367b_portrange_uesd[i]?"Y":"N");

	printk("\n");
}


void rtl867x_8367b_qosShowSwRule(void)
{
	rtl867x_8367b_qos_rule_t	*qosRule_entry;	
	int index = 0;

	list_for_each_entry(qosRule_entry,&rtl8367b_qosRuleHead,qos_rule_list) {	
		printk("==   Qos Rule %d == \n",index);
		
		rtl867x_rtl8367b_show_aclrule_Datafiled(qosRule_entry->rule_cfg);	
		printk("[index:%02x]  Priority: %d	sw_Qid:0x%08X  ipRange_bitmask:0x%X  portRange_bitmask:0x%X\n\n"
			, qosRule_entry->index, qosRule_entry->priority, qosRule_entry->swQid
			, qosRule_entry->iprange_use_bitmask,qosRule_entry->portrange_use_bitmask);
		index++;
	}
}


static void __exit rtl867x_8367b_qos_exit(void)
{
	rtl867x_rtl8367b_unregister_aclchain(RL6000_ACL_CHAIN_QOS);
}
module_init(rtl867x_8367b_qos_init);
module_exit(rtl867x_8367b_qos_exit);