Merge Official Source
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
LINUX_VERSION-5.15 = .114
|
||||
LINUX_KERNEL_HASH-5.15.114 = e981ea5d219f77735bf5a3f7e84a8af578df8ac3e1c4ff1b0649e2b0795277d2
|
||||
LINUX_VERSION-5.15 = .116
|
||||
LINUX_KERNEL_HASH-5.15.116 = f617c9d1bb5326cc93495938f43eb8cb9aea9d2f451e5a99bce2893f296e179a
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/drivers/net/phy/Kconfig
|
||||
+++ b/drivers/net/phy/Kconfig
|
||||
@@ -95,6 +95,10 @@ config IP17XX_PHY
|
||||
@@ -96,6 +96,10 @@ config IP17XX_PHY
|
||||
tristate "Driver for IC+ IP17xx switches"
|
||||
select SWCONFIG
|
||||
|
||||
|
||||
@@ -336,7 +336,7 @@ SVN-Revision: 35130
|
||||
#endif /* _LINUX_TYPES_H */
|
||||
--- a/net/ipv4/af_inet.c
|
||||
+++ b/net/ipv4/af_inet.c
|
||||
@@ -1475,8 +1475,8 @@ struct sk_buff *inet_gro_receive(struct
|
||||
@@ -1477,8 +1477,8 @@ struct sk_buff *inet_gro_receive(struct
|
||||
if (unlikely(ip_fast_csum((u8 *)iph, 5)))
|
||||
goto out_unlock;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
board_config_update
|
||||
|
||||
case "$(board_name)" in
|
||||
comtrend,ar-5381u |\
|
||||
comtrend,ar-5387un)
|
||||
ucidef_set_bridge_device switch
|
||||
ucidef_set_interface_lan "lan1 lan2 lan3 lan4"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
. /lib/functions.sh
|
||||
|
||||
case "$(board_name)" in
|
||||
comtrend,ar-5381u |\
|
||||
comtrend,ar-5387un)
|
||||
mtd fixtrx firmware
|
||||
;;
|
||||
|
||||
190
target/linux/bmips/dts/bcm6328-comtrend-ar-5381u.dts
Normal file
190
target/linux/bmips/dts/bcm6328-comtrend-ar-5381u.dts
Normal file
@@ -0,0 +1,190 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "bcm6328.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Comtrend AR-5381u";
|
||||
compatible = "comtrend,ar-5381u", "brcm,bcm6328";
|
||||
|
||||
aliases {
|
||||
led-boot = &led_power_green;
|
||||
led-failsafe = &led_alarm_red;
|
||||
led-running = &led_power_green;
|
||||
led-upgrade = &led_power_green;
|
||||
};
|
||||
|
||||
keys {
|
||||
compatible = "gpio-keys-polled";
|
||||
poll-interval = <100>;
|
||||
|
||||
reset {
|
||||
label = "reset";
|
||||
gpios = <&gpio 23 GPIO_ACTIVE_LOW>;
|
||||
linux,code = <KEY_RESTART>;
|
||||
debounce-interval = <60>;
|
||||
};
|
||||
};
|
||||
|
||||
bcm43225-sprom {
|
||||
compatible = "brcm,bcma-sprom";
|
||||
|
||||
pci-bus = <1>;
|
||||
pci-dev = <0>;
|
||||
|
||||
nvmem-cells = <&macaddr_cfe_6a0>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
mac-address-increment = <1>;
|
||||
|
||||
brcm,sprom = "brcm/bcm43225-sprom.bin";
|
||||
brcm,sprom-fixups = <97 0xfee5>,
|
||||
<98 0x157c>,
|
||||
<99 0xfae7>,
|
||||
<113 0xfefa>,
|
||||
<114 0x15d6>,
|
||||
<115 0xfaf8>;
|
||||
};
|
||||
};
|
||||
|
||||
&ehci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
ðernet {
|
||||
status = "okay";
|
||||
|
||||
nvmem-cells = <&macaddr_cfe_6a0>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
&hsspi {
|
||||
status = "okay";
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <16666667>;
|
||||
spi-tx-bus-width = <2>;
|
||||
spi-rx-bus-width = <2>;
|
||||
reg = <0>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
cfe: partition@0 {
|
||||
reg = <0x000000 0x010000>;
|
||||
label = "cfe";
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@10000 {
|
||||
compatible = "brcm,bcm963xx-imagetag";
|
||||
reg = <0x010000 0xfe0000>;
|
||||
label = "firmware";
|
||||
};
|
||||
|
||||
partition@ff0000 {
|
||||
reg = <0xff0000 0x010000>;
|
||||
label = "nvram";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&leds {
|
||||
status = "okay";
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_leds>;
|
||||
|
||||
led_alarm_red: led@2 {
|
||||
reg = <2>;
|
||||
active-low;
|
||||
label = "red:alarm";
|
||||
panic-indicator;
|
||||
};
|
||||
|
||||
led@3 {
|
||||
reg = <3>;
|
||||
active-low;
|
||||
label = "green:internet";
|
||||
};
|
||||
|
||||
led_power_green: led@4 {
|
||||
reg = <4>;
|
||||
active-low;
|
||||
label = "green:power";
|
||||
};
|
||||
};
|
||||
|
||||
&ohci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pcie {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pinctrl {
|
||||
pinctrl_leds: leds {
|
||||
function = "led";
|
||||
pins = "gpio2", "gpio3", "gpio4";
|
||||
};
|
||||
};
|
||||
|
||||
&switch0 {
|
||||
ports {
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "lan1";
|
||||
|
||||
phy-handle = <&phy1>;
|
||||
phy-mode = "mii";
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "lan2";
|
||||
|
||||
phy-handle = <&phy2>;
|
||||
phy-mode = "mii";
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "lan3";
|
||||
|
||||
phy-handle = <&phy3>;
|
||||
phy-mode = "mii";
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "lan4";
|
||||
|
||||
phy-handle = <&phy4>;
|
||||
phy-mode = "mii";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usbh {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cfe {
|
||||
compatible = "nvmem-cells";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
macaddr_cfe_6a0: macaddr@6a0 {
|
||||
reg = <0x6a0 0x6>;
|
||||
};
|
||||
};
|
||||
@@ -1,5 +1,18 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
define Device/comtrend_ar-5381u
|
||||
$(Device/bcm63xx-cfe)
|
||||
DEVICE_VENDOR := Comtrend
|
||||
DEVICE_MODEL := AR-5381u
|
||||
CHIP_ID := 6328
|
||||
CFE_BOARD_ID := 96328A-1241N
|
||||
FLASH_MB := 16
|
||||
DEVICE_PACKAGES += $(USB2_PACKAGES) \
|
||||
$(B43_PACKAGES) broadcom-43225-sprom \
|
||||
kmod-leds-bcm6328
|
||||
endef
|
||||
TARGET_DEVICES += comtrend_ar-5381u
|
||||
|
||||
define Device/comtrend_ar-5387un
|
||||
$(Device/bcm63xx-cfe)
|
||||
DEVICE_VENDOR := Comtrend
|
||||
|
||||
@@ -53,7 +53,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
map->format.format_write(map, reg, val);
|
||||
|
||||
trace_regmap_hw_write_start(map, reg, 1);
|
||||
@@ -2346,6 +2349,7 @@ static int _regmap_raw_multi_reg_write(s
|
||||
@@ -2348,6 +2351,7 @@ static int _regmap_raw_multi_reg_write(s
|
||||
unsigned int reg = regs[i].reg;
|
||||
unsigned int val = regs[i].def;
|
||||
trace_regmap_hw_write_start(map, reg, 1);
|
||||
@@ -61,7 +61,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
map->format.format_reg(u8, reg, map->reg_shift);
|
||||
u8 += reg_bytes + pad_bytes;
|
||||
map->format.format_val(u8, val, 0);
|
||||
@@ -2673,6 +2677,7 @@ static int _regmap_raw_read(struct regma
|
||||
@@ -2675,6 +2679,7 @@ static int _regmap_raw_read(struct regma
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
reg >>= map->format.reg_downshift;
|
||||
map->format.format_write(map, reg, val);
|
||||
|
||||
@@ -2349,6 +2353,7 @@ static int _regmap_raw_multi_reg_write(s
|
||||
@@ -2351,6 +2355,7 @@ static int _regmap_raw_multi_reg_write(s
|
||||
unsigned int reg = regs[i].reg;
|
||||
unsigned int val = regs[i].def;
|
||||
trace_regmap_hw_write_start(map, reg, 1);
|
||||
@@ -66,7 +66,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
reg >>= map->format.reg_downshift;
|
||||
map->format.format_reg(u8, reg, map->reg_shift);
|
||||
u8 += reg_bytes + pad_bytes;
|
||||
@@ -2677,6 +2682,7 @@ static int _regmap_raw_read(struct regma
|
||||
@@ -2679,6 +2684,7 @@ static int _regmap_raw_read(struct regma
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
return map->bus->reg_write(map->bus_context, reg, val);
|
||||
}
|
||||
|
||||
@@ -2703,6 +2705,8 @@ static int _regmap_bus_reg_read(void *co
|
||||
@@ -2705,6 +2707,8 @@ static int _regmap_bus_reg_read(void *co
|
||||
{
|
||||
struct regmap *map = context;
|
||||
|
||||
@@ -46,7 +46,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
return map->bus->reg_read(map->bus_context, reg, val);
|
||||
}
|
||||
|
||||
@@ -3078,6 +3082,8 @@ static int _regmap_update_bits(struct re
|
||||
@@ -3080,6 +3084,8 @@ static int _regmap_update_bits(struct re
|
||||
*change = false;
|
||||
|
||||
if (regmap_volatile(map, reg) && map->reg_update_bits) {
|
||||
|
||||
@@ -87,9 +87,9 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
help
|
||||
--- a/net/core/page_pool.c
|
||||
+++ b/net/core/page_pool.c
|
||||
@@ -26,6 +26,13 @@
|
||||
|
||||
#define BIAS_MAX LONG_MAX
|
||||
@@ -49,6 +49,13 @@ static void page_pool_producer_unlock(st
|
||||
spin_unlock_bh(&pool->ring.producer_lock);
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_PAGE_POOL_STATS
|
||||
+/* alloc_stat_inc is intended to be used in softirq context */
|
||||
@@ -101,7 +101,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
static int page_pool_init(struct page_pool *pool,
|
||||
const struct page_pool_params *params)
|
||||
{
|
||||
@@ -117,8 +124,10 @@ static struct page *page_pool_refill_all
|
||||
@@ -140,8 +147,10 @@ static struct page *page_pool_refill_all
|
||||
int pref_nid; /* preferred NUMA node */
|
||||
|
||||
/* Quicker fallback, avoid locks when ring is empty */
|
||||
@@ -113,7 +113,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
/* Softirq guarantee CPU and thus NUMA node is stable. This,
|
||||
* assumes CPU refilling driver RX-ring will also run RX-NAPI.
|
||||
@@ -148,14 +157,17 @@ static struct page *page_pool_refill_all
|
||||
@@ -171,14 +180,17 @@ static struct page *page_pool_refill_all
|
||||
* This limit stress on page buddy alloactor.
|
||||
*/
|
||||
page_pool_return_page(pool, page);
|
||||
@@ -132,7 +132,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
spin_unlock(&r->consumer_lock);
|
||||
return page;
|
||||
@@ -170,6 +182,7 @@ static struct page *__page_pool_get_cach
|
||||
@@ -193,6 +205,7 @@ static struct page *__page_pool_get_cach
|
||||
if (likely(pool->alloc.count)) {
|
||||
/* Fast-path */
|
||||
page = pool->alloc.cache[--pool->alloc.count];
|
||||
@@ -140,7 +140,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
} else {
|
||||
page = page_pool_refill_alloc_cache(pool);
|
||||
}
|
||||
@@ -241,6 +254,7 @@ static struct page *__page_pool_alloc_pa
|
||||
@@ -264,6 +277,7 @@ static struct page *__page_pool_alloc_pa
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
page_pool_set_pp_info(pool, page);
|
||||
|
||||
/* Track how many pages are held 'in-flight' */
|
||||
@@ -295,10 +309,12 @@ static struct page *__page_pool_alloc_pa
|
||||
@@ -318,10 +332,12 @@ static struct page *__page_pool_alloc_pa
|
||||
}
|
||||
|
||||
/* Return last page */
|
||||
|
||||
@@ -53,7 +53,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
/* A page_pool is strictly tied to a single RX-queue being
|
||||
--- a/net/core/page_pool.c
|
||||
+++ b/net/core/page_pool.c
|
||||
@@ -29,8 +29,15 @@
|
||||
@@ -52,8 +52,15 @@ static void page_pool_producer_unlock(st
|
||||
#ifdef CONFIG_PAGE_POOL_STATS
|
||||
/* alloc_stat_inc is intended to be used in softirq context */
|
||||
#define alloc_stat_inc(pool, __stat) (pool->alloc_stats.__stat++)
|
||||
@@ -69,7 +69,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
#endif
|
||||
|
||||
static int page_pool_init(struct page_pool *pool,
|
||||
@@ -80,6 +87,12 @@ static int page_pool_init(struct page_po
|
||||
@@ -103,6 +110,12 @@ static int page_pool_init(struct page_po
|
||||
pool->p.flags & PP_FLAG_PAGE_FRAG)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -82,7 +82,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
if (ptr_ring_init(&pool->ring, ring_qsize, GFP_KERNEL) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -412,7 +425,12 @@ static bool page_pool_recycle_in_ring(st
|
||||
@@ -435,7 +448,12 @@ static bool page_pool_recycle_in_ring(st
|
||||
else
|
||||
ret = ptr_ring_produce_bh(&pool->ring, page);
|
||||
|
||||
@@ -96,7 +96,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
}
|
||||
|
||||
/* Only allow direct recycling in special circumstances, into the
|
||||
@@ -423,11 +441,14 @@ static bool page_pool_recycle_in_ring(st
|
||||
@@ -446,11 +464,14 @@ static bool page_pool_recycle_in_ring(st
|
||||
static bool page_pool_recycle_in_cache(struct page *page,
|
||||
struct page_pool *pool)
|
||||
{
|
||||
@@ -112,7 +112,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -482,6 +503,7 @@ __page_pool_put_page(struct page_pool *p
|
||||
@@ -505,6 +526,7 @@ __page_pool_put_page(struct page_pool *p
|
||||
* doing refcnt based recycle tricks, meaning another process
|
||||
* will be invoking put_page.
|
||||
*/
|
||||
@@ -120,7 +120,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
/* Do not replace this with page_pool_return_page() */
|
||||
page_pool_release_page(pool, page);
|
||||
put_page(page);
|
||||
@@ -495,6 +517,7 @@ void page_pool_put_page(struct page_pool
|
||||
@@ -518,6 +540,7 @@ void page_pool_put_page(struct page_pool
|
||||
page = __page_pool_put_page(pool, page, dma_sync_size, allow_direct);
|
||||
if (page && !page_pool_recycle_in_ring(pool, page)) {
|
||||
/* Cache full, fallback to free pages */
|
||||
@@ -128,7 +128,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
page_pool_return_page(pool, page);
|
||||
}
|
||||
}
|
||||
@@ -641,6 +664,9 @@ static void page_pool_free(struct page_p
|
||||
@@ -665,6 +688,9 @@ static void page_pool_free(struct page_p
|
||||
if (pool->p.flags & PP_FLAG_DMA_MAP)
|
||||
put_device(pool->p.dev);
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
struct page_pool {
|
||||
--- a/net/core/page_pool.c
|
||||
+++ b/net/core/page_pool.c
|
||||
@@ -35,6 +35,31 @@
|
||||
@@ -58,6 +58,31 @@ static void page_pool_producer_unlock(st
|
||||
struct page_pool_recycle_stats __percpu *s = pool->recycle_stats; \
|
||||
this_cpu_inc(s->__stat); \
|
||||
} while (0)
|
||||
|
||||
@@ -16,7 +16,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
--- a/net/core/page_pool.c
|
||||
+++ b/net/core/page_pool.c
|
||||
@@ -36,6 +36,12 @@
|
||||
@@ -59,6 +59,12 @@ static void page_pool_producer_unlock(st
|
||||
this_cpu_inc(s->__stat); \
|
||||
} while (0)
|
||||
|
||||
@@ -29,7 +29,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
bool page_pool_get_stats(struct page_pool *pool,
|
||||
struct page_pool_stats *stats)
|
||||
{
|
||||
@@ -63,6 +69,7 @@ EXPORT_SYMBOL(page_pool_get_stats);
|
||||
@@ -86,6 +92,7 @@ EXPORT_SYMBOL(page_pool_get_stats);
|
||||
#else
|
||||
#define alloc_stat_inc(pool, __stat)
|
||||
#define recycle_stat_inc(pool, __stat)
|
||||
@@ -37,9 +37,9 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
#endif
|
||||
|
||||
static int page_pool_init(struct page_pool *pool,
|
||||
@@ -569,9 +576,13 @@ void page_pool_put_page_bulk(struct page
|
||||
@@ -593,9 +600,13 @@ void page_pool_put_page_bulk(struct page
|
||||
/* Bulk producer into ptr_ring page_pool cache */
|
||||
page_pool_ring_lock(pool);
|
||||
in_softirq = page_pool_producer_lock(pool);
|
||||
for (i = 0; i < bulk_len; i++) {
|
||||
- if (__ptr_ring_produce(&pool->ring, data[i]))
|
||||
- break; /* ring full */
|
||||
@@ -50,6 +50,6 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
+ }
|
||||
}
|
||||
+ recycle_stat_add(pool, ring, i);
|
||||
page_pool_ring_unlock(pool);
|
||||
page_pool_producer_unlock(pool, in_softirq);
|
||||
|
||||
/* Hopefully all pages was return into ptr_ring */
|
||||
|
||||
@@ -62,7 +62,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
#include <trace/events/page_pool.h>
|
||||
|
||||
@@ -42,6 +43,20 @@
|
||||
@@ -65,6 +66,20 @@ static void page_pool_producer_unlock(st
|
||||
this_cpu_add(s->__stat, val); \
|
||||
} while (0)
|
||||
|
||||
@@ -83,7 +83,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
bool page_pool_get_stats(struct page_pool *pool,
|
||||
struct page_pool_stats *stats)
|
||||
{
|
||||
@@ -50,7 +65,13 @@ bool page_pool_get_stats(struct page_poo
|
||||
@@ -73,7 +88,13 @@ bool page_pool_get_stats(struct page_poo
|
||||
if (!stats)
|
||||
return false;
|
||||
|
||||
@@ -98,7 +98,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
const struct page_pool_recycle_stats *pcpu =
|
||||
@@ -66,6 +87,46 @@ bool page_pool_get_stats(struct page_poo
|
||||
@@ -89,6 +110,46 @@ bool page_pool_get_stats(struct page_poo
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(page_pool_get_stats);
|
||||
|
||||
@@ -48,7 +48,7 @@ Signed-off-by: Alexei Starovoitov <ast@kernel.org>
|
||||
int xdp_rxq_info_reg(struct xdp_rxq_info *xdp_rxq,
|
||||
--- a/net/core/xdp.c
|
||||
+++ b/net/core/xdp.c
|
||||
@@ -376,12 +376,38 @@ static void __xdp_return(void *data, str
|
||||
@@ -409,12 +409,38 @@ static void __xdp_return(void *data, str
|
||||
|
||||
void xdp_return_frame(struct xdp_frame *xdpf)
|
||||
{
|
||||
@@ -87,7 +87,7 @@ Signed-off-by: Alexei Starovoitov <ast@kernel.org>
|
||||
__xdp_return(xdpf->data, &xdpf->mem, true, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdp_return_frame_rx_napi);
|
||||
@@ -417,7 +443,7 @@ void xdp_return_frame_bulk(struct xdp_fr
|
||||
@@ -450,7 +476,7 @@ void xdp_return_frame_bulk(struct xdp_fr
|
||||
struct xdp_mem_allocator *xa;
|
||||
|
||||
if (mem->type != MEM_TYPE_PAGE_POOL) {
|
||||
@@ -96,7 +96,7 @@ Signed-off-by: Alexei Starovoitov <ast@kernel.org>
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -436,12 +462,38 @@ void xdp_return_frame_bulk(struct xdp_fr
|
||||
@@ -469,12 +495,38 @@ void xdp_return_frame_bulk(struct xdp_fr
|
||||
bq->xa = rhashtable_lookup(mem_id_ht, &mem->id, mem_id_rht_params);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
From: Qingfang DENG <qingfang.deng@siflower.com.cn>
|
||||
Date: Fri, 3 Feb 2023 09:16:11 +0800
|
||||
Subject: [PATCH] net: page_pool: use in_softirq() instead
|
||||
|
||||
We use BH context only for synchronization, so we don't care if it's
|
||||
actually serving softirq or not.
|
||||
|
||||
As a side node, in case of threaded NAPI, in_serving_softirq() will
|
||||
return false because it's in process context with BH off, making
|
||||
page_pool_recycle_in_cache() unreachable.
|
||||
|
||||
Signed-off-by: Qingfang DENG <qingfang.deng@siflower.com.cn>
|
||||
---
|
||||
|
||||
--- a/include/net/page_pool.h
|
||||
+++ b/include/net/page_pool.h
|
||||
@@ -357,7 +357,7 @@ static inline void page_pool_nid_changed
|
||||
static inline void page_pool_ring_lock(struct page_pool *pool)
|
||||
__acquires(&pool->ring.producer_lock)
|
||||
{
|
||||
- if (in_serving_softirq())
|
||||
+ if (in_softirq())
|
||||
spin_lock(&pool->ring.producer_lock);
|
||||
else
|
||||
spin_lock_bh(&pool->ring.producer_lock);
|
||||
@@ -366,7 +366,7 @@ static inline void page_pool_ring_lock(s
|
||||
static inline void page_pool_ring_unlock(struct page_pool *pool)
|
||||
__releases(&pool->ring.producer_lock)
|
||||
{
|
||||
- if (in_serving_softirq())
|
||||
+ if (in_softirq())
|
||||
spin_unlock(&pool->ring.producer_lock);
|
||||
else
|
||||
spin_unlock_bh(&pool->ring.producer_lock);
|
||||
--- a/net/core/page_pool.c
|
||||
+++ b/net/core/page_pool.c
|
||||
@@ -512,8 +512,8 @@ static void page_pool_return_page(struct
|
||||
static bool page_pool_recycle_in_ring(struct page_pool *pool, struct page *page)
|
||||
{
|
||||
int ret;
|
||||
- /* BH protection not needed if current is serving softirq */
|
||||
- if (in_serving_softirq())
|
||||
+ /* BH protection not needed if current is softirq */
|
||||
+ if (in_softirq())
|
||||
ret = ptr_ring_produce(&pool->ring, page);
|
||||
else
|
||||
ret = ptr_ring_produce_bh(&pool->ring, page);
|
||||
@@ -576,7 +576,7 @@ __page_pool_put_page(struct page_pool *p
|
||||
page_pool_dma_sync_for_device(pool, page,
|
||||
dma_sync_size);
|
||||
|
||||
- if (allow_direct && in_serving_softirq() &&
|
||||
+ if (allow_direct && in_softirq() &&
|
||||
page_pool_recycle_in_cache(page, pool))
|
||||
return NULL;
|
||||
|
||||
@@ -94,7 +94,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
/*
|
||||
* Configuration data for this switch.
|
||||
*/
|
||||
@@ -584,6 +589,13 @@ struct dsa_switch_ops {
|
||||
@@ -612,6 +617,13 @@ struct dsa_switch_ops {
|
||||
enum dsa_tag_protocol mprot);
|
||||
int (*change_tag_protocol)(struct dsa_switch *ds, int port,
|
||||
enum dsa_tag_protocol proto);
|
||||
|
||||
@@ -26,7 +26,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
--- a/include/net/dsa.h
|
||||
+++ b/include/net/dsa.h
|
||||
@@ -626,6 +626,8 @@ struct dsa_switch_ops {
|
||||
@@ -654,6 +654,8 @@ struct dsa_switch_ops {
|
||||
/*
|
||||
* PHYLINK integration
|
||||
*/
|
||||
|
||||
@@ -24,7 +24,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/include/net/dsa.h
|
||||
+++ b/include/net/dsa.h
|
||||
@@ -626,8 +626,8 @@ struct dsa_switch_ops {
|
||||
@@ -654,8 +654,8 @@ struct dsa_switch_ops {
|
||||
/*
|
||||
* PHYLINK integration
|
||||
*/
|
||||
|
||||
@@ -16,7 +16,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
--- a/include/net/dsa.h
|
||||
+++ b/include/net/dsa.h
|
||||
@@ -631,6 +631,9 @@ struct dsa_switch_ops {
|
||||
@@ -659,6 +659,9 @@ struct dsa_switch_ops {
|
||||
void (*phylink_validate)(struct dsa_switch *ds, int port,
|
||||
unsigned long *supported,
|
||||
struct phylink_link_state *state);
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
From 82b318983c515f29b8b3a0dad9f6a5fe8a68a7f4 Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Date: Wed, 20 Oct 2021 20:49:49 +0300
|
||||
Subject: [PATCH] net: dsa: introduce helpers for iterating through ports using
|
||||
dp
|
||||
|
||||
Since the DSA conversion from the ds->ports array into the dst->ports
|
||||
list, the DSA API has encouraged driver writers, as well as the core
|
||||
itself, to write inefficient code.
|
||||
|
||||
Currently, code that wants to filter by a specific type of port when
|
||||
iterating, like {!unused, user, cpu, dsa}, uses the dsa_is_*_port helper.
|
||||
Under the hood, this uses dsa_to_port which iterates again through
|
||||
dst->ports. But the driver iterates through the port list already, so
|
||||
the complexity is quadratic for the typical case of a single-switch
|
||||
tree.
|
||||
|
||||
This patch introduces some iteration helpers where the iterator is
|
||||
already a struct dsa_port *dp, so that the other variant of the
|
||||
filtering functions, dsa_port_is_{unused,user,cpu_dsa}, can be used
|
||||
directly on the iterator. This eliminates the second lookup.
|
||||
|
||||
These functions can be used both by the core and by drivers.
|
||||
|
||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/net/dsa.h | 28 ++++++++++++++++++++++++++++
|
||||
1 file changed, 28 insertions(+)
|
||||
|
||||
--- a/include/net/dsa.h
|
||||
+++ b/include/net/dsa.h
|
||||
@@ -476,6 +476,34 @@ static inline bool dsa_is_user_port(stru
|
||||
return dsa_to_port(ds, p)->type == DSA_PORT_TYPE_USER;
|
||||
}
|
||||
|
||||
+#define dsa_tree_for_each_user_port(_dp, _dst) \
|
||||
+ list_for_each_entry((_dp), &(_dst)->ports, list) \
|
||||
+ if (dsa_port_is_user((_dp)))
|
||||
+
|
||||
+#define dsa_switch_for_each_port(_dp, _ds) \
|
||||
+ list_for_each_entry((_dp), &(_ds)->dst->ports, list) \
|
||||
+ if ((_dp)->ds == (_ds))
|
||||
+
|
||||
+#define dsa_switch_for_each_port_safe(_dp, _next, _ds) \
|
||||
+ list_for_each_entry_safe((_dp), (_next), &(_ds)->dst->ports, list) \
|
||||
+ if ((_dp)->ds == (_ds))
|
||||
+
|
||||
+#define dsa_switch_for_each_port_continue_reverse(_dp, _ds) \
|
||||
+ list_for_each_entry_continue_reverse((_dp), &(_ds)->dst->ports, list) \
|
||||
+ if ((_dp)->ds == (_ds))
|
||||
+
|
||||
+#define dsa_switch_for_each_available_port(_dp, _ds) \
|
||||
+ dsa_switch_for_each_port((_dp), (_ds)) \
|
||||
+ if (!dsa_port_is_unused((_dp)))
|
||||
+
|
||||
+#define dsa_switch_for_each_user_port(_dp, _ds) \
|
||||
+ dsa_switch_for_each_port((_dp), (_ds)) \
|
||||
+ if (dsa_port_is_user((_dp)))
|
||||
+
|
||||
+#define dsa_switch_for_each_cpu_port(_dp, _ds) \
|
||||
+ dsa_switch_for_each_port((_dp), (_ds)) \
|
||||
+ if (dsa_port_is_cpu((_dp)))
|
||||
+
|
||||
static inline u32 dsa_user_ports(struct dsa_switch *ds)
|
||||
{
|
||||
u32 mask = 0;
|
||||
@@ -23,7 +23,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2412,6 +2412,32 @@ mt7531_setup(struct dsa_switch *ds)
|
||||
@@ -2444,6 +2444,32 @@ mt7531_setup(struct dsa_switch *ds)
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
static bool
|
||||
mt7530_phy_mode_supported(struct dsa_switch *ds, int port,
|
||||
const struct phylink_link_state *state)
|
||||
@@ -2448,6 +2474,37 @@ static bool mt7531_is_rgmii_port(struct
|
||||
@@ -2480,6 +2506,37 @@ static bool mt7531_is_rgmii_port(struct
|
||||
return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII);
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
static bool
|
||||
mt7531_phy_mode_supported(struct dsa_switch *ds, int port,
|
||||
const struct phylink_link_state *state)
|
||||
@@ -2924,6 +2981,18 @@ mt7531_cpu_port_config(struct dsa_switch
|
||||
@@ -2956,6 +3013,18 @@ mt7531_cpu_port_config(struct dsa_switch
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
static void
|
||||
mt7530_mac_port_validate(struct dsa_switch *ds, int port,
|
||||
unsigned long *supported)
|
||||
@@ -3159,6 +3228,7 @@ static const struct dsa_switch_ops mt753
|
||||
@@ -3191,6 +3260,7 @@ static const struct dsa_switch_ops mt753
|
||||
.port_vlan_del = mt7530_port_vlan_del,
|
||||
.port_mirror_add = mt753x_port_mirror_add,
|
||||
.port_mirror_del = mt753x_port_mirror_del,
|
||||
@@ -121,7 +121,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
.phylink_validate = mt753x_phylink_validate,
|
||||
.phylink_mac_link_state = mt753x_phylink_mac_link_state,
|
||||
.phylink_mac_config = mt753x_phylink_mac_config,
|
||||
@@ -3176,6 +3246,7 @@ static const struct mt753x_info mt753x_t
|
||||
@@ -3208,6 +3278,7 @@ static const struct mt753x_info mt753x_t
|
||||
.phy_read = mt7530_phy_read,
|
||||
.phy_write = mt7530_phy_write,
|
||||
.pad_setup = mt7530_pad_clk_setup,
|
||||
@@ -129,7 +129,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
.phy_mode_supported = mt7530_phy_mode_supported,
|
||||
.mac_port_validate = mt7530_mac_port_validate,
|
||||
.mac_port_get_state = mt7530_phylink_mac_link_state,
|
||||
@@ -3187,6 +3258,7 @@ static const struct mt753x_info mt753x_t
|
||||
@@ -3219,6 +3290,7 @@ static const struct mt753x_info mt753x_t
|
||||
.phy_read = mt7530_phy_read,
|
||||
.phy_write = mt7530_phy_write,
|
||||
.pad_setup = mt7530_pad_clk_setup,
|
||||
@@ -137,7 +137,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
.phy_mode_supported = mt7530_phy_mode_supported,
|
||||
.mac_port_validate = mt7530_mac_port_validate,
|
||||
.mac_port_get_state = mt7530_phylink_mac_link_state,
|
||||
@@ -3199,6 +3271,7 @@ static const struct mt753x_info mt753x_t
|
||||
@@ -3231,6 +3303,7 @@ static const struct mt753x_info mt753x_t
|
||||
.phy_write = mt7531_ind_phy_write,
|
||||
.pad_setup = mt7531_pad_setup,
|
||||
.cpu_port_config = mt7531_cpu_port_config,
|
||||
@@ -145,7 +145,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
.phy_mode_supported = mt7531_phy_mode_supported,
|
||||
.mac_port_validate = mt7531_mac_port_validate,
|
||||
.mac_port_get_state = mt7531_phylink_mac_link_state,
|
||||
@@ -3261,6 +3334,7 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
@@ -3293,6 +3366,7 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
*/
|
||||
if (!priv->info->sw_setup || !priv->info->pad_setup ||
|
||||
!priv->info->phy_read || !priv->info->phy_write ||
|
||||
|
||||
@@ -21,7 +21,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2438,37 +2438,6 @@ static void mt7530_mac_port_get_caps(str
|
||||
@@ -2470,37 +2470,6 @@ static void mt7530_mac_port_get_caps(str
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port)
|
||||
{
|
||||
return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII);
|
||||
@@ -2505,44 +2474,6 @@ static void mt7531_mac_port_get_caps(str
|
||||
@@ -2537,44 +2506,6 @@ static void mt7531_mac_port_get_caps(str
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
static int
|
||||
mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state)
|
||||
{
|
||||
@@ -2797,9 +2728,6 @@ mt753x_phylink_mac_config(struct dsa_swi
|
||||
@@ -2829,9 +2760,6 @@ mt753x_phylink_mac_config(struct dsa_swi
|
||||
struct mt7530_priv *priv = ds->priv;
|
||||
u32 mcr_cur, mcr_new;
|
||||
|
||||
@@ -114,7 +114,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
switch (port) {
|
||||
case 0 ... 4: /* Internal phy */
|
||||
if (state->interface != PHY_INTERFACE_MODE_GMII)
|
||||
@@ -3015,12 +2943,6 @@ mt753x_phylink_validate(struct dsa_switc
|
||||
@@ -3047,12 +2975,6 @@ mt753x_phylink_validate(struct dsa_switc
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
|
||||
struct mt7530_priv *priv = ds->priv;
|
||||
|
||||
@@ -127,7 +127,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
phylink_set_port_modes(mask);
|
||||
|
||||
if (state->interface != PHY_INTERFACE_MODE_TRGMII &&
|
||||
@@ -3247,7 +3169,6 @@ static const struct mt753x_info mt753x_t
|
||||
@@ -3279,7 +3201,6 @@ static const struct mt753x_info mt753x_t
|
||||
.phy_write = mt7530_phy_write,
|
||||
.pad_setup = mt7530_pad_clk_setup,
|
||||
.mac_port_get_caps = mt7530_mac_port_get_caps,
|
||||
@@ -135,7 +135,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
.mac_port_validate = mt7530_mac_port_validate,
|
||||
.mac_port_get_state = mt7530_phylink_mac_link_state,
|
||||
.mac_port_config = mt7530_mac_config,
|
||||
@@ -3259,7 +3180,6 @@ static const struct mt753x_info mt753x_t
|
||||
@@ -3291,7 +3212,6 @@ static const struct mt753x_info mt753x_t
|
||||
.phy_write = mt7530_phy_write,
|
||||
.pad_setup = mt7530_pad_clk_setup,
|
||||
.mac_port_get_caps = mt7530_mac_port_get_caps,
|
||||
@@ -143,7 +143,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
.mac_port_validate = mt7530_mac_port_validate,
|
||||
.mac_port_get_state = mt7530_phylink_mac_link_state,
|
||||
.mac_port_config = mt7530_mac_config,
|
||||
@@ -3272,7 +3192,6 @@ static const struct mt753x_info mt753x_t
|
||||
@@ -3304,7 +3224,6 @@ static const struct mt753x_info mt753x_t
|
||||
.pad_setup = mt7531_pad_setup,
|
||||
.cpu_port_config = mt7531_cpu_port_config,
|
||||
.mac_port_get_caps = mt7531_mac_port_get_caps,
|
||||
@@ -151,7 +151,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
.mac_port_validate = mt7531_mac_port_validate,
|
||||
.mac_port_get_state = mt7531_phylink_mac_link_state,
|
||||
.mac_port_config = mt7531_mac_config,
|
||||
@@ -3335,7 +3254,6 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
@@ -3367,7 +3286,6 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
if (!priv->info->sw_setup || !priv->info->pad_setup ||
|
||||
!priv->info->phy_read || !priv->info->phy_write ||
|
||||
!priv->info->mac_port_get_caps ||
|
||||
|
||||
@@ -20,7 +20,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2967,11 +2967,6 @@ mt753x_phylink_validate(struct dsa_switc
|
||||
@@ -2999,11 +2999,6 @@ mt753x_phylink_validate(struct dsa_switc
|
||||
|
||||
linkmode_and(supported, supported, mask);
|
||||
linkmode_and(state->advertising, state->advertising, mask);
|
||||
|
||||
@@ -23,7 +23,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2545,12 +2545,13 @@ static int mt7531_rgmii_setup(struct mt7
|
||||
@@ -2577,12 +2577,13 @@ static int mt7531_rgmii_setup(struct mt7
|
||||
}
|
||||
|
||||
static void mt7531_sgmii_validate(struct mt7530_priv *priv, int port,
|
||||
@@ -38,7 +38,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
phylink_set(supported, 2500baseX_Full);
|
||||
phylink_set(supported, 2500baseT_Full);
|
||||
}
|
||||
@@ -2923,16 +2924,18 @@ static void mt753x_phylink_get_caps(stru
|
||||
@@ -2955,16 +2956,18 @@ static void mt753x_phylink_get_caps(stru
|
||||
|
||||
static void
|
||||
mt7530_mac_port_validate(struct dsa_switch *ds, int port,
|
||||
@@ -58,7 +58,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2955,12 +2958,13 @@ mt753x_phylink_validate(struct dsa_switc
|
||||
@@ -2987,12 +2990,13 @@ mt753x_phylink_validate(struct dsa_switc
|
||||
}
|
||||
|
||||
/* This switch only supports 1G full-duplex. */
|
||||
|
||||
@@ -20,7 +20,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2544,19 +2544,6 @@ static int mt7531_rgmii_setup(struct mt7
|
||||
@@ -2576,19 +2576,6 @@ static int mt7531_rgmii_setup(struct mt7
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
static void
|
||||
mt7531_sgmii_link_up_force(struct dsa_switch *ds, int port,
|
||||
unsigned int mode, phy_interface_t interface,
|
||||
@@ -2923,51 +2910,21 @@ static void mt753x_phylink_get_caps(stru
|
||||
@@ -2955,51 +2942,21 @@ static void mt753x_phylink_get_caps(stru
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -97,7 +97,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
linkmode_and(supported, supported, mask);
|
||||
linkmode_and(state->advertising, state->advertising, mask);
|
||||
@@ -3168,7 +3125,6 @@ static const struct mt753x_info mt753x_t
|
||||
@@ -3200,7 +3157,6 @@ static const struct mt753x_info mt753x_t
|
||||
.phy_write = mt7530_phy_write,
|
||||
.pad_setup = mt7530_pad_clk_setup,
|
||||
.mac_port_get_caps = mt7530_mac_port_get_caps,
|
||||
@@ -105,7 +105,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
.mac_port_get_state = mt7530_phylink_mac_link_state,
|
||||
.mac_port_config = mt7530_mac_config,
|
||||
},
|
||||
@@ -3179,7 +3135,6 @@ static const struct mt753x_info mt753x_t
|
||||
@@ -3211,7 +3167,6 @@ static const struct mt753x_info mt753x_t
|
||||
.phy_write = mt7530_phy_write,
|
||||
.pad_setup = mt7530_pad_clk_setup,
|
||||
.mac_port_get_caps = mt7530_mac_port_get_caps,
|
||||
@@ -113,7 +113,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
.mac_port_get_state = mt7530_phylink_mac_link_state,
|
||||
.mac_port_config = mt7530_mac_config,
|
||||
},
|
||||
@@ -3191,7 +3146,6 @@ static const struct mt753x_info mt753x_t
|
||||
@@ -3223,7 +3178,6 @@ static const struct mt753x_info mt753x_t
|
||||
.pad_setup = mt7531_pad_setup,
|
||||
.cpu_port_config = mt7531_cpu_port_config,
|
||||
.mac_port_get_caps = mt7531_mac_port_get_caps,
|
||||
@@ -121,7 +121,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
.mac_port_get_state = mt7531_phylink_mac_link_state,
|
||||
.mac_port_config = mt7531_mac_config,
|
||||
.mac_pcs_an_restart = mt7531_sgmii_restart_an,
|
||||
@@ -3253,7 +3207,6 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
@@ -3285,7 +3239,6 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
if (!priv->info->sw_setup || !priv->info->pad_setup ||
|
||||
!priv->info->phy_read || !priv->info->phy_write ||
|
||||
!priv->info->mac_port_get_caps ||
|
||||
|
||||
@@ -33,7 +33,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
/* String, offset, and register size in bytes if different from 4 bytes */
|
||||
static const struct mt7530_mib_desc mt7530_mib[] = {
|
||||
MIB_DESC(1, 0x00, "TxDrop"),
|
||||
@@ -2544,12 +2549,11 @@ static int mt7531_rgmii_setup(struct mt7
|
||||
@@ -2576,12 +2581,11 @@ static int mt7531_rgmii_setup(struct mt7
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
unsigned int val;
|
||||
|
||||
/* For adjusting speed and duplex of SGMII force mode. */
|
||||
@@ -2575,6 +2579,9 @@ mt7531_sgmii_link_up_force(struct dsa_sw
|
||||
@@ -2607,6 +2611,9 @@ mt7531_sgmii_link_up_force(struct dsa_sw
|
||||
|
||||
/* MT7531 SGMII 1G force mode can only work in full duplex mode,
|
||||
* no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not.
|
||||
@@ -60,7 +60,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
*/
|
||||
if ((speed == SPEED_10 || speed == SPEED_100) &&
|
||||
duplex != DUPLEX_FULL)
|
||||
@@ -2650,9 +2657,10 @@ static int mt7531_sgmii_setup_mode_an(st
|
||||
@@ -2682,9 +2689,10 @@ static int mt7531_sgmii_setup_mode_an(st
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
u32 val;
|
||||
|
||||
/* Only restart AN when AN is enabled */
|
||||
@@ -2709,6 +2717,24 @@ mt753x_mac_config(struct dsa_switch *ds,
|
||||
@@ -2741,6 +2749,24 @@ mt753x_mac_config(struct dsa_switch *ds,
|
||||
return priv->info->mac_port_config(ds, port, mode, state->interface);
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
static void
|
||||
mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
|
||||
const struct phylink_link_state *state)
|
||||
@@ -2770,17 +2796,6 @@ unsupported:
|
||||
@@ -2802,17 +2828,6 @@ unsupported:
|
||||
mt7530_write(priv, MT7530_PMCR_P(port), mcr_new);
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port,
|
||||
unsigned int mode,
|
||||
phy_interface_t interface)
|
||||
@@ -2790,16 +2805,13 @@ static void mt753x_phylink_mac_link_down
|
||||
@@ -2822,16 +2837,13 @@ static void mt753x_phylink_mac_link_down
|
||||
mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
}
|
||||
|
||||
static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
|
||||
@@ -2812,8 +2824,6 @@ static void mt753x_phylink_mac_link_up(s
|
||||
@@ -2844,8 +2856,6 @@ static void mt753x_phylink_mac_link_up(s
|
||||
struct mt7530_priv *priv = ds->priv;
|
||||
u32 mcr;
|
||||
|
||||
@@ -148,7 +148,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK;
|
||||
|
||||
/* MT753x MAC works in 1G full duplex mode for all up-clocked
|
||||
@@ -2891,6 +2901,8 @@ mt7531_cpu_port_config(struct dsa_switch
|
||||
@@ -2923,6 +2933,8 @@ mt7531_cpu_port_config(struct dsa_switch
|
||||
return ret;
|
||||
mt7530_write(priv, MT7530_PMCR_P(port),
|
||||
PMCR_CPU_PORT_SETTING(priv->id));
|
||||
@@ -157,7 +157,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL,
|
||||
speed, DUPLEX_FULL, true, true);
|
||||
|
||||
@@ -2930,16 +2942,13 @@ mt753x_phylink_validate(struct dsa_switc
|
||||
@@ -2962,16 +2974,13 @@ mt753x_phylink_validate(struct dsa_switc
|
||||
linkmode_and(state->advertising, state->advertising, mask);
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
pmsr = mt7530_read(priv, MT7530_PMSR_P(port));
|
||||
|
||||
state->link = (pmsr & PMSR_LINK);
|
||||
@@ -2966,8 +2975,6 @@ mt7530_phylink_mac_link_state(struct dsa
|
||||
@@ -2998,8 +3007,6 @@ mt7530_phylink_mac_link_state(struct dsa
|
||||
state->pause |= MLO_PAUSE_RX;
|
||||
if (pmsr & PMSR_TX_FC)
|
||||
state->pause |= MLO_PAUSE_TX;
|
||||
@@ -187,7 +187,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3009,32 +3016,49 @@ mt7531_sgmii_pcs_get_state_an(struct mt7
|
||||
@@ -3041,32 +3048,49 @@ mt7531_sgmii_pcs_get_state_an(struct mt7
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -3047,6 +3071,13 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
@@ -3079,6 +3103,13 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
if (ret && priv->irq)
|
||||
mt7530_free_irq_common(priv);
|
||||
|
||||
@@ -263,7 +263,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3108,9 +3139,8 @@ static const struct dsa_switch_ops mt753
|
||||
@@ -3140,9 +3171,8 @@ static const struct dsa_switch_ops mt753
|
||||
.port_mirror_del = mt753x_port_mirror_del,
|
||||
.phylink_get_caps = mt753x_phylink_get_caps,
|
||||
.phylink_validate = mt753x_phylink_validate,
|
||||
@@ -274,7 +274,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
.phylink_mac_link_down = mt753x_phylink_mac_link_down,
|
||||
.phylink_mac_link_up = mt753x_phylink_mac_link_up,
|
||||
.get_mac_eee = mt753x_get_mac_eee,
|
||||
@@ -3120,36 +3150,34 @@ static const struct dsa_switch_ops mt753
|
||||
@@ -3152,36 +3182,34 @@ static const struct dsa_switch_ops mt753
|
||||
static const struct mt753x_info mt753x_table[] = {
|
||||
[ID_MT7621] = {
|
||||
.id = ID_MT7621,
|
||||
@@ -314,7 +314,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
},
|
||||
};
|
||||
|
||||
@@ -3207,7 +3235,7 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
@@ -3239,7 +3267,7 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
if (!priv->info->sw_setup || !priv->info->pad_setup ||
|
||||
!priv->info->phy_read || !priv->info->phy_write ||
|
||||
!priv->info->mac_port_get_caps ||
|
||||
|
||||
@@ -20,7 +20,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2921,25 +2921,16 @@ static void mt753x_phylink_get_caps(stru
|
||||
@@ -2953,25 +2953,16 @@ static void mt753x_phylink_get_caps(stru
|
||||
priv->info->mac_port_get_caps(ds, port, config);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
}
|
||||
|
||||
static void mt7530_pcs_get_state(struct phylink_pcs *pcs,
|
||||
@@ -3041,12 +3032,14 @@ static void mt7530_pcs_an_restart(struct
|
||||
@@ -3073,12 +3064,14 @@ static void mt7530_pcs_an_restart(struct
|
||||
}
|
||||
|
||||
static const struct phylink_pcs_ops mt7530_pcs_ops = {
|
||||
@@ -70,7 +70,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
.pcs_get_state = mt7531_pcs_get_state,
|
||||
.pcs_config = mt753x_pcs_config,
|
||||
.pcs_an_restart = mt7531_pcs_an_restart,
|
||||
@@ -3138,7 +3131,6 @@ static const struct dsa_switch_ops mt753
|
||||
@@ -3170,7 +3163,6 @@ static const struct dsa_switch_ops mt753
|
||||
.port_mirror_add = mt753x_port_mirror_add,
|
||||
.port_mirror_del = mt753x_port_mirror_del,
|
||||
.phylink_get_caps = mt753x_phylink_get_caps,
|
||||
|
||||
@@ -19,7 +19,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2918,6 +2918,12 @@ static void mt753x_phylink_get_caps(stru
|
||||
@@ -2950,6 +2950,12 @@ static void mt753x_phylink_get_caps(stru
|
||||
config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
|
||||
MAC_10 | MAC_100 | MAC_1000FD;
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -3056,9 +3056,16 @@ static int
|
||||
@@ -3088,9 +3088,16 @@ static int
|
||||
mt753x_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct mt7530_priv *priv = ds->priv;
|
||||
@@ -100,7 +100,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -3070,13 +3077,6 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
@@ -3102,13 +3109,6 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
if (ret && priv->irq)
|
||||
mt7530_free_irq_common(priv);
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
From 1f0dfd443eea7fc3e818e96f7c8264913ba41859 Mon Sep 17 00:00:00 2001
|
||||
From: Frank Wunderlich <frank-w@public-files.de>
|
||||
Date: Fri, 10 Jun 2022 19:05:38 +0200
|
||||
Subject: [PATCH 12/13] net: dsa: mt7530: rework mt753[01]_setup
|
||||
|
||||
Enumerate available cpu-ports instead of using hardcoded constant.
|
||||
|
||||
Suggested-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/mt7530.c | 25 +++++++++++++++++++++----
|
||||
1 file changed, 21 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2101,11 +2101,12 @@ static int
|
||||
mt7530_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct mt7530_priv *priv = ds->priv;
|
||||
+ struct device_node *dn = NULL;
|
||||
struct device_node *phy_node;
|
||||
struct device_node *mac_np;
|
||||
struct mt7530_dummy_poll p;
|
||||
phy_interface_t interface;
|
||||
- struct device_node *dn;
|
||||
+ struct dsa_port *cpu_dp;
|
||||
u32 id, val;
|
||||
int ret, i;
|
||||
|
||||
@@ -2113,7 +2114,19 @@ mt7530_setup(struct dsa_switch *ds)
|
||||
* controller also is the container for two GMACs nodes representing
|
||||
* as two netdev instances.
|
||||
*/
|
||||
- dn = dsa_to_port(ds, MT7530_CPU_PORT)->master->dev.of_node->parent;
|
||||
+ dsa_switch_for_each_cpu_port(cpu_dp, ds) {
|
||||
+ dn = cpu_dp->master->dev.of_node->parent;
|
||||
+ /* It doesn't matter which CPU port is found first,
|
||||
+ * their masters should share the same parent OF node
|
||||
+ */
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (!dn) {
|
||||
+ dev_err(ds->dev, "parent OF node of DSA master not found");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
ds->assisted_learning_on_cpu_port = true;
|
||||
ds->mtu_enforcement_ingress = true;
|
||||
|
||||
@@ -2286,6 +2299,7 @@ mt7531_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct mt7530_priv *priv = ds->priv;
|
||||
struct mt7530_dummy_poll p;
|
||||
+ struct dsa_port *cpu_dp;
|
||||
u32 val, id;
|
||||
int ret, i;
|
||||
|
||||
@@ -2360,8 +2374,11 @@ mt7531_setup(struct dsa_switch *ds)
|
||||
CORE_PLL_GROUP4, val);
|
||||
|
||||
/* BPDU to CPU port */
|
||||
- mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
|
||||
- BIT(MT7530_CPU_PORT));
|
||||
+ dsa_switch_for_each_cpu_port(cpu_dp, ds) {
|
||||
+ mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
|
||||
+ BIT(cpu_dp->index));
|
||||
+ break;
|
||||
+ }
|
||||
mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
|
||||
MT753X_BPDU_CPU_ONLY);
|
||||
|
||||
@@ -19,7 +19,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2721,9 +2721,6 @@ mt7531_mac_config(struct dsa_switch *ds,
|
||||
@@ -2736,9 +2736,6 @@ mt7531_mac_config(struct dsa_switch *ds,
|
||||
case PHY_INTERFACE_MODE_NA:
|
||||
case PHY_INTERFACE_MODE_1000BASEX:
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
@@ -29,7 +29,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
return mt7531_sgmii_setup_mode_force(priv, port, interface);
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -2799,13 +2796,6 @@ unsupported:
|
||||
@@ -2814,13 +2811,6 @@ unsupported:
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
|
||||
mcr_new = mcr_cur;
|
||||
mcr_new &= ~PMCR_LINK_SETTINGS_MASK;
|
||||
@@ -2942,6 +2932,9 @@ static void mt753x_phylink_get_caps(stru
|
||||
@@ -2957,6 +2947,9 @@ static void mt753x_phylink_get_caps(stru
|
||||
config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
|
||||
MAC_10 | MAC_100 | MAC_1000FD;
|
||||
|
||||
@@ -53,7 +53,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
/* This driver does not make use of the speed, duplex, pause or the
|
||||
* advertisement in its mac_config, so it is safe to mark this driver
|
||||
* as non-legacy.
|
||||
@@ -3007,6 +3000,7 @@ mt7531_sgmii_pcs_get_state_an(struct mt7
|
||||
@@ -3022,6 +3015,7 @@ mt7531_sgmii_pcs_get_state_an(struct mt7
|
||||
|
||||
status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
|
||||
state->link = !!(status & MT7531_SGMII_LINK_STATUS);
|
||||
@@ -61,7 +61,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
if (state->interface == PHY_INTERFACE_MODE_SGMII &&
|
||||
(status & MT7531_SGMII_AN_ENABLE)) {
|
||||
val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port));
|
||||
@@ -3037,16 +3031,44 @@ mt7531_sgmii_pcs_get_state_an(struct mt7
|
||||
@@ -3052,16 +3046,44 @@ mt7531_sgmii_pcs_get_state_an(struct mt7
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
}
|
||||
|
||||
static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
|
||||
@@ -3087,6 +3109,8 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
@@ -3102,6 +3124,8 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
priv->pcs[i].pcs.ops = priv->info->pcs_ops;
|
||||
priv->pcs[i].priv = priv;
|
||||
priv->pcs[i].port = i;
|
||||
|
||||
@@ -81,7 +81,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
@@ -2573,128 +2574,11 @@ static int mt7531_rgmii_setup(struct mt7
|
||||
@@ -2588,128 +2589,11 @@ static int mt7531_rgmii_setup(struct mt7
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
|
||||
static int
|
||||
mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
|
||||
phy_interface_t interface)
|
||||
@@ -2717,11 +2601,11 @@ mt7531_mac_config(struct dsa_switch *ds,
|
||||
@@ -2732,11 +2616,11 @@ mt7531_mac_config(struct dsa_switch *ds,
|
||||
phydev = dp->slave->phydev;
|
||||
return mt7531_rgmii_setup(priv, port, interface, phydev);
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
@@ -224,7 +224,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -2746,11 +2630,11 @@ mt753x_phylink_mac_select_pcs(struct dsa
|
||||
@@ -2761,11 +2645,11 @@ mt753x_phylink_mac_select_pcs(struct dsa
|
||||
|
||||
switch (interface) {
|
||||
case PHY_INTERFACE_MODE_TRGMII:
|
||||
@@ -238,7 +238,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@@ -2991,86 +2875,6 @@ static void mt7530_pcs_get_state(struct
|
||||
@@ -3006,86 +2890,6 @@ static void mt7530_pcs_get_state(struct
|
||||
state->pause |= MLO_PAUSE_TX;
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
|
||||
static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
|
||||
phy_interface_t interface,
|
||||
const unsigned long *advertising,
|
||||
@@ -3090,18 +2894,57 @@ static const struct phylink_pcs_ops mt75
|
||||
@@ -3105,18 +2909,57 @@ static const struct phylink_pcs_ops mt75
|
||||
.pcs_an_restart = mt7530_pcs_an_restart,
|
||||
};
|
||||
|
||||
@@ -389,7 +389,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
|
||||
int i, ret;
|
||||
|
||||
/* Initialise the PCS devices */
|
||||
@@ -3109,8 +2952,6 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
@@ -3124,8 +2967,6 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
priv->pcs[i].pcs.ops = priv->info->pcs_ops;
|
||||
priv->pcs[i].priv = priv;
|
||||
priv->pcs[i].port = i;
|
||||
@@ -398,7 +398,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
|
||||
}
|
||||
|
||||
ret = priv->info->sw_setup(ds);
|
||||
@@ -3125,6 +2966,16 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
@@ -3140,6 +2981,16 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
if (ret && priv->irq)
|
||||
mt7530_free_irq_common(priv);
|
||||
|
||||
@@ -415,7 +415,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3216,7 +3067,7 @@ static const struct mt753x_info mt753x_t
|
||||
@@ -3231,7 +3082,7 @@ static const struct mt753x_info mt753x_t
|
||||
},
|
||||
[ID_MT7531] = {
|
||||
.id = ID_MT7531,
|
||||
@@ -424,7 +424,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
|
||||
.sw_setup = mt7531_setup,
|
||||
.phy_read = mt7531_ind_phy_read,
|
||||
.phy_write = mt7531_ind_phy_write,
|
||||
@@ -3324,7 +3175,7 @@ static void
|
||||
@@ -3339,7 +3190,7 @@ static void
|
||||
mt7530_remove(struct mdio_device *mdiodev)
|
||||
{
|
||||
struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
|
||||
@@ -433,7 +433,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
|
||||
|
||||
if (!priv)
|
||||
return;
|
||||
@@ -3343,6 +3194,10 @@ mt7530_remove(struct mdio_device *mdiode
|
||||
@@ -3358,6 +3209,10 @@ mt7530_remove(struct mdio_device *mdiode
|
||||
mt7530_free_irq(priv);
|
||||
|
||||
dsa_unregister_switch(priv->ds);
|
||||
|
||||
@@ -18,7 +18,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2926,26 +2926,56 @@ static const struct regmap_bus mt7531_re
|
||||
@@ -2941,26 +2941,56 @@ static const struct regmap_bus mt7531_re
|
||||
.reg_update_bits = mt7530_regmap_update_bits,
|
||||
};
|
||||
|
||||
@@ -88,7 +88,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
int i, ret;
|
||||
|
||||
/* Initialise the PCS devices */
|
||||
@@ -2967,15 +2997,11 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
@@ -2982,15 +3012,11 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
if (ret && priv->irq)
|
||||
mt7530_free_irq_common(priv);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2899,7 +2899,7 @@ static int mt7530_regmap_read(void *cont
|
||||
@@ -2914,7 +2914,7 @@ static int mt7530_regmap_read(void *cont
|
||||
{
|
||||
struct mt7530_priv *priv = context;
|
||||
|
||||
@@ -28,7 +28,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -2907,23 +2907,25 @@ static int mt7530_regmap_write(void *con
|
||||
@@ -2922,23 +2922,25 @@ static int mt7530_regmap_write(void *con
|
||||
{
|
||||
struct mt7530_priv *priv = context;
|
||||
|
||||
@@ -62,7 +62,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -2949,6 +2951,9 @@ mt7531_create_sgmii(struct mt7530_priv *
|
||||
@@ -2964,6 +2966,9 @@ mt7531_create_sgmii(struct mt7530_priv *
|
||||
mt7531_pcs_config[i]->reg_stride = 4;
|
||||
mt7531_pcs_config[i]->reg_base = MT7531_SGMII_REG_BASE(5 + i);
|
||||
mt7531_pcs_config[i]->max_register = 0x17c;
|
||||
|
||||
@@ -133,7 +133,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2895,22 +2916,6 @@ static const struct phylink_pcs_ops mt75
|
||||
@@ -2910,22 +2931,6 @@ static const struct phylink_pcs_ops mt75
|
||||
.pcs_an_restart = mt7530_pcs_an_restart,
|
||||
};
|
||||
|
||||
@@ -156,7 +156,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
static void
|
||||
mt7530_mdio_regmap_lock(void *mdio_lock)
|
||||
{
|
||||
@@ -2923,7 +2928,7 @@ mt7530_mdio_regmap_unlock(void *mdio_loc
|
||||
@@ -2938,7 +2943,7 @@ mt7530_mdio_regmap_unlock(void *mdio_loc
|
||||
mutex_unlock(mdio_lock);
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
.reg_write = mt7530_regmap_write,
|
||||
.reg_read = mt7530_regmap_read,
|
||||
};
|
||||
@@ -2956,7 +2961,7 @@ mt7531_create_sgmii(struct mt7530_priv *
|
||||
@@ -2971,7 +2976,7 @@ mt7531_create_sgmii(struct mt7530_priv *
|
||||
mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock;
|
||||
|
||||
regmap = devm_regmap_init(priv->dev,
|
||||
@@ -174,7 +174,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
mt7531_pcs_config[i]);
|
||||
if (IS_ERR(regmap)) {
|
||||
ret = PTR_ERR(regmap);
|
||||
@@ -3121,6 +3126,7 @@ MODULE_DEVICE_TABLE(of, mt7530_of_match)
|
||||
@@ -3136,6 +3141,7 @@ MODULE_DEVICE_TABLE(of, mt7530_of_match)
|
||||
static int
|
||||
mt7530_probe(struct mdio_device *mdiodev)
|
||||
{
|
||||
@@ -182,7 +182,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
struct mt7530_priv *priv;
|
||||
struct device_node *dn;
|
||||
|
||||
@@ -3200,6 +3206,21 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
@@ -3215,6 +3221,21 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
mutex_init(&priv->reg_mutex);
|
||||
dev_set_drvdata(&mdiodev->dev, priv);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -3007,12 +3007,6 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
@@ -3022,12 +3022,6 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
if (ret && priv->irq)
|
||||
mt7530_free_irq_common(priv);
|
||||
|
||||
@@ -31,7 +31,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3129,6 +3123,7 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
@@ -3144,6 +3138,7 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
static struct regmap_config *regmap_config;
|
||||
struct mt7530_priv *priv;
|
||||
struct device_node *dn;
|
||||
@@ -39,7 +39,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
dn = mdiodev->dev.of_node;
|
||||
|
||||
@@ -3221,6 +3216,12 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
@@ -3236,6 +3231,12 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
if (IS_ERR(priv->regmap))
|
||||
return PTR_ERR(priv->regmap);
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -3135,44 +3135,21 @@ static const struct of_device_id mt7530_
|
||||
@@ -3150,44 +3150,21 @@ static const struct of_device_id mt7530_
|
||||
MODULE_DEVICE_TABLE(of, mt7530_of_match);
|
||||
|
||||
static int
|
||||
@@ -67,7 +67,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
if (!priv->info)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -3186,23 +3163,53 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
@@ -3201,23 +3178,53 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
return -EINVAL;
|
||||
|
||||
priv->id = priv->info->id;
|
||||
@@ -131,7 +131,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(priv->reset)) {
|
||||
@@ -3211,12 +3218,15 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
@@ -3226,12 +3233,15 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -3253,6 +3253,17 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
@@ -3268,6 +3268,17 @@ mt7530_probe(struct mdio_device *mdiodev
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -35,7 +35,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
mt7530_remove(struct mdio_device *mdiodev)
|
||||
{
|
||||
struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
|
||||
@@ -3271,16 +3282,11 @@ mt7530_remove(struct mdio_device *mdiode
|
||||
@@ -3286,16 +3297,11 @@ mt7530_remove(struct mdio_device *mdiode
|
||||
dev_err(priv->dev, "Failed to disable io pwr: %d\n",
|
||||
ret);
|
||||
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
From 7f54cc9772ced2d76ac11832f0ada43798443ac9 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Mon, 3 Apr 2023 02:19:02 +0100
|
||||
Subject: [PATCH 13/16] net: dsa: mt7530: split-off common parts from
|
||||
mt7531_setup
|
||||
|
||||
MT7988 shares a significant part of the setup function with MT7531.
|
||||
Split-off those parts into a shared function which is going to be used
|
||||
also by mt7988_setup.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/mt7530.c | 99 ++++++++++++++++++++++------------------
|
||||
1 file changed, 55 insertions(+), 44 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2348,11 +2348,64 @@ mt7530_setup(struct dsa_switch *ds)
|
||||
}
|
||||
|
||||
static int
|
||||
+mt7531_setup_common(struct dsa_switch *ds)
|
||||
+{
|
||||
+ struct mt7530_priv *priv = ds->priv;
|
||||
+ struct dsa_port *cpu_dp;
|
||||
+ int ret, i;
|
||||
+
|
||||
+ /* BPDU to CPU port */
|
||||
+ dsa_switch_for_each_cpu_port(cpu_dp, ds) {
|
||||
+ mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
|
||||
+ BIT(cpu_dp->index));
|
||||
+ break;
|
||||
+ }
|
||||
+ mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
|
||||
+ MT753X_BPDU_CPU_ONLY);
|
||||
+
|
||||
+ /* Enable and reset MIB counters */
|
||||
+ mt7530_mib_reset(ds);
|
||||
+
|
||||
+ for (i = 0; i < MT7530_NUM_PORTS; i++) {
|
||||
+ /* Disable forwarding by default on all ports */
|
||||
+ mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
|
||||
+ PCR_MATRIX_CLR);
|
||||
+
|
||||
+ /* Disable learning by default on all ports */
|
||||
+ mt7530_set(priv, MT7530_PSC_P(i), SA_DIS);
|
||||
+
|
||||
+ mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR);
|
||||
+
|
||||
+ if (dsa_is_cpu_port(ds, i)) {
|
||||
+ ret = mt753x_cpu_port_enable(ds, i);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ } else {
|
||||
+ mt7530_port_disable(ds, i);
|
||||
+
|
||||
+ /* Set default PVID to 0 on all user ports */
|
||||
+ mt7530_rmw(priv, MT7530_PPBV1_P(i), G0_PORT_VID_MASK,
|
||||
+ G0_PORT_VID_DEF);
|
||||
+ }
|
||||
+
|
||||
+ /* Enable consistent egress tag */
|
||||
+ mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
|
||||
+ PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
|
||||
+ }
|
||||
+
|
||||
+ /* Flush the FDB table */
|
||||
+ ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
mt7531_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct mt7530_priv *priv = ds->priv;
|
||||
struct mt7530_dummy_poll p;
|
||||
- struct dsa_port *cpu_dp;
|
||||
u32 val, id;
|
||||
int ret, i;
|
||||
|
||||
@@ -2426,44 +2479,7 @@ mt7531_setup(struct dsa_switch *ds)
|
||||
mt7531_ind_c45_phy_write(priv, MT753X_CTRL_PHY_ADDR, MDIO_MMD_VEND2,
|
||||
CORE_PLL_GROUP4, val);
|
||||
|
||||
- /* BPDU to CPU port */
|
||||
- dsa_switch_for_each_cpu_port(cpu_dp, ds) {
|
||||
- mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
|
||||
- BIT(cpu_dp->index));
|
||||
- break;
|
||||
- }
|
||||
- mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
|
||||
- MT753X_BPDU_CPU_ONLY);
|
||||
-
|
||||
- /* Enable and reset MIB counters */
|
||||
- mt7530_mib_reset(ds);
|
||||
-
|
||||
- for (i = 0; i < MT7530_NUM_PORTS; i++) {
|
||||
- /* Disable forwarding by default on all ports */
|
||||
- mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
|
||||
- PCR_MATRIX_CLR);
|
||||
-
|
||||
- /* Disable learning by default on all ports */
|
||||
- mt7530_set(priv, MT7530_PSC_P(i), SA_DIS);
|
||||
-
|
||||
- mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR);
|
||||
-
|
||||
- if (dsa_is_cpu_port(ds, i)) {
|
||||
- ret = mt753x_cpu_port_enable(ds, i);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
- } else {
|
||||
- mt7530_port_disable(ds, i);
|
||||
-
|
||||
- /* Set default PVID to 0 on all user ports */
|
||||
- mt7530_rmw(priv, MT7530_PPBV1_P(i), G0_PORT_VID_MASK,
|
||||
- G0_PORT_VID_DEF);
|
||||
- }
|
||||
-
|
||||
- /* Enable consistent egress tag */
|
||||
- mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
|
||||
- PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
|
||||
- }
|
||||
+ mt7531_setup_common(ds);
|
||||
|
||||
/* Setup VLAN ID 0 for VLAN-unaware bridges */
|
||||
ret = mt7530_setup_vlan0(priv);
|
||||
@@ -2473,11 +2489,6 @@ mt7531_setup(struct dsa_switch *ds)
|
||||
ds->assisted_learning_on_cpu_port = true;
|
||||
ds->mtu_enforcement_ingress = true;
|
||||
|
||||
- /* Flush the FDB table */
|
||||
- ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
|
||||
- if (ret < 0)
|
||||
- return ret;
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -416,7 +416,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
static u32
|
||||
mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
|
||||
{
|
||||
@@ -2944,72 +2895,6 @@ static const struct phylink_pcs_ops mt75
|
||||
@@ -2948,72 +2899,6 @@ static const struct phylink_pcs_ops mt75
|
||||
.pcs_an_restart = mt7530_pcs_an_restart,
|
||||
};
|
||||
|
||||
@@ -489,7 +489,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
static int
|
||||
mt753x_setup(struct dsa_switch *ds)
|
||||
{
|
||||
@@ -3068,7 +2953,7 @@ static int mt753x_set_mac_eee(struct dsa
|
||||
@@ -3072,7 +2957,7 @@ static int mt753x_set_mac_eee(struct dsa
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -498,7 +498,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
.get_tag_protocol = mtk_get_tag_protocol,
|
||||
.setup = mt753x_setup,
|
||||
.get_strings = mt7530_get_strings,
|
||||
@@ -3102,8 +2987,9 @@ static const struct dsa_switch_ops mt753
|
||||
@@ -3106,8 +2991,9 @@ static const struct dsa_switch_ops mt753
|
||||
.get_mac_eee = mt753x_get_mac_eee,
|
||||
.set_mac_eee = mt753x_set_mac_eee,
|
||||
};
|
||||
@@ -509,7 +509,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
[ID_MT7621] = {
|
||||
.id = ID_MT7621,
|
||||
.pcs_ops = &mt7530_pcs_ops,
|
||||
@@ -3136,16 +3022,9 @@ static const struct mt753x_info mt753x_t
|
||||
@@ -3140,16 +3026,9 @@ static const struct mt753x_info mt753x_t
|
||||
.mac_port_config = mt7531_mac_config,
|
||||
},
|
||||
};
|
||||
@@ -528,7 +528,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
mt7530_probe_common(struct mt7530_priv *priv)
|
||||
{
|
||||
struct device *dev = priv->dev;
|
||||
@@ -3182,88 +3061,9 @@ mt7530_probe_common(struct mt7530_priv *
|
||||
@@ -3186,88 +3065,9 @@ mt7530_probe_common(struct mt7530_priv *
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -619,7 +619,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
mt7530_remove_common(struct mt7530_priv *priv)
|
||||
{
|
||||
if (priv->irq)
|
||||
@@ -3274,57 +3074,6 @@ mt7530_remove_common(struct mt7530_priv
|
||||
@@ -3278,57 +3078,6 @@ mt7530_remove_common(struct mt7530_priv
|
||||
mutex_destroy(&priv->reg_mutex);
|
||||
}
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
if (!priv->irq_domain) {
|
||||
dev_err(dev, "failed to create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
@@ -2507,6 +2555,25 @@ static void mt7531_mac_port_get_caps(str
|
||||
@@ -2511,6 +2559,25 @@ static void mt7531_mac_port_get_caps(str
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
static int
|
||||
mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state)
|
||||
{
|
||||
@@ -2583,6 +2650,17 @@ static bool mt753x_is_mac_port(u32 port)
|
||||
@@ -2587,6 +2654,17 @@ static bool mt753x_is_mac_port(u32 port)
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -294,7 +294,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
@@ -2652,7 +2730,8 @@ mt753x_phylink_mac_config(struct dsa_swi
|
||||
@@ -2656,7 +2734,8 @@ mt753x_phylink_mac_config(struct dsa_swi
|
||||
|
||||
switch (port) {
|
||||
case 0 ... 4: /* Internal phy */
|
||||
@@ -304,7 +304,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
goto unsupported;
|
||||
break;
|
||||
case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
|
||||
@@ -2730,7 +2809,8 @@ static void mt753x_phylink_mac_link_up(s
|
||||
@@ -2734,7 +2813,8 @@ static void mt753x_phylink_mac_link_up(s
|
||||
/* MT753x MAC works in 1G full duplex mode for all up-clocked
|
||||
* variants.
|
||||
*/
|
||||
@@ -314,7 +314,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
(phy_interface_mode_is_8023z(interface))) {
|
||||
speed = SPEED_1000;
|
||||
duplex = DUPLEX_FULL;
|
||||
@@ -2810,6 +2890,21 @@ mt7531_cpu_port_config(struct dsa_switch
|
||||
@@ -2814,6 +2894,21 @@ mt7531_cpu_port_config(struct dsa_switch
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
|
||||
struct phylink_config *config)
|
||||
{
|
||||
@@ -2955,6 +3050,27 @@ static int mt753x_set_mac_eee(struct dsa
|
||||
@@ -2959,6 +3054,27 @@ static int mt753x_set_mac_eee(struct dsa
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
const struct dsa_switch_ops mt7530_switch_ops = {
|
||||
.get_tag_protocol = mtk_get_tag_protocol,
|
||||
.setup = mt753x_setup,
|
||||
@@ -3023,6 +3139,17 @@ const struct mt753x_info mt753x_table[]
|
||||
@@ -3027,6 +3143,17 @@ const struct mt753x_info mt753x_table[]
|
||||
.mac_port_get_caps = mt7531_mac_port_get_caps,
|
||||
.mac_port_config = mt7531_mac_config,
|
||||
},
|
||||
|
||||
@@ -73,7 +73,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
}
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -3017,6 +3017,12 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
@@ -3021,6 +3021,12 @@ mt753x_setup(struct dsa_switch *ds)
|
||||
if (ret && priv->irq)
|
||||
mt7530_free_irq_common(priv);
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
|
||||
--- a/arch/arm/configs/multi_v7_defconfig
|
||||
+++ b/arch/arm/configs/multi_v7_defconfig
|
||||
@@ -1125,10 +1125,10 @@ CONFIG_TI_PIPE3=y
|
||||
@@ -1124,10 +1124,10 @@ CONFIG_TI_PIPE3=y
|
||||
CONFIG_TWL4030_USB=m
|
||||
CONFIG_RAS=y
|
||||
CONFIG_NVMEM_IMX_OCOTP=y
|
||||
|
||||
@@ -1633,6 +1633,7 @@ CONFIG_DQL=y
|
||||
# CONFIG_DRM_RADEON_USERPTR is not set
|
||||
# CONFIG_DRM_RCAR_DW_HDMI is not set
|
||||
# CONFIG_DRM_RCAR_LVDS is not set
|
||||
# CONFIG_DRM_RCAR_USE_LVDS is not set
|
||||
# CONFIG_DRM_ROCKCHIP is not set
|
||||
# CONFIG_DRM_SII902X is not set
|
||||
# CONFIG_DRM_SII9234 is not set
|
||||
|
||||
@@ -125,7 +125,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/property.h>
|
||||
@@ -3358,3 +3359,5 @@ static int __init regmap_initcall(void)
|
||||
@@ -3360,3 +3361,5 @@ static int __init regmap_initcall(void)
|
||||
return 0;
|
||||
}
|
||||
postcore_initcall(regmap_initcall);
|
||||
|
||||
@@ -1,846 +0,0 @@
|
||||
From 11c3fae5afa6cac444d12622e2cf5af60a99c1ef Mon Sep 17 00:00:00 2001
|
||||
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
|
||||
Date: Wed, 13 Jul 2022 13:43:15 +0200
|
||||
Subject: [PATCH] net/bridge: add bridge offload
|
||||
|
||||
---
|
||||
include/linux/if_bridge.h | 1 +
|
||||
net/bridge/Makefile | 2 +-
|
||||
net/bridge/br.c | 8 +
|
||||
net/bridge/br_device.c | 2 +
|
||||
net/bridge/br_fdb.c | 5 +
|
||||
net/bridge/br_forward.c | 3 +
|
||||
net/bridge/br_if.c | 6 +-
|
||||
net/bridge/br_input.c | 5 +
|
||||
net/bridge/br_offload.c | 438 ++++++++++++++++++++++++++++++++
|
||||
net/bridge/br_private.h | 22 +-
|
||||
net/bridge/br_private_offload.h | 23 ++
|
||||
net/bridge/br_stp.c | 3 +
|
||||
net/bridge/br_sysfs_br.c | 35 +++
|
||||
net/bridge/br_sysfs_if.c | 2 +
|
||||
net/bridge/br_vlan_tunnel.c | 3 +
|
||||
15 files changed, 555 insertions(+), 3 deletions(-)
|
||||
create mode 100644 net/bridge/br_offload.c
|
||||
create mode 100644 net/bridge/br_private_offload.h
|
||||
|
||||
--- a/include/linux/if_bridge.h
|
||||
+++ b/include/linux/if_bridge.h
|
||||
@@ -59,6 +59,7 @@ struct br_ip_list {
|
||||
#define BR_MRP_LOST_IN_CONT BIT(19)
|
||||
#define BR_TX_FWD_OFFLOAD BIT(20)
|
||||
#define BR_BPDU_FILTER BIT(21)
|
||||
+#define BR_OFFLOAD BIT(22)
|
||||
|
||||
#define BR_DEFAULT_AGEING_TIME (300 * HZ)
|
||||
|
||||
--- a/net/bridge/Makefile
|
||||
+++ b/net/bridge/Makefile
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
obj-$(CONFIG_BRIDGE) += bridge.o
|
||||
|
||||
-bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
|
||||
+bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o br_offload.o \
|
||||
br_ioctl.o br_stp.o br_stp_bpdu.o \
|
||||
br_stp_if.o br_stp_timer.o br_netlink.o \
|
||||
br_netlink_tunnel.o br_arp_nd_proxy.o
|
||||
--- a/net/bridge/br.c
|
||||
+++ b/net/bridge/br.c
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <net/switchdev.h>
|
||||
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/*
|
||||
* Handle changes in state of network devices enslaved to a bridge.
|
||||
@@ -381,6 +382,10 @@ static int __init br_init(void)
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
+ err = br_offload_init();
|
||||
+ if (err)
|
||||
+ goto err_out0;
|
||||
+
|
||||
err = register_pernet_subsys(&br_net_ops);
|
||||
if (err)
|
||||
goto err_out1;
|
||||
@@ -430,6 +435,8 @@ err_out3:
|
||||
err_out2:
|
||||
unregister_pernet_subsys(&br_net_ops);
|
||||
err_out1:
|
||||
+ br_offload_fini();
|
||||
+err_out0:
|
||||
br_fdb_fini();
|
||||
err_out:
|
||||
stp_proto_unregister(&br_stp_proto);
|
||||
@@ -452,6 +459,7 @@ static void __exit br_deinit(void)
|
||||
#if IS_ENABLED(CONFIG_ATM_LANE)
|
||||
br_fdb_test_addr_hook = NULL;
|
||||
#endif
|
||||
+ br_offload_fini();
|
||||
br_fdb_fini();
|
||||
}
|
||||
|
||||
--- a/net/bridge/br_device.c
|
||||
+++ b/net/bridge/br_device.c
|
||||
@@ -524,6 +524,8 @@ void br_dev_setup(struct net_device *dev
|
||||
br->bridge_hello_time = br->hello_time = 2 * HZ;
|
||||
br->bridge_forward_delay = br->forward_delay = 15 * HZ;
|
||||
br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME;
|
||||
+ br->offload_cache_size = 128;
|
||||
+ br->offload_cache_reserved = 8;
|
||||
dev->max_mtu = ETH_MAX_MTU;
|
||||
|
||||
br_netfilter_rtable_init(br);
|
||||
--- a/net/bridge/br_fdb.c
|
||||
+++ b/net/bridge/br_fdb.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <net/switchdev.h>
|
||||
#include <trace/events/bridge.h>
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
static const struct rhashtable_params br_fdb_rht_params = {
|
||||
.head_offset = offsetof(struct net_bridge_fdb_entry, rhnode),
|
||||
@@ -518,6 +519,8 @@ static struct net_bridge_fdb_entry *fdb_
|
||||
fdb->key.vlan_id = vid;
|
||||
fdb->flags = flags;
|
||||
fdb->updated = fdb->used = jiffies;
|
||||
+ INIT_HLIST_HEAD(&fdb->offload_in);
|
||||
+ INIT_HLIST_HEAD(&fdb->offload_out);
|
||||
if (rhashtable_lookup_insert_fast(&br->fdb_hash_tbl,
|
||||
&fdb->rhnode,
|
||||
br_fdb_rht_params)) {
|
||||
@@ -794,6 +797,8 @@ static void fdb_notify(struct net_bridge
|
||||
struct sk_buff *skb;
|
||||
int err = -ENOBUFS;
|
||||
|
||||
+ br_offload_fdb_update(fdb);
|
||||
+
|
||||
if (swdev_notify)
|
||||
br_switchdev_fdb_notify(br, fdb, type);
|
||||
|
||||
--- a/net/bridge/br_forward.c
|
||||
+++ b/net/bridge/br_forward.c
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/* Don't forward packets to originating port or forwarding disabled */
|
||||
static inline int should_deliver(const struct net_bridge_port *p,
|
||||
@@ -32,6 +33,8 @@ static inline int should_deliver(const s
|
||||
|
||||
int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
+ br_offload_output(skb);
|
||||
+
|
||||
skb_push(skb, ETH_HLEN);
|
||||
if (!is_skb_forwardable(skb->dev, skb))
|
||||
goto drop;
|
||||
--- a/net/bridge/br_if.c
|
||||
+++ b/net/bridge/br_if.c
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/*
|
||||
* Determine initial path cost based on speed.
|
||||
@@ -428,7 +429,7 @@ static struct net_bridge_port *new_nbp(s
|
||||
p->path_cost = port_cost(dev);
|
||||
p->priority = 0x8000 >> BR_PORT_BITS;
|
||||
p->port_no = index;
|
||||
- p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
|
||||
+ p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD | BR_OFFLOAD;
|
||||
br_init_port(p);
|
||||
br_set_state(p, BR_STATE_DISABLED);
|
||||
br_stp_port_timer_init(p);
|
||||
@@ -771,6 +772,9 @@ void br_port_flags_change(struct net_bri
|
||||
|
||||
if (mask & BR_NEIGH_SUPPRESS)
|
||||
br_recalculate_neigh_suppress_enabled(br);
|
||||
+
|
||||
+ if (mask & BR_OFFLOAD)
|
||||
+ br_offload_port_state(p);
|
||||
}
|
||||
|
||||
bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag)
|
||||
--- a/net/bridge/br_input.c
|
||||
+++ b/net/bridge/br_input.c
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/rculist.h>
|
||||
#include "br_private.h"
|
||||
#include "br_private_tunnel.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
static int
|
||||
br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
@@ -171,6 +172,7 @@ int br_handle_frame_finish(struct net *n
|
||||
dst->used = now;
|
||||
br_forward(dst->dst, skb, local_rcv, false);
|
||||
} else {
|
||||
+ br_offload_skb_disable(skb);
|
||||
if (!mcast_hit)
|
||||
br_flood(br, skb, pkt_type, local_rcv, false);
|
||||
else
|
||||
@@ -304,6 +306,9 @@ static rx_handler_result_t br_handle_fra
|
||||
memset(skb->cb, 0, sizeof(struct br_input_skb_cb));
|
||||
|
||||
p = br_port_get_rcu(skb->dev);
|
||||
+ if (br_offload_input(p, skb))
|
||||
+ return RX_HANDLER_CONSUMED;
|
||||
+
|
||||
if (p->flags & BR_VLAN_TUNNEL)
|
||||
br_handle_ingress_vlan_tunnel(skb, p, nbp_vlan_group_rcu(p));
|
||||
|
||||
--- /dev/null
|
||||
+++ b/net/bridge/br_offload.c
|
||||
@@ -0,0 +1,438 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
+
|
||||
+static DEFINE_SPINLOCK(offload_lock);
|
||||
+
|
||||
+struct bridge_flow_key {
|
||||
+ u8 dest[ETH_ALEN];
|
||||
+ u8 src[ETH_ALEN];
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ u16 vlan_tag;
|
||||
+ bool vlan_present;
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+struct bridge_flow {
|
||||
+ struct net_bridge_port *port;
|
||||
+ struct rhash_head node;
|
||||
+ struct bridge_flow_key key;
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ bool vlan_out_present;
|
||||
+ u16 vlan_out;
|
||||
+#endif
|
||||
+
|
||||
+ unsigned long used;
|
||||
+ struct net_bridge_fdb_entry *fdb_in, *fdb_out;
|
||||
+ struct hlist_node fdb_list_in, fdb_list_out;
|
||||
+
|
||||
+ struct rcu_head rcu;
|
||||
+};
|
||||
+
|
||||
+static const struct rhashtable_params flow_params = {
|
||||
+ .automatic_shrinking = true,
|
||||
+ .head_offset = offsetof(struct bridge_flow, node),
|
||||
+ .key_len = sizeof(struct bridge_flow_key),
|
||||
+ .key_offset = offsetof(struct bridge_flow, key),
|
||||
+};
|
||||
+
|
||||
+static struct kmem_cache *offload_cache __read_mostly;
|
||||
+
|
||||
+static void
|
||||
+flow_rcu_free(struct rcu_head *head)
|
||||
+{
|
||||
+ struct bridge_flow *flow;
|
||||
+
|
||||
+ flow = container_of(head, struct bridge_flow, rcu);
|
||||
+ kmem_cache_free(offload_cache, flow);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+__br_offload_flow_free(struct bridge_flow *flow)
|
||||
+{
|
||||
+ flow->used = 0;
|
||||
+ hlist_del(&flow->fdb_list_in);
|
||||
+ hlist_del(&flow->fdb_list_out);
|
||||
+
|
||||
+ call_rcu(&flow->rcu, flow_rcu_free);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_flow_free(struct bridge_flow *flow)
|
||||
+{
|
||||
+ if (rhashtable_remove_fast(&flow->port->offload.rht, &flow->node,
|
||||
+ flow_params) != 0)
|
||||
+ return;
|
||||
+
|
||||
+ __br_offload_flow_free(flow);
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+br_offload_flow_fdb_refresh_time(struct bridge_flow *flow,
|
||||
+ struct net_bridge_fdb_entry *fdb)
|
||||
+{
|
||||
+ if (!time_after(flow->used, fdb->updated))
|
||||
+ return false;
|
||||
+
|
||||
+ fdb->updated = flow->used;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static void
|
||||
+br_offload_flow_refresh_time(struct bridge_flow *flow)
|
||||
+{
|
||||
+ br_offload_flow_fdb_refresh_time(flow, flow->fdb_in);
|
||||
+ br_offload_flow_fdb_refresh_time(flow, flow->fdb_out);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_destroy_cb(void *ptr, void *arg)
|
||||
+{
|
||||
+ struct bridge_flow *flow = ptr;
|
||||
+
|
||||
+ __br_offload_flow_free(flow);
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+br_offload_need_gc(struct net_bridge_port *p)
|
||||
+{
|
||||
+ return (atomic_read(&p->offload.rht.nelems) +
|
||||
+ p->br->offload_cache_reserved) >= p->br->offload_cache_size;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_gc_work(struct work_struct *work)
|
||||
+{
|
||||
+ struct rhashtable_iter hti;
|
||||
+ struct net_bridge_port *p;
|
||||
+ struct bridge_flow *gc_flow = NULL;
|
||||
+ struct bridge_flow *flow;
|
||||
+ unsigned long gc_used;
|
||||
+
|
||||
+ p = container_of(work, struct net_bridge_port, offload.gc_work);
|
||||
+
|
||||
+ if (!br_offload_need_gc(p))
|
||||
+ return;
|
||||
+
|
||||
+ rhashtable_walk_enter(&p->offload.rht, &hti);
|
||||
+ rhashtable_walk_start(&hti);
|
||||
+ while ((flow = rhashtable_walk_next(&hti)) != NULL) {
|
||||
+ unsigned long used;
|
||||
+
|
||||
+ if (IS_ERR(flow))
|
||||
+ continue;
|
||||
+
|
||||
+ used = READ_ONCE(flow->used);
|
||||
+ if (!used)
|
||||
+ continue;
|
||||
+
|
||||
+ if (gc_flow && !time_before(used, gc_used))
|
||||
+ continue;
|
||||
+
|
||||
+ gc_flow = flow;
|
||||
+ gc_used = used;
|
||||
+ }
|
||||
+ rhashtable_walk_stop(&hti);
|
||||
+ rhashtable_walk_exit(&hti);
|
||||
+
|
||||
+ if (!gc_flow)
|
||||
+ return;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+ if (br_offload_need_gc(p) && gc_flow &&
|
||||
+ gc_flow->used == gc_used)
|
||||
+ br_offload_flow_free(gc_flow);
|
||||
+ if (p->offload.enabled && br_offload_need_gc(p))
|
||||
+ queue_work(system_long_wq, work);
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+
|
||||
+}
|
||||
+
|
||||
+void br_offload_port_state(struct net_bridge_port *p)
|
||||
+{
|
||||
+ struct net_bridge_port_offload *o = &p->offload;
|
||||
+ bool enabled = true;
|
||||
+ bool flush = false;
|
||||
+
|
||||
+ if (p->state != BR_STATE_FORWARDING ||
|
||||
+ !(p->flags & BR_OFFLOAD))
|
||||
+ enabled = false;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+ if (o->enabled == enabled)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (enabled) {
|
||||
+ if (!o->gc_work.func)
|
||||
+ INIT_WORK(&o->gc_work, br_offload_gc_work);
|
||||
+ rhashtable_init(&o->rht, &flow_params);
|
||||
+ } else {
|
||||
+ flush = true;
|
||||
+ rhashtable_free_and_destroy(&o->rht, br_offload_destroy_cb, o);
|
||||
+ }
|
||||
+
|
||||
+ o->enabled = enabled;
|
||||
+
|
||||
+out:
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+
|
||||
+ if (flush)
|
||||
+ flush_work(&o->gc_work);
|
||||
+}
|
||||
+
|
||||
+void br_offload_fdb_update(const struct net_bridge_fdb_entry *fdb)
|
||||
+{
|
||||
+ struct bridge_flow *f;
|
||||
+ struct hlist_node *tmp;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+
|
||||
+ hlist_for_each_entry_safe(f, tmp, &fdb->offload_in, fdb_list_in)
|
||||
+ br_offload_flow_free(f);
|
||||
+
|
||||
+ hlist_for_each_entry_safe(f, tmp, &fdb->offload_out, fdb_list_out)
|
||||
+ br_offload_flow_free(f);
|
||||
+
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_prepare_key(struct net_bridge_port *p, struct bridge_flow_key *key,
|
||||
+ struct sk_buff *skb)
|
||||
+{
|
||||
+ memset(key, 0, sizeof(*key));
|
||||
+ memcpy(key, eth_hdr(skb), 2 * ETH_ALEN);
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ if (!br_opt_get(p->br, BROPT_VLAN_ENABLED))
|
||||
+ return;
|
||||
+
|
||||
+ if (!skb_vlan_tag_present(skb) || skb->vlan_proto != p->br->vlan_proto)
|
||||
+ return;
|
||||
+
|
||||
+ key->vlan_present = true;
|
||||
+ key->vlan_tag = skb_vlan_tag_get_id(skb);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+void br_offload_output(struct sk_buff *skb)
|
||||
+{
|
||||
+ struct net_bridge_port_offload *o;
|
||||
+ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
|
||||
+ struct net_bridge_port *p, *inp;
|
||||
+ struct net_device *dev;
|
||||
+ struct net_bridge_fdb_entry *fdb_in, *fdb_out;
|
||||
+ struct net_bridge_vlan_group *vg;
|
||||
+ struct bridge_flow_key key;
|
||||
+ struct bridge_flow *flow;
|
||||
+ u16 vlan;
|
||||
+
|
||||
+ if (!cb->offload)
|
||||
+ return;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+
|
||||
+ p = br_port_get_rcu(skb->dev);
|
||||
+ if (!p)
|
||||
+ goto out;
|
||||
+
|
||||
+ o = &p->offload;
|
||||
+ if (!o->enabled)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (atomic_read(&p->offload.rht.nelems) >= p->br->offload_cache_size)
|
||||
+ goto out;
|
||||
+
|
||||
+ dev = dev_get_by_index_rcu(dev_net(p->br->dev), cb->input_ifindex);
|
||||
+ if (!dev)
|
||||
+ goto out;
|
||||
+
|
||||
+ inp = br_port_get_rcu(dev);
|
||||
+ if (!inp)
|
||||
+ goto out;
|
||||
+
|
||||
+ vg = nbp_vlan_group_rcu(inp);
|
||||
+ vlan = cb->input_vlan_present ? cb->input_vlan_tag : br_get_pvid(vg);
|
||||
+ fdb_in = br_fdb_find_rcu(p->br, eth_hdr(skb)->h_source, vlan);
|
||||
+ if (!fdb_in || !fdb_in->dst)
|
||||
+ goto out;
|
||||
+
|
||||
+ vg = nbp_vlan_group_rcu(p);
|
||||
+ vlan = skb_vlan_tag_present(skb) ? skb_vlan_tag_get_id(skb) : br_get_pvid(vg);
|
||||
+ fdb_out = br_fdb_find_rcu(p->br, eth_hdr(skb)->h_dest, vlan);
|
||||
+ if (!fdb_out || !fdb_out->dst)
|
||||
+ goto out;
|
||||
+
|
||||
+ br_offload_prepare_key(p, &key, skb);
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ key.vlan_present = cb->input_vlan_present;
|
||||
+ key.vlan_tag = cb->input_vlan_tag;
|
||||
+#endif
|
||||
+
|
||||
+ flow = kmem_cache_alloc(offload_cache, GFP_ATOMIC);
|
||||
+ flow->port = inp;
|
||||
+ memcpy(&flow->key, &key, sizeof(key));
|
||||
+
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ flow->vlan_out_present = skb_vlan_tag_present(skb);
|
||||
+ flow->vlan_out = skb_vlan_tag_get(skb);
|
||||
+#endif
|
||||
+
|
||||
+ flow->fdb_in = fdb_in;
|
||||
+ flow->fdb_out = fdb_out;
|
||||
+ flow->used = jiffies;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+ if (!o->enabled ||
|
||||
+ atomic_read(&p->offload.rht.nelems) >= p->br->offload_cache_size ||
|
||||
+ rhashtable_insert_fast(&inp->offload.rht, &flow->node, flow_params)) {
|
||||
+ kmem_cache_free(offload_cache, flow);
|
||||
+ goto out_unlock;
|
||||
+ }
|
||||
+
|
||||
+ hlist_add_head(&flow->fdb_list_in, &fdb_in->offload_in);
|
||||
+ hlist_add_head(&flow->fdb_list_out, &fdb_out->offload_out);
|
||||
+
|
||||
+ if (br_offload_need_gc(p))
|
||||
+ queue_work(system_long_wq, &p->offload.gc_work);
|
||||
+
|
||||
+out_unlock:
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+
|
||||
+out:
|
||||
+ rcu_read_unlock();
|
||||
+}
|
||||
+
|
||||
+bool br_offload_input(struct net_bridge_port *p, struct sk_buff *skb)
|
||||
+{
|
||||
+ struct net_bridge_port_offload *o = &p->offload;
|
||||
+ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
|
||||
+ struct bridge_flow_key key;
|
||||
+ struct net_bridge_port *dst;
|
||||
+ struct bridge_flow *flow;
|
||||
+ unsigned long now = jiffies;
|
||||
+ bool ret = false;
|
||||
+
|
||||
+ if (skb->len < sizeof(key))
|
||||
+ return false;
|
||||
+
|
||||
+ if (!o->enabled)
|
||||
+ return false;
|
||||
+
|
||||
+ if (is_multicast_ether_addr(eth_hdr(skb)->h_dest))
|
||||
+ return false;
|
||||
+
|
||||
+ br_offload_prepare_key(p, &key, skb);
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ flow = rhashtable_lookup(&o->rht, &key, flow_params);
|
||||
+ if (!flow) {
|
||||
+ cb->offload = 1;
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ cb->input_vlan_present = key.vlan_present != 0;
|
||||
+ cb->input_vlan_tag = key.vlan_tag;
|
||||
+#endif
|
||||
+ cb->input_ifindex = p->dev->ifindex;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (flow->fdb_in->dst != p)
|
||||
+ goto out;
|
||||
+
|
||||
+ dst = flow->fdb_out->dst;
|
||||
+ if (!dst)
|
||||
+ goto out;
|
||||
+
|
||||
+ ret = true;
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ if (!flow->vlan_out_present && key.vlan_present) {
|
||||
+ __vlan_hwaccel_clear_tag(skb);
|
||||
+ } else if (flow->vlan_out_present) {
|
||||
+ if (skb_vlan_tag_present(skb) &&
|
||||
+ skb->vlan_proto != p->br->vlan_proto) {
|
||||
+ /* Protocol-mismatch, empty out vlan_tci for new tag */
|
||||
+ skb_push(skb, ETH_HLEN);
|
||||
+ skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto,
|
||||
+ skb_vlan_tag_get(skb));
|
||||
+ if (unlikely(!skb))
|
||||
+ goto out;
|
||||
+
|
||||
+ skb_pull(skb, ETH_HLEN);
|
||||
+ skb_reset_mac_len(skb);
|
||||
+ }
|
||||
+
|
||||
+ __vlan_hwaccel_put_tag(skb, p->br->vlan_proto,
|
||||
+ flow->vlan_out);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ skb->dev = dst->dev;
|
||||
+ skb_push(skb, ETH_HLEN);
|
||||
+
|
||||
+ if (skb_warn_if_lro(skb) || !is_skb_forwardable(skb->dev, skb)) {
|
||||
+ kfree_skb(skb);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (now - flow->used >= HZ) {
|
||||
+ flow->used = now;
|
||||
+ br_offload_flow_refresh_time(flow);
|
||||
+ }
|
||||
+
|
||||
+ skb_forward_csum(skb);
|
||||
+ dev_queue_xmit(skb);
|
||||
+
|
||||
+out:
|
||||
+ rcu_read_unlock();
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_check_gc(struct net_bridge *br)
|
||||
+{
|
||||
+ struct net_bridge_port *p;
|
||||
+
|
||||
+ spin_lock_bh(&br->lock);
|
||||
+ list_for_each_entry(p, &br->port_list, list)
|
||||
+ if (br_offload_need_gc(p))
|
||||
+ queue_work(system_long_wq, &p->offload.gc_work);
|
||||
+ spin_unlock_bh(&br->lock);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+int br_offload_set_cache_size(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ br->offload_cache_size = val;
|
||||
+ br_offload_check_gc(br);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int br_offload_set_cache_reserved(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ br->offload_cache_reserved = val;
|
||||
+ br_offload_check_gc(br);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int __init br_offload_init(void)
|
||||
+{
|
||||
+ offload_cache = kmem_cache_create("bridge_offload_cache",
|
||||
+ sizeof(struct bridge_flow),
|
||||
+ 0, SLAB_HWCACHE_ALIGN, NULL);
|
||||
+ if (!offload_cache)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void br_offload_fini(void)
|
||||
+{
|
||||
+ kmem_cache_destroy(offload_cache);
|
||||
+}
|
||||
--- a/net/bridge/br_private.h
|
||||
+++ b/net/bridge/br_private.h
|
||||
@@ -268,7 +268,13 @@ struct net_bridge_fdb_entry {
|
||||
unsigned long updated ____cacheline_aligned_in_smp;
|
||||
unsigned long used;
|
||||
|
||||
- struct rcu_head rcu;
|
||||
+ union {
|
||||
+ struct {
|
||||
+ struct hlist_head offload_in;
|
||||
+ struct hlist_head offload_out;
|
||||
+ };
|
||||
+ struct rcu_head rcu;
|
||||
+ };
|
||||
};
|
||||
|
||||
#define MDB_PG_FLAGS_PERMANENT BIT(0)
|
||||
@@ -343,6 +349,12 @@ struct net_bridge_mdb_entry {
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
+struct net_bridge_port_offload {
|
||||
+ struct rhashtable rht;
|
||||
+ struct work_struct gc_work;
|
||||
+ bool enabled;
|
||||
+};
|
||||
+
|
||||
struct net_bridge_port {
|
||||
struct net_bridge *br;
|
||||
struct net_device *dev;
|
||||
@@ -403,6 +415,7 @@ struct net_bridge_port {
|
||||
u16 backup_redirected_cnt;
|
||||
|
||||
struct bridge_stp_xstats stp_xstats;
|
||||
+ struct net_bridge_port_offload offload;
|
||||
};
|
||||
|
||||
#define kobj_to_brport(obj) container_of(obj, struct net_bridge_port, kobj)
|
||||
@@ -519,6 +532,9 @@ struct net_bridge {
|
||||
struct kobject *ifobj;
|
||||
u32 auto_cnt;
|
||||
|
||||
+ u32 offload_cache_size;
|
||||
+ u32 offload_cache_reserved;
|
||||
+
|
||||
#ifdef CONFIG_NET_SWITCHDEV
|
||||
/* Counter used to make sure that hardware domains get unique
|
||||
* identifiers in case a bridge spans multiple switchdev instances.
|
||||
@@ -553,6 +569,10 @@ struct br_input_skb_cb {
|
||||
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
|
||||
u8 br_netfilter_broute:1;
|
||||
#endif
|
||||
+ u8 offload:1;
|
||||
+ u8 input_vlan_present:1;
|
||||
+ u16 input_vlan_tag;
|
||||
+ int input_ifindex;
|
||||
|
||||
#ifdef CONFIG_NET_SWITCHDEV
|
||||
/* Set if TX data plane offloading is used towards at least one
|
||||
--- /dev/null
|
||||
+++ b/net/bridge/br_private_offload.h
|
||||
@@ -0,0 +1,23 @@
|
||||
+#ifndef __BR_OFFLOAD_H
|
||||
+#define __BR_OFFLOAD_H
|
||||
+
|
||||
+bool br_offload_input(struct net_bridge_port *p, struct sk_buff *skb);
|
||||
+void br_offload_output(struct sk_buff *skb);
|
||||
+void br_offload_port_state(struct net_bridge_port *p);
|
||||
+void br_offload_fdb_update(const struct net_bridge_fdb_entry *fdb);
|
||||
+int br_offload_init(void);
|
||||
+void br_offload_fini(void);
|
||||
+int br_offload_set_cache_size(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack);
|
||||
+int br_offload_set_cache_reserved(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack);
|
||||
+
|
||||
+static inline void br_offload_skb_disable(struct sk_buff *skb)
|
||||
+{
|
||||
+ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
|
||||
+
|
||||
+ if (cb->offload)
|
||||
+ cb->offload = 0;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
--- a/net/bridge/br_stp.c
|
||||
+++ b/net/bridge/br_stp.c
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "br_private.h"
|
||||
#include "br_private_stp.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/* since time values in bpdu are in jiffies and then scaled (1/256)
|
||||
* before sending, make sure that is at least one STP tick.
|
||||
@@ -52,6 +53,8 @@ void br_set_state(struct net_bridge_port
|
||||
(unsigned int) p->port_no, p->dev->name,
|
||||
br_port_state_names[p->state]);
|
||||
|
||||
+ br_offload_port_state(p);
|
||||
+
|
||||
if (p->br->stp_enabled == BR_KERNEL_STP) {
|
||||
switch (p->state) {
|
||||
case BR_STATE_BLOCKING:
|
||||
--- a/net/bridge/br_sysfs_br.c
|
||||
+++ b/net/bridge/br_sysfs_br.c
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/sched/signal.h>
|
||||
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/* IMPORTANT: new bridge options must be added with netlink support only
|
||||
* please do not add new sysfs entries
|
||||
@@ -930,6 +931,38 @@ static ssize_t vlan_stats_per_port_store
|
||||
static DEVICE_ATTR_RW(vlan_stats_per_port);
|
||||
#endif
|
||||
|
||||
+static ssize_t offload_cache_size_show(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct net_bridge *br = to_bridge(d);
|
||||
+ return sprintf(buf, "%u\n", br->offload_cache_size);
|
||||
+}
|
||||
+
|
||||
+static ssize_t offload_cache_size_store(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t len)
|
||||
+{
|
||||
+ return store_bridge_parm(d, buf, len, br_offload_set_cache_size);
|
||||
+}
|
||||
+static DEVICE_ATTR_RW(offload_cache_size);
|
||||
+
|
||||
+static ssize_t offload_cache_reserved_show(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct net_bridge *br = to_bridge(d);
|
||||
+ return sprintf(buf, "%u\n", br->offload_cache_reserved);
|
||||
+}
|
||||
+
|
||||
+static ssize_t offload_cache_reserved_store(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t len)
|
||||
+{
|
||||
+ return store_bridge_parm(d, buf, len, br_offload_set_cache_reserved);
|
||||
+}
|
||||
+static DEVICE_ATTR_RW(offload_cache_reserved);
|
||||
+
|
||||
static struct attribute *bridge_attrs[] = {
|
||||
&dev_attr_forward_delay.attr,
|
||||
&dev_attr_hello_time.attr,
|
||||
@@ -984,6 +1017,8 @@ static struct attribute *bridge_attrs[]
|
||||
&dev_attr_vlan_stats_enabled.attr,
|
||||
&dev_attr_vlan_stats_per_port.attr,
|
||||
#endif
|
||||
+ &dev_attr_offload_cache_size.attr,
|
||||
+ &dev_attr_offload_cache_reserved.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
--- a/net/bridge/br_sysfs_if.c
|
||||
+++ b/net/bridge/br_sysfs_if.c
|
||||
@@ -241,6 +241,7 @@ BRPORT_ATTR_FLAG(broadcast_flood, BR_BCA
|
||||
BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS);
|
||||
BRPORT_ATTR_FLAG(isolated, BR_ISOLATED);
|
||||
BRPORT_ATTR_FLAG(bpdu_filter, BR_BPDU_FILTER);
|
||||
+BRPORT_ATTR_FLAG(offload, BR_OFFLOAD);
|
||||
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
|
||||
@@ -295,6 +296,7 @@ static const struct brport_attribute *br
|
||||
&brport_attr_isolated,
|
||||
&brport_attr_bpdu_filter,
|
||||
&brport_attr_backup_port,
|
||||
+ &brport_attr_offload,
|
||||
NULL
|
||||
};
|
||||
|
||||
--- a/net/bridge/br_vlan_tunnel.c
|
||||
+++ b/net/bridge/br_vlan_tunnel.c
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "br_private.h"
|
||||
#include "br_private_tunnel.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
static inline int br_vlan_tunid_cmp(struct rhashtable_compare_arg *arg,
|
||||
const void *ptr)
|
||||
@@ -180,6 +181,7 @@ void br_handle_ingress_vlan_tunnel(struc
|
||||
skb_dst_drop(skb);
|
||||
|
||||
__vlan_hwaccel_put_tag(skb, p->br->vlan_proto, vlan->vid);
|
||||
+ br_offload_skb_disable(skb);
|
||||
}
|
||||
|
||||
int br_handle_egress_vlan_tunnel(struct sk_buff *skb,
|
||||
@@ -201,6 +203,7 @@ int br_handle_egress_vlan_tunnel(struct
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
+ br_offload_skb_disable(skb);
|
||||
tunnel_dst = rcu_dereference(vlan->tinfo.tunnel_dst);
|
||||
if (tunnel_dst && dst_hold_safe(&tunnel_dst->dst))
|
||||
skb_dst_set(skb, &tunnel_dst->dst);
|
||||
@@ -1,846 +0,0 @@
|
||||
From 11c3fae5afa6cac444d12622e2cf5af60a99c1ef Mon Sep 17 00:00:00 2001
|
||||
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
|
||||
Date: Wed, 13 Jul 2022 13:43:15 +0200
|
||||
Subject: [PATCH] net/bridge: add bridge offload
|
||||
|
||||
---
|
||||
include/linux/if_bridge.h | 1 +
|
||||
net/bridge/Makefile | 2 +-
|
||||
net/bridge/br.c | 8 +
|
||||
net/bridge/br_device.c | 2 +
|
||||
net/bridge/br_fdb.c | 5 +
|
||||
net/bridge/br_forward.c | 3 +
|
||||
net/bridge/br_if.c | 6 +-
|
||||
net/bridge/br_input.c | 5 +
|
||||
net/bridge/br_offload.c | 438 ++++++++++++++++++++++++++++++++
|
||||
net/bridge/br_private.h | 22 +-
|
||||
net/bridge/br_private_offload.h | 23 ++
|
||||
net/bridge/br_stp.c | 3 +
|
||||
net/bridge/br_sysfs_br.c | 35 +++
|
||||
net/bridge/br_sysfs_if.c | 2 +
|
||||
net/bridge/br_vlan_tunnel.c | 3 +
|
||||
15 files changed, 555 insertions(+), 3 deletions(-)
|
||||
create mode 100644 net/bridge/br_offload.c
|
||||
create mode 100644 net/bridge/br_private_offload.h
|
||||
|
||||
--- a/include/linux/if_bridge.h
|
||||
+++ b/include/linux/if_bridge.h
|
||||
@@ -60,6 +60,7 @@ struct br_ip_list {
|
||||
#define BR_TX_FWD_OFFLOAD BIT(20)
|
||||
#define BR_PORT_LOCKED BIT(21)
|
||||
#define BR_BPDU_FILTER BIT(22)
|
||||
+#define BR_OFFLOAD BIT(23)
|
||||
|
||||
#define BR_DEFAULT_AGEING_TIME (300 * HZ)
|
||||
|
||||
--- a/net/bridge/Makefile
|
||||
+++ b/net/bridge/Makefile
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
obj-$(CONFIG_BRIDGE) += bridge.o
|
||||
|
||||
-bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
|
||||
+bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o br_offload.o \
|
||||
br_ioctl.o br_stp.o br_stp_bpdu.o \
|
||||
br_stp_if.o br_stp_timer.o br_netlink.o \
|
||||
br_netlink_tunnel.o br_arp_nd_proxy.o
|
||||
--- a/net/bridge/br.c
|
||||
+++ b/net/bridge/br.c
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <net/switchdev.h>
|
||||
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/*
|
||||
* Handle changes in state of network devices enslaved to a bridge.
|
||||
@@ -389,6 +390,10 @@ static int __init br_init(void)
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
+ err = br_offload_init();
|
||||
+ if (err)
|
||||
+ goto err_out0;
|
||||
+
|
||||
err = register_pernet_subsys(&br_net_ops);
|
||||
if (err)
|
||||
goto err_out1;
|
||||
@@ -438,6 +443,8 @@ err_out3:
|
||||
err_out2:
|
||||
unregister_pernet_subsys(&br_net_ops);
|
||||
err_out1:
|
||||
+ br_offload_fini();
|
||||
+err_out0:
|
||||
br_fdb_fini();
|
||||
err_out:
|
||||
stp_proto_unregister(&br_stp_proto);
|
||||
@@ -460,6 +467,7 @@ static void __exit br_deinit(void)
|
||||
#if IS_ENABLED(CONFIG_ATM_LANE)
|
||||
br_fdb_test_addr_hook = NULL;
|
||||
#endif
|
||||
+ br_offload_fini();
|
||||
br_fdb_fini();
|
||||
}
|
||||
|
||||
--- a/net/bridge/br_device.c
|
||||
+++ b/net/bridge/br_device.c
|
||||
@@ -525,6 +525,8 @@ void br_dev_setup(struct net_device *dev
|
||||
br->bridge_hello_time = br->hello_time = 2 * HZ;
|
||||
br->bridge_forward_delay = br->forward_delay = 15 * HZ;
|
||||
br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME;
|
||||
+ br->offload_cache_size = 128;
|
||||
+ br->offload_cache_reserved = 8;
|
||||
dev->max_mtu = ETH_MAX_MTU;
|
||||
|
||||
br_netfilter_rtable_init(br);
|
||||
--- a/net/bridge/br_fdb.c
|
||||
+++ b/net/bridge/br_fdb.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <net/switchdev.h>
|
||||
#include <trace/events/bridge.h>
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
static const struct rhashtable_params br_fdb_rht_params = {
|
||||
.head_offset = offsetof(struct net_bridge_fdb_entry, rhnode),
|
||||
@@ -185,6 +186,8 @@ static void fdb_notify(struct net_bridge
|
||||
struct sk_buff *skb;
|
||||
int err = -ENOBUFS;
|
||||
|
||||
+ br_offload_fdb_update(fdb);
|
||||
+
|
||||
if (swdev_notify)
|
||||
br_switchdev_fdb_notify(br, fdb, type);
|
||||
|
||||
@@ -393,6 +396,8 @@ static struct net_bridge_fdb_entry *fdb_
|
||||
fdb->key.vlan_id = vid;
|
||||
fdb->flags = flags;
|
||||
fdb->updated = fdb->used = jiffies;
|
||||
+ INIT_HLIST_HEAD(&fdb->offload_in);
|
||||
+ INIT_HLIST_HEAD(&fdb->offload_out);
|
||||
err = rhashtable_lookup_insert_fast(&br->fdb_hash_tbl, &fdb->rhnode,
|
||||
br_fdb_rht_params);
|
||||
if (err) {
|
||||
--- a/net/bridge/br_forward.c
|
||||
+++ b/net/bridge/br_forward.c
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/* Don't forward packets to originating port or forwarding disabled */
|
||||
static inline int should_deliver(const struct net_bridge_port *p,
|
||||
@@ -32,6 +33,8 @@ static inline int should_deliver(const s
|
||||
|
||||
int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
+ br_offload_output(skb);
|
||||
+
|
||||
skb_push(skb, ETH_HLEN);
|
||||
if (!is_skb_forwardable(skb->dev, skb))
|
||||
goto drop;
|
||||
--- a/net/bridge/br_if.c
|
||||
+++ b/net/bridge/br_if.c
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/*
|
||||
* Determine initial path cost based on speed.
|
||||
@@ -437,7 +438,7 @@ static struct net_bridge_port *new_nbp(s
|
||||
p->path_cost = port_cost(dev);
|
||||
p->priority = 0x8000 >> BR_PORT_BITS;
|
||||
p->port_no = index;
|
||||
- p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
|
||||
+ p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD | BR_OFFLOAD;
|
||||
br_init_port(p);
|
||||
br_set_state(p, BR_STATE_DISABLED);
|
||||
br_stp_port_timer_init(p);
|
||||
@@ -761,6 +762,9 @@ void br_port_flags_change(struct net_bri
|
||||
|
||||
if (mask & BR_NEIGH_SUPPRESS)
|
||||
br_recalculate_neigh_suppress_enabled(br);
|
||||
+
|
||||
+ if (mask & BR_OFFLOAD)
|
||||
+ br_offload_port_state(p);
|
||||
}
|
||||
|
||||
bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag)
|
||||
--- a/net/bridge/br_input.c
|
||||
+++ b/net/bridge/br_input.c
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/rculist.h>
|
||||
#include "br_private.h"
|
||||
#include "br_private_tunnel.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
static int
|
||||
br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
@@ -189,6 +190,7 @@ int br_handle_frame_finish(struct net *n
|
||||
dst->used = now;
|
||||
br_forward(dst->dst, skb, local_rcv, false);
|
||||
} else {
|
||||
+ br_offload_skb_disable(skb);
|
||||
if (!mcast_hit)
|
||||
br_flood(br, skb, pkt_type, local_rcv, false);
|
||||
else
|
||||
@@ -322,6 +324,9 @@ static rx_handler_result_t br_handle_fra
|
||||
memset(skb->cb, 0, sizeof(struct br_input_skb_cb));
|
||||
|
||||
p = br_port_get_rcu(skb->dev);
|
||||
+ if (br_offload_input(p, skb))
|
||||
+ return RX_HANDLER_CONSUMED;
|
||||
+
|
||||
if (p->flags & BR_VLAN_TUNNEL)
|
||||
br_handle_ingress_vlan_tunnel(skb, p, nbp_vlan_group_rcu(p));
|
||||
|
||||
--- /dev/null
|
||||
+++ b/net/bridge/br_offload.c
|
||||
@@ -0,0 +1,438 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
+
|
||||
+static DEFINE_SPINLOCK(offload_lock);
|
||||
+
|
||||
+struct bridge_flow_key {
|
||||
+ u8 dest[ETH_ALEN];
|
||||
+ u8 src[ETH_ALEN];
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ u16 vlan_tag;
|
||||
+ bool vlan_present;
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+struct bridge_flow {
|
||||
+ struct net_bridge_port *port;
|
||||
+ struct rhash_head node;
|
||||
+ struct bridge_flow_key key;
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ bool vlan_out_present;
|
||||
+ u16 vlan_out;
|
||||
+#endif
|
||||
+
|
||||
+ unsigned long used;
|
||||
+ struct net_bridge_fdb_entry *fdb_in, *fdb_out;
|
||||
+ struct hlist_node fdb_list_in, fdb_list_out;
|
||||
+
|
||||
+ struct rcu_head rcu;
|
||||
+};
|
||||
+
|
||||
+static const struct rhashtable_params flow_params = {
|
||||
+ .automatic_shrinking = true,
|
||||
+ .head_offset = offsetof(struct bridge_flow, node),
|
||||
+ .key_len = sizeof(struct bridge_flow_key),
|
||||
+ .key_offset = offsetof(struct bridge_flow, key),
|
||||
+};
|
||||
+
|
||||
+static struct kmem_cache *offload_cache __read_mostly;
|
||||
+
|
||||
+static void
|
||||
+flow_rcu_free(struct rcu_head *head)
|
||||
+{
|
||||
+ struct bridge_flow *flow;
|
||||
+
|
||||
+ flow = container_of(head, struct bridge_flow, rcu);
|
||||
+ kmem_cache_free(offload_cache, flow);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+__br_offload_flow_free(struct bridge_flow *flow)
|
||||
+{
|
||||
+ flow->used = 0;
|
||||
+ hlist_del(&flow->fdb_list_in);
|
||||
+ hlist_del(&flow->fdb_list_out);
|
||||
+
|
||||
+ call_rcu(&flow->rcu, flow_rcu_free);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_flow_free(struct bridge_flow *flow)
|
||||
+{
|
||||
+ if (rhashtable_remove_fast(&flow->port->offload.rht, &flow->node,
|
||||
+ flow_params) != 0)
|
||||
+ return;
|
||||
+
|
||||
+ __br_offload_flow_free(flow);
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+br_offload_flow_fdb_refresh_time(struct bridge_flow *flow,
|
||||
+ struct net_bridge_fdb_entry *fdb)
|
||||
+{
|
||||
+ if (!time_after(flow->used, fdb->updated))
|
||||
+ return false;
|
||||
+
|
||||
+ fdb->updated = flow->used;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static void
|
||||
+br_offload_flow_refresh_time(struct bridge_flow *flow)
|
||||
+{
|
||||
+ br_offload_flow_fdb_refresh_time(flow, flow->fdb_in);
|
||||
+ br_offload_flow_fdb_refresh_time(flow, flow->fdb_out);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_destroy_cb(void *ptr, void *arg)
|
||||
+{
|
||||
+ struct bridge_flow *flow = ptr;
|
||||
+
|
||||
+ __br_offload_flow_free(flow);
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+br_offload_need_gc(struct net_bridge_port *p)
|
||||
+{
|
||||
+ return (atomic_read(&p->offload.rht.nelems) +
|
||||
+ p->br->offload_cache_reserved) >= p->br->offload_cache_size;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_gc_work(struct work_struct *work)
|
||||
+{
|
||||
+ struct rhashtable_iter hti;
|
||||
+ struct net_bridge_port *p;
|
||||
+ struct bridge_flow *gc_flow = NULL;
|
||||
+ struct bridge_flow *flow;
|
||||
+ unsigned long gc_used;
|
||||
+
|
||||
+ p = container_of(work, struct net_bridge_port, offload.gc_work);
|
||||
+
|
||||
+ if (!br_offload_need_gc(p))
|
||||
+ return;
|
||||
+
|
||||
+ rhashtable_walk_enter(&p->offload.rht, &hti);
|
||||
+ rhashtable_walk_start(&hti);
|
||||
+ while ((flow = rhashtable_walk_next(&hti)) != NULL) {
|
||||
+ unsigned long used;
|
||||
+
|
||||
+ if (IS_ERR(flow))
|
||||
+ continue;
|
||||
+
|
||||
+ used = READ_ONCE(flow->used);
|
||||
+ if (!used)
|
||||
+ continue;
|
||||
+
|
||||
+ if (gc_flow && !time_before(used, gc_used))
|
||||
+ continue;
|
||||
+
|
||||
+ gc_flow = flow;
|
||||
+ gc_used = used;
|
||||
+ }
|
||||
+ rhashtable_walk_stop(&hti);
|
||||
+ rhashtable_walk_exit(&hti);
|
||||
+
|
||||
+ if (!gc_flow)
|
||||
+ return;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+ if (br_offload_need_gc(p) && gc_flow &&
|
||||
+ gc_flow->used == gc_used)
|
||||
+ br_offload_flow_free(gc_flow);
|
||||
+ if (p->offload.enabled && br_offload_need_gc(p))
|
||||
+ queue_work(system_long_wq, work);
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+
|
||||
+}
|
||||
+
|
||||
+void br_offload_port_state(struct net_bridge_port *p)
|
||||
+{
|
||||
+ struct net_bridge_port_offload *o = &p->offload;
|
||||
+ bool enabled = true;
|
||||
+ bool flush = false;
|
||||
+
|
||||
+ if (p->state != BR_STATE_FORWARDING ||
|
||||
+ !(p->flags & BR_OFFLOAD))
|
||||
+ enabled = false;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+ if (o->enabled == enabled)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (enabled) {
|
||||
+ if (!o->gc_work.func)
|
||||
+ INIT_WORK(&o->gc_work, br_offload_gc_work);
|
||||
+ rhashtable_init(&o->rht, &flow_params);
|
||||
+ } else {
|
||||
+ flush = true;
|
||||
+ rhashtable_free_and_destroy(&o->rht, br_offload_destroy_cb, o);
|
||||
+ }
|
||||
+
|
||||
+ o->enabled = enabled;
|
||||
+
|
||||
+out:
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+
|
||||
+ if (flush)
|
||||
+ flush_work(&o->gc_work);
|
||||
+}
|
||||
+
|
||||
+void br_offload_fdb_update(const struct net_bridge_fdb_entry *fdb)
|
||||
+{
|
||||
+ struct bridge_flow *f;
|
||||
+ struct hlist_node *tmp;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+
|
||||
+ hlist_for_each_entry_safe(f, tmp, &fdb->offload_in, fdb_list_in)
|
||||
+ br_offload_flow_free(f);
|
||||
+
|
||||
+ hlist_for_each_entry_safe(f, tmp, &fdb->offload_out, fdb_list_out)
|
||||
+ br_offload_flow_free(f);
|
||||
+
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_prepare_key(struct net_bridge_port *p, struct bridge_flow_key *key,
|
||||
+ struct sk_buff *skb)
|
||||
+{
|
||||
+ memset(key, 0, sizeof(*key));
|
||||
+ memcpy(key, eth_hdr(skb), 2 * ETH_ALEN);
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ if (!br_opt_get(p->br, BROPT_VLAN_ENABLED))
|
||||
+ return;
|
||||
+
|
||||
+ if (!skb_vlan_tag_present(skb) || skb->vlan_proto != p->br->vlan_proto)
|
||||
+ return;
|
||||
+
|
||||
+ key->vlan_present = true;
|
||||
+ key->vlan_tag = skb_vlan_tag_get_id(skb);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+void br_offload_output(struct sk_buff *skb)
|
||||
+{
|
||||
+ struct net_bridge_port_offload *o;
|
||||
+ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
|
||||
+ struct net_bridge_port *p, *inp;
|
||||
+ struct net_device *dev;
|
||||
+ struct net_bridge_fdb_entry *fdb_in, *fdb_out;
|
||||
+ struct net_bridge_vlan_group *vg;
|
||||
+ struct bridge_flow_key key;
|
||||
+ struct bridge_flow *flow;
|
||||
+ u16 vlan;
|
||||
+
|
||||
+ if (!cb->offload)
|
||||
+ return;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+
|
||||
+ p = br_port_get_rcu(skb->dev);
|
||||
+ if (!p)
|
||||
+ goto out;
|
||||
+
|
||||
+ o = &p->offload;
|
||||
+ if (!o->enabled)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (atomic_read(&p->offload.rht.nelems) >= p->br->offload_cache_size)
|
||||
+ goto out;
|
||||
+
|
||||
+ dev = dev_get_by_index_rcu(dev_net(p->br->dev), cb->input_ifindex);
|
||||
+ if (!dev)
|
||||
+ goto out;
|
||||
+
|
||||
+ inp = br_port_get_rcu(dev);
|
||||
+ if (!inp)
|
||||
+ goto out;
|
||||
+
|
||||
+ vg = nbp_vlan_group_rcu(inp);
|
||||
+ vlan = cb->input_vlan_present ? cb->input_vlan_tag : br_get_pvid(vg);
|
||||
+ fdb_in = br_fdb_find_rcu(p->br, eth_hdr(skb)->h_source, vlan);
|
||||
+ if (!fdb_in || !fdb_in->dst)
|
||||
+ goto out;
|
||||
+
|
||||
+ vg = nbp_vlan_group_rcu(p);
|
||||
+ vlan = skb_vlan_tag_present(skb) ? skb_vlan_tag_get_id(skb) : br_get_pvid(vg);
|
||||
+ fdb_out = br_fdb_find_rcu(p->br, eth_hdr(skb)->h_dest, vlan);
|
||||
+ if (!fdb_out || !fdb_out->dst)
|
||||
+ goto out;
|
||||
+
|
||||
+ br_offload_prepare_key(p, &key, skb);
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ key.vlan_present = cb->input_vlan_present;
|
||||
+ key.vlan_tag = cb->input_vlan_tag;
|
||||
+#endif
|
||||
+
|
||||
+ flow = kmem_cache_alloc(offload_cache, GFP_ATOMIC);
|
||||
+ flow->port = inp;
|
||||
+ memcpy(&flow->key, &key, sizeof(key));
|
||||
+
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ flow->vlan_out_present = skb_vlan_tag_present(skb);
|
||||
+ flow->vlan_out = skb_vlan_tag_get(skb);
|
||||
+#endif
|
||||
+
|
||||
+ flow->fdb_in = fdb_in;
|
||||
+ flow->fdb_out = fdb_out;
|
||||
+ flow->used = jiffies;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+ if (!o->enabled ||
|
||||
+ atomic_read(&p->offload.rht.nelems) >= p->br->offload_cache_size ||
|
||||
+ rhashtable_insert_fast(&inp->offload.rht, &flow->node, flow_params)) {
|
||||
+ kmem_cache_free(offload_cache, flow);
|
||||
+ goto out_unlock;
|
||||
+ }
|
||||
+
|
||||
+ hlist_add_head(&flow->fdb_list_in, &fdb_in->offload_in);
|
||||
+ hlist_add_head(&flow->fdb_list_out, &fdb_out->offload_out);
|
||||
+
|
||||
+ if (br_offload_need_gc(p))
|
||||
+ queue_work(system_long_wq, &p->offload.gc_work);
|
||||
+
|
||||
+out_unlock:
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+
|
||||
+out:
|
||||
+ rcu_read_unlock();
|
||||
+}
|
||||
+
|
||||
+bool br_offload_input(struct net_bridge_port *p, struct sk_buff *skb)
|
||||
+{
|
||||
+ struct net_bridge_port_offload *o = &p->offload;
|
||||
+ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
|
||||
+ struct bridge_flow_key key;
|
||||
+ struct net_bridge_port *dst;
|
||||
+ struct bridge_flow *flow;
|
||||
+ unsigned long now = jiffies;
|
||||
+ bool ret = false;
|
||||
+
|
||||
+ if (skb->len < sizeof(key))
|
||||
+ return false;
|
||||
+
|
||||
+ if (!o->enabled)
|
||||
+ return false;
|
||||
+
|
||||
+ if (is_multicast_ether_addr(eth_hdr(skb)->h_dest))
|
||||
+ return false;
|
||||
+
|
||||
+ br_offload_prepare_key(p, &key, skb);
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ flow = rhashtable_lookup(&o->rht, &key, flow_params);
|
||||
+ if (!flow) {
|
||||
+ cb->offload = 1;
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ cb->input_vlan_present = key.vlan_present != 0;
|
||||
+ cb->input_vlan_tag = key.vlan_tag;
|
||||
+#endif
|
||||
+ cb->input_ifindex = p->dev->ifindex;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (flow->fdb_in->dst != p)
|
||||
+ goto out;
|
||||
+
|
||||
+ dst = flow->fdb_out->dst;
|
||||
+ if (!dst)
|
||||
+ goto out;
|
||||
+
|
||||
+ ret = true;
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ if (!flow->vlan_out_present && key.vlan_present) {
|
||||
+ __vlan_hwaccel_clear_tag(skb);
|
||||
+ } else if (flow->vlan_out_present) {
|
||||
+ if (skb_vlan_tag_present(skb) &&
|
||||
+ skb->vlan_proto != p->br->vlan_proto) {
|
||||
+ /* Protocol-mismatch, empty out vlan_tci for new tag */
|
||||
+ skb_push(skb, ETH_HLEN);
|
||||
+ skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto,
|
||||
+ skb_vlan_tag_get(skb));
|
||||
+ if (unlikely(!skb))
|
||||
+ goto out;
|
||||
+
|
||||
+ skb_pull(skb, ETH_HLEN);
|
||||
+ skb_reset_mac_len(skb);
|
||||
+ }
|
||||
+
|
||||
+ __vlan_hwaccel_put_tag(skb, p->br->vlan_proto,
|
||||
+ flow->vlan_out);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ skb->dev = dst->dev;
|
||||
+ skb_push(skb, ETH_HLEN);
|
||||
+
|
||||
+ if (skb_warn_if_lro(skb) || !is_skb_forwardable(skb->dev, skb)) {
|
||||
+ kfree_skb(skb);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (now - flow->used >= HZ) {
|
||||
+ flow->used = now;
|
||||
+ br_offload_flow_refresh_time(flow);
|
||||
+ }
|
||||
+
|
||||
+ skb_forward_csum(skb);
|
||||
+ dev_queue_xmit(skb);
|
||||
+
|
||||
+out:
|
||||
+ rcu_read_unlock();
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_check_gc(struct net_bridge *br)
|
||||
+{
|
||||
+ struct net_bridge_port *p;
|
||||
+
|
||||
+ spin_lock_bh(&br->lock);
|
||||
+ list_for_each_entry(p, &br->port_list, list)
|
||||
+ if (br_offload_need_gc(p))
|
||||
+ queue_work(system_long_wq, &p->offload.gc_work);
|
||||
+ spin_unlock_bh(&br->lock);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+int br_offload_set_cache_size(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ br->offload_cache_size = val;
|
||||
+ br_offload_check_gc(br);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int br_offload_set_cache_reserved(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ br->offload_cache_reserved = val;
|
||||
+ br_offload_check_gc(br);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int __init br_offload_init(void)
|
||||
+{
|
||||
+ offload_cache = kmem_cache_create("bridge_offload_cache",
|
||||
+ sizeof(struct bridge_flow),
|
||||
+ 0, SLAB_HWCACHE_ALIGN, NULL);
|
||||
+ if (!offload_cache)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void br_offload_fini(void)
|
||||
+{
|
||||
+ kmem_cache_destroy(offload_cache);
|
||||
+}
|
||||
--- a/net/bridge/br_private.h
|
||||
+++ b/net/bridge/br_private.h
|
||||
@@ -271,7 +271,13 @@ struct net_bridge_fdb_entry {
|
||||
unsigned long updated ____cacheline_aligned_in_smp;
|
||||
unsigned long used;
|
||||
|
||||
- struct rcu_head rcu;
|
||||
+ union {
|
||||
+ struct {
|
||||
+ struct hlist_head offload_in;
|
||||
+ struct hlist_head offload_out;
|
||||
+ };
|
||||
+ struct rcu_head rcu;
|
||||
+ };
|
||||
};
|
||||
|
||||
struct net_bridge_fdb_flush_desc {
|
||||
@@ -353,6 +359,12 @@ struct net_bridge_mdb_entry {
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
+struct net_bridge_port_offload {
|
||||
+ struct rhashtable rht;
|
||||
+ struct work_struct gc_work;
|
||||
+ bool enabled;
|
||||
+};
|
||||
+
|
||||
struct net_bridge_port {
|
||||
struct net_bridge *br;
|
||||
struct net_device *dev;
|
||||
@@ -414,6 +426,7 @@ struct net_bridge_port {
|
||||
u16 backup_redirected_cnt;
|
||||
|
||||
struct bridge_stp_xstats stp_xstats;
|
||||
+ struct net_bridge_port_offload offload;
|
||||
};
|
||||
|
||||
#define kobj_to_brport(obj) container_of(obj, struct net_bridge_port, kobj)
|
||||
@@ -531,6 +544,9 @@ struct net_bridge {
|
||||
struct kobject *ifobj;
|
||||
u32 auto_cnt;
|
||||
|
||||
+ u32 offload_cache_size;
|
||||
+ u32 offload_cache_reserved;
|
||||
+
|
||||
#ifdef CONFIG_NET_SWITCHDEV
|
||||
/* Counter used to make sure that hardware domains get unique
|
||||
* identifiers in case a bridge spans multiple switchdev instances.
|
||||
@@ -565,6 +581,10 @@ struct br_input_skb_cb {
|
||||
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
|
||||
u8 br_netfilter_broute:1;
|
||||
#endif
|
||||
+ u8 offload:1;
|
||||
+ u8 input_vlan_present:1;
|
||||
+ u16 input_vlan_tag;
|
||||
+ int input_ifindex;
|
||||
|
||||
#ifdef CONFIG_NET_SWITCHDEV
|
||||
/* Set if TX data plane offloading is used towards at least one
|
||||
--- /dev/null
|
||||
+++ b/net/bridge/br_private_offload.h
|
||||
@@ -0,0 +1,23 @@
|
||||
+#ifndef __BR_OFFLOAD_H
|
||||
+#define __BR_OFFLOAD_H
|
||||
+
|
||||
+bool br_offload_input(struct net_bridge_port *p, struct sk_buff *skb);
|
||||
+void br_offload_output(struct sk_buff *skb);
|
||||
+void br_offload_port_state(struct net_bridge_port *p);
|
||||
+void br_offload_fdb_update(const struct net_bridge_fdb_entry *fdb);
|
||||
+int br_offload_init(void);
|
||||
+void br_offload_fini(void);
|
||||
+int br_offload_set_cache_size(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack);
|
||||
+int br_offload_set_cache_reserved(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack);
|
||||
+
|
||||
+static inline void br_offload_skb_disable(struct sk_buff *skb)
|
||||
+{
|
||||
+ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
|
||||
+
|
||||
+ if (cb->offload)
|
||||
+ cb->offload = 0;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
--- a/net/bridge/br_stp.c
|
||||
+++ b/net/bridge/br_stp.c
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "br_private.h"
|
||||
#include "br_private_stp.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/* since time values in bpdu are in jiffies and then scaled (1/256)
|
||||
* before sending, make sure that is at least one STP tick.
|
||||
@@ -58,6 +59,8 @@ void br_set_state(struct net_bridge_port
|
||||
(unsigned int) p->port_no, p->dev->name,
|
||||
br_port_state_names[p->state]);
|
||||
|
||||
+ br_offload_port_state(p);
|
||||
+
|
||||
if (p->br->stp_enabled == BR_KERNEL_STP) {
|
||||
switch (p->state) {
|
||||
case BR_STATE_BLOCKING:
|
||||
--- a/net/bridge/br_sysfs_br.c
|
||||
+++ b/net/bridge/br_sysfs_br.c
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/sched/signal.h>
|
||||
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/* IMPORTANT: new bridge options must be added with netlink support only
|
||||
* please do not add new sysfs entries
|
||||
@@ -933,6 +934,38 @@ static ssize_t vlan_stats_per_port_store
|
||||
static DEVICE_ATTR_RW(vlan_stats_per_port);
|
||||
#endif
|
||||
|
||||
+static ssize_t offload_cache_size_show(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct net_bridge *br = to_bridge(d);
|
||||
+ return sprintf(buf, "%u\n", br->offload_cache_size);
|
||||
+}
|
||||
+
|
||||
+static ssize_t offload_cache_size_store(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t len)
|
||||
+{
|
||||
+ return store_bridge_parm(d, buf, len, br_offload_set_cache_size);
|
||||
+}
|
||||
+static DEVICE_ATTR_RW(offload_cache_size);
|
||||
+
|
||||
+static ssize_t offload_cache_reserved_show(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct net_bridge *br = to_bridge(d);
|
||||
+ return sprintf(buf, "%u\n", br->offload_cache_reserved);
|
||||
+}
|
||||
+
|
||||
+static ssize_t offload_cache_reserved_store(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t len)
|
||||
+{
|
||||
+ return store_bridge_parm(d, buf, len, br_offload_set_cache_reserved);
|
||||
+}
|
||||
+static DEVICE_ATTR_RW(offload_cache_reserved);
|
||||
+
|
||||
static struct attribute *bridge_attrs[] = {
|
||||
&dev_attr_forward_delay.attr,
|
||||
&dev_attr_hello_time.attr,
|
||||
@@ -987,6 +1020,8 @@ static struct attribute *bridge_attrs[]
|
||||
&dev_attr_vlan_stats_enabled.attr,
|
||||
&dev_attr_vlan_stats_per_port.attr,
|
||||
#endif
|
||||
+ &dev_attr_offload_cache_size.attr,
|
||||
+ &dev_attr_offload_cache_reserved.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
--- a/net/bridge/br_sysfs_if.c
|
||||
+++ b/net/bridge/br_sysfs_if.c
|
||||
@@ -241,6 +241,7 @@ BRPORT_ATTR_FLAG(broadcast_flood, BR_BCA
|
||||
BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS);
|
||||
BRPORT_ATTR_FLAG(isolated, BR_ISOLATED);
|
||||
BRPORT_ATTR_FLAG(bpdu_filter, BR_BPDU_FILTER);
|
||||
+BRPORT_ATTR_FLAG(offload, BR_OFFLOAD);
|
||||
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
|
||||
@@ -295,6 +296,7 @@ static const struct brport_attribute *br
|
||||
&brport_attr_isolated,
|
||||
&brport_attr_bpdu_filter,
|
||||
&brport_attr_backup_port,
|
||||
+ &brport_attr_offload,
|
||||
NULL
|
||||
};
|
||||
|
||||
--- a/net/bridge/br_vlan_tunnel.c
|
||||
+++ b/net/bridge/br_vlan_tunnel.c
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "br_private.h"
|
||||
#include "br_private_tunnel.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
static inline int br_vlan_tunid_cmp(struct rhashtable_compare_arg *arg,
|
||||
const void *ptr)
|
||||
@@ -180,6 +181,7 @@ void br_handle_ingress_vlan_tunnel(struc
|
||||
skb_dst_drop(skb);
|
||||
|
||||
__vlan_hwaccel_put_tag(skb, p->br->vlan_proto, vlan->vid);
|
||||
+ br_offload_skb_disable(skb);
|
||||
}
|
||||
|
||||
int br_handle_egress_vlan_tunnel(struct sk_buff *skb,
|
||||
@@ -201,6 +203,7 @@ int br_handle_egress_vlan_tunnel(struct
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
+ br_offload_skb_disable(skb);
|
||||
tunnel_dst = rcu_dereference(vlan->tinfo.tunnel_dst);
|
||||
if (tunnel_dst && dst_hold_safe(&tunnel_dst->dst))
|
||||
skb_dst_set(skb, &tunnel_dst->dst);
|
||||
@@ -87,7 +87,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
if (!net_eq(dev_net(dev), sock_net(sk)))
|
||||
goto drop;
|
||||
|
||||
@@ -3340,6 +3342,7 @@ static int packet_create(struct net *net
|
||||
@@ -3342,6 +3344,7 @@ static int packet_create(struct net *net
|
||||
mutex_init(&po->pg_vec_lock);
|
||||
po->rollover = NULL;
|
||||
po->prot_hook.func = packet_rcv;
|
||||
@@ -95,7 +95,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
if (sock->type == SOCK_PACKET)
|
||||
po->prot_hook.func = packet_rcv_spkt;
|
||||
@@ -3977,6 +3980,16 @@ packet_setsockopt(struct socket *sock, i
|
||||
@@ -3979,6 +3982,16 @@ packet_setsockopt(struct socket *sock, i
|
||||
WRITE_ONCE(po->xmit, val ? packet_direct_xmit : dev_queue_xmit);
|
||||
return 0;
|
||||
}
|
||||
@@ -112,7 +112,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
default:
|
||||
return -ENOPROTOOPT;
|
||||
}
|
||||
@@ -4033,6 +4046,13 @@ static int packet_getsockopt(struct sock
|
||||
@@ -4035,6 +4048,13 @@ static int packet_getsockopt(struct sock
|
||||
case PACKET_VNET_HDR:
|
||||
val = po->has_vnet_hdr;
|
||||
break;
|
||||
|
||||
@@ -161,7 +161,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
struct rtnl_link {
|
||||
rtnl_doit_func doit;
|
||||
@@ -4700,7 +4700,9 @@ int ndo_dflt_bridge_getlink(struct sk_bu
|
||||
@@ -4706,7 +4706,9 @@ int ndo_dflt_bridge_getlink(struct sk_bu
|
||||
brport_nla_put_flag(skb, flags, mask,
|
||||
IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD) ||
|
||||
brport_nla_put_flag(skb, flags, mask,
|
||||
|
||||
@@ -10,12 +10,21 @@ The datasheet [1] explicit describes it as requirement for a reset.
|
||||
|
||||
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
|
||||
---
|
||||
drivers/net/dsa/mt7530.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
drivers/net/dsa/mt7530.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2440,6 +2440,10 @@ mt7531_setup(struct dsa_switch *ds)
|
||||
@@ -2412,7 +2412,7 @@ mt7531_setup(struct dsa_switch *ds)
|
||||
struct mt7530_priv *priv = ds->priv;
|
||||
struct mt7530_dummy_poll p;
|
||||
u32 val, id;
|
||||
- int ret;
|
||||
+ int ret, i;
|
||||
|
||||
/* Reset whole chip through gpio pin or memory-mapped registers for
|
||||
* different type of hardware
|
||||
@@ -2444,6 +2444,10 @@ mt7531_setup(struct dsa_switch *ds)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||
|
||||
--- a/drivers/media/usb/uvc/uvc_driver.c
|
||||
+++ b/drivers/media/usb/uvc/uvc_driver.c
|
||||
@@ -3152,6 +3152,18 @@ static const struct usb_device_id uvc_id
|
||||
@@ -3158,6 +3158,18 @@ static const struct usb_device_id uvc_id
|
||||
.bInterfaceSubClass = 1,
|
||||
.bInterfaceProtocol = 0,
|
||||
.driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) },
|
||||
|
||||
Reference in New Issue
Block a user