aboutsummaryrefslogtreecommitdiffstats
path: root/target
diff options
context:
space:
mode:
authorHsiuWen Yen <y.hsiuwen@gmail.com>2019-01-23 12:14:19 +0800
committerJohn Crispin <john@phrozen.org>2019-01-23 09:27:30 +0100
commitfe7d965ea95e78905328fe5425c8e90e3bf11e58 (patch)
treedeb2c34c3fb69412f38635919282f3325cadb86a /target
parent45a2771953fb351879c332105c8d270c6daed0a7 (diff)
downloadupstream-fe7d965ea95e78905328fe5425c8e90e3bf11e58.tar.gz
upstream-fe7d965ea95e78905328fe5425c8e90e3bf11e58.tar.bz2
upstream-fe7d965ea95e78905328fe5425c8e90e3bf11e58.zip
ramips: fix two-way hash and auto ageout on MT7621
Current code directly writes the FOE entry to hash_val+1 position when hash collision occurs. However, it is found that this behavior will cause the cache and the hardware FOE table to be inconsistent. For example, there are three flows, and their hashed values are all equal to 100. The first flow is written to the position of 100. The second flow is written to the position of 100+1. Then, the logic of the current code will also write the third flow to 100+1. At this time, the cache has flow 1 and 2; and the hardware FOE table has flow 1 and 3, where these two parts store different contents. So it is necessary to check whether the hash_val+1 is also occupied before writing. If hash_val+1 is also occupied, we won’t bind th third flow to the FOE table. Addition to that, we also cancel the processing of foe_entry removal because the hardware has auto age-out ability. The hardware will periodically iterate through the FOE table to find out the time-out entry and set it as INVALID. Signed-off-by: HsiuWen Yen <y.hsiuwen@gmail.com>
Diffstat (limited to 'target')
-rw-r--r--target/linux/ramips/files-4.14/drivers/net/ethernet/mediatek/mtk_offload.c35
1 files changed, 18 insertions, 17 deletions
diff --git a/target/linux/ramips/files-4.14/drivers/net/ethernet/mediatek/mtk_offload.c b/target/linux/ramips/files-4.14/drivers/net/ethernet/mediatek/mtk_offload.c
index 6e814ad72e..5f9e6a6b07 100644
--- a/target/linux/ramips/files-4.14/drivers/net/ethernet/mediatek/mtk_offload.c
+++ b/target/linux/ramips/files-4.14/drivers/net/ethernet/mediatek/mtk_offload.c
@@ -119,11 +119,11 @@ mtk_foe_set_mac(struct mtk_foe_entry *entry, u8 *smac, u8 *dmac)
}
static int
-mtk_check_hashcollision(struct mtk_eth *eth, u32 hash)
+mtk_check_entry_available(struct mtk_eth *eth, u32 hash)
{
struct mtk_foe_entry entry = ((struct mtk_foe_entry *)eth->foe_table)[hash];
- return (entry.bfib1.state != BIND)? 0:1;
+ return (entry.bfib1.state == BIND)? 0:1;
}
static void
@@ -156,6 +156,12 @@ int mtk_flow_offload(struct mtk_eth *eth,
if (otuple->l4proto != IPPROTO_TCP && otuple->l4proto != IPPROTO_UDP)
return -EINVAL;
+
+ if (type == FLOW_OFFLOAD_DEL) {
+ flow = NULL;
+ synchronize_rcu();
+ return 0;
+ }
switch (otuple->l3proto) {
case AF_INET:
@@ -174,30 +180,25 @@ int mtk_flow_offload(struct mtk_eth *eth,
return -EINVAL;
}
- if (type == FLOW_OFFLOAD_DEL) {
- orig.bfib1.state = INVALID;
- reply.bfib1.state = INVALID;
- flow = NULL;
- goto write;
+ /* Two-way hash: when hash collision occurs, the hash value will be shifted to the next position. */
+ if (!mtk_check_entry_available(eth, ohash)){
+ if (!mtk_check_entry_available(eth, ohash + 1))
+ return -EINVAL;
+ ohash += 1;
+ }
+ if (!mtk_check_entry_available(eth, rhash)){
+ if (!mtk_check_entry_available(eth, rhash + 1))
+ return -EINVAL;
+ rhash += 1;
}
- /* Two-way hash: when hash collision occurs, the hash value will be shifted to the next position. */
- if(mtk_check_hashcollision(eth, ohash))
- ohash += 1;
- if(mtk_check_hashcollision(eth, rhash))
- rhash += 1;
mtk_foe_set_mac(&orig, dest->eth_src, dest->eth_dest);
mtk_foe_set_mac(&reply, src->eth_src, src->eth_dest);
-
-write:
mtk_foe_write(eth, ohash, &orig);
mtk_foe_write(eth, rhash, &reply);
rcu_assign_pointer(eth->foe_flow_table[ohash], flow);
rcu_assign_pointer(eth->foe_flow_table[rhash], flow);
- if (type == FLOW_OFFLOAD_DEL)
- synchronize_rcu();
-
return 0;
}