Merge bb8f86f40e ("net: export a helper for adding up queue stats") into android16-6.12-lts

Steps on the way to 6.12.29

Change-Id: I176bb12ce2ae5614c558f22d50d03f8588b0d28a
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2025-05-30 13:12:24 +00:00
12 changed files with 340 additions and 199 deletions
+153 -60
View File
@@ -373,15 +373,17 @@ static void b53_enable_vlan(struct b53_device *dev, int port, bool enable,
b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5); b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5);
} }
vc1 &= ~VC1_RX_MCST_FWD_EN;
if (enable) { if (enable) {
vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID; vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID;
vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN; vc1 |= VC1_RX_MCST_UNTAG_EN;
vc4 &= ~VC4_ING_VID_CHECK_MASK; vc4 &= ~VC4_ING_VID_CHECK_MASK;
if (enable_filtering) { if (enable_filtering) {
vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S; vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S;
vc5 |= VC5_DROP_VTABLE_MISS; vc5 |= VC5_DROP_VTABLE_MISS;
} else { } else {
vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S; vc4 |= VC4_NO_ING_VID_CHK << VC4_ING_VID_CHECK_S;
vc5 &= ~VC5_DROP_VTABLE_MISS; vc5 &= ~VC5_DROP_VTABLE_MISS;
} }
@@ -393,7 +395,7 @@ static void b53_enable_vlan(struct b53_device *dev, int port, bool enable,
} else { } else {
vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID); vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID);
vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN); vc1 &= ~VC1_RX_MCST_UNTAG_EN;
vc4 &= ~VC4_ING_VID_CHECK_MASK; vc4 &= ~VC4_ING_VID_CHECK_MASK;
vc5 &= ~VC5_DROP_VTABLE_MISS; vc5 &= ~VC5_DROP_VTABLE_MISS;
@@ -576,6 +578,18 @@ static void b53_eee_enable_set(struct dsa_switch *ds, int port, bool enable)
b53_write16(dev, B53_EEE_PAGE, B53_EEE_EN_CTRL, reg); b53_write16(dev, B53_EEE_PAGE, B53_EEE_EN_CTRL, reg);
} }
int b53_setup_port(struct dsa_switch *ds, int port)
{
struct b53_device *dev = ds->priv;
b53_port_set_ucast_flood(dev, port, true);
b53_port_set_mcast_flood(dev, port, true);
b53_port_set_learning(dev, port, false);
return 0;
}
EXPORT_SYMBOL(b53_setup_port);
int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy) int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
{ {
struct b53_device *dev = ds->priv; struct b53_device *dev = ds->priv;
@@ -588,10 +602,6 @@ int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
cpu_port = dsa_to_port(ds, port)->cpu_dp->index; cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
b53_port_set_ucast_flood(dev, port, true);
b53_port_set_mcast_flood(dev, port, true);
b53_port_set_learning(dev, port, false);
if (dev->ops->irq_enable) if (dev->ops->irq_enable)
ret = dev->ops->irq_enable(dev, port); ret = dev->ops->irq_enable(dev, port);
if (ret) if (ret)
@@ -722,10 +732,6 @@ static void b53_enable_cpu_port(struct b53_device *dev, int port)
b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), port_ctrl); b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), port_ctrl);
b53_brcm_hdr_setup(dev->ds, port); b53_brcm_hdr_setup(dev->ds, port);
b53_port_set_ucast_flood(dev, port, true);
b53_port_set_mcast_flood(dev, port, true);
b53_port_set_learning(dev, port, false);
} }
static void b53_enable_mib(struct b53_device *dev) static void b53_enable_mib(struct b53_device *dev)
@@ -761,6 +767,22 @@ static bool b53_vlan_port_needs_forced_tagged(struct dsa_switch *ds, int port)
return dev->tag_protocol == DSA_TAG_PROTO_NONE && dsa_is_cpu_port(ds, port); return dev->tag_protocol == DSA_TAG_PROTO_NONE && dsa_is_cpu_port(ds, port);
} }
static bool b53_vlan_port_may_join_untagged(struct dsa_switch *ds, int port)
{
struct b53_device *dev = ds->priv;
struct dsa_port *dp;
if (!dev->vlan_filtering)
return true;
dp = dsa_to_port(ds, port);
if (dsa_port_is_cpu(dp))
return true;
return dp->bridge == NULL;
}
int b53_configure_vlan(struct dsa_switch *ds) int b53_configure_vlan(struct dsa_switch *ds)
{ {
struct b53_device *dev = ds->priv; struct b53_device *dev = ds->priv;
@@ -779,7 +801,7 @@ int b53_configure_vlan(struct dsa_switch *ds)
b53_do_vlan_op(dev, VTA_CMD_CLEAR); b53_do_vlan_op(dev, VTA_CMD_CLEAR);
} }
b53_enable_vlan(dev, -1, dev->vlan_enabled, ds->vlan_filtering); b53_enable_vlan(dev, -1, dev->vlan_enabled, dev->vlan_filtering);
/* Create an untagged VLAN entry for the default PVID in case /* Create an untagged VLAN entry for the default PVID in case
* CONFIG_VLAN_8021Q is disabled and there are no calls to * CONFIG_VLAN_8021Q is disabled and there are no calls to
@@ -787,26 +809,39 @@ int b53_configure_vlan(struct dsa_switch *ds)
* entry. Do this only when the tagging protocol is not * entry. Do this only when the tagging protocol is not
* DSA_TAG_PROTO_NONE * DSA_TAG_PROTO_NONE
*/ */
v = &dev->vlans[def_vid];
b53_for_each_port(dev, i) { b53_for_each_port(dev, i) {
v = &dev->vlans[def_vid]; if (!b53_vlan_port_may_join_untagged(ds, i))
v->members |= BIT(i);
if (!b53_vlan_port_needs_forced_tagged(ds, i))
v->untag = v->members;
b53_write16(dev, B53_VLAN_PAGE,
B53_VLAN_PORT_DEF_TAG(i), def_vid);
}
/* Upon initial call we have not set-up any VLANs, but upon
* system resume, we need to restore all VLAN entries.
*/
for (vid = def_vid; vid < dev->num_vlans; vid++) {
v = &dev->vlans[vid];
if (!v->members)
continue; continue;
b53_set_vlan_entry(dev, vid, v); vl.members |= BIT(i);
b53_fast_age_vlan(dev, vid); if (!b53_vlan_port_needs_forced_tagged(ds, i))
vl.untag = vl.members;
b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(i),
def_vid);
}
b53_set_vlan_entry(dev, def_vid, &vl);
if (dev->vlan_filtering) {
/* Upon initial call we have not set-up any VLANs, but upon
* system resume, we need to restore all VLAN entries.
*/
for (vid = def_vid + 1; vid < dev->num_vlans; vid++) {
v = &dev->vlans[vid];
if (!v->members)
continue;
b53_set_vlan_entry(dev, vid, v);
b53_fast_age_vlan(dev, vid);
}
b53_for_each_port(dev, i) {
if (!dsa_is_cpu_port(ds, i))
b53_write16(dev, B53_VLAN_PAGE,
B53_VLAN_PORT_DEF_TAG(i),
dev->ports[i].pvid);
}
} }
return 0; return 0;
@@ -1126,7 +1161,9 @@ EXPORT_SYMBOL(b53_setup_devlink_resources);
static int b53_setup(struct dsa_switch *ds) static int b53_setup(struct dsa_switch *ds)
{ {
struct b53_device *dev = ds->priv; struct b53_device *dev = ds->priv;
struct b53_vlan *vl;
unsigned int port; unsigned int port;
u16 pvid;
int ret; int ret;
/* Request bridge PVID untagged when DSA_TAG_PROTO_NONE is set /* Request bridge PVID untagged when DSA_TAG_PROTO_NONE is set
@@ -1134,12 +1171,26 @@ static int b53_setup(struct dsa_switch *ds)
*/ */
ds->untag_bridge_pvid = dev->tag_protocol == DSA_TAG_PROTO_NONE; ds->untag_bridge_pvid = dev->tag_protocol == DSA_TAG_PROTO_NONE;
/* The switch does not tell us the original VLAN for untagged
* packets, so keep the CPU port always tagged.
*/
ds->untag_vlan_aware_bridge_pvid = true;
ret = b53_reset_switch(dev); ret = b53_reset_switch(dev);
if (ret) { if (ret) {
dev_err(ds->dev, "failed to reset switch\n"); dev_err(ds->dev, "failed to reset switch\n");
return ret; return ret;
} }
/* setup default vlan for filtering mode */
pvid = b53_default_pvid(dev);
vl = &dev->vlans[pvid];
b53_for_each_port(dev, port) {
vl->members |= BIT(port);
if (!b53_vlan_port_needs_forced_tagged(ds, port))
vl->untag |= BIT(port);
}
b53_reset_mib(dev); b53_reset_mib(dev);
ret = b53_apply_config(dev); ret = b53_apply_config(dev);
@@ -1493,7 +1544,10 @@ int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
{ {
struct b53_device *dev = ds->priv; struct b53_device *dev = ds->priv;
b53_enable_vlan(dev, port, dev->vlan_enabled, vlan_filtering); if (dev->vlan_filtering != vlan_filtering) {
dev->vlan_filtering = vlan_filtering;
b53_apply_config(dev);
}
return 0; return 0;
} }
@@ -1518,7 +1572,7 @@ static int b53_vlan_prepare(struct dsa_switch *ds, int port,
if (vlan->vid >= dev->num_vlans) if (vlan->vid >= dev->num_vlans)
return -ERANGE; return -ERANGE;
b53_enable_vlan(dev, port, true, ds->vlan_filtering); b53_enable_vlan(dev, port, true, dev->vlan_filtering);
return 0; return 0;
} }
@@ -1531,18 +1585,29 @@ int b53_vlan_add(struct dsa_switch *ds, int port,
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
struct b53_vlan *vl; struct b53_vlan *vl;
u16 old_pvid, new_pvid;
int err; int err;
err = b53_vlan_prepare(ds, port, vlan); err = b53_vlan_prepare(ds, port, vlan);
if (err) if (err)
return err; return err;
if (vlan->vid == 0)
return 0;
old_pvid = dev->ports[port].pvid;
if (pvid)
new_pvid = vlan->vid;
else if (!pvid && vlan->vid == old_pvid)
new_pvid = b53_default_pvid(dev);
else
new_pvid = old_pvid;
dev->ports[port].pvid = new_pvid;
vl = &dev->vlans[vlan->vid]; vl = &dev->vlans[vlan->vid];
b53_get_vlan_entry(dev, vlan->vid, vl); if (dsa_is_cpu_port(ds, port))
untagged = false;
if (vlan->vid == 0 && vlan->vid == b53_default_pvid(dev))
untagged = true;
vl->members |= BIT(port); vl->members |= BIT(port);
if (untagged && !b53_vlan_port_needs_forced_tagged(ds, port)) if (untagged && !b53_vlan_port_needs_forced_tagged(ds, port))
@@ -1550,13 +1615,16 @@ int b53_vlan_add(struct dsa_switch *ds, int port,
else else
vl->untag &= ~BIT(port); vl->untag &= ~BIT(port);
if (!dev->vlan_filtering)
return 0;
b53_set_vlan_entry(dev, vlan->vid, vl); b53_set_vlan_entry(dev, vlan->vid, vl);
b53_fast_age_vlan(dev, vlan->vid); b53_fast_age_vlan(dev, vlan->vid);
if (pvid && !dsa_is_cpu_port(ds, port)) { if (!dsa_is_cpu_port(ds, port) && new_pvid != old_pvid) {
b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port),
vlan->vid); new_pvid);
b53_fast_age_vlan(dev, vlan->vid); b53_fast_age_vlan(dev, old_pvid);
} }
return 0; return 0;
@@ -1571,20 +1639,25 @@ int b53_vlan_del(struct dsa_switch *ds, int port,
struct b53_vlan *vl; struct b53_vlan *vl;
u16 pvid; u16 pvid;
b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), &pvid); if (vlan->vid == 0)
return 0;
pvid = dev->ports[port].pvid;
vl = &dev->vlans[vlan->vid]; vl = &dev->vlans[vlan->vid];
b53_get_vlan_entry(dev, vlan->vid, vl);
vl->members &= ~BIT(port); vl->members &= ~BIT(port);
if (pvid == vlan->vid) if (pvid == vlan->vid)
pvid = b53_default_pvid(dev); pvid = b53_default_pvid(dev);
dev->ports[port].pvid = pvid;
if (untagged && !b53_vlan_port_needs_forced_tagged(ds, port)) if (untagged && !b53_vlan_port_needs_forced_tagged(ds, port))
vl->untag &= ~(BIT(port)); vl->untag &= ~(BIT(port));
if (!dev->vlan_filtering)
return 0;
b53_set_vlan_entry(dev, vlan->vid, vl); b53_set_vlan_entry(dev, vlan->vid, vl);
b53_fast_age_vlan(dev, vlan->vid); b53_fast_age_vlan(dev, vlan->vid);
@@ -1917,8 +1990,9 @@ int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge,
bool *tx_fwd_offload, struct netlink_ext_ack *extack) bool *tx_fwd_offload, struct netlink_ext_ack *extack)
{ {
struct b53_device *dev = ds->priv; struct b53_device *dev = ds->priv;
struct b53_vlan *vl;
s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
u16 pvlan, reg; u16 pvlan, reg, pvid;
unsigned int i; unsigned int i;
/* On 7278, port 7 which connects to the ASP should only receive /* On 7278, port 7 which connects to the ASP should only receive
@@ -1927,15 +2001,29 @@ int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge,
if (dev->chip_id == BCM7278_DEVICE_ID && port == 7) if (dev->chip_id == BCM7278_DEVICE_ID && port == 7)
return -EINVAL; return -EINVAL;
/* Make this port leave the all VLANs join since we will have proper pvid = b53_default_pvid(dev);
* VLAN entries from now on vl = &dev->vlans[pvid];
*/
if (is58xx(dev)) { if (dev->vlan_filtering) {
b53_read16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN, &reg); /* Make this port leave the all VLANs join since we will have
reg &= ~BIT(port); * proper VLAN entries from now on
if ((reg & BIT(cpu_port)) == BIT(cpu_port)) */
reg &= ~BIT(cpu_port); if (is58xx(dev)) {
b53_write16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN, reg); b53_read16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN,
&reg);
reg &= ~BIT(port);
if ((reg & BIT(cpu_port)) == BIT(cpu_port))
reg &= ~BIT(cpu_port);
b53_write16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN,
reg);
}
b53_get_vlan_entry(dev, pvid, vl);
vl->members &= ~BIT(port);
if (vl->members == BIT(cpu_port))
vl->members &= ~BIT(cpu_port);
vl->untag = vl->members;
b53_set_vlan_entry(dev, pvid, vl);
} }
b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), &pvlan); b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), &pvlan);
@@ -1968,7 +2056,7 @@ EXPORT_SYMBOL(b53_br_join);
void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge) void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge)
{ {
struct b53_device *dev = ds->priv; struct b53_device *dev = ds->priv;
struct b53_vlan *vl = &dev->vlans[0]; struct b53_vlan *vl;
s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
unsigned int i; unsigned int i;
u16 pvlan, reg, pvid; u16 pvlan, reg, pvid;
@@ -1994,15 +2082,18 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge)
dev->ports[port].vlan_ctl_mask = pvlan; dev->ports[port].vlan_ctl_mask = pvlan;
pvid = b53_default_pvid(dev); pvid = b53_default_pvid(dev);
vl = &dev->vlans[pvid];
if (dev->vlan_filtering) {
/* Make this port join all VLANs without VLAN entries */
if (is58xx(dev)) {
b53_read16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN, &reg);
reg |= BIT(port);
if (!(reg & BIT(cpu_port)))
reg |= BIT(cpu_port);
b53_write16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN, reg);
}
/* Make this port join all VLANs without VLAN entries */
if (is58xx(dev)) {
b53_read16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN, &reg);
reg |= BIT(port);
if (!(reg & BIT(cpu_port)))
reg |= BIT(cpu_port);
b53_write16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN, reg);
} else {
b53_get_vlan_entry(dev, pvid, vl); b53_get_vlan_entry(dev, pvid, vl);
vl->members |= BIT(port) | BIT(cpu_port); vl->members |= BIT(port) | BIT(cpu_port);
vl->untag |= BIT(port) | BIT(cpu_port); vl->untag |= BIT(port) | BIT(cpu_port);
@@ -2307,6 +2398,7 @@ static const struct dsa_switch_ops b53_switch_ops = {
.phy_read = b53_phy_read16, .phy_read = b53_phy_read16,
.phy_write = b53_phy_write16, .phy_write = b53_phy_write16,
.phylink_get_caps = b53_phylink_get_caps, .phylink_get_caps = b53_phylink_get_caps,
.port_setup = b53_setup_port,
.port_enable = b53_enable_port, .port_enable = b53_enable_port,
.port_disable = b53_disable_port, .port_disable = b53_disable_port,
.get_mac_eee = b53_get_mac_eee, .get_mac_eee = b53_get_mac_eee,
@@ -2751,6 +2843,7 @@ struct b53_device *b53_switch_alloc(struct device *base,
ds->ops = &b53_switch_ops; ds->ops = &b53_switch_ops;
ds->phylink_mac_ops = &b53_phylink_mac_ops; ds->phylink_mac_ops = &b53_phylink_mac_ops;
dev->vlan_enabled = true; dev->vlan_enabled = true;
dev->vlan_filtering = false;
/* Let DSA handle the case were multiple bridges span the same switch /* Let DSA handle the case were multiple bridges span the same switch
* device and different VLAN awareness settings are requested, which * device and different VLAN awareness settings are requested, which
* would be breaking filtering semantics for any of the other bridge * would be breaking filtering semantics for any of the other bridge
+3
View File
@@ -95,6 +95,7 @@ struct b53_pcs {
struct b53_port { struct b53_port {
u16 vlan_ctl_mask; u16 vlan_ctl_mask;
u16 pvid;
struct ethtool_keee eee; struct ethtool_keee eee;
}; };
@@ -146,6 +147,7 @@ struct b53_device {
unsigned int num_vlans; unsigned int num_vlans;
struct b53_vlan *vlans; struct b53_vlan *vlans;
bool vlan_enabled; bool vlan_enabled;
bool vlan_filtering;
unsigned int num_ports; unsigned int num_ports;
struct b53_port *ports; struct b53_port *ports;
@@ -380,6 +382,7 @@ enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port,
enum dsa_tag_protocol mprot); enum dsa_tag_protocol mprot);
void b53_mirror_del(struct dsa_switch *ds, int port, void b53_mirror_del(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror); struct dsa_mall_mirror_tc_entry *mirror);
int b53_setup_port(struct dsa_switch *ds, int port);
int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy); int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy);
void b53_disable_port(struct dsa_switch *ds, int port); void b53_disable_port(struct dsa_switch *ds, int port);
void b53_brcm_hdr_setup(struct dsa_switch *ds, int port); void b53_brcm_hdr_setup(struct dsa_switch *ds, int port);
+1
View File
@@ -1230,6 +1230,7 @@ static const struct dsa_switch_ops bcm_sf2_ops = {
.resume = bcm_sf2_sw_resume, .resume = bcm_sf2_sw_resume,
.get_wol = bcm_sf2_sw_get_wol, .get_wol = bcm_sf2_sw_get_wol,
.set_wol = bcm_sf2_sw_set_wol, .set_wol = bcm_sf2_sw_set_wol,
.port_setup = b53_setup_port,
.port_enable = bcm_sf2_port_setup, .port_enable = bcm_sf2_port_setup,
.port_disable = bcm_sf2_port_disable, .port_disable = bcm_sf2_port_disable,
.get_mac_eee = b53_get_mac_eee, .get_mac_eee = b53_get_mac_eee,
@@ -700,8 +700,10 @@ enum {
/* PUL User Registers */ /* PUL User Registers */
#define FBNIC_CSR_START_PUL_USER 0x31000 /* CSR section delimiter */ #define FBNIC_CSR_START_PUL_USER 0x31000 /* CSR section delimiter */
#define FBNIC_PUL_OB_TLP_HDR_AW_CFG 0x3103d /* 0xc40f4 */ #define FBNIC_PUL_OB_TLP_HDR_AW_CFG 0x3103d /* 0xc40f4 */
#define FBNIC_PUL_OB_TLP_HDR_AW_CFG_FLUSH CSR_BIT(19)
#define FBNIC_PUL_OB_TLP_HDR_AW_CFG_BME CSR_BIT(18) #define FBNIC_PUL_OB_TLP_HDR_AW_CFG_BME CSR_BIT(18)
#define FBNIC_PUL_OB_TLP_HDR_AR_CFG 0x3103e /* 0xc40f8 */ #define FBNIC_PUL_OB_TLP_HDR_AR_CFG 0x3103e /* 0xc40f8 */
#define FBNIC_PUL_OB_TLP_HDR_AR_CFG_FLUSH CSR_BIT(19)
#define FBNIC_PUL_OB_TLP_HDR_AR_CFG_BME CSR_BIT(18) #define FBNIC_PUL_OB_TLP_HDR_AR_CFG_BME CSR_BIT(18)
#define FBNIC_CSR_END_PUL_USER 0x31080 /* CSR section delimiter */ #define FBNIC_CSR_END_PUL_USER 0x31080 /* CSR section delimiter */
+102 -78
View File
@@ -17,11 +17,29 @@ static void __fbnic_mbx_wr_desc(struct fbnic_dev *fbd, int mbx_idx,
{ {
u32 desc_offset = FBNIC_IPC_MBX(mbx_idx, desc_idx); u32 desc_offset = FBNIC_IPC_MBX(mbx_idx, desc_idx);
/* Write the upper 32b and then the lower 32b. Doing this the
* FW can then read lower, upper, lower to verify that the state
* of the descriptor wasn't changed mid-transaction.
*/
fw_wr32(fbd, desc_offset + 1, upper_32_bits(desc)); fw_wr32(fbd, desc_offset + 1, upper_32_bits(desc));
fw_wrfl(fbd); fw_wrfl(fbd);
fw_wr32(fbd, desc_offset, lower_32_bits(desc)); fw_wr32(fbd, desc_offset, lower_32_bits(desc));
} }
static void __fbnic_mbx_invalidate_desc(struct fbnic_dev *fbd, int mbx_idx,
int desc_idx, u32 desc)
{
u32 desc_offset = FBNIC_IPC_MBX(mbx_idx, desc_idx);
/* For initialization we write the lower 32b of the descriptor first.
* This way we can set the state to mark it invalid before we clear the
* upper 32b.
*/
fw_wr32(fbd, desc_offset, desc);
fw_wrfl(fbd);
fw_wr32(fbd, desc_offset + 1, 0);
}
static u64 __fbnic_mbx_rd_desc(struct fbnic_dev *fbd, int mbx_idx, int desc_idx) static u64 __fbnic_mbx_rd_desc(struct fbnic_dev *fbd, int mbx_idx, int desc_idx)
{ {
u32 desc_offset = FBNIC_IPC_MBX(mbx_idx, desc_idx); u32 desc_offset = FBNIC_IPC_MBX(mbx_idx, desc_idx);
@@ -33,29 +51,41 @@ static u64 __fbnic_mbx_rd_desc(struct fbnic_dev *fbd, int mbx_idx, int desc_idx)
return desc; return desc;
} }
static void fbnic_mbx_init_desc_ring(struct fbnic_dev *fbd, int mbx_idx) static void fbnic_mbx_reset_desc_ring(struct fbnic_dev *fbd, int mbx_idx)
{ {
int desc_idx; int desc_idx;
/* Disable DMA transactions from the device,
* and flush any transactions triggered during cleaning
*/
switch (mbx_idx) {
case FBNIC_IPC_MBX_RX_IDX:
wr32(fbd, FBNIC_PUL_OB_TLP_HDR_AW_CFG,
FBNIC_PUL_OB_TLP_HDR_AW_CFG_FLUSH);
break;
case FBNIC_IPC_MBX_TX_IDX:
wr32(fbd, FBNIC_PUL_OB_TLP_HDR_AR_CFG,
FBNIC_PUL_OB_TLP_HDR_AR_CFG_FLUSH);
break;
}
wrfl(fbd);
/* Initialize first descriptor to all 0s. Doing this gives us a /* Initialize first descriptor to all 0s. Doing this gives us a
* solid stop for the firmware to hit when it is done looping * solid stop for the firmware to hit when it is done looping
* through the ring. * through the ring.
*/ */
__fbnic_mbx_wr_desc(fbd, mbx_idx, 0, 0); __fbnic_mbx_invalidate_desc(fbd, mbx_idx, 0, 0);
fw_wrfl(fbd);
/* We then fill the rest of the ring starting at the end and moving /* We then fill the rest of the ring starting at the end and moving
* back toward descriptor 0 with skip descriptors that have no * back toward descriptor 0 with skip descriptors that have no
* length nor address, and tell the firmware that they can skip * length nor address, and tell the firmware that they can skip
* them and just move past them to the one we initialized to 0. * them and just move past them to the one we initialized to 0.
*/ */
for (desc_idx = FBNIC_IPC_MBX_DESC_LEN; --desc_idx;) { for (desc_idx = FBNIC_IPC_MBX_DESC_LEN; --desc_idx;)
__fbnic_mbx_wr_desc(fbd, mbx_idx, desc_idx, __fbnic_mbx_invalidate_desc(fbd, mbx_idx, desc_idx,
FBNIC_IPC_MBX_DESC_FW_CMPL | FBNIC_IPC_MBX_DESC_FW_CMPL |
FBNIC_IPC_MBX_DESC_HOST_CMPL); FBNIC_IPC_MBX_DESC_HOST_CMPL);
fw_wrfl(fbd);
}
} }
void fbnic_mbx_init(struct fbnic_dev *fbd) void fbnic_mbx_init(struct fbnic_dev *fbd)
@@ -76,7 +106,7 @@ void fbnic_mbx_init(struct fbnic_dev *fbd)
wr32(fbd, FBNIC_INTR_CLEAR(0), 1u << FBNIC_FW_MSIX_ENTRY); wr32(fbd, FBNIC_INTR_CLEAR(0), 1u << FBNIC_FW_MSIX_ENTRY);
for (i = 0; i < FBNIC_IPC_MBX_INDICES; i++) for (i = 0; i < FBNIC_IPC_MBX_INDICES; i++)
fbnic_mbx_init_desc_ring(fbd, i); fbnic_mbx_reset_desc_ring(fbd, i);
} }
static int fbnic_mbx_map_msg(struct fbnic_dev *fbd, int mbx_idx, static int fbnic_mbx_map_msg(struct fbnic_dev *fbd, int mbx_idx,
@@ -141,7 +171,7 @@ static void fbnic_mbx_clean_desc_ring(struct fbnic_dev *fbd, int mbx_idx)
{ {
int i; int i;
fbnic_mbx_init_desc_ring(fbd, mbx_idx); fbnic_mbx_reset_desc_ring(fbd, mbx_idx);
for (i = FBNIC_IPC_MBX_DESC_LEN; i--;) for (i = FBNIC_IPC_MBX_DESC_LEN; i--;)
fbnic_mbx_unmap_and_free_msg(fbd, mbx_idx, i); fbnic_mbx_unmap_and_free_msg(fbd, mbx_idx, i);
@@ -265,67 +295,41 @@ static int fbnic_fw_xmit_simple_msg(struct fbnic_dev *fbd, u32 msg_type)
return err; return err;
} }
/** static void fbnic_mbx_init_desc_ring(struct fbnic_dev *fbd, int mbx_idx)
* fbnic_fw_xmit_cap_msg - Allocate and populate a FW capabilities message
* @fbd: FBNIC device structure
*
* Return: NULL on failure to allocate, error pointer on error, or pointer
* to new TLV test message.
*
* Sends a single TLV header indicating the host wants the firmware to
* confirm the capabilities and version.
**/
static int fbnic_fw_xmit_cap_msg(struct fbnic_dev *fbd)
{
int err = fbnic_fw_xmit_simple_msg(fbd, FBNIC_TLV_MSG_ID_HOST_CAP_REQ);
/* Return 0 if we are not calling this on ASIC */
return (err == -EOPNOTSUPP) ? 0 : err;
}
static void fbnic_mbx_postinit_desc_ring(struct fbnic_dev *fbd, int mbx_idx)
{ {
struct fbnic_fw_mbx *mbx = &fbd->mbx[mbx_idx]; struct fbnic_fw_mbx *mbx = &fbd->mbx[mbx_idx];
/* This is a one time init, so just exit if it is completed */
if (mbx->ready)
return;
mbx->ready = true; mbx->ready = true;
switch (mbx_idx) { switch (mbx_idx) {
case FBNIC_IPC_MBX_RX_IDX: case FBNIC_IPC_MBX_RX_IDX:
/* Enable DMA writes from the device */
wr32(fbd, FBNIC_PUL_OB_TLP_HDR_AW_CFG,
FBNIC_PUL_OB_TLP_HDR_AW_CFG_BME);
/* Make sure we have a page for the FW to write to */ /* Make sure we have a page for the FW to write to */
fbnic_mbx_alloc_rx_msgs(fbd); fbnic_mbx_alloc_rx_msgs(fbd);
break; break;
case FBNIC_IPC_MBX_TX_IDX: case FBNIC_IPC_MBX_TX_IDX:
/* Force version to 1 if we successfully requested an update /* Enable DMA reads from the device */
* from the firmware. This should be overwritten once we get wr32(fbd, FBNIC_PUL_OB_TLP_HDR_AR_CFG,
* the actual version from the firmware in the capabilities FBNIC_PUL_OB_TLP_HDR_AR_CFG_BME);
* request message.
*/
if (!fbnic_fw_xmit_cap_msg(fbd) &&
!fbd->fw_cap.running.mgmt.version)
fbd->fw_cap.running.mgmt.version = 1;
break; break;
} }
} }
static void fbnic_mbx_postinit(struct fbnic_dev *fbd) static bool fbnic_mbx_event(struct fbnic_dev *fbd)
{ {
int i; /* We only need to do this on the first interrupt following reset.
/* We only need to do this on the first interrupt following init.
* this primes the mailbox so that we will have cleared all the * this primes the mailbox so that we will have cleared all the
* skip descriptors. * skip descriptors.
*/ */
if (!(rd32(fbd, FBNIC_INTR_STATUS(0)) & (1u << FBNIC_FW_MSIX_ENTRY))) if (!(rd32(fbd, FBNIC_INTR_STATUS(0)) & (1u << FBNIC_FW_MSIX_ENTRY)))
return; return false;
wr32(fbd, FBNIC_INTR_CLEAR(0), 1u << FBNIC_FW_MSIX_ENTRY); wr32(fbd, FBNIC_INTR_CLEAR(0), 1u << FBNIC_FW_MSIX_ENTRY);
for (i = 0; i < FBNIC_IPC_MBX_INDICES; i++) return true;
fbnic_mbx_postinit_desc_ring(fbd, i);
} }
/** /**
@@ -726,7 +730,7 @@ next_page:
void fbnic_mbx_poll(struct fbnic_dev *fbd) void fbnic_mbx_poll(struct fbnic_dev *fbd)
{ {
fbnic_mbx_postinit(fbd); fbnic_mbx_event(fbd);
fbnic_mbx_process_tx_msgs(fbd); fbnic_mbx_process_tx_msgs(fbd);
fbnic_mbx_process_rx_msgs(fbd); fbnic_mbx_process_rx_msgs(fbd);
@@ -734,60 +738,80 @@ void fbnic_mbx_poll(struct fbnic_dev *fbd)
int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd) int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd)
{ {
struct fbnic_fw_mbx *tx_mbx; unsigned long timeout = jiffies + 10 * HZ + 1;
int attempts = 50; int err, i;
/* Immediate fail if BAR4 isn't there */ do {
if (!fbnic_fw_present(fbd)) if (!time_is_after_jiffies(timeout))
return -ENODEV; return -ETIMEDOUT;
tx_mbx = &fbd->mbx[FBNIC_IPC_MBX_TX_IDX];
while (!tx_mbx->ready && --attempts) {
/* Force the firmware to trigger an interrupt response to /* Force the firmware to trigger an interrupt response to
* avoid the mailbox getting stuck closed if the interrupt * avoid the mailbox getting stuck closed if the interrupt
* is reset. * is reset.
*/ */
fbnic_mbx_init_desc_ring(fbd, FBNIC_IPC_MBX_TX_IDX); fbnic_mbx_reset_desc_ring(fbd, FBNIC_IPC_MBX_TX_IDX);
msleep(200); /* Immediate fail if BAR4 went away */
if (!fbnic_fw_present(fbd))
return -ENODEV;
fbnic_mbx_poll(fbd); msleep(20);
} } while (!fbnic_mbx_event(fbd));
return attempts ? 0 : -ETIMEDOUT; /* FW has shown signs of life. Enable DMA and start Tx/Rx */
for (i = 0; i < FBNIC_IPC_MBX_INDICES; i++)
fbnic_mbx_init_desc_ring(fbd, i);
/* Request an update from the firmware. This should overwrite
* mgmt.version once we get the actual version from the firmware
* in the capabilities request message.
*/
err = fbnic_fw_xmit_simple_msg(fbd, FBNIC_TLV_MSG_ID_HOST_CAP_REQ);
if (err)
goto clean_mbx;
/* Use "1" to indicate we entered the state waiting for a response */
fbd->fw_cap.running.mgmt.version = 1;
return 0;
clean_mbx:
/* Cleanup Rx buffers and disable mailbox */
fbnic_mbx_clean(fbd);
return err;
} }
void fbnic_mbx_flush_tx(struct fbnic_dev *fbd) void fbnic_mbx_flush_tx(struct fbnic_dev *fbd)
{ {
unsigned long timeout = jiffies + 10 * HZ + 1;
struct fbnic_fw_mbx *tx_mbx; struct fbnic_fw_mbx *tx_mbx;
int attempts = 50; u8 tail;
u8 count = 0;
/* Nothing to do if there is no mailbox */
if (!fbnic_fw_present(fbd))
return;
/* Record current Rx stats */ /* Record current Rx stats */
tx_mbx = &fbd->mbx[FBNIC_IPC_MBX_TX_IDX]; tx_mbx = &fbd->mbx[FBNIC_IPC_MBX_TX_IDX];
/* Nothing to do if mailbox never got to ready */ spin_lock_irq(&fbd->fw_tx_lock);
if (!tx_mbx->ready)
return; /* Clear ready to prevent any further attempts to transmit */
tx_mbx->ready = false;
/* Read tail to determine the last tail state for the ring */
tail = tx_mbx->tail;
spin_unlock_irq(&fbd->fw_tx_lock);
/* Give firmware time to process packet, /* Give firmware time to process packet,
* we will wait up to 10 seconds which is 50 waits of 200ms. * we will wait up to 10 seconds which is 500 waits of 20ms.
*/ */
do { do {
u8 head = tx_mbx->head; u8 head = tx_mbx->head;
if (head == tx_mbx->tail) /* Tx ring is empty once head == tail */
if (head == tail)
break; break;
msleep(200); msleep(20);
fbnic_mbx_process_tx_msgs(fbd); fbnic_mbx_process_tx_msgs(fbd);
} while (time_is_after_jiffies(timeout));
count += (tx_mbx->head - head) % FBNIC_IPC_MBX_DESC_LEN;
} while (count < FBNIC_IPC_MBX_DESC_LEN && --attempts);
} }
void fbnic_get_fw_ver_commit_str(struct fbnic_dev *fbd, char *fw_version, void fbnic_get_fw_ver_commit_str(struct fbnic_dev *fbd, char *fw_version,
@@ -79,12 +79,6 @@ static void fbnic_mac_init_axi(struct fbnic_dev *fbd)
fbnic_init_readrq(fbd, FBNIC_QM_RNI_RBP_CTL, cls, readrq); fbnic_init_readrq(fbd, FBNIC_QM_RNI_RBP_CTL, cls, readrq);
fbnic_init_mps(fbd, FBNIC_QM_RNI_RDE_CTL, cls, mps); fbnic_init_mps(fbd, FBNIC_QM_RNI_RDE_CTL, cls, mps);
fbnic_init_mps(fbd, FBNIC_QM_RNI_RCM_CTL, cls, mps); fbnic_init_mps(fbd, FBNIC_QM_RNI_RCM_CTL, cls, mps);
/* Enable XALI AR/AW outbound */
wr32(fbd, FBNIC_PUL_OB_TLP_HDR_AW_CFG,
FBNIC_PUL_OB_TLP_HDR_AW_CFG_BME);
wr32(fbd, FBNIC_PUL_OB_TLP_HDR_AR_CFG,
FBNIC_PUL_OB_TLP_HDR_AR_CFG_BME);
} }
static void fbnic_mac_init_qm(struct fbnic_dev *fbd) static void fbnic_mac_init_qm(struct fbnic_dev *fbd)
+13 -16
View File
@@ -82,9 +82,6 @@ struct z_erofs_pcluster {
/* L: whether partial decompression or not */ /* L: whether partial decompression or not */
bool partial; bool partial;
/* L: indicate several pageofs_outs or not */
bool multibases;
/* L: whether extra buffer allocations are best-effort */ /* L: whether extra buffer allocations are best-effort */
bool besteffort; bool besteffort;
@@ -1073,8 +1070,6 @@ static int z_erofs_scan_folio(struct z_erofs_decompress_frontend *f,
break; break;
erofs_onlinefolio_split(folio); erofs_onlinefolio_split(folio);
if (f->pcl->pageofs_out != (map->m_la & ~PAGE_MASK))
f->pcl->multibases = true;
if (f->pcl->length < offset + end - map->m_la) { if (f->pcl->length < offset + end - map->m_la) {
f->pcl->length = offset + end - map->m_la; f->pcl->length = offset + end - map->m_la;
f->pcl->pageofs_out = map->m_la & ~PAGE_MASK; f->pcl->pageofs_out = map->m_la & ~PAGE_MASK;
@@ -1120,7 +1115,6 @@ struct z_erofs_decompress_backend {
struct page *onstack_pages[Z_EROFS_ONSTACK_PAGES]; struct page *onstack_pages[Z_EROFS_ONSTACK_PAGES];
struct super_block *sb; struct super_block *sb;
struct z_erofs_pcluster *pcl; struct z_erofs_pcluster *pcl;
/* pages with the longest decompressed length for deduplication */ /* pages with the longest decompressed length for deduplication */
struct page **decompressed_pages; struct page **decompressed_pages;
/* pages to keep the compressed data */ /* pages to keep the compressed data */
@@ -1129,6 +1123,8 @@ struct z_erofs_decompress_backend {
struct list_head decompressed_secondary_bvecs; struct list_head decompressed_secondary_bvecs;
struct page **pagepool; struct page **pagepool;
unsigned int onstack_used, nr_pages; unsigned int onstack_used, nr_pages;
/* indicate if temporary copies should be preserved for later use */
bool keepxcpy;
}; };
struct z_erofs_bvec_item { struct z_erofs_bvec_item {
@@ -1139,18 +1135,20 @@ struct z_erofs_bvec_item {
static void z_erofs_do_decompressed_bvec(struct z_erofs_decompress_backend *be, static void z_erofs_do_decompressed_bvec(struct z_erofs_decompress_backend *be,
struct z_erofs_bvec *bvec) struct z_erofs_bvec *bvec)
{ {
int poff = bvec->offset + be->pcl->pageofs_out;
struct z_erofs_bvec_item *item; struct z_erofs_bvec_item *item;
unsigned int pgnr; struct page **page;
if (!((bvec->offset + be->pcl->pageofs_out) & ~PAGE_MASK) && if (!(poff & ~PAGE_MASK) && (bvec->end == PAGE_SIZE ||
(bvec->end == PAGE_SIZE || bvec->offset + bvec->end == be->pcl->length)) {
bvec->offset + bvec->end == be->pcl->length)) { DBG_BUGON((poff >> PAGE_SHIFT) >= be->nr_pages);
pgnr = (bvec->offset + be->pcl->pageofs_out) >> PAGE_SHIFT; page = be->decompressed_pages + (poff >> PAGE_SHIFT);
DBG_BUGON(pgnr >= be->nr_pages); if (!*page) {
if (!be->decompressed_pages[pgnr]) { *page = bvec->page;
be->decompressed_pages[pgnr] = bvec->page;
return; return;
} }
} else {
be->keepxcpy = true;
} }
/* (cold path) one pcluster is requested multiple times */ /* (cold path) one pcluster is requested multiple times */
@@ -1316,7 +1314,7 @@ static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be,
.alg = pcl->algorithmformat, .alg = pcl->algorithmformat,
.inplace_io = overlapped, .inplace_io = overlapped,
.partial_decoding = pcl->partial, .partial_decoding = pcl->partial,
.fillgaps = pcl->multibases, .fillgaps = be->keepxcpy,
.gfp = pcl->besteffort ? GFP_KERNEL : .gfp = pcl->besteffort ? GFP_KERNEL :
GFP_NOWAIT | __GFP_NORETRY GFP_NOWAIT | __GFP_NORETRY
}, be->pagepool); }, be->pagepool);
@@ -1370,7 +1368,6 @@ static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be,
pcl->length = 0; pcl->length = 0;
pcl->partial = true; pcl->partial = true;
pcl->multibases = false;
pcl->besteffort = false; pcl->besteffort = false;
pcl->bvset.nextpage = NULL; pcl->bvset.nextpage = NULL;
pcl->vcnt = 0; pcl->vcnt = 0;
+6
View File
@@ -92,6 +92,12 @@ struct netdev_stat_ops {
struct netdev_queue_stats_tx *tx); struct netdev_queue_stats_tx *tx);
}; };
void netdev_stat_queue_sum(struct net_device *netdev,
int rx_start, int rx_end,
struct netdev_queue_stats_rx *rx_sum,
int tx_start, int tx_end,
struct netdev_queue_stats_tx *tx_sum);
/** /**
* struct netdev_queue_mgmt_ops - netdev ops for queue management * struct netdev_queue_mgmt_ops - netdev ops for queue management
* *
+1
View File
@@ -2534,6 +2534,7 @@ int skb_do_redirect(struct sk_buff *skb)
goto out_drop; goto out_drop;
skb->dev = dev; skb->dev = dev;
dev_sw_netstats_rx_add(dev, skb->len); dev_sw_netstats_rx_add(dev, skb->len);
skb_scrub_packet(skb, false);
return -EAGAIN; return -EAGAIN;
} }
return flags & BPF_F_NEIGH ? return flags & BPF_F_NEIGH ?
+50 -19
View File
@@ -616,25 +616,66 @@ netdev_nl_stats_by_queue(struct net_device *netdev, struct sk_buff *rsp,
return 0; return 0;
} }
/**
* netdev_stat_queue_sum() - add up queue stats from range of queues
* @netdev: net_device
* @rx_start: index of the first Rx queue to query
* @rx_end: index after the last Rx queue (first *not* to query)
* @rx_sum: output Rx stats, should be already initialized
* @tx_start: index of the first Tx queue to query
* @tx_end: index after the last Tx queue (first *not* to query)
* @tx_sum: output Tx stats, should be already initialized
*
* Add stats from [start, end) range of queue IDs to *x_sum structs.
* The sum structs must be already initialized. Usually this
* helper is invoked from the .get_base_stats callbacks of drivers
* to account for stats of disabled queues. In that case the ranges
* are usually [netdev->real_num_*x_queues, netdev->num_*x_queues).
*/
void netdev_stat_queue_sum(struct net_device *netdev,
int rx_start, int rx_end,
struct netdev_queue_stats_rx *rx_sum,
int tx_start, int tx_end,
struct netdev_queue_stats_tx *tx_sum)
{
const struct netdev_stat_ops *ops;
struct netdev_queue_stats_rx rx;
struct netdev_queue_stats_tx tx;
int i;
ops = netdev->stat_ops;
for (i = rx_start; i < rx_end; i++) {
memset(&rx, 0xff, sizeof(rx));
if (ops->get_queue_stats_rx)
ops->get_queue_stats_rx(netdev, i, &rx);
netdev_nl_stats_add(rx_sum, &rx, sizeof(rx));
}
for (i = tx_start; i < tx_end; i++) {
memset(&tx, 0xff, sizeof(tx));
if (ops->get_queue_stats_tx)
ops->get_queue_stats_tx(netdev, i, &tx);
netdev_nl_stats_add(tx_sum, &tx, sizeof(tx));
}
}
EXPORT_SYMBOL(netdev_stat_queue_sum);
static int static int
netdev_nl_stats_by_netdev(struct net_device *netdev, struct sk_buff *rsp, netdev_nl_stats_by_netdev(struct net_device *netdev, struct sk_buff *rsp,
const struct genl_info *info) const struct genl_info *info)
{ {
struct netdev_queue_stats_rx rx_sum, rx; struct netdev_queue_stats_rx rx_sum;
struct netdev_queue_stats_tx tx_sum, tx; struct netdev_queue_stats_tx tx_sum;
const struct netdev_stat_ops *ops;
void *hdr; void *hdr;
int i;
ops = netdev->stat_ops;
/* Netdev can't guarantee any complete counters */ /* Netdev can't guarantee any complete counters */
if (!ops->get_base_stats) if (!netdev->stat_ops->get_base_stats)
return 0; return 0;
memset(&rx_sum, 0xff, sizeof(rx_sum)); memset(&rx_sum, 0xff, sizeof(rx_sum));
memset(&tx_sum, 0xff, sizeof(tx_sum)); memset(&tx_sum, 0xff, sizeof(tx_sum));
ops->get_base_stats(netdev, &rx_sum, &tx_sum); netdev->stat_ops->get_base_stats(netdev, &rx_sum, &tx_sum);
/* The op was there, but nothing reported, don't bother */ /* The op was there, but nothing reported, don't bother */
if (!memchr_inv(&rx_sum, 0xff, sizeof(rx_sum)) && if (!memchr_inv(&rx_sum, 0xff, sizeof(rx_sum)) &&
@@ -647,18 +688,8 @@ netdev_nl_stats_by_netdev(struct net_device *netdev, struct sk_buff *rsp,
if (nla_put_u32(rsp, NETDEV_A_QSTATS_IFINDEX, netdev->ifindex)) if (nla_put_u32(rsp, NETDEV_A_QSTATS_IFINDEX, netdev->ifindex))
goto nla_put_failure; goto nla_put_failure;
for (i = 0; i < netdev->real_num_rx_queues; i++) { netdev_stat_queue_sum(netdev, 0, netdev->real_num_rx_queues, &rx_sum,
memset(&rx, 0xff, sizeof(rx)); 0, netdev->real_num_tx_queues, &tx_sum);
if (ops->get_queue_stats_rx)
ops->get_queue_stats_rx(netdev, i, &rx);
netdev_nl_stats_add(&rx_sum, &rx, sizeof(rx));
}
for (i = 0; i < netdev->real_num_tx_queues; i++) {
memset(&tx, 0xff, sizeof(tx));
if (ops->get_queue_stats_tx)
ops->get_queue_stats_tx(netdev, i, &tx);
netdev_nl_stats_add(&tx_sum, &tx, sizeof(tx));
}
if (netdev_nl_stats_write_rx(rsp, &rx_sum) || if (netdev_nl_stats_write_rx(rsp, &rx_sum) ||
netdev_nl_stats_write_tx(rsp, &tx_sum)) netdev_nl_stats_write_tx(rsp, &tx_sum))
+1 -1
View File
@@ -64,7 +64,7 @@ struct hbucket {
#define ahash_sizeof_regions(htable_bits) \ #define ahash_sizeof_regions(htable_bits) \
(ahash_numof_locks(htable_bits) * sizeof(struct ip_set_region)) (ahash_numof_locks(htable_bits) * sizeof(struct ip_set_region))
#define ahash_region(n, htable_bits) \ #define ahash_region(n, htable_bits) \
((n) % ahash_numof_locks(htable_bits)) ((n) / jhash_size(HTABLE_REGION_BITS))
#define ahash_bucket_start(h, htable_bits) \ #define ahash_bucket_start(h, htable_bits) \
((htable_bits) < HTABLE_REGION_BITS ? 0 \ ((htable_bits) < HTABLE_REGION_BITS ? 0 \
: (h) * jhash_size(HTABLE_REGION_BITS)) : (h) * jhash_size(HTABLE_REGION_BITS))
+8 -19
View File
@@ -119,13 +119,12 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
return false; return false;
} }
/* Get route to daddr, update *saddr, optionally bind route to saddr */ /* Get route to daddr, optionally bind route to saddr */
static struct rtable *do_output_route4(struct net *net, __be32 daddr, static struct rtable *do_output_route4(struct net *net, __be32 daddr,
int rt_mode, __be32 *saddr) int rt_mode, __be32 *ret_saddr)
{ {
struct flowi4 fl4; struct flowi4 fl4;
struct rtable *rt; struct rtable *rt;
bool loop = false;
memset(&fl4, 0, sizeof(fl4)); memset(&fl4, 0, sizeof(fl4));
fl4.daddr = daddr; fl4.daddr = daddr;
@@ -135,23 +134,17 @@ static struct rtable *do_output_route4(struct net *net, __be32 daddr,
retry: retry:
rt = ip_route_output_key(net, &fl4); rt = ip_route_output_key(net, &fl4);
if (IS_ERR(rt)) { if (IS_ERR(rt)) {
/* Invalid saddr ? */
if (PTR_ERR(rt) == -EINVAL && *saddr &&
rt_mode & IP_VS_RT_MODE_CONNECT && !loop) {
*saddr = 0;
flowi4_update_output(&fl4, 0, daddr, 0);
goto retry;
}
IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", &daddr); IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", &daddr);
return NULL; return NULL;
} else if (!*saddr && rt_mode & IP_VS_RT_MODE_CONNECT && fl4.saddr) { }
if (rt_mode & IP_VS_RT_MODE_CONNECT && fl4.saddr) {
ip_rt_put(rt); ip_rt_put(rt);
*saddr = fl4.saddr;
flowi4_update_output(&fl4, 0, daddr, fl4.saddr); flowi4_update_output(&fl4, 0, daddr, fl4.saddr);
loop = true; rt_mode = 0;
goto retry; goto retry;
} }
*saddr = fl4.saddr; if (ret_saddr)
*ret_saddr = fl4.saddr;
return rt; return rt;
} }
@@ -344,19 +337,15 @@ __ip_vs_get_out_rt(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
if (ret_saddr) if (ret_saddr)
*ret_saddr = dest_dst->dst_saddr.ip; *ret_saddr = dest_dst->dst_saddr.ip;
} else { } else {
__be32 saddr = htonl(INADDR_ANY);
noref = 0; noref = 0;
/* For such unconfigured boxes avoid many route lookups /* For such unconfigured boxes avoid many route lookups
* for performance reasons because we do not remember saddr * for performance reasons because we do not remember saddr
*/ */
rt_mode &= ~IP_VS_RT_MODE_CONNECT; rt_mode &= ~IP_VS_RT_MODE_CONNECT;
rt = do_output_route4(net, daddr, rt_mode, &saddr); rt = do_output_route4(net, daddr, rt_mode, ret_saddr);
if (!rt) if (!rt)
goto err_unreach; goto err_unreach;
if (ret_saddr)
*ret_saddr = saddr;
} }
local = (rt->rt_flags & RTCF_LOCAL) ? 1 : 0; local = (rt->rt_flags & RTCF_LOCAL) ? 1 : 0;