src/dpdk/drivers/net/cxgbe/cxgbe_filter.c
int cxgbe_set_filter(struct rte_eth_dev *dev, unsigned int filter_id,
		     struct ch_filter_specification *fs,
		     struct filter_ctx *ctx)
{
	struct port_info *pi = ethdev2pinfo(dev);
	struct adapter *adapter = pi->adapter;
	u8 nentries, bitoff[16] = {0};
	struct filter_entry *f;
	unsigned int chip_ver;
	unsigned int fidx, iq;
	u32 iconf;
	int ret;

	if (is_hashfilter(adapter) && fs->cap)
		return cxgbe_set_hash_filter(dev, fs, ctx);

	if (filter_id >= adapter->tids.nftids)
		return -ERANGE;

	chip_ver = CHELSIO_CHIP_VERSION(adapter->params.chip);

	ret = cxgbe_validate_filter(adapter, fs);
	if (ret)
		return ret;

	/*
	 * IPv6 filters occupy four slots and must be aligned on four-slot
	 * boundaries for T5. On T6, IPv6 filters occupy two-slots and
	 * must be aligned on two-slot boundaries.
	 *
	 * IPv4 filters only occupy a single slot and have no alignment
	 * requirements.
	 */
	fidx = filter_id;
	if (fs->type == FILTER_TYPE_IPV6) {
		if (chip_ver < CHELSIO_T6)
			fidx &= ~(0x3);
		else
			fidx &= ~(0x1);
	}

	if (fidx != filter_id)
		return -EINVAL;

	nentries = cxgbe_filter_slots(adapter, fs->type);
	ret = cxgbe_is_filter_set(&adapter->tids, filter_id, nentries);
	if (ret)
		return -EBUSY;

	iq = get_filter_steerq(dev, fs);

	/*
	 * Check to make sure that provided filter index is not
	 * already in use by someone else
	 */
	f = &adapter->tids.ftid_tab[filter_id];
	if (f->valid)
		return -EBUSY;

	fidx = adapter->tids.ftid_base + filter_id;
	ret = cxgbe_set_ftid(&adapter->tids, filter_id, nentries);
	if (ret)
		return ret;

	/*
	 * Check to make sure the filter requested is writable ...
	 */
	ret = writable_filter(f);
	if (ret) {
		/* Clear the bits we have set above */
		cxgbe_clear_ftid(&adapter->tids, filter_id, nentries);
		return ret;
	}

	/*
	 * Convert the filter specification into our internal format.
	 * We copy the PF/VF specification into the Outer VLAN field
	 * here so the rest of the code -- including the interface to
	 * the firmware -- doesn't have to constantly do these checks.
	 */
	f->fs = *fs;
	f->fs.iq = iq;
	f->dev = dev;

	/* Allocate MPS TCAM entry to match Destination MAC. */
	if (f->fs.mask.macidx) {
		int idx;

		idx = cxgbe_mpstcam_alloc(pi, f->fs.val.dmac, f->fs.mask.dmac);
		if (idx <= 0) {
			ret = -ENOMEM;
			goto free_tid;
		}

		f->fs.val.macidx = idx;
	}

	/* Allocate a clip table entry only if we have non-zero IPv6 address. */
	if (chip_ver > CHELSIO_T5 && f->fs.type &&
	    memcmp(f->fs.val.lip, bitoff, sizeof(bitoff))) {
		f->clipt = cxgbe_clip_alloc(dev, (u32 *)&f->fs.val.lip);
		if (!f->clipt) {
			ret = -ENOMEM;
			goto free_tid;
		}
	}

	/* If the new filter requires loopback Destination MAC and/or VLAN
	 * rewriting then we need to allocate a Layer 2 Table (L2T) entry for
	 * the filter.
	 */
	if (f->fs.newvlan || f->fs.newdmac) {
		f->l2t = cxgbe_l2t_alloc_switching(f->dev, f->fs.vlan,
						   f->fs.eport, f->fs.dmac);
		if (!f->l2t) {
			ret = -ENOMEM;
			goto free_tid;
		}
	}

	/* If the new filter requires Source MAC rewriting then we need to
	 * allocate a SMT entry for the filter
	 */
	if (f->fs.newsmac) {
		f->smt = cxgbe_smt_alloc_switching(f->dev, f->fs.smac);
		if (!f->smt) {
			ret = -ENOMEM;
			goto free_tid;
		}
	}

	iconf = adapter->params.tp.ingress_config;

	/* Either PFVF or OVLAN can be active, but not both
	 * So, if PFVF is enabled, then overwrite the OVLAN
	 * fields with PFVF fields before writing the spec
	 * to hardware.
	 */
	if (iconf & F_VNIC) {
		f->fs.val.ovlan = fs->val.pf << 13 | fs->val.vf;
		f->fs.mask.ovlan = fs->mask.pf << 13 | fs->mask.vf;
		f->fs.val.ovlan_vld = fs->val.pfvf_vld;
		f->fs.mask.ovlan_vld = fs->mask.pfvf_vld;
	}

	/*
	 * Attempt to set the filter.  If we don't succeed, we clear
	 * it and return the failure.
	 */
	f->ctx = ctx;
	f->tid = fidx; /* Save the actual tid */
	ret = set_filter_wr(dev, filter_id);
	if (ret)
		goto free_tid;

	return ret;

free_tid:
	cxgbe_clear_ftid(&adapter->tids, filter_id, nentries);
	clear_filter(f);
	return ret;
}
/**
 * Check a Chelsio Filter Request for validity, convert it into our internal
 * format and send it to the hardware.  Return 0 on success, an error number
 * otherwise.  We attach any provided filter operation context to the internal
 * filter specification in order to facilitate signaling completion of the
 * operation.
 */
Check a Chelsio Filter Request for validity, convert it into our internal
format and send it to the hardware.  Return 0 on success, an error number
otherwise.  We attach any provided filter operation context to the internal
filter specification in order to facilitate signaling completion of the
operation.
Check a Chelsio Filter Request for validity convert it into our internal format and send it to the hardware . Return 0 on success an error number otherwise . We attach any provided filter operation context to the internal filter specification in order to facilitate signaling completion of the operation .
int cxgbe_set_filter(struct rte_eth_dev *dev, unsigned int filter_id,
		     struct ch_filter_specification *fs,
		     struct filter_ctx *ctx)
{
	struct port_info *pi = ethdev2pinfo(dev);
	struct adapter *adapter = pi->adapter;
	u8 nentries, bitoff[16] = {0};
	struct filter_entry *f;
	unsigned int chip_ver;
	unsigned int fidx, iq;
	u32 iconf;
	int ret;
	if (is_hashfilter(adapter) && fs->cap)
		return cxgbe_set_hash_filter(dev, fs, ctx);
	if (filter_id >= adapter->tids.nftids)
		return -ERANGE;
	chip_ver = CHELSIO_CHIP_VERSION(adapter->params.chip);
	ret = cxgbe_validate_filter(adapter, fs);
	if (ret)
		return ret;
	fidx = filter_id;
	if (fs->type == FILTER_TYPE_IPV6) {
		if (chip_ver < CHELSIO_T6)
			fidx &= ~(0x3);
		else
			fidx &= ~(0x1);
	}
	if (fidx != filter_id)
		return -EINVAL;
	nentries = cxgbe_filter_slots(adapter, fs->type);
	ret = cxgbe_is_filter_set(&adapter->tids, filter_id, nentries);
	if (ret)
		return -EBUSY;
	iq = get_filter_steerq(dev, fs);
	f = &adapter->tids.ftid_tab[filter_id];
	if (f->valid)
		return -EBUSY;
	fidx = adapter->tids.ftid_base + filter_id;
	ret = cxgbe_set_ftid(&adapter->tids, filter_id, nentries);
	if (ret)
		return ret;
	ret = writable_filter(f);
	if (ret) {
		cxgbe_clear_ftid(&adapter->tids, filter_id, nentries);
		return ret;
	}
	f->fs = *fs;
	f->fs.iq = iq;
	f->dev = dev;
	if (f->fs.mask.macidx) {
		int idx;
		idx = cxgbe_mpstcam_alloc(pi, f->fs.val.dmac, f->fs.mask.dmac);
		if (idx <= 0) {
			ret = -ENOMEM;
			goto free_tid;
		}
		f->fs.val.macidx = idx;
	}
	if (chip_ver > CHELSIO_T5 && f->fs.type &&
	    memcmp(f->fs.val.lip, bitoff, sizeof(bitoff))) {
		f->clipt = cxgbe_clip_alloc(dev, (u32 *)&f->fs.val.lip);
		if (!f->clipt) {
			ret = -ENOMEM;
			goto free_tid;
		}
	}
	if (f->fs.newvlan || f->fs.newdmac) {
		f->l2t = cxgbe_l2t_alloc_switching(f->dev, f->fs.vlan,
						   f->fs.eport, f->fs.dmac);
		if (!f->l2t) {
			ret = -ENOMEM;
			goto free_tid;
		}
	}
	if (f->fs.newsmac) {
		f->smt = cxgbe_smt_alloc_switching(f->dev, f->fs.smac);
		if (!f->smt) {
			ret = -ENOMEM;
			goto free_tid;
		}
	}
	iconf = adapter->params.tp.ingress_config;
	if (iconf & F_VNIC) {
		f->fs.val.ovlan = fs->val.pf << 13 | fs->val.vf;
		f->fs.mask.ovlan = fs->mask.pf << 13 | fs->mask.vf;
		f->fs.val.ovlan_vld = fs->val.pfvf_vld;
		f->fs.mask.ovlan_vld = fs->mask.pfvf_vld;
	}
	f->ctx = ctx;
	f->tid = fidx; 
	ret = set_filter_wr(dev, filter_id);
	if (ret)
		goto free_tid;
	return ret;
free_tid:
	cxgbe_clear_ftid(&adapter->tids, filter_id, nentries);
	clear_filter(f);
	return ret;
}
int cxgbe_set_filter ( struct rte_eth_dev * dev , unsigned int filter_id , struct ch_filter_specification * fs , struct filter_ctx * ctx ) { struct port_info * pi = ethdev2pinfo ( dev ) ; struct adapter * adapter = pi -> adapter ; u8 nentries , bitoff [ 16 ] = { 0 } ; struct filter_entry * f ; unsigned int chip_ver ; unsigned int fidx , iq ; u32 iconf ; int ret ; if ( is_hashfilter ( adapter ) && fs -> cap ) return cxgbe_set_hash_filter ( dev , fs , ctx ) ; if ( filter_id >= adapter -> tids . nftids ) return - ERANGE ; chip_ver = CHELSIO_CHIP_VERSION ( adapter -> params . chip ) ; ret = cxgbe_validate_filter ( adapter , fs ) ; if ( ret ) return ret ; fidx = filter_id ; if ( fs -> type == FILTER_TYPE_IPV6 ) { if ( chip_ver < CHELSIO_T6 ) fidx &= ~ ( 0x3 ) ; else fidx &= ~ ( 0x1 ) ; } if ( fidx != filter_id ) return - EINVAL ; nentries = cxgbe_filter_slots ( adapter , fs -> type ) ; ret = cxgbe_is_filter_set ( & adapter -> tids , filter_id , nentries ) ; if ( ret ) return - EBUSY ; iq = get_filter_steerq ( dev , fs ) ; f = & adapter -> tids . ftid_tab [ filter_id ] ; if ( f -> valid ) return - EBUSY ; fidx = adapter -> tids . ftid_base + filter_id ; ret = cxgbe_set_ftid ( & adapter -> tids , filter_id , nentries ) ; if ( ret ) return ret ; ret = writable_filter ( f ) ; if ( ret ) { cxgbe_clear_ftid ( & adapter -> tids , filter_id , nentries ) ; return ret ; } f -> fs = * fs ; f -> fs . iq = iq ; f -> dev = dev ; if ( f -> fs . mask . macidx ) { int idx ; idx = cxgbe_mpstcam_alloc ( pi , f -> fs . val . dmac , f -> fs . mask . dmac ) ; if ( idx <= 0 ) { ret = - ENOMEM ; goto free_tid ; } f -> fs . val . macidx = idx ; } if ( chip_ver > CHELSIO_T5 && f -> fs . type && memcmp ( f -> fs . val . lip , bitoff , sizeof ( bitoff ) ) ) { f -> clipt = cxgbe_clip_alloc ( dev , ( u32 * ) & f -> fs . val . lip ) ; if ( ! f -> clipt ) { ret = - ENOMEM ; goto free_tid ; } } if ( f -> fs . newvlan || f -> fs . newdmac ) { f -> l2t = cxgbe_l2t_alloc_switching ( f -> dev , f -> fs . vlan , f -> fs . eport , f -> fs . dmac ) ; if ( ! f -> l2t ) { ret = - ENOMEM ; goto free_tid ; } } if ( f -> fs . newsmac ) { f -> smt = cxgbe_smt_alloc_switching ( f -> dev , f -> fs . smac ) ; if ( ! f -> smt ) { ret = - ENOMEM ; goto free_tid ; } } iconf = adapter -> params . tp . ingress_config ; if ( iconf & F_VNIC ) { f -> fs . val . ovlan = fs -> val . pf << 13 | fs -> val . vf ; f -> fs . mask . ovlan = fs -> mask . pf << 13 | fs -> mask . vf ; f -> fs . val . ovlan_vld = fs -> val . pfvf_vld ; f -> fs . mask . ovlan_vld = fs -> mask . pfvf_vld ; } f -> ctx = ctx ; f -> tid = fidx ; ret = set_filter_wr ( dev , filter_id ) ; if ( ret ) goto free_tid ; return ret ; free_tid : cxgbe_clear_ftid ( & adapter -> tids , filter_id , nentries ) ; clear_filter ( f ) ; return ret ; }
Check a Chelsio Filter Request for validity, convert it into our internal
 format and send it to the hardware.
Check a Chelsio Filter Request for validity convert it into our internal format and send it to the hardware .
/*
	 * IPv6 filters occupy four slots and must be aligned on four-slot
	 * boundaries for T5. On T6, IPv6 filters occupy two-slots and
	 * must be aligned on two-slot boundaries.
	 *
	 * IPv4 filters only occupy a single slot and have no alignment
	 * requirements.
	 */ /*
	 * Check to make sure that provided filter index is not
	 * already in use by someone else
	 */ /*
	 * Check to make sure the filter requested is writable ...
	 */ /* Clear the bits we have set above */ /*
	 * Convert the filter specification into our internal format.
	 * We copy the PF/VF specification into the Outer VLAN field
	 * here so the rest of the code -- including the interface to
	 * the firmware -- doesn't have to constantly do these checks.
	 */ /* Allocate MPS TCAM entry to match Destination MAC. */ /* Allocate a clip table entry only if we have non-zero IPv6 address. */ /* If the new filter requires loopback Destination MAC and/or VLAN
	 * rewriting then we need to allocate a Layer 2 Table (L2T) entry for
	 * the filter.
	 */ /* If the new filter requires Source MAC rewriting then we need to
	 * allocate a SMT entry for the filter
	 */ /* Either PFVF or OVLAN can be active, but not both
	 * So, if PFVF is enabled, then overwrite the OVLAN
	 * fields with PFVF fields before writing the spec
	 * to hardware.
	 */ /*
	 * Attempt to set the filter.  If we don't succeed, we clear
	 * it and return the failure.
	 */ /* Save the actual tid */