|
@@ -1003,7 +1003,7 @@ s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw)
|
|
udelay(10);
|
|
udelay(10);
|
|
}
|
|
}
|
|
if (i >= IXGBE_FDIRCMD_CMD_POLL) {
|
|
if (i >= IXGBE_FDIRCMD_CMD_POLL) {
|
|
- hw_dbg(hw ,"Flow Director previous command isn't complete, "
|
|
|
|
|
|
+ hw_dbg(hw, "Flow Director previous command isn't complete, "
|
|
"aborting table re-initialization.\n");
|
|
"aborting table re-initialization.\n");
|
|
return IXGBE_ERR_FDIR_REINIT_FAILED;
|
|
return IXGBE_ERR_FDIR_REINIT_FAILED;
|
|
}
|
|
}
|
|
@@ -1113,13 +1113,10 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc)
|
|
/* Move the flexible bytes to use the ethertype - shift 6 words */
|
|
/* Move the flexible bytes to use the ethertype - shift 6 words */
|
|
fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT);
|
|
fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT);
|
|
|
|
|
|
- fdirctrl |= IXGBE_FDIRCTRL_REPORT_STATUS;
|
|
|
|
|
|
|
|
/* Prime the keys for hashing */
|
|
/* Prime the keys for hashing */
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY,
|
|
|
|
- htonl(IXGBE_ATR_BUCKET_HASH_KEY));
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY,
|
|
|
|
- htonl(IXGBE_ATR_SIGNATURE_HASH_KEY));
|
|
|
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY, IXGBE_ATR_BUCKET_HASH_KEY);
|
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY, IXGBE_ATR_SIGNATURE_HASH_KEY);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Poll init-done after we write the register. Estimated times:
|
|
* Poll init-done after we write the register. Estimated times:
|
|
@@ -1209,10 +1206,8 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc)
|
|
fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT);
|
|
fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT);
|
|
|
|
|
|
/* Prime the keys for hashing */
|
|
/* Prime the keys for hashing */
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY,
|
|
|
|
- htonl(IXGBE_ATR_BUCKET_HASH_KEY));
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY,
|
|
|
|
- htonl(IXGBE_ATR_SIGNATURE_HASH_KEY));
|
|
|
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY, IXGBE_ATR_BUCKET_HASH_KEY);
|
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY, IXGBE_ATR_SIGNATURE_HASH_KEY);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Poll init-done after we write the register. Estimated times:
|
|
* Poll init-done after we write the register. Estimated times:
|
|
@@ -1251,8 +1246,8 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc)
|
|
* @stream: input bitstream to compute the hash on
|
|
* @stream: input bitstream to compute the hash on
|
|
* @key: 32-bit hash key
|
|
* @key: 32-bit hash key
|
|
**/
|
|
**/
|
|
-static u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input,
|
|
|
|
- u32 key)
|
|
|
|
|
|
+static u32 ixgbe_atr_compute_hash_82599(union ixgbe_atr_input *atr_input,
|
|
|
|
+ u32 key)
|
|
{
|
|
{
|
|
/*
|
|
/*
|
|
* The algorithm is as follows:
|
|
* The algorithm is as follows:
|
|
@@ -1272,409 +1267,249 @@ static u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input,
|
|
* To simplify for programming, the algorithm is implemented
|
|
* To simplify for programming, the algorithm is implemented
|
|
* in software this way:
|
|
* in software this way:
|
|
*
|
|
*
|
|
- * Key[31:0], Stream[335:0]
|
|
|
|
|
|
+ * key[31:0], hi_hash_dword[31:0], lo_hash_dword[31:0], hash[15:0]
|
|
|
|
+ *
|
|
|
|
+ * for (i = 0; i < 352; i+=32)
|
|
|
|
+ * hi_hash_dword[31:0] ^= Stream[(i+31):i];
|
|
|
|
+ *
|
|
|
|
+ * lo_hash_dword[15:0] ^= Stream[15:0];
|
|
|
|
+ * lo_hash_dword[15:0] ^= hi_hash_dword[31:16];
|
|
|
|
+ * lo_hash_dword[31:16] ^= hi_hash_dword[15:0];
|
|
*
|
|
*
|
|
- * tmp_key[11 * 32 - 1:0] = 11{Key[31:0] = key concatenated 11 times
|
|
|
|
- * int_key[350:0] = tmp_key[351:1]
|
|
|
|
- * int_stream[365:0] = Stream[14:0] | Stream[335:0] | Stream[335:321]
|
|
|
|
|
|
+ * hi_hash_dword[31:0] ^= Stream[351:320];
|
|
*
|
|
*
|
|
- * hash[15:0] = 0;
|
|
|
|
- * for (i = 0; i < 351; i++) {
|
|
|
|
- * if (int_key[i])
|
|
|
|
- * hash ^= int_stream[(i + 15):i];
|
|
|
|
|
|
+ * if(key[0])
|
|
|
|
+ * hash[15:0] ^= Stream[15:0];
|
|
|
|
+ *
|
|
|
|
+ * for (i = 0; i < 16; i++) {
|
|
|
|
+ * if (key[i])
|
|
|
|
+ * hash[15:0] ^= lo_hash_dword[(i+15):i];
|
|
|
|
+ * if (key[i + 16])
|
|
|
|
+ * hash[15:0] ^= hi_hash_dword[(i+15):i];
|
|
* }
|
|
* }
|
|
|
|
+ *
|
|
*/
|
|
*/
|
|
|
|
+ __be32 common_hash_dword = 0;
|
|
|
|
+ u32 hi_hash_dword, lo_hash_dword, flow_vm_vlan;
|
|
|
|
+ u32 hash_result = 0;
|
|
|
|
+ u8 i;
|
|
|
|
|
|
- union {
|
|
|
|
- u64 fill[6];
|
|
|
|
- u32 key[11];
|
|
|
|
- u8 key_stream[44];
|
|
|
|
- } tmp_key;
|
|
|
|
|
|
+ /* record the flow_vm_vlan bits as they are a key part to the hash */
|
|
|
|
+ flow_vm_vlan = ntohl(atr_input->dword_stream[0]);
|
|
|
|
|
|
- u8 *stream = (u8 *)atr_input;
|
|
|
|
- u8 int_key[44]; /* upper-most bit unused */
|
|
|
|
- u8 hash_str[46]; /* upper-most 2 bits unused */
|
|
|
|
- u16 hash_result = 0;
|
|
|
|
- int i, j, k, h;
|
|
|
|
|
|
+ /* generate common hash dword */
|
|
|
|
+ for (i = 10; i; i -= 2)
|
|
|
|
+ common_hash_dword ^= atr_input->dword_stream[i] ^
|
|
|
|
+ atr_input->dword_stream[i - 1];
|
|
|
|
|
|
- /*
|
|
|
|
- * Initialize the fill member to prevent warnings
|
|
|
|
- * on some compilers
|
|
|
|
- */
|
|
|
|
- tmp_key.fill[0] = 0;
|
|
|
|
|
|
+ hi_hash_dword = ntohl(common_hash_dword);
|
|
|
|
|
|
- /* First load the temporary key stream */
|
|
|
|
- for (i = 0; i < 6; i++) {
|
|
|
|
- u64 fillkey = ((u64)key << 32) | key;
|
|
|
|
- tmp_key.fill[i] = fillkey;
|
|
|
|
- }
|
|
|
|
|
|
+ /* low dword is word swapped version of common */
|
|
|
|
+ lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16);
|
|
|
|
|
|
- /*
|
|
|
|
- * Set the interim key for the hashing. Bit 352 is unused, so we must
|
|
|
|
- * shift and compensate when building the key.
|
|
|
|
- */
|
|
|
|
|
|
+ /* apply flow ID/VM pool/VLAN ID bits to hash words */
|
|
|
|
+ hi_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan >> 16);
|
|
|
|
|
|
- int_key[0] = tmp_key.key_stream[0] >> 1;
|
|
|
|
- for (i = 1, j = 0; i < 44; i++) {
|
|
|
|
- unsigned int this_key = tmp_key.key_stream[j] << 7;
|
|
|
|
- j++;
|
|
|
|
- int_key[i] = (u8)(this_key | (tmp_key.key_stream[j] >> 1));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Set the interim bit string for the hashing. Bits 368 and 367 are
|
|
|
|
- * unused, so shift and compensate when building the string.
|
|
|
|
- */
|
|
|
|
- hash_str[0] = (stream[40] & 0x7f) >> 1;
|
|
|
|
- for (i = 1, j = 40; i < 46; i++) {
|
|
|
|
- unsigned int this_str = stream[j] << 7;
|
|
|
|
- j++;
|
|
|
|
- if (j > 41)
|
|
|
|
- j = 0;
|
|
|
|
- hash_str[i] = (u8)(this_str | (stream[j] >> 1));
|
|
|
|
- }
|
|
|
|
|
|
+ /* Process bits 0 and 16 */
|
|
|
|
+ if (key & 0x0001) hash_result ^= lo_hash_dword;
|
|
|
|
+ if (key & 0x00010000) hash_result ^= hi_hash_dword;
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Now compute the hash. i is the index into hash_str, j is into our
|
|
|
|
- * key stream, k is counting the number of bits, and h interates within
|
|
|
|
- * each byte.
|
|
|
|
|
|
+ * apply flow ID/VM pool/VLAN ID bits to lo hash dword, we had to
|
|
|
|
+ * delay this because bit 0 of the stream should not be processed
|
|
|
|
+ * so we do not add the vlan until after bit 0 was processed
|
|
*/
|
|
*/
|
|
- for (i = 45, j = 43, k = 0; k < 351 && i >= 2 && j >= 0; i--, j--) {
|
|
|
|
- for (h = 0; h < 8 && k < 351; h++, k++) {
|
|
|
|
- if (int_key[j] & (1 << h)) {
|
|
|
|
- /*
|
|
|
|
- * Key bit is set, XOR in the current 16-bit
|
|
|
|
- * string. Example of processing:
|
|
|
|
- * h = 0,
|
|
|
|
- * tmp = (hash_str[i - 2] & 0 << 16) |
|
|
|
|
- * (hash_str[i - 1] & 0xff << 8) |
|
|
|
|
- * (hash_str[i] & 0xff >> 0)
|
|
|
|
- * So tmp = hash_str[15 + k:k], since the
|
|
|
|
- * i + 2 clause rolls off the 16-bit value
|
|
|
|
- * h = 7,
|
|
|
|
- * tmp = (hash_str[i - 2] & 0x7f << 9) |
|
|
|
|
- * (hash_str[i - 1] & 0xff << 1) |
|
|
|
|
- * (hash_str[i] & 0x80 >> 7)
|
|
|
|
- */
|
|
|
|
- int tmp = (hash_str[i] >> h);
|
|
|
|
- tmp |= (hash_str[i - 1] << (8 - h));
|
|
|
|
- tmp |= (int)(hash_str[i - 2] & ((1 << h) - 1))
|
|
|
|
- << (16 - h);
|
|
|
|
- hash_result ^= (u16)tmp;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return hash_result;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_set_vlan_id_82599 - Sets the VLAN id in the ATR input stream
|
|
|
|
- * @input: input stream to modify
|
|
|
|
- * @vlan: the VLAN id to load
|
|
|
|
- **/
|
|
|
|
-s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, u16 vlan)
|
|
|
|
-{
|
|
|
|
- input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] = vlan >> 8;
|
|
|
|
- input->byte_stream[IXGBE_ATR_VLAN_OFFSET] = vlan & 0xff;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_set_src_ipv4_82599 - Sets the source IPv4 address
|
|
|
|
- * @input: input stream to modify
|
|
|
|
- * @src_addr: the IP address to load
|
|
|
|
- **/
|
|
|
|
-s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, u32 src_addr)
|
|
|
|
-{
|
|
|
|
- input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 3] = src_addr >> 24;
|
|
|
|
- input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 2] =
|
|
|
|
- (src_addr >> 16) & 0xff;
|
|
|
|
- input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] =
|
|
|
|
- (src_addr >> 8) & 0xff;
|
|
|
|
- input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET] = src_addr & 0xff;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_set_dst_ipv4_82599 - Sets the destination IPv4 address
|
|
|
|
- * @input: input stream to modify
|
|
|
|
- * @dst_addr: the IP address to load
|
|
|
|
- **/
|
|
|
|
-s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr)
|
|
|
|
-{
|
|
|
|
- input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 3] = dst_addr >> 24;
|
|
|
|
- input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 2] =
|
|
|
|
- (dst_addr >> 16) & 0xff;
|
|
|
|
- input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] =
|
|
|
|
- (dst_addr >> 8) & 0xff;
|
|
|
|
- input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET] = dst_addr & 0xff;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
|
|
+ lo_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan << 16);
|
|
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_set_src_port_82599 - Sets the source port
|
|
|
|
- * @input: input stream to modify
|
|
|
|
- * @src_port: the source port to load
|
|
|
|
- **/
|
|
|
|
-s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, u16 src_port)
|
|
|
|
-{
|
|
|
|
- input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1] = src_port >> 8;
|
|
|
|
- input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] = src_port & 0xff;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_set_dst_port_82599 - Sets the destination port
|
|
|
|
- * @input: input stream to modify
|
|
|
|
- * @dst_port: the destination port to load
|
|
|
|
- **/
|
|
|
|
-s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input, u16 dst_port)
|
|
|
|
-{
|
|
|
|
- input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1] = dst_port >> 8;
|
|
|
|
- input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] = dst_port & 0xff;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_set_flex_byte_82599 - Sets the flexible bytes
|
|
|
|
- * @input: input stream to modify
|
|
|
|
- * @flex_bytes: the flexible bytes to load
|
|
|
|
- **/
|
|
|
|
-s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte)
|
|
|
|
-{
|
|
|
|
- input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] = flex_byte >> 8;
|
|
|
|
- input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET] = flex_byte & 0xff;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_set_l4type_82599 - Sets the layer 4 packet type
|
|
|
|
- * @input: input stream to modify
|
|
|
|
- * @l4type: the layer 4 type value to load
|
|
|
|
- **/
|
|
|
|
-s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type)
|
|
|
|
-{
|
|
|
|
- input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET] = l4type;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_get_vlan_id_82599 - Gets the VLAN id from the ATR input stream
|
|
|
|
- * @input: input stream to search
|
|
|
|
- * @vlan: the VLAN id to load
|
|
|
|
- **/
|
|
|
|
-static s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, u16 *vlan)
|
|
|
|
-{
|
|
|
|
- *vlan = input->byte_stream[IXGBE_ATR_VLAN_OFFSET];
|
|
|
|
- *vlan |= input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] << 8;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_get_src_ipv4_82599 - Gets the source IPv4 address
|
|
|
|
- * @input: input stream to search
|
|
|
|
- * @src_addr: the IP address to load
|
|
|
|
- **/
|
|
|
|
-static s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input,
|
|
|
|
- u32 *src_addr)
|
|
|
|
-{
|
|
|
|
- *src_addr = input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET];
|
|
|
|
- *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] << 8;
|
|
|
|
- *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 2] << 16;
|
|
|
|
- *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 3] << 24;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_get_dst_ipv4_82599 - Gets the destination IPv4 address
|
|
|
|
- * @input: input stream to search
|
|
|
|
- * @dst_addr: the IP address to load
|
|
|
|
- **/
|
|
|
|
-static s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input,
|
|
|
|
- u32 *dst_addr)
|
|
|
|
-{
|
|
|
|
- *dst_addr = input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET];
|
|
|
|
- *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] << 8;
|
|
|
|
- *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 2] << 16;
|
|
|
|
- *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 3] << 24;
|
|
|
|
|
|
+ /* process the remaining 30 bits in the key 2 bits at a time */
|
|
|
|
+ for (i = 15; i; i-- ) {
|
|
|
|
+ if (key & (0x0001 << i)) hash_result ^= lo_hash_dword >> i;
|
|
|
|
+ if (key & (0x00010000 << i)) hash_result ^= hi_hash_dword >> i;
|
|
|
|
+ }
|
|
|
|
|
|
- return 0;
|
|
|
|
|
|
+ return hash_result & IXGBE_ATR_HASH_MASK;
|
|
}
|
|
}
|
|
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_get_src_ipv6_82599 - Gets the source IPv6 address
|
|
|
|
- * @input: input stream to search
|
|
|
|
- * @src_addr_1: the first 4 bytes of the IP address to load
|
|
|
|
- * @src_addr_2: the second 4 bytes of the IP address to load
|
|
|
|
- * @src_addr_3: the third 4 bytes of the IP address to load
|
|
|
|
- * @src_addr_4: the fourth 4 bytes of the IP address to load
|
|
|
|
- **/
|
|
|
|
-static s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input,
|
|
|
|
- u32 *src_addr_1, u32 *src_addr_2,
|
|
|
|
- u32 *src_addr_3, u32 *src_addr_4)
|
|
|
|
-{
|
|
|
|
- *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 12];
|
|
|
|
- *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 13] << 8;
|
|
|
|
- *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 14] << 16;
|
|
|
|
- *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 15] << 24;
|
|
|
|
-
|
|
|
|
- *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 8];
|
|
|
|
- *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 9] << 8;
|
|
|
|
- *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 10] << 16;
|
|
|
|
- *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 11] << 24;
|
|
|
|
-
|
|
|
|
- *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 4];
|
|
|
|
- *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 5] << 8;
|
|
|
|
- *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 6] << 16;
|
|
|
|
- *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 7] << 24;
|
|
|
|
-
|
|
|
|
- *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET];
|
|
|
|
- *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] << 8;
|
|
|
|
- *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 2] << 16;
|
|
|
|
- *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 3] << 24;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
|
|
+/*
|
|
|
|
+ * These defines allow us to quickly generate all of the necessary instructions
|
|
|
|
+ * in the function below by simply calling out IXGBE_COMPUTE_SIG_HASH_ITERATION
|
|
|
|
+ * for values 0 through 15
|
|
|
|
+ */
|
|
|
|
+#define IXGBE_ATR_COMMON_HASH_KEY \
|
|
|
|
+ (IXGBE_ATR_BUCKET_HASH_KEY & IXGBE_ATR_SIGNATURE_HASH_KEY)
|
|
|
|
+#define IXGBE_COMPUTE_SIG_HASH_ITERATION(_n) \
|
|
|
|
+do { \
|
|
|
|
+ u32 n = (_n); \
|
|
|
|
+ if (IXGBE_ATR_COMMON_HASH_KEY & (0x01 << n)) \
|
|
|
|
+ common_hash ^= lo_hash_dword >> n; \
|
|
|
|
+ else if (IXGBE_ATR_BUCKET_HASH_KEY & (0x01 << n)) \
|
|
|
|
+ bucket_hash ^= lo_hash_dword >> n; \
|
|
|
|
+ else if (IXGBE_ATR_SIGNATURE_HASH_KEY & (0x01 << n)) \
|
|
|
|
+ sig_hash ^= lo_hash_dword << (16 - n); \
|
|
|
|
+ if (IXGBE_ATR_COMMON_HASH_KEY & (0x01 << (n + 16))) \
|
|
|
|
+ common_hash ^= hi_hash_dword >> n; \
|
|
|
|
+ else if (IXGBE_ATR_BUCKET_HASH_KEY & (0x01 << (n + 16))) \
|
|
|
|
+ bucket_hash ^= hi_hash_dword >> n; \
|
|
|
|
+ else if (IXGBE_ATR_SIGNATURE_HASH_KEY & (0x01 << (n + 16))) \
|
|
|
|
+ sig_hash ^= hi_hash_dword << (16 - n); \
|
|
|
|
+} while (0);
|
|
|
|
|
|
/**
|
|
/**
|
|
- * ixgbe_atr_get_src_port_82599 - Gets the source port
|
|
|
|
- * @input: input stream to modify
|
|
|
|
- * @src_port: the source port to load
|
|
|
|
|
|
+ * ixgbe_atr_compute_sig_hash_82599 - Compute the signature hash
|
|
|
|
+ * @stream: input bitstream to compute the hash on
|
|
*
|
|
*
|
|
- * Even though the input is given in big-endian, the FDIRPORT registers
|
|
|
|
- * expect the ports to be programmed in little-endian. Hence the need to swap
|
|
|
|
- * endianness when retrieving the data. This can be confusing since the
|
|
|
|
- * internal hash engine expects it to be big-endian.
|
|
|
|
|
|
+ * This function is almost identical to the function above but contains
|
|
|
|
+ * several optomizations such as unwinding all of the loops, letting the
|
|
|
|
+ * compiler work out all of the conditional ifs since the keys are static
|
|
|
|
+ * defines, and computing two keys at once since the hashed dword stream
|
|
|
|
+ * will be the same for both keys.
|
|
**/
|
|
**/
|
|
-static s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input,
|
|
|
|
- u16 *src_port)
|
|
|
|
|
|
+static u32 ixgbe_atr_compute_sig_hash_82599(union ixgbe_atr_hash_dword input,
|
|
|
|
+ union ixgbe_atr_hash_dword common)
|
|
{
|
|
{
|
|
- *src_port = input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] << 8;
|
|
|
|
- *src_port |= input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1];
|
|
|
|
|
|
+ u32 hi_hash_dword, lo_hash_dword, flow_vm_vlan;
|
|
|
|
+ u32 sig_hash = 0, bucket_hash = 0, common_hash = 0;
|
|
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
|
|
+ /* record the flow_vm_vlan bits as they are a key part to the hash */
|
|
|
|
+ flow_vm_vlan = ntohl(input.dword);
|
|
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_get_dst_port_82599 - Gets the destination port
|
|
|
|
- * @input: input stream to modify
|
|
|
|
- * @dst_port: the destination port to load
|
|
|
|
- *
|
|
|
|
- * Even though the input is given in big-endian, the FDIRPORT registers
|
|
|
|
- * expect the ports to be programmed in little-endian. Hence the need to swap
|
|
|
|
- * endianness when retrieving the data. This can be confusing since the
|
|
|
|
- * internal hash engine expects it to be big-endian.
|
|
|
|
- **/
|
|
|
|
-static s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input,
|
|
|
|
- u16 *dst_port)
|
|
|
|
-{
|
|
|
|
- *dst_port = input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] << 8;
|
|
|
|
- *dst_port |= input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1];
|
|
|
|
|
|
+ /* generate common hash dword */
|
|
|
|
+ hi_hash_dword = ntohl(common.dword);
|
|
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
|
|
+ /* low dword is word swapped version of common */
|
|
|
|
+ lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16);
|
|
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_get_flex_byte_82599 - Gets the flexible bytes
|
|
|
|
- * @input: input stream to modify
|
|
|
|
- * @flex_bytes: the flexible bytes to load
|
|
|
|
- **/
|
|
|
|
-static s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input,
|
|
|
|
- u16 *flex_byte)
|
|
|
|
-{
|
|
|
|
- *flex_byte = input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET];
|
|
|
|
- *flex_byte |= input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] << 8;
|
|
|
|
|
|
+ /* apply flow ID/VM pool/VLAN ID bits to hash words */
|
|
|
|
+ hi_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan >> 16);
|
|
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
|
|
+ /* Process bits 0 and 16 */
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(0);
|
|
|
|
|
|
-/**
|
|
|
|
- * ixgbe_atr_get_l4type_82599 - Gets the layer 4 packet type
|
|
|
|
- * @input: input stream to modify
|
|
|
|
- * @l4type: the layer 4 type value to load
|
|
|
|
- **/
|
|
|
|
-static s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input,
|
|
|
|
- u8 *l4type)
|
|
|
|
-{
|
|
|
|
- *l4type = input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET];
|
|
|
|
|
|
+ /*
|
|
|
|
+ * apply flow ID/VM pool/VLAN ID bits to lo hash dword, we had to
|
|
|
|
+ * delay this because bit 0 of the stream should not be processed
|
|
|
|
+ * so we do not add the vlan until after bit 0 was processed
|
|
|
|
+ */
|
|
|
|
+ lo_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan << 16);
|
|
|
|
+
|
|
|
|
+ /* Process remaining 30 bit of the key */
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(1);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(2);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(3);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(4);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(5);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(6);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(7);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(8);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(9);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(10);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(11);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(12);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(13);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(14);
|
|
|
|
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(15);
|
|
|
|
+
|
|
|
|
+ /* combine common_hash result with signature and bucket hashes */
|
|
|
|
+ bucket_hash ^= common_hash;
|
|
|
|
+ bucket_hash &= IXGBE_ATR_HASH_MASK;
|
|
|
|
|
|
- return 0;
|
|
|
|
|
|
+ sig_hash ^= common_hash << 16;
|
|
|
|
+ sig_hash &= IXGBE_ATR_HASH_MASK << 16;
|
|
|
|
+
|
|
|
|
+ /* return completed signature hash */
|
|
|
|
+ return sig_hash ^ bucket_hash;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* ixgbe_atr_add_signature_filter_82599 - Adds a signature hash filter
|
|
* ixgbe_atr_add_signature_filter_82599 - Adds a signature hash filter
|
|
* @hw: pointer to hardware structure
|
|
* @hw: pointer to hardware structure
|
|
- * @stream: input bitstream
|
|
|
|
|
|
+ * @input: unique input dword
|
|
|
|
+ * @common: compressed common input dword
|
|
* @queue: queue index to direct traffic to
|
|
* @queue: queue index to direct traffic to
|
|
**/
|
|
**/
|
|
s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
|
|
s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
|
|
- struct ixgbe_atr_input *input,
|
|
|
|
|
|
+ union ixgbe_atr_hash_dword input,
|
|
|
|
+ union ixgbe_atr_hash_dword common,
|
|
u8 queue)
|
|
u8 queue)
|
|
{
|
|
{
|
|
u64 fdirhashcmd;
|
|
u64 fdirhashcmd;
|
|
- u64 fdircmd;
|
|
|
|
- u32 fdirhash;
|
|
|
|
- u16 bucket_hash, sig_hash;
|
|
|
|
- u8 l4type;
|
|
|
|
-
|
|
|
|
- bucket_hash = ixgbe_atr_compute_hash_82599(input,
|
|
|
|
- IXGBE_ATR_BUCKET_HASH_KEY);
|
|
|
|
-
|
|
|
|
- /* bucket_hash is only 15 bits */
|
|
|
|
- bucket_hash &= IXGBE_ATR_HASH_MASK;
|
|
|
|
-
|
|
|
|
- sig_hash = ixgbe_atr_compute_hash_82599(input,
|
|
|
|
- IXGBE_ATR_SIGNATURE_HASH_KEY);
|
|
|
|
-
|
|
|
|
- /* Get the l4type in order to program FDIRCMD properly */
|
|
|
|
- /* lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6 */
|
|
|
|
- ixgbe_atr_get_l4type_82599(input, &l4type);
|
|
|
|
|
|
+ u32 fdircmd;
|
|
|
|
|
|
/*
|
|
/*
|
|
- * The lower 32-bits of fdirhashcmd is for FDIRHASH, the upper 32-bits
|
|
|
|
- * is for FDIRCMD. Then do a 64-bit register write from FDIRHASH.
|
|
|
|
|
|
+ * Get the flow_type in order to program FDIRCMD properly
|
|
|
|
+ * lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6
|
|
*/
|
|
*/
|
|
- fdirhash = sig_hash << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT | bucket_hash;
|
|
|
|
-
|
|
|
|
- fdircmd = (IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE |
|
|
|
|
- IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN);
|
|
|
|
-
|
|
|
|
- switch (l4type & IXGBE_ATR_L4TYPE_MASK) {
|
|
|
|
- case IXGBE_ATR_L4TYPE_TCP:
|
|
|
|
- fdircmd |= IXGBE_FDIRCMD_L4TYPE_TCP;
|
|
|
|
- break;
|
|
|
|
- case IXGBE_ATR_L4TYPE_UDP:
|
|
|
|
- fdircmd |= IXGBE_FDIRCMD_L4TYPE_UDP;
|
|
|
|
- break;
|
|
|
|
- case IXGBE_ATR_L4TYPE_SCTP:
|
|
|
|
- fdircmd |= IXGBE_FDIRCMD_L4TYPE_SCTP;
|
|
|
|
|
|
+ switch (input.formatted.flow_type) {
|
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_TCPV4:
|
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_UDPV4:
|
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_SCTPV4:
|
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_TCPV6:
|
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_UDPV6:
|
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_SCTPV6:
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
- hw_dbg(hw, "Error on l4type input\n");
|
|
|
|
|
|
+ hw_dbg(hw, " Error on flow type input\n");
|
|
return IXGBE_ERR_CONFIG;
|
|
return IXGBE_ERR_CONFIG;
|
|
}
|
|
}
|
|
|
|
|
|
- if (l4type & IXGBE_ATR_L4TYPE_IPV6_MASK)
|
|
|
|
- fdircmd |= IXGBE_FDIRCMD_IPV6;
|
|
|
|
|
|
+ /* configure FDIRCMD register */
|
|
|
|
+ fdircmd = IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE |
|
|
|
|
+ IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN;
|
|
|
|
+ fdircmd |= input.formatted.flow_type << IXGBE_FDIRCMD_FLOW_TYPE_SHIFT;
|
|
|
|
+ fdircmd |= (u32)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT;
|
|
|
|
|
|
- fdircmd |= ((u64)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT);
|
|
|
|
- fdirhashcmd = ((fdircmd << 32) | fdirhash);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * The lower 32-bits of fdirhashcmd is for FDIRHASH, the upper 32-bits
|
|
|
|
+ * is for FDIRCMD. Then do a 64-bit register write from FDIRHASH.
|
|
|
|
+ */
|
|
|
|
+ fdirhashcmd = (u64)fdircmd << 32;
|
|
|
|
+ fdirhashcmd |= ixgbe_atr_compute_sig_hash_82599(input, common);
|
|
|
|
|
|
IXGBE_WRITE_REG64(hw, IXGBE_FDIRHASH, fdirhashcmd);
|
|
IXGBE_WRITE_REG64(hw, IXGBE_FDIRHASH, fdirhashcmd);
|
|
|
|
|
|
|
|
+ hw_dbg(hw, "Tx Queue=%x hash=%x\n", queue, (u32)fdirhashcmd);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * ixgbe_get_fdirtcpm_82599 - generate a tcp port from atr_input_masks
|
|
|
|
+ * @input_mask: mask to be bit swapped
|
|
|
|
+ *
|
|
|
|
+ * The source and destination port masks for flow director are bit swapped
|
|
|
|
+ * in that bit 15 effects bit 0, 14 effects 1, 13, 2 etc. In order to
|
|
|
|
+ * generate a correctly swapped value we need to bit swap the mask and that
|
|
|
|
+ * is what is accomplished by this function.
|
|
|
|
+ **/
|
|
|
|
+static u32 ixgbe_get_fdirtcpm_82599(struct ixgbe_atr_input_masks *input_masks)
|
|
|
|
+{
|
|
|
|
+ u32 mask = ntohs(input_masks->dst_port_mask);
|
|
|
|
+ mask <<= IXGBE_FDIRTCPM_DPORTM_SHIFT;
|
|
|
|
+ mask |= ntohs(input_masks->src_port_mask);
|
|
|
|
+ mask = ((mask & 0x55555555) << 1) | ((mask & 0xAAAAAAAA) >> 1);
|
|
|
|
+ mask = ((mask & 0x33333333) << 2) | ((mask & 0xCCCCCCCC) >> 2);
|
|
|
|
+ mask = ((mask & 0x0F0F0F0F) << 4) | ((mask & 0xF0F0F0F0) >> 4);
|
|
|
|
+ return ((mask & 0x00FF00FF) << 8) | ((mask & 0xFF00FF00) >> 8);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * These two macros are meant to address the fact that we have registers
|
|
|
|
+ * that are either all or in part big-endian. As a result on big-endian
|
|
|
|
+ * systems we will end up byte swapping the value to little-endian before
|
|
|
|
+ * it is byte swapped again and written to the hardware in the original
|
|
|
|
+ * big-endian format.
|
|
|
|
+ */
|
|
|
|
+#define IXGBE_STORE_AS_BE32(_value) \
|
|
|
|
+ (((u32)(_value) >> 24) | (((u32)(_value) & 0x00FF0000) >> 8) | \
|
|
|
|
+ (((u32)(_value) & 0x0000FF00) << 8) | ((u32)(_value) << 24))
|
|
|
|
+
|
|
|
|
+#define IXGBE_WRITE_REG_BE32(a, reg, value) \
|
|
|
|
+ IXGBE_WRITE_REG((a), (reg), IXGBE_STORE_AS_BE32(ntohl(value)))
|
|
|
|
+
|
|
|
|
+#define IXGBE_STORE_AS_BE16(_value) \
|
|
|
|
+ (((u16)(_value) >> 8) | ((u16)(_value) << 8))
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* ixgbe_fdir_add_perfect_filter_82599 - Adds a perfect filter
|
|
* ixgbe_fdir_add_perfect_filter_82599 - Adds a perfect filter
|
|
* @hw: pointer to hardware structure
|
|
* @hw: pointer to hardware structure
|
|
@@ -1687,135 +1522,139 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
|
|
* hardware writes must be protected from one another.
|
|
* hardware writes must be protected from one another.
|
|
**/
|
|
**/
|
|
s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
|
|
s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
|
|
- struct ixgbe_atr_input *input,
|
|
|
|
|
|
+ union ixgbe_atr_input *input,
|
|
struct ixgbe_atr_input_masks *input_masks,
|
|
struct ixgbe_atr_input_masks *input_masks,
|
|
u16 soft_id, u8 queue)
|
|
u16 soft_id, u8 queue)
|
|
{
|
|
{
|
|
- u32 fdircmd = 0;
|
|
|
|
u32 fdirhash;
|
|
u32 fdirhash;
|
|
- u32 src_ipv4 = 0, dst_ipv4 = 0;
|
|
|
|
- u32 src_ipv6_1, src_ipv6_2, src_ipv6_3, src_ipv6_4;
|
|
|
|
- u16 src_port, dst_port, vlan_id, flex_bytes;
|
|
|
|
- u16 bucket_hash;
|
|
|
|
- u8 l4type;
|
|
|
|
- u8 fdirm = 0;
|
|
|
|
-
|
|
|
|
- /* Get our input values */
|
|
|
|
- ixgbe_atr_get_l4type_82599(input, &l4type);
|
|
|
|
|
|
+ u32 fdircmd;
|
|
|
|
+ u32 fdirport, fdirtcpm;
|
|
|
|
+ u32 fdirvlan;
|
|
|
|
+ /* start with VLAN, flex bytes, VM pool, and IPv6 destination masked */
|
|
|
|
+ u32 fdirm = IXGBE_FDIRM_VLANID | IXGBE_FDIRM_VLANP | IXGBE_FDIRM_FLEX |
|
|
|
|
+ IXGBE_FDIRM_POOL | IXGBE_FDIRM_DIPv6;
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Check l4type formatting, and bail out before we touch the hardware
|
|
|
|
|
|
+ * Check flow_type formatting, and bail out before we touch the hardware
|
|
* if there's a configuration issue
|
|
* if there's a configuration issue
|
|
*/
|
|
*/
|
|
- switch (l4type & IXGBE_ATR_L4TYPE_MASK) {
|
|
|
|
- case IXGBE_ATR_L4TYPE_TCP:
|
|
|
|
- fdircmd |= IXGBE_FDIRCMD_L4TYPE_TCP;
|
|
|
|
- break;
|
|
|
|
- case IXGBE_ATR_L4TYPE_UDP:
|
|
|
|
- fdircmd |= IXGBE_FDIRCMD_L4TYPE_UDP;
|
|
|
|
- break;
|
|
|
|
- case IXGBE_ATR_L4TYPE_SCTP:
|
|
|
|
- fdircmd |= IXGBE_FDIRCMD_L4TYPE_SCTP;
|
|
|
|
|
|
+ switch (input->formatted.flow_type) {
|
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_IPV4:
|
|
|
|
+ /* use the L4 protocol mask for raw IPv4/IPv6 traffic */
|
|
|
|
+ fdirm |= IXGBE_FDIRM_L4P;
|
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_SCTPV4:
|
|
|
|
+ if (input_masks->dst_port_mask || input_masks->src_port_mask) {
|
|
|
|
+ hw_dbg(hw, " Error on src/dst port mask\n");
|
|
|
|
+ return IXGBE_ERR_CONFIG;
|
|
|
|
+ }
|
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_TCPV4:
|
|
|
|
+ case IXGBE_ATR_FLOW_TYPE_UDPV4:
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
- hw_dbg(hw, "Error on l4type input\n");
|
|
|
|
|
|
+ hw_dbg(hw, " Error on flow type input\n");
|
|
return IXGBE_ERR_CONFIG;
|
|
return IXGBE_ERR_CONFIG;
|
|
}
|
|
}
|
|
|
|
|
|
- bucket_hash = ixgbe_atr_compute_hash_82599(input,
|
|
|
|
- IXGBE_ATR_BUCKET_HASH_KEY);
|
|
|
|
-
|
|
|
|
- /* bucket_hash is only 15 bits */
|
|
|
|
- bucket_hash &= IXGBE_ATR_HASH_MASK;
|
|
|
|
-
|
|
|
|
- ixgbe_atr_get_vlan_id_82599(input, &vlan_id);
|
|
|
|
- ixgbe_atr_get_src_port_82599(input, &src_port);
|
|
|
|
- ixgbe_atr_get_dst_port_82599(input, &dst_port);
|
|
|
|
- ixgbe_atr_get_flex_byte_82599(input, &flex_bytes);
|
|
|
|
-
|
|
|
|
- fdirhash = soft_id << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT | bucket_hash;
|
|
|
|
-
|
|
|
|
- /* Now figure out if we're IPv4 or IPv6 */
|
|
|
|
- if (l4type & IXGBE_ATR_L4TYPE_IPV6_MASK) {
|
|
|
|
- /* IPv6 */
|
|
|
|
- ixgbe_atr_get_src_ipv6_82599(input, &src_ipv6_1, &src_ipv6_2,
|
|
|
|
- &src_ipv6_3, &src_ipv6_4);
|
|
|
|
-
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(0), src_ipv6_1);
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(1), src_ipv6_2);
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(2), src_ipv6_3);
|
|
|
|
- /* The last 4 bytes is the same register as IPv4 */
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv6_4);
|
|
|
|
-
|
|
|
|
- fdircmd |= IXGBE_FDIRCMD_IPV6;
|
|
|
|
- fdircmd |= IXGBE_FDIRCMD_IPv6DMATCH;
|
|
|
|
- } else {
|
|
|
|
- /* IPv4 */
|
|
|
|
- ixgbe_atr_get_src_ipv4_82599(input, &src_ipv4);
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv4);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ixgbe_atr_get_dst_ipv4_82599(input, &dst_ipv4);
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRIPDA, dst_ipv4);
|
|
|
|
-
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRVLAN, (vlan_id |
|
|
|
|
- (flex_bytes << IXGBE_FDIRVLAN_FLEX_SHIFT)));
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRPORT, (src_port |
|
|
|
|
- (dst_port << IXGBE_FDIRPORT_DESTINATION_SHIFT)));
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
- * Program the relevant mask registers. L4type cannot be
|
|
|
|
- * masked out in this implementation.
|
|
|
|
|
|
+ * Program the relevant mask registers. If src/dst_port or src/dst_addr
|
|
|
|
+ * are zero, then assume a full mask for that field. Also assume that
|
|
|
|
+ * a VLAN of 0 is unspecified, so mask that out as well. L4type
|
|
|
|
+ * cannot be masked out in this implementation.
|
|
*
|
|
*
|
|
* This also assumes IPv4 only. IPv6 masking isn't supported at this
|
|
* This also assumes IPv4 only. IPv6 masking isn't supported at this
|
|
* point in time.
|
|
* point in time.
|
|
*/
|
|
*/
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSIP4M, input_masks->src_ip_mask);
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRDIP4M, input_masks->dst_ip_mask);
|
|
|
|
-
|
|
|
|
- switch (l4type & IXGBE_ATR_L4TYPE_MASK) {
|
|
|
|
- case IXGBE_ATR_L4TYPE_TCP:
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, input_masks->src_port_mask);
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM,
|
|
|
|
- (IXGBE_READ_REG(hw, IXGBE_FDIRTCPM) |
|
|
|
|
- (input_masks->dst_port_mask << 16)));
|
|
|
|
|
|
+
|
|
|
|
+ /* Program FDIRM */
|
|
|
|
+ switch (ntohs(input_masks->vlan_id_mask) & 0xEFFF) {
|
|
|
|
+ case 0xEFFF:
|
|
|
|
+ /* Unmask VLAN ID - bit 0 and fall through to unmask prio */
|
|
|
|
+ fdirm &= ~IXGBE_FDIRM_VLANID;
|
|
|
|
+ case 0xE000:
|
|
|
|
+ /* Unmask VLAN prio - bit 1 */
|
|
|
|
+ fdirm &= ~IXGBE_FDIRM_VLANP;
|
|
break;
|
|
break;
|
|
- case IXGBE_ATR_L4TYPE_UDP:
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, input_masks->src_port_mask);
|
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM,
|
|
|
|
- (IXGBE_READ_REG(hw, IXGBE_FDIRUDPM) |
|
|
|
|
- (input_masks->src_port_mask << 16)));
|
|
|
|
|
|
+ case 0x0FFF:
|
|
|
|
+ /* Unmask VLAN ID - bit 0 */
|
|
|
|
+ fdirm &= ~IXGBE_FDIRM_VLANID;
|
|
break;
|
|
break;
|
|
- default:
|
|
|
|
- /* this already would have failed above */
|
|
|
|
|
|
+ case 0x0000:
|
|
|
|
+ /* do nothing, vlans already masked */
|
|
break;
|
|
break;
|
|
|
|
+ default:
|
|
|
|
+ hw_dbg(hw, " Error on VLAN mask\n");
|
|
|
|
+ return IXGBE_ERR_CONFIG;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Program the last mask register, FDIRM */
|
|
|
|
- if (input_masks->vlan_id_mask)
|
|
|
|
- /* Mask both VLAN and VLANP - bits 0 and 1 */
|
|
|
|
- fdirm |= 0x3;
|
|
|
|
-
|
|
|
|
- if (input_masks->data_mask)
|
|
|
|
- /* Flex bytes need masking, so mask the whole thing - bit 4 */
|
|
|
|
- fdirm |= 0x10;
|
|
|
|
|
|
+ if (input_masks->flex_mask & 0xFFFF) {
|
|
|
|
+ if ((input_masks->flex_mask & 0xFFFF) != 0xFFFF) {
|
|
|
|
+ hw_dbg(hw, " Error on flexible byte mask\n");
|
|
|
|
+ return IXGBE_ERR_CONFIG;
|
|
|
|
+ }
|
|
|
|
+ /* Unmask Flex Bytes - bit 4 */
|
|
|
|
+ fdirm &= ~IXGBE_FDIRM_FLEX;
|
|
|
|
+ }
|
|
|
|
|
|
/* Now mask VM pool and destination IPv6 - bits 5 and 2 */
|
|
/* Now mask VM pool and destination IPv6 - bits 5 and 2 */
|
|
- fdirm |= 0x24;
|
|
|
|
-
|
|
|
|
IXGBE_WRITE_REG(hw, IXGBE_FDIRM, fdirm);
|
|
IXGBE_WRITE_REG(hw, IXGBE_FDIRM, fdirm);
|
|
|
|
|
|
- fdircmd |= IXGBE_FDIRCMD_CMD_ADD_FLOW;
|
|
|
|
- fdircmd |= IXGBE_FDIRCMD_FILTER_UPDATE;
|
|
|
|
- fdircmd |= IXGBE_FDIRCMD_LAST;
|
|
|
|
- fdircmd |= IXGBE_FDIRCMD_QUEUE_EN;
|
|
|
|
- fdircmd |= queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT;
|
|
|
|
|
|
+ /* store the TCP/UDP port masks, bit reversed from port layout */
|
|
|
|
+ fdirtcpm = ixgbe_get_fdirtcpm_82599(input_masks);
|
|
|
|
+
|
|
|
|
+ /* write both the same so that UDP and TCP use the same mask */
|
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, ~fdirtcpm);
|
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, ~fdirtcpm);
|
|
|
|
+
|
|
|
|
+ /* store source and destination IP masks (big-enian) */
|
|
|
|
+ IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRSIP4M,
|
|
|
|
+ ~input_masks->src_ip_mask[0]);
|
|
|
|
+ IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRDIP4M,
|
|
|
|
+ ~input_masks->dst_ip_mask[0]);
|
|
|
|
+
|
|
|
|
+ /* Apply masks to input data */
|
|
|
|
+ input->formatted.vlan_id &= input_masks->vlan_id_mask;
|
|
|
|
+ input->formatted.flex_bytes &= input_masks->flex_mask;
|
|
|
|
+ input->formatted.src_port &= input_masks->src_port_mask;
|
|
|
|
+ input->formatted.dst_port &= input_masks->dst_port_mask;
|
|
|
|
+ input->formatted.src_ip[0] &= input_masks->src_ip_mask[0];
|
|
|
|
+ input->formatted.dst_ip[0] &= input_masks->dst_ip_mask[0];
|
|
|
|
+
|
|
|
|
+ /* record vlan (little-endian) and flex_bytes(big-endian) */
|
|
|
|
+ fdirvlan =
|
|
|
|
+ IXGBE_STORE_AS_BE16(ntohs(input->formatted.flex_bytes));
|
|
|
|
+ fdirvlan <<= IXGBE_FDIRVLAN_FLEX_SHIFT;
|
|
|
|
+ fdirvlan |= ntohs(input->formatted.vlan_id);
|
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRVLAN, fdirvlan);
|
|
|
|
+
|
|
|
|
+ /* record source and destination port (little-endian)*/
|
|
|
|
+ fdirport = ntohs(input->formatted.dst_port);
|
|
|
|
+ fdirport <<= IXGBE_FDIRPORT_DESTINATION_SHIFT;
|
|
|
|
+ fdirport |= ntohs(input->formatted.src_port);
|
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRPORT, fdirport);
|
|
|
|
+
|
|
|
|
+ /* record the first 32 bits of the destination address (big-endian) */
|
|
|
|
+ IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRIPDA, input->formatted.dst_ip[0]);
|
|
|
|
+
|
|
|
|
+ /* record the source address (big-endian) */
|
|
|
|
+ IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRIPSA, input->formatted.src_ip[0]);
|
|
|
|
+
|
|
|
|
+ /* configure FDIRCMD register */
|
|
|
|
+ fdircmd = IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE |
|
|
|
|
+ IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN;
|
|
|
|
+ fdircmd |= input->formatted.flow_type << IXGBE_FDIRCMD_FLOW_TYPE_SHIFT;
|
|
|
|
+ fdircmd |= (u32)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT;
|
|
|
|
+
|
|
|
|
+ /* we only want the bucket hash so drop the upper 16 bits */
|
|
|
|
+ fdirhash = ixgbe_atr_compute_hash_82599(input,
|
|
|
|
+ IXGBE_ATR_BUCKET_HASH_KEY);
|
|
|
|
+ fdirhash |= soft_id << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT;
|
|
|
|
|
|
IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, fdirhash);
|
|
IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, fdirhash);
|
|
IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, fdircmd);
|
|
IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, fdircmd);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* ixgbe_read_analog_reg8_82599 - Reads 8 bit Omer analog register
|
|
* ixgbe_read_analog_reg8_82599 - Reads 8 bit Omer analog register
|
|
* @hw: pointer to hardware structure
|
|
* @hw: pointer to hardware structure
|