sfc: Copy shared files needed for Siena (part 1)
These are the files starting with b through i. No changes are done, those will be done with subsequent commits. Signed-off-by: Martin Habets <habetsm.xilinx@gmail.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
36ff639329
commit
6e173d3b4a
|
@ -0,0 +1,614 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/****************************************************************************
|
||||
* Driver for Solarflare network controllers and boards
|
||||
* Copyright 2005-2006 Fen Systems Ltd.
|
||||
* Copyright 2006-2013 Solarflare Communications Inc.
|
||||
*/
|
||||
|
||||
#ifndef EFX_BITFIELD_H
|
||||
#define EFX_BITFIELD_H
|
||||
|
||||
/*
|
||||
* Efx bitfield access
|
||||
*
|
||||
* Efx NICs make extensive use of bitfields up to 128 bits
|
||||
* wide. Since there is no native 128-bit datatype on most systems,
|
||||
* and since 64-bit datatypes are inefficient on 32-bit systems and
|
||||
* vice versa, we wrap accesses in a way that uses the most efficient
|
||||
* datatype.
|
||||
*
|
||||
* The NICs are PCI devices and therefore little-endian. Since most
|
||||
* of the quantities that we deal with are DMAed to/from host memory,
|
||||
* we define our datatypes (efx_oword_t, efx_qword_t and
|
||||
* efx_dword_t) to be little-endian.
|
||||
*/
|
||||
|
||||
/* Lowest bit numbers and widths */
|
||||
#define EFX_DUMMY_FIELD_LBN 0
|
||||
#define EFX_DUMMY_FIELD_WIDTH 0
|
||||
#define EFX_WORD_0_LBN 0
|
||||
#define EFX_WORD_0_WIDTH 16
|
||||
#define EFX_WORD_1_LBN 16
|
||||
#define EFX_WORD_1_WIDTH 16
|
||||
#define EFX_DWORD_0_LBN 0
|
||||
#define EFX_DWORD_0_WIDTH 32
|
||||
#define EFX_DWORD_1_LBN 32
|
||||
#define EFX_DWORD_1_WIDTH 32
|
||||
#define EFX_DWORD_2_LBN 64
|
||||
#define EFX_DWORD_2_WIDTH 32
|
||||
#define EFX_DWORD_3_LBN 96
|
||||
#define EFX_DWORD_3_WIDTH 32
|
||||
#define EFX_QWORD_0_LBN 0
|
||||
#define EFX_QWORD_0_WIDTH 64
|
||||
|
||||
/* Specified attribute (e.g. LBN) of the specified field */
|
||||
#define EFX_VAL(field, attribute) field ## _ ## attribute
|
||||
/* Low bit number of the specified field */
|
||||
#define EFX_LOW_BIT(field) EFX_VAL(field, LBN)
|
||||
/* Bit width of the specified field */
|
||||
#define EFX_WIDTH(field) EFX_VAL(field, WIDTH)
|
||||
/* High bit number of the specified field */
|
||||
#define EFX_HIGH_BIT(field) (EFX_LOW_BIT(field) + EFX_WIDTH(field) - 1)
|
||||
/* Mask equal in width to the specified field.
|
||||
*
|
||||
* For example, a field with width 5 would have a mask of 0x1f.
|
||||
*
|
||||
* The maximum width mask that can be generated is 64 bits.
|
||||
*/
|
||||
#define EFX_MASK64(width) \
|
||||
((width) == 64 ? ~((u64) 0) : \
|
||||
(((((u64) 1) << (width))) - 1))
|
||||
|
||||
/* Mask equal in width to the specified field.
|
||||
*
|
||||
* For example, a field with width 5 would have a mask of 0x1f.
|
||||
*
|
||||
* The maximum width mask that can be generated is 32 bits. Use
|
||||
* EFX_MASK64 for higher width fields.
|
||||
*/
|
||||
#define EFX_MASK32(width) \
|
||||
((width) == 32 ? ~((u32) 0) : \
|
||||
(((((u32) 1) << (width))) - 1))
|
||||
|
||||
/* A doubleword (i.e. 4 byte) datatype - little-endian in HW */
|
||||
typedef union efx_dword {
|
||||
__le32 u32[1];
|
||||
} efx_dword_t;
|
||||
|
||||
/* A quadword (i.e. 8 byte) datatype - little-endian in HW */
|
||||
typedef union efx_qword {
|
||||
__le64 u64[1];
|
||||
__le32 u32[2];
|
||||
efx_dword_t dword[2];
|
||||
} efx_qword_t;
|
||||
|
||||
/* An octword (eight-word, i.e. 16 byte) datatype - little-endian in HW */
|
||||
typedef union efx_oword {
|
||||
__le64 u64[2];
|
||||
efx_qword_t qword[2];
|
||||
__le32 u32[4];
|
||||
efx_dword_t dword[4];
|
||||
} efx_oword_t;
|
||||
|
||||
/* Format string and value expanders for printk */
|
||||
#define EFX_DWORD_FMT "%08x"
|
||||
#define EFX_QWORD_FMT "%08x:%08x"
|
||||
#define EFX_OWORD_FMT "%08x:%08x:%08x:%08x"
|
||||
#define EFX_DWORD_VAL(dword) \
|
||||
((unsigned int) le32_to_cpu((dword).u32[0]))
|
||||
#define EFX_QWORD_VAL(qword) \
|
||||
((unsigned int) le32_to_cpu((qword).u32[1])), \
|
||||
((unsigned int) le32_to_cpu((qword).u32[0]))
|
||||
#define EFX_OWORD_VAL(oword) \
|
||||
((unsigned int) le32_to_cpu((oword).u32[3])), \
|
||||
((unsigned int) le32_to_cpu((oword).u32[2])), \
|
||||
((unsigned int) le32_to_cpu((oword).u32[1])), \
|
||||
((unsigned int) le32_to_cpu((oword).u32[0]))
|
||||
|
||||
/*
|
||||
* Extract bit field portion [low,high) from the native-endian element
|
||||
* which contains bits [min,max).
|
||||
*
|
||||
* For example, suppose "element" represents the high 32 bits of a
|
||||
* 64-bit value, and we wish to extract the bits belonging to the bit
|
||||
* field occupying bits 28-45 of this 64-bit value.
|
||||
*
|
||||
* Then EFX_EXTRACT ( element, 32, 63, 28, 45 ) would give
|
||||
*
|
||||
* ( element ) << 4
|
||||
*
|
||||
* The result will contain the relevant bits filled in in the range
|
||||
* [0,high-low), with garbage in bits [high-low+1,...).
|
||||
*/
|
||||
#define EFX_EXTRACT_NATIVE(native_element, min, max, low, high) \
|
||||
((low) > (max) || (high) < (min) ? 0 : \
|
||||
(low) > (min) ? \
|
||||
(native_element) >> ((low) - (min)) : \
|
||||
(native_element) << ((min) - (low)))
|
||||
|
||||
/*
|
||||
* Extract bit field portion [low,high) from the 64-bit little-endian
|
||||
* element which contains bits [min,max)
|
||||
*/
|
||||
#define EFX_EXTRACT64(element, min, max, low, high) \
|
||||
EFX_EXTRACT_NATIVE(le64_to_cpu(element), min, max, low, high)
|
||||
|
||||
/*
|
||||
* Extract bit field portion [low,high) from the 32-bit little-endian
|
||||
* element which contains bits [min,max)
|
||||
*/
|
||||
#define EFX_EXTRACT32(element, min, max, low, high) \
|
||||
EFX_EXTRACT_NATIVE(le32_to_cpu(element), min, max, low, high)
|
||||
|
||||
#define EFX_EXTRACT_OWORD64(oword, low, high) \
|
||||
((EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) | \
|
||||
EFX_EXTRACT64((oword).u64[1], 64, 127, low, high)) & \
|
||||
EFX_MASK64((high) + 1 - (low)))
|
||||
|
||||
#define EFX_EXTRACT_QWORD64(qword, low, high) \
|
||||
(EFX_EXTRACT64((qword).u64[0], 0, 63, low, high) & \
|
||||
EFX_MASK64((high) + 1 - (low)))
|
||||
|
||||
#define EFX_EXTRACT_OWORD32(oword, low, high) \
|
||||
((EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) | \
|
||||
EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) | \
|
||||
EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) | \
|
||||
EFX_EXTRACT32((oword).u32[3], 96, 127, low, high)) & \
|
||||
EFX_MASK32((high) + 1 - (low)))
|
||||
|
||||
#define EFX_EXTRACT_QWORD32(qword, low, high) \
|
||||
((EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) | \
|
||||
EFX_EXTRACT32((qword).u32[1], 32, 63, low, high)) & \
|
||||
EFX_MASK32((high) + 1 - (low)))
|
||||
|
||||
#define EFX_EXTRACT_DWORD(dword, low, high) \
|
||||
(EFX_EXTRACT32((dword).u32[0], 0, 31, low, high) & \
|
||||
EFX_MASK32((high) + 1 - (low)))
|
||||
|
||||
#define EFX_OWORD_FIELD64(oword, field) \
|
||||
EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field), \
|
||||
EFX_HIGH_BIT(field))
|
||||
|
||||
#define EFX_QWORD_FIELD64(qword, field) \
|
||||
EFX_EXTRACT_QWORD64(qword, EFX_LOW_BIT(field), \
|
||||
EFX_HIGH_BIT(field))
|
||||
|
||||
#define EFX_OWORD_FIELD32(oword, field) \
|
||||
EFX_EXTRACT_OWORD32(oword, EFX_LOW_BIT(field), \
|
||||
EFX_HIGH_BIT(field))
|
||||
|
||||
#define EFX_QWORD_FIELD32(qword, field) \
|
||||
EFX_EXTRACT_QWORD32(qword, EFX_LOW_BIT(field), \
|
||||
EFX_HIGH_BIT(field))
|
||||
|
||||
#define EFX_DWORD_FIELD(dword, field) \
|
||||
EFX_EXTRACT_DWORD(dword, EFX_LOW_BIT(field), \
|
||||
EFX_HIGH_BIT(field))
|
||||
|
||||
#define EFX_OWORD_IS_ZERO64(oword) \
|
||||
(((oword).u64[0] | (oword).u64[1]) == (__force __le64) 0)
|
||||
|
||||
#define EFX_QWORD_IS_ZERO64(qword) \
|
||||
(((qword).u64[0]) == (__force __le64) 0)
|
||||
|
||||
#define EFX_OWORD_IS_ZERO32(oword) \
|
||||
(((oword).u32[0] | (oword).u32[1] | (oword).u32[2] | (oword).u32[3]) \
|
||||
== (__force __le32) 0)
|
||||
|
||||
#define EFX_QWORD_IS_ZERO32(qword) \
|
||||
(((qword).u32[0] | (qword).u32[1]) == (__force __le32) 0)
|
||||
|
||||
#define EFX_DWORD_IS_ZERO(dword) \
|
||||
(((dword).u32[0]) == (__force __le32) 0)
|
||||
|
||||
#define EFX_OWORD_IS_ALL_ONES64(oword) \
|
||||
(((oword).u64[0] & (oword).u64[1]) == ~((__force __le64) 0))
|
||||
|
||||
#define EFX_QWORD_IS_ALL_ONES64(qword) \
|
||||
((qword).u64[0] == ~((__force __le64) 0))
|
||||
|
||||
#define EFX_OWORD_IS_ALL_ONES32(oword) \
|
||||
(((oword).u32[0] & (oword).u32[1] & (oword).u32[2] & (oword).u32[3]) \
|
||||
== ~((__force __le32) 0))
|
||||
|
||||
#define EFX_QWORD_IS_ALL_ONES32(qword) \
|
||||
(((qword).u32[0] & (qword).u32[1]) == ~((__force __le32) 0))
|
||||
|
||||
#define EFX_DWORD_IS_ALL_ONES(dword) \
|
||||
((dword).u32[0] == ~((__force __le32) 0))
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
#define EFX_OWORD_FIELD EFX_OWORD_FIELD64
|
||||
#define EFX_QWORD_FIELD EFX_QWORD_FIELD64
|
||||
#define EFX_OWORD_IS_ZERO EFX_OWORD_IS_ZERO64
|
||||
#define EFX_QWORD_IS_ZERO EFX_QWORD_IS_ZERO64
|
||||
#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES64
|
||||
#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES64
|
||||
#else
|
||||
#define EFX_OWORD_FIELD EFX_OWORD_FIELD32
|
||||
#define EFX_QWORD_FIELD EFX_QWORD_FIELD32
|
||||
#define EFX_OWORD_IS_ZERO EFX_OWORD_IS_ZERO32
|
||||
#define EFX_QWORD_IS_ZERO EFX_QWORD_IS_ZERO32
|
||||
#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES32
|
||||
#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES32
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Construct bit field portion
|
||||
*
|
||||
* Creates the portion of the bit field [low,high) that lies within
|
||||
* the range [min,max).
|
||||
*/
|
||||
#define EFX_INSERT_NATIVE64(min, max, low, high, value) \
|
||||
(((low > max) || (high < min)) ? 0 : \
|
||||
((low > min) ? \
|
||||
(((u64) (value)) << (low - min)) : \
|
||||
(((u64) (value)) >> (min - low))))
|
||||
|
||||
#define EFX_INSERT_NATIVE32(min, max, low, high, value) \
|
||||
(((low > max) || (high < min)) ? 0 : \
|
||||
((low > min) ? \
|
||||
(((u32) (value)) << (low - min)) : \
|
||||
(((u32) (value)) >> (min - low))))
|
||||
|
||||
#define EFX_INSERT_NATIVE(min, max, low, high, value) \
|
||||
((((max - min) >= 32) || ((high - low) >= 32)) ? \
|
||||
EFX_INSERT_NATIVE64(min, max, low, high, value) : \
|
||||
EFX_INSERT_NATIVE32(min, max, low, high, value))
|
||||
|
||||
/*
|
||||
* Construct bit field portion
|
||||
*
|
||||
* Creates the portion of the named bit field that lies within the
|
||||
* range [min,max).
|
||||
*/
|
||||
#define EFX_INSERT_FIELD_NATIVE(min, max, field, value) \
|
||||
EFX_INSERT_NATIVE(min, max, EFX_LOW_BIT(field), \
|
||||
EFX_HIGH_BIT(field), value)
|
||||
|
||||
/*
|
||||
* Construct bit field
|
||||
*
|
||||
* Creates the portion of the named bit fields that lie within the
|
||||
* range [min,max).
|
||||
*/
|
||||
#define EFX_INSERT_FIELDS_NATIVE(min, max, \
|
||||
field1, value1, \
|
||||
field2, value2, \
|
||||
field3, value3, \
|
||||
field4, value4, \
|
||||
field5, value5, \
|
||||
field6, value6, \
|
||||
field7, value7, \
|
||||
field8, value8, \
|
||||
field9, value9, \
|
||||
field10, value10, \
|
||||
field11, value11, \
|
||||
field12, value12, \
|
||||
field13, value13, \
|
||||
field14, value14, \
|
||||
field15, value15, \
|
||||
field16, value16, \
|
||||
field17, value17, \
|
||||
field18, value18, \
|
||||
field19, value19) \
|
||||
(EFX_INSERT_FIELD_NATIVE((min), (max), field1, (value1)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field2, (value2)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field3, (value3)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field4, (value4)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field5, (value5)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field6, (value6)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field7, (value7)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field8, (value8)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field9, (value9)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field10, (value10)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field11, (value11)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field12, (value12)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field13, (value13)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field14, (value14)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field15, (value15)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field16, (value16)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field17, (value17)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field18, (value18)) | \
|
||||
EFX_INSERT_FIELD_NATIVE((min), (max), field19, (value19)))
|
||||
|
||||
#define EFX_INSERT_FIELDS64(...) \
|
||||
cpu_to_le64(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__))
|
||||
|
||||
#define EFX_INSERT_FIELDS32(...) \
|
||||
cpu_to_le32(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__))
|
||||
|
||||
#define EFX_POPULATE_OWORD64(oword, ...) do { \
|
||||
(oword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__); \
|
||||
(oword).u64[1] = EFX_INSERT_FIELDS64(64, 127, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define EFX_POPULATE_QWORD64(qword, ...) do { \
|
||||
(qword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define EFX_POPULATE_OWORD32(oword, ...) do { \
|
||||
(oword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
|
||||
(oword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__); \
|
||||
(oword).u32[2] = EFX_INSERT_FIELDS32(64, 95, __VA_ARGS__); \
|
||||
(oword).u32[3] = EFX_INSERT_FIELDS32(96, 127, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define EFX_POPULATE_QWORD32(qword, ...) do { \
|
||||
(qword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
|
||||
(qword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define EFX_POPULATE_DWORD(dword, ...) do { \
|
||||
(dword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD64
|
||||
#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD64
|
||||
#else
|
||||
#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD32
|
||||
#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD32
|
||||
#endif
|
||||
|
||||
/* Populate an octword field with various numbers of arguments */
|
||||
#define EFX_POPULATE_OWORD_19 EFX_POPULATE_OWORD
|
||||
#define EFX_POPULATE_OWORD_18(oword, ...) \
|
||||
EFX_POPULATE_OWORD_19(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_17(oword, ...) \
|
||||
EFX_POPULATE_OWORD_18(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_16(oword, ...) \
|
||||
EFX_POPULATE_OWORD_17(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_15(oword, ...) \
|
||||
EFX_POPULATE_OWORD_16(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_14(oword, ...) \
|
||||
EFX_POPULATE_OWORD_15(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_13(oword, ...) \
|
||||
EFX_POPULATE_OWORD_14(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_12(oword, ...) \
|
||||
EFX_POPULATE_OWORD_13(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_11(oword, ...) \
|
||||
EFX_POPULATE_OWORD_12(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_10(oword, ...) \
|
||||
EFX_POPULATE_OWORD_11(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_9(oword, ...) \
|
||||
EFX_POPULATE_OWORD_10(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_8(oword, ...) \
|
||||
EFX_POPULATE_OWORD_9(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_7(oword, ...) \
|
||||
EFX_POPULATE_OWORD_8(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_6(oword, ...) \
|
||||
EFX_POPULATE_OWORD_7(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_5(oword, ...) \
|
||||
EFX_POPULATE_OWORD_6(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_4(oword, ...) \
|
||||
EFX_POPULATE_OWORD_5(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_3(oword, ...) \
|
||||
EFX_POPULATE_OWORD_4(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_2(oword, ...) \
|
||||
EFX_POPULATE_OWORD_3(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_OWORD_1(oword, ...) \
|
||||
EFX_POPULATE_OWORD_2(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_ZERO_OWORD(oword) \
|
||||
EFX_POPULATE_OWORD_1(oword, EFX_DUMMY_FIELD, 0)
|
||||
#define EFX_SET_OWORD(oword) \
|
||||
EFX_POPULATE_OWORD_4(oword, \
|
||||
EFX_DWORD_0, 0xffffffff, \
|
||||
EFX_DWORD_1, 0xffffffff, \
|
||||
EFX_DWORD_2, 0xffffffff, \
|
||||
EFX_DWORD_3, 0xffffffff)
|
||||
|
||||
/* Populate a quadword field with various numbers of arguments */
|
||||
#define EFX_POPULATE_QWORD_19 EFX_POPULATE_QWORD
|
||||
#define EFX_POPULATE_QWORD_18(qword, ...) \
|
||||
EFX_POPULATE_QWORD_19(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_17(qword, ...) \
|
||||
EFX_POPULATE_QWORD_18(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_16(qword, ...) \
|
||||
EFX_POPULATE_QWORD_17(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_15(qword, ...) \
|
||||
EFX_POPULATE_QWORD_16(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_14(qword, ...) \
|
||||
EFX_POPULATE_QWORD_15(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_13(qword, ...) \
|
||||
EFX_POPULATE_QWORD_14(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_12(qword, ...) \
|
||||
EFX_POPULATE_QWORD_13(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_11(qword, ...) \
|
||||
EFX_POPULATE_QWORD_12(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_10(qword, ...) \
|
||||
EFX_POPULATE_QWORD_11(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_9(qword, ...) \
|
||||
EFX_POPULATE_QWORD_10(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_8(qword, ...) \
|
||||
EFX_POPULATE_QWORD_9(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_7(qword, ...) \
|
||||
EFX_POPULATE_QWORD_8(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_6(qword, ...) \
|
||||
EFX_POPULATE_QWORD_7(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_5(qword, ...) \
|
||||
EFX_POPULATE_QWORD_6(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_4(qword, ...) \
|
||||
EFX_POPULATE_QWORD_5(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_3(qword, ...) \
|
||||
EFX_POPULATE_QWORD_4(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_2(qword, ...) \
|
||||
EFX_POPULATE_QWORD_3(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_QWORD_1(qword, ...) \
|
||||
EFX_POPULATE_QWORD_2(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_ZERO_QWORD(qword) \
|
||||
EFX_POPULATE_QWORD_1(qword, EFX_DUMMY_FIELD, 0)
|
||||
#define EFX_SET_QWORD(qword) \
|
||||
EFX_POPULATE_QWORD_2(qword, \
|
||||
EFX_DWORD_0, 0xffffffff, \
|
||||
EFX_DWORD_1, 0xffffffff)
|
||||
|
||||
/* Populate a dword field with various numbers of arguments */
|
||||
#define EFX_POPULATE_DWORD_19 EFX_POPULATE_DWORD
|
||||
#define EFX_POPULATE_DWORD_18(dword, ...) \
|
||||
EFX_POPULATE_DWORD_19(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_17(dword, ...) \
|
||||
EFX_POPULATE_DWORD_18(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_16(dword, ...) \
|
||||
EFX_POPULATE_DWORD_17(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_15(dword, ...) \
|
||||
EFX_POPULATE_DWORD_16(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_14(dword, ...) \
|
||||
EFX_POPULATE_DWORD_15(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_13(dword, ...) \
|
||||
EFX_POPULATE_DWORD_14(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_12(dword, ...) \
|
||||
EFX_POPULATE_DWORD_13(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_11(dword, ...) \
|
||||
EFX_POPULATE_DWORD_12(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_10(dword, ...) \
|
||||
EFX_POPULATE_DWORD_11(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_9(dword, ...) \
|
||||
EFX_POPULATE_DWORD_10(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_8(dword, ...) \
|
||||
EFX_POPULATE_DWORD_9(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_7(dword, ...) \
|
||||
EFX_POPULATE_DWORD_8(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_6(dword, ...) \
|
||||
EFX_POPULATE_DWORD_7(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_5(dword, ...) \
|
||||
EFX_POPULATE_DWORD_6(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_4(dword, ...) \
|
||||
EFX_POPULATE_DWORD_5(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_3(dword, ...) \
|
||||
EFX_POPULATE_DWORD_4(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_2(dword, ...) \
|
||||
EFX_POPULATE_DWORD_3(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_POPULATE_DWORD_1(dword, ...) \
|
||||
EFX_POPULATE_DWORD_2(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
|
||||
#define EFX_ZERO_DWORD(dword) \
|
||||
EFX_POPULATE_DWORD_1(dword, EFX_DUMMY_FIELD, 0)
|
||||
#define EFX_SET_DWORD(dword) \
|
||||
EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xffffffff)
|
||||
|
||||
/*
|
||||
* Modify a named field within an already-populated structure. Used
|
||||
* for read-modify-write operations.
|
||||
*
|
||||
*/
|
||||
#define EFX_INVERT_OWORD(oword) do { \
|
||||
(oword).u64[0] = ~((oword).u64[0]); \
|
||||
(oword).u64[1] = ~((oword).u64[1]); \
|
||||
} while (0)
|
||||
|
||||
#define EFX_AND_OWORD(oword, from, mask) \
|
||||
do { \
|
||||
(oword).u64[0] = (from).u64[0] & (mask).u64[0]; \
|
||||
(oword).u64[1] = (from).u64[1] & (mask).u64[1]; \
|
||||
} while (0)
|
||||
|
||||
#define EFX_AND_QWORD(qword, from, mask) \
|
||||
(qword).u64[0] = (from).u64[0] & (mask).u64[0]
|
||||
|
||||
#define EFX_OR_OWORD(oword, from, mask) \
|
||||
do { \
|
||||
(oword).u64[0] = (from).u64[0] | (mask).u64[0]; \
|
||||
(oword).u64[1] = (from).u64[1] | (mask).u64[1]; \
|
||||
} while (0)
|
||||
|
||||
#define EFX_INSERT64(min, max, low, high, value) \
|
||||
cpu_to_le64(EFX_INSERT_NATIVE(min, max, low, high, value))
|
||||
|
||||
#define EFX_INSERT32(min, max, low, high, value) \
|
||||
cpu_to_le32(EFX_INSERT_NATIVE(min, max, low, high, value))
|
||||
|
||||
#define EFX_INPLACE_MASK64(min, max, low, high) \
|
||||
EFX_INSERT64(min, max, low, high, EFX_MASK64((high) + 1 - (low)))
|
||||
|
||||
#define EFX_INPLACE_MASK32(min, max, low, high) \
|
||||
EFX_INSERT32(min, max, low, high, EFX_MASK32((high) + 1 - (low)))
|
||||
|
||||
#define EFX_SET_OWORD64(oword, low, high, value) do { \
|
||||
(oword).u64[0] = (((oword).u64[0] \
|
||||
& ~EFX_INPLACE_MASK64(0, 63, low, high)) \
|
||||
| EFX_INSERT64(0, 63, low, high, value)); \
|
||||
(oword).u64[1] = (((oword).u64[1] \
|
||||
& ~EFX_INPLACE_MASK64(64, 127, low, high)) \
|
||||
| EFX_INSERT64(64, 127, low, high, value)); \
|
||||
} while (0)
|
||||
|
||||
#define EFX_SET_QWORD64(qword, low, high, value) do { \
|
||||
(qword).u64[0] = (((qword).u64[0] \
|
||||
& ~EFX_INPLACE_MASK64(0, 63, low, high)) \
|
||||
| EFX_INSERT64(0, 63, low, high, value)); \
|
||||
} while (0)
|
||||
|
||||
#define EFX_SET_OWORD32(oword, low, high, value) do { \
|
||||
(oword).u32[0] = (((oword).u32[0] \
|
||||
& ~EFX_INPLACE_MASK32(0, 31, low, high)) \
|
||||
| EFX_INSERT32(0, 31, low, high, value)); \
|
||||
(oword).u32[1] = (((oword).u32[1] \
|
||||
& ~EFX_INPLACE_MASK32(32, 63, low, high)) \
|
||||
| EFX_INSERT32(32, 63, low, high, value)); \
|
||||
(oword).u32[2] = (((oword).u32[2] \
|
||||
& ~EFX_INPLACE_MASK32(64, 95, low, high)) \
|
||||
| EFX_INSERT32(64, 95, low, high, value)); \
|
||||
(oword).u32[3] = (((oword).u32[3] \
|
||||
& ~EFX_INPLACE_MASK32(96, 127, low, high)) \
|
||||
| EFX_INSERT32(96, 127, low, high, value)); \
|
||||
} while (0)
|
||||
|
||||
#define EFX_SET_QWORD32(qword, low, high, value) do { \
|
||||
(qword).u32[0] = (((qword).u32[0] \
|
||||
& ~EFX_INPLACE_MASK32(0, 31, low, high)) \
|
||||
| EFX_INSERT32(0, 31, low, high, value)); \
|
||||
(qword).u32[1] = (((qword).u32[1] \
|
||||
& ~EFX_INPLACE_MASK32(32, 63, low, high)) \
|
||||
| EFX_INSERT32(32, 63, low, high, value)); \
|
||||
} while (0)
|
||||
|
||||
#define EFX_SET_DWORD32(dword, low, high, value) do { \
|
||||
(dword).u32[0] = (((dword).u32[0] \
|
||||
& ~EFX_INPLACE_MASK32(0, 31, low, high)) \
|
||||
| EFX_INSERT32(0, 31, low, high, value)); \
|
||||
} while (0)
|
||||
|
||||
#define EFX_SET_OWORD_FIELD64(oword, field, value) \
|
||||
EFX_SET_OWORD64(oword, EFX_LOW_BIT(field), \
|
||||
EFX_HIGH_BIT(field), value)
|
||||
|
||||
#define EFX_SET_QWORD_FIELD64(qword, field, value) \
|
||||
EFX_SET_QWORD64(qword, EFX_LOW_BIT(field), \
|
||||
EFX_HIGH_BIT(field), value)
|
||||
|
||||
#define EFX_SET_OWORD_FIELD32(oword, field, value) \
|
||||
EFX_SET_OWORD32(oword, EFX_LOW_BIT(field), \
|
||||
EFX_HIGH_BIT(field), value)
|
||||
|
||||
#define EFX_SET_QWORD_FIELD32(qword, field, value) \
|
||||
EFX_SET_QWORD32(qword, EFX_LOW_BIT(field), \
|
||||
EFX_HIGH_BIT(field), value)
|
||||
|
||||
#define EFX_SET_DWORD_FIELD(dword, field, value) \
|
||||
EFX_SET_DWORD32(dword, EFX_LOW_BIT(field), \
|
||||
EFX_HIGH_BIT(field), value)
|
||||
|
||||
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD64
|
||||
#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD64
|
||||
#else
|
||||
#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD32
|
||||
#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD32
|
||||
#endif
|
||||
|
||||
/* Used to avoid compiler warnings about shift range exceeding width
|
||||
* of the data types when dma_addr_t is only 32 bits wide.
|
||||
*/
|
||||
#define DMA_ADDR_T_WIDTH (8 * sizeof(dma_addr_t))
|
||||
#define EFX_DMA_TYPE_WIDTH(width) \
|
||||
(((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH)
|
||||
|
||||
|
||||
/* Static initialiser */
|
||||
#define EFX_OWORD32(a, b, c, d) \
|
||||
{ .u32 = { cpu_to_le32(a), cpu_to_le32(b), \
|
||||
cpu_to_le32(c), cpu_to_le32(d) } }
|
||||
|
||||
#endif /* EFX_BITFIELD_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,236 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/****************************************************************************
|
||||
* Driver for Solarflare network controllers and boards
|
||||
* Copyright 2005-2006 Fen Systems Ltd.
|
||||
* Copyright 2006-2013 Solarflare Communications Inc.
|
||||
*/
|
||||
|
||||
#ifndef EFX_EFX_H
|
||||
#define EFX_EFX_H
|
||||
|
||||
#include <linux/indirect_call_wrapper.h>
|
||||
#include "net_driver.h"
|
||||
#include "ef100_rx.h"
|
||||
#include "ef100_tx.h"
|
||||
#include "filter.h"
|
||||
|
||||
int efx_net_open(struct net_device *net_dev);
|
||||
int efx_net_stop(struct net_device *net_dev);
|
||||
|
||||
/* TX */
|
||||
void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue);
|
||||
netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *net_dev);
|
||||
netdev_tx_t __efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
|
||||
static inline netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
|
||||
{
|
||||
return INDIRECT_CALL_2(tx_queue->efx->type->tx_enqueue,
|
||||
ef100_enqueue_skb, __efx_enqueue_skb,
|
||||
tx_queue, skb);
|
||||
}
|
||||
void efx_xmit_done_single(struct efx_tx_queue *tx_queue);
|
||||
int efx_setup_tc(struct net_device *net_dev, enum tc_setup_type type,
|
||||
void *type_data);
|
||||
extern unsigned int efx_piobuf_size;
|
||||
|
||||
/* RX */
|
||||
void __efx_rx_packet(struct efx_channel *channel);
|
||||
void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
|
||||
unsigned int n_frags, unsigned int len, u16 flags);
|
||||
static inline void efx_rx_flush_packet(struct efx_channel *channel)
|
||||
{
|
||||
if (channel->rx_pkt_n_frags)
|
||||
INDIRECT_CALL_2(channel->efx->type->rx_packet,
|
||||
__ef100_rx_packet, __efx_rx_packet,
|
||||
channel);
|
||||
}
|
||||
static inline bool efx_rx_buf_hash_valid(struct efx_nic *efx, const u8 *prefix)
|
||||
{
|
||||
if (efx->type->rx_buf_hash_valid)
|
||||
return INDIRECT_CALL_1(efx->type->rx_buf_hash_valid,
|
||||
ef100_rx_buf_hash_valid,
|
||||
prefix);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Maximum number of TCP segments we support for soft-TSO */
|
||||
#define EFX_TSO_MAX_SEGS 100
|
||||
|
||||
/* The smallest [rt]xq_entries that the driver supports. RX minimum
|
||||
* is a bit arbitrary. For TX, we must have space for at least 2
|
||||
* TSO skbs.
|
||||
*/
|
||||
#define EFX_RXQ_MIN_ENT 128U
|
||||
#define EFX_TXQ_MIN_ENT(efx) (2 * efx_tx_max_skb_descs(efx))
|
||||
|
||||
/* All EF10 architecture NICs steal one bit of the DMAQ size for various
|
||||
* other purposes when counting TxQ entries, so we halve the queue size.
|
||||
*/
|
||||
#define EFX_TXQ_MAX_ENT(efx) (EFX_WORKAROUND_EF10(efx) ? \
|
||||
EFX_MAX_DMAQ_SIZE / 2 : EFX_MAX_DMAQ_SIZE)
|
||||
|
||||
static inline bool efx_rss_enabled(struct efx_nic *efx)
|
||||
{
|
||||
return efx->rss_spread > 1;
|
||||
}
|
||||
|
||||
/* Filters */
|
||||
|
||||
/**
|
||||
* efx_filter_insert_filter - add or replace a filter
|
||||
* @efx: NIC in which to insert the filter
|
||||
* @spec: Specification for the filter
|
||||
* @replace_equal: Flag for whether the specified filter may replace an
|
||||
* existing filter with equal priority
|
||||
*
|
||||
* On success, return the filter ID.
|
||||
* On failure, return a negative error code.
|
||||
*
|
||||
* If existing filters have equal match values to the new filter spec,
|
||||
* then the new filter might replace them or the function might fail,
|
||||
* as follows.
|
||||
*
|
||||
* 1. If the existing filters have lower priority, or @replace_equal
|
||||
* is set and they have equal priority, replace them.
|
||||
*
|
||||
* 2. If the existing filters have higher priority, return -%EPERM.
|
||||
*
|
||||
* 3. If !efx_filter_is_mc_recipient(@spec), or the NIC does not
|
||||
* support delivery to multiple recipients, return -%EEXIST.
|
||||
*
|
||||
* This implies that filters for multiple multicast recipients must
|
||||
* all be inserted with the same priority and @replace_equal = %false.
|
||||
*/
|
||||
static inline s32 efx_filter_insert_filter(struct efx_nic *efx,
|
||||
struct efx_filter_spec *spec,
|
||||
bool replace_equal)
|
||||
{
|
||||
return efx->type->filter_insert(efx, spec, replace_equal);
|
||||
}
|
||||
|
||||
/**
|
||||
* efx_filter_remove_id_safe - remove a filter by ID, carefully
|
||||
* @efx: NIC from which to remove the filter
|
||||
* @priority: Priority of filter, as passed to @efx_filter_insert_filter
|
||||
* @filter_id: ID of filter, as returned by @efx_filter_insert_filter
|
||||
*
|
||||
* This function will range-check @filter_id, so it is safe to call
|
||||
* with a value passed from userland.
|
||||
*/
|
||||
static inline int efx_filter_remove_id_safe(struct efx_nic *efx,
|
||||
enum efx_filter_priority priority,
|
||||
u32 filter_id)
|
||||
{
|
||||
return efx->type->filter_remove_safe(efx, priority, filter_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* efx_filter_get_filter_safe - retrieve a filter by ID, carefully
|
||||
* @efx: NIC from which to remove the filter
|
||||
* @priority: Priority of filter, as passed to @efx_filter_insert_filter
|
||||
* @filter_id: ID of filter, as returned by @efx_filter_insert_filter
|
||||
* @spec: Buffer in which to store filter specification
|
||||
*
|
||||
* This function will range-check @filter_id, so it is safe to call
|
||||
* with a value passed from userland.
|
||||
*/
|
||||
static inline int
|
||||
efx_filter_get_filter_safe(struct efx_nic *efx,
|
||||
enum efx_filter_priority priority,
|
||||
u32 filter_id, struct efx_filter_spec *spec)
|
||||
{
|
||||
return efx->type->filter_get_safe(efx, priority, filter_id, spec);
|
||||
}
|
||||
|
||||
static inline u32 efx_filter_count_rx_used(struct efx_nic *efx,
|
||||
enum efx_filter_priority priority)
|
||||
{
|
||||
return efx->type->filter_count_rx_used(efx, priority);
|
||||
}
|
||||
static inline u32 efx_filter_get_rx_id_limit(struct efx_nic *efx)
|
||||
{
|
||||
return efx->type->filter_get_rx_id_limit(efx);
|
||||
}
|
||||
static inline s32 efx_filter_get_rx_ids(struct efx_nic *efx,
|
||||
enum efx_filter_priority priority,
|
||||
u32 *buf, u32 size)
|
||||
{
|
||||
return efx->type->filter_get_rx_ids(efx, priority, buf, size);
|
||||
}
|
||||
|
||||
/* RSS contexts */
|
||||
static inline bool efx_rss_active(struct efx_rss_context *ctx)
|
||||
{
|
||||
return ctx->context_id != EFX_MCDI_RSS_CONTEXT_INVALID;
|
||||
}
|
||||
|
||||
/* Ethtool support */
|
||||
extern const struct ethtool_ops efx_ethtool_ops;
|
||||
|
||||
/* Global */
|
||||
unsigned int efx_usecs_to_ticks(struct efx_nic *efx, unsigned int usecs);
|
||||
unsigned int efx_ticks_to_usecs(struct efx_nic *efx, unsigned int ticks);
|
||||
int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs,
|
||||
unsigned int rx_usecs, bool rx_adaptive,
|
||||
bool rx_may_override_tx);
|
||||
void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs,
|
||||
unsigned int *rx_usecs, bool *rx_adaptive);
|
||||
|
||||
/* Update the generic software stats in the passed stats array */
|
||||
void efx_update_sw_stats(struct efx_nic *efx, u64 *stats);
|
||||
|
||||
/* MTD */
|
||||
#ifdef CONFIG_SFC_MTD
|
||||
int efx_mtd_add(struct efx_nic *efx, struct efx_mtd_partition *parts,
|
||||
size_t n_parts, size_t sizeof_part);
|
||||
static inline int efx_mtd_probe(struct efx_nic *efx)
|
||||
{
|
||||
return efx->type->mtd_probe(efx);
|
||||
}
|
||||
void efx_mtd_rename(struct efx_nic *efx);
|
||||
void efx_mtd_remove(struct efx_nic *efx);
|
||||
#else
|
||||
static inline int efx_mtd_probe(struct efx_nic *efx) { return 0; }
|
||||
static inline void efx_mtd_rename(struct efx_nic *efx) {}
|
||||
static inline void efx_mtd_remove(struct efx_nic *efx) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SFC_SRIOV
|
||||
static inline unsigned int efx_vf_size(struct efx_nic *efx)
|
||||
{
|
||||
return 1 << efx->vi_scale;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void efx_device_detach_sync(struct efx_nic *efx)
|
||||
{
|
||||
struct net_device *dev = efx->net_dev;
|
||||
|
||||
/* Lock/freeze all TX queues so that we can be sure the
|
||||
* TX scheduler is stopped when we're done and before
|
||||
* netif_device_present() becomes false.
|
||||
*/
|
||||
netif_tx_lock_bh(dev);
|
||||
netif_device_detach(dev);
|
||||
netif_tx_unlock_bh(dev);
|
||||
}
|
||||
|
||||
static inline void efx_device_attach_if_not_resetting(struct efx_nic *efx)
|
||||
{
|
||||
if ((efx->state != STATE_DISABLED) && !efx->reset_pending)
|
||||
netif_device_attach(efx->net_dev);
|
||||
}
|
||||
|
||||
static inline bool efx_rwsem_assert_write_locked(struct rw_semaphore *sem)
|
||||
{
|
||||
if (WARN_ON(down_read_trylock(sem))) {
|
||||
up_read(sem);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int efx_xdp_tx_buffers(struct efx_nic *efx, int n, struct xdp_frame **xdpfs,
|
||||
bool flush);
|
||||
|
||||
#endif /* EFX_EFX_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,52 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/****************************************************************************
|
||||
* Driver for Solarflare network controllers and boards
|
||||
* Copyright 2018 Solarflare Communications Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation, incorporated herein by reference.
|
||||
*/
|
||||
|
||||
#ifndef EFX_CHANNELS_H
|
||||
#define EFX_CHANNELS_H
|
||||
|
||||
extern unsigned int efx_interrupt_mode;
|
||||
extern unsigned int rss_cpus;
|
||||
|
||||
int efx_probe_interrupts(struct efx_nic *efx);
|
||||
void efx_remove_interrupts(struct efx_nic *efx);
|
||||
int efx_soft_enable_interrupts(struct efx_nic *efx);
|
||||
void efx_soft_disable_interrupts(struct efx_nic *efx);
|
||||
int efx_enable_interrupts(struct efx_nic *efx);
|
||||
void efx_disable_interrupts(struct efx_nic *efx);
|
||||
|
||||
void efx_set_interrupt_affinity(struct efx_nic *efx);
|
||||
void efx_clear_interrupt_affinity(struct efx_nic *efx);
|
||||
|
||||
int efx_probe_eventq(struct efx_channel *channel);
|
||||
int efx_init_eventq(struct efx_channel *channel);
|
||||
void efx_start_eventq(struct efx_channel *channel);
|
||||
void efx_stop_eventq(struct efx_channel *channel);
|
||||
void efx_fini_eventq(struct efx_channel *channel);
|
||||
void efx_remove_eventq(struct efx_channel *channel);
|
||||
|
||||
int efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries);
|
||||
void efx_set_channel_names(struct efx_nic *efx);
|
||||
int efx_init_channels(struct efx_nic *efx);
|
||||
int efx_probe_channels(struct efx_nic *efx);
|
||||
int efx_set_channels(struct efx_nic *efx);
|
||||
void efx_remove_channel(struct efx_channel *channel);
|
||||
void efx_remove_channels(struct efx_nic *efx);
|
||||
void efx_fini_channels(struct efx_nic *efx);
|
||||
void efx_start_channels(struct efx_nic *efx);
|
||||
void efx_stop_channels(struct efx_nic *efx);
|
||||
|
||||
void efx_init_napi_channel(struct efx_channel *channel);
|
||||
void efx_init_napi(struct efx_nic *efx);
|
||||
void efx_fini_napi_channel(struct efx_channel *channel);
|
||||
void efx_fini_napi(struct efx_nic *efx);
|
||||
|
||||
void efx_channel_dummy_op_void(struct efx_channel *channel);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,116 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/****************************************************************************
|
||||
* Driver for Solarflare network controllers and boards
|
||||
* Copyright 2018 Solarflare Communications Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation, incorporated herein by reference.
|
||||
*/
|
||||
|
||||
#ifndef EFX_COMMON_H
|
||||
#define EFX_COMMON_H
|
||||
|
||||
int efx_init_io(struct efx_nic *efx, int bar, dma_addr_t dma_mask,
|
||||
unsigned int mem_map_size);
|
||||
void efx_fini_io(struct efx_nic *efx);
|
||||
int efx_init_struct(struct efx_nic *efx, struct pci_dev *pci_dev,
|
||||
struct net_device *net_dev);
|
||||
void efx_fini_struct(struct efx_nic *efx);
|
||||
|
||||
#define EFX_MAX_DMAQ_SIZE 4096UL
|
||||
#define EFX_DEFAULT_DMAQ_SIZE 1024UL
|
||||
#define EFX_MIN_DMAQ_SIZE 512UL
|
||||
|
||||
#define EFX_MAX_EVQ_SIZE 16384UL
|
||||
#define EFX_MIN_EVQ_SIZE 512UL
|
||||
|
||||
void efx_link_clear_advertising(struct efx_nic *efx);
|
||||
void efx_link_set_wanted_fc(struct efx_nic *efx, u8);
|
||||
|
||||
void efx_start_all(struct efx_nic *efx);
|
||||
void efx_stop_all(struct efx_nic *efx);
|
||||
|
||||
void efx_net_stats(struct net_device *net_dev, struct rtnl_link_stats64 *stats);
|
||||
|
||||
int efx_create_reset_workqueue(void);
|
||||
void efx_queue_reset_work(struct efx_nic *efx);
|
||||
void efx_flush_reset_workqueue(struct efx_nic *efx);
|
||||
void efx_destroy_reset_workqueue(void);
|
||||
|
||||
void efx_start_monitor(struct efx_nic *efx);
|
||||
|
||||
int __efx_reconfigure_port(struct efx_nic *efx);
|
||||
int efx_reconfigure_port(struct efx_nic *efx);
|
||||
|
||||
#define EFX_ASSERT_RESET_SERIALISED(efx) \
|
||||
do { \
|
||||
if ((efx->state == STATE_READY) || \
|
||||
(efx->state == STATE_RECOVERY) || \
|
||||
(efx->state == STATE_DISABLED)) \
|
||||
ASSERT_RTNL(); \
|
||||
} while (0)
|
||||
|
||||
int efx_try_recovery(struct efx_nic *efx);
|
||||
void efx_reset_down(struct efx_nic *efx, enum reset_type method);
|
||||
void efx_watchdog(struct net_device *net_dev, unsigned int txqueue);
|
||||
int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);
|
||||
int efx_reset(struct efx_nic *efx, enum reset_type method);
|
||||
void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
|
||||
|
||||
/* Dummy PHY ops for PHY drivers */
|
||||
int efx_port_dummy_op_int(struct efx_nic *efx);
|
||||
void efx_port_dummy_op_void(struct efx_nic *efx);
|
||||
|
||||
static inline int efx_check_disabled(struct efx_nic *efx)
|
||||
{
|
||||
if (efx->state == STATE_DISABLED || efx->state == STATE_RECOVERY) {
|
||||
netif_err(efx, drv, efx->net_dev,
|
||||
"device is disabled due to earlier errors\n");
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void efx_schedule_channel(struct efx_channel *channel)
|
||||
{
|
||||
netif_vdbg(channel->efx, intr, channel->efx->net_dev,
|
||||
"channel %d scheduling NAPI poll on CPU%d\n",
|
||||
channel->channel, raw_smp_processor_id());
|
||||
|
||||
napi_schedule(&channel->napi_str);
|
||||
}
|
||||
|
||||
static inline void efx_schedule_channel_irq(struct efx_channel *channel)
|
||||
{
|
||||
channel->event_test_cpu = raw_smp_processor_id();
|
||||
efx_schedule_channel(channel);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SFC_MCDI_LOGGING
|
||||
void efx_init_mcdi_logging(struct efx_nic *efx);
|
||||
void efx_fini_mcdi_logging(struct efx_nic *efx);
|
||||
#else
|
||||
static inline void efx_init_mcdi_logging(struct efx_nic *efx) {}
|
||||
static inline void efx_fini_mcdi_logging(struct efx_nic *efx) {}
|
||||
#endif
|
||||
|
||||
void efx_mac_reconfigure(struct efx_nic *efx, bool mtu_only);
|
||||
int efx_set_mac_address(struct net_device *net_dev, void *data);
|
||||
void efx_set_rx_mode(struct net_device *net_dev);
|
||||
int efx_set_features(struct net_device *net_dev, netdev_features_t data);
|
||||
void efx_link_status_changed(struct efx_nic *efx);
|
||||
unsigned int efx_xdp_max_mtu(struct efx_nic *efx);
|
||||
int efx_change_mtu(struct net_device *net_dev, int new_mtu);
|
||||
|
||||
extern const struct pci_error_handlers efx_err_handlers;
|
||||
|
||||
netdev_features_t efx_features_check(struct sk_buff *skb, struct net_device *dev,
|
||||
netdev_features_t features);
|
||||
|
||||
int efx_get_phys_port_id(struct net_device *net_dev,
|
||||
struct netdev_phys_item_id *ppid);
|
||||
|
||||
int efx_get_phys_port_name(struct net_device *net_dev,
|
||||
char *name, size_t len);
|
||||
#endif
|
|
@ -0,0 +1,176 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/****************************************************************************
|
||||
* Driver for Solarflare network controllers and boards
|
||||
* Copyright 2007-2013 Solarflare Communications Inc.
|
||||
*/
|
||||
|
||||
#ifndef EFX_ENUM_H
|
||||
#define EFX_ENUM_H
|
||||
|
||||
/**
|
||||
* enum efx_loopback_mode - loopback modes
|
||||
* @LOOPBACK_NONE: no loopback
|
||||
* @LOOPBACK_DATA: data path loopback
|
||||
* @LOOPBACK_GMAC: loopback within GMAC
|
||||
* @LOOPBACK_XGMII: loopback after XMAC
|
||||
* @LOOPBACK_XGXS: loopback within BPX after XGXS
|
||||
* @LOOPBACK_XAUI: loopback within BPX before XAUI serdes
|
||||
* @LOOPBACK_GMII: loopback within BPX after GMAC
|
||||
* @LOOPBACK_SGMII: loopback within BPX within SGMII
|
||||
* @LOOPBACK_XGBR: loopback within BPX within XGBR
|
||||
* @LOOPBACK_XFI: loopback within BPX before XFI serdes
|
||||
* @LOOPBACK_XAUI_FAR: loopback within BPX after XAUI serdes
|
||||
* @LOOPBACK_GMII_FAR: loopback within BPX before SGMII
|
||||
* @LOOPBACK_SGMII_FAR: loopback within BPX after SGMII
|
||||
* @LOOPBACK_XFI_FAR: loopback after XFI serdes
|
||||
* @LOOPBACK_GPHY: loopback within 1G PHY at unspecified level
|
||||
* @LOOPBACK_PHYXS: loopback within 10G PHY at PHYXS level
|
||||
* @LOOPBACK_PCS: loopback within 10G PHY at PCS level
|
||||
* @LOOPBACK_PMAPMD: loopback within 10G PHY at PMAPMD level
|
||||
* @LOOPBACK_XPORT: cross port loopback
|
||||
* @LOOPBACK_XGMII_WS: wireside loopback excluding XMAC
|
||||
* @LOOPBACK_XAUI_WS: wireside loopback within BPX within XAUI serdes
|
||||
* @LOOPBACK_XAUI_WS_FAR: wireside loopback within BPX including XAUI serdes
|
||||
* @LOOPBACK_XAUI_WS_NEAR: wireside loopback within BPX excluding XAUI serdes
|
||||
* @LOOPBACK_GMII_WS: wireside loopback excluding GMAC
|
||||
* @LOOPBACK_XFI_WS: wireside loopback excluding XFI serdes
|
||||
* @LOOPBACK_XFI_WS_FAR: wireside loopback including XFI serdes
|
||||
* @LOOPBACK_PHYXS_WS: wireside loopback within 10G PHY at PHYXS level
|
||||
*/
|
||||
/* Please keep up-to-date w.r.t the following two #defines */
|
||||
enum efx_loopback_mode {
|
||||
LOOPBACK_NONE = 0,
|
||||
LOOPBACK_DATA = 1,
|
||||
LOOPBACK_GMAC = 2,
|
||||
LOOPBACK_XGMII = 3,
|
||||
LOOPBACK_XGXS = 4,
|
||||
LOOPBACK_XAUI = 5,
|
||||
LOOPBACK_GMII = 6,
|
||||
LOOPBACK_SGMII = 7,
|
||||
LOOPBACK_XGBR = 8,
|
||||
LOOPBACK_XFI = 9,
|
||||
LOOPBACK_XAUI_FAR = 10,
|
||||
LOOPBACK_GMII_FAR = 11,
|
||||
LOOPBACK_SGMII_FAR = 12,
|
||||
LOOPBACK_XFI_FAR = 13,
|
||||
LOOPBACK_GPHY = 14,
|
||||
LOOPBACK_PHYXS = 15,
|
||||
LOOPBACK_PCS = 16,
|
||||
LOOPBACK_PMAPMD = 17,
|
||||
LOOPBACK_XPORT = 18,
|
||||
LOOPBACK_XGMII_WS = 19,
|
||||
LOOPBACK_XAUI_WS = 20,
|
||||
LOOPBACK_XAUI_WS_FAR = 21,
|
||||
LOOPBACK_XAUI_WS_NEAR = 22,
|
||||
LOOPBACK_GMII_WS = 23,
|
||||
LOOPBACK_XFI_WS = 24,
|
||||
LOOPBACK_XFI_WS_FAR = 25,
|
||||
LOOPBACK_PHYXS_WS = 26,
|
||||
LOOPBACK_MAX
|
||||
};
|
||||
#define LOOPBACK_TEST_MAX LOOPBACK_PMAPMD
|
||||
|
||||
/* These loopbacks occur within the controller */
|
||||
#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_DATA) | \
|
||||
(1 << LOOPBACK_GMAC) | \
|
||||
(1 << LOOPBACK_XGMII)| \
|
||||
(1 << LOOPBACK_XGXS) | \
|
||||
(1 << LOOPBACK_XAUI) | \
|
||||
(1 << LOOPBACK_GMII) | \
|
||||
(1 << LOOPBACK_SGMII) | \
|
||||
(1 << LOOPBACK_XGBR) | \
|
||||
(1 << LOOPBACK_XFI) | \
|
||||
(1 << LOOPBACK_XAUI_FAR) | \
|
||||
(1 << LOOPBACK_GMII_FAR) | \
|
||||
(1 << LOOPBACK_SGMII_FAR) | \
|
||||
(1 << LOOPBACK_XFI_FAR) | \
|
||||
(1 << LOOPBACK_XGMII_WS) | \
|
||||
(1 << LOOPBACK_XAUI_WS) | \
|
||||
(1 << LOOPBACK_XAUI_WS_FAR) | \
|
||||
(1 << LOOPBACK_XAUI_WS_NEAR) | \
|
||||
(1 << LOOPBACK_GMII_WS) | \
|
||||
(1 << LOOPBACK_XFI_WS) | \
|
||||
(1 << LOOPBACK_XFI_WS_FAR))
|
||||
|
||||
#define LOOPBACKS_WS ((1 << LOOPBACK_XGMII_WS) | \
|
||||
(1 << LOOPBACK_XAUI_WS) | \
|
||||
(1 << LOOPBACK_XAUI_WS_FAR) | \
|
||||
(1 << LOOPBACK_XAUI_WS_NEAR) | \
|
||||
(1 << LOOPBACK_GMII_WS) | \
|
||||
(1 << LOOPBACK_XFI_WS) | \
|
||||
(1 << LOOPBACK_XFI_WS_FAR) | \
|
||||
(1 << LOOPBACK_PHYXS_WS))
|
||||
|
||||
#define LOOPBACKS_EXTERNAL(_efx) \
|
||||
((_efx)->loopback_modes & ~LOOPBACKS_INTERNAL & \
|
||||
~(1 << LOOPBACK_NONE))
|
||||
|
||||
#define LOOPBACK_MASK(_efx) \
|
||||
(1 << (_efx)->loopback_mode)
|
||||
|
||||
#define LOOPBACK_INTERNAL(_efx) \
|
||||
(!!(LOOPBACKS_INTERNAL & LOOPBACK_MASK(_efx)))
|
||||
|
||||
#define LOOPBACK_EXTERNAL(_efx) \
|
||||
(!!(LOOPBACK_MASK(_efx) & LOOPBACKS_EXTERNAL(_efx)))
|
||||
|
||||
#define LOOPBACK_CHANGED(_from, _to, _mask) \
|
||||
(!!((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) & (_mask)))
|
||||
|
||||
#define LOOPBACK_OUT_OF(_from, _to, _mask) \
|
||||
((LOOPBACK_MASK(_from) & (_mask)) && !(LOOPBACK_MASK(_to) & (_mask)))
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* enum reset_type - reset types
|
||||
*
|
||||
* %RESET_TYPE_INVSIBLE, %RESET_TYPE_ALL, %RESET_TYPE_WORLD and
|
||||
* %RESET_TYPE_DISABLE specify the method/scope of the reset. The
|
||||
* other valuesspecify reasons, which efx_schedule_reset() will choose
|
||||
* a method for.
|
||||
*
|
||||
* Reset methods are numbered in order of increasing scope.
|
||||
*
|
||||
* @RESET_TYPE_INVISIBLE: Reset datapath and MAC (Falcon only)
|
||||
* @RESET_TYPE_RECOVER_OR_ALL: Try to recover. Apply RESET_TYPE_ALL
|
||||
* if unsuccessful.
|
||||
* @RESET_TYPE_ALL: Reset datapath, MAC and PHY
|
||||
* @RESET_TYPE_WORLD: Reset as much as possible
|
||||
* @RESET_TYPE_RECOVER_OR_DISABLE: Try to recover. Apply RESET_TYPE_DISABLE if
|
||||
* unsuccessful.
|
||||
* @RESET_TYPE_DATAPATH: Reset datapath only.
|
||||
* @RESET_TYPE_MC_BIST: MC entering BIST mode.
|
||||
* @RESET_TYPE_DISABLE: Reset datapath, MAC and PHY; leave NIC disabled
|
||||
* @RESET_TYPE_TX_WATCHDOG: reset due to TX watchdog
|
||||
* @RESET_TYPE_INT_ERROR: reset due to internal error
|
||||
* @RESET_TYPE_DMA_ERROR: DMA error
|
||||
* @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors
|
||||
* @RESET_TYPE_MC_FAILURE: MC reboot/assertion
|
||||
* @RESET_TYPE_MCDI_TIMEOUT: MCDI timeout.
|
||||
*/
|
||||
enum reset_type {
|
||||
RESET_TYPE_INVISIBLE,
|
||||
RESET_TYPE_RECOVER_OR_ALL,
|
||||
RESET_TYPE_ALL,
|
||||
RESET_TYPE_WORLD,
|
||||
RESET_TYPE_RECOVER_OR_DISABLE,
|
||||
RESET_TYPE_DATAPATH,
|
||||
RESET_TYPE_MC_BIST,
|
||||
RESET_TYPE_DISABLE,
|
||||
RESET_TYPE_MAX_METHOD,
|
||||
RESET_TYPE_TX_WATCHDOG,
|
||||
RESET_TYPE_INT_ERROR,
|
||||
RESET_TYPE_DMA_ERROR,
|
||||
RESET_TYPE_TX_SKIP,
|
||||
RESET_TYPE_MC_FAILURE,
|
||||
/* RESET_TYPE_MCDI_TIMEOUT is actually a method, not just a reason, but
|
||||
* it doesn't fit the scope hierarchy (not well-ordered by inclusion).
|
||||
* We encode this by having its enum value be greater than
|
||||
* RESET_TYPE_MAX_METHOD.
|
||||
*/
|
||||
RESET_TYPE_MCDI_TIMEOUT,
|
||||
RESET_TYPE_MAX,
|
||||
};
|
||||
|
||||
#endif /* EFX_ENUM_H */
|
|
@ -0,0 +1,282 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/****************************************************************************
|
||||
* Driver for Solarflare network controllers and boards
|
||||
* Copyright 2005-2006 Fen Systems Ltd.
|
||||
* Copyright 2006-2013 Solarflare Communications Inc.
|
||||
*/
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/in.h>
|
||||
#include "net_driver.h"
|
||||
#include "workarounds.h"
|
||||
#include "selftest.h"
|
||||
#include "efx.h"
|
||||
#include "efx_channels.h"
|
||||
#include "rx_common.h"
|
||||
#include "tx_common.h"
|
||||
#include "ethtool_common.h"
|
||||
#include "filter.h"
|
||||
#include "nic.h"
|
||||
|
||||
#define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* Ethtool operations
|
||||
*
|
||||
**************************************************************************
|
||||
*/
|
||||
|
||||
/* Identify device by flashing LEDs */
|
||||
static int efx_ethtool_phys_id(struct net_device *net_dev,
|
||||
enum ethtool_phys_id_state state)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
enum efx_led_mode mode = EFX_LED_DEFAULT;
|
||||
|
||||
switch (state) {
|
||||
case ETHTOOL_ID_ON:
|
||||
mode = EFX_LED_ON;
|
||||
break;
|
||||
case ETHTOOL_ID_OFF:
|
||||
mode = EFX_LED_OFF;
|
||||
break;
|
||||
case ETHTOOL_ID_INACTIVE:
|
||||
mode = EFX_LED_DEFAULT;
|
||||
break;
|
||||
case ETHTOOL_ID_ACTIVE:
|
||||
return 1; /* cycle on/off once per second */
|
||||
}
|
||||
|
||||
return efx_mcdi_set_id_led(efx, mode);
|
||||
}
|
||||
|
||||
static int efx_ethtool_get_regs_len(struct net_device *net_dev)
|
||||
{
|
||||
return efx_nic_get_regs_len(netdev_priv(net_dev));
|
||||
}
|
||||
|
||||
static void efx_ethtool_get_regs(struct net_device *net_dev,
|
||||
struct ethtool_regs *regs, void *buf)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
|
||||
regs->version = efx->type->revision;
|
||||
efx_nic_get_regs(efx, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Each channel has a single IRQ and moderation timer, started by any
|
||||
* completion (or other event). Unless the module parameter
|
||||
* separate_tx_channels is set, IRQs and moderation are therefore
|
||||
* shared between RX and TX completions. In this case, when RX IRQ
|
||||
* moderation is explicitly changed then TX IRQ moderation is
|
||||
* automatically changed too, but otherwise we fail if the two values
|
||||
* are requested to be different.
|
||||
*
|
||||
* The hardware does not support a limit on the number of completions
|
||||
* before an IRQ, so we do not use the max_frames fields. We should
|
||||
* report and require that max_frames == (usecs != 0), but this would
|
||||
* invalidate existing user documentation.
|
||||
*
|
||||
* The hardware does not have distinct settings for interrupt
|
||||
* moderation while the previous IRQ is being handled, so we should
|
||||
* not use the 'irq' fields. However, an earlier developer
|
||||
* misunderstood the meaning of the 'irq' fields and the driver did
|
||||
* not support the standard fields. To avoid invalidating existing
|
||||
* user documentation, we report and accept changes through either the
|
||||
* standard or 'irq' fields. If both are changed at the same time, we
|
||||
* prefer the standard field.
|
||||
*
|
||||
* We implement adaptive IRQ moderation, but use a different algorithm
|
||||
* from that assumed in the definition of struct ethtool_coalesce.
|
||||
* Therefore we do not use any of the adaptive moderation parameters
|
||||
* in it.
|
||||
*/
|
||||
|
||||
static int efx_ethtool_get_coalesce(struct net_device *net_dev,
|
||||
struct ethtool_coalesce *coalesce,
|
||||
struct kernel_ethtool_coalesce *kernel_coal,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
unsigned int tx_usecs, rx_usecs;
|
||||
bool rx_adaptive;
|
||||
|
||||
efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &rx_adaptive);
|
||||
|
||||
coalesce->tx_coalesce_usecs = tx_usecs;
|
||||
coalesce->tx_coalesce_usecs_irq = tx_usecs;
|
||||
coalesce->rx_coalesce_usecs = rx_usecs;
|
||||
coalesce->rx_coalesce_usecs_irq = rx_usecs;
|
||||
coalesce->use_adaptive_rx_coalesce = rx_adaptive;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efx_ethtool_set_coalesce(struct net_device *net_dev,
|
||||
struct ethtool_coalesce *coalesce,
|
||||
struct kernel_ethtool_coalesce *kernel_coal,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
struct efx_channel *channel;
|
||||
unsigned int tx_usecs, rx_usecs;
|
||||
bool adaptive, rx_may_override_tx;
|
||||
int rc;
|
||||
|
||||
efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &adaptive);
|
||||
|
||||
if (coalesce->rx_coalesce_usecs != rx_usecs)
|
||||
rx_usecs = coalesce->rx_coalesce_usecs;
|
||||
else
|
||||
rx_usecs = coalesce->rx_coalesce_usecs_irq;
|
||||
|
||||
adaptive = coalesce->use_adaptive_rx_coalesce;
|
||||
|
||||
/* If channels are shared, TX IRQ moderation can be quietly
|
||||
* overridden unless it is changed from its old value.
|
||||
*/
|
||||
rx_may_override_tx = (coalesce->tx_coalesce_usecs == tx_usecs &&
|
||||
coalesce->tx_coalesce_usecs_irq == tx_usecs);
|
||||
if (coalesce->tx_coalesce_usecs != tx_usecs)
|
||||
tx_usecs = coalesce->tx_coalesce_usecs;
|
||||
else
|
||||
tx_usecs = coalesce->tx_coalesce_usecs_irq;
|
||||
|
||||
rc = efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive,
|
||||
rx_may_override_tx);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
efx_for_each_channel(channel, efx)
|
||||
efx->type->push_irq_moderation(channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
efx_ethtool_get_ringparam(struct net_device *net_dev,
|
||||
struct ethtool_ringparam *ring,
|
||||
struct kernel_ethtool_ringparam *kernel_ring,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
|
||||
ring->rx_max_pending = EFX_MAX_DMAQ_SIZE;
|
||||
ring->tx_max_pending = EFX_TXQ_MAX_ENT(efx);
|
||||
ring->rx_pending = efx->rxq_entries;
|
||||
ring->tx_pending = efx->txq_entries;
|
||||
}
|
||||
|
||||
static int
|
||||
efx_ethtool_set_ringparam(struct net_device *net_dev,
|
||||
struct ethtool_ringparam *ring,
|
||||
struct kernel_ethtool_ringparam *kernel_ring,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
u32 txq_entries;
|
||||
|
||||
if (ring->rx_mini_pending || ring->rx_jumbo_pending ||
|
||||
ring->rx_pending > EFX_MAX_DMAQ_SIZE ||
|
||||
ring->tx_pending > EFX_TXQ_MAX_ENT(efx))
|
||||
return -EINVAL;
|
||||
|
||||
if (ring->rx_pending < EFX_RXQ_MIN_ENT) {
|
||||
netif_err(efx, drv, efx->net_dev,
|
||||
"RX queues cannot be smaller than %u\n",
|
||||
EFX_RXQ_MIN_ENT);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
txq_entries = max(ring->tx_pending, EFX_TXQ_MIN_ENT(efx));
|
||||
if (txq_entries != ring->tx_pending)
|
||||
netif_warn(efx, drv, efx->net_dev,
|
||||
"increasing TX queue size to minimum of %u\n",
|
||||
txq_entries);
|
||||
|
||||
return efx_realloc_channels(efx, ring->rx_pending, txq_entries);
|
||||
}
|
||||
|
||||
static void efx_ethtool_get_wol(struct net_device *net_dev,
|
||||
struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
return efx->type->get_wol(efx, wol);
|
||||
}
|
||||
|
||||
|
||||
static int efx_ethtool_set_wol(struct net_device *net_dev,
|
||||
struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
return efx->type->set_wol(efx, wol->wolopts);
|
||||
}
|
||||
|
||||
static void efx_ethtool_get_fec_stats(struct net_device *net_dev,
|
||||
struct ethtool_fec_stats *fec_stats)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
|
||||
if (efx->type->get_fec_stats)
|
||||
efx->type->get_fec_stats(efx, fec_stats);
|
||||
}
|
||||
|
||||
static int efx_ethtool_get_ts_info(struct net_device *net_dev,
|
||||
struct ethtool_ts_info *ts_info)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
|
||||
/* Software capabilities */
|
||||
ts_info->so_timestamping = (SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_SOFTWARE);
|
||||
ts_info->phc_index = -1;
|
||||
|
||||
efx_ptp_get_ts_info(efx, ts_info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct ethtool_ops efx_ethtool_ops = {
|
||||
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
||||
ETHTOOL_COALESCE_USECS_IRQ |
|
||||
ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
|
||||
.get_drvinfo = efx_ethtool_get_drvinfo,
|
||||
.get_regs_len = efx_ethtool_get_regs_len,
|
||||
.get_regs = efx_ethtool_get_regs,
|
||||
.get_msglevel = efx_ethtool_get_msglevel,
|
||||
.set_msglevel = efx_ethtool_set_msglevel,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_coalesce = efx_ethtool_get_coalesce,
|
||||
.set_coalesce = efx_ethtool_set_coalesce,
|
||||
.get_ringparam = efx_ethtool_get_ringparam,
|
||||
.set_ringparam = efx_ethtool_set_ringparam,
|
||||
.get_pauseparam = efx_ethtool_get_pauseparam,
|
||||
.set_pauseparam = efx_ethtool_set_pauseparam,
|
||||
.get_sset_count = efx_ethtool_get_sset_count,
|
||||
.self_test = efx_ethtool_self_test,
|
||||
.get_strings = efx_ethtool_get_strings,
|
||||
.set_phys_id = efx_ethtool_phys_id,
|
||||
.get_ethtool_stats = efx_ethtool_get_stats,
|
||||
.get_wol = efx_ethtool_get_wol,
|
||||
.set_wol = efx_ethtool_set_wol,
|
||||
.reset = efx_ethtool_reset,
|
||||
.get_rxnfc = efx_ethtool_get_rxnfc,
|
||||
.set_rxnfc = efx_ethtool_set_rxnfc,
|
||||
.get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
|
||||
.get_rxfh_key_size = efx_ethtool_get_rxfh_key_size,
|
||||
.get_rxfh = efx_ethtool_get_rxfh,
|
||||
.set_rxfh = efx_ethtool_set_rxfh,
|
||||
.get_rxfh_context = efx_ethtool_get_rxfh_context,
|
||||
.set_rxfh_context = efx_ethtool_set_rxfh_context,
|
||||
.get_ts_info = efx_ethtool_get_ts_info,
|
||||
.get_module_info = efx_ethtool_get_module_info,
|
||||
.get_module_eeprom = efx_ethtool_get_module_eeprom,
|
||||
.get_link_ksettings = efx_ethtool_get_link_ksettings,
|
||||
.set_link_ksettings = efx_ethtool_set_link_ksettings,
|
||||
.get_fec_stats = efx_ethtool_get_fec_stats,
|
||||
.get_fecparam = efx_ethtool_get_fecparam,
|
||||
.set_fecparam = efx_ethtool_set_fecparam,
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,63 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/****************************************************************************
|
||||
* Driver for Solarflare network controllers and boards
|
||||
* Copyright 2019 Solarflare Communications Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation, incorporated herein by reference.
|
||||
*/
|
||||
|
||||
#ifndef EFX_ETHTOOL_COMMON_H
|
||||
#define EFX_ETHTOOL_COMMON_H
|
||||
|
||||
void efx_ethtool_get_drvinfo(struct net_device *net_dev,
|
||||
struct ethtool_drvinfo *info);
|
||||
u32 efx_ethtool_get_msglevel(struct net_device *net_dev);
|
||||
void efx_ethtool_set_msglevel(struct net_device *net_dev, u32 msg_enable);
|
||||
void efx_ethtool_self_test(struct net_device *net_dev,
|
||||
struct ethtool_test *test, u64 *data);
|
||||
void efx_ethtool_get_pauseparam(struct net_device *net_dev,
|
||||
struct ethtool_pauseparam *pause);
|
||||
int efx_ethtool_set_pauseparam(struct net_device *net_dev,
|
||||
struct ethtool_pauseparam *pause);
|
||||
int efx_ethtool_fill_self_tests(struct efx_nic *efx,
|
||||
struct efx_self_tests *tests,
|
||||
u8 *strings, u64 *data);
|
||||
int efx_ethtool_get_sset_count(struct net_device *net_dev, int string_set);
|
||||
void efx_ethtool_get_strings(struct net_device *net_dev, u32 string_set,
|
||||
u8 *strings);
|
||||
void efx_ethtool_get_stats(struct net_device *net_dev,
|
||||
struct ethtool_stats *stats __attribute__ ((unused)),
|
||||
u64 *data);
|
||||
int efx_ethtool_get_link_ksettings(struct net_device *net_dev,
|
||||
struct ethtool_link_ksettings *out);
|
||||
int efx_ethtool_set_link_ksettings(struct net_device *net_dev,
|
||||
const struct ethtool_link_ksettings *settings);
|
||||
int efx_ethtool_get_fecparam(struct net_device *net_dev,
|
||||
struct ethtool_fecparam *fecparam);
|
||||
int efx_ethtool_set_fecparam(struct net_device *net_dev,
|
||||
struct ethtool_fecparam *fecparam);
|
||||
int efx_ethtool_get_rxnfc(struct net_device *net_dev,
|
||||
struct ethtool_rxnfc *info, u32 *rule_locs);
|
||||
int efx_ethtool_set_rxnfc(struct net_device *net_dev,
|
||||
struct ethtool_rxnfc *info);
|
||||
u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev);
|
||||
u32 efx_ethtool_get_rxfh_key_size(struct net_device *net_dev);
|
||||
int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key,
|
||||
u8 *hfunc);
|
||||
int efx_ethtool_set_rxfh(struct net_device *net_dev,
|
||||
const u32 *indir, const u8 *key, const u8 hfunc);
|
||||
int efx_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
|
||||
u8 *key, u8 *hfunc, u32 rss_context);
|
||||
int efx_ethtool_set_rxfh_context(struct net_device *net_dev,
|
||||
const u32 *indir, const u8 *key,
|
||||
const u8 hfunc, u32 *rss_context,
|
||||
bool delete);
|
||||
int efx_ethtool_reset(struct net_device *net_dev, u32 *flags);
|
||||
int efx_ethtool_get_module_eeprom(struct net_device *net_dev,
|
||||
struct ethtool_eeprom *ee,
|
||||
u8 *data);
|
||||
int efx_ethtool_get_module_info(struct net_device *net_dev,
|
||||
struct ethtool_modinfo *modinfo);
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,309 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/****************************************************************************
|
||||
* Driver for Solarflare network controllers and boards
|
||||
* Copyright 2005-2013 Solarflare Communications Inc.
|
||||
*/
|
||||
|
||||
#ifndef EFX_FILTER_H
|
||||
#define EFX_FILTER_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
/**
|
||||
* enum efx_filter_match_flags - Flags for hardware filter match type
|
||||
* @EFX_FILTER_MATCH_REM_HOST: Match by remote IP host address
|
||||
* @EFX_FILTER_MATCH_LOC_HOST: Match by local IP host address
|
||||
* @EFX_FILTER_MATCH_REM_MAC: Match by remote MAC address
|
||||
* @EFX_FILTER_MATCH_REM_PORT: Match by remote TCP/UDP port
|
||||
* @EFX_FILTER_MATCH_LOC_MAC: Match by local MAC address
|
||||
* @EFX_FILTER_MATCH_LOC_PORT: Match by local TCP/UDP port
|
||||
* @EFX_FILTER_MATCH_ETHER_TYPE: Match by Ether-type
|
||||
* @EFX_FILTER_MATCH_INNER_VID: Match by inner VLAN ID
|
||||
* @EFX_FILTER_MATCH_OUTER_VID: Match by outer VLAN ID
|
||||
* @EFX_FILTER_MATCH_IP_PROTO: Match by IP transport protocol
|
||||
* @EFX_FILTER_MATCH_LOC_MAC_IG: Match by local MAC address I/G bit.
|
||||
* @EFX_FILTER_MATCH_ENCAP_TYPE: Match by encapsulation type.
|
||||
* Used for RX default unicast and multicast/broadcast filters.
|
||||
*
|
||||
* Only some combinations are supported, depending on NIC type:
|
||||
*
|
||||
* - Falcon supports RX filters matching by {TCP,UDP}/IPv4 4-tuple or
|
||||
* local 2-tuple (only implemented for Falcon B0)
|
||||
*
|
||||
* - Siena supports RX and TX filters matching by {TCP,UDP}/IPv4 4-tuple
|
||||
* or local 2-tuple, or local MAC with or without outer VID, and RX
|
||||
* default filters
|
||||
*
|
||||
* - Huntington supports filter matching controlled by firmware, potentially
|
||||
* using {TCP,UDP}/IPv{4,6} 4-tuple or local 2-tuple, local MAC or I/G bit,
|
||||
* with or without outer and inner VID
|
||||
*/
|
||||
enum efx_filter_match_flags {
|
||||
EFX_FILTER_MATCH_REM_HOST = 0x0001,
|
||||
EFX_FILTER_MATCH_LOC_HOST = 0x0002,
|
||||
EFX_FILTER_MATCH_REM_MAC = 0x0004,
|
||||
EFX_FILTER_MATCH_REM_PORT = 0x0008,
|
||||
EFX_FILTER_MATCH_LOC_MAC = 0x0010,
|
||||
EFX_FILTER_MATCH_LOC_PORT = 0x0020,
|
||||
EFX_FILTER_MATCH_ETHER_TYPE = 0x0040,
|
||||
EFX_FILTER_MATCH_INNER_VID = 0x0080,
|
||||
EFX_FILTER_MATCH_OUTER_VID = 0x0100,
|
||||
EFX_FILTER_MATCH_IP_PROTO = 0x0200,
|
||||
EFX_FILTER_MATCH_LOC_MAC_IG = 0x0400,
|
||||
EFX_FILTER_MATCH_ENCAP_TYPE = 0x0800,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum efx_filter_priority - priority of a hardware filter specification
|
||||
* @EFX_FILTER_PRI_HINT: Performance hint
|
||||
* @EFX_FILTER_PRI_AUTO: Automatic filter based on device address list
|
||||
* or hardware requirements. This may only be used by the filter
|
||||
* implementation for each NIC type.
|
||||
* @EFX_FILTER_PRI_MANUAL: Manually configured filter
|
||||
* @EFX_FILTER_PRI_REQUIRED: Required for correct behaviour (user-level
|
||||
* networking and SR-IOV)
|
||||
*/
|
||||
enum efx_filter_priority {
|
||||
EFX_FILTER_PRI_HINT = 0,
|
||||
EFX_FILTER_PRI_AUTO,
|
||||
EFX_FILTER_PRI_MANUAL,
|
||||
EFX_FILTER_PRI_REQUIRED,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum efx_filter_flags - flags for hardware filter specifications
|
||||
* @EFX_FILTER_FLAG_RX_RSS: Use RSS to spread across multiple queues.
|
||||
* By default, matching packets will be delivered only to the
|
||||
* specified queue. If this flag is set, they will be delivered
|
||||
* to a range of queues offset from the specified queue number
|
||||
* according to the indirection table.
|
||||
* @EFX_FILTER_FLAG_RX_SCATTER: Enable DMA scatter on the receiving
|
||||
* queue.
|
||||
* @EFX_FILTER_FLAG_RX_OVER_AUTO: Indicates a filter that is
|
||||
* overriding an automatic filter (priority
|
||||
* %EFX_FILTER_PRI_AUTO). This may only be set by the filter
|
||||
* implementation for each type. A removal request will restore
|
||||
* the automatic filter in its place.
|
||||
* @EFX_FILTER_FLAG_RX: Filter is for RX
|
||||
* @EFX_FILTER_FLAG_TX: Filter is for TX
|
||||
*/
|
||||
enum efx_filter_flags {
|
||||
EFX_FILTER_FLAG_RX_RSS = 0x01,
|
||||
EFX_FILTER_FLAG_RX_SCATTER = 0x02,
|
||||
EFX_FILTER_FLAG_RX_OVER_AUTO = 0x04,
|
||||
EFX_FILTER_FLAG_RX = 0x08,
|
||||
EFX_FILTER_FLAG_TX = 0x10,
|
||||
};
|
||||
|
||||
/** enum efx_encap_type - types of encapsulation
|
||||
* @EFX_ENCAP_TYPE_NONE: no encapsulation
|
||||
* @EFX_ENCAP_TYPE_VXLAN: VXLAN encapsulation
|
||||
* @EFX_ENCAP_TYPE_NVGRE: NVGRE encapsulation
|
||||
* @EFX_ENCAP_TYPE_GENEVE: GENEVE encapsulation
|
||||
* @EFX_ENCAP_FLAG_IPV6: indicates IPv6 outer frame
|
||||
*
|
||||
* Contains both enumerated types and flags.
|
||||
* To get just the type, OR with @EFX_ENCAP_TYPES_MASK.
|
||||
*/
|
||||
enum efx_encap_type {
|
||||
EFX_ENCAP_TYPE_NONE = 0,
|
||||
EFX_ENCAP_TYPE_VXLAN = 1,
|
||||
EFX_ENCAP_TYPE_NVGRE = 2,
|
||||
EFX_ENCAP_TYPE_GENEVE = 3,
|
||||
|
||||
EFX_ENCAP_TYPES_MASK = 7,
|
||||
EFX_ENCAP_FLAG_IPV6 = 8,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct efx_filter_spec - specification for a hardware filter
|
||||
* @match_flags: Match type flags, from &enum efx_filter_match_flags
|
||||
* @priority: Priority of the filter, from &enum efx_filter_priority
|
||||
* @flags: Miscellaneous flags, from &enum efx_filter_flags
|
||||
* @rss_context: RSS context to use, if %EFX_FILTER_FLAG_RX_RSS is set. This
|
||||
* is a user_id (with 0 meaning the driver/default RSS context), not an
|
||||
* MCFW context_id.
|
||||
* @dmaq_id: Source/target queue index, or %EFX_FILTER_RX_DMAQ_ID_DROP for
|
||||
* an RX drop filter
|
||||
* @outer_vid: Outer VLAN ID to match, if %EFX_FILTER_MATCH_OUTER_VID is set
|
||||
* @inner_vid: Inner VLAN ID to match, if %EFX_FILTER_MATCH_INNER_VID is set
|
||||
* @loc_mac: Local MAC address to match, if %EFX_FILTER_MATCH_LOC_MAC or
|
||||
* %EFX_FILTER_MATCH_LOC_MAC_IG is set
|
||||
* @rem_mac: Remote MAC address to match, if %EFX_FILTER_MATCH_REM_MAC is set
|
||||
* @ether_type: Ether-type to match, if %EFX_FILTER_MATCH_ETHER_TYPE is set
|
||||
* @ip_proto: IP transport protocol to match, if %EFX_FILTER_MATCH_IP_PROTO
|
||||
* is set
|
||||
* @loc_host: Local IP host to match, if %EFX_FILTER_MATCH_LOC_HOST is set
|
||||
* @rem_host: Remote IP host to match, if %EFX_FILTER_MATCH_REM_HOST is set
|
||||
* @loc_port: Local TCP/UDP port to match, if %EFX_FILTER_MATCH_LOC_PORT is set
|
||||
* @rem_port: Remote TCP/UDP port to match, if %EFX_FILTER_MATCH_REM_PORT is set
|
||||
* @encap_type: Encapsulation type to match (from &enum efx_encap_type), if
|
||||
* %EFX_FILTER_MATCH_ENCAP_TYPE is set
|
||||
*
|
||||
* The efx_filter_init_rx() or efx_filter_init_tx() function *must* be
|
||||
* used to initialise the structure. The efx_filter_set_*() functions
|
||||
* may then be used to set @rss_context, @match_flags and related
|
||||
* fields.
|
||||
*
|
||||
* The @priority field is used by software to determine whether a new
|
||||
* filter may replace an old one. The hardware priority of a filter
|
||||
* depends on which fields are matched.
|
||||
*/
|
||||
struct efx_filter_spec {
|
||||
u32 match_flags:12;
|
||||
u32 priority:2;
|
||||
u32 flags:6;
|
||||
u32 dmaq_id:12;
|
||||
u32 rss_context;
|
||||
__be16 outer_vid __aligned(4); /* allow jhash2() of match values */
|
||||
__be16 inner_vid;
|
||||
u8 loc_mac[ETH_ALEN];
|
||||
u8 rem_mac[ETH_ALEN];
|
||||
__be16 ether_type;
|
||||
u8 ip_proto;
|
||||
__be32 loc_host[4];
|
||||
__be32 rem_host[4];
|
||||
__be16 loc_port;
|
||||
__be16 rem_port;
|
||||
u32 encap_type:4;
|
||||
/* total 65 bytes */
|
||||
};
|
||||
|
||||
enum {
|
||||
EFX_FILTER_RX_DMAQ_ID_DROP = 0xfff
|
||||
};
|
||||
|
||||
static inline void efx_filter_init_rx(struct efx_filter_spec *spec,
|
||||
enum efx_filter_priority priority,
|
||||
enum efx_filter_flags flags,
|
||||
unsigned rxq_id)
|
||||
{
|
||||
memset(spec, 0, sizeof(*spec));
|
||||
spec->priority = priority;
|
||||
spec->flags = EFX_FILTER_FLAG_RX | flags;
|
||||
spec->rss_context = 0;
|
||||
spec->dmaq_id = rxq_id;
|
||||
}
|
||||
|
||||
static inline void efx_filter_init_tx(struct efx_filter_spec *spec,
|
||||
unsigned txq_id)
|
||||
{
|
||||
memset(spec, 0, sizeof(*spec));
|
||||
spec->priority = EFX_FILTER_PRI_REQUIRED;
|
||||
spec->flags = EFX_FILTER_FLAG_TX;
|
||||
spec->dmaq_id = txq_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* efx_filter_set_ipv4_local - specify IPv4 host, transport protocol and port
|
||||
* @spec: Specification to initialise
|
||||
* @proto: Transport layer protocol number
|
||||
* @host: Local host address (network byte order)
|
||||
* @port: Local port (network byte order)
|
||||
*/
|
||||
static inline int
|
||||
efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto,
|
||||
__be32 host, __be16 port)
|
||||
{
|
||||
spec->match_flags |=
|
||||
EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
|
||||
EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
|
||||
spec->ether_type = htons(ETH_P_IP);
|
||||
spec->ip_proto = proto;
|
||||
spec->loc_host[0] = host;
|
||||
spec->loc_port = port;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* efx_filter_set_ipv4_full - specify IPv4 hosts, transport protocol and ports
|
||||
* @spec: Specification to initialise
|
||||
* @proto: Transport layer protocol number
|
||||
* @lhost: Local host address (network byte order)
|
||||
* @lport: Local port (network byte order)
|
||||
* @rhost: Remote host address (network byte order)
|
||||
* @rport: Remote port (network byte order)
|
||||
*/
|
||||
static inline int
|
||||
efx_filter_set_ipv4_full(struct efx_filter_spec *spec, u8 proto,
|
||||
__be32 lhost, __be16 lport,
|
||||
__be32 rhost, __be16 rport)
|
||||
{
|
||||
spec->match_flags |=
|
||||
EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
|
||||
EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
|
||||
EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
|
||||
spec->ether_type = htons(ETH_P_IP);
|
||||
spec->ip_proto = proto;
|
||||
spec->loc_host[0] = lhost;
|
||||
spec->loc_port = lport;
|
||||
spec->rem_host[0] = rhost;
|
||||
spec->rem_port = rport;
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum {
|
||||
EFX_FILTER_VID_UNSPEC = 0xffff,
|
||||
};
|
||||
|
||||
/**
|
||||
* efx_filter_set_eth_local - specify local Ethernet address and/or VID
|
||||
* @spec: Specification to initialise
|
||||
* @vid: Outer VLAN ID to match, or %EFX_FILTER_VID_UNSPEC
|
||||
* @addr: Local Ethernet MAC address, or %NULL
|
||||
*/
|
||||
static inline int efx_filter_set_eth_local(struct efx_filter_spec *spec,
|
||||
u16 vid, const u8 *addr)
|
||||
{
|
||||
if (vid == EFX_FILTER_VID_UNSPEC && addr == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (vid != EFX_FILTER_VID_UNSPEC) {
|
||||
spec->match_flags |= EFX_FILTER_MATCH_OUTER_VID;
|
||||
spec->outer_vid = htons(vid);
|
||||
}
|
||||
if (addr != NULL) {
|
||||
spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC;
|
||||
ether_addr_copy(spec->loc_mac, addr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* efx_filter_set_uc_def - specify matching otherwise-unmatched unicast
|
||||
* @spec: Specification to initialise
|
||||
*/
|
||||
static inline int efx_filter_set_uc_def(struct efx_filter_spec *spec)
|
||||
{
|
||||
spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* efx_filter_set_mc_def - specify matching otherwise-unmatched multicast
|
||||
* @spec: Specification to initialise
|
||||
*/
|
||||
static inline int efx_filter_set_mc_def(struct efx_filter_spec *spec)
|
||||
{
|
||||
spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
|
||||
spec->loc_mac[0] = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void efx_filter_set_encap_type(struct efx_filter_spec *spec,
|
||||
enum efx_encap_type encap_type)
|
||||
{
|
||||
spec->match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
|
||||
spec->encap_type = encap_type;
|
||||
}
|
||||
|
||||
static inline enum efx_encap_type efx_filter_get_encap_type(
|
||||
const struct efx_filter_spec *spec)
|
||||
{
|
||||
if (spec->match_flags & EFX_FILTER_MATCH_ENCAP_TYPE)
|
||||
return spec->encap_type;
|
||||
return EFX_ENCAP_TYPE_NONE;
|
||||
}
|
||||
#endif /* EFX_FILTER_H */
|
|
@ -0,0 +1,310 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/****************************************************************************
|
||||
* Driver for Solarflare network controllers and boards
|
||||
* Copyright 2005-2006 Fen Systems Ltd.
|
||||
* Copyright 2006-2013 Solarflare Communications Inc.
|
||||
*/
|
||||
|
||||
#ifndef EFX_IO_H
|
||||
#define EFX_IO_H
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NIC register I/O
|
||||
*
|
||||
**************************************************************************
|
||||
*
|
||||
* Notes on locking strategy for the Falcon architecture:
|
||||
*
|
||||
* Many CSRs are very wide and cannot be read or written atomically.
|
||||
* Writes from the host are buffered by the Bus Interface Unit (BIU)
|
||||
* up to 128 bits. Whenever the host writes part of such a register,
|
||||
* the BIU collects the written value and does not write to the
|
||||
* underlying register until all 4 dwords have been written. A
|
||||
* similar buffering scheme applies to host access to the NIC's 64-bit
|
||||
* SRAM.
|
||||
*
|
||||
* Writes to different CSRs and 64-bit SRAM words must be serialised,
|
||||
* since interleaved access can result in lost writes. We use
|
||||
* efx_nic::biu_lock for this.
|
||||
*
|
||||
* We also serialise reads from 128-bit CSRs and SRAM with the same
|
||||
* spinlock. This may not be necessary, but it doesn't really matter
|
||||
* as there are no such reads on the fast path.
|
||||
*
|
||||
* The DMA descriptor pointers (RX_DESC_UPD and TX_DESC_UPD) are
|
||||
* 128-bit but are special-cased in the BIU to avoid the need for
|
||||
* locking in the host:
|
||||
*
|
||||
* - They are write-only.
|
||||
* - The semantics of writing to these registers are such that
|
||||
* replacing the low 96 bits with zero does not affect functionality.
|
||||
* - If the host writes to the last dword address of such a register
|
||||
* (i.e. the high 32 bits) the underlying register will always be
|
||||
* written. If the collector and the current write together do not
|
||||
* provide values for all 128 bits of the register, the low 96 bits
|
||||
* will be written as zero.
|
||||
* - If the host writes to the address of any other part of such a
|
||||
* register while the collector already holds values for some other
|
||||
* register, the write is discarded and the collector maintains its
|
||||
* current state.
|
||||
*
|
||||
* The EF10 architecture exposes very few registers to the host and
|
||||
* most of them are only 32 bits wide. The only exceptions are the MC
|
||||
* doorbell register pair, which has its own latching, and
|
||||
* TX_DESC_UPD, which works in a similar way to the Falcon
|
||||
* architecture.
|
||||
*/
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
#define EFX_USE_QWORD_IO 1
|
||||
#endif
|
||||
|
||||
/* Hardware issue requires that only 64-bit naturally aligned writes
|
||||
* are seen by hardware. Its not strictly necessary to restrict to
|
||||
* x86_64 arch, but done for safety since unusual write combining behaviour
|
||||
* can break PIO.
|
||||
*/
|
||||
#ifdef CONFIG_X86_64
|
||||
/* PIO is a win only if write-combining is possible */
|
||||
#ifdef ARCH_HAS_IOREMAP_WC
|
||||
#define EFX_USE_PIO 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static inline u32 efx_reg(struct efx_nic *efx, unsigned int reg)
|
||||
{
|
||||
return efx->reg_base + reg;
|
||||
}
|
||||
|
||||
#ifdef EFX_USE_QWORD_IO
|
||||
static inline void _efx_writeq(struct efx_nic *efx, __le64 value,
|
||||
unsigned int reg)
|
||||
{
|
||||
__raw_writeq((__force u64)value, efx->membase + reg);
|
||||
}
|
||||
static inline __le64 _efx_readq(struct efx_nic *efx, unsigned int reg)
|
||||
{
|
||||
return (__force __le64)__raw_readq(efx->membase + reg);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void _efx_writed(struct efx_nic *efx, __le32 value,
|
||||
unsigned int reg)
|
||||
{
|
||||
__raw_writel((__force u32)value, efx->membase + reg);
|
||||
}
|
||||
static inline __le32 _efx_readd(struct efx_nic *efx, unsigned int reg)
|
||||
{
|
||||
return (__force __le32)__raw_readl(efx->membase + reg);
|
||||
}
|
||||
|
||||
/* Write a normal 128-bit CSR, locking as appropriate. */
|
||||
static inline void efx_writeo(struct efx_nic *efx, const efx_oword_t *value,
|
||||
unsigned int reg)
|
||||
{
|
||||
unsigned long flags __attribute__ ((unused));
|
||||
|
||||
netif_vdbg(efx, hw, efx->net_dev,
|
||||
"writing register %x with " EFX_OWORD_FMT "\n", reg,
|
||||
EFX_OWORD_VAL(*value));
|
||||
|
||||
spin_lock_irqsave(&efx->biu_lock, flags);
|
||||
#ifdef EFX_USE_QWORD_IO
|
||||
_efx_writeq(efx, value->u64[0], reg + 0);
|
||||
_efx_writeq(efx, value->u64[1], reg + 8);
|
||||
#else
|
||||
_efx_writed(efx, value->u32[0], reg + 0);
|
||||
_efx_writed(efx, value->u32[1], reg + 4);
|
||||
_efx_writed(efx, value->u32[2], reg + 8);
|
||||
_efx_writed(efx, value->u32[3], reg + 12);
|
||||
#endif
|
||||
spin_unlock_irqrestore(&efx->biu_lock, flags);
|
||||
}
|
||||
|
||||
/* Write 64-bit SRAM through the supplied mapping, locking as appropriate. */
|
||||
static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase,
|
||||
const efx_qword_t *value, unsigned int index)
|
||||
{
|
||||
unsigned int addr = index * sizeof(*value);
|
||||
unsigned long flags __attribute__ ((unused));
|
||||
|
||||
netif_vdbg(efx, hw, efx->net_dev,
|
||||
"writing SRAM address %x with " EFX_QWORD_FMT "\n",
|
||||
addr, EFX_QWORD_VAL(*value));
|
||||
|
||||
spin_lock_irqsave(&efx->biu_lock, flags);
|
||||
#ifdef EFX_USE_QWORD_IO
|
||||
__raw_writeq((__force u64)value->u64[0], membase + addr);
|
||||
#else
|
||||
__raw_writel((__force u32)value->u32[0], membase + addr);
|
||||
__raw_writel((__force u32)value->u32[1], membase + addr + 4);
|
||||
#endif
|
||||
spin_unlock_irqrestore(&efx->biu_lock, flags);
|
||||
}
|
||||
|
||||
/* Write a 32-bit CSR or the last dword of a special 128-bit CSR */
|
||||
static inline void efx_writed(struct efx_nic *efx, const efx_dword_t *value,
|
||||
unsigned int reg)
|
||||
{
|
||||
netif_vdbg(efx, hw, efx->net_dev,
|
||||
"writing register %x with "EFX_DWORD_FMT"\n",
|
||||
reg, EFX_DWORD_VAL(*value));
|
||||
|
||||
/* No lock required */
|
||||
_efx_writed(efx, value->u32[0], reg);
|
||||
}
|
||||
|
||||
/* Read a 128-bit CSR, locking as appropriate. */
|
||||
static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value,
|
||||
unsigned int reg)
|
||||
{
|
||||
unsigned long flags __attribute__ ((unused));
|
||||
|
||||
spin_lock_irqsave(&efx->biu_lock, flags);
|
||||
value->u32[0] = _efx_readd(efx, reg + 0);
|
||||
value->u32[1] = _efx_readd(efx, reg + 4);
|
||||
value->u32[2] = _efx_readd(efx, reg + 8);
|
||||
value->u32[3] = _efx_readd(efx, reg + 12);
|
||||
spin_unlock_irqrestore(&efx->biu_lock, flags);
|
||||
|
||||
netif_vdbg(efx, hw, efx->net_dev,
|
||||
"read from register %x, got " EFX_OWORD_FMT "\n", reg,
|
||||
EFX_OWORD_VAL(*value));
|
||||
}
|
||||
|
||||
/* Read 64-bit SRAM through the supplied mapping, locking as appropriate. */
|
||||
static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase,
|
||||
efx_qword_t *value, unsigned int index)
|
||||
{
|
||||
unsigned int addr = index * sizeof(*value);
|
||||
unsigned long flags __attribute__ ((unused));
|
||||
|
||||
spin_lock_irqsave(&efx->biu_lock, flags);
|
||||
#ifdef EFX_USE_QWORD_IO
|
||||
value->u64[0] = (__force __le64)__raw_readq(membase + addr);
|
||||
#else
|
||||
value->u32[0] = (__force __le32)__raw_readl(membase + addr);
|
||||
value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4);
|
||||
#endif
|
||||
spin_unlock_irqrestore(&efx->biu_lock, flags);
|
||||
|
||||
netif_vdbg(efx, hw, efx->net_dev,
|
||||
"read from SRAM address %x, got "EFX_QWORD_FMT"\n",
|
||||
addr, EFX_QWORD_VAL(*value));
|
||||
}
|
||||
|
||||
/* Read a 32-bit CSR or SRAM */
|
||||
static inline void efx_readd(struct efx_nic *efx, efx_dword_t *value,
|
||||
unsigned int reg)
|
||||
{
|
||||
value->u32[0] = _efx_readd(efx, reg);
|
||||
netif_vdbg(efx, hw, efx->net_dev,
|
||||
"read from register %x, got "EFX_DWORD_FMT"\n",
|
||||
reg, EFX_DWORD_VAL(*value));
|
||||
}
|
||||
|
||||
/* Write a 128-bit CSR forming part of a table */
|
||||
static inline void
|
||||
efx_writeo_table(struct efx_nic *efx, const efx_oword_t *value,
|
||||
unsigned int reg, unsigned int index)
|
||||
{
|
||||
efx_writeo(efx, value, reg + index * sizeof(efx_oword_t));
|
||||
}
|
||||
|
||||
/* Read a 128-bit CSR forming part of a table */
|
||||
static inline void efx_reado_table(struct efx_nic *efx, efx_oword_t *value,
|
||||
unsigned int reg, unsigned int index)
|
||||
{
|
||||
efx_reado(efx, value, reg + index * sizeof(efx_oword_t));
|
||||
}
|
||||
|
||||
/* default VI stride (step between per-VI registers) is 8K on EF10 and
|
||||
* 64K on EF100
|
||||
*/
|
||||
#define EFX_DEFAULT_VI_STRIDE 0x2000
|
||||
#define EF100_DEFAULT_VI_STRIDE 0x10000
|
||||
|
||||
/* Calculate offset to page-mapped register */
|
||||
static inline unsigned int efx_paged_reg(struct efx_nic *efx, unsigned int page,
|
||||
unsigned int reg)
|
||||
{
|
||||
return page * efx->vi_stride + reg;
|
||||
}
|
||||
|
||||
/* Write the whole of RX_DESC_UPD or TX_DESC_UPD */
|
||||
static inline void _efx_writeo_page(struct efx_nic *efx, efx_oword_t *value,
|
||||
unsigned int reg, unsigned int page)
|
||||
{
|
||||
reg = efx_paged_reg(efx, page, reg);
|
||||
|
||||
netif_vdbg(efx, hw, efx->net_dev,
|
||||
"writing register %x with " EFX_OWORD_FMT "\n", reg,
|
||||
EFX_OWORD_VAL(*value));
|
||||
|
||||
#ifdef EFX_USE_QWORD_IO
|
||||
_efx_writeq(efx, value->u64[0], reg + 0);
|
||||
_efx_writeq(efx, value->u64[1], reg + 8);
|
||||
#else
|
||||
_efx_writed(efx, value->u32[0], reg + 0);
|
||||
_efx_writed(efx, value->u32[1], reg + 4);
|
||||
_efx_writed(efx, value->u32[2], reg + 8);
|
||||
_efx_writed(efx, value->u32[3], reg + 12);
|
||||
#endif
|
||||
}
|
||||
#define efx_writeo_page(efx, value, reg, page) \
|
||||
_efx_writeo_page(efx, value, \
|
||||
reg + \
|
||||
BUILD_BUG_ON_ZERO((reg) != 0x830 && (reg) != 0xa10), \
|
||||
page)
|
||||
|
||||
/* Write a page-mapped 32-bit CSR (EVQ_RPTR, EVQ_TMR (EF10), or the
|
||||
* high bits of RX_DESC_UPD or TX_DESC_UPD)
|
||||
*/
|
||||
static inline void
|
||||
_efx_writed_page(struct efx_nic *efx, const efx_dword_t *value,
|
||||
unsigned int reg, unsigned int page)
|
||||
{
|
||||
efx_writed(efx, value, efx_paged_reg(efx, page, reg));
|
||||
}
|
||||
#define efx_writed_page(efx, value, reg, page) \
|
||||
_efx_writed_page(efx, value, \
|
||||
reg + \
|
||||
BUILD_BUG_ON_ZERO((reg) != 0x180 && \
|
||||
(reg) != 0x200 && \
|
||||
(reg) != 0x400 && \
|
||||
(reg) != 0x420 && \
|
||||
(reg) != 0x830 && \
|
||||
(reg) != 0x83c && \
|
||||
(reg) != 0xa18 && \
|
||||
(reg) != 0xa1c), \
|
||||
page)
|
||||
|
||||
/* Write TIMER_COMMAND. This is a page-mapped 32-bit CSR, but a bug
|
||||
* in the BIU means that writes to TIMER_COMMAND[0] invalidate the
|
||||
* collector register.
|
||||
*/
|
||||
static inline void _efx_writed_page_locked(struct efx_nic *efx,
|
||||
const efx_dword_t *value,
|
||||
unsigned int reg,
|
||||
unsigned int page)
|
||||
{
|
||||
unsigned long flags __attribute__ ((unused));
|
||||
|
||||
if (page == 0) {
|
||||
spin_lock_irqsave(&efx->biu_lock, flags);
|
||||
efx_writed(efx, value, efx_paged_reg(efx, page, reg));
|
||||
spin_unlock_irqrestore(&efx->biu_lock, flags);
|
||||
} else {
|
||||
efx_writed(efx, value, efx_paged_reg(efx, page, reg));
|
||||
}
|
||||
}
|
||||
#define efx_writed_page_locked(efx, value, reg, page) \
|
||||
_efx_writed_page_locked(efx, value, \
|
||||
reg + BUILD_BUG_ON_ZERO((reg) != 0x420), \
|
||||
page)
|
||||
|
||||
#endif /* EFX_IO_H */
|
Loading…
Reference in New Issue