コード例 #1
0
ファイル: hunt_filter.c プロジェクト: fengsi/freebsd
	__checkReturn	int
hunt_filter_restore(
	__in		efx_nic_t *enp)
{
	int tbl_id;
	efx_filter_spec_t *spec;
	hunt_filter_table_t *hftp = enp->en_filter.ef_hunt_filter_table;
	boolean_t restoring;
	int state;
	int rc;

	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);

	for (tbl_id = 0; tbl_id < EFX_HUNT_FILTER_TBL_ROWS; tbl_id++) {

		EFSYS_LOCK(enp->en_eslp, state);

		spec = hunt_filter_entry_spec(hftp, tbl_id);
		if (spec == NULL) {
			restoring = B_FALSE;
		} else if (hunt_filter_entry_is_busy(hftp, tbl_id)) {
			/* Ignore busy entries. */
			restoring = B_FALSE;
		} else {
			hunt_filter_set_entry_busy(hftp, tbl_id);
			restoring = B_TRUE;
		}

		EFSYS_UNLOCK(enp->en_eslp, state);

		if (restoring == B_FALSE)
			continue;

		if (hunt_filter_is_exclusive(spec)) {
			rc = efx_mcdi_filter_op_add(enp, spec,
			    MC_CMD_FILTER_OP_IN_OP_INSERT,
			    &hftp->hft_entry[tbl_id].hfe_handle);
		} else {
			rc = efx_mcdi_filter_op_add(enp, spec,
			    MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE,
			    &hftp->hft_entry[tbl_id].hfe_handle);
		}

		if (rc != 0)
			goto fail1;

		EFSYS_LOCK(enp->en_eslp, state);

		hunt_filter_set_entry_not_busy(hftp, tbl_id);

		EFSYS_UNLOCK(enp->en_eslp, state);
	}

	return (0);

fail1:
	EFSYS_PROBE1(fail1, int, rc);

	return (rc);
}
コード例 #2
0
ファイル: ef10_filter.c プロジェクト: btw616/dpdk
static	__checkReturn	efx_rc_t
ef10_filter_add_internal(
	__in		efx_nic_t *enp,
	__inout		efx_filter_spec_t *spec,
	__in		boolean_t may_replace,
	__out_opt	uint32_t *filter_id)
{
	efx_rc_t rc;
	ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
	efx_filter_spec_t *saved_spec;
	uint32_t hash;
	unsigned int depth;
	int ins_index;
	boolean_t replacing = B_FALSE;
	unsigned int i;
	efsys_lock_state_t state;
	boolean_t locked = B_FALSE;

	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
	    enp->en_family == EFX_FAMILY_MEDFORD ||
	    enp->en_family == EFX_FAMILY_MEDFORD2);

	hash = ef10_filter_hash(spec);

	/*
	 * FIXME: Add support for inserting filters of different priorities
	 * and removing lower priority multicast filters (bug 42378)
	 */

	/*
	 * Find any existing filters with the same match tuple or
	 * else a free slot to insert at.  If any of them are busy,
	 * we have to wait and retry.
	 */
	for (;;) {
		ins_index = -1;
		depth = 1;
		EFSYS_LOCK(enp->en_eslp, state);
		locked = B_TRUE;

		for (;;) {
			i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1);
			saved_spec = ef10_filter_entry_spec(eftp, i);

			if (!saved_spec) {
				if (ins_index < 0) {
					ins_index = i;
				}
			} else if (ef10_filter_equal(spec, saved_spec)) {
				if (ef10_filter_entry_is_busy(eftp, i))
					break;
				if (saved_spec->efs_priority
					    == EFX_FILTER_PRI_AUTO) {
					ins_index = i;
					goto found;
				} else if (ef10_filter_is_exclusive(spec)) {
					if (may_replace) {
						ins_index = i;
						goto found;
					} else {
						rc = EEXIST;
						goto fail1;
					}
				}

				/* Leave existing */
			}

			/*
			 * Once we reach the maximum search depth, use
			 * the first suitable slot or return EBUSY if
			 * there was none.
			 */
			if (depth == EF10_FILTER_SEARCH_LIMIT) {
				if (ins_index < 0) {
					rc = EBUSY;
					goto fail2;
				}
				goto found;
			}
			depth++;
		}
		EFSYS_UNLOCK(enp->en_eslp, state);
		locked = B_FALSE;
	}

found:
	/*
	 * Create a software table entry if necessary, and mark it
	 * busy.  We might yet fail to insert, but any attempt to
	 * insert a conflicting filter while we're waiting for the
	 * firmware must find the busy entry.
	 */
	saved_spec = ef10_filter_entry_spec(eftp, ins_index);
	if (saved_spec) {
		if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) {
			/* This is a filter we are refreshing */
			ef10_filter_set_entry_not_auto_old(eftp, ins_index);
			goto out_unlock;

		}
		replacing = B_TRUE;
	} else {
		EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec);
		if (!saved_spec) {
			rc = ENOMEM;
			goto fail3;
		}
		*saved_spec = *spec;
		ef10_filter_set_entry(eftp, ins_index, saved_spec);
	}
	ef10_filter_set_entry_busy(eftp, ins_index);

	EFSYS_UNLOCK(enp->en_eslp, state);
	locked = B_FALSE;

	/*
	 * On replacing the filter handle may change after after a successful
	 * replace operation.
	 */
	if (replacing) {
		rc = efx_mcdi_filter_op_add(enp, spec,
		    MC_CMD_FILTER_OP_IN_OP_REPLACE,
		    &eftp->eft_entry[ins_index].efe_handle);
	} else if (ef10_filter_is_exclusive(spec)) {
		rc = efx_mcdi_filter_op_add(enp, spec,
		    MC_CMD_FILTER_OP_IN_OP_INSERT,
		    &eftp->eft_entry[ins_index].efe_handle);
	} else {
		rc = efx_mcdi_filter_op_add(enp, spec,
		    MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE,
		    &eftp->eft_entry[ins_index].efe_handle);
	}

	if (rc != 0)
		goto fail4;

	EFSYS_LOCK(enp->en_eslp, state);
	locked = B_TRUE;

	if (replacing) {
		/* Update the fields that may differ */
		saved_spec->efs_priority = spec->efs_priority;
		saved_spec->efs_flags = spec->efs_flags;
		saved_spec->efs_rss_context = spec->efs_rss_context;
		saved_spec->efs_dmaq_id = spec->efs_dmaq_id;
	}

	ef10_filter_set_entry_not_busy(eftp, ins_index);

out_unlock:

	EFSYS_UNLOCK(enp->en_eslp, state);
	locked = B_FALSE;

	if (filter_id)
		*filter_id = ins_index;

	return (0);

fail4:
	EFSYS_PROBE(fail4);

	if (!replacing) {
		EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec);
		saved_spec = NULL;
	}
	ef10_filter_set_entry_not_busy(eftp, ins_index);
	ef10_filter_set_entry(eftp, ins_index, NULL);

fail3:
	EFSYS_PROBE(fail3);

fail2:
	EFSYS_PROBE(fail2);

fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	if (locked)
		EFSYS_UNLOCK(enp->en_eslp, state);

	return (rc);
}