diff options
Diffstat (limited to 'drivers/net')
151 files changed, 7285 insertions, 1702 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 931d9d935686..21d8fcc83c9c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4039,7 +4039,7 @@ out: * this to-be-skipped slave to send a packet out. */ old_arr = rtnl_dereference(bond->slave_arr); - for (idx = 0; idx < old_arr->count; idx++) { + for (idx = 0; old_arr != NULL && idx < old_arr->count; idx++) { if (skipslave == old_arr->arr[idx]) { old_arr->arr[idx] = old_arr->arr[old_arr->count-1]; diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 526ba2ab66f1..baadf622ac55 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -524,7 +524,7 @@ int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy) if (!dsa_is_user_port(ds, port)) return 0; - cpu_port = ds->ports[port].cpu_dp->index; + cpu_port = dsa_to_port(ds, port)->cpu_dp->index; if (dev->ops->irq_enable) ret = dev->ops->irq_enable(dev, port); @@ -1629,7 +1629,7 @@ EXPORT_SYMBOL(b53_fdb_dump); int b53_br_join(struct dsa_switch *ds, int port, struct net_device *br) { struct b53_device *dev = ds->priv; - s8 cpu_port = ds->ports[port].cpu_dp->index; + s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; u16 pvlan, reg; unsigned int i; @@ -1675,7 +1675,7 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *br) { struct b53_device *dev = ds->priv; struct b53_vlan *vl = &dev->vlans[0]; - s8 cpu_port = ds->ports[port].cpu_dp->index; + s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; unsigned int i; u16 pvlan, reg, pvid; @@ -1845,7 +1845,6 @@ int b53_mirror_add(struct dsa_switch *ds, int port, loc = B53_EG_MIR_CTL; b53_read16(dev, B53_MGMT_PAGE, loc, ®); - reg &= ~MIRROR_MASK; reg |= BIT(port); b53_write16(dev, B53_MGMT_PAGE, loc, reg); @@ -2342,10 +2341,13 @@ struct b53_device *b53_switch_alloc(struct device *base, struct dsa_switch *ds; struct b53_device *dev; - ds = dsa_switch_alloc(base, DSA_MAX_PORTS); + ds = devm_kzalloc(base, sizeof(*ds), GFP_KERNEL); if (!ds) return NULL; + ds->dev = base; + ds->num_ports = DSA_MAX_PORTS; + dev = devm_kzalloc(base, sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 26509fa37a50..c068a3b7207b 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -662,7 +662,7 @@ static void bcm_sf2_sw_fixed_state(struct dsa_switch *ds, int port, * state machine and make it go in PHY_FORCING state instead. */ if (!status->link) - netif_carrier_off(ds->ports[port].slave); + netif_carrier_off(dsa_to_port(ds, port)->slave); status->duplex = DUPLEX_FULL; } else { status->link = true; @@ -728,7 +728,7 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port, struct ethtool_wolinfo *wol) { - struct net_device *p = ds->ports[port].cpu_dp->master; + struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master; struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); struct ethtool_wolinfo pwol = { }; @@ -752,9 +752,9 @@ static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port, static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port, struct ethtool_wolinfo *wol) { - struct net_device *p = ds->ports[port].cpu_dp->master; + struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master; struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); - s8 cpu_port = ds->ports[port].cpu_dp->index; + s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; struct ethtool_wolinfo pwol = { }; if (p->ethtool_ops->get_wol) diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index d264776a95a3..f3f0c3f07391 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -821,7 +821,7 @@ static int bcm_sf2_cfp_rule_insert(struct dsa_switch *ds, int port, struct ethtool_rx_flow_spec *fs) { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); - s8 cpu_port = ds->ports[port].cpu_dp->index; + s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; __u64 ring_cookie = fs->ring_cookie; unsigned int queue_num, port_num; int ret; @@ -1049,7 +1049,7 @@ static int bcm_sf2_cfp_rule_get_all(struct bcm_sf2_priv *priv, int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port, struct ethtool_rxnfc *nfc, u32 *rule_locs) { - struct net_device *p = ds->ports[port].cpu_dp->master; + struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master; struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); int ret = 0; @@ -1092,7 +1092,7 @@ int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port, int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port, struct ethtool_rxnfc *nfc) { - struct net_device *p = ds->ports[port].cpu_dp->master; + struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master; struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); int ret = 0; diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index 925ed135a4d9..c8d7ef27fd72 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -286,10 +286,13 @@ static int dsa_loop_drv_probe(struct mdio_device *mdiodev) dev_info(&mdiodev->dev, "%s: 0x%0x\n", pdata->name, pdata->enabled_ports); - ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS); + ds = devm_kzalloc(&mdiodev->dev, sizeof(*ds), GFP_KERNEL); if (!ds) return -ENOMEM; + ds->dev = &mdiodev->dev; + ds->num_ports = DSA_MAX_PORTS; + ps = devm_kzalloc(&mdiodev->dev, sizeof(*ps), GFP_KERNEL); if (!ps) return -ENOMEM; diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index bbec86b9418e..e3c333a8f45d 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c @@ -1283,10 +1283,12 @@ static int lan9303_register_switch(struct lan9303 *chip) { int base; - chip->ds = dsa_switch_alloc(chip->dev, LAN9303_NUM_PORTS); + chip->ds = devm_kzalloc(chip->dev, sizeof(*chip->ds), GFP_KERNEL); if (!chip->ds) return -ENOMEM; + chip->ds->dev = chip->dev; + chip->ds->num_ports = LAN9303_NUM_PORTS; chip->ds->priv = chip; chip->ds->ops = &lan9303_switch_ops; base = chip->phy_addr_base; diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index a69c9b9878b7..955324968b74 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -1854,10 +1854,12 @@ static int gswip_probe(struct platform_device *pdev) if (!priv->hw_info) return -EINVAL; - priv->ds = dsa_switch_alloc(dev, priv->hw_info->max_ports); + priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL); if (!priv->ds) return -ENOMEM; + priv->ds->dev = dev; + priv->ds->num_ports = priv->hw_info->max_ports; priv->ds->priv = priv; priv->ds->ops = &gswip_switch_ops; priv->dev = dev; diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index a23d3ffdf0c4..24a5e99f7fd5 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -1224,10 +1224,6 @@ static int ksz8795_switch_init(struct ksz_device *dev) { int i; - mutex_init(&dev->stats_mutex); - mutex_init(&dev->alu_mutex); - mutex_init(&dev->vlan_mutex); - dev->ds->ops = &ksz8795_switch_ops; for (i = 0; i < ARRAY_SIZE(ksz8795_switch_chips); i++) { diff --git a/drivers/net/dsa/microchip/ksz8795_spi.c b/drivers/net/dsa/microchip/ksz8795_spi.c index d0f8153e86b7..8b00f8e6c02f 100644 --- a/drivers/net/dsa/microchip/ksz8795_spi.c +++ b/drivers/net/dsa/microchip/ksz8795_spi.c @@ -25,6 +25,7 @@ KSZ_REGMAP_TABLE(ksz8795, 16, SPI_ADDR_SHIFT, static int ksz8795_spi_probe(struct spi_device *spi) { + struct regmap_config rc; struct ksz_device *dev; int i, ret; @@ -33,9 +34,9 @@ static int ksz8795_spi_probe(struct spi_device *spi) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) { - dev->regmap[i] = devm_regmap_init_spi(spi, - &ksz8795_regmap_config - [i]); + rc = ksz8795_regmap_config[i]; + rc.lock_arg = &dev->regmap_mutex; + dev->regmap[i] = devm_regmap_init_spi(spi, &rc); if (IS_ERR(dev->regmap[i])) { ret = PTR_ERR(dev->regmap[i]); dev_err(&spi->dev, diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c index b0a1595d780d..7d050fab0889 100644 --- a/drivers/net/dsa/microchip/ksz9477_i2c.c +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c @@ -17,6 +17,7 @@ KSZ_REGMAP_TABLE(ksz9477, not_used, 16, 0, 0); static int ksz9477_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i2c_id) { + struct regmap_config rc; struct ksz_device *dev; int i, ret; @@ -25,8 +26,9 @@ static int ksz9477_i2c_probe(struct i2c_client *i2c, return -ENOMEM; for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_config); i++) { - dev->regmap[i] = devm_regmap_init_i2c(i2c, - &ksz9477_regmap_config[i]); + rc = ksz9477_regmap_config[i]; + rc.lock_arg = &dev->regmap_mutex; + dev->regmap[i] = devm_regmap_init_i2c(i2c, &rc); if (IS_ERR(dev->regmap[i])) { ret = PTR_ERR(dev->regmap[i]); dev_err(&i2c->dev, diff --git a/drivers/net/dsa/microchip/ksz9477_reg.h b/drivers/net/dsa/microchip/ksz9477_reg.h index 2938e892b631..16939f29faa5 100644 --- a/drivers/net/dsa/microchip/ksz9477_reg.h +++ b/drivers/net/dsa/microchip/ksz9477_reg.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 - * +/* SPDX-License-Identifier: GPL-2.0 */ +/* * Microchip KSZ9477 register definitions * * Copyright (C) 2017-2018 Microchip Technology Inc. diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index f4198d6f72be..c5f64959a184 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -24,6 +24,7 @@ KSZ_REGMAP_TABLE(ksz9477, 32, SPI_ADDR_SHIFT, static int ksz9477_spi_probe(struct spi_device *spi) { + struct regmap_config rc; struct ksz_device *dev; int i, ret; @@ -32,8 +33,9 @@ static int ksz9477_spi_probe(struct spi_device *spi) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_config); i++) { - dev->regmap[i] = devm_regmap_init_spi(spi, - &ksz9477_regmap_config[i]); + rc = ksz9477_regmap_config[i]; + rc.lock_arg = &dev->regmap_mutex; + dev->regmap[i] = devm_regmap_init_spi(spi, &rc); if (IS_ERR(dev->regmap[i])) { ret = PTR_ERR(dev->regmap[i]); dev_err(&spi->dev, diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index b0b870f0c252..5d08e4430824 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -398,10 +398,13 @@ struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) struct dsa_switch *ds; struct ksz_device *swdev; - ds = dsa_switch_alloc(base, DSA_MAX_PORTS); + ds = devm_kzalloc(base, sizeof(*ds), GFP_KERNEL); if (!ds) return NULL; + ds->dev = base; + ds->num_ports = DSA_MAX_PORTS; + swdev = devm_kzalloc(base, sizeof(*swdev), GFP_KERNEL); if (!swdev) return NULL; @@ -436,7 +439,7 @@ int ksz_switch_register(struct ksz_device *dev, } mutex_init(&dev->dev_mutex); - mutex_init(&dev->stats_mutex); + mutex_init(&dev->regmap_mutex); mutex_init(&dev->alu_mutex); mutex_init(&dev->vlan_mutex); diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index dd60d0837fc6..a20ebb749377 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 - * Microchip switch driver common header +/* SPDX-License-Identifier: GPL-2.0 */ +/* Microchip switch driver common header * * Copyright (C) 2017-2019 Microchip Technology Inc. */ @@ -47,7 +47,7 @@ struct ksz_device { const char *name; struct mutex dev_mutex; /* device access */ - struct mutex stats_mutex; /* status access */ + struct mutex regmap_mutex; /* regmap access */ struct mutex alu_mutex; /* ALU access */ struct mutex vlan_mutex; /* vlan access */ const struct ksz_dev_ops *dev_ops; @@ -290,6 +290,18 @@ static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset, ksz_write32(dev, dev->dev_ops->get_port_addr(port, offset), data); } +static inline void ksz_regmap_lock(void *__mtx) +{ + struct mutex *mtx = __mtx; + mutex_lock(mtx); +} + +static inline void ksz_regmap_unlock(void *__mtx) +{ + struct mutex *mtx = __mtx; + mutex_unlock(mtx); +} + /* Regmap tables generation */ #define KSZ_SPI_OP_RD 3 #define KSZ_SPI_OP_WR 2 @@ -314,6 +326,8 @@ static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset, .write_flag_mask = \ KSZ_SPI_OP_FLAG_MASK(KSZ_SPI_OP_WR, swp, \ regbits, regpad), \ + .lock = ksz_regmap_lock, \ + .unlock = ksz_regmap_unlock, \ .reg_format_endian = REGMAP_ENDIAN_BIG, \ .val_format_endian = REGMAP_ENDIAN_BIG \ } diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 1d8d36de4d20..add9e4279176 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -862,7 +862,7 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port) for (i = 0; i < MT7530_NUM_PORTS; i++) { if (dsa_is_user_port(ds, i) && - dsa_port_is_vlan_filtering(&ds->ports[i])) { + dsa_port_is_vlan_filtering(dsa_to_port(ds, i))) { all_user_ports_removed = false; break; } @@ -922,7 +922,7 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, * other port is still a VLAN-aware port. */ if (dsa_is_user_port(ds, i) && i != port && - !dsa_port_is_vlan_filtering(&ds->ports[i])) { + !dsa_port_is_vlan_filtering(dsa_to_port(ds, i))) { if (dsa_to_port(ds, i)->bridge_dev != bridge) continue; if (priv->ports[i].enable) @@ -1165,7 +1165,7 @@ mt7530_port_vlan_add(struct dsa_switch *ds, int port, /* The port is kept as VLAN-unaware if bridge with vlan_filtering not * being set. */ - if (!dsa_port_is_vlan_filtering(&ds->ports[port])) + if (!dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) return; mutex_lock(&priv->reg_mutex); @@ -1196,7 +1196,7 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port, /* The port is kept as VLAN-unaware if bridge with vlan_filtering not * being set. */ - if (!dsa_port_is_vlan_filtering(&ds->ports[port])) + if (!dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) return 0; mutex_lock(&priv->reg_mutex); @@ -1252,7 +1252,7 @@ mt7530_setup(struct dsa_switch *ds) * controller also is the container for two GMACs nodes representing * as two netdev instances. */ - dn = ds->ports[MT7530_CPU_PORT].master->dev.of_node->parent; + dn = dsa_to_port(ds, MT7530_CPU_PORT)->master->dev.of_node->parent; if (priv->id == ID_MT7530) { priv->ethernet = syscon_node_to_regmap(dn); @@ -1340,7 +1340,7 @@ mt7530_setup(struct dsa_switch *ds) if (!dsa_is_unused_port(ds, 5)) { priv->p5_intf_sel = P5_INTF_SEL_GMAC5; - interface = of_get_phy_mode(ds->ports[5].dn); + interface = of_get_phy_mode(dsa_to_port(ds, 5)->dn); } else { /* Scan the ethernet nodes. look for GMAC1, lookup used phy */ for_each_child_of_node(dn, mac_np) { @@ -1632,10 +1632,13 @@ mt7530_probe(struct mdio_device *mdiodev) if (!priv) return -ENOMEM; - priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS); + priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); if (!priv->ds) return -ENOMEM; + priv->ds->dev = &mdiodev->dev; + priv->ds->num_ports = DSA_MAX_PORTS; + /* Use medatek,mcm property to distinguish hardware type that would * casues a little bit differences on power-on sequence. */ diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c index 2a2489b5196d..a5a37f47b320 100644 --- a/drivers/net/dsa/mv88e6060.c +++ b/drivers/net/dsa/mv88e6060.c @@ -270,10 +270,12 @@ static int mv88e6060_probe(struct mdio_device *mdiodev) dev_info(dev, "switch %s detected\n", name); - ds = dsa_switch_alloc(dev, MV88E6060_PORTS); + ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); if (!ds) return -ENOMEM; + ds->dev = dev; + ds->num_ports = MV88E6060_PORTS; ds->priv = priv; ds->dev = dev; ds->ops = &mv88e6060_switch_ops; diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 6787d560e9e3..5fdf6d6ebe27 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1057,35 +1057,43 @@ static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port, return 0; } +/* Mask of the local ports allowed to receive frames from a given fabric port */ static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port) { - struct dsa_switch *ds = NULL; + struct dsa_switch *ds = chip->ds; + struct dsa_switch_tree *dst = ds->dst; struct net_device *br; + struct dsa_port *dp; + bool found = false; u16 pvlan; - int i; - if (dev < DSA_MAX_SWITCHES) - ds = chip->ds->dst->ds[dev]; + list_for_each_entry(dp, &dst->ports, list) { + if (dp->ds->index == dev && dp->index == port) { + found = true; + break; + } + } /* Prevent frames from unknown switch or port */ - if (!ds || port >= ds->num_ports) + if (!found) return 0; /* Frames from DSA links and CPU ports can egress any local port */ - if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) + if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA) return mv88e6xxx_port_mask(chip); - br = ds->ports[port].bridge_dev; + br = dp->bridge_dev; pvlan = 0; /* Frames from user ports can egress any local DSA links and CPU ports, * as well as any local member of their bridge group. */ - for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) - if (dsa_is_cpu_port(chip->ds, i) || - dsa_is_dsa_port(chip->ds, i) || - (br && dsa_to_port(chip->ds, i)->bridge_dev == br)) - pvlan |= BIT(i); + list_for_each_entry(dp, &dst->ports, list) + if (dp->ds == ds && + (dp->type == DSA_PORT_TYPE_CPU || + dp->type == DSA_PORT_TYPE_DSA || + (br && dp->bridge_dev == br))) + pvlan |= BIT(dp->index); return pvlan; } @@ -1253,7 +1261,7 @@ static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port) u16 pvlan = 0; if (!mv88e6xxx_has_pvt(chip)) - return -EOPNOTSUPP; + return 0; /* Skip the local source device, which uses in-chip port VLAN */ if (dev != chip->ds->index) @@ -1402,7 +1410,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i)) continue; - if (!ds->ports[i].slave) + if (!dsa_to_port(ds, i)->slave) continue; if (vlan.member[i] == @@ -1410,7 +1418,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, continue; if (dsa_to_port(ds, i)->bridge_dev == - ds->ports[port].bridge_dev) + dsa_to_port(ds, port)->bridge_dev) break; /* same bridge, check next VLAN */ if (!dsa_to_port(ds, i)->bridge_dev) @@ -2035,32 +2043,26 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, struct net_device *br) { - struct dsa_switch *ds; - int port; - int dev; + struct dsa_switch *ds = chip->ds; + struct dsa_switch_tree *dst = ds->dst; + struct dsa_port *dp; int err; - /* Remap the Port VLAN of each local bridge group member */ - for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) { - if (chip->ds->ports[port].bridge_dev == br) { - err = mv88e6xxx_port_vlan_map(chip, port); - if (err) - return err; - } - } - - if (!mv88e6xxx_has_pvt(chip)) - return 0; - - /* Remap the Port VLAN of each cross-chip bridge group member */ - for (dev = 0; dev < DSA_MAX_SWITCHES; ++dev) { - ds = chip->ds->dst->ds[dev]; - if (!ds) - break; - - for (port = 0; port < ds->num_ports; ++port) { - if (ds->ports[port].bridge_dev == br) { - err = mv88e6xxx_pvt_map(chip, dev, port); + list_for_each_entry(dp, &dst->ports, list) { + if (dp->bridge_dev == br) { + if (dp->ds == ds) { + /* This is a local bridge group member, + * remap its Port VLAN Map. + */ + err = mv88e6xxx_port_vlan_map(chip, dp->index); + if (err) + return err; + } else { + /* This is an external bridge group member, + * remap its cross-chip Port VLAN Table entry. + */ + err = mv88e6xxx_pvt_map(chip, dp->ds->index, + dp->index); if (err) return err; } @@ -2101,9 +2103,6 @@ static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev, struct mv88e6xxx_chip *chip = ds->priv; int err; - if (!mv88e6xxx_has_pvt(chip)) - return 0; - mv88e6xxx_reg_lock(chip); err = mv88e6xxx_pvt_map(chip, dev, port); mv88e6xxx_reg_unlock(chip); @@ -2116,9 +2115,6 @@ static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev, { struct mv88e6xxx_chip *chip = ds->priv; - if (!mv88e6xxx_has_pvt(chip)) - return; - mv88e6xxx_reg_lock(chip); if (mv88e6xxx_pvt_map(chip, dev, port)) dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); @@ -4982,10 +4978,12 @@ static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) struct device *dev = chip->dev; struct dsa_switch *ds; - ds = dsa_switch_alloc(dev, mv88e6xxx_num_ports(chip)); + ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); if (!ds) return -ENOMEM; + ds->dev = dev; + ds->num_ports = mv88e6xxx_num_ports(chip); ds->priv = chip; ds->dev = dev; ds->ops = &mv88e6xxx_switch_ops; diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index b00274caae4f..7e742cd491e8 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -661,7 +661,7 @@ qca8k_setup(struct dsa_switch *ds) return ret; /* Initialize CPU port pad mode (xMII type, delays...) */ - phy_mode = of_get_phy_mode(ds->ports[QCA8K_CPU_PORT].dn); + phy_mode = of_get_phy_mode(dsa_to_port(ds, QCA8K_CPU_PORT)->dn); if (phy_mode < 0) { pr_err("Can't find phy-mode for master device\n"); return phy_mode; @@ -1077,10 +1077,13 @@ qca8k_sw_probe(struct mdio_device *mdiodev) if (id != QCA8K_ID_QCA8337) return -ENODEV; - priv->ds = dsa_switch_alloc(&mdiodev->dev, QCA8K_NUM_PORTS); + priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), + QCA8K_NUM_PORTS); if (!priv->ds) return -ENOMEM; + priv->ds->dev = &mdiodev->dev; + priv->ds->num_ports = DSA_MAX_PORTS; priv->ds->priv = priv; priv->ops = qca8k_switch_ops; priv->ds->ops = &priv->ops; diff --git a/drivers/net/dsa/realtek-smi-core.c b/drivers/net/dsa/realtek-smi-core.c index dc0509c02d29..fae188c60191 100644 --- a/drivers/net/dsa/realtek-smi-core.c +++ b/drivers/net/dsa/realtek-smi-core.c @@ -444,9 +444,12 @@ static int realtek_smi_probe(struct platform_device *pdev) return ret; } - smi->ds = dsa_switch_alloc(dev, smi->num_ports); + smi->ds = devm_kzalloc(dev, sizeof(*smi->ds), GFP_KERNEL); if (!smi->ds) return -ENOMEM; + + smi->ds->dev = dev; + smi->ds->num_ports = smi->num_ports; smi->ds->priv = smi; smi->ds->ops = var->ds_ops; diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 0ef97a916707..91063ed3ef1b 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 - * Copyright (c) 2018, Sensor-Technik Wiedemann GmbH +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018, Sensor-Technik Wiedemann GmbH * Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com> */ #ifndef _SJA1105_H @@ -33,9 +33,8 @@ struct sja1105_regs { u64 config; u64 rmii_pll1; u64 ptp_control; - u64 ptpclk; + u64 ptpclkval; u64 ptpclkrate; - u64 ptptsclk; u64 ptpegr_ts[SJA1105_NUM_PORTS]; u64 pad_mii_tx[SJA1105_NUM_PORTS]; u64 pad_mii_id[SJA1105_NUM_PORTS]; diff --git a/drivers/net/dsa/sja1105/sja1105_dynamic_config.h b/drivers/net/dsa/sja1105/sja1105_dynamic_config.h index 740dadf43f01..1fc0d13dc623 100644 --- a/drivers/net/dsa/sja1105/sja1105_dynamic_config.h +++ b/drivers/net/dsa/sja1105/sja1105_dynamic_config.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 - * Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com> +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com> */ #ifndef _SJA1105_DYNAMIC_CONFIG_H #define _SJA1105_DYNAMIC_CONFIG_H diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 2ffe642cf54b..2ae84a9dea59 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1058,7 +1058,7 @@ int sja1105pqrs_fdb_add(struct dsa_switch *ds, int port, l2_lookup.vlanid = vid; l2_lookup.iotag = SJA1105_S_TAG; l2_lookup.mask_macaddr = GENMASK_ULL(ETH_ALEN * 8 - 1, 0); - if (dsa_port_is_vlan_filtering(&ds->ports[port])) { + if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) { l2_lookup.mask_vlanid = VLAN_VID_MASK; l2_lookup.mask_iotag = BIT(0); } else { @@ -1121,7 +1121,7 @@ int sja1105pqrs_fdb_del(struct dsa_switch *ds, int port, l2_lookup.vlanid = vid; l2_lookup.iotag = SJA1105_S_TAG; l2_lookup.mask_macaddr = GENMASK_ULL(ETH_ALEN * 8 - 1, 0); - if (dsa_port_is_vlan_filtering(&ds->ports[port])) { + if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) { l2_lookup.mask_vlanid = VLAN_VID_MASK; l2_lookup.mask_iotag = BIT(0); } else { @@ -1167,7 +1167,7 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port, * for what gets printed in 'bridge fdb show'. In the case of zero, * no VID gets printed at all. */ - if (!dsa_port_is_vlan_filtering(&ds->ports[port])) + if (!dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) vid = 0; return priv->info->fdb_add_cmd(ds, port, addr, vid); @@ -1178,7 +1178,7 @@ static int sja1105_fdb_del(struct dsa_switch *ds, int port, { struct sja1105_private *priv = ds->priv; - if (!dsa_port_is_vlan_filtering(&ds->ports[port])) + if (!dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) vid = 0; return priv->info->fdb_del_cmd(ds, port, addr, vid); @@ -1217,7 +1217,7 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port, u64_to_ether_addr(l2_lookup.macaddr, macaddr); /* We need to hide the dsa_8021q VLANs from the user. */ - if (!dsa_port_is_vlan_filtering(&ds->ports[port])) + if (!dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) l2_lookup.vlanid = 0; cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data); } @@ -1704,7 +1704,7 @@ static int sja1105_port_enable(struct dsa_switch *ds, int port, if (!dsa_is_user_port(ds, port)) return 0; - slave = ds->ports[port].slave; + slave = dsa_to_port(ds, port)->slave; slave->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; @@ -1736,7 +1736,7 @@ static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot, } /* Transfer skb to the host port. */ - dsa_enqueue_skb(skb, ds->ports[port].slave); + dsa_enqueue_skb(skb, dsa_to_port(ds, port)->slave); /* Wait until the switch has processed the frame */ do { @@ -2047,30 +2047,37 @@ static int sja1105_probe(struct spi_device *spi) dev_info(dev, "Probed switch chip: %s\n", priv->info->name); - ds = dsa_switch_alloc(dev, SJA1105_NUM_PORTS); + ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); if (!ds) return -ENOMEM; + ds->dev = dev; + ds->num_ports = SJA1105_NUM_PORTS; ds->ops = &sja1105_switch_ops; ds->priv = priv; priv->ds = ds; tagger_data = &priv->tagger_data; + mutex_init(&priv->ptp_data.lock); + mutex_init(&priv->mgmt_lock); + + sja1105_tas_setup(ds); + + rc = dsa_register_switch(priv->ds); + if (rc) + return rc; + /* Connections between dsa_port and sja1105_port */ for (i = 0; i < SJA1105_NUM_PORTS; i++) { struct sja1105_port *sp = &priv->ports[i]; - ds->ports[i].priv = sp; - sp->dp = &ds->ports[i]; + dsa_to_port(ds, i)->priv = sp; + sp->dp = dsa_to_port(ds, i); sp->data = tagger_data; } - mutex_init(&priv->ptp_data.lock); - mutex_init(&priv->mgmt_lock); - sja1105_tas_setup(ds); - - return dsa_register_switch(priv->ds); + return 0; } static int sja1105_remove(struct spi_device *spi) diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index b43096063cf4..783100397f8a 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -13,24 +13,6 @@ #define SJA1105_MAX_ADJ_PPB 32000000 #define SJA1105_SIZE_PTP_CMD 4 -/* Timestamps are in units of 8 ns clock ticks (equivalent to a fixed - * 125 MHz clock) so the scale factor (MULT / SHIFT) needs to be 8. - * Furthermore, wisely pick SHIFT as 28 bits, which translates - * MULT into 2^31 (0x80000000). This is the same value around which - * the hardware PTPCLKRATE is centered, so the same ppb conversion - * arithmetic can be reused. - */ -#define SJA1105_CC_SHIFT 28 -#define SJA1105_CC_MULT (8 << SJA1105_CC_SHIFT) - -/* Having 33 bits of cycle counter left until a 64-bit overflow during delta - * conversion, we multiply this by the 8 ns counter resolution and arrive at - * a comfortable 68.71 second refresh interval until the delta would cause - * an integer overflow, in absence of any other readout. - * Approximate to 1 minute. - */ -#define SJA1105_REFRESH_INTERVAL (HZ * 60) - /* This range is actually +/- SJA1105_MAX_ADJ_PPB * divided by 1000 (ppb -> ppm) and with a 16-bit * "fractional" part (actually fixed point). @@ -41,7 +23,7 @@ * * This forgoes a "ppb" numeric representation (up to NSEC_PER_SEC) * and defines the scaling factor between scaled_ppm and the actual - * frequency adjustments (both cycle counter and hardware). + * frequency adjustments of the PHC. * * ptpclkrate = scaled_ppm * 2^31 / (10^6 * 2^16) * simplifies to @@ -49,13 +31,15 @@ */ #define SJA1105_CC_MULT_NUM (1 << 9) #define SJA1105_CC_MULT_DEM 15625 +#define SJA1105_CC_MULT 0x80000000 + +enum sja1105_ptp_clk_mode { + PTP_ADD_MODE = 1, + PTP_SET_MODE = 0, +}; #define ptp_caps_to_data(d) \ container_of((d), struct sja1105_ptp_data, caps) -#define cc_to_ptp_data(d) \ - container_of((d), struct sja1105_ptp_data, tstamp_cc) -#define dw_to_ptp_data(d) \ - container_of((d), struct sja1105_ptp_data, refresh_work) #define ptp_data_to_sja1105(d) \ container_of((d), struct sja1105_private, ptp_data) @@ -220,6 +204,8 @@ int sja1105et_ptp_cmd(const struct dsa_switch *ds, sja1105_pack(buf, &valid, 31, 31, size); sja1105_pack(buf, &cmd->resptp, 2, 2, size); + sja1105_pack(buf, &cmd->corrclk4ts, 1, 1, size); + sja1105_pack(buf, &cmd->ptpclkadd, 0, 0, size); return sja1105_xfer_buf(priv, SPI_WRITE, regs->ptp_control, buf, SJA1105_SIZE_PTP_CMD); @@ -237,6 +223,8 @@ int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, sja1105_pack(buf, &valid, 31, 31, size); sja1105_pack(buf, &cmd->resptp, 3, 3, size); + sja1105_pack(buf, &cmd->corrclk4ts, 2, 2, size); + sja1105_pack(buf, &cmd->ptpclkadd, 0, 0, size); return sja1105_xfer_buf(priv, SPI_WRITE, regs->ptp_control, buf, SJA1105_SIZE_PTP_CMD); @@ -346,6 +334,22 @@ static int sja1105_ptpegr_ts_poll(struct dsa_switch *ds, int port, u64 *ts) return 0; } +/* Caller must hold ptp_data->lock */ +static int sja1105_ptpclkval_read(struct sja1105_private *priv, u64 *ticks) +{ + const struct sja1105_regs *regs = priv->info->regs; + + return sja1105_xfer_u64(priv, SPI_READ, regs->ptpclkval, ticks); +} + +/* Caller must hold ptp_data->lock */ +static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 ticks) +{ + const struct sja1105_regs *regs = priv->info->regs; + + return sja1105_xfer_u64(priv, SPI_WRITE, regs->ptpclkval, &ticks); +} + #define rxtstamp_to_tagger(d) \ container_of((d), struct sja1105_tagger_data, rxtstamp_work) #define tagger_to_sja1105(d) \ @@ -363,17 +367,22 @@ static void sja1105_rxtstamp_work(struct work_struct *work) while ((skb = skb_dequeue(&tagger_data->skb_rxtstamp_queue)) != NULL) { struct skb_shared_hwtstamps *shwt = skb_hwtstamps(skb); - u64 now, ts; + u64 ticks, ts; + int rc; - now = ptp_data->tstamp_cc.read(&ptp_data->tstamp_cc); + rc = sja1105_ptpclkval_read(priv, &ticks); + if (rc < 0) { + dev_err(ds->dev, "Failed to read PTP clock: %d\n", rc); + kfree_skb(skb); + continue; + } *shwt = (struct skb_shared_hwtstamps) {0}; ts = SJA1105_SKB_CB(skb)->meta_tstamp; - ts = sja1105_tstamp_reconstruct(ds, now, ts); - ts = timecounter_cyc2time(&ptp_data->tstamp_tc, ts); + ts = sja1105_tstamp_reconstruct(ds, ticks, ts); - shwt->hwtstamp = ns_to_ktime(ts); + shwt->hwtstamp = ns_to_ktime(sja1105_ticks_to_ns(ts)); netif_rx_ni(skb); } @@ -427,9 +436,6 @@ int sja1105_ptp_reset(struct dsa_switch *ds) dev_dbg(ds->dev, "Resetting PTP clock\n"); rc = priv->info->ptp_cmd(ds, &cmd); - timecounter_init(&ptp_data->tstamp_tc, &ptp_data->tstamp_cc, - ktime_to_ns(ktime_get_real())); - mutex_unlock(&ptp_data->lock); return rc; @@ -439,112 +445,106 @@ static int sja1105_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); - u64 ns; + struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); + u64 ticks = 0; + int rc; mutex_lock(&ptp_data->lock); - ns = timecounter_read(&ptp_data->tstamp_tc); + + rc = sja1105_ptpclkval_read(priv, &ticks); + *ts = ns_to_timespec64(sja1105_ticks_to_ns(ticks)); + mutex_unlock(&ptp_data->lock); - *ts = ns_to_timespec64(ns); + return rc; +} - return 0; +/* Caller must hold ptp_data->lock */ +static int sja1105_ptp_mode_set(struct sja1105_private *priv, + enum sja1105_ptp_clk_mode mode) +{ + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; + + if (ptp_data->cmd.ptpclkadd == mode) + return 0; + + ptp_data->cmd.ptpclkadd = mode; + + return priv->info->ptp_cmd(priv->ds, &ptp_data->cmd); } +/* Write to PTPCLKVAL while PTPCLKADD is 0 */ static int sja1105_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); - u64 ns = timespec64_to_ns(ts); + struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); + u64 ticks = ns_to_sja1105_ticks(timespec64_to_ns(ts)); + int rc; mutex_lock(&ptp_data->lock); - timecounter_init(&ptp_data->tstamp_tc, &ptp_data->tstamp_cc, ns); + + rc = sja1105_ptp_mode_set(priv, PTP_SET_MODE); + if (rc < 0) { + dev_err(priv->ds->dev, "Failed to put PTPCLK in set mode\n"); + goto out; + } + + rc = sja1105_ptpclkval_write(priv, ticks); +out: mutex_unlock(&ptp_data->lock); - return 0; + return rc; } static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); + struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); + const struct sja1105_regs *regs = priv->info->regs; + u32 clkrate32; s64 clkrate; + int rc; clkrate = (s64)scaled_ppm * SJA1105_CC_MULT_NUM; clkrate = div_s64(clkrate, SJA1105_CC_MULT_DEM); - mutex_lock(&ptp_data->lock); + /* Take a +/- value and re-center it around 2^31. */ + clkrate = SJA1105_CC_MULT + clkrate; + WARN_ON(abs(clkrate) >= GENMASK_ULL(31, 0)); + clkrate32 = clkrate; - /* Force a readout to update the timer *before* changing its frequency. - * - * This way, its corrected time curve can at all times be modeled - * as a linear "A * x + B" function, where: - * - * - B are past frequency adjustments and offset shifts, all - * accumulated into the cycle_last variable. - * - * - A is the new frequency adjustments we're just about to set. - * - * Reading now makes B accumulate the correct amount of time, - * corrected at the old rate, before changing it. - * - * Hardware timestamps then become simple points on the curve and - * are approximated using the above function. This is still better - * than letting the switch take the timestamps using the hardware - * rate-corrected clock (PTPCLKVAL) - the comparison in this case would - * be that we're shifting the ruler at the same time as we're taking - * measurements with it. - * - * The disadvantage is that it's possible to receive timestamps when - * a frequency adjustment took place in the near past. - * In this case they will be approximated using the new ppb value - * instead of a compound function made of two segments (one at the old - * and the other at the new rate) - introducing some inaccuracy. - */ - timecounter_read(&ptp_data->tstamp_tc); + mutex_lock(&ptp_data->lock); - ptp_data->tstamp_cc.mult = SJA1105_CC_MULT + clkrate; + rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->ptpclkrate, &clkrate32); mutex_unlock(&ptp_data->lock); - return 0; + return rc; } +/* Write to PTPCLKVAL while PTPCLKADD is 1 */ static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); - - mutex_lock(&ptp_data->lock); - timecounter_adjtime(&ptp_data->tstamp_tc, delta); - mutex_unlock(&ptp_data->lock); - - return 0; -} - -static u64 sja1105_ptptsclk_read(const struct cyclecounter *cc) -{ - struct sja1105_ptp_data *ptp_data = cc_to_ptp_data(cc); struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); - const struct sja1105_regs *regs = priv->info->regs; - u64 ptptsclk = 0; + s64 ticks = ns_to_sja1105_ticks(delta); int rc; - rc = sja1105_xfer_u64(priv, SPI_READ, regs->ptptsclk, &ptptsclk); - if (rc < 0) - dev_err_ratelimited(priv->ds->dev, - "failed to read ptp cycle counter: %d\n", - rc); - return ptptsclk; -} + mutex_lock(&ptp_data->lock); -static void sja1105_ptp_overflow_check(struct work_struct *work) -{ - struct delayed_work *dw = to_delayed_work(work); - struct sja1105_ptp_data *ptp_data = dw_to_ptp_data(dw); - struct timespec64 ts; + rc = sja1105_ptp_mode_set(priv, PTP_ADD_MODE); + if (rc < 0) { + dev_err(priv->ds->dev, "Failed to put PTPCLK in add mode\n"); + goto out; + } - sja1105_ptp_gettime(&ptp_data->caps, &ts); + rc = sja1105_ptpclkval_write(priv, ticks); - schedule_delayed_work(&ptp_data->refresh_work, - SJA1105_REFRESH_INTERVAL); +out: + mutex_unlock(&ptp_data->lock); + + return rc; } int sja1105_ptp_clock_register(struct dsa_switch *ds) @@ -553,13 +553,6 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds) struct sja1105_tagger_data *tagger_data = &priv->tagger_data; struct sja1105_ptp_data *ptp_data = &priv->ptp_data; - /* Set up the cycle counter */ - ptp_data->tstamp_cc = (struct cyclecounter) { - .read = sja1105_ptptsclk_read, - .mask = CYCLECOUNTER_MASK(64), - .shift = SJA1105_CC_SHIFT, - .mult = SJA1105_CC_MULT, - }; ptp_data->caps = (struct ptp_clock_info) { .owner = THIS_MODULE, .name = "SJA1105 PHC", @@ -578,8 +571,8 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds) if (IS_ERR_OR_NULL(ptp_data->clock)) return PTR_ERR(ptp_data->clock); - INIT_DELAYED_WORK(&ptp_data->refresh_work, sja1105_ptp_overflow_check); - schedule_delayed_work(&ptp_data->refresh_work, SJA1105_REFRESH_INTERVAL); + ptp_data->cmd.corrclk4ts = true; + ptp_data->cmd.ptpclkadd = PTP_SET_MODE; return sja1105_ptp_reset(ds); } @@ -594,7 +587,6 @@ void sja1105_ptp_clock_unregister(struct dsa_switch *ds) cancel_work_sync(&priv->tagger_data.rxtstamp_work); skb_queue_purge(&priv->tagger_data.skb_rxtstamp_queue); - cancel_delayed_work_sync(&ptp_data->refresh_work); ptp_clock_unregister(ptp_data->clock); ptp_data->clock = NULL; } @@ -605,14 +597,19 @@ void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, struct sja1105_private *priv = ds->priv; struct sja1105_ptp_data *ptp_data = &priv->ptp_data; struct skb_shared_hwtstamps shwt = {0}; - u64 now, ts; + u64 ticks, ts; int rc; skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; mutex_lock(&ptp_data->lock); - now = ptp_data->tstamp_cc.read(&ptp_data->tstamp_cc); + rc = sja1105_ptpclkval_read(priv, &ticks); + if (rc < 0) { + dev_err(ds->dev, "Failed to read PTP clock: %d\n", rc); + kfree_skb(skb); + goto out; + } rc = sja1105_ptpegr_ts_poll(ds, slot, &ts); if (rc < 0) { @@ -621,10 +618,9 @@ void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, goto out; } - ts = sja1105_tstamp_reconstruct(ds, now, ts); - ts = timecounter_cyc2time(&ptp_data->tstamp_tc, ts); + ts = sja1105_tstamp_reconstruct(ds, ticks, ts); - shwt.hwtstamp = ns_to_ktime(ts); + shwt.hwtstamp = ns_to_ktime(sja1105_ticks_to_ns(ts)); skb_complete_tx_timestamp(skb, &shwt); out: diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index 507107ffd6a3..243f130374d2 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -1,26 +1,37 @@ -/* SPDX-License-Identifier: GPL-2.0 - * Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com> +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com> */ #ifndef _SJA1105_PTP_H #define _SJA1105_PTP_H #if IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP) +/* Timestamps are in units of 8 ns clock ticks (equivalent to + * a fixed 125 MHz clock). + */ +#define SJA1105_TICK_NS 8 + +static inline s64 ns_to_sja1105_ticks(s64 ns) +{ + return ns / SJA1105_TICK_NS; +} + +static inline s64 sja1105_ticks_to_ns(s64 ticks) +{ + return ticks * SJA1105_TICK_NS; +} + struct sja1105_ptp_cmd { u64 resptp; /* reset */ + u64 corrclk4ts; /* use the corrected clock for timestamps */ + u64 ptpclkadd; /* enum sja1105_ptp_clk_mode */ }; struct sja1105_ptp_data { struct ptp_clock_info caps; struct ptp_clock *clock; struct sja1105_ptp_cmd cmd; - /* The cycle counter translates the PTP timestamps (based on - * a free-running counter) into a software time domain. - */ - struct cyclecounter tstamp_cc; - struct timecounter tstamp_tc; - struct delayed_work refresh_work; - /* Serializes all operations on the cycle counter */ + /* Serializes all operations on the PTP hardware clock */ struct mutex lock; }; diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index e25724d99594..ed02410a9366 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -516,9 +516,8 @@ static struct sja1105_regs sja1105et_regs = { .rmii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034}, .ptpegr_ts = {0xC0, 0xC2, 0xC4, 0xC6, 0xC8}, .ptp_control = 0x17, - .ptpclk = 0x18, /* Spans 0x18 to 0x19 */ + .ptpclkval = 0x18, /* Spans 0x18 to 0x19 */ .ptpclkrate = 0x1A, - .ptptsclk = 0x1B, /* Spans 0x1B to 0x1C */ }; static struct sja1105_regs sja1105pqrs_regs = { @@ -547,9 +546,8 @@ static struct sja1105_regs sja1105pqrs_regs = { .qlevel = {0x604, 0x614, 0x624, 0x634, 0x644}, .ptpegr_ts = {0xC0, 0xC4, 0xC8, 0xCC, 0xD0}, .ptp_control = 0x18, - .ptpclk = 0x19, + .ptpclkval = 0x19, .ptpclkrate = 0x1B, - .ptptsclk = 0x1C, }; struct sja1105_info sja1105e_info = { diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.h b/drivers/net/dsa/sja1105/sja1105_static_config.h index 7f87022a2d61..f4a5c5c04311 100644 --- a/drivers/net/dsa/sja1105/sja1105_static_config.h +++ b/drivers/net/dsa/sja1105/sja1105_static_config.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2016-2018, NXP Semiconductors +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2016-2018, NXP Semiconductors * Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com> */ #ifndef _SJA1105_STATIC_CONFIG_H diff --git a/drivers/net/dsa/sja1105/sja1105_tas.h b/drivers/net/dsa/sja1105/sja1105_tas.h index 0b803c30e640..0aad212d88b2 100644 --- a/drivers/net/dsa/sja1105/sja1105_tas.h +++ b/drivers/net/dsa/sja1105/sja1105_tas.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 - * Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com> +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com> */ #ifndef _SJA1105_TAS_H #define _SJA1105_TAS_H diff --git a/drivers/net/dsa/vitesse-vsc73xx-core.c b/drivers/net/dsa/vitesse-vsc73xx-core.c index 614377ef7956..42c1574d45f2 100644 --- a/drivers/net/dsa/vitesse-vsc73xx-core.c +++ b/drivers/net/dsa/vitesse-vsc73xx-core.c @@ -1178,9 +1178,12 @@ int vsc73xx_probe(struct vsc73xx *vsc) * We allocate 8 ports and avoid access to the nonexistant * ports. */ - vsc->ds = dsa_switch_alloc(dev, 8); + vsc->ds = devm_kzalloc(dev, sizeof(*vsc->ds), GFP_KERNEL); if (!vsc->ds) return -ENOMEM; + + vsc->ds->dev = dev; + vsc->ds->num_ports = 8; vsc->ds->priv = vsc; vsc->ds->ops = &vsc73xx_ds_ops; diff --git a/drivers/net/ethernet/aquantia/atlantic/Makefile b/drivers/net/ethernet/aquantia/atlantic/Makefile index 131cab855be7..0020726db204 100644 --- a/drivers/net/ethernet/aquantia/atlantic/Makefile +++ b/drivers/net/ethernet/aquantia/atlantic/Makefile @@ -24,8 +24,11 @@ atlantic-objs := aq_main.o \ aq_ethtool.o \ aq_drvinfo.o \ aq_filters.o \ + aq_phy.o \ hw_atl/hw_atl_a0.o \ hw_atl/hw_atl_b0.o \ hw_atl/hw_atl_utils.o \ hw_atl/hw_atl_utils_fw2x.o \ hw_atl/hw_atl_llh.o + +atlantic-$(CONFIG_PTP_1588_CLOCK) += aq_ptp.o
\ No newline at end of file diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h index 02f1b70c4e25..8c633caf79d2 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_cfg.h: Definition of configuration parameters and constants. */ @@ -27,7 +27,7 @@ #define AQ_CFG_INTERRUPT_MODERATION_USEC_MAX (0x1FF * 2) -#define AQ_CFG_IRQ_MASK 0x1FFU +#define AQ_CFG_IRQ_MASK 0x3FFU #define AQ_CFG_VECS_MAX 8U #define AQ_CFG_TCS_MAX 8U diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 24df132384fb..1ae8aabcc41a 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_ethtool.c: Definition of ethertool related functions. */ @@ -9,8 +9,11 @@ #include "aq_ethtool.h" #include "aq_nic.h" #include "aq_vec.h" +#include "aq_ptp.h" #include "aq_filters.h" +#include <linux/ptp_clock_kernel.h> + static void aq_ethtool_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *p) { @@ -377,6 +380,35 @@ static int aq_ethtool_set_wol(struct net_device *ndev, return err; } +static int aq_ethtool_get_ts_info(struct net_device *ndev, + struct ethtool_ts_info *info) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + + ethtool_op_get_ts_info(ndev, info); + + if (!aq_nic->aq_ptp) + return 0; + + info->so_timestamping |= + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + info->tx_types = BIT(HWTSTAMP_TX_OFF) | + BIT(HWTSTAMP_TX_ON); + + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE); + + info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_EVENT); + + info->phc_index = ptp_clock_index(aq_ptp_get_ptp_clock(aq_nic->aq_ptp)); + + return 0; +} + static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed) { u32 rate = 0; @@ -604,4 +636,5 @@ const struct ethtool_ops aq_ethtool_ops = { .set_link_ksettings = aq_ethtool_set_link_ksettings, .get_coalesce = aq_ethtool_get_coalesce, .set_coalesce = aq_ethtool_set_coalesce, + .get_ts_info = aq_ethtool_get_ts_info, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c index aee827f07c16..6102251bb909 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (C) 2014-2017 aQuantia Corporation. */ +/* Copyright (C) 2014-2019 aQuantia Corporation. */ /* File aq_filters.c: RX filters related functions. */ @@ -89,12 +89,14 @@ static int aq_check_approve_fl3l4(struct aq_nic_s *aq_nic, struct aq_hw_rx_fltrs_s *rx_fltrs, struct ethtool_rx_flow_spec *fsp) { + u32 last_location = AQ_RX_LAST_LOC_FL3L4 - + aq_nic->aq_hw_rx_fltrs.fl3l4.reserved_count; + if (fsp->location < AQ_RX_FIRST_LOC_FL3L4 || - fsp->location > AQ_RX_LAST_LOC_FL3L4) { + fsp->location > last_location) { netdev_err(aq_nic->ndev, "ethtool: location must be in range [%d, %d]", - AQ_RX_FIRST_LOC_FL3L4, - AQ_RX_LAST_LOC_FL3L4); + AQ_RX_FIRST_LOC_FL3L4, last_location); return -EINVAL; } if (rx_fltrs->fl3l4.is_ipv6 && rx_fltrs->fl3l4.active_ipv4) { @@ -124,12 +126,15 @@ aq_check_approve_fl2(struct aq_nic_s *aq_nic, struct aq_hw_rx_fltrs_s *rx_fltrs, struct ethtool_rx_flow_spec *fsp) { + u32 last_location = AQ_RX_LAST_LOC_FETHERT - + aq_nic->aq_hw_rx_fltrs.fet_reserved_count; + if (fsp->location < AQ_RX_FIRST_LOC_FETHERT || - fsp->location > AQ_RX_LAST_LOC_FETHERT) { + fsp->location > last_location) { netdev_err(aq_nic->ndev, "ethtool: location must be in range [%d, %d]", AQ_RX_FIRST_LOC_FETHERT, - AQ_RX_LAST_LOC_FETHERT); + last_location); return -EINVAL; } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index 53d7478689a0..5246cf44ce51 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_hw.h: Declaration of abstract interface for NIC hardware specific @@ -15,6 +15,9 @@ #include "aq_rss.h" #include "hw_atl/hw_atl_utils.h" +#define AQ_HW_MAC_COUNTER_HZ 312500000ll +#define AQ_HW_PHY_COUNTER_HZ 160000000ll + #define AQ_RX_FIRST_LOC_FVLANID 0U #define AQ_RX_LAST_LOC_FVLANID 15U #define AQ_RX_FIRST_LOC_FETHERT 16U @@ -94,6 +97,7 @@ struct aq_stats_s { #define AQ_HW_FLAG_STOPPING 0x00000008U #define AQ_HW_FLAG_RESETTING 0x00000010U #define AQ_HW_FLAG_CLOSING 0x00000020U +#define AQ_HW_PTP_AVAILABLE 0x01000000U #define AQ_HW_LINK_DOWN 0x04000000U #define AQ_HW_FLAG_ERR_UNPLUG 0x40000000U #define AQ_HW_FLAG_ERR_HW 0x80000000U @@ -135,6 +139,8 @@ struct aq_hw_s { u32 rpc_addr; u32 rpc_tid; struct hw_atl_utils_fw_rpc rpc; + s64 ptp_clk_offset; + u16 phy_id; }; struct aq_ring_s; @@ -235,6 +241,40 @@ struct aq_hw_ops { int (*hw_set_offload)(struct aq_hw_s *self, struct aq_nic_cfg_s *aq_nic_cfg); + int (*hw_tx_tc_mode_get)(struct aq_hw_s *self, u32 *tc_mode); + + int (*hw_rx_tc_mode_get)(struct aq_hw_s *self, u32 *tc_mode); + + int (*hw_ring_hwts_rx_fill)(struct aq_hw_s *self, + struct aq_ring_s *aq_ring); + + int (*hw_ring_hwts_rx_receive)(struct aq_hw_s *self, + struct aq_ring_s *ring); + + void (*hw_get_ptp_ts)(struct aq_hw_s *self, u64 *stamp); + + int (*hw_adj_clock_freq)(struct aq_hw_s *self, s32 delta); + + int (*hw_adj_sys_clock)(struct aq_hw_s *self, s64 delta); + + int (*hw_set_sys_clock)(struct aq_hw_s *self, u64 time, u64 ts); + + int (*hw_ts_to_sys_clock)(struct aq_hw_s *self, u64 ts, u64 *time); + + int (*hw_gpio_pulse)(struct aq_hw_s *self, u32 index, u64 start, + u32 period); + + int (*hw_extts_gpio_enable)(struct aq_hw_s *self, u32 index, + u32 enable); + + int (*hw_get_sync_ts)(struct aq_hw_s *self, u64 *ts); + + u16 (*rx_extract_ts)(struct aq_hw_s *self, u8 *p, unsigned int len, + u64 *timestamp); + + int (*extract_hwts)(struct aq_hw_s *self, u8 *p, unsigned int len, + u64 *timestamp); + int (*hw_set_fc)(struct aq_hw_s *self, u32 fc, u32 tc); }; @@ -267,6 +307,12 @@ struct aq_fw_ops { int (*set_power)(struct aq_hw_s *self, unsigned int power_state, u8 *mac); + int (*send_fw_request)(struct aq_hw_s *self, + const struct hw_fw_request_iface *fw_req, + size_t size); + + void (*enable_ptp)(struct aq_hw_s *self, int enable); + int (*set_eee_rate)(struct aq_hw_s *self, u32 speed); int (*get_eee_rate)(struct aq_hw_s *self, u32 *rate, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c index b4a0fb281e69..a26d4a69efad 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_main.c: Main file for aQuantia Linux driver. */ @@ -10,10 +10,13 @@ #include "aq_nic.h" #include "aq_pci_func.h" #include "aq_ethtool.h" +#include "aq_ptp.h" #include "aq_filters.h" #include <linux/netdevice.h> #include <linux/module.h> +#include <linux/ip.h> +#include <linux/udp.h> MODULE_LICENSE("GPL v2"); MODULE_VERSION(AQ_CFG_DRV_VERSION); @@ -93,6 +96,24 @@ static int aq_ndev_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct aq_nic_s *aq_nic = netdev_priv(ndev); + if (unlikely(aq_utils_obj_test(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP))) { + /* Hardware adds the Timestamp for PTPv2 802.AS1 + * and PTPv2 IPv4 UDP. + * We have to push even general 320 port messages to the ptp + * queue explicitly. This is a limitation of current firmware + * and hardware PTP design of the chip. Otherwise ptp stream + * will fail to sync + */ + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) || + unlikely((ip_hdr(skb)->version == 4) && + (ip_hdr(skb)->protocol == IPPROTO_UDP) && + ((udp_hdr(skb)->dest == htons(319)) || + (udp_hdr(skb)->dest == htons(320)))) || + unlikely(eth_hdr(skb)->h_proto == htons(ETH_P_1588))) + return aq_ptp_xmit(aq_nic, skb); + } + + skb_tx_timestamp(skb); return aq_nic_xmit(aq_nic, skb); } @@ -194,9 +215,88 @@ static void aq_ndev_set_multicast_settings(struct net_device *ndev) { struct aq_nic_s *aq_nic = netdev_priv(ndev); - aq_nic_set_packet_filter(aq_nic, ndev->flags); + (void)aq_nic_set_multicast_list(aq_nic, ndev); +} + +static int aq_ndev_config_hwtstamp(struct aq_nic_s *aq_nic, + struct hwtstamp_config *config) +{ + if (config->flags) + return -EINVAL; + + switch (config->tx_type) { + case HWTSTAMP_TX_OFF: + case HWTSTAMP_TX_ON: + break; + default: + return -ERANGE; + } + + switch (config->rx_filter) { + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + break; + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_NONE: + break; + default: + return -ERANGE; + } + + return aq_ptp_hwtstamp_config_set(aq_nic->aq_ptp, config); +} + +static int aq_ndev_hwtstamp_set(struct aq_nic_s *aq_nic, struct ifreq *ifr) +{ + struct hwtstamp_config config; + int ret_val; + + if (!aq_nic->aq_ptp) + return -EOPNOTSUPP; + + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) + return -EFAULT; + + ret_val = aq_ndev_config_hwtstamp(aq_nic, &config); + if (ret_val) + return ret_val; + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + +static int aq_ndev_hwtstamp_get(struct aq_nic_s *aq_nic, struct ifreq *ifr) +{ + struct hwtstamp_config config; + + if (!aq_nic->aq_ptp) + return -EOPNOTSUPP; + + aq_ptp_hwtstamp_config_get(aq_nic->aq_ptp, &config); + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + +static int aq_ndev_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct aq_nic_s *aq_nic = netdev_priv(netdev); + + switch (cmd) { + case SIOCSHWTSTAMP: + return aq_ndev_hwtstamp_set(aq_nic, ifr); + + case SIOCGHWTSTAMP: + return aq_ndev_hwtstamp_get(aq_nic, ifr); + } - aq_nic_set_multicast_list(aq_nic, ndev); + return -EOPNOTSUPP; } static int aq_ndo_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, @@ -236,6 +336,7 @@ static const struct net_device_ops aq_ndev_ops = { .ndo_change_mtu = aq_ndev_change_mtu, .ndo_set_mac_address = aq_ndev_set_mac_address, .ndo_set_features = aq_ndev_set_features, + .ndo_do_ioctl = aq_ndev_ioctl, .ndo_vlan_rx_add_vid = aq_ndo_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = aq_ndo_vlan_rx_kill_vid, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 8f66e7817811..433adc099e44 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_nic.c: Definition of common code for NIC. */ @@ -12,6 +12,9 @@ #include "aq_hw.h" #include "aq_pci_func.h" #include "aq_main.h" +#include "aq_phy.h" +#include "aq_ptp.h" +#include "aq_filters.h" #include <linux/moduleparam.h> #include <linux/netdevice.h> @@ -145,6 +148,13 @@ static int aq_nic_update_link_status(struct aq_nic_s *self) self->aq_hw->aq_link_status.mbps); aq_nic_update_interrupt_moderation_settings(self); + if (self->aq_ptp) { + aq_ptp_clock_init(self); + aq_ptp_tm_offset_set(self, + self->aq_hw->aq_link_status.mbps); + aq_ptp_link_change(self); + } + /* Driver has to update flow control settings on RX block * on any link event. * We should query FW whether it negotiated FC. @@ -192,6 +202,8 @@ static void aq_nic_service_task(struct work_struct *work) service_task); int err; + aq_ptp_service_task(self); + if (aq_utils_obj_test(&self->flags, AQ_NIC_FLAGS_IS_NOT_READY)) return; @@ -327,10 +339,27 @@ int aq_nic_init(struct aq_nic_s *self) if (err < 0) goto err_exit; + if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_TP) { + self->aq_hw->phy_id = HW_ATL_PHY_ID_MAX; + err = aq_phy_init(self->aq_hw); + } + for (i = 0U, aq_vec = self->aq_vec[0]; self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) aq_vec_init(aq_vec, self->aq_hw_ops, self->aq_hw); + err = aq_ptp_init(self, self->irqvecs - 1); + if (err < 0) + goto err_exit; + + err = aq_ptp_ring_alloc(self); + if (err < 0) + goto err_exit; + + err = aq_ptp_ring_init(self); + if (err < 0) + goto err_exit; + netif_carrier_off(self->ndev); err_exit: @@ -361,6 +390,10 @@ int aq_nic_start(struct aq_nic_s *self) goto err_exit; } + err = aq_ptp_ring_start(self); + if (err < 0) + goto err_exit; + err = self->aq_hw_ops->hw_start(self->aq_hw); if (err < 0) goto err_exit; @@ -388,6 +421,10 @@ int aq_nic_start(struct aq_nic_s *self) goto err_exit; } + err = aq_ptp_irq_alloc(self); + if (err < 0) + goto err_exit; + if (self->aq_nic_cfg.link_irq_vec) { int irqvec = pci_irq_vector(self->pdev, self->aq_nic_cfg.link_irq_vec); @@ -420,9 +457,8 @@ err_exit: return err; } -static unsigned int aq_nic_map_skb(struct aq_nic_s *self, - struct sk_buff *skb, - struct aq_ring_s *ring) +unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb, + struct aq_ring_s *ring) { unsigned int ret = 0U; unsigned int nr_frags = skb_shinfo(skb)->nr_frags; @@ -631,9 +667,12 @@ err_exit: int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev) { - unsigned int packet_filter = self->packet_filter; + const struct aq_hw_ops *hw_ops = self->aq_hw_ops; + struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; + unsigned int packet_filter = ndev->flags; struct netdev_hw_addr *ha = NULL; unsigned int i = 0U; + int err = 0; self->mc_list.count = 0; if (netdev_uc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) { @@ -641,29 +680,28 @@ int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev) } else { netdev_for_each_uc_addr(ha, ndev) { ether_addr_copy(self->mc_list.ar[i++], ha->addr); - - if (i >= AQ_HW_MULTICAST_ADDRESS_MAX) - break; } } - if (i + netdev_mc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) { - packet_filter |= IFF_ALLMULTI; - } else { - netdev_for_each_mc_addr(ha, ndev) { - ether_addr_copy(self->mc_list.ar[i++], ha->addr); - - if (i >= AQ_HW_MULTICAST_ADDRESS_MAX) - break; + cfg->is_mc_list_enabled = !!(packet_filter & IFF_MULTICAST); + if (cfg->is_mc_list_enabled) { + if (i + netdev_mc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) { + packet_filter |= IFF_ALLMULTI; + } else { + netdev_for_each_mc_addr(ha, ndev) { + ether_addr_copy(self->mc_list.ar[i++], + ha->addr); + } } } if (i > 0 && i <= AQ_HW_MULTICAST_ADDRESS_MAX) { - packet_filter |= IFF_MULTICAST; self->mc_list.count = i; - self->aq_hw_ops->hw_multicast_list_set(self->aq_hw, - self->mc_list.ar, - self->mc_list.count); + err = hw_ops->hw_multicast_list_set(self->aq_hw, + self->mc_list.ar, + self->mc_list.count); + if (err < 0) + return err; } return aq_nic_set_packet_filter(self, packet_filter); } @@ -951,10 +989,14 @@ int aq_nic_stop(struct aq_nic_s *self) else aq_pci_func_free_irqs(self); + aq_ptp_irq_free(self); + for (i = 0U, aq_vec = self->aq_vec[0]; self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) aq_vec_stop(aq_vec); + aq_ptp_ring_stop(self); + return self->aq_hw_ops->hw_stop(self->aq_hw); } @@ -970,6 +1012,11 @@ void aq_nic_deinit(struct aq_nic_s *self) self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) aq_vec_deinit(aq_vec); + aq_ptp_unregister(self); + aq_ptp_ring_deinit(self); + aq_ptp_ring_free(self); + aq_ptp_free(self); + if (likely(self->aq_fw_ops->deinit)) { mutex_lock(&self->fwreq_mutex); self->aq_fw_ops->deinit(self->aq_hw); @@ -1066,3 +1113,46 @@ void aq_nic_shutdown(struct aq_nic_s *self) err_exit: rtnl_unlock(); } + +u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type) +{ + u8 location = 0xFF; + u32 fltr_cnt; + u32 n_bit; + + switch (type) { + case aq_rx_filter_ethertype: + location = AQ_RX_LAST_LOC_FETHERT - AQ_RX_FIRST_LOC_FETHERT - + self->aq_hw_rx_fltrs.fet_reserved_count; + self->aq_hw_rx_fltrs.fet_reserved_count++; + break; + case aq_rx_filter_l3l4: + fltr_cnt = AQ_RX_LAST_LOC_FL3L4 - AQ_RX_FIRST_LOC_FL3L4; + n_bit = fltr_cnt - self->aq_hw_rx_fltrs.fl3l4.reserved_count; + + self->aq_hw_rx_fltrs.fl3l4.active_ipv4 |= BIT(n_bit); + self->aq_hw_rx_fltrs.fl3l4.reserved_count++; + location = n_bit; + break; + default: + break; + } + + return location; +} + +void aq_nic_release_filter(struct aq_nic_s *self, enum aq_rx_filter_type type, + u32 location) +{ + switch (type) { + case aq_rx_filter_ethertype: + self->aq_hw_rx_fltrs.fet_reserved_count--; + break; + case aq_rx_filter_l3l4: + self->aq_hw_rx_fltrs.fl3l4.reserved_count--; + self->aq_hw_rx_fltrs.fl3l4.active_ipv4 &= ~BIT(location); + break; + default: + break; + } +} diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index 255b54a6ae07..c2513b79b9e9 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_nic.h: Declaration of common code for NIC. */ @@ -17,6 +17,8 @@ struct aq_ring_s; struct aq_hw_ops; struct aq_fw_s; struct aq_vec_s; +struct aq_ptp_s; +enum aq_rx_filter_type; struct aq_nic_cfg_s { const struct aq_hw_caps_s *aq_hw_caps; @@ -53,6 +55,7 @@ struct aq_nic_cfg_s { #define AQ_NIC_FLAG_STOPPING 0x00000008U #define AQ_NIC_FLAG_RESETTING 0x00000010U #define AQ_NIC_FLAG_CLOSING 0x00000020U +#define AQ_NIC_PTP_DPATH_UP 0x02000000U #define AQ_NIC_LINK_DOWN 0x04000000U #define AQ_NIC_FLAG_ERR_UNPLUG 0x40000000U #define AQ_NIC_FLAG_ERR_HW 0x80000000U @@ -70,6 +73,7 @@ struct aq_hw_rx_fl3l4 { u8 active_ipv4; u8 active_ipv6:2; u8 is_ipv6; + u8 reserved_count; }; struct aq_hw_rx_fltrs_s { @@ -77,6 +81,8 @@ struct aq_hw_rx_fltrs_s { u16 active_filters; struct aq_hw_rx_fl2 fl2; struct aq_hw_rx_fl3l4 fl3l4; + /*filter ether type */ + u8 fet_reserved_count; }; struct aq_nic_s { @@ -108,6 +114,8 @@ struct aq_nic_s { u32 irqvecs; /* mutex to serialize FW interface access operations */ struct mutex fwreq_mutex; + /* PTP support */ + struct aq_ptp_s *aq_ptp; struct aq_hw_rx_fltrs_s aq_hw_rx_fltrs; }; @@ -126,6 +134,8 @@ void aq_nic_cfg_start(struct aq_nic_s *self); int aq_nic_ndev_register(struct aq_nic_s *self); void aq_nic_ndev_free(struct aq_nic_s *self); int aq_nic_start(struct aq_nic_s *self); +unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb, + struct aq_ring_s *ring); int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb); int aq_nic_get_regs(struct aq_nic_s *self, struct ethtool_regs *regs, void *p); int aq_nic_get_regs_count(struct aq_nic_s *self); @@ -148,5 +158,7 @@ u32 aq_nic_get_fw_version(struct aq_nic_s *self); int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg); int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self); void aq_nic_shutdown(struct aq_nic_s *self); - +u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type); +void aq_nic_release_filter(struct aq_nic_s *self, enum aq_rx_filter_type type, + u32 location); #endif /* AQ_NIC_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index 74b9f3f1da81..e82c96b50373 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_pci_func.c: Definition of PCI functions. */ @@ -269,6 +269,9 @@ static int aq_pci_probe(struct pci_dev *pdev, numvecs = min((u8)AQ_CFG_VECS_DEF, aq_nic_get_cfg(self)->aq_hw_caps->msix_irqs); numvecs = min(numvecs, num_online_cpus()); + /* Request IRQ vector for PTP */ + numvecs += 1; + numvecs += AQ_HW_SERVICE_IRQS; /*enable interrupts */ #if !AQ_CFG_FORCE_LEGACY_INT diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_phy.c b/drivers/net/ethernet/aquantia/atlantic/aq_phy.c new file mode 100644 index 000000000000..51ae921e3e1f --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic/aq_phy.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* aQuantia Corporation Network Driver + * Copyright (C) 2018-2019 aQuantia Corporation. All rights reserved + */ + +#include "aq_phy.h" + +bool aq_mdio_busy_wait(struct aq_hw_s *aq_hw) +{ + int err = 0; + u32 val; + + err = readx_poll_timeout_atomic(hw_atl_mdio_busy_get, aq_hw, + val, val == 0U, 10U, 100000U); + + if (err < 0) + return false; + + return true; +} + +u16 aq_mdio_read_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr) +{ + u16 phy_addr = aq_hw->phy_id << 5 | mmd; + + /* Set Address register. */ + hw_atl_glb_mdio_iface4_set(aq_hw, (addr & HW_ATL_MDIO_ADDRESS_MSK) << + HW_ATL_MDIO_ADDRESS_SHIFT); + /* Send Address command. */ + hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK | + (3 << HW_ATL_MDIO_OP_MODE_SHIFT) | + ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) << + HW_ATL_MDIO_PHY_ADDRESS_SHIFT)); + + aq_mdio_busy_wait(aq_hw); + + /* Send Read command. */ + hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK | + (1 << HW_ATL_MDIO_OP_MODE_SHIFT) | + ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) << + HW_ATL_MDIO_PHY_ADDRESS_SHIFT)); + /* Read result. */ + aq_mdio_busy_wait(aq_hw); + + return (u16)hw_atl_glb_mdio_iface5_get(aq_hw); +} + +void aq_mdio_write_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr, u16 data) +{ + u16 phy_addr = aq_hw->phy_id << 5 | mmd; + + /* Set Address register. */ + hw_atl_glb_mdio_iface4_set(aq_hw, (addr & HW_ATL_MDIO_ADDRESS_MSK) << + HW_ATL_MDIO_ADDRESS_SHIFT); + /* Send Address command. */ + hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK | + (3 << HW_ATL_MDIO_OP_MODE_SHIFT) | + ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) << + HW_ATL_MDIO_PHY_ADDRESS_SHIFT)); + + aq_mdio_busy_wait(aq_hw); + + hw_atl_glb_mdio_iface3_set(aq_hw, (data & HW_ATL_MDIO_WRITE_DATA_MSK) << + HW_ATL_MDIO_WRITE_DATA_SHIFT); + /* Send Write command. */ + hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK | + (2 << HW_ATL_MDIO_OP_MODE_SHIFT) | + ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) << + HW_ATL_MDIO_PHY_ADDRESS_SHIFT)); + + aq_mdio_busy_wait(aq_hw); +} + +u16 aq_phy_read_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address) +{ + int err = 0; + u32 val; + + err = readx_poll_timeout_atomic(hw_atl_sem_mdio_get, aq_hw, + val, val == 1U, 10U, 100000U); + + if (err < 0) { + err = 0xffff; + goto err_exit; + } + + err = aq_mdio_read_word(aq_hw, mmd, address); + + hw_atl_reg_glb_cpu_sem_set(aq_hw, 1U, HW_ATL_FW_SM_MDIO); + +err_exit: + return err; +} + +void aq_phy_write_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address, u16 data) +{ + int err = 0; + u32 val; + + err = readx_poll_timeout_atomic(hw_atl_sem_mdio_get, aq_hw, + val, val == 1U, 10U, 100000U); + if (err < 0) + return; + + aq_mdio_write_word(aq_hw, mmd, address, data); + hw_atl_reg_glb_cpu_sem_set(aq_hw, 1U, HW_ATL_FW_SM_MDIO); +} + +bool aq_phy_init_phy_id(struct aq_hw_s *aq_hw) +{ + u16 val; + + for (aq_hw->phy_id = 0; aq_hw->phy_id < HW_ATL_PHY_ID_MAX; + ++aq_hw->phy_id) { + /* PMA Standard Device Identifier 2: Address 1.3 */ + val = aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 3); + + if (val != 0xffff) + return true; + } + + return false; +} + +bool aq_phy_init(struct aq_hw_s *aq_hw) +{ + u32 dev_id; + + if (aq_hw->phy_id == HW_ATL_PHY_ID_MAX) + if (!aq_phy_init_phy_id(aq_hw)) + return false; + + /* PMA Standard Device Identifier: + * Address 1.2 = MSW, + * Address 1.3 = LSW + */ + dev_id = aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 2); + dev_id <<= 16; + dev_id |= aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 3); + + if (dev_id == 0xffffffff) { + aq_hw->phy_id = HW_ATL_PHY_ID_MAX; + return false; + } + + return true; +} diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_phy.h b/drivers/net/ethernet/aquantia/atlantic/aq_phy.h new file mode 100644 index 000000000000..84b72ad04a4a --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic/aq_phy.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* aQuantia Corporation Network Driver + * Copyright (C) 2018-2019 aQuantia Corporation. All rights reserved + */ + +#ifndef AQ_PHY_H +#define AQ_PHY_H + +#include <linux/mdio.h> + +#include "hw_atl/hw_atl_llh.h" +#include "hw_atl/hw_atl_llh_internal.h" +#include "aq_hw_utils.h" +#include "aq_hw.h" + +#define HW_ATL_PHY_ID_MAX 32U + +bool aq_mdio_busy_wait(struct aq_hw_s *aq_hw); + +u16 aq_mdio_read_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr); + +void aq_mdio_write_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr, u16 data); + +u16 aq_phy_read_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address); + +void aq_phy_write_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address, u16 data); + +bool aq_phy_init_phy_id(struct aq_hw_s *aq_hw); + +bool aq_phy_init(struct aq_hw_s *aq_hw); + +#endif /* AQ_PHY_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c new file mode 100644 index 000000000000..bb6fbbadfd47 --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -0,0 +1,1390 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Aquantia Corporation Network Driver + * Copyright (C) 2014-2019 Aquantia Corporation. All rights reserved + */ + +/* File aq_ptp.c: + * Definition of functions for Linux PTP support. + */ + +#include <linux/ptp_clock_kernel.h> +#include <linux/ptp_classify.h> +#include <linux/interrupt.h> +#include <linux/clocksource.h> + +#include "aq_nic.h" +#include "aq_ptp.h" +#include "aq_ring.h" +#include "aq_phy.h" +#include "aq_filters.h" + +#define AQ_PTP_TX_TIMEOUT (HZ * 10) + +#define POLL_SYNC_TIMER_MS 15 + +enum ptp_speed_offsets { + ptp_offset_idx_10 = 0, + ptp_offset_idx_100, + ptp_offset_idx_1000, + ptp_offset_idx_2500, + ptp_offset_idx_5000, + ptp_offset_idx_10000, +}; + +struct ptp_skb_ring { + struct sk_buff **buff; + spinlock_t lock; + unsigned int size; + unsigned int head; + unsigned int tail; +}; + +struct ptp_tx_timeout { + spinlock_t lock; + bool active; + unsigned long tx_start; +}; + +struct aq_ptp_s { + struct aq_nic_s *aq_nic; + struct hwtstamp_config hwtstamp_config; + spinlock_t ptp_lock; + spinlock_t ptp_ring_lock; + struct ptp_clock *ptp_clock; + struct ptp_clock_info ptp_info; + + atomic_t offset_egress; + atomic_t offset_ingress; + + struct aq_ring_param_s ptp_ring_param; + + struct ptp_tx_timeout ptp_tx_timeout; + + unsigned int idx_vector; + struct napi_struct napi; + + struct aq_ring_s ptp_tx; + struct aq_ring_s ptp_rx; + struct aq_ring_s hwts_rx; + + struct ptp_skb_ring skb_ring; + + struct aq_rx_filter_l3l4 udp_filter; + struct aq_rx_filter_l2 eth_type_filter; + + struct delayed_work poll_sync; + u32 poll_timeout_ms; + + bool extts_pin_enabled; + u64 last_sync1588_ts; +}; + +struct ptp_tm_offset { + unsigned int mbps; + int egress; + int ingress; +}; + +static struct ptp_tm_offset ptp_offset[6]; + +void aq_ptp_tm_offset_set(struct aq_nic_s *aq_nic, unsigned int mbps) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + int i, egress, ingress; + + if (!aq_ptp) + return; + + egress = 0; + ingress = 0; + + for (i = 0; i < ARRAY_SIZE(ptp_offset); i++) { + if (mbps == ptp_offset[i].mbps) { + egress = ptp_offset[i].egress; + ingress = ptp_offset[i].ingress; + break; + } + } + + atomic_set(&aq_ptp->offset_egress, egress); + atomic_set(&aq_ptp->offset_ingress, ingress); +} + +static int __aq_ptp_skb_put(struct ptp_skb_ring *ring, struct sk_buff *skb) +{ + unsigned int next_head = (ring->head + 1) % ring->size; + + if (next_head == ring->tail) + return -ENOMEM; + + ring->buff[ring->head] = skb_get(skb); + ring->head = next_head; + + return 0; +} + +static int aq_ptp_skb_put(struct ptp_skb_ring *ring, struct sk_buff *skb) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&ring->lock, flags); + ret = __aq_ptp_skb_put(ring, skb); + spin_unlock_irqrestore(&ring->lock, flags); + + return ret; +} + +static struct sk_buff *__aq_ptp_skb_get(struct ptp_skb_ring *ring) +{ + struct sk_buff *skb; + + if (ring->tail == ring->head) + return NULL; + + skb = ring->buff[ring->tail]; + ring->tail = (ring->tail + 1) % ring->size; + + return skb; +} + +static struct sk_buff *aq_ptp_skb_get(struct ptp_skb_ring *ring) +{ + unsigned long flags; + struct sk_buff *skb; + + spin_lock_irqsave(&ring->lock, flags); + skb = __aq_ptp_skb_get(ring); + spin_unlock_irqrestore(&ring->lock, flags); + + return skb; +} + +static unsigned int aq_ptp_skb_buf_len(struct ptp_skb_ring *ring) +{ + unsigned long flags; + unsigned int len; + + spin_lock_irqsave(&ring->lock, flags); + len = (ring->head >= ring->tail) ? + ring->head - ring->tail : + ring->size - ring->tail + ring->head; + spin_unlock_irqrestore(&ring->lock, flags); + + return len; +} + +static int aq_ptp_skb_ring_init(struct ptp_skb_ring *ring, unsigned int size) +{ + struct sk_buff **buff = kmalloc(sizeof(*buff) * size, GFP_KERNEL); + + if (!buff) + return -ENOMEM; + + spin_lock_init(&ring->lock); + + ring->buff = buff; + ring->size = size; + ring->head = 0; + ring->tail = 0; + + return 0; +} + +static void aq_ptp_skb_ring_clean(struct ptp_skb_ring *ring) +{ + struct sk_buff *skb; + + while ((skb = aq_ptp_skb_get(ring)) != NULL) + dev_kfree_skb_any(skb); +} + +static void aq_ptp_skb_ring_release(struct ptp_skb_ring *ring) +{ + if (ring->buff) { + aq_ptp_skb_ring_clean(ring); + kfree(ring->buff); + ring->buff = NULL; + } +} + +static void aq_ptp_tx_timeout_init(struct ptp_tx_timeout *timeout) +{ + spin_lock_init(&timeout->lock); + timeout->active = false; +} + +static void aq_ptp_tx_timeout_start(struct aq_ptp_s *aq_ptp) +{ + struct ptp_tx_timeout *timeout = &aq_ptp->ptp_tx_timeout; + unsigned long flags; + + spin_lock_irqsave(&timeout->lock, flags); + timeout->active = true; + timeout->tx_start = jiffies; + spin_unlock_irqrestore(&timeout->lock, flags); +} + +static void aq_ptp_tx_timeout_update(struct aq_ptp_s *aq_ptp) +{ + if (!aq_ptp_skb_buf_len(&aq_ptp->skb_ring)) { + struct ptp_tx_timeout *timeout = &aq_ptp->ptp_tx_timeout; + unsigned long flags; + + spin_lock_irqsave(&timeout->lock, flags); + timeout->active = false; + spin_unlock_irqrestore(&timeout->lock, flags); + } +} + +static void aq_ptp_tx_timeout_check(struct aq_ptp_s *aq_ptp) +{ + struct ptp_tx_timeout *timeout = &aq_ptp->ptp_tx_timeout; + unsigned long flags; + bool timeout_flag; + + timeout_flag = false; + + spin_lock_irqsave(&timeout->lock, flags); + if (timeout->active) { + timeout_flag = time_is_before_jiffies(timeout->tx_start + + AQ_PTP_TX_TIMEOUT); + /* reset active flag if timeout detected */ + if (timeout_flag) + timeout->active = false; + } + spin_unlock_irqrestore(&timeout->lock, flags); + + if (timeout_flag) { + aq_ptp_skb_ring_clean(&aq_ptp->skb_ring); + netdev_err(aq_ptp->aq_nic->ndev, + "PTP Timeout. Clearing Tx Timestamp SKBs\n"); + } +} + +/* aq_ptp_adjfine + * @ptp: the ptp clock structure + * @ppb: parts per billion adjustment from base + * + * adjust the frequency of the ptp cycle counter by the + * indicated ppb from the base frequency. + */ +static int aq_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + + mutex_lock(&aq_nic->fwreq_mutex); + aq_nic->aq_hw_ops->hw_adj_clock_freq(aq_nic->aq_hw, + scaled_ppm_to_ppb(scaled_ppm)); + mutex_unlock(&aq_nic->fwreq_mutex); + + return 0; +} + +/* aq_ptp_adjtime + * @ptp: the ptp clock structure + * @delta: offset to adjust the cycle counter by + * + * adjust the timer by resetting the timecounter structure. + */ +static int aq_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + unsigned long flags; + + spin_lock_irqsave(&aq_ptp->ptp_lock, flags); + aq_nic->aq_hw_ops->hw_adj_sys_clock(aq_nic->aq_hw, delta); + spin_unlock_irqrestore(&aq_ptp->ptp_lock, flags); + + return 0; +} + +/* aq_ptp_gettime + * @ptp: the ptp clock structure + * @ts: timespec structure to hold the current time value + * + * read the timecounter and return the correct value on ns, + * after converting it into a struct timespec. + */ +static int aq_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + unsigned long flags; + u64 ns; + + spin_lock_irqsave(&aq_ptp->ptp_lock, flags); + aq_nic->aq_hw_ops->hw_get_ptp_ts(aq_nic->aq_hw, &ns); + spin_unlock_irqrestore(&aq_ptp->ptp_lock, flags); + + *ts = ns_to_timespec64(ns); + + return 0; +} + +/* aq_ptp_settime + * @ptp: the ptp clock structure + * @ts: the timespec containing the new time for the cycle counter + * + * reset the timecounter to use a new base value instead of the kernel + * wall timer value. + */ +static int aq_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + unsigned long flags; + u64 ns = timespec64_to_ns(ts); + u64 now; + + spin_lock_irqsave(&aq_ptp->ptp_lock, flags); + aq_nic->aq_hw_ops->hw_get_ptp_ts(aq_nic->aq_hw, &now); + aq_nic->aq_hw_ops->hw_adj_sys_clock(aq_nic->aq_hw, (s64)ns - (s64)now); + + spin_unlock_irqrestore(&aq_ptp->ptp_lock, flags); + + return 0; +} + +static void aq_ptp_convert_to_hwtstamp(struct aq_ptp_s *aq_ptp, + struct skb_shared_hwtstamps *hwtstamp, + u64 timestamp) +{ + memset(hwtstamp, 0, sizeof(*hwtstamp)); + hwtstamp->hwtstamp = ns_to_ktime(timestamp); +} + +static int aq_ptp_hw_pin_conf(struct aq_nic_s *aq_nic, u32 pin_index, u64 start, + u64 period) +{ + if (period) + netdev_dbg(aq_nic->ndev, + "Enable GPIO %d pulsing, start time %llu, period %u\n", + pin_index, start, (u32)period); + else + netdev_dbg(aq_nic->ndev, + "Disable GPIO %d pulsing, start time %llu, period %u\n", + pin_index, start, (u32)period); + + /* Notify hardware of request to being sending pulses. + * If period is ZERO then pulsen is disabled. + */ + mutex_lock(&aq_nic->fwreq_mutex); + aq_nic->aq_hw_ops->hw_gpio_pulse(aq_nic->aq_hw, pin_index, + start, (u32)period); + mutex_unlock(&aq_nic->fwreq_mutex); + + return 0; +} + +static int aq_ptp_perout_pin_configure(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + struct ptp_clock_time *t = &rq->perout.period; + struct ptp_clock_time *s = &rq->perout.start; + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + u64 start, period; + u32 pin_index = rq->perout.index; + + /* verify the request channel is there */ + if (pin_index >= ptp->n_per_out) + return -EINVAL; + + /* we cannot support periods greater + * than 4 seconds due to reg limit + */ + if (t->sec > 4 || t->sec < 0) + return -ERANGE; + + /* convert to unsigned 64b ns, + * verify we can put it in a 32b register + */ + period = on ? t->sec * NSEC_PER_SEC + t->nsec : 0; + + /* verify the value is in range supported by hardware */ + if (period > U32_MAX) + return -ERANGE; + /* convert to unsigned 64b ns */ + /* TODO convert to AQ time */ + start = on ? s->sec * NSEC_PER_SEC + s->nsec : 0; + + aq_ptp_hw_pin_conf(aq_nic, pin_index, start, period); + + return 0; +} + +static int aq_ptp_pps_pin_configure(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + u64 start, period; + u32 pin_index = 0; + u32 rest = 0; + + /* verify the request channel is there */ + if (pin_index >= ptp->n_per_out) + return -EINVAL; + + aq_nic->aq_hw_ops->hw_get_ptp_ts(aq_nic->aq_hw, &start); + div_u64_rem(start, NSEC_PER_SEC, &rest); + period = on ? NSEC_PER_SEC : 0; /* PPS - pulse per second */ + start = on ? start - rest + NSEC_PER_SEC * + (rest > 990000000LL ? 2 : 1) : 0; + + aq_ptp_hw_pin_conf(aq_nic, pin_index, start, period); + + return 0; +} + +static void aq_ptp_extts_pin_ctrl(struct aq_ptp_s *aq_ptp) +{ + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + u32 enable = aq_ptp->extts_pin_enabled; + + if (aq_nic->aq_hw_ops->hw_extts_gpio_enable) + aq_nic->aq_hw_ops->hw_extts_gpio_enable(aq_nic->aq_hw, 0, + enable); +} + +static int aq_ptp_extts_pin_configure(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + + u32 pin_index = rq->extts.index; + + if (pin_index >= ptp->n_ext_ts) + return -EINVAL; + + aq_ptp->extts_pin_enabled = !!on; + if (on) { + aq_ptp->poll_timeout_ms = POLL_SYNC_TIMER_MS; + cancel_delayed_work_sync(&aq_ptp->poll_sync); + schedule_delayed_work(&aq_ptp->poll_sync, + msecs_to_jiffies(aq_ptp->poll_timeout_ms)); + } + + aq_ptp_extts_pin_ctrl(aq_ptp); + return 0; +} + +/* aq_ptp_gpio_feature_enable + * @ptp: the ptp clock structure + * @rq: the requested feature to change + * @on: whether to enable or disable the feature + */ +static int aq_ptp_gpio_feature_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + switch (rq->type) { + case PTP_CLK_REQ_EXTTS: + return aq_ptp_extts_pin_configure(ptp, rq, on); + case PTP_CLK_REQ_PEROUT: + return aq_ptp_perout_pin_configure(ptp, rq, on); + case PTP_CLK_REQ_PPS: + return aq_ptp_pps_pin_configure(ptp, rq, on); + default: + return -EOPNOTSUPP; + } + + return 0; +} + +/* aq_ptp_verify + * @ptp: the ptp clock structure + * @pin: index of the pin in question + * @func: the desired function to use + * @chan: the function channel index to use + */ +static int aq_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin, + enum ptp_pin_function func, unsigned int chan) +{ + /* verify the requested pin is there */ + if (!ptp->pin_config || pin >= ptp->n_pins) + return -EINVAL; + + /* enforce locked channels, no changing them */ + if (chan != ptp->pin_config[pin].chan) + return -EINVAL; + + /* we want to keep the functions locked as well */ + if (func != ptp->pin_config[pin].func) + return -EINVAL; + + return 0; +} + +/* aq_ptp_tx_hwtstamp - utility function which checks for TX time stamp + * @adapter: the private adapter struct + * + * if the timestamp is valid, we convert it into the timecounter ns + * value, then store that result into the hwtstamps structure which + * is passed up the network stack + */ +void aq_ptp_tx_hwtstamp(struct aq_nic_s *aq_nic, u64 timestamp) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + struct sk_buff *skb = aq_ptp_skb_get(&aq_ptp->skb_ring); + struct skb_shared_hwtstamps hwtstamp; + + if (!skb) { + netdev_err(aq_nic->ndev, "have timestamp but tx_queus empty\n"); + return; + } + + timestamp += atomic_read(&aq_ptp->offset_egress); + aq_ptp_convert_to_hwtstamp(aq_ptp, &hwtstamp, timestamp); + skb_tstamp_tx(skb, &hwtstamp); + dev_kfree_skb_any(skb); + + aq_ptp_tx_timeout_update(aq_ptp); +} + +/* aq_ptp_rx_hwtstamp - utility function which checks for RX time stamp + * @adapter: pointer to adapter struct + * @skb: particular skb to send timestamp with + * + * if the timestamp is valid, we convert it into the timecounter ns + * value, then store that result into the hwtstamps structure which + * is passed up the network stack + */ +static void aq_ptp_rx_hwtstamp(struct aq_ptp_s *aq_ptp, struct sk_buff *skb, + u64 timestamp) +{ + timestamp -= atomic_read(&aq_ptp->offset_ingress); + aq_ptp_convert_to_hwtstamp(aq_ptp, skb_hwtstamps(skb), timestamp); +} + +void aq_ptp_hwtstamp_config_get(struct aq_ptp_s *aq_ptp, + struct hwtstamp_config *config) +{ + *config = aq_ptp->hwtstamp_config; +} + +static void aq_ptp_prepare_filters(struct aq_ptp_s *aq_ptp) +{ + aq_ptp->udp_filter.cmd = HW_ATL_RX_ENABLE_FLTR_L3L4 | + HW_ATL_RX_ENABLE_CMP_PROT_L4 | + HW_ATL_RX_UDP | + HW_ATL_RX_ENABLE_CMP_DEST_PORT_L4 | + HW_ATL_RX_HOST << HW_ATL_RX_ACTION_FL3F4_SHIFT | + HW_ATL_RX_ENABLE_QUEUE_L3L4 | + aq_ptp->ptp_rx.idx << HW_ATL_RX_QUEUE_FL3L4_SHIFT; + aq_ptp->udp_filter.p_dst = PTP_EV_PORT; + + aq_ptp->eth_type_filter.ethertype = ETH_P_1588; + aq_ptp->eth_type_filter.queue = aq_ptp->ptp_rx.idx; +} + +int aq_ptp_hwtstamp_config_set(struct aq_ptp_s *aq_ptp, + struct hwtstamp_config *config) +{ + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + const struct aq_hw_ops *hw_ops; + int err = 0; + + hw_ops = aq_nic->aq_hw_ops; + if (config->tx_type == HWTSTAMP_TX_ON || + config->rx_filter == HWTSTAMP_FILTER_PTP_V2_EVENT) { + aq_ptp_prepare_filters(aq_ptp); + if (hw_ops->hw_filter_l3l4_set) { + err = hw_ops->hw_filter_l3l4_set(aq_nic->aq_hw, + &aq_ptp->udp_filter); + } + if (!err && hw_ops->hw_filter_l2_set) { + err = hw_ops->hw_filter_l2_set(aq_nic->aq_hw, + &aq_ptp->eth_type_filter); + } + aq_utils_obj_set(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP); + } else { + aq_ptp->udp_filter.cmd &= ~HW_ATL_RX_ENABLE_FLTR_L3L4; + if (hw_ops->hw_filter_l3l4_set) { + err = hw_ops->hw_filter_l3l4_set(aq_nic->aq_hw, + &aq_ptp->udp_filter); + } + if (!err && hw_ops->hw_filter_l2_clear) { + err = hw_ops->hw_filter_l2_clear(aq_nic->aq_hw, + &aq_ptp->eth_type_filter); + } + aq_utils_obj_clear(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP); + } + + if (err) + return -EREMOTEIO; + + aq_ptp->hwtstamp_config = *config; + + return 0; +} + +bool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return false; + + return &aq_ptp->ptp_tx == ring || + &aq_ptp->ptp_rx == ring || &aq_ptp->hwts_rx == ring; +} + +u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, struct sk_buff *skb, u8 *p, + unsigned int len) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + u64 timestamp = 0; + u16 ret = aq_nic->aq_hw_ops->rx_extract_ts(aq_nic->aq_hw, + p, len, ×tamp); + + if (ret > 0) + aq_ptp_rx_hwtstamp(aq_ptp, skb, timestamp); + + return ret; +} + +static int aq_ptp_poll(struct napi_struct *napi, int budget) +{ + struct aq_ptp_s *aq_ptp = container_of(napi, struct aq_ptp_s, napi); + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + bool was_cleaned = false; + int work_done = 0; + int err; + + /* Processing PTP TX traffic */ + err = aq_nic->aq_hw_ops->hw_ring_tx_head_update(aq_nic->aq_hw, + &aq_ptp->ptp_tx); + if (err < 0) + goto err_exit; + + if (aq_ptp->ptp_tx.sw_head != aq_ptp->ptp_tx.hw_head) { + aq_ring_tx_clean(&aq_ptp->ptp_tx); + + was_cleaned = true; + } + + /* Processing HW_TIMESTAMP RX traffic */ + err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_receive(aq_nic->aq_hw, + &aq_ptp->hwts_rx); + if (err < 0) + goto err_exit; + + if (aq_ptp->hwts_rx.sw_head != aq_ptp->hwts_rx.hw_head) { + aq_ring_hwts_rx_clean(&aq_ptp->hwts_rx, aq_nic); + + err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_fill(aq_nic->aq_hw, + &aq_ptp->hwts_rx); + + was_cleaned = true; + } + + /* Processing PTP RX traffic */ + err = aq_nic->aq_hw_ops->hw_ring_rx_receive(aq_nic->aq_hw, + &aq_ptp->ptp_rx); + if (err < 0) + goto err_exit; + + if (aq_ptp->ptp_rx.sw_head != aq_ptp->ptp_rx.hw_head) { + unsigned int sw_tail_old; + + err = aq_ring_rx_clean(&aq_ptp->ptp_rx, napi, &work_done, budget); + if (err < 0) + goto err_exit; + + sw_tail_old = aq_ptp->ptp_rx.sw_tail; + err = aq_ring_rx_fill(&aq_ptp->ptp_rx); + if (err < 0) + goto err_exit; + + err = aq_nic->aq_hw_ops->hw_ring_rx_fill(aq_nic->aq_hw, + &aq_ptp->ptp_rx, + sw_tail_old); + if (err < 0) + goto err_exit; + } + + if (was_cleaned) + work_done = budget; + + if (work_done < budget) { + napi_complete_done(napi, work_done); + aq_nic->aq_hw_ops->hw_irq_enable(aq_nic->aq_hw, + 1 << aq_ptp->ptp_ring_param.vec_idx); + } + +err_exit: + return work_done; +} + +static irqreturn_t aq_ptp_isr(int irq, void *private) +{ + struct aq_ptp_s *aq_ptp = private; + int err = 0; + + if (!aq_ptp) { + err = -EINVAL; + goto err_exit; + } + napi_schedule(&aq_ptp->napi); + +err_exit: + return err >= 0 ? IRQ_HANDLED : IRQ_NONE; +} + +int aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + struct aq_ring_s *ring = &aq_ptp->ptp_tx; + unsigned long irq_flags; + int err = NETDEV_TX_OK; + unsigned int frags; + + if (skb->len <= 0) { + dev_kfree_skb_any(skb); + goto err_exit; + } + + frags = skb_shinfo(skb)->nr_frags + 1; + /* Frags cannot be bigger 16KB + * because PTP usually works + * without Jumbo even in a background + */ + if (frags > AQ_CFG_SKB_FRAGS_MAX || frags > aq_ring_avail_dx(ring)) { + /* Drop packet because it doesn't make sence to delay it */ + dev_kfree_skb_any(skb); + goto err_exit; + } + + err = aq_ptp_skb_put(&aq_ptp->skb_ring, skb); + if (err) { + netdev_err(aq_nic->ndev, "SKB Ring is overflow (%u)!\n", + ring->size); + return NETDEV_TX_BUSY; + } + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + aq_ptp_tx_timeout_start(aq_ptp); + skb_tx_timestamp(skb); + + spin_lock_irqsave(&aq_nic->aq_ptp->ptp_ring_lock, irq_flags); + frags = aq_nic_map_skb(aq_nic, skb, ring); + + if (likely(frags)) { + err = aq_nic->aq_hw_ops->hw_ring_tx_xmit(aq_nic->aq_hw, + ring, frags); + if (err >= 0) { + ++ring->stats.tx.packets; + ring->stats.tx.bytes += skb->len; + } + } else { + err = NETDEV_TX_BUSY; + } + spin_unlock_irqrestore(&aq_nic->aq_ptp->ptp_ring_lock, irq_flags); + +err_exit: + return err; +} + +void aq_ptp_service_task(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return; + + aq_ptp_tx_timeout_check(aq_ptp); +} + +int aq_ptp_irq_alloc(struct aq_nic_s *aq_nic) +{ + struct pci_dev *pdev = aq_nic->pdev; + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + int err = 0; + + if (!aq_ptp) + return 0; + + if (pdev->msix_enabled || pdev->msi_enabled) { + err = request_irq(pci_irq_vector(pdev, aq_ptp->idx_vector), + aq_ptp_isr, 0, aq_nic->ndev->name, aq_ptp); + } else { + err = -EINVAL; + goto err_exit; + } + +err_exit: + return err; +} + +void aq_ptp_irq_free(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + struct pci_dev *pdev = aq_nic->pdev; + + if (!aq_ptp) + return; + + free_irq(pci_irq_vector(pdev, aq_ptp->idx_vector), aq_ptp); +} + +int aq_ptp_ring_init(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + int err = 0; + + if (!aq_ptp) + return 0; + + err = aq_ring_init(&aq_ptp->ptp_tx); + if (err < 0) + goto err_exit; + err = aq_nic->aq_hw_ops->hw_ring_tx_init(aq_nic->aq_hw, + &aq_ptp->ptp_tx, + &aq_ptp->ptp_ring_param); + if (err < 0) + goto err_exit; + + err = aq_ring_init(&aq_ptp->ptp_rx); + if (err < 0) + goto err_exit; + err = aq_nic->aq_hw_ops->hw_ring_rx_init(aq_nic->aq_hw, + &aq_ptp->ptp_rx, + &aq_ptp->ptp_ring_param); + if (err < 0) + goto err_exit; + + err = aq_ring_rx_fill(&aq_ptp->ptp_rx); + if (err < 0) + goto err_rx_free; + err = aq_nic->aq_hw_ops->hw_ring_rx_fill(aq_nic->aq_hw, + &aq_ptp->ptp_rx, + 0U); + if (err < 0) + goto err_rx_free; + + err = aq_ring_init(&aq_ptp->hwts_rx); + if (err < 0) + goto err_rx_free; + err = aq_nic->aq_hw_ops->hw_ring_rx_init(aq_nic->aq_hw, + &aq_ptp->hwts_rx, + &aq_ptp->ptp_ring_param); + if (err < 0) + goto err_exit; + err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_fill(aq_nic->aq_hw, + &aq_ptp->hwts_rx); + if (err < 0) + goto err_exit; + + return err; + +err_rx_free: + aq_ring_rx_deinit(&aq_ptp->ptp_rx); +err_exit: + return err; +} + +int aq_ptp_ring_start(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + int err = 0; + + if (!aq_ptp) + return 0; + + err = aq_nic->aq_hw_ops->hw_ring_tx_start(aq_nic->aq_hw, &aq_ptp->ptp_tx); + if (err < 0) + goto err_exit; + + err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw, &aq_ptp->ptp_rx); + if (err < 0) + goto err_exit; + + err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw, + &aq_ptp->hwts_rx); + if (err < 0) + goto err_exit; + + napi_enable(&aq_ptp->napi); + +err_exit: + return err; +} + +void aq_ptp_ring_stop(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return; + + aq_nic->aq_hw_ops->hw_ring_tx_stop(aq_nic->aq_hw, &aq_ptp->ptp_tx); + aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->ptp_rx); + + aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->hwts_rx); + + napi_disable(&aq_ptp->napi); +} + +void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp || !aq_ptp->ptp_tx.aq_nic || !aq_ptp->ptp_rx.aq_nic) + return; + + aq_ring_tx_clean(&aq_ptp->ptp_tx); + aq_ring_rx_deinit(&aq_ptp->ptp_rx); +} + +#define PTP_8TC_RING_IDX 8 +#define PTP_4TC_RING_IDX 16 +#define PTP_HWST_RING_IDX 31 + +int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + unsigned int tx_ring_idx, rx_ring_idx; + struct aq_ring_s *hwts; + u32 tx_tc_mode, rx_tc_mode; + struct aq_ring_s *ring; + int err; + + if (!aq_ptp) + return 0; + + /* Index must to be 8 (8 TCs) or 16 (4 TCs). + * It depends from Traffic Class mode. + */ + aq_nic->aq_hw_ops->hw_tx_tc_mode_get(aq_nic->aq_hw, &tx_tc_mode); + if (tx_tc_mode == 0) + tx_ring_idx = PTP_8TC_RING_IDX; + else + tx_ring_idx = PTP_4TC_RING_IDX; + + ring = aq_ring_tx_alloc(&aq_ptp->ptp_tx, aq_nic, + tx_ring_idx, &aq_nic->aq_nic_cfg); + if (!ring) { + err = -ENOMEM; + goto err_exit; + } + + aq_nic->aq_hw_ops->hw_rx_tc_mode_get(aq_nic->aq_hw, &rx_tc_mode); + if (rx_tc_mode == 0) + rx_ring_idx = PTP_8TC_RING_IDX; + else + rx_ring_idx = PTP_4TC_RING_IDX; + + ring = aq_ring_rx_alloc(&aq_ptp->ptp_rx, aq_nic, + rx_ring_idx, &aq_nic->aq_nic_cfg); + if (!ring) { + err = -ENOMEM; + goto err_exit_ptp_tx; + } + + hwts = aq_ring_hwts_rx_alloc(&aq_ptp->hwts_rx, aq_nic, PTP_HWST_RING_IDX, + aq_nic->aq_nic_cfg.rxds, + aq_nic->aq_nic_cfg.aq_hw_caps->rxd_size); + if (!hwts) { + err = -ENOMEM; + goto err_exit_ptp_rx; + } + + err = aq_ptp_skb_ring_init(&aq_ptp->skb_ring, aq_nic->aq_nic_cfg.rxds); + if (err != 0) { + err = -ENOMEM; + goto err_exit_hwts_rx; + } + + aq_ptp->ptp_ring_param.vec_idx = aq_ptp->idx_vector; + aq_ptp->ptp_ring_param.cpu = aq_ptp->ptp_ring_param.vec_idx + + aq_nic_get_cfg(aq_nic)->aq_rss.base_cpu_number; + cpumask_set_cpu(aq_ptp->ptp_ring_param.cpu, + &aq_ptp->ptp_ring_param.affinity_mask); + + return 0; + +err_exit_hwts_rx: + aq_ring_free(&aq_ptp->hwts_rx); +err_exit_ptp_rx: + aq_ring_free(&aq_ptp->ptp_rx); +err_exit_ptp_tx: + aq_ring_free(&aq_ptp->ptp_tx); +err_exit: + return err; +} + +void aq_ptp_ring_free(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return; + + aq_ring_free(&aq_ptp->ptp_tx); + aq_ring_free(&aq_ptp->ptp_rx); + aq_ring_free(&aq_ptp->hwts_rx); + + aq_ptp_skb_ring_release(&aq_ptp->skb_ring); +} + +#define MAX_PTP_GPIO_COUNT 4 + +static struct ptp_clock_info aq_ptp_clock = { + .owner = THIS_MODULE, + .name = "atlantic ptp", + .max_adj = 999999999, + .n_ext_ts = 0, + .pps = 0, + .adjfine = aq_ptp_adjfine, + .adjtime = aq_ptp_adjtime, + .gettime64 = aq_ptp_gettime, + .settime64 = aq_ptp_settime, + .n_per_out = 0, + .enable = aq_ptp_gpio_feature_enable, + .n_pins = 0, + .verify = aq_ptp_verify, + .pin_config = NULL, +}; + +#define ptp_offset_init(__idx, __mbps, __egress, __ingress) do { \ + ptp_offset[__idx].mbps = (__mbps); \ + ptp_offset[__idx].egress = (__egress); \ + ptp_offset[__idx].ingress = (__ingress); } \ + while (0) + +static void aq_ptp_offset_init_from_fw(const struct hw_aq_ptp_offset *offsets) +{ + int i; + + /* Load offsets for PTP */ + for (i = 0; i < ARRAY_SIZE(ptp_offset); i++) { + switch (i) { + /* 100M */ + case ptp_offset_idx_100: + ptp_offset_init(i, 100, + offsets->egress_100, + offsets->ingress_100); + break; + /* 1G */ + case ptp_offset_idx_1000: + ptp_offset_init(i, 1000, + offsets->egress_1000, + offsets->ingress_1000); + break; + /* 2.5G */ + case ptp_offset_idx_2500: + ptp_offset_init(i, 2500, + offsets->egress_2500, + offsets->ingress_2500); + break; + /* 5G */ + case ptp_offset_idx_5000: + ptp_offset_init(i, 5000, + offsets->egress_5000, + offsets->ingress_5000); + break; + /* 10G */ + case ptp_offset_idx_10000: + ptp_offset_init(i, 10000, + offsets->egress_10000, + offsets->ingress_10000); + break; + } + } +} + +static void aq_ptp_offset_init(const struct hw_aq_ptp_offset *offsets) +{ + memset(ptp_offset, 0, sizeof(ptp_offset)); + + aq_ptp_offset_init_from_fw(offsets); +} + +static void aq_ptp_gpio_init(struct ptp_clock_info *info, + struct hw_aq_info *hw_info) +{ + struct ptp_pin_desc pin_desc[MAX_PTP_GPIO_COUNT]; + u32 extts_pin_cnt = 0; + u32 out_pin_cnt = 0; + u32 i; + + memset(pin_desc, 0, sizeof(pin_desc)); + + for (i = 0; i < MAX_PTP_GPIO_COUNT - 1; i++) { + if (hw_info->gpio_pin[i] == + (GPIO_PIN_FUNCTION_PTP0 + out_pin_cnt)) { + snprintf(pin_desc[out_pin_cnt].name, + sizeof(pin_desc[out_pin_cnt].name), + "AQ_GPIO%d", i); + pin_desc[out_pin_cnt].index = out_pin_cnt; + pin_desc[out_pin_cnt].chan = out_pin_cnt; + pin_desc[out_pin_cnt++].func = PTP_PF_PEROUT; + } + } + + info->n_per_out = out_pin_cnt; + + if (hw_info->caps_ex & BIT(CAPS_EX_PHY_CTRL_TS_PIN)) { + extts_pin_cnt += 1; + + snprintf(pin_desc[out_pin_cnt].name, + sizeof(pin_desc[out_pin_cnt].name), + "AQ_GPIO%d", out_pin_cnt); + pin_desc[out_pin_cnt].index = out_pin_cnt; + pin_desc[out_pin_cnt].chan = 0; + pin_desc[out_pin_cnt].func = PTP_PF_EXTTS; + } + + info->n_pins = out_pin_cnt + extts_pin_cnt; + info->n_ext_ts = extts_pin_cnt; + + if (!info->n_pins) + return; + + info->pin_config = kcalloc(info->n_pins, sizeof(struct ptp_pin_desc), + GFP_KERNEL); + + if (!info->pin_config) + return; + + memcpy(info->pin_config, &pin_desc, + sizeof(struct ptp_pin_desc) * info->n_pins); +} + +void aq_ptp_clock_init(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + struct timespec64 ts; + + ktime_get_real_ts64(&ts); + aq_ptp_settime(&aq_ptp->ptp_info, &ts); +} + +static void aq_ptp_poll_sync_work_cb(struct work_struct *w); + +int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) +{ + struct hw_atl_utils_mbox mbox; + struct ptp_clock *clock; + struct aq_ptp_s *aq_ptp; + int err = 0; + + if (!aq_nic->aq_hw_ops->hw_get_ptp_ts) { + aq_nic->aq_ptp = NULL; + return 0; + } + + if (!aq_nic->aq_fw_ops->enable_ptp) { + aq_nic->aq_ptp = NULL; + return 0; + } + + hw_atl_utils_mpi_read_stats(aq_nic->aq_hw, &mbox); + + if (!(mbox.info.caps_ex & BIT(CAPS_EX_PHY_PTP_EN))) { + aq_nic->aq_ptp = NULL; + return 0; + } + + aq_ptp_offset_init(&mbox.info.ptp_offset); + + aq_ptp = kzalloc(sizeof(*aq_ptp), GFP_KERNEL); + if (!aq_ptp) { + err = -ENOMEM; + goto err_exit; + } + + aq_ptp->aq_nic = aq_nic; + + spin_lock_init(&aq_ptp->ptp_lock); + spin_lock_init(&aq_ptp->ptp_ring_lock); + + aq_ptp->ptp_info = aq_ptp_clock; + aq_ptp_gpio_init(&aq_ptp->ptp_info, &mbox.info); + clock = ptp_clock_register(&aq_ptp->ptp_info, &aq_nic->ndev->dev); + if (!clock || IS_ERR(clock)) { + netdev_err(aq_nic->ndev, "ptp_clock_register failed\n"); + err = PTR_ERR(clock); + goto err_exit; + } + aq_ptp->ptp_clock = clock; + aq_ptp_tx_timeout_init(&aq_ptp->ptp_tx_timeout); + + atomic_set(&aq_ptp->offset_egress, 0); + atomic_set(&aq_ptp->offset_ingress, 0); + + netif_napi_add(aq_nic_get_ndev(aq_nic), &aq_ptp->napi, + aq_ptp_poll, AQ_CFG_NAPI_WEIGHT); + + aq_ptp->idx_vector = idx_vec; + + aq_nic->aq_ptp = aq_ptp; + + /* enable ptp counter */ + aq_utils_obj_set(&aq_nic->aq_hw->flags, AQ_HW_PTP_AVAILABLE); + mutex_lock(&aq_nic->fwreq_mutex); + aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 1); + aq_ptp_clock_init(aq_nic); + mutex_unlock(&aq_nic->fwreq_mutex); + + INIT_DELAYED_WORK(&aq_ptp->poll_sync, &aq_ptp_poll_sync_work_cb); + aq_ptp->eth_type_filter.location = + aq_nic_reserve_filter(aq_nic, aq_rx_filter_ethertype); + aq_ptp->udp_filter.location = + aq_nic_reserve_filter(aq_nic, aq_rx_filter_l3l4); + + return 0; + +err_exit: + if (aq_ptp) + kfree(aq_ptp->ptp_info.pin_config); + kfree(aq_ptp); + aq_nic->aq_ptp = NULL; + return err; +} + +void aq_ptp_unregister(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return; + + ptp_clock_unregister(aq_ptp->ptp_clock); +} + +void aq_ptp_free(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return; + + aq_nic_release_filter(aq_nic, aq_rx_filter_ethertype, + aq_ptp->eth_type_filter.location); + aq_nic_release_filter(aq_nic, aq_rx_filter_l3l4, + aq_ptp->udp_filter.location); + cancel_delayed_work_sync(&aq_ptp->poll_sync); + /* disable ptp */ + mutex_lock(&aq_nic->fwreq_mutex); + aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 0); + mutex_unlock(&aq_nic->fwreq_mutex); + + kfree(aq_ptp->ptp_info.pin_config); + + netif_napi_del(&aq_ptp->napi); + kfree(aq_ptp); + aq_nic->aq_ptp = NULL; +} + +struct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp) +{ + return aq_ptp->ptp_clock; +} + +/* PTP external GPIO nanoseconds count */ +static uint64_t aq_ptp_get_sync1588_ts(struct aq_nic_s *aq_nic) +{ + u64 ts = 0; + + if (aq_nic->aq_hw_ops->hw_get_sync_ts) + aq_nic->aq_hw_ops->hw_get_sync_ts(aq_nic->aq_hw, &ts); + + return ts; +} + +static void aq_ptp_start_work(struct aq_ptp_s *aq_ptp) +{ + if (aq_ptp->extts_pin_enabled) { + aq_ptp->poll_timeout_ms = POLL_SYNC_TIMER_MS; + aq_ptp->last_sync1588_ts = + aq_ptp_get_sync1588_ts(aq_ptp->aq_nic); + schedule_delayed_work(&aq_ptp->poll_sync, + msecs_to_jiffies(aq_ptp->poll_timeout_ms)); + } +} + +int aq_ptp_link_change(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return 0; + + if (aq_nic->aq_hw->aq_link_status.mbps) + aq_ptp_start_work(aq_ptp); + else + cancel_delayed_work_sync(&aq_ptp->poll_sync); + + return 0; +} + +static bool aq_ptp_sync_ts_updated(struct aq_ptp_s *aq_ptp, u64 *new_ts) +{ + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + u64 sync_ts2; + u64 sync_ts; + + sync_ts = aq_ptp_get_sync1588_ts(aq_nic); + + if (sync_ts != aq_ptp->last_sync1588_ts) { + sync_ts2 = aq_ptp_get_sync1588_ts(aq_nic); + if (sync_ts != sync_ts2) { + sync_ts = sync_ts2; + sync_ts2 = aq_ptp_get_sync1588_ts(aq_nic); + if (sync_ts != sync_ts2) { + netdev_err(aq_nic->ndev, + "%s: Unable to get correct GPIO TS", + __func__); + sync_ts = 0; + } + } + + *new_ts = sync_ts; + return true; + } + return false; +} + +static int aq_ptp_check_sync1588(struct aq_ptp_s *aq_ptp) +{ + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + u64 sync_ts; + + /* Sync1588 pin was triggered */ + if (aq_ptp_sync_ts_updated(aq_ptp, &sync_ts)) { + if (aq_ptp->extts_pin_enabled) { + struct ptp_clock_event ptp_event; + u64 time = 0; + + aq_nic->aq_hw_ops->hw_ts_to_sys_clock(aq_nic->aq_hw, + sync_ts, &time); + ptp_event.index = aq_ptp->ptp_info.n_pins - 1; + ptp_event.timestamp = time; + + ptp_event.type = PTP_CLOCK_EXTTS; + ptp_clock_event(aq_ptp->ptp_clock, &ptp_event); + } + + aq_ptp->last_sync1588_ts = sync_ts; + } + + return 0; +} + +void aq_ptp_poll_sync_work_cb(struct work_struct *w) +{ + struct delayed_work *dw = to_delayed_work(w); + struct aq_ptp_s *aq_ptp = container_of(dw, struct aq_ptp_s, poll_sync); + + aq_ptp_check_sync1588(aq_ptp); + + if (aq_ptp->extts_pin_enabled) { + unsigned long timeout = msecs_to_jiffies(aq_ptp->poll_timeout_ms); + + schedule_delayed_work(&aq_ptp->poll_sync, timeout); + } +} diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h new file mode 100644 index 000000000000..bf503a40b6a4 --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Aquantia Corporation Network Driver + * Copyright (C) 2014-2019 Aquantia Corporation. All rights reserved + */ + +/* File aq_ptp.h: Declaration of PTP functions. + */ +#ifndef AQ_PTP_H +#define AQ_PTP_H + +#include <linux/net_tstamp.h> +#include <linux/version.h> + +#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK) + +/* Common functions */ +int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec); + +void aq_ptp_unregister(struct aq_nic_s *aq_nic); +void aq_ptp_free(struct aq_nic_s *aq_nic); + +int aq_ptp_irq_alloc(struct aq_nic_s *aq_nic); +void aq_ptp_irq_free(struct aq_nic_s *aq_nic); + +int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic); +void aq_ptp_ring_free(struct aq_nic_s *aq_nic); + +int aq_ptp_ring_init(struct aq_nic_s *aq_nic); +int aq_ptp_ring_start(struct aq_nic_s *aq_nic); +void aq_ptp_ring_stop(struct aq_nic_s *aq_nic); +void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic); + +void aq_ptp_service_task(struct aq_nic_s *aq_nic); + +void aq_ptp_tm_offset_set(struct aq_nic_s *aq_nic, unsigned int mbps); + +void aq_ptp_clock_init(struct aq_nic_s *aq_nic); + +/* Traffic processing functions */ +int aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb); +void aq_ptp_tx_hwtstamp(struct aq_nic_s *aq_nic, u64 timestamp); + +/* Must be to check available of PTP before call */ +void aq_ptp_hwtstamp_config_get(struct aq_ptp_s *aq_ptp, + struct hwtstamp_config *config); +int aq_ptp_hwtstamp_config_set(struct aq_ptp_s *aq_ptp, + struct hwtstamp_config *config); + +/* Return either ring is belong to PTP or not*/ +bool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring); + +u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, struct sk_buff *skb, u8 *p, + unsigned int len); + +struct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp); + +int aq_ptp_link_change(struct aq_nic_s *aq_nic); + +#else + +static inline int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) +{ + return 0; +} + +static inline void aq_ptp_unregister(struct aq_nic_s *aq_nic) {} + +static inline void aq_ptp_free(struct aq_nic_s *aq_nic) +{ +} + +static inline int aq_ptp_irq_alloc(struct aq_nic_s *aq_nic) +{ + return 0; +} + +static inline void aq_ptp_irq_free(struct aq_nic_s *aq_nic) +{ +} + +static inline int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic) +{ + return 0; +} + +static inline void aq_ptp_ring_free(struct aq_nic_s *aq_nic) {} + +static inline int aq_ptp_ring_init(struct aq_nic_s *aq_nic) +{ + return 0; +} + +static inline int aq_ptp_ring_start(struct aq_nic_s *aq_nic) +{ + return 0; +} + +static inline void aq_ptp_ring_stop(struct aq_nic_s *aq_nic) {} +static inline void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic) {} +static inline void aq_ptp_service_task(struct aq_nic_s *aq_nic) {} +static inline void aq_ptp_tm_offset_set(struct aq_nic_s *aq_nic, + unsigned int mbps) {} +static inline void aq_ptp_clock_init(struct aq_nic_s *aq_nic) {} +static inline int aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb) +{ + return -EOPNOTSUPP; +} + +static inline void aq_ptp_tx_hwtstamp(struct aq_nic_s *aq_nic, u64 timestamp) {} +static inline void aq_ptp_hwtstamp_config_get(struct aq_ptp_s *aq_ptp, + struct hwtstamp_config *config) {} +static inline int aq_ptp_hwtstamp_config_set(struct aq_ptp_s *aq_ptp, + struct hwtstamp_config *config) +{ + return 0; +} + +static inline bool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring) +{ + return false; +} + +static inline u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, + struct sk_buff *skb, u8 *p, + unsigned int len) +{ + return 0; +} + +static inline struct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp) +{ + return NULL; +} + +static inline int aq_ptp_link_change(struct aq_nic_s *aq_nic) +{ + return 0; +} +#endif + +#endif /* AQ_PTP_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index 3901d7994ca1..f756cc0bbdf0 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_ring.c: Definition of functions for Rx/Tx rings. */ @@ -10,6 +10,7 @@ #include "aq_nic.h" #include "aq_hw.h" #include "aq_hw_utils.h" +#include "aq_ptp.h" #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -177,6 +178,30 @@ err_exit: return self; } +struct aq_ring_s * +aq_ring_hwts_rx_alloc(struct aq_ring_s *self, struct aq_nic_s *aq_nic, + unsigned int idx, unsigned int size, unsigned int dx_size) +{ + struct device *dev = aq_nic_get_dev(aq_nic); + size_t sz = size * dx_size + AQ_CFG_RXDS_DEF; + + memset(self, 0, sizeof(*self)); + + self->aq_nic = aq_nic; + self->idx = idx; + self->size = size; + self->dx_size = dx_size; + + self->dx_ring = dma_alloc_coherent(dev, sz, &self->dx_ring_pa, + GFP_KERNEL); + if (!self->dx_ring) { + aq_ring_free(self); + return NULL; + } + + return self; +} + int aq_ring_init(struct aq_ring_s *self) { self->hw_head = 0; @@ -290,6 +315,7 @@ int aq_ring_rx_clean(struct aq_ring_s *self, self->sw_head = aq_ring_next_dx(self, self->sw_head), --budget, ++(*work_done)) { struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head]; + bool is_ptp_ring = aq_ptp_ring(self->aq_nic, self); struct aq_ring_buff_s *buff_ = NULL; struct sk_buff *skb = NULL; unsigned int next_ = 0U; @@ -313,6 +339,7 @@ int aq_ring_rx_clean(struct aq_ring_s *self, break; buff->is_error |= buff_->is_error; + buff->is_cso_err |= buff_->is_cso_err; } while (!buff_->is_eop); @@ -320,7 +347,7 @@ int aq_ring_rx_clean(struct aq_ring_s *self, err = 0; goto err_exit; } - if (buff->is_error) { + if (buff->is_error || buff->is_cso_err) { buff_ = buff; do { next_ = buff_->next, @@ -353,6 +380,11 @@ int aq_ring_rx_clean(struct aq_ring_s *self, err = -ENOMEM; goto err_exit; } + if (is_ptp_ring) + buff->len -= + aq_ptp_extract_ts(self->aq_nic, skb, + aq_buf_vaddr(&buff->rxdata), + buff->len); skb_put(skb, buff->len); page_ref_inc(buff->rxdata.page); } else { @@ -361,6 +393,11 @@ int aq_ring_rx_clean(struct aq_ring_s *self, err = -ENOMEM; goto err_exit; } + if (is_ptp_ring) + buff->len -= + aq_ptp_extract_ts(self->aq_nic, skb, + aq_buf_vaddr(&buff->rxdata), + buff->len); hdr_len = buff->len; if (hdr_len > AQ_CFG_RX_HDR_SIZE) @@ -420,8 +457,8 @@ int aq_ring_rx_clean(struct aq_ring_s *self, skb_set_hash(skb, buff->rss_hash, buff->is_hash_l4 ? PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_NONE); - - skb_record_rx_queue(skb, self->idx); + /* Send all PTP traffic to 0 queue */ + skb_record_rx_queue(skb, is_ptp_ring ? 0 : self->idx); ++self->stats.rx.packets; self->stats.rx.bytes += skb->len; @@ -433,6 +470,21 @@ err_exit: return err; } +void aq_ring_hwts_rx_clean(struct aq_ring_s *self, struct aq_nic_s *aq_nic) +{ + while (self->sw_head != self->hw_head) { + u64 ns; + + aq_nic->aq_hw_ops->extract_hwts(aq_nic->aq_hw, + self->dx_ring + + (self->sw_head * self->dx_size), + self->dx_size, &ns); + aq_ptp_tx_hwtstamp(aq_nic, ns); + + self->sw_head = aq_ring_next_dx(self, self->sw_head); + } +} + int aq_ring_rx_fill(struct aq_ring_s *self) { unsigned int page_order = self->page_order; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h index 47abd09d06c2..be3702a4dcc9 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_ring.h: Declaration of functions for Rx/Tx rings. */ @@ -174,4 +174,9 @@ int aq_ring_rx_clean(struct aq_ring_s *self, int budget); int aq_ring_rx_fill(struct aq_ring_s *self); +struct aq_ring_s *aq_ring_hwts_rx_alloc(struct aq_ring_s *self, + struct aq_nic_s *aq_nic, unsigned int idx, + unsigned int size, unsigned int dx_size); +void aq_ring_hwts_rx_clean(struct aq_ring_s *self, struct aq_nic_s *aq_nic); + #endif /* AQ_RING_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 30f7fc4c97ff..abee561ea54e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_b0.c: Definition of Atlantic hardware specific functions. */ @@ -10,6 +10,7 @@ #include "../aq_hw_utils.h" #include "../aq_ring.h" #include "../aq_nic.h" +#include "../aq_phy.h" #include "hw_atl_b0.h" #include "hw_atl_utils.h" #include "hw_atl_llh.h" @@ -49,6 +50,8 @@ .mac_regs_count = 88, \ .hw_alive_check_addr = 0x10U +#define FRAC_PER_NS 0x100000000LL + const struct aq_hw_caps_s hw_atl_b0_caps_aqc100 = { DEFAULT_B0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_FIBRE, @@ -124,13 +127,16 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) hw_atl_tps_tx_pkt_shed_desc_tc_arb_mode_set(self, 0U); hw_atl_tps_tx_pkt_shed_data_arb_mode_set(self, 0U); - hw_atl_tps_tx_pkt_shed_tc_data_max_credit_set(self, 0xFFF, 0U); - hw_atl_tps_tx_pkt_shed_tc_data_weight_set(self, 0x64, 0U); - hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(self, 0x50, 0U); - hw_atl_tps_tx_pkt_shed_desc_tc_weight_set(self, 0x1E, 0U); + tc = 0; + + /* TX Packet Scheduler Data TC0 */ + hw_atl_tps_tx_pkt_shed_tc_data_max_credit_set(self, 0xFFF, tc); + hw_atl_tps_tx_pkt_shed_tc_data_weight_set(self, 0x64, tc); + hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(self, 0x50, tc); + hw_atl_tps_tx_pkt_shed_desc_tc_weight_set(self, 0x1E, tc); - /* Tx buf size */ - buff_size = HW_ATL_B0_TXBUF_MAX; + /* Tx buf size TC0 */ + buff_size = HW_ATL_B0_TXBUF_MAX - HW_ATL_B0_PTP_TXBUF_SIZE; hw_atl_tpb_tx_pkt_buff_size_per_tc_set(self, buff_size, tc); hw_atl_tpb_tx_buff_hi_threshold_per_tc_set(self, @@ -141,10 +147,15 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) (buff_size * (1024 / 32U) * 50U) / 100U, tc); + /* Init TC2 for PTP_TX */ + tc = 2; + + hw_atl_tpb_tx_pkt_buff_size_per_tc_set(self, HW_ATL_B0_PTP_TXBUF_SIZE, + tc); /* QoS Rx buf size per TC */ tc = 0; - buff_size = HW_ATL_B0_RXBUF_MAX; + buff_size = HW_ATL_B0_RXBUF_MAX - HW_ATL_B0_PTP_RXBUF_SIZE; hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, buff_size, tc); hw_atl_rpb_rx_buff_hi_threshold_per_tc_set(self, @@ -158,6 +169,14 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) hw_atl_b0_set_fc(self, self->aq_nic_cfg->flow_control, tc); + /* Init TC2 for PTP_RX */ + tc = 2; + + hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, HW_ATL_B0_PTP_RXBUF_SIZE, + tc); + /* No flow control for PTP */ + hw_atl_rpb_rx_xoff_en_per_tc_set(self, 0U, tc); + /* QoS 802.1p priority -> TC mapping */ for (i_priority = 8U; i_priority--;) hw_atl_rpf_rpb_user_priority_tc_map_set(self, i_priority, 0U); @@ -664,6 +683,46 @@ static int hw_atl_b0_hw_ring_rx_fill(struct aq_hw_s *self, return aq_hw_err_from_flags(self); } +static int hw_atl_b0_hw_ring_hwts_rx_fill(struct aq_hw_s *self, + struct aq_ring_s *ring) +{ + unsigned int i; + + for (i = aq_ring_avail_dx(ring); i--; + ring->sw_tail = aq_ring_next_dx(ring, ring->sw_tail)) { + struct hw_atl_rxd_s *rxd = + (struct hw_atl_rxd_s *) + &ring->dx_ring[ring->sw_tail * HW_ATL_B0_RXD_SIZE]; + + rxd->buf_addr = ring->dx_ring_pa + ring->size * ring->dx_size; + rxd->hdr_addr = 0U; + } + /* Make sure descriptors are updated before bump tail*/ + wmb(); + + hw_atl_reg_rx_dma_desc_tail_ptr_set(self, ring->sw_tail, ring->idx); + + return aq_hw_err_from_flags(self); +} + +static int hw_atl_b0_hw_ring_hwts_rx_receive(struct aq_hw_s *self, + struct aq_ring_s *ring) +{ + while (ring->hw_head != ring->sw_tail) { + struct hw_atl_rxd_hwts_wb_s *hwts_wb = + (struct hw_atl_rxd_hwts_wb_s *) + (ring->dx_ring + (ring->hw_head * HW_ATL_B0_RXD_SIZE)); + + /* RxD is not done */ + if (!(hwts_wb->sec_lw0 & 0x1U)) + break; + + ring->hw_head = aq_ring_next_dx(ring, ring->hw_head); + } + + return aq_hw_err_from_flags(self); +} + static int hw_atl_b0_hw_ring_tx_head_update(struct aq_hw_s *self, struct aq_ring_s *ring) { @@ -818,14 +877,15 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self, cfg->is_vlan_force_promisc); hw_atl_rpfl2multicast_flr_en_set(self, - IS_FILTER_ENABLED(IFF_ALLMULTI), 0); + IS_FILTER_ENABLED(IFF_ALLMULTI) && + IS_FILTER_ENABLED(IFF_MULTICAST), 0); hw_atl_rpfl2_accept_all_mc_packets_set(self, - IS_FILTER_ENABLED(IFF_ALLMULTI)); + IS_FILTER_ENABLED(IFF_ALLMULTI) && + IS_FILTER_ENABLED(IFF_MULTICAST)); hw_atl_rpfl2broadcast_en_set(self, IS_FILTER_ENABLED(IFF_BROADCAST)); - cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST); for (i = HW_ATL_B0_MAC_MIN; i < HW_ATL_B0_MAC_MAX; ++i) hw_atl_rpfl2_uc_flr_en_set(self, @@ -968,14 +1028,26 @@ static int hw_atl_b0_hw_interrupt_moderation_set(struct aq_hw_s *self) static int hw_atl_b0_hw_stop(struct aq_hw_s *self) { + int err; + u32 val; + hw_atl_b0_hw_irq_disable(self, HW_ATL_B0_INT_MASK); /* Invalidate Descriptor Cache to prevent writing to the cached * descriptors and to the data pointer of those descriptors */ - hw_atl_rdm_rx_dma_desc_cache_init_set(self, 1); + hw_atl_rdm_rx_dma_desc_cache_init_tgl(self); - return aq_hw_err_from_flags(self); + err = aq_hw_err_from_flags(self); + + if (err) + goto err_exit; + + readx_poll_timeout_atomic(hw_atl_rdm_rx_dma_desc_cache_init_done_get, + self, val, val == 1, 1000U, 10000U); + +err_exit: + return err; } static int hw_atl_b0_hw_ring_tx_stop(struct aq_hw_s *self, @@ -992,6 +1064,227 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self, return aq_hw_err_from_flags(self); } +static int hw_atl_b0_tx_tc_mode_get(struct aq_hw_s *self, u32 *tc_mode) +{ + *tc_mode = hw_atl_rpb_tps_tx_tc_mode_get(self); + return aq_hw_err_from_flags(self); +} + +static int hw_atl_b0_rx_tc_mode_get(struct aq_hw_s *self, u32 *tc_mode) +{ + *tc_mode = hw_atl_rpb_rpf_rx_traf_class_mode_get(self); + return aq_hw_err_from_flags(self); +} + +#define get_ptp_ts_val_u64(self, indx) \ + ((u64)(hw_atl_pcs_ptp_clock_get(self, indx) & 0xffff)) + +static void hw_atl_b0_get_ptp_ts(struct aq_hw_s *self, u64 *stamp) +{ + u64 ns; + + hw_atl_pcs_ptp_clock_read_enable(self, 1); + hw_atl_pcs_ptp_clock_read_enable(self, 0); + ns = (get_ptp_ts_val_u64(self, 0) + + (get_ptp_ts_val_u64(self, 1) << 16)) * NSEC_PER_SEC + + (get_ptp_ts_val_u64(self, 3) + + (get_ptp_ts_val_u64(self, 4) << 16)); + + *stamp = ns + self->ptp_clk_offset; +} + +static void hw_atl_b0_adj_params_get(u64 freq, s64 adj, u32 *ns, u32 *fns) +{ + /* For accuracy, the digit is extended */ + s64 base_ns = ((adj + NSEC_PER_SEC) * NSEC_PER_SEC); + u64 nsi_frac = 0; + u64 nsi; + + base_ns = div64_s64(base_ns, freq); + nsi = div64_u64(base_ns, NSEC_PER_SEC); + + if (base_ns != nsi * NSEC_PER_SEC) { + s64 divisor = div64_s64((s64)NSEC_PER_SEC * NSEC_PER_SEC, + base_ns - nsi * NSEC_PER_SEC); + nsi_frac = div64_s64(FRAC_PER_NS * NSEC_PER_SEC, divisor); + } + + *ns = (u32)nsi; + *fns = (u32)nsi_frac; +} + +static void +hw_atl_b0_mac_adj_param_calc(struct hw_fw_request_ptp_adj_freq *ptp_adj_freq, + u64 phyfreq, u64 macfreq) +{ + s64 adj_fns_val; + s64 fns_in_sec_phy = phyfreq * (ptp_adj_freq->fns_phy + + FRAC_PER_NS * ptp_adj_freq->ns_phy); + s64 fns_in_sec_mac = macfreq * (ptp_adj_freq->fns_mac + + FRAC_PER_NS * ptp_adj_freq->ns_mac); + s64 fault_in_sec_phy = FRAC_PER_NS * NSEC_PER_SEC - fns_in_sec_phy; + s64 fault_in_sec_mac = FRAC_PER_NS * NSEC_PER_SEC - fns_in_sec_mac; + /* MAC MCP counter freq is macfreq / 4 */ + s64 diff_in_mcp_overflow = (fault_in_sec_mac - fault_in_sec_phy) * + 4 * FRAC_PER_NS; + + diff_in_mcp_overflow = div64_s64(diff_in_mcp_overflow, + AQ_HW_MAC_COUNTER_HZ); + adj_fns_val = (ptp_adj_freq->fns_mac + FRAC_PER_NS * + ptp_adj_freq->ns_mac) + diff_in_mcp_overflow; + + ptp_adj_freq->mac_ns_adj = div64_s64(adj_fns_val, FRAC_PER_NS); + ptp_adj_freq->mac_fns_adj = adj_fns_val - ptp_adj_freq->mac_ns_adj * + FRAC_PER_NS; +} + +static int hw_atl_b0_adj_sys_clock(struct aq_hw_s *self, s64 delta) +{ + self->ptp_clk_offset += delta; + + return 0; +} + +static int hw_atl_b0_set_sys_clock(struct aq_hw_s *self, u64 time, u64 ts) +{ + s64 delta = time - (self->ptp_clk_offset + ts); + + return hw_atl_b0_adj_sys_clock(self, delta); +} + +int hw_atl_b0_ts_to_sys_clock(struct aq_hw_s *self, u64 ts, u64 *time) +{ + *time = self->ptp_clk_offset + ts; + return 0; +} + +static int hw_atl_b0_adj_clock_freq(struct aq_hw_s *self, s32 ppb) +{ + struct hw_fw_request_iface fwreq; + size_t size; + + memset(&fwreq, 0, sizeof(fwreq)); + + fwreq.msg_id = HW_AQ_FW_REQUEST_PTP_ADJ_FREQ; + hw_atl_b0_adj_params_get(AQ_HW_MAC_COUNTER_HZ, ppb, + &fwreq.ptp_adj_freq.ns_mac, + &fwreq.ptp_adj_freq.fns_mac); + hw_atl_b0_adj_params_get(AQ_HW_PHY_COUNTER_HZ, ppb, + &fwreq.ptp_adj_freq.ns_phy, + &fwreq.ptp_adj_freq.fns_phy); + hw_atl_b0_mac_adj_param_calc(&fwreq.ptp_adj_freq, + AQ_HW_PHY_COUNTER_HZ, + AQ_HW_MAC_COUNTER_HZ); + + size = sizeof(fwreq.msg_id) + sizeof(fwreq.ptp_adj_freq); + return self->aq_fw_ops->send_fw_request(self, &fwreq, size); +} + +static int hw_atl_b0_gpio_pulse(struct aq_hw_s *self, u32 index, + u64 start, u32 period) +{ + struct hw_fw_request_iface fwreq; + size_t size; + + memset(&fwreq, 0, sizeof(fwreq)); + + fwreq.msg_id = HW_AQ_FW_REQUEST_PTP_GPIO_CTRL; + fwreq.ptp_gpio_ctrl.index = index; + fwreq.ptp_gpio_ctrl.period = period; + /* Apply time offset */ + fwreq.ptp_gpio_ctrl.start = start - self->ptp_clk_offset; + + size = sizeof(fwreq.msg_id) + sizeof(fwreq.ptp_gpio_ctrl); + return self->aq_fw_ops->send_fw_request(self, &fwreq, size); +} + +static int hw_atl_b0_extts_gpio_enable(struct aq_hw_s *self, u32 index, + u32 enable) +{ + /* Enable/disable Sync1588 GPIO Timestamping */ + aq_phy_write_reg(self, MDIO_MMD_PCS, 0xc611, enable ? 0x71 : 0); + + return 0; +} + +static int hw_atl_b0_get_sync_ts(struct aq_hw_s *self, u64 *ts) +{ + u64 sec_l; + u64 sec_h; + u64 nsec_l; + u64 nsec_h; + + if (!ts) + return -1; + + /* PTP external GPIO clock seconds count 15:0 */ + sec_l = aq_phy_read_reg(self, MDIO_MMD_PCS, 0xc914); + /* PTP external GPIO clock seconds count 31:16 */ + sec_h = aq_phy_read_reg(self, MDIO_MMD_PCS, 0xc915); + /* PTP external GPIO clock nanoseconds count 15:0 */ + nsec_l = aq_phy_read_reg(self, MDIO_MMD_PCS, 0xc916); + /* PTP external GPIO clock nanoseconds count 31:16 */ + nsec_h = aq_phy_read_reg(self, MDIO_MMD_PCS, 0xc917); + + *ts = (nsec_h << 16) + nsec_l + ((sec_h << 16) + sec_l) * NSEC_PER_SEC; + + return 0; +} + +static u16 hw_atl_b0_rx_extract_ts(struct aq_hw_s *self, u8 *p, + unsigned int len, u64 *timestamp) +{ + unsigned int offset = 14; + struct ethhdr *eth; + __be64 sec; + __be32 ns; + u8 *ptr; + + if (len <= offset || !timestamp) + return 0; + + /* The TIMESTAMP in the end of package has following format: + * (big-endian) + * struct { + * uint64_t sec; + * uint32_t ns; + * uint16_t stream_id; + * }; + */ + ptr = p + (len - offset); + memcpy(&sec, ptr, sizeof(sec)); + ptr += sizeof(sec); + memcpy(&ns, ptr, sizeof(ns)); + + *timestamp = (be64_to_cpu(sec) & 0xffffffffffffllu) * NSEC_PER_SEC + + be32_to_cpu(ns) + self->ptp_clk_offset; + + eth = (struct ethhdr *)p; + + return (eth->h_proto == htons(ETH_P_1588)) ? 12 : 14; +} + +static int hw_atl_b0_extract_hwts(struct aq_hw_s *self, u8 *p, unsigned int len, + u64 *timestamp) +{ + struct hw_atl_rxd_hwts_wb_s *hwts_wb = (struct hw_atl_rxd_hwts_wb_s *)p; + u64 tmp, sec, ns; + + sec = 0; + tmp = (hwts_wb->sec_lw0 >> 2) & 0x3ff; + sec += tmp; + tmp = (u64)((hwts_wb->sec_lw1 >> 16) & 0xffff) << 10; + sec += tmp; + tmp = (u64)(hwts_wb->sec_hw & 0xfff) << 26; + sec += tmp; + tmp = (u64)((hwts_wb->sec_hw >> 22) & 0x3ff) << 38; + sec += tmp; + ns = sec * NSEC_PER_SEC + hwts_wb->ns; + if (timestamp) + *timestamp = ns + self->ptp_clk_offset; + return 0; +} + static int hw_atl_b0_hw_fl3l4_clear(struct aq_hw_s *self, struct aq_rx_filter_l3l4 *data) { @@ -1025,7 +1318,8 @@ static int hw_atl_b0_hw_fl3l4_set(struct aq_hw_s *self, hw_atl_b0_hw_fl3l4_clear(self, data); - if (data->cmd) { + if (data->cmd & (HW_ATL_RX_ENABLE_CMP_DEST_ADDR_L3 | + HW_ATL_RX_ENABLE_CMP_SRC_ADDR_L3)) { if (!data->is_ipv6) { hw_atl_rpfl3l4_ipv4_dest_addr_set(self, location, @@ -1042,8 +1336,13 @@ static int hw_atl_b0_hw_fl3l4_set(struct aq_hw_s *self, data->ip_src); } } - hw_atl_rpf_l4_dpd_set(self, data->p_dst, location); - hw_atl_rpf_l4_spd_set(self, data->p_src, location); + + if (data->cmd & (HW_ATL_RX_ENABLE_CMP_DEST_PORT_L4 | + HW_ATL_RX_ENABLE_CMP_SRC_PORT_L4)) { + hw_atl_rpf_l4_dpd_set(self, data->p_dst, location); + hw_atl_rpf_l4_spd_set(self, data->p_src, location); + } + hw_atl_rpfl3l4_cmd_set(self, location, data->cmd); return aq_hw_err_from_flags(self); @@ -1164,6 +1463,23 @@ const struct aq_hw_ops hw_atl_ops_b0 = { .hw_get_regs = hw_atl_utils_hw_get_regs, .hw_get_hw_stats = hw_atl_utils_get_hw_stats, .hw_get_fw_version = hw_atl_utils_get_fw_version, - .hw_set_offload = hw_atl_b0_hw_offload_set, + + .hw_tx_tc_mode_get = hw_atl_b0_tx_tc_mode_get, + .hw_rx_tc_mode_get = hw_atl_b0_rx_tc_mode_get, + + .hw_ring_hwts_rx_fill = hw_atl_b0_hw_ring_hwts_rx_fill, + .hw_ring_hwts_rx_receive = hw_atl_b0_hw_ring_hwts_rx_receive, + + .hw_get_ptp_ts = hw_atl_b0_get_ptp_ts, + .hw_adj_sys_clock = hw_atl_b0_adj_sys_clock, + .hw_set_sys_clock = hw_atl_b0_set_sys_clock, + .hw_ts_to_sys_clock = hw_atl_b0_ts_to_sys_clock, + .hw_adj_clock_freq = hw_atl_b0_adj_clock_freq, + .hw_gpio_pulse = hw_atl_b0_gpio_pulse, + .hw_extts_gpio_enable = hw_atl_b0_extts_gpio_enable, + .hw_get_sync_ts = hw_atl_b0_get_sync_ts, + .rx_extract_ts = hw_atl_b0_rx_extract_ts, + .extract_hwts = hw_atl_b0_extract_hwts, + .hw_set_offload = hw_atl_b0_hw_offload_set, .hw_set_fc = hw_atl_b0_set_fc, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h index 808d8cd4252a..7ab23a1751d3 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_b0_internal.h: Definition of Atlantic B0 chip specific @@ -64,8 +64,11 @@ #define HW_ATL_B0_MPI_SPEED_MSK 0xFFFFU #define HW_ATL_B0_MPI_SPEED_SHIFT 16U -#define HW_ATL_B0_TXBUF_MAX 160U -#define HW_ATL_B0_RXBUF_MAX 320U +#define HW_ATL_B0_TXBUF_MAX 160U +#define HW_ATL_B0_PTP_TXBUF_SIZE 8U + +#define HW_ATL_B0_RXBUF_MAX 320U +#define HW_ATL_B0_PTP_RXBUF_SIZE 16U #define HW_ATL_B0_RSS_REDIRECTION_MAX 64U #define HW_ATL_B0_RSS_REDIRECTION_BITS 3U diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c index 1149812ae463..6cadc9054544 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_llh.c: Definitions of bitfield and register access functions for @@ -572,6 +572,13 @@ void hw_atl_rpb_rpf_rx_traf_class_mode_set(struct aq_hw_s *aq_hw, rx_traf_class_mode); } +u32 hw_atl_rpb_rpf_rx_traf_class_mode_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_RPB_RPF_RX_TC_MODE_ADR, + HW_ATL_RPB_RPF_RX_TC_MODE_MSK, + HW_ATL_RPB_RPF_RX_TC_MODE_SHIFT); +} + void hw_atl_rpb_rx_buff_en_set(struct aq_hw_s *aq_hw, u32 rx_buff_en) { aq_hw_write_reg_bit(aq_hw, HW_ATL_RPB_RX_BUF_EN_ADR, @@ -606,12 +613,25 @@ void hw_atl_rpb_rx_flow_ctl_mode_set(struct aq_hw_s *aq_hw, u32 rx_flow_ctl_mode HW_ATL_RPB_RX_FC_MODE_SHIFT, rx_flow_ctl_mode); } -void hw_atl_rdm_rx_dma_desc_cache_init_set(struct aq_hw_s *aq_hw, u32 init) +void hw_atl_rdm_rx_dma_desc_cache_init_tgl(struct aq_hw_s *aq_hw) { + u32 val; + + val = aq_hw_read_reg_bit(aq_hw, HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_ADR, + HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_MSK, + HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_SHIFT); + aq_hw_write_reg_bit(aq_hw, HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_ADR, HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_MSK, HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_SHIFT, - init); + val ^ 1); +} + +u32 hw_atl_rdm_rx_dma_desc_cache_init_done_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, RDM_RX_DMA_DESC_CACHE_INIT_DONE_ADR, + RDM_RX_DMA_DESC_CACHE_INIT_DONE_MSK, + RDM_RX_DMA_DESC_CACHE_INIT_DONE_SHIFT); } void hw_atl_rpb_rx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw, @@ -623,8 +643,8 @@ void hw_atl_rpb_rx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw, rx_pkt_buff_size_per_tc); } -void hw_atl_rpb_rx_xoff_en_per_tc_set(struct aq_hw_s *aq_hw, u32 rx_xoff_en_per_tc, - u32 buffer) +void hw_atl_rpb_rx_xoff_en_per_tc_set(struct aq_hw_s *aq_hw, + u32 rx_xoff_en_per_tc, u32 buffer) { aq_hw_write_reg_bit(aq_hw, HW_ATL_RPB_RXBXOFF_EN_ADR(buffer), HW_ATL_RPB_RXBXOFF_EN_MSK, @@ -1277,6 +1297,13 @@ void hw_atl_tpb_tx_buff_en_set(struct aq_hw_s *aq_hw, u32 tx_buff_en) HW_ATL_TPB_TX_BUF_EN_SHIFT, tx_buff_en); } +u32 hw_atl_rpb_tps_tx_tc_mode_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_TPB_TX_TC_MODE_ADDR, + HW_ATL_TPB_TX_TC_MODE_MSK, + HW_ATL_TPB_TX_TC_MODE_SHIFT); +} + void hw_atl_rpb_tps_tx_tc_mode_set(struct aq_hw_s *aq_hw, u32 tx_traf_class_mode) { @@ -1513,6 +1540,20 @@ void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s *aq_hw, glb_cpu_scratch_scp); } +void hw_atl_pcs_ptp_clock_read_enable(struct aq_hw_s *aq_hw, + u32 ptp_clock_read_enable) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_ADR, + HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_MSK, + HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_SHIFT, + ptp_clock_read_enable); +} + +u32 hw_atl_pcs_ptp_clock_get(struct aq_hw_s *aq_hw, u32 index) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_PCS_PTP_TS_VAL_ADDR(index)); +} + void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr) { aq_hw_write_reg_bit(aq_hw, HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR, @@ -1603,6 +1644,11 @@ u32 hw_atl_sem_ram_get(struct aq_hw_s *self) return hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM); } +u32 hw_atl_sem_mdio_get(struct aq_hw_s *self) +{ + return hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_MDIO); +} + u32 hw_atl_scrpad_get(struct aq_hw_s *aq_hw, u32 scratch_scp) { return aq_hw_read_reg(aq_hw, @@ -1618,3 +1664,60 @@ u32 hw_atl_scrpad25_get(struct aq_hw_s *self) { return hw_atl_scrpad_get(self, 0x18); } + +void hw_atl_glb_mdio_iface1_set(struct aq_hw_s *aq_hw, u32 value) +{ + aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(1), value); +} + +u32 hw_atl_glb_mdio_iface1_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(1)); +} + +void hw_atl_glb_mdio_iface2_set(struct aq_hw_s *aq_hw, u32 value) +{ + aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(2), value); +} + +u32 hw_atl_glb_mdio_iface2_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(2)); +} + +void hw_atl_glb_mdio_iface3_set(struct aq_hw_s *aq_hw, u32 value) +{ + aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(3), value); +} + +u32 hw_atl_glb_mdio_iface3_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(3)); +} + +void hw_atl_glb_mdio_iface4_set(struct aq_hw_s *aq_hw, u32 value) +{ + aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(4), value); +} + +u32 hw_atl_glb_mdio_iface4_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(4)); +} + +void hw_atl_glb_mdio_iface5_set(struct aq_hw_s *aq_hw, u32 value) +{ + aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(5), value); +} + +u32 hw_atl_glb_mdio_iface5_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(5)); +} + +u32 hw_atl_mdio_busy_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_MDIO_BUSY_ADR, + HW_ATL_MDIO_BUSY_MSK, + HW_ATL_MDIO_BUSY_SHIFT); +} diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h index 0c37abbabca5..5750b0c9cae7 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_llh.h: Declarations of bitfield and register access functions for @@ -292,6 +292,9 @@ void hw_atl_rpb_dma_sys_lbk_set(struct aq_hw_s *aq_hw, u32 dma_sys_lbk); void hw_atl_rpb_rpf_rx_traf_class_mode_set(struct aq_hw_s *aq_hw, u32 rx_traf_class_mode); +/* get rx traffic class mode */ +u32 hw_atl_rpb_rpf_rx_traf_class_mode_get(struct aq_hw_s *aq_hw); + /* set rx buffer enable */ void hw_atl_rpb_rx_buff_en_set(struct aq_hw_s *aq_hw, u32 rx_buff_en); @@ -306,18 +309,23 @@ void hw_atl_rpb_rx_buff_lo_threshold_per_tc_set(struct aq_hw_s *aq_hw, u32 buffer); /* set rx flow control mode */ -void hw_atl_rpb_rx_flow_ctl_mode_set(struct aq_hw_s *aq_hw, u32 rx_flow_ctl_mode); +void hw_atl_rpb_rx_flow_ctl_mode_set(struct aq_hw_s *aq_hw, + u32 rx_flow_ctl_mode); /* set rx packet buffer size (per tc) */ void hw_atl_rpb_rx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw, u32 rx_pkt_buff_size_per_tc, u32 buffer); -/* set rdm rx dma descriptor cache init */ -void hw_atl_rdm_rx_dma_desc_cache_init_set(struct aq_hw_s *aq_hw, u32 init); +/* toggle rdm rx dma descriptor cache init */ +void hw_atl_rdm_rx_dma_desc_cache_init_tgl(struct aq_hw_s *aq_hw); + +/* get rdm rx dma descriptor cache init done */ +u32 hw_atl_rdm_rx_dma_desc_cache_init_done_get(struct aq_hw_s *aq_hw); /* set rx xoff enable (per tc) */ -void hw_atl_rpb_rx_xoff_en_per_tc_set(struct aq_hw_s *aq_hw, u32 rx_xoff_en_per_tc, +void hw_atl_rpb_rx_xoff_en_per_tc_set(struct aq_hw_s *aq_hw, + u32 rx_xoff_en_per_tc, u32 buffer); /* rpf */ @@ -602,6 +610,9 @@ void hw_atl_thm_lso_tcp_flag_of_middle_pkt_set(struct aq_hw_s *aq_hw, void hw_atl_rpb_tps_tx_tc_mode_set(struct aq_hw_s *aq_hw, u32 tx_traf_class_mode); +/* get TX Traffic Class Mode */ +u32 hw_atl_rpb_tps_tx_tc_mode_get(struct aq_hw_s *aq_hw); + /* set tx buffer enable */ void hw_atl_tpb_tx_buff_en_set(struct aq_hw_s *aq_hw, u32 tx_buff_en); @@ -620,7 +631,8 @@ void hw_atl_tpb_tx_dma_sys_lbk_en_set(struct aq_hw_s *aq_hw, u32 tx_dma_sys_lbk_ /* set tx packet buffer size (per tc) */ void hw_atl_tpb_tx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw, - u32 tx_pkt_buff_size_per_tc, u32 buffer); + u32 tx_pkt_buff_size_per_tc, + u32 buffer); /* set tx path pad insert enable */ void hw_atl_tpb_tx_path_scp_ins_en_set(struct aq_hw_s *aq_hw, u32 tx_path_scp_ins_en); @@ -712,6 +724,12 @@ void hw_atl_msm_reg_wr_strobe_set(struct aq_hw_s *aq_hw, u32 reg_wr_strobe); /* set pci register reset disable */ void hw_atl_pci_pci_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 pci_reg_res_dis); +/* pcs */ +void hw_atl_pcs_ptp_clock_read_enable(struct aq_hw_s *aq_hw, + u32 ptp_clock_read_enable); + +u32 hw_atl_pcs_ptp_clock_get(struct aq_hw_s *aq_hw, u32 index); + /* set uP Force Interrupt */ void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr); @@ -749,9 +767,44 @@ void hw_atl_rpfl3l4_ipv6_src_addr_set(struct aq_hw_s *aq_hw, u8 location, void hw_atl_rpfl3l4_ipv6_dest_addr_set(struct aq_hw_s *aq_hw, u8 location, u32 *ipv6_dest); +/* set Global MDIO Interface 1 */ +void hw_atl_glb_mdio_iface1_set(struct aq_hw_s *hw, u32 value); + +/* get Global MDIO Interface 1 */ +u32 hw_atl_glb_mdio_iface1_get(struct aq_hw_s *hw); + +/* set Global MDIO Interface 2 */ +void hw_atl_glb_mdio_iface2_set(struct aq_hw_s *hw, u32 value); + +/* get Global MDIO Interface 2 */ +u32 hw_atl_glb_mdio_iface2_get(struct aq_hw_s *hw); + +/* set Global MDIO Interface 3 */ +void hw_atl_glb_mdio_iface3_set(struct aq_hw_s *hw, u32 value); + +/* get Global MDIO Interface 3 */ +u32 hw_atl_glb_mdio_iface3_get(struct aq_hw_s *hw); + +/* set Global MDIO Interface 4 */ +void hw_atl_glb_mdio_iface4_set(struct aq_hw_s *hw, u32 value); + +/* get Global MDIO Interface 4 */ +u32 hw_atl_glb_mdio_iface4_get(struct aq_hw_s *hw); + +/* set Global MDIO Interface 5 */ +void hw_atl_glb_mdio_iface5_set(struct aq_hw_s *hw, u32 value); + +/* get Global MDIO Interface 5 */ +u32 hw_atl_glb_mdio_iface5_get(struct aq_hw_s *hw); + +u32 hw_atl_mdio_busy_get(struct aq_hw_s *aq_hw); + /* get global microprocessor ram semaphore */ u32 hw_atl_sem_ram_get(struct aq_hw_s *self); +/* get global microprocessor mdio semaphore */ +u32 hw_atl_sem_mdio_get(struct aq_hw_s *self); + /* get global microprocessor scratch pad register */ u32 hw_atl_scrpad_get(struct aq_hw_s *aq_hw, u32 scratch_scp); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h index c3febcdfa92e..ec3bcdcefc4d 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_llh_internal.h: Preprocessor definitions @@ -318,6 +318,25 @@ /* default value of bitfield rdm_desc_init_i */ #define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_DEFAULT 0x0 +/* rdm_desc_init_done_i bitfield definitions + * preprocessor definitions for the bitfield rdm_desc_init_done_i. + * port="pif_rdm_desc_init_done_i" + */ + +/* register address for bitfield rdm_desc_init_done_i */ +#define RDM_RX_DMA_DESC_CACHE_INIT_DONE_ADR 0x00005a10 +/* bitmask for bitfield rdm_desc_init_done_i */ +#define RDM_RX_DMA_DESC_CACHE_INIT_DONE_MSK 0x00000001U +/* inverted bitmask for bitfield rdm_desc_init_done_i */ +#define RDM_RX_DMA_DESC_CACHE_INIT_DONE_MSKN 0xfffffffe +/* lower bit position of bitfield rdm_desc_init_done_i */ +#define RDM_RX_DMA_DESC_CACHE_INIT_DONE_SHIFT 0U +/* width of bitfield rdm_desc_init_done_i */ +#define RDM_RX_DMA_DESC_CACHE_INIT_DONE_WIDTH 1 +/* default value of bitfield rdm_desc_init_done_i */ +#define RDM_RX_DMA_DESC_CACHE_INIT_DONE_DEFAULT 0x0 + + /* rx int_desc_wrb_en bitfield definitions * preprocessor definitions for the bitfield "int_desc_wrb_en". * port="pif_rdm_int_desc_wrb_en_i" @@ -1289,6 +1308,52 @@ /* default value of bitfield et_val{f}[f:0] */ #define HW_ATL_RPF_ET_VALF_DEFAULT 0x0 +/* RX l3_l4_en{F} Bitfield Definitions + * Preprocessor definitions for the bitfield "l3_l4_en{F}". + * Parameter: filter {F} | stride size 0x4 | range [0, 7] + * PORT="pif_rpf_l3_l4_en_i[0]" + */ + +#define HW_ATL_RPF_L3_REG_CTRL_ADR(filter) (0x00005380 + (filter) * 0x4) + +/* RX rpf_l3_sa{D}[1F:0] Bitfield Definitions + * Preprocessor definitions for the bitfield "l3_sa{D}[1F:0]". + * Parameter: location {D} | stride size 0x4 | range [0, 7] + * PORT="pif_rpf_l3_sa0_i[31:0]" + */ + +/* Register address for bitfield pif_rpf_l3_sa0_i[31:0] */ +#define HW_ATL_RPF_L3_SRCA_ADR(filter) (0x000053B0 + (filter) * 0x4) +/* Bitmask for bitfield l3_sa0[1F:0] */ +#define HW_ATL_RPF_L3_SRCA_MSK 0xFFFFFFFFu +/* Inverted bitmask for bitfield l3_sa0[1F:0] */ +#define HW_ATL_RPF_L3_SRCA_MSKN 0xFFFFFFFFu +/* Lower bit position of bitfield l3_sa0[1F:0] */ +#define HW_ATL_RPF_L3_SRCA_SHIFT 0 +/* Width of bitfield l3_sa0[1F:0] */ +#define HW_ATL_RPF_L3_SRCA_WIDTH 32 +/* Default value of bitfield l3_sa0[1F:0] */ +#define HW_ATL_RPF_L3_SRCA_DEFAULT 0x0 + +/* RX rpf_l3_da{D}[1F:0] Bitfield Definitions + * Preprocessor definitions for the bitfield "l3_da{D}[1F:0]". + * Parameter: location {D} | stride size 0x4 | range [0, 7] + * PORT="pif_rpf_l3_da0_i[31:0]" + */ + + /* Register address for bitfield pif_rpf_l3_da0_i[31:0] */ +#define HW_ATL_RPF_L3_DSTA_ADR(filter) (0x000053B0 + (filter) * 0x4) +/* Bitmask for bitfield l3_da0[1F:0] */ +#define HW_ATL_RPF_L3_DSTA_MSK 0xFFFFFFFFu +/* Inverted bitmask for bitfield l3_da0[1F:0] */ +#define HW_ATL_RPF_L3_DSTA_MSKN 0xFFFFFFFFu +/* Lower bit position of bitfield l3_da0[1F:0] */ +#define HW_ATL_RPF_L3_DSTA_SHIFT 0 +/* Width of bitfield l3_da0[1F:0] */ +#define HW_ATL_RPF_L3_DSTA_WIDTH 32 +/* Default value of bitfield l3_da0[1F:0] */ +#define HW_ATL_RPF_L3_DSTA_DEFAULT 0x0 + /* RX l4_sp{D}[F:0] Bitfield Definitions * Preprocessor definitions for the bitfield "l4_sp{D}[F:0]". * Parameter: srcport {D} | stride size 0x4 | range [0, 7] @@ -2421,6 +2486,22 @@ /* default value of bitfield register write strobe */ #define HW_ATL_MSM_REG_WR_STROBE_DEFAULT 0x0 +/* register address for bitfield PTP Digital Clock Read Enable */ +#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_ADR 0x00004628 +/* bitmask for bitfield PTP Digital Clock Read Enable */ +#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_MSK 0x00000010 +/* inverted bitmask for bitfield PTP Digital Clock Read Enable */ +#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_MSKN 0xFFFFFFEF +/* lower bit position of bitfield PTP Digital Clock Read Enable */ +#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_SHIFT 4 +/* width of bitfield PTP Digital Clock Read Enable */ +#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_WIDTH 1 +/* default value of bitfield PTP Digital Clock Read Enable */ +#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_DEFAULT 0x0 + +/* register address for ptp counter reading */ +#define HW_ATL_PCS_PTP_TS_VAL_ADDR(index) (0x00004900 + (index) * 0x4) + /* mif soft reset bitfield definitions * preprocessor definitions for the bitfield "soft reset". * port="pif_glb_res_i" @@ -2513,50 +2594,121 @@ /* default value of bitfield uP Force Interrupt */ #define HW_ATL_MCP_UP_FORCE_INTERRUPT_DEFAULT 0x0 -#define HW_ATL_RX_CTRL_ADDR_BEGIN_FL3L4 0x00005380 -#define HW_ATL_RX_SRCA_ADDR_BEGIN_FL3L4 0x000053B0 -#define HW_ATL_RX_DESTA_ADDR_BEGIN_FL3L4 0x000053D0 - -#define HW_ATL_RPF_L3_REG_CTRL_ADR(location) (0x00005380 + (location) * 0x4) - -/* RX rpf_l3_sa{D}[1F:0] Bitfield Definitions - * Preprocessor definitions for the bitfield "l3_sa{D}[1F:0]". - * Parameter: location {D} | stride size 0x4 | range [0, 7] - * PORT="pif_rpf_l3_sa0_i[31:0]" - */ - -/* Register address for bitfield pif_rpf_l3_sa0_i[31:0] */ -#define HW_ATL_RPF_L3_SRCA_ADR(location) (0x000053B0 + (location) * 0x4) -/* Bitmask for bitfield l3_sa0[1F:0] */ -#define HW_ATL_RPF_L3_SRCA_MSK 0xFFFFFFFFu -/* Inverted bitmask for bitfield l3_sa0[1F:0] */ -#define HW_ATL_RPF_L3_SRCA_MSKN 0xFFFFFFFFu -/* Lower bit position of bitfield l3_sa0[1F:0] */ -#define HW_ATL_RPF_L3_SRCA_SHIFT 0 -/* Width of bitfield l3_sa0[1F:0] */ -#define HW_ATL_RPF_L3_SRCA_WIDTH 32 -/* Default value of bitfield l3_sa0[1F:0] */ -#define HW_ATL_RPF_L3_SRCA_DEFAULT 0x0 - -/* RX rpf_l3_da{D}[1F:0] Bitfield Definitions - * Preprocessor definitions for the bitfield "l3_da{D}[1F:0]". - * Parameter: location {D} | stride size 0x4 | range [0, 7] - * PORT="pif_rpf_l3_da0_i[31:0]" - */ - - /* Register address for bitfield pif_rpf_l3_da0_i[31:0] */ -#define HW_ATL_RPF_L3_DSTA_ADR(location) (0x000053B0 + (location) * 0x4) -/* Bitmask for bitfield l3_da0[1F:0] */ -#define HW_ATL_RPF_L3_DSTA_MSK 0xFFFFFFFFu -/* Inverted bitmask for bitfield l3_da0[1F:0] */ -#define HW_ATL_RPF_L3_DSTA_MSKN 0xFFFFFFFFu -/* Lower bit position of bitfield l3_da0[1F:0] */ -#define HW_ATL_RPF_L3_DSTA_SHIFT 0 -/* Width of bitfield l3_da0[1F:0] */ -#define HW_ATL_RPF_L3_DSTA_WIDTH 32 -/* Default value of bitfield l3_da0[1F:0] */ -#define HW_ATL_RPF_L3_DSTA_DEFAULT 0x0 - +/* Preprocessor definitions for Global MDIO Interfaces + * Address: 0x00000280 + 0x4 * Number of interface + */ +#define HW_ATL_GLB_MDIO_IFACE_ADDR_BEGIN 0x00000280u + +#define HW_ATL_GLB_MDIO_IFACE_N_ADR(number) \ + (HW_ATL_GLB_MDIO_IFACE_ADDR_BEGIN + (((number) - 1) * 0x4)) + +/* MIF MDIO Busy Bitfield Definitions + * Preprocessor definitions for the bitfield "MDIO Busy". + * PORT="mdio_pif_busy_o" + */ + +/* Register address for bitfield MDIO Busy */ +#define HW_ATL_MDIO_BUSY_ADR 0x00000284 +/* Bitmask for bitfield MDIO Busy */ +#define HW_ATL_MDIO_BUSY_MSK 0x80000000 +/* Inverted bitmask for bitfield MDIO Busy */ +#define HW_ATL_MDIO_BUSY_MSKN 0x7FFFFFFF +/* Lower bit position of bitfield MDIO Busy */ +#define HW_ATL_MDIO_BUSY_SHIFT 31 +/* Width of bitfield MDIO Busy */ +#define HW_ATL_MDIO_BUSY_WIDTH 1 + +/* MIF MDIO Execute Operation Bitfield Definitions + * Preprocessor definitions for the bitfield "MDIO Execute Operation". + * PORT="pif_mdio_op_start_i" + */ + +/* Register address for bitfield MDIO Execute Operation */ +#define HW_ATL_MDIO_EXECUTE_OPERATION_ADR 0x00000284 +/* Bitmask for bitfield MDIO Execute Operation */ +#define HW_ATL_MDIO_EXECUTE_OPERATION_MSK 0x00008000 +/* Inverted bitmask for bitfield MDIO Execute Operation */ +#define HW_ATL_MDIO_EXECUTE_OPERATION_MSKN 0xFFFF7FFF +/* Lower bit position of bitfield MDIO Execute Operation */ +#define HW_ATL_MDIO_EXECUTE_OPERATION_SHIFT 15 +/* Width of bitfield MDIO Execute Operation */ +#define HW_ATL_MDIO_EXECUTE_OPERATION_WIDTH 1 +/* Default value of bitfield MDIO Execute Operation */ +#define HW_ATL_MDIO_EXECUTE_OPERATION_DEFAULT 0x0 + +/* MIF Op Mode [1:0] Bitfield Definitions + * Preprocessor definitions for the bitfield "Op Mode [1:0]". + * PORT="pif_mdio_mode_i[1:0]" + */ + +/* Register address for bitfield Op Mode [1:0] */ +#define HW_ATL_MDIO_OP_MODE_ADR 0x00000284 +/* Bitmask for bitfield Op Mode [1:0] */ +#define HW_ATL_MDIO_OP_MODE_MSK 0x00003000 +/* Inverted bitmask for bitfield Op Mode [1:0] */ +#define HW_ATL_MDIO_OP_MODE_MSKN 0xFFFFCFFF +/* Lower bit position of bitfield Op Mode [1:0] */ +#define HW_ATL_MDIO_OP_MODE_SHIFT 12 +/* Width of bitfield Op Mode [1:0] */ +#define HW_ATL_MDIO_OP_MODE_WIDTH 2 +/* Default value of bitfield Op Mode [1:0] */ +#define HW_ATL_MDIO_OP_MODE_DEFAULT 0x0 + +/* MIF PHY address Bitfield Definitions + * Preprocessor definitions for the bitfield "PHY address". + * PORT="pif_mdio_phy_addr_i[9:0]" + */ + +/* Register address for bitfield PHY address */ +#define HW_ATL_MDIO_PHY_ADDRESS_ADR 0x00000284 +/* Bitmask for bitfield PHY address */ +#define HW_ATL_MDIO_PHY_ADDRESS_MSK 0x000003FF +/* Inverted bitmask for bitfield PHY address */ +#define HW_ATL_MDIO_PHY_ADDRESS_MSKN 0xFFFFFC00 +/* Lower bit position of bitfield PHY address */ +#define HW_ATL_MDIO_PHY_ADDRESS_SHIFT 0 +/* Width of bitfield PHY address */ +#define HW_ATL_MDIO_PHY_ADDRESS_WIDTH 10 +/* Default value of bitfield PHY address */ +#define HW_ATL_MDIO_PHY_ADDRESS_DEFAULT 0x0 + +/* MIF MDIO WriteData [F:0] Bitfield Definitions + * Preprocessor definitions for the bitfield "MDIO WriteData [F:0]". + * PORT="pif_mdio_wdata_i[15:0]" + */ + +/* Register address for bitfield MDIO WriteData [F:0] */ +#define HW_ATL_MDIO_WRITE_DATA_ADR 0x00000288 +/* Bitmask for bitfield MDIO WriteData [F:0] */ +#define HW_ATL_MDIO_WRITE_DATA_MSK 0x0000FFFF +/* Inverted bitmask for bitfield MDIO WriteData [F:0] */ +#define HW_ATL_MDIO_WRITE_DATA_MSKN 0xFFFF0000 +/* Lower bit position of bitfield MDIO WriteData [F:0] */ +#define HW_ATL_MDIO_WRITE_DATA_SHIFT 0 +/* Width of bitfield MDIO WriteData [F:0] */ +#define HW_ATL_MDIO_WRITE_DATA_WIDTH 16 +/* Default value of bitfield MDIO WriteData [F:0] */ +#define HW_ATL_MDIO_WRITE_DATA_DEFAULT 0x0 + +/* MIF MDIO Address [F:0] Bitfield Definitions + * Preprocessor definitions for the bitfield "MDIO Address [F:0]". + * PORT="pif_mdio_addr_i[15:0]" + */ + +/* Register address for bitfield MDIO Address [F:0] */ +#define HW_ATL_MDIO_ADDRESS_ADR 0x0000028C +/* Bitmask for bitfield MDIO Address [F:0] */ +#define HW_ATL_MDIO_ADDRESS_MSK 0x0000FFFF +/* Inverted bitmask for bitfield MDIO Address [F:0] */ +#define HW_ATL_MDIO_ADDRESS_MSKN 0xFFFF0000 +/* Lower bit position of bitfield MDIO Address [F:0] */ +#define HW_ATL_MDIO_ADDRESS_SHIFT 0 +/* Width of bitfield MDIO Address [F:0] */ +#define HW_ATL_MDIO_ADDRESS_WIDTH 16 +/* Default value of bitfield MDIO Address [F:0] */ +#define HW_ATL_MDIO_ADDRESS_DEFAULT 0x0 + +#define HW_ATL_FW_SM_MDIO 0x0U #define HW_ATL_FW_SM_RAM 0x2U #endif /* HW_ATL_LLH_INTERNAL_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index 52646855495e..6fc5640065bd 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_utils.c: Definition of common functions for Atlantic hardware @@ -327,8 +327,7 @@ err_exit: return err; } -static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, - u32 cnt) +int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt) { u32 val; int err = 0; @@ -964,4 +963,6 @@ const struct aq_fw_ops aq_fw_1x_ops = { .set_eee_rate = NULL, .get_eee_rate = NULL, .set_flow_control = NULL, + .send_fw_request = NULL, + .enable_ptp = NULL, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index 692bed70e104..ee11b107f0a5 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_utils.h: Declaration of common functions for Atlantic hardware @@ -41,7 +41,15 @@ struct __packed hw_atl_rxd_wb_s { u16 status; u16 pkt_len; u16 next_desc_ptr; - u16 vlan; + __le16 vlan; +}; + +/* Hardware rx HW TIMESTAMP writeback */ +struct __packed hw_atl_rxd_hwts_wb_s { + u32 sec_hw; + u32 ns; + u32 sec_lw0; + u32 sec_lw1; }; struct __packed hw_atl_stats_s { @@ -168,6 +176,34 @@ struct __packed hw_atl_utils_mbox_header { u32 error; }; +struct __packed hw_aq_ptp_offset { + u16 ingress_100; + u16 egress_100; + u16 ingress_1000; + u16 egress_1000; + u16 ingress_2500; + u16 egress_2500; + u16 ingress_5000; + u16 egress_5000; + u16 ingress_10000; + u16 egress_10000; +}; + +enum gpio_pin_function { + GPIO_PIN_FUNCTION_NC, + GPIO_PIN_FUNCTION_VAUX_ENABLE, + GPIO_PIN_FUNCTION_EFUSE_BURN_ENABLE, + GPIO_PIN_FUNCTION_SFP_PLUS_DETECT, + GPIO_PIN_FUNCTION_TX_DISABLE, + GPIO_PIN_FUNCTION_RATE_SEL_0, + GPIO_PIN_FUNCTION_RATE_SEL_1, + GPIO_PIN_FUNCTION_TX_FAULT, + GPIO_PIN_FUNCTION_PTP0, + GPIO_PIN_FUNCTION_PTP1, + GPIO_PIN_FUNCTION_PTP2, + GPIO_PIN_FUNCTION_SIZE +}; + struct __packed hw_aq_info { u8 reserved[6]; u16 phy_fault_code; @@ -175,9 +211,23 @@ struct __packed hw_aq_info { u8 cable_len; u8 reserved1; u32 cable_diag_data[4]; - u8 reserved2[32]; + struct hw_aq_ptp_offset ptp_offset; + u8 reserved2[12]; u32 caps_lo; u32 caps_hi; + u32 reserved_datapath; + u32 reserved3[7]; + u32 reserved_simpleresp[3]; + u32 reserved_linkstat[7]; + u32 reserved_wakes_count; + u32 reserved_eee_stat[12]; + u32 tx_stuck_cnt; + u32 setting_address; + u32 setting_length; + u32 caps_ex; + enum gpio_pin_function gpio_pin[3]; + u32 pcie_aer_dump[18]; + u16 snr_margin[4]; }; struct __packed hw_atl_utils_mbox { @@ -237,6 +287,42 @@ struct __packed offload_info { u8 buf[0]; }; +/* Mailbox FW Request interface */ +struct __packed hw_fw_request_ptp_gpio_ctrl { + u32 index; + u32 period; + u64 start; +}; + +struct __packed hw_fw_request_ptp_adj_freq { + u32 ns_mac; + u32 fns_mac; + u32 ns_phy; + u32 fns_phy; + u32 mac_ns_adj; + u32 mac_fns_adj; +}; + +struct __packed hw_fw_request_ptp_adj_clock { + u32 ns; + u32 sec; + int sign; +}; + +#define HW_AQ_FW_REQUEST_PTP_GPIO_CTRL 0x11 +#define HW_AQ_FW_REQUEST_PTP_ADJ_FREQ 0x12 +#define HW_AQ_FW_REQUEST_PTP_ADJ_CLOCK 0x13 + +struct __packed hw_fw_request_iface { + u32 msg_id; + union { + /* PTP FW Request */ + struct hw_fw_request_ptp_gpio_ctrl ptp_gpio_ctrl; + struct hw_fw_request_ptp_adj_freq ptp_adj_freq; + struct hw_fw_request_ptp_adj_clock ptp_adj_clock; + }; +}; + enum hw_atl_rx_action_with_traffic { HW_ATL_RX_DISCARD, HW_ATL_RX_HOST, @@ -344,91 +430,135 @@ enum hw_atl_fw2x_rate { FW2X_RATE_10G = 0x800, }; +/* 0x370 + * Link capabilities resolution register + */ enum hw_atl_fw2x_caps_lo { - CAPS_LO_10BASET_HD = 0x00, + CAPS_LO_10BASET_HD = 0, CAPS_LO_10BASET_FD, CAPS_LO_100BASETX_HD, CAPS_LO_100BASET4_HD, CAPS_LO_100BASET2_HD, - CAPS_LO_100BASETX_FD, + CAPS_LO_100BASETX_FD = 5, CAPS_LO_100BASET2_FD, CAPS_LO_1000BASET_HD, CAPS_LO_1000BASET_FD, CAPS_LO_2P5GBASET_FD, - CAPS_LO_5GBASET_FD, + CAPS_LO_5GBASET_FD = 10, CAPS_LO_10GBASET_FD, }; +/* 0x374 + * Status register + */ enum hw_atl_fw2x_caps_hi { - CAPS_HI_RESERVED1 = 0x00, + CAPS_HI_RESERVED1 = 0, CAPS_HI_10BASET_EEE, CAPS_HI_RESERVED2, CAPS_HI_PAUSE, CAPS_HI_ASYMMETRIC_PAUSE, - CAPS_HI_100BASETX_EEE, + CAPS_HI_100BASETX_EEE = 5, CAPS_HI_RESERVED3, CAPS_HI_RESERVED4, CAPS_HI_1000BASET_FD_EEE, CAPS_HI_2P5GBASET_FD_EEE, - CAPS_HI_5GBASET_FD_EEE, + CAPS_HI_5GBASET_FD_EEE = 10, CAPS_HI_10GBASET_FD_EEE, - CAPS_HI_RESERVED5, + CAPS_HI_FW_REQUEST, CAPS_HI_RESERVED6, CAPS_HI_RESERVED7, - CAPS_HI_RESERVED8, + CAPS_HI_RESERVED8 = 15, CAPS_HI_RESERVED9, CAPS_HI_CABLE_DIAG, CAPS_HI_TEMPERATURE, CAPS_HI_DOWNSHIFT, - CAPS_HI_PTP_AVB_EN, + CAPS_HI_PTP_AVB_EN_FW2X = 20, CAPS_HI_MEDIA_DETECT, CAPS_HI_LINK_DROP, CAPS_HI_SLEEP_PROXY, CAPS_HI_WOL, - CAPS_HI_MAC_STOP, + CAPS_HI_MAC_STOP = 25, CAPS_HI_EXT_LOOPBACK, CAPS_HI_INT_LOOPBACK, CAPS_HI_EFUSE_AGENT, CAPS_HI_WOL_TIMER, - CAPS_HI_STATISTICS, + CAPS_HI_STATISTICS = 30, CAPS_HI_TRANSACTION_ID, }; +/* 0x36C + * Control register + */ enum hw_atl_fw2x_ctrl { - CTRL_RESERVED1 = 0x00, + CTRL_RESERVED1 = 0, CTRL_RESERVED2, CTRL_RESERVED3, CTRL_PAUSE, CTRL_ASYMMETRIC_PAUSE, - CTRL_RESERVED4, + CTRL_RESERVED4 = 5, CTRL_RESERVED5, CTRL_RESERVED6, CTRL_1GBASET_FD_EEE, CTRL_2P5GBASET_FD_EEE, - CTRL_5GBASET_FD_EEE, + CTRL_5GBASET_FD_EEE = 10, CTRL_10GBASET_FD_EEE, CTRL_THERMAL_SHUTDOWN, CTRL_PHY_LOGS, CTRL_EEE_AUTO_DISABLE, - CTRL_PFC, + CTRL_PFC = 15, CTRL_WAKE_ON_LINK, CTRL_CABLE_DIAG, CTRL_TEMPERATURE, CTRL_DOWNSHIFT, - CTRL_PTP_AVB, + CTRL_PTP_AVB = 20, CTRL_RESERVED7, CTRL_LINK_DROP, CTRL_SLEEP_PROXY, CTRL_WOL, - CTRL_MAC_STOP, + CTRL_MAC_STOP = 25, CTRL_EXT_LOOPBACK, CTRL_INT_LOOPBACK, CTRL_RESERVED8, CTRL_WOL_TIMER, - CTRL_STATISTICS, + CTRL_STATISTICS = 30, CTRL_FORCE_RECONNECT, }; +enum hw_atl_caps_ex { + CAPS_EX_LED_CONTROL = 0, + CAPS_EX_LED0_MODE_LO, + CAPS_EX_LED0_MODE_HI, + CAPS_EX_LED1_MODE_LO, + CAPS_EX_LED1_MODE_HI, + CAPS_EX_LED2_MODE_LO = 5, + CAPS_EX_LED2_MODE_HI, + CAPS_EX_RESERVED07, + CAPS_EX_RESERVED08, + CAPS_EX_RESERVED09, + CAPS_EX_RESERVED10 = 10, + CAPS_EX_RESERVED11, + CAPS_EX_RESERVED12, + CAPS_EX_RESERVED13, + CAPS_EX_RESERVED14, + CAPS_EX_RESERVED15 = 15, + CAPS_EX_PHY_PTP_EN, + CAPS_EX_MAC_PTP_EN, + CAPS_EX_EXT_CLK_EN, + CAPS_EX_SCHED_DMA_EN, + CAPS_EX_PTP_GPIO_EN = 20, + CAPS_EX_UPDATE_SETTINGS, + CAPS_EX_PHY_CTRL_TS_PIN, + CAPS_EX_SNR_OPERATING_MARGIN, + CAPS_EX_RESERVED24, + CAPS_EX_RESERVED25 = 25, + CAPS_EX_RESERVED26, + CAPS_EX_RESERVED27, + CAPS_EX_RESERVED28, + CAPS_EX_RESERVED29, + CAPS_EX_RESERVED30 = 30, + CAPS_EX_RESERVED31 +}; + struct aq_hw_s; struct aq_fw_ops; struct aq_hw_caps_s; @@ -475,6 +605,8 @@ struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self); int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt); +int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt); + int hw_atl_utils_fw_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac); int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index da726489e3c8..f649ac949d06 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for @@ -17,14 +17,17 @@ #include "hw_atl_utils.h" #include "hw_atl_llh.h" -#define HW_ATL_FW2X_MPI_RPC_ADDR 0x334 +#define HW_ATL_FW2X_MPI_RPC_ADDR 0x334 -#define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360 -#define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364 -#define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368 -#define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C -#define HW_ATL_FW2X_MPI_STATE_ADDR 0x370 -#define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374 +#define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360 +#define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364 +#define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368 +#define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C +#define HW_ATL_FW2X_MPI_STATE_ADDR 0x370 +#define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374 + +#define HW_ATL_FW3X_EXT_CONTROL_ADDR 0x378 +#define HW_ATL_FW3X_EXT_STATE_ADDR 0x37c #define HW_ATL_FW2X_CAP_PAUSE BIT(CAPS_HI_PAUSE) #define HW_ATL_FW2X_CAP_ASYM_PAUSE BIT(CAPS_HI_ASYMMETRIC_PAUSE) @@ -337,7 +340,7 @@ static int aq_fw2x_get_phy_temp(struct aq_hw_s *self, int *temp) /* Convert PHY temperature from 1/256 degree Celsius * to 1/1000 degree Celsius. */ - *temp = temp_res * 1000 / 256; + *temp = (temp_res & 0xFFFF) * 1000 / 256; return 0; } @@ -444,6 +447,54 @@ err_exit: return err; } +static int aq_fw2x_send_fw_request(struct aq_hw_s *self, + const struct hw_fw_request_iface *fw_req, + size_t size) +{ + u32 ctrl2, orig_ctrl2; + u32 dword_cnt; + int err = 0; + u32 val; + + /* Write data to drvIface Mailbox */ + dword_cnt = size / sizeof(u32); + if (size % sizeof(u32)) + dword_cnt++; + err = hw_atl_utils_fw_upload_dwords(self, aq_fw2x_rpc_get(self), + (void *)fw_req, dword_cnt); + if (err < 0) + goto err_exit; + + /* Toggle statistics bit for FW to update */ + ctrl2 = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); + orig_ctrl2 = ctrl2 & BIT(CAPS_HI_FW_REQUEST); + ctrl2 = ctrl2 ^ BIT(CAPS_HI_FW_REQUEST); + aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, ctrl2); + + /* Wait FW to report back */ + err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val, + orig_ctrl2 != (val & + BIT(CAPS_HI_FW_REQUEST)), + 1U, 10000U); + +err_exit: + return err; +} + +static void aq_fw3x_enable_ptp(struct aq_hw_s *self, int enable) +{ + u32 ptp_opts = aq_hw_read_reg(self, HW_ATL_FW3X_EXT_STATE_ADDR); + u32 all_ptp_features = BIT(CAPS_EX_PHY_PTP_EN) | + BIT(CAPS_EX_PTP_GPIO_EN); + + if (enable) + ptp_opts |= all_ptp_features; + else + ptp_opts &= ~all_ptp_features; + + aq_hw_write_reg(self, HW_ATL_FW3X_EXT_CONTROL_ADDR, ptp_opts); +} + static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed) { u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); @@ -534,19 +585,21 @@ static u32 aq_fw2x_state2_get(struct aq_hw_s *self) } const struct aq_fw_ops aq_fw_2x_ops = { - .init = aq_fw2x_init, - .deinit = aq_fw2x_deinit, - .reset = NULL, - .renegotiate = aq_fw2x_renegotiate, - .get_mac_permanent = aq_fw2x_get_mac_permanent, - .set_link_speed = aq_fw2x_set_link_speed, - .set_state = aq_fw2x_set_state, + .init = aq_fw2x_init, + .deinit = aq_fw2x_deinit, + .reset = NULL, + .renegotiate = aq_fw2x_renegotiate, + .get_mac_permanent = aq_fw2x_get_mac_permanent, + .set_link_speed = aq_fw2x_set_link_speed, + .set_state = aq_fw2x_set_state, .update_link_status = aq_fw2x_update_link_status, - .update_stats = aq_fw2x_update_stats, - .get_phy_temp = aq_fw2x_get_phy_temp, - .set_power = aq_fw2x_set_power, - .set_eee_rate = aq_fw2x_set_eee_rate, - .get_eee_rate = aq_fw2x_get_eee_rate, - .set_flow_control = aq_fw2x_set_flow_control, - .get_flow_control = aq_fw2x_get_flow_control + .update_stats = aq_fw2x_update_stats, + .get_phy_temp = aq_fw2x_get_phy_temp, + .set_power = aq_fw2x_set_power, + .set_eee_rate = aq_fw2x_set_eee_rate, + .get_eee_rate = aq_fw2x_get_eee_rate, + .set_flow_control = aq_fw2x_set_flow_control, + .get_flow_control = aq_fw2x_get_flow_control, + .send_fw_request = aq_fw2x_send_fw_request, + .enable_ptp = aq_fw3x_enable_ptp, }; diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index e24f5d2b6afe..53055ce5dfd6 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -8,7 +8,6 @@ config NET_VENDOR_BROADCOM default y depends on (SSB_POSSIBLE && HAS_DMA) || PCI || BCM63XX || \ SIBYTE_SB1xxx_SOC - select DIMLIB ---help--- If you have a network (Ethernet) chipset belonging to this class, say Y. @@ -69,6 +68,7 @@ config BCMGENET select FIXED_PHY select BCM7XXX_PHY select MDIO_BCM_UNIMAC + select DIMLIB help This driver supports the built-in Ethernet MACs found in the Broadcom BCM7xxx Set Top Box family chipset. @@ -188,6 +188,7 @@ config SYSTEMPORT select MII select PHYLIB select FIXED_PHY + select DIMLIB help This driver supports the built-in Ethernet MACs found in the Broadcom BCM7xxx Set Top Box family chipset using an internal @@ -200,6 +201,7 @@ config BNXT select LIBCRC32C select NET_DEVLINK select PAGE_POOL + select DIMLIB ---help--- This driver supports Broadcom NetXtreme-C/E 10/25/40/50 gigabit Ethernet cards. To compile this driver as a module, choose M here: diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 12cb77ef1081..4f689fb7a61c 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2018,6 +2018,8 @@ static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv) */ if (priv->internal_phy) { int0_enable |= UMAC_IRQ_LINK_EVENT; + if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv)) + int0_enable |= UMAC_IRQ_PHY_DET_R; } else if (priv->ext_phy) { int0_enable |= UMAC_IRQ_LINK_EVENT; } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { @@ -2611,11 +2613,14 @@ static void bcmgenet_irq_task(struct work_struct *work) priv->irq0_stat = 0; spin_unlock_irq(&priv->lock); + if (status & UMAC_IRQ_PHY_DET_R && + priv->dev->phydev->autoneg != AUTONEG_ENABLE) + phy_init_hw(priv->dev->phydev); + /* Link UP/DOWN event */ - if (status & UMAC_IRQ_LINK_EVENT) { - priv->dev->phydev->link = !!(status & UMAC_IRQ_LINK_UP); + if (status & UMAC_IRQ_LINK_EVENT) phy_mac_interrupt(priv->dev->phydev); - } + } /* bcmgenet_isr1: handle Rx and Tx priority queues */ @@ -2710,7 +2715,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) } /* all other interested interrupts handled in bottom half */ - status &= UMAC_IRQ_LINK_EVENT; + status &= (UMAC_IRQ_LINK_EVENT | UMAC_IRQ_PHY_DET_R); if (status) { /* Save irq status for bottom-half processing. */ spin_lock_irqsave(&priv->lock, flags); @@ -2874,6 +2879,12 @@ static int bcmgenet_open(struct net_device *dev) if (priv->internal_phy) bcmgenet_power_up(priv, GENET_POWER_PASSIVE); + ret = bcmgenet_mii_connect(dev); + if (ret) { + netdev_err(dev, "failed to connect to PHY\n"); + goto err_clk_disable; + } + /* take MAC out of reset */ bcmgenet_umac_reset(priv); @@ -2883,6 +2894,12 @@ static int bcmgenet_open(struct net_device *dev) reg = bcmgenet_umac_readl(priv, UMAC_CMD); priv->crc_fwd_en = !!(reg & CMD_CRC_FWD); + ret = bcmgenet_mii_config(dev, true); + if (ret) { + netdev_err(dev, "unsupported PHY\n"); + goto err_disconnect_phy; + } + bcmgenet_set_hw_addr(priv, dev->dev_addr); if (priv->internal_phy) { @@ -2898,7 +2915,7 @@ static int bcmgenet_open(struct net_device *dev) ret = bcmgenet_init_dma(priv); if (ret) { netdev_err(dev, "failed to initialize DMA\n"); - goto err_clk_disable; + goto err_disconnect_phy; } /* Always enable ring 16 - descriptor ring */ @@ -2921,25 +2938,19 @@ static int bcmgenet_open(struct net_device *dev) goto err_irq0; } - ret = bcmgenet_mii_probe(dev); - if (ret) { - netdev_err(dev, "failed to connect to PHY\n"); - goto err_irq1; - } - bcmgenet_netif_start(dev); netif_tx_start_all_queues(dev); return 0; -err_irq1: - free_irq(priv->irq1, priv); err_irq0: free_irq(priv->irq0, priv); err_fini_dma: bcmgenet_dma_teardown(priv); bcmgenet_fini_dma(priv); +err_disconnect_phy: + phy_disconnect(dev->phydev); err_clk_disable: if (priv->internal_phy) bcmgenet_power_down(priv, GENET_POWER_PASSIVE); @@ -3461,16 +3472,10 @@ static int bcmgenet_probe(struct platform_device *pdev) goto err; } - if (dn) { + if (dn) macaddr = of_get_mac_address(dn); - if (IS_ERR(macaddr)) { - dev_err(&pdev->dev, "can't find MAC address\n"); - err = -EINVAL; - goto err; - } - } else { + else macaddr = pd->mac_address; - } priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) { @@ -3482,7 +3487,12 @@ static int bcmgenet_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); dev_set_drvdata(&pdev->dev, dev); - ether_addr_copy(dev->dev_addr, macaddr); + if (IS_ERR_OR_NULL(macaddr) || !is_valid_ether_addr(macaddr)) { + dev_warn(&pdev->dev, "using random Ethernet MAC\n"); + eth_hw_addr_random(dev); + } else { + ether_addr_copy(dev->dev_addr, macaddr); + } dev->watchdog_timeo = 2 * HZ; dev->ethtool_ops = &bcmgenet_ethtool_ops; dev->netdev_ops = &bcmgenet_netdev_ops; @@ -3597,6 +3607,11 @@ static int bcmgenet_remove(struct platform_device *pdev) return 0; } +static void bcmgenet_shutdown(struct platform_device *pdev) +{ + bcmgenet_remove(pdev); +} + #ifdef CONFIG_PM_SLEEP static int bcmgenet_resume(struct device *d) { @@ -3620,6 +3635,8 @@ static int bcmgenet_resume(struct device *d) if (priv->internal_phy) bcmgenet_power_up(priv, GENET_POWER_PASSIVE); + phy_init_hw(dev->phydev); + bcmgenet_umac_reset(priv); init_umac(priv); @@ -3628,8 +3645,6 @@ static int bcmgenet_resume(struct device *d) if (priv->wolopts) clk_disable_unprepare(priv->clk_wol); - phy_init_hw(dev->phydev); - /* Speed settings must be restored */ bcmgenet_mii_config(priv->dev, false); @@ -3715,6 +3730,7 @@ static SIMPLE_DEV_PM_OPS(bcmgenet_pm_ops, bcmgenet_suspend, bcmgenet_resume); static struct platform_driver bcmgenet_driver = { .probe = bcmgenet_probe, .remove = bcmgenet_remove, + .shutdown = bcmgenet_shutdown, .driver = { .name = "bcmgenet", .of_match_table = bcmgenet_match, diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 4a8fc03d82fd..7fbf573d8d52 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -366,6 +366,7 @@ struct bcmgenet_mib_counters { #define EXT_PWR_DOWN_PHY_EN (1 << 20) #define EXT_RGMII_OOB_CTRL 0x0C +#define RGMII_MODE_EN_V123 (1 << 0) #define RGMII_LINK (1 << 4) #define OOB_DISABLE (1 << 5) #define RGMII_MODE_EN (1 << 6) @@ -719,8 +720,8 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF); /* MDIO routines */ int bcmgenet_mii_init(struct net_device *dev); +int bcmgenet_mii_connect(struct net_device *dev); int bcmgenet_mii_config(struct net_device *dev, bool init); -int bcmgenet_mii_probe(struct net_device *dev); void bcmgenet_mii_exit(struct net_device *dev); void bcmgenet_phy_power_set(struct net_device *dev, bool enable); void bcmgenet_mii_setup(struct net_device *dev); diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 970e478a9017..17bb8d60a157 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -173,6 +173,46 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) bcmgenet_fixed_phy_link_update); } +int bcmgenet_mii_connect(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + struct device_node *dn = priv->pdev->dev.of_node; + struct phy_device *phydev; + u32 phy_flags = 0; + int ret; + + /* Communicate the integrated PHY revision */ + if (priv->internal_phy) + phy_flags = priv->gphy_rev; + + /* Initialize link state variables that bcmgenet_mii_setup() uses */ + priv->old_link = -1; + priv->old_speed = -1; + priv->old_duplex = -1; + priv->old_pause = -1; + + if (dn) { + phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup, + phy_flags, priv->phy_interface); + if (!phydev) { + pr_err("could not attach to PHY\n"); + return -ENODEV; + } + } else { + phydev = dev->phydev; + phydev->dev_flags = phy_flags; + + ret = phy_connect_direct(dev, phydev, bcmgenet_mii_setup, + priv->phy_interface); + if (ret) { + pr_err("could not attach to PHY\n"); + return -ENODEV; + } + } + + return 0; +} + int bcmgenet_mii_config(struct net_device *dev, bool init) { struct bcmgenet_priv *priv = netdev_priv(dev); @@ -258,74 +298,29 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) */ if (priv->ext_phy) { reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL); - reg |= RGMII_MODE_EN | id_mode_dis; + reg |= id_mode_dis; + if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv)) + reg |= RGMII_MODE_EN_V123; + else + reg |= RGMII_MODE_EN; bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL); } - if (init) - dev_info(kdev, "configuring instance for %s\n", phy_name); - - return 0; -} - -int bcmgenet_mii_probe(struct net_device *dev) -{ - struct bcmgenet_priv *priv = netdev_priv(dev); - struct device_node *dn = priv->pdev->dev.of_node; - struct phy_device *phydev; - u32 phy_flags; - int ret; - - /* Communicate the integrated PHY revision */ - phy_flags = priv->gphy_rev; - - /* Initialize link state variables that bcmgenet_mii_setup() uses */ - priv->old_link = -1; - priv->old_speed = -1; - priv->old_duplex = -1; - priv->old_pause = -1; - - if (dn) { - phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup, - phy_flags, priv->phy_interface); - if (!phydev) { - pr_err("could not attach to PHY\n"); - return -ENODEV; - } - } else { - phydev = dev->phydev; - phydev->dev_flags = phy_flags; + if (init) { + linkmode_copy(phydev->advertising, phydev->supported); - ret = phy_connect_direct(dev, phydev, bcmgenet_mii_setup, - priv->phy_interface); - if (ret) { - pr_err("could not attach to PHY\n"); - return -ENODEV; - } - } + /* The internal PHY has its link interrupts routed to the + * Ethernet MAC ISRs. On GENETv5 there is a hardware issue + * that prevents the signaling of link UP interrupts when + * the link operates at 10Mbps, so fallback to polling for + * those versions of GENET. + */ + if (priv->internal_phy && !GENET_IS_V5(priv)) + phydev->irq = PHY_IGNORE_INTERRUPT; - /* Configure port multiplexer based on what the probed PHY device since - * reading the 'max-speed' property determines the maximum supported - * PHY speed which is needed for bcmgenet_mii_config() to configure - * things appropriately. - */ - ret = bcmgenet_mii_config(dev, true); - if (ret) { - phy_disconnect(dev->phydev); - return ret; + dev_info(kdev, "configuring instance for %s\n", phy_name); } - linkmode_copy(phydev->advertising, phydev->supported); - - /* The internal PHY has its link interrupts routed to the - * Ethernet MAC ISRs. On GENETv5 there is a hardware issue - * that prevents the signaling of link UP interrupts when - * the link operates at 10Mbps, so fallback to polling for - * those versions of GENET. - */ - if (priv->internal_phy && !GENET_IS_V5(priv)) - dev->phydev->irq = PHY_IGNORE_INTERRUPT; - return 0; } diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 8e8d557901a9..1e1b774e1953 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -3405,17 +3405,17 @@ static int macb_clk_init(struct platform_device *pdev, struct clk **pclk, return err; } - *tx_clk = devm_clk_get(&pdev->dev, "tx_clk"); + *tx_clk = devm_clk_get_optional(&pdev->dev, "tx_clk"); if (IS_ERR(*tx_clk)) - *tx_clk = NULL; + return PTR_ERR(*tx_clk); - *rx_clk = devm_clk_get(&pdev->dev, "rx_clk"); + *rx_clk = devm_clk_get_optional(&pdev->dev, "rx_clk"); if (IS_ERR(*rx_clk)) - *rx_clk = NULL; + return PTR_ERR(*rx_clk); - *tsu_clk = devm_clk_get(&pdev->dev, "tsu_clk"); + *tsu_clk = devm_clk_get_optional(&pdev->dev, "tsu_clk"); if (IS_ERR(*tsu_clk)) - *tsu_clk = NULL; + return PTR_ERR(*tsu_clk); err = clk_prepare_enable(*pclk); if (err) { diff --git a/drivers/net/ethernet/cavium/common/cavium_ptp.h b/drivers/net/ethernet/cavium/common/cavium_ptp.h index be2bafc7beeb..a04eccbc78e8 100644 --- a/drivers/net/ethernet/cavium/common/cavium_ptp.h +++ b/drivers/net/ethernet/cavium/common/cavium_ptp.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* cavium_ptp.h - PTP 1588 clock on Cavium hardware * Copyright (c) 2003-2015, 2017 Cavium, Inc. */ diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index b4b82b9c5cd6..d3214541c7c5 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -901,7 +901,7 @@ static void dpaa_fq_setup(struct dpaa_priv *priv, if (num_portals == 0) dev_err(priv->net_dev->dev.parent, - "No Qman software (affine) channels found"); + "No Qman software (affine) channels found\n"); /* Initialize each FQ in the list */ list_for_each_entry(fq, &priv->dpaa_fq_list, list) { @@ -1335,15 +1335,15 @@ static void dpaa_fd_release(const struct net_device *net_dev, vaddr = phys_to_virt(qm_fd_addr(fd)); sgt = vaddr + qm_fd_get_offset(fd); - dma_unmap_single(dpaa_bp->dev, qm_fd_addr(fd), dpaa_bp->size, - DMA_FROM_DEVICE); + dma_unmap_single(dpaa_bp->priv->rx_dma_dev, qm_fd_addr(fd), + dpaa_bp->size, DMA_FROM_DEVICE); dpaa_release_sgt_members(sgt); - addr = dma_map_single(dpaa_bp->dev, vaddr, dpaa_bp->size, - DMA_FROM_DEVICE); - if (dma_mapping_error(dpaa_bp->dev, addr)) { - dev_err(dpaa_bp->dev, "DMA mapping failed"); + addr = dma_map_single(dpaa_bp->priv->rx_dma_dev, vaddr, + dpaa_bp->size, DMA_FROM_DEVICE); + if (dma_mapping_error(dpaa_bp->priv->rx_dma_dev, addr)) { + netdev_err(net_dev, "DMA mapping failed\n"); return; } bm_buffer_set64(&bmb, addr); @@ -1488,7 +1488,7 @@ return_error: static int dpaa_bp_add_8_bufs(const struct dpaa_bp *dpaa_bp) { - struct device *dev = dpaa_bp->dev; + struct net_device *net_dev = dpaa_bp->priv->net_dev; struct bm_buffer bmb[8]; dma_addr_t addr; void *new_buf; @@ -1497,16 +1497,18 @@ static int dpaa_bp_add_8_bufs(const struct dpaa_bp *dpaa_bp) for (i = 0; i < 8; i++) { new_buf = netdev_alloc_frag(dpaa_bp->raw_size); if (unlikely(!new_buf)) { - dev_err(dev, "netdev_alloc_frag() failed, size %zu\n", - dpaa_bp->raw_size); + netdev_err(net_dev, + "netdev_alloc_frag() failed, size %zu\n", + dpaa_bp->raw_size); goto release_previous_buffs; } new_buf = PTR_ALIGN(new_buf, SMP_CACHE_BYTES); - addr = dma_map_single(dev, new_buf, + addr = dma_map_single(dpaa_bp->priv->rx_dma_dev, new_buf, dpaa_bp->size, DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(dev, addr))) { - dev_err(dpaa_bp->dev, "DMA map failed"); + if (unlikely(dma_mapping_error(dpaa_bp->priv->rx_dma_dev, + addr))) { + netdev_err(net_dev, "DMA map failed\n"); goto release_previous_buffs; } @@ -1634,7 +1636,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) { nr_frags = skb_shinfo(skb)->nr_frags; - dma_unmap_single(dev, addr, + dma_unmap_single(priv->tx_dma_dev, addr, qm_fd_get_offset(fd) + DPAA_SGT_SIZE, dma_dir); @@ -1644,21 +1646,21 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, sgt = phys_to_virt(addr + qm_fd_get_offset(fd)); /* sgt[0] is from lowmem, was dma_map_single()-ed */ - dma_unmap_single(dev, qm_sg_addr(&sgt[0]), + dma_unmap_single(priv->tx_dma_dev, qm_sg_addr(&sgt[0]), qm_sg_entry_get_len(&sgt[0]), dma_dir); /* remaining pages were mapped with skb_frag_dma_map() */ for (i = 1; i <= nr_frags; i++) { WARN_ON(qm_sg_entry_is_ext(&sgt[i])); - dma_unmap_page(dev, qm_sg_addr(&sgt[i]), + dma_unmap_page(priv->tx_dma_dev, qm_sg_addr(&sgt[i]), qm_sg_entry_get_len(&sgt[i]), dma_dir); } /* Free the page frag that we allocated on Tx */ skb_free_frag(phys_to_virt(addr)); } else { - dma_unmap_single(dev, addr, + dma_unmap_single(priv->tx_dma_dev, addr, skb_tail_pointer(skb) - (u8 *)skbh, dma_dir); } @@ -1762,8 +1764,8 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv, goto free_buffers; count_ptr = this_cpu_ptr(dpaa_bp->percpu_count); - dma_unmap_single(dpaa_bp->dev, sg_addr, dpaa_bp->size, - DMA_FROM_DEVICE); + dma_unmap_single(dpaa_bp->priv->rx_dma_dev, sg_addr, + dpaa_bp->size, DMA_FROM_DEVICE); if (!skb) { sz = dpaa_bp->size + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); @@ -1853,7 +1855,6 @@ static int skb_to_contig_fd(struct dpaa_priv *priv, int *offset) { struct net_device *net_dev = priv->net_dev; - struct device *dev = net_dev->dev.parent; enum dma_data_direction dma_dir; unsigned char *buffer_start; struct sk_buff **skbh; @@ -1889,9 +1890,9 @@ static int skb_to_contig_fd(struct dpaa_priv *priv, fd->cmd |= cpu_to_be32(FM_FD_CMD_FCO); /* Map the entire buffer size that may be seen by FMan, but no more */ - addr = dma_map_single(dev, skbh, + addr = dma_map_single(priv->tx_dma_dev, skbh, skb_tail_pointer(skb) - buffer_start, dma_dir); - if (unlikely(dma_mapping_error(dev, addr))) { + if (unlikely(dma_mapping_error(priv->tx_dma_dev, addr))) { if (net_ratelimit()) netif_err(priv, tx_err, net_dev, "dma_map_single() failed\n"); return -EINVAL; @@ -1907,7 +1908,6 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, const enum dma_data_direction dma_dir = DMA_TO_DEVICE; const int nr_frags = skb_shinfo(skb)->nr_frags; struct net_device *net_dev = priv->net_dev; - struct device *dev = net_dev->dev.parent; struct qm_sg_entry *sgt; struct sk_buff **skbh; int i, j, err, sz; @@ -1946,10 +1946,10 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, qm_sg_entry_set_len(&sgt[0], frag_len); sgt[0].bpid = FSL_DPAA_BPID_INV; sgt[0].offset = 0; - addr = dma_map_single(dev, skb->data, + addr = dma_map_single(priv->tx_dma_dev, skb->data, skb_headlen(skb), dma_dir); - if (unlikely(dma_mapping_error(dev, addr))) { - dev_err(dev, "DMA mapping failed"); + if (unlikely(dma_mapping_error(priv->tx_dma_dev, addr))) { + netdev_err(priv->net_dev, "DMA mapping failed\n"); err = -EINVAL; goto sg0_map_failed; } @@ -1960,10 +1960,10 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, frag = &skb_shinfo(skb)->frags[i]; frag_len = skb_frag_size(frag); WARN_ON(!skb_frag_page(frag)); - addr = skb_frag_dma_map(dev, frag, 0, + addr = skb_frag_dma_map(priv->tx_dma_dev, frag, 0, frag_len, dma_dir); - if (unlikely(dma_mapping_error(dev, addr))) { - dev_err(dev, "DMA mapping failed"); + if (unlikely(dma_mapping_error(priv->tx_dma_dev, addr))) { + netdev_err(priv->net_dev, "DMA mapping failed\n"); err = -EINVAL; goto sg_map_failed; } @@ -1986,10 +1986,10 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, skbh = (struct sk_buff **)buffer_start; *skbh = skb; - addr = dma_map_single(dev, buffer_start, + addr = dma_map_single(priv->tx_dma_dev, buffer_start, priv->tx_headroom + DPAA_SGT_SIZE, dma_dir); - if (unlikely(dma_mapping_error(dev, addr))) { - dev_err(dev, "DMA mapping failed"); + if (unlikely(dma_mapping_error(priv->tx_dma_dev, addr))) { + netdev_err(priv->net_dev, "DMA mapping failed\n"); err = -EINVAL; goto sgt_map_failed; } @@ -2003,7 +2003,7 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, sgt_map_failed: sg_map_failed: for (j = 0; j < i; j++) - dma_unmap_page(dev, qm_sg_addr(&sgt[j]), + dma_unmap_page(priv->tx_dma_dev, qm_sg_addr(&sgt[j]), qm_sg_entry_get_len(&sgt[j]), dma_dir); sg0_map_failed: csum_failed: @@ -2304,11 +2304,8 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal, return qman_cb_dqrr_consume; } - dpaa_bp = dpaa_bpid2pool(fd->bpid); - if (!dpaa_bp) - return qman_cb_dqrr_consume; - - dma_unmap_single(dpaa_bp->dev, addr, dpaa_bp->size, DMA_FROM_DEVICE); + dma_unmap_single(dpaa_bp->priv->rx_dma_dev, addr, dpaa_bp->size, + DMA_FROM_DEVICE); /* prefetch the first 64 bytes of the frame or the SGT start */ vaddr = phys_to_virt(addr); @@ -2663,7 +2660,7 @@ static inline void dpaa_bp_free_pf(const struct dpaa_bp *bp, { dma_addr_t addr = bm_buf_addr(bmb); - dma_unmap_single(bp->dev, addr, bp->size, DMA_FROM_DEVICE); + dma_unmap_single(bp->priv->rx_dma_dev, addr, bp->size, DMA_FROM_DEVICE); skb_free_frag(phys_to_virt(addr)); } @@ -2773,12 +2770,37 @@ static int dpaa_eth_probe(struct platform_device *pdev) int err = 0, i, channel; struct device *dev; - /* device used for DMA mapping */ - dev = pdev->dev.parent; - err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40)); - if (err) { - dev_err(dev, "dma_coerce_mask_and_coherent() failed\n"); - return err; + dev = &pdev->dev; + + err = bman_is_probed(); + if (!err) + return -EPROBE_DEFER; + if (err < 0) { + dev_err(dev, "failing probe due to bman probe error\n"); + return -ENODEV; + } + err = qman_is_probed(); + if (!err) + return -EPROBE_DEFER; + if (err < 0) { + dev_err(dev, "failing probe due to qman probe error\n"); + return -ENODEV; + } + err = bman_portals_probed(); + if (!err) + return -EPROBE_DEFER; + if (err < 0) { + dev_err(dev, + "failing probe due to bman portals probe error\n"); + return -ENODEV; + } + err = qman_portals_probed(); + if (!err) + return -EPROBE_DEFER; + if (err < 0) { + dev_err(dev, + "failing probe due to qman portals probe error\n"); + return -ENODEV; } /* Allocate this early, so we can store relevant information in @@ -2801,11 +2823,23 @@ static int dpaa_eth_probe(struct platform_device *pdev) mac_dev = dpaa_mac_dev_get(pdev); if (IS_ERR(mac_dev)) { - dev_err(dev, "dpaa_mac_dev_get() failed\n"); + netdev_err(net_dev, "dpaa_mac_dev_get() failed\n"); err = PTR_ERR(mac_dev); goto free_netdev; } + /* Devices used for DMA mapping */ + priv->rx_dma_dev = fman_port_get_device(mac_dev->port[RX]); + priv->tx_dma_dev = fman_port_get_device(mac_dev->port[TX]); + err = dma_coerce_mask_and_coherent(priv->rx_dma_dev, DMA_BIT_MASK(40)); + if (!err) + err = dma_coerce_mask_and_coherent(priv->tx_dma_dev, + DMA_BIT_MASK(40)); + if (err) { + netdev_err(net_dev, "dma_coerce_mask_and_coherent() failed\n"); + return err; + } + /* If fsl_fm_max_frm is set to a higher value than the all-common 1500, * we choose conservatively and let the user explicitly set a higher * MTU via ifconfig. Otherwise, the user may end up with different MTUs @@ -2832,7 +2866,7 @@ static int dpaa_eth_probe(struct platform_device *pdev) dpaa_bps[i]->raw_size = bpool_buffer_raw_size(i, DPAA_BPS_NUM); /* avoid runtime computations by keeping the usable size here */ dpaa_bps[i]->size = dpaa_bp_size(dpaa_bps[i]->raw_size); - dpaa_bps[i]->dev = dev; + dpaa_bps[i]->priv = priv; err = dpaa_bp_alloc_pool(dpaa_bps[i]); if (err < 0) @@ -2955,7 +2989,7 @@ static int dpaa_remove(struct platform_device *pdev) struct device *dev; int err; - dev = pdev->dev.parent; + dev = &pdev->dev; net_dev = dev_get_drvdata(dev); priv = netdev_priv(net_dev); diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h index f7e59e8db075..1bdfead1d334 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h @@ -80,9 +80,11 @@ struct dpaa_fq_cbs { struct qman_fq egress_ern; }; +struct dpaa_priv; + struct dpaa_bp { - /* device used in the DMA mapping operations */ - struct device *dev; + /* used in the DMA mapping operations */ + struct dpaa_priv *priv; /* current number of buffers in the buffer pool alloted to each CPU */ int __percpu *percpu_count; /* all buffers allocated for this pool have this raw size */ @@ -153,6 +155,8 @@ struct dpaa_priv { u16 tx_headroom; struct net_device *net_dev; struct mac_device *mac_dev; + struct device *rx_dma_dev; + struct device *tx_dma_dev; struct qman_fq *egress_fqs[DPAA_ETH_TXQ_NUM]; struct qman_fq *conf_fqs[DPAA_ETH_TXQ_NUM]; diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 1b959d7ec923..90fc79b3fd0a 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -1255,6 +1255,8 @@ static void dpaa2_eth_set_rx_taildrop(struct dpaa2_eth_priv *priv, bool enable) priv->rx_td_enabled = enable; } +static void update_tx_fqids(struct dpaa2_eth_priv *priv); + static int link_state_update(struct dpaa2_eth_priv *priv) { struct dpni_link_state state = {0}; @@ -1281,6 +1283,7 @@ static int link_state_update(struct dpaa2_eth_priv *priv) goto out; if (state.up) { + update_tx_fqids(priv); netif_carrier_on(priv->net_dev); netif_tx_start_all_queues(priv->net_dev); } else { @@ -2546,6 +2549,47 @@ static int set_pause(struct dpaa2_eth_priv *priv) return 0; } +static void update_tx_fqids(struct dpaa2_eth_priv *priv) +{ + struct dpni_queue_id qid = {0}; + struct dpaa2_eth_fq *fq; + struct dpni_queue queue; + int i, j, err; + + /* We only use Tx FQIDs for FQID-based enqueue, so check + * if DPNI version supports it before updating FQIDs + */ + if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_ENQUEUE_FQID_VER_MAJOR, + DPNI_ENQUEUE_FQID_VER_MINOR) < 0) + return; + + for (i = 0; i < priv->num_fqs; i++) { + fq = &priv->fq[i]; + if (fq->type != DPAA2_TX_CONF_FQ) + continue; + for (j = 0; j < dpaa2_eth_tc_count(priv); j++) { + err = dpni_get_queue(priv->mc_io, 0, priv->mc_token, + DPNI_QUEUE_TX, j, fq->flowid, + &queue, &qid); + if (err) + goto out_err; + + fq->tx_fqid[j] = qid.fqid; + if (fq->tx_fqid[j] == 0) + goto out_err; + } + } + + priv->enqueue = dpaa2_eth_enqueue_fq; + + return; + +out_err: + netdev_info(priv->net_dev, + "Error reading Tx FQID, fallback to QDID-based enqueue\n"); + priv->enqueue = dpaa2_eth_enqueue_qd; +} + /* Configure the DPNI object this interface is associated with */ static int setup_dpni(struct fsl_mc_device *ls_dev) { @@ -3319,6 +3363,9 @@ static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg) if (status & DPNI_IRQ_EVENT_LINK_CHANGED) link_state_update(netdev_priv(net_dev)); + if (status & DPNI_IRQ_EVENT_ENDPOINT_CHANGED) + set_mac_addr(netdev_priv(net_dev)); + return IRQ_HANDLED; } @@ -3344,7 +3391,8 @@ static int setup_irqs(struct fsl_mc_device *ls_dev) } err = dpni_set_irq_mask(ls_dev->mc_io, 0, ls_dev->mc_handle, - DPNI_IRQ_INDEX, DPNI_IRQ_EVENT_LINK_CHANGED); + DPNI_IRQ_INDEX, DPNI_IRQ_EVENT_LINK_CHANGED | + DPNI_IRQ_EVENT_ENDPOINT_CHANGED); if (err < 0) { dev_err(&ls_dev->dev, "dpni_set_irq_mask(): %d\n", err); goto free_irq; diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni.h b/drivers/net/ethernet/freescale/dpaa2/dpni.h index fd583911b6c0..ee0711d06b3a 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpni.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h @@ -133,9 +133,12 @@ int dpni_reset(struct fsl_mc_io *mc_io, */ #define DPNI_IRQ_INDEX 0 /** - * IRQ event - indicates a change in link state + * IRQ events: + * indicates a change in link state + * indicates a change in endpoint */ #define DPNI_IRQ_EVENT_LINK_CHANGED 0x00000001 +#define DPNI_IRQ_EVENT_ENDPOINT_CHANGED 0x00000002 int dpni_set_irq_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c index 210749bf1eac..934111def0be 100644 --- a/drivers/net/ethernet/freescale/fman/fman.c +++ b/drivers/net/ethernet/freescale/fman/fman.c @@ -634,6 +634,9 @@ static void set_port_liodn(struct fman *fman, u8 port_id, { u32 tmp; + iowrite32be(liodn_ofst, &fman->bmi_regs->fmbm_spliodn[port_id - 1]); + if (!IS_ENABLED(CONFIG_FSL_PAMU)) + return; /* set LIODN base for this port */ tmp = ioread32be(&fman->dma_regs->fmdmplr[port_id / 2]); if (port_id % 2) { @@ -644,7 +647,6 @@ static void set_port_liodn(struct fman *fman, u8 port_id, tmp |= liodn_base << DMA_LIODN_SHIFT; } iowrite32be(tmp, &fman->dma_regs->fmdmplr[port_id / 2]); - iowrite32be(liodn_ofst, &fman->bmi_regs->fmbm_spliodn[port_id - 1]); } static void enable_rams_ecc(struct fman_fpm_regs __iomem *fpm_rg) @@ -1942,6 +1944,8 @@ static int fman_init(struct fman *fman) fman->liodn_offset[i] = ioread32be(&fman->bmi_regs->fmbm_spliodn[i - 1]); + if (!IS_ENABLED(CONFIG_FSL_PAMU)) + continue; liodn_base = ioread32be(&fman->dma_regs->fmdmplr[i / 2]); if (i % 2) { /* FMDM_PLR LSB holds LIODN base for odd ports */ diff --git a/drivers/net/ethernet/freescale/fman/fman_port.c b/drivers/net/ethernet/freescale/fman/fman_port.c index ee82ee1384eb..87b26f063cc8 100644 --- a/drivers/net/ethernet/freescale/fman/fman_port.c +++ b/drivers/net/ethernet/freescale/fman/fman_port.c @@ -435,7 +435,6 @@ struct fman_port_cfg { struct fman_port_rx_pools_params { u8 num_of_pools; - u16 second_largest_buf_size; u16 largest_buf_size; }; @@ -946,8 +945,6 @@ static int set_ext_buffer_pools(struct fman_port *port) port->rx_pools_params.num_of_pools = ext_buf_pools->num_of_pools_used; port->rx_pools_params.largest_buf_size = sizes_array[ordered_array[ext_buf_pools->num_of_pools_used - 1]]; - port->rx_pools_params.second_largest_buf_size = - sizes_array[ordered_array[ext_buf_pools->num_of_pools_used - 2]]; /* FMBM_RMPD reg. - pool depletion */ if (buf_pool_depletion->pools_grp_mode_enable) { @@ -1728,6 +1725,20 @@ u32 fman_port_get_qman_channel_id(struct fman_port *port) } EXPORT_SYMBOL(fman_port_get_qman_channel_id); +/** + * fman_port_get_device + * port: Pointer to the FMan port device + * + * Get the 'struct device' associated to the specified FMan port device + * + * Return: pointer to associated 'struct device' + */ +struct device *fman_port_get_device(struct fman_port *port) +{ + return port->dev; +} +EXPORT_SYMBOL(fman_port_get_device); + int fman_port_get_hash_result_offset(struct fman_port *port, u32 *offset) { if (port->buffer_offsets.hash_result_offset == ILLEGAL_BASE) diff --git a/drivers/net/ethernet/freescale/fman/fman_port.h b/drivers/net/ethernet/freescale/fman/fman_port.h index 9dbb69f40121..82f12661a46d 100644 --- a/drivers/net/ethernet/freescale/fman/fman_port.h +++ b/drivers/net/ethernet/freescale/fman/fman_port.h @@ -157,4 +157,6 @@ int fman_port_get_tstamp(struct fman_port *port, const void *data, u64 *tstamp); struct fman_port *fman_port_bind(struct device *dev); +struct device *fman_port_get_device(struct fman_port *port); + #endif /* __FMAN_PORT_H */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index c15d7fc31bb8..e48023643f4c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -32,6 +32,8 @@ #define HNAE3_MOD_VERSION "1.0" +#define HNAE3_MIN_VECTOR_NUM 2 /* first one for misc, another for IO */ + /* Device IDs */ #define HNAE3_DEV_ID_GE 0xA220 #define HNAE3_DEV_ID_25GE 0xA221 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index 28961a68e333..fe5bc6fa8bcd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -16,15 +16,14 @@ static int hns3_dbg_queue_info(struct hnae3_handle *h, const char *cmd_buf) { struct hns3_nic_priv *priv = h->priv; - struct hns3_nic_ring_data *ring_data; struct hns3_enet_ring *ring; u32 base_add_l, base_add_h; u32 queue_num, queue_max; u32 value, i = 0; int cnt; - if (!priv->ring_data) { - dev_err(&h->pdev->dev, "ring_data is NULL\n"); + if (!priv->ring) { + dev_err(&h->pdev->dev, "priv->ring is NULL\n"); return -EFAULT; } @@ -44,7 +43,6 @@ static int hns3_dbg_queue_info(struct hnae3_handle *h, return -EINVAL; } - ring_data = priv->ring_data; for (i = queue_num; i < queue_max; i++) { /* Each cycle needs to determine whether the instance is reset, * to prevent reference to invalid memory. And need to ensure @@ -54,7 +52,7 @@ static int hns3_dbg_queue_info(struct hnae3_handle *h, test_bit(HNS3_NIC_STATE_RESETTING, &priv->state)) return -EPERM; - ring = ring_data[(u32)(i + h->kinfo.num_tqps)].ring; + ring = &priv->ring[(u32)(i + h->kinfo.num_tqps)]; base_add_h = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_BASEADDR_H_REG); base_add_l = readl_relaxed(ring->tqp->io_base + @@ -86,7 +84,7 @@ static int hns3_dbg_queue_info(struct hnae3_handle *h, HNS3_RING_RX_RING_PKTNUM_RECORD_REG); dev_info(&h->pdev->dev, "RX(%d) RING PKTNUM: %u\n", i, value); - ring = ring_data[i].ring; + ring = &priv->ring[i]; base_add_h = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_BASEADDR_H_REG); base_add_l = readl_relaxed(ring->tqp->io_base + @@ -130,7 +128,6 @@ static int hns3_dbg_queue_info(struct hnae3_handle *h, static int hns3_dbg_queue_map(struct hnae3_handle *h) { struct hns3_nic_priv *priv = h->priv; - struct hns3_nic_ring_data *ring_data; int i; if (!h->ae_algo->ops->get_global_queue_id) @@ -143,15 +140,12 @@ static int hns3_dbg_queue_map(struct hnae3_handle *h) u16 global_qid; global_qid = h->ae_algo->ops->get_global_queue_id(h, i); - ring_data = &priv->ring_data[i]; - if (!ring_data || !ring_data->ring || - !ring_data->ring->tqp_vector) + if (!priv->ring || !priv->ring[i].tqp_vector) continue; dev_info(&h->pdev->dev, " %4d %4d %4d\n", - i, global_qid, - ring_data->ring->tqp_vector->vector_irq); + i, global_qid, priv->ring[i].tqp_vector->vector_irq); } return 0; @@ -160,7 +154,6 @@ static int hns3_dbg_queue_map(struct hnae3_handle *h) static int hns3_dbg_bd_info(struct hnae3_handle *h, const char *cmd_buf) { struct hns3_nic_priv *priv = h->priv; - struct hns3_nic_ring_data *ring_data; struct hns3_desc *rx_desc, *tx_desc; struct device *dev = &h->pdev->dev; struct hns3_enet_ring *ring; @@ -183,8 +176,7 @@ static int hns3_dbg_bd_info(struct hnae3_handle *h, const char *cmd_buf) return -EINVAL; } - ring_data = priv->ring_data; - ring = ring_data[q_num].ring; + ring = &priv->ring[q_num]; value = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_TAIL_REG); tx_index = (cnt == 1) ? value : tx_index; @@ -214,7 +206,7 @@ static int hns3_dbg_bd_info(struct hnae3_handle *h, const char *cmd_buf) dev_info(dev, "(TX)vld_ra_ri: %u\n", tx_desc->tx.bdtp_fe_sc_vld_ra_ri); dev_info(dev, "(TX)mss: %u\n", tx_desc->tx.mss); - ring = ring_data[q_num + h->kinfo.num_tqps].ring; + ring = &priv->ring[q_num + h->kinfo.num_tqps]; value = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_TAIL_REG); rx_index = (cnt == 1) ? value : tx_index; rx_desc = &ring->desc[rx_index]; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 6e0b2612d92d..0fdd684a8524 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -483,7 +483,7 @@ static void hns3_reset_tx_queue(struct hnae3_handle *h) for (i = 0; i < h->kinfo.num_tqps; i++) { dev_queue = netdev_get_tx_queue(ndev, - priv->ring_data[i].queue_index); + priv->ring[i].queue_index); netdev_tx_reset_queue(dev_queue); } } @@ -1390,9 +1390,7 @@ static int hns3_fill_skb_to_desc(struct hns3_enet_ring *ring, netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) { struct hns3_nic_priv *priv = netdev_priv(netdev); - struct hns3_nic_ring_data *ring_data = - &tx_ring_data(priv, skb->queue_mapping); - struct hns3_enet_ring *ring = ring_data->ring; + struct hns3_enet_ring *ring = &priv->ring[skb->queue_mapping]; struct netdev_queue *dev_queue; int pre_ntu, next_to_use_head; struct sk_buff *frag_skb; @@ -1444,7 +1442,7 @@ out: cpu_to_le16(BIT(HNS3_TXD_FE_B)); /* Complete translate all packets */ - dev_queue = netdev_get_tx_queue(netdev, ring_data->queue_index); + dev_queue = netdev_get_tx_queue(netdev, ring->queue_index); netdev_tx_sent_queue(dev_queue, skb->len); wmb(); /* Commit all data before submit */ @@ -1461,7 +1459,7 @@ out_err_tx_ok: return NETDEV_TX_OK; out_net_tx_busy: - netif_stop_subqueue(netdev, ring_data->queue_index); + netif_stop_subqueue(netdev, ring->queue_index); smp_mb(); /* Commit all data before submit */ return NETDEV_TX_BUSY; @@ -1584,7 +1582,7 @@ static void hns3_nic_get_stats64(struct net_device *netdev, for (idx = 0; idx < queue_num; idx++) { /* fetch the tx stats */ - ring = priv->ring_data[idx].ring; + ring = &priv->ring[idx]; do { start = u64_stats_fetch_begin_irq(&ring->syncp); tx_bytes += ring->stats.tx_bytes; @@ -1602,7 +1600,7 @@ static void hns3_nic_get_stats64(struct net_device *netdev, } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); /* fetch the rx stats */ - ring = priv->ring_data[idx + queue_num].ring; + ring = &priv->ring[idx + queue_num]; do { start = u64_stats_fetch_begin_irq(&ring->syncp); rx_bytes += ring->stats.rx_bytes; @@ -1807,7 +1805,7 @@ static bool hns3_get_tx_timeo_queue_info(struct net_device *ndev) priv->tx_timeout_count++; - tx_ring = priv->ring_data[timeout_queue].ring; + tx_ring = &priv->ring[timeout_queue]; napi = &tx_ring->tqp_vector->napi; netdev_info(ndev, @@ -2480,18 +2478,19 @@ static int is_valid_clean_head(struct hns3_enet_ring *ring, int h) void hns3_clean_tx_ring(struct hns3_enet_ring *ring) { - struct net_device *netdev = ring->tqp->handle->kinfo.netdev; + struct net_device *netdev = ring_to_netdev(ring); struct hns3_nic_priv *priv = netdev_priv(netdev); struct netdev_queue *dev_queue; int bytes, pkts; int head; head = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_HEAD_REG); - rmb(); /* Make sure head is ready before touch any data */ if (is_ring_empty(ring) || head == ring->next_to_clean) return; /* no data to poll */ + rmb(); /* Make sure head is ready before touch any data */ + if (unlikely(!is_valid_clean_head(ring, head))) { netdev_err(netdev, "wrong head (%d, %d-%d)\n", head, ring->next_to_use, ring->next_to_clean); @@ -2561,7 +2560,7 @@ static void hns3_nic_alloc_rx_buffers(struct hns3_enet_ring *ring, ring->stats.sw_err_cnt++; u64_stats_update_end(&ring->syncp); - hns3_rl_err(ring->tqp_vector->napi.dev, + hns3_rl_err(ring_to_netdev(ring), "alloc rx buffer failed: %d\n", ret); break; @@ -2670,7 +2669,7 @@ static int hns3_gro_complete(struct sk_buff *skb, u32 l234info) static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb, u32 l234info, u32 bd_base_info, u32 ol_info) { - struct net_device *netdev = ring->tqp->handle->kinfo.netdev; + struct net_device *netdev = ring_to_netdev(ring); int l3_type, l4_type; int ol4_type; @@ -2786,7 +2785,7 @@ static int hns3_alloc_skb(struct hns3_enet_ring *ring, unsigned int length, { #define HNS3_NEED_ADD_FRAG 1 struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_clean]; - struct net_device *netdev = ring->tqp->handle->kinfo.netdev; + struct net_device *netdev = ring_to_netdev(ring); struct sk_buff *skb; ring->skb = napi_alloc_skb(&ring->tqp_vector->napi, HNS3_RX_HEAD_SIZE); @@ -2832,10 +2831,10 @@ static int hns3_alloc_skb(struct hns3_enet_ring *ring, unsigned int length, } static int hns3_add_frag(struct hns3_enet_ring *ring, struct hns3_desc *desc, - struct sk_buff **out_skb, bool pending) + bool pending) { - struct sk_buff *skb = *out_skb; - struct sk_buff *head_skb = *out_skb; + struct sk_buff *skb = ring->skb; + struct sk_buff *head_skb = skb; struct sk_buff *new_skb; struct hns3_desc_cb *desc_cb; struct hns3_desc *pre_desc; @@ -2864,10 +2863,9 @@ static int hns3_add_frag(struct hns3_enet_ring *ring, struct hns3_desc *desc, return -ENXIO; if (unlikely(ring->frag_num >= MAX_SKB_FRAGS)) { - new_skb = napi_alloc_skb(&ring->tqp_vector->napi, - HNS3_RX_HEAD_SIZE); + new_skb = napi_alloc_skb(&ring->tqp_vector->napi, 0); if (unlikely(!new_skb)) { - hns3_rl_err(ring->tqp_vector->napi.dev, + hns3_rl_err(ring_to_netdev(ring), "alloc rx fraglist skb fail\n"); return -ENXIO; } @@ -2943,7 +2941,7 @@ static void hns3_set_rx_skb_rss_type(struct hns3_enet_ring *ring, static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb) { - struct net_device *netdev = ring->tqp->handle->kinfo.netdev; + struct net_device *netdev = ring_to_netdev(ring); enum hns3_pkt_l2t_type l2_frame_type; u32 bd_base_info, l234info, ol_info; struct hns3_desc *desc; @@ -3018,8 +3016,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb) return 0; } -static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, - struct sk_buff **out_skb) +static int hns3_handle_rx_bd(struct hns3_enet_ring *ring) { struct sk_buff *skb = ring->skb; struct hns3_desc_cb *desc_cb; @@ -3057,12 +3054,12 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, if (!skb) { ret = hns3_alloc_skb(ring, length, ring->va); - *out_skb = skb = ring->skb; + skb = ring->skb; if (ret < 0) /* alloc buffer fail */ return ret; if (ret > 0) { /* need add frag */ - ret = hns3_add_frag(ring, desc, &skb, false); + ret = hns3_add_frag(ring, desc, false); if (ret) return ret; @@ -3073,7 +3070,7 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, ALIGN(ring->pull_len, sizeof(long))); } } else { - ret = hns3_add_frag(ring, desc, &skb, true); + ret = hns3_add_frag(ring, desc, true); if (ret) return ret; @@ -3091,8 +3088,6 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, } skb_record_rx_queue(skb, ring->tqp->tqp_index); - *out_skb = skb; - return 0; } @@ -3101,17 +3096,19 @@ int hns3_clean_rx_ring(struct hns3_enet_ring *ring, int budget, { #define RCB_NOF_ALLOC_RX_BUFF_ONCE 16 int unused_count = hns3_desc_unused(ring); - struct sk_buff *skb = ring->skb; int recv_pkts = 0; int recv_bds = 0; int err, num; num = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_FBDNUM_REG); - rmb(); /* Make sure num taken effect before the other data is touched */ - num -= unused_count; unused_count -= ring->pending_buf; + if (num <= 0) + goto out; + + rmb(); /* Make sure num taken effect before the other data is touched */ + while (recv_pkts < budget && recv_bds < num) { /* Reuse or realloc buffers */ if (unused_count >= RCB_NOF_ALLOC_RX_BUFF_ONCE) { @@ -3121,27 +3118,19 @@ int hns3_clean_rx_ring(struct hns3_enet_ring *ring, int budget, } /* Poll one pkt */ - err = hns3_handle_rx_bd(ring, &skb); - if (unlikely(!skb)) /* This fault cannot be repaired */ - goto out; - - if (err == -ENXIO) { /* Do not get FE for the packet */ + err = hns3_handle_rx_bd(ring); + /* Do not get FE for the packet or failed to alloc skb */ + if (unlikely(!ring->skb || err == -ENXIO)) { goto out; - } else if (unlikely(err)) { /* Do jump the err */ - recv_bds += ring->pending_buf; - unused_count += ring->pending_buf; - ring->skb = NULL; - ring->pending_buf = 0; - continue; + } else if (likely(!err)) { + rx_fn(ring, ring->skb); + recv_pkts++; } - rx_fn(ring, skb); recv_bds += ring->pending_buf; unused_count += ring->pending_buf; ring->skb = NULL; ring->pending_buf = 0; - - recv_pkts++; } out: @@ -3484,13 +3473,13 @@ static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv) tqp_vector = &priv->tqp_vector[vector_i]; hns3_add_ring_to_group(&tqp_vector->tx_group, - priv->ring_data[i].ring); + &priv->ring[i]); hns3_add_ring_to_group(&tqp_vector->rx_group, - priv->ring_data[i + tqp_num].ring); + &priv->ring[i + tqp_num]); - priv->ring_data[i].ring->tqp_vector = tqp_vector; - priv->ring_data[i + tqp_num].ring->tqp_vector = tqp_vector; + priv->ring[i].tqp_vector = tqp_vector; + priv->ring[i + tqp_num].tqp_vector = tqp_vector; tqp_vector->num_tqps++; } @@ -3634,28 +3623,22 @@ static int hns3_nic_dealloc_vector_data(struct hns3_nic_priv *priv) return 0; } -static int hns3_ring_get_cfg(struct hnae3_queue *q, struct hns3_nic_priv *priv, - unsigned int ring_type) +static void hns3_ring_get_cfg(struct hnae3_queue *q, struct hns3_nic_priv *priv, + unsigned int ring_type) { - struct hns3_nic_ring_data *ring_data = priv->ring_data; int queue_num = priv->ae_handle->kinfo.num_tqps; - struct pci_dev *pdev = priv->ae_handle->pdev; struct hns3_enet_ring *ring; int desc_num; - ring = devm_kzalloc(&pdev->dev, sizeof(*ring), GFP_KERNEL); - if (!ring) - return -ENOMEM; - if (ring_type == HNAE3_RING_TYPE_TX) { + ring = &priv->ring[q->tqp_index]; desc_num = priv->ae_handle->kinfo.num_tx_desc; - ring_data[q->tqp_index].ring = ring; - ring_data[q->tqp_index].queue_index = q->tqp_index; + ring->queue_index = q->tqp_index; ring->io_base = (u8 __iomem *)q->io_base + HNS3_TX_REG_OFFSET; } else { + ring = &priv->ring[q->tqp_index + queue_num]; desc_num = priv->ae_handle->kinfo.num_rx_desc; - ring_data[q->tqp_index + queue_num].ring = ring; - ring_data[q->tqp_index + queue_num].queue_index = q->tqp_index; + ring->queue_index = q->tqp_index; ring->io_base = q->io_base; } @@ -3670,76 +3653,41 @@ static int hns3_ring_get_cfg(struct hnae3_queue *q, struct hns3_nic_priv *priv, ring->desc_num = desc_num; ring->next_to_use = 0; ring->next_to_clean = 0; - - return 0; } -static int hns3_queue_to_ring(struct hnae3_queue *tqp, - struct hns3_nic_priv *priv) +static void hns3_queue_to_ring(struct hnae3_queue *tqp, + struct hns3_nic_priv *priv) { - int ret; - - ret = hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_TX); - if (ret) - return ret; - - ret = hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_RX); - if (ret) { - devm_kfree(priv->dev, priv->ring_data[tqp->tqp_index].ring); - return ret; - } - - return 0; + hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_TX); + hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_RX); } static int hns3_get_ring_config(struct hns3_nic_priv *priv) { struct hnae3_handle *h = priv->ae_handle; struct pci_dev *pdev = h->pdev; - int i, ret; + int i; - priv->ring_data = devm_kzalloc(&pdev->dev, - array3_size(h->kinfo.num_tqps, - sizeof(*priv->ring_data), - 2), - GFP_KERNEL); - if (!priv->ring_data) + priv->ring = devm_kzalloc(&pdev->dev, + array3_size(h->kinfo.num_tqps, + sizeof(*priv->ring), 2), + GFP_KERNEL); + if (!priv->ring) return -ENOMEM; - for (i = 0; i < h->kinfo.num_tqps; i++) { - ret = hns3_queue_to_ring(h->kinfo.tqp[i], priv); - if (ret) - goto err; - } + for (i = 0; i < h->kinfo.num_tqps; i++) + hns3_queue_to_ring(h->kinfo.tqp[i], priv); return 0; -err: - while (i--) { - devm_kfree(priv->dev, priv->ring_data[i].ring); - devm_kfree(priv->dev, - priv->ring_data[i + h->kinfo.num_tqps].ring); - } - - devm_kfree(&pdev->dev, priv->ring_data); - priv->ring_data = NULL; - return ret; } static void hns3_put_ring_config(struct hns3_nic_priv *priv) { - struct hnae3_handle *h = priv->ae_handle; - int i; - - if (!priv->ring_data) + if (!priv->ring) return; - for (i = 0; i < h->kinfo.num_tqps; i++) { - devm_kfree(priv->dev, priv->ring_data[i].ring); - devm_kfree(priv->dev, - priv->ring_data[i + h->kinfo.num_tqps].ring); - } - devm_kfree(priv->dev, priv->ring_data); - priv->ring_data = NULL; + devm_kfree(priv->dev, priv->ring); + priv->ring = NULL; } static int hns3_alloc_ring_memory(struct hns3_enet_ring *ring) @@ -3856,7 +3804,7 @@ static void hns3_init_tx_ring_tc(struct hns3_nic_priv *priv) for (j = 0; j < tc_info->tqp_count; j++) { struct hnae3_queue *q; - q = priv->ring_data[tc_info->tqp_offset + j].ring->tqp; + q = priv->ring[tc_info->tqp_offset + j].tqp; hns3_write_dev(q, HNS3_RING_TX_RING_TC_REG, tc_info->tc); } @@ -3871,21 +3819,21 @@ int hns3_init_all_ring(struct hns3_nic_priv *priv) int ret; for (i = 0; i < ring_num; i++) { - ret = hns3_alloc_ring_memory(priv->ring_data[i].ring); + ret = hns3_alloc_ring_memory(&priv->ring[i]); if (ret) { dev_err(priv->dev, "Alloc ring memory fail! ret=%d\n", ret); goto out_when_alloc_ring_memory; } - u64_stats_init(&priv->ring_data[i].ring->syncp); + u64_stats_init(&priv->ring[i].syncp); } return 0; out_when_alloc_ring_memory: for (j = i - 1; j >= 0; j--) - hns3_fini_ring(priv->ring_data[j].ring); + hns3_fini_ring(&priv->ring[j]); return -ENOMEM; } @@ -3896,8 +3844,8 @@ int hns3_uninit_all_ring(struct hns3_nic_priv *priv) int i; for (i = 0; i < h->kinfo.num_tqps; i++) { - hns3_fini_ring(priv->ring_data[i].ring); - hns3_fini_ring(priv->ring_data[i + h->kinfo.num_tqps].ring); + hns3_fini_ring(&priv->ring[i]); + hns3_fini_ring(&priv->ring[i + h->kinfo.num_tqps]); } return 0; } @@ -4058,7 +4006,7 @@ static int hns3_client_init(struct hnae3_handle *handle) ret = hns3_init_all_ring(priv); if (ret) { ret = -ENOMEM; - goto out_init_ring_data; + goto out_init_ring; } ret = hns3_init_phy(netdev); @@ -4097,12 +4045,12 @@ out_reg_netdev_fail: hns3_uninit_phy(netdev); out_init_phy: hns3_uninit_all_ring(priv); -out_init_ring_data: +out_init_ring: hns3_nic_uninit_vector_data(priv); out_init_vector_data: hns3_nic_dealloc_vector_data(priv); out_alloc_vector_data: - priv->ring_data = NULL; + priv->ring = NULL; out_get_ring_cfg: priv->ae_handle = NULL; free_netdev(netdev); @@ -4263,7 +4211,7 @@ static int hns3_clear_rx_ring(struct hns3_enet_ring *ring) /* if alloc new buffer fail, exit directly * and reclear in up flow. */ - netdev_warn(ring->tqp->handle->kinfo.netdev, + netdev_warn(ring_to_netdev(ring), "reserve buffer map failed, ret = %d\n", ret); return ret; @@ -4309,10 +4257,10 @@ static void hns3_clear_all_ring(struct hnae3_handle *h, bool force) for (i = 0; i < h->kinfo.num_tqps; i++) { struct hns3_enet_ring *ring; - ring = priv->ring_data[i].ring; + ring = &priv->ring[i]; hns3_clear_tx_ring(ring); - ring = priv->ring_data[i + h->kinfo.num_tqps].ring; + ring = &priv->ring[i + h->kinfo.num_tqps]; /* Continue to clear other rings even if clearing some * rings failed. */ @@ -4336,16 +4284,16 @@ int hns3_nic_reset_all_ring(struct hnae3_handle *h) if (ret) return ret; - hns3_init_ring_hw(priv->ring_data[i].ring); + hns3_init_ring_hw(&priv->ring[i]); /* We need to clear tx ring here because self test will * use the ring and will not run down before up */ - hns3_clear_tx_ring(priv->ring_data[i].ring); - priv->ring_data[i].ring->next_to_clean = 0; - priv->ring_data[i].ring->next_to_use = 0; + hns3_clear_tx_ring(&priv->ring[i]); + priv->ring[i].next_to_clean = 0; + priv->ring[i].next_to_use = 0; - rx_ring = priv->ring_data[i + h->kinfo.num_tqps].ring; + rx_ring = &priv->ring[i + h->kinfo.num_tqps]; hns3_init_ring_hw(rx_ring); ret = hns3_clear_rx_ring(rx_ring); if (ret) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index c5b7c22263b1..0725dc52341e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -409,6 +409,7 @@ struct hns3_enet_ring { struct hns3_enet_ring *next; struct hns3_enet_tqp_vector *tqp_vector; struct hnae3_queue *tqp; + int queue_index; struct device *dev; /* will be used for DMA mapping of descriptors */ /* statistic */ @@ -434,18 +435,7 @@ struct hns3_enet_ring { int pending_buf; struct sk_buff *skb; struct sk_buff *tail_skb; -}; - -struct hns_queue; - -struct hns3_nic_ring_data { - struct hns3_enet_ring *ring; - struct napi_struct napi; - int queue_index; - int (*poll_one)(struct hns3_nic_ring_data *, int, void *); - void (*ex_process)(struct hns3_nic_ring_data *, struct sk_buff *); - void (*fini_process)(struct hns3_nic_ring_data *); -}; +} ____cacheline_internodealigned_in_smp; enum hns3_flow_level_range { HNS3_FLOW_LOW = 0, @@ -522,7 +512,7 @@ struct hns3_nic_priv { * the cb for nic to manage the ring buffer, the first half of the * array is for tx_ring and vice versa for the second half */ - struct hns3_nic_ring_data *ring_data; + struct hns3_enet_ring *ring; struct hns3_enet_tqp_vector *tqp_vector; u16 vector_num; @@ -617,11 +607,11 @@ static inline bool hns3_nic_resetting(struct net_device *netdev) #define ring_to_dev(ring) ((ring)->dev) +#define ring_to_netdev(ring) ((ring)->tqp_vector->napi.dev) + #define ring_to_dma_dir(ring) (HNAE3_IS_TX_RING(ring) ? \ DMA_TO_DEVICE : DMA_FROM_DEVICE) -#define tx_ring_data(priv, idx) ((priv)->ring_data[idx]) - #define hns3_buf_size(_ring) ((_ring)->buf_size) static inline unsigned int hns3_page_order(struct hns3_enet_ring *ring) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 680c3508876d..50b07b9aafa5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -203,7 +203,7 @@ static u32 hns3_lb_check_rx_ring(struct hns3_nic_priv *priv, u32 budget) kinfo = &h->kinfo; for (i = kinfo->num_tqps; i < kinfo->num_tqps * 2; i++) { - struct hns3_enet_ring *ring = priv->ring_data[i].ring; + struct hns3_enet_ring *ring = &priv->ring[i]; struct hns3_enet_ring_group *rx_group; u64 pre_rx_pkt; @@ -226,7 +226,7 @@ static void hns3_lb_clear_tx_ring(struct hns3_nic_priv *priv, u32 start_ringid, u32 i; for (i = start_ringid; i <= end_ringid; i++) { - struct hns3_enet_ring *ring = priv->ring_data[i].ring; + struct hns3_enet_ring *ring = &priv->ring[i]; hns3_clean_tx_ring(ring); } @@ -491,7 +491,7 @@ static u64 *hns3_get_stats_tqps(struct hnae3_handle *handle, u64 *data) /* get stats for Tx */ for (i = 0; i < kinfo->num_tqps; i++) { - ring = nic_priv->ring_data[i].ring; + ring = &nic_priv->ring[i]; for (j = 0; j < HNS3_TXQ_STATS_COUNT; j++) { stat = (u8 *)ring + hns3_txq_stats[j].stats_offset; *data++ = *(u64 *)stat; @@ -500,7 +500,7 @@ static u64 *hns3_get_stats_tqps(struct hnae3_handle *handle, u64 *data) /* get stats for Rx */ for (i = 0; i < kinfo->num_tqps; i++) { - ring = nic_priv->ring_data[i + kinfo->num_tqps].ring; + ring = &nic_priv->ring[i + kinfo->num_tqps]; for (j = 0; j < HNS3_RXQ_STATS_COUNT; j++) { stat = (u8 *)ring + hns3_rxq_stats[j].stats_offset; *data++ = *(u64 *)stat; @@ -603,8 +603,8 @@ static void hns3_get_ringparam(struct net_device *netdev, param->tx_max_pending = HNS3_RING_MAX_PENDING; param->rx_max_pending = HNS3_RING_MAX_PENDING; - param->tx_pending = priv->ring_data[0].ring->desc_num; - param->rx_pending = priv->ring_data[queue_num].ring->desc_num; + param->tx_pending = priv->ring[0].desc_num; + param->rx_pending = priv->ring[queue_num].desc_num; } static void hns3_get_pauseparam(struct net_device *netdev, @@ -906,9 +906,8 @@ static void hns3_change_all_ring_bd_num(struct hns3_nic_priv *priv, h->kinfo.num_rx_desc = rx_desc_num; for (i = 0; i < h->kinfo.num_tqps; i++) { - priv->ring_data[i].ring->desc_num = tx_desc_num; - priv->ring_data[i + h->kinfo.num_tqps].ring->desc_num = - rx_desc_num; + priv->ring[i].desc_num = tx_desc_num; + priv->ring[i + h->kinfo.num_tqps].desc_num = rx_desc_num; } } @@ -924,7 +923,7 @@ static struct hns3_enet_ring *hns3_backup_ringparam(struct hns3_nic_priv *priv) return NULL; for (i = 0; i < handle->kinfo.num_tqps * 2; i++) { - memcpy(&tmp_rings[i], priv->ring_data[i].ring, + memcpy(&tmp_rings[i], &priv->ring[i], sizeof(struct hns3_enet_ring)); tmp_rings[i].skb = NULL; } @@ -972,8 +971,8 @@ static int hns3_set_ringparam(struct net_device *ndev, /* Hardware requires that its descriptors must be multiple of eight */ new_tx_desc_num = ALIGN(param->tx_pending, HNS3_RING_BD_MULTIPLE); new_rx_desc_num = ALIGN(param->rx_pending, HNS3_RING_BD_MULTIPLE); - old_tx_desc_num = priv->ring_data[0].ring->desc_num; - old_rx_desc_num = priv->ring_data[queue_num].ring->desc_num; + old_tx_desc_num = priv->ring[0].desc_num; + old_rx_desc_num = priv->ring[queue_num].desc_num; if (old_tx_desc_num == new_tx_desc_num && old_rx_desc_num == new_rx_desc_num) return 0; @@ -1002,7 +1001,7 @@ static int hns3_set_ringparam(struct net_device *ndev, hns3_change_all_ring_bd_num(priv, old_tx_desc_num, old_rx_desc_num); for (i = 0; i < h->kinfo.num_tqps * 2; i++) - memcpy(priv->ring_data[i].ring, &tmp_rings[i], + memcpy(&priv->ring[i], &tmp_rings[i], sizeof(struct hns3_enet_ring)); } else { for (i = 0; i < h->kinfo.num_tqps * 2; i++) @@ -1103,8 +1102,8 @@ static int hns3_get_coalesce_per_queue(struct net_device *netdev, u32 queue, return -EINVAL; } - tx_vector = priv->ring_data[queue].ring->tqp_vector; - rx_vector = priv->ring_data[queue_num + queue].ring->tqp_vector; + tx_vector = priv->ring[queue].tqp_vector; + rx_vector = priv->ring[queue_num + queue].tqp_vector; cmd->use_adaptive_tx_coalesce = tx_vector->tx_group.coal.gl_adapt_enable; @@ -1229,8 +1228,8 @@ static void hns3_set_coalesce_per_queue(struct net_device *netdev, struct hnae3_handle *h = priv->ae_handle; int queue_num = h->kinfo.num_tqps; - tx_vector = priv->ring_data[queue].ring->tqp_vector; - rx_vector = priv->ring_data[queue_num + queue].ring->tqp_vector; + tx_vector = priv->ring[queue].tqp_vector; + rx_vector = priv->ring[queue_num + queue].tqp_vector; tx_vector->tx_group.coal.gl_adapt_enable = cmd->use_adaptive_tx_coalesce; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 3578832067ff..919911fe02ae 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -5,6 +5,7 @@ #define __HCLGE_CMD_H #include <linux/types.h> #include <linux/io.h> +#include <linux/etherdevice.h> #define HCLGE_CMDQ_TX_TIMEOUT 30000 @@ -712,8 +713,7 @@ struct hclge_mac_mgr_tbl_entry_cmd { u8 flags; u8 resp_code; __le16 vlan_tag; - __le32 mac_addr_hi32; - __le16 mac_addr_lo16; + u8 mac_addr[ETH_ALEN]; __le16 rsv1; __le16 ethter_type; __le16 egress_port; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 8a3a4fdc12ed..bf6bca26c337 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -325,8 +325,7 @@ static const struct hclge_mac_mgr_tbl_entry_cmd hclge_mgr_table[] = { { .flags = HCLGE_MAC_MGR_MASK_VLAN_B, .ethter_type = cpu_to_le16(ETH_P_LLDP), - .mac_addr_hi32 = cpu_to_le32(htonl(0x0180C200)), - .mac_addr_lo16 = cpu_to_le16(htons(0x000E)), + .mac_addr = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e}, .i_port_bitmap = 0x1, }, }; @@ -908,6 +907,9 @@ static int hclge_query_pf_resource(struct hclge_dev *hdev) hnae3_get_field(__le16_to_cpu(req->pf_intr_vector_number), HCLGE_PF_VEC_NUM_M, HCLGE_PF_VEC_NUM_S); + /* nic's msix numbers is always equals to the roce's. */ + hdev->num_nic_msi = hdev->num_roce_msi; + /* PF should have NIC vectors and Roce vectors, * NIC vectors are queued before Roce vectors. */ @@ -917,6 +919,15 @@ static int hclge_query_pf_resource(struct hclge_dev *hdev) hdev->num_msi = hnae3_get_field(__le16_to_cpu(req->pf_intr_vector_number), HCLGE_PF_VEC_NUM_M, HCLGE_PF_VEC_NUM_S); + + hdev->num_nic_msi = hdev->num_msi; + } + + if (hdev->num_nic_msi < HNAE3_MIN_VECTOR_NUM) { + dev_err(&hdev->pdev->dev, + "Just %u msi resources, not enough for pf(min:2).\n", + hdev->num_nic_msi); + return -EINVAL; } return 0; @@ -1540,6 +1551,10 @@ static int hclge_assign_tqp(struct hclge_vport *vport, u16 num_tqps) kinfo->rss_size = min_t(u16, hdev->rss_size_max, vport->alloc_tqps / hdev->tm_info.num_tc); + /* ensure one to one mapping between irq and queue at default */ + kinfo->rss_size = min_t(u16, kinfo->rss_size, + (hdev->num_nic_msi - 1) / hdev->tm_info.num_tc); + return 0; } @@ -2319,7 +2334,8 @@ static int hclge_init_msi(struct hclge_dev *hdev) int vectors; int i; - vectors = pci_alloc_irq_vectors(pdev, 1, hdev->num_msi, + vectors = pci_alloc_irq_vectors(pdev, HNAE3_MIN_VECTOR_NUM, + hdev->num_msi, PCI_IRQ_MSI | PCI_IRQ_MSIX); if (vectors < 0) { dev_err(&pdev->dev, @@ -2334,6 +2350,7 @@ static int hclge_init_msi(struct hclge_dev *hdev) hdev->num_msi = vectors; hdev->num_msi_left = vectors; + hdev->base_msi_vector = pdev->irq; hdev->roce_base_vector = hdev->base_msi_vector + hdev->roce_base_msix_offset; @@ -3993,6 +4010,7 @@ static int hclge_get_vector(struct hnae3_handle *handle, u16 vector_num, int alloc = 0; int i, j; + vector_num = min_t(u16, hdev->num_nic_msi - 1, vector_num); vector_num = min(hdev->num_msi_left, vector_num); for (j = 0; j < vector_num; j++) { @@ -9782,6 +9800,9 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) return ret; } + /* Log and clear the hw errors those already occurred */ + hclge_handle_all_hns_hw_errors(ae_dev); + /* Re-enable the hw error interrupts because * the interrupts get disabled on global reset. */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 3153a96729d3..9e59f0e074be 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -764,6 +764,7 @@ struct hclge_dev { u32 base_msi_vector; u16 *vector_status; int *vector_irq; + u16 num_nic_msi; /* Num of nic vectors for this PF */ u16 num_roce_msi; /* Num of roce vectors for this PF */ int roce_base_vector; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 09349545c473..b3c30e5f9aa5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -580,9 +580,16 @@ static void hclge_tm_vport_tc_info_update(struct hclge_vport *vport) kinfo->rss_size = kinfo->req_rss_size; } else if (kinfo->rss_size > max_rss_size || (!kinfo->req_rss_size && kinfo->rss_size < max_rss_size)) { + /* if user not set rss, the rss_size should compare with the + * valid msi numbers to ensure one to one map between tqp and + * irq as default. + */ + if (!kinfo->req_rss_size) + max_rss_size = min_t(u16, max_rss_size, + (hdev->num_nic_msi - 1) / + kinfo->num_tc); + /* Set to the maximum specification value (max_rss_size). */ - dev_info(&hdev->pdev->dev, "rss changes from %d to %d\n", - kinfo->rss_size, max_rss_size); kinfo->rss_size = max_rss_size; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 9c8fd971f9fd..408e38644c60 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -411,6 +411,13 @@ static int hclgevf_knic_setup(struct hclgevf_dev *hdev) kinfo->tqp[i] = &hdev->htqp[i].q; } + /* after init the max rss_size and tqps, adjust the default tqp numbers + * and rss size with the actual vector numbers + */ + kinfo->num_tqps = min_t(u16, hdev->num_nic_msix - 1, kinfo->num_tqps); + kinfo->rss_size = min_t(u16, kinfo->num_tqps / kinfo->num_tc, + kinfo->rss_size); + return 0; } @@ -502,6 +509,7 @@ static int hclgevf_get_vector(struct hnae3_handle *handle, u16 vector_num, int alloc = 0; int i, j; + vector_num = min_t(u16, hdev->num_nic_msix - 1, vector_num); vector_num = min(hdev->num_msi_left, vector_num); for (j = 0; j < vector_num; j++) { @@ -2282,13 +2290,14 @@ static int hclgevf_init_msi(struct hclgevf_dev *hdev) int vectors; int i; - if (hnae3_get_bit(hdev->ae_dev->flag, HNAE3_DEV_SUPPORT_ROCE_B)) + if (hnae3_dev_roce_supported(hdev)) vectors = pci_alloc_irq_vectors(pdev, hdev->roce_base_msix_offset + 1, hdev->num_msi, PCI_IRQ_MSIX); else - vectors = pci_alloc_irq_vectors(pdev, 1, hdev->num_msi, + vectors = pci_alloc_irq_vectors(pdev, HNAE3_MIN_VECTOR_NUM, + hdev->num_msi, PCI_IRQ_MSI | PCI_IRQ_MSIX); if (vectors < 0) { @@ -2304,6 +2313,7 @@ static int hclgevf_init_msi(struct hclgevf_dev *hdev) hdev->num_msi = vectors; hdev->num_msi_left = vectors; + hdev->base_msi_vector = pdev->irq; hdev->roce_base_vector = pdev->irq + hdev->roce_base_msix_offset; @@ -2569,7 +2579,7 @@ static int hclgevf_query_vf_resource(struct hclgevf_dev *hdev) req = (struct hclgevf_query_res_cmd *)desc.data; - if (hnae3_get_bit(hdev->ae_dev->flag, HNAE3_DEV_SUPPORT_ROCE_B)) { + if (hnae3_dev_roce_supported(hdev)) { hdev->roce_base_msix_offset = hnae3_get_field(__le16_to_cpu(req->msixcap_localid_ba_rocee), HCLGEVF_MSIX_OFT_ROCEE_M, @@ -2578,6 +2588,9 @@ static int hclgevf_query_vf_resource(struct hclgevf_dev *hdev) hnae3_get_field(__le16_to_cpu(req->vf_intr_vector_number), HCLGEVF_VEC_NUM_M, HCLGEVF_VEC_NUM_S); + /* nic's msix numbers is always equals to the roce's. */ + hdev->num_nic_msix = hdev->num_roce_msix; + /* VF should have NIC vectors and Roce vectors, NIC vectors * are queued before Roce vectors. The offset is fixed to 64. */ @@ -2587,6 +2600,15 @@ static int hclgevf_query_vf_resource(struct hclgevf_dev *hdev) hdev->num_msi = hnae3_get_field(__le16_to_cpu(req->vf_intr_vector_number), HCLGEVF_VEC_NUM_M, HCLGEVF_VEC_NUM_S); + + hdev->num_nic_msix = hdev->num_msi; + } + + if (hdev->num_nic_msix < HNAE3_MIN_VECTOR_NUM) { + dev_err(&hdev->pdev->dev, + "Just %u msi resources, not enough for vf(min:2).\n", + hdev->num_nic_msix); + return -EINVAL; } return 0; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index ed839408850e..ef86155de9e0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -271,6 +271,7 @@ struct hclgevf_dev { u16 num_msi; u16 num_msi_left; u16 num_msi_used; + u16 num_nic_msix; /* Num of nic vectors for this VF */ u16 num_roce_msix; /* Num of roce vectors for this VF */ u16 roce_base_msix_offset; int roce_base_vector; diff --git a/drivers/net/ethernet/i825xx/lasi_82596.c b/drivers/net/ethernet/i825xx/lasi_82596.c index 211c5f74b4c8..aec7e98bcc85 100644 --- a/drivers/net/ethernet/i825xx/lasi_82596.c +++ b/drivers/net/ethernet/i825xx/lasi_82596.c @@ -96,6 +96,8 @@ #define OPT_SWAP_PORT 0x0001 /* Need to wordswp on the MPU port */ +#define LIB82596_DMA_ATTR DMA_ATTR_NON_CONSISTENT + #define DMA_WBACK(ndev, addr, len) \ do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_TO_DEVICE); } while (0) @@ -200,7 +202,7 @@ static int __exit lan_remove_chip(struct parisc_device *pdev) unregister_netdev (dev); dma_free_attrs(&pdev->dev, sizeof(struct i596_private), lp->dma, - lp->dma_addr, DMA_ATTR_NON_CONSISTENT); + lp->dma_addr, LIB82596_DMA_ATTR); free_netdev (dev); return 0; } diff --git a/drivers/net/ethernet/i825xx/lib82596.c b/drivers/net/ethernet/i825xx/lib82596.c index 1274ad24d6af..f9742af7f142 100644 --- a/drivers/net/ethernet/i825xx/lib82596.c +++ b/drivers/net/ethernet/i825xx/lib82596.c @@ -1065,7 +1065,7 @@ static int i82596_probe(struct net_device *dev) dma = dma_alloc_attrs(dev->dev.parent, sizeof(struct i596_dma), &lp->dma_addr, GFP_KERNEL, - DMA_ATTR_NON_CONSISTENT); + LIB82596_DMA_ATTR); if (!dma) { printk(KERN_ERR "%s: Couldn't get shared memory\n", __FILE__); return -ENOMEM; @@ -1087,7 +1087,7 @@ static int i82596_probe(struct net_device *dev) i = register_netdev(dev); if (i) { dma_free_attrs(dev->dev.parent, sizeof(struct i596_dma), - dma, lp->dma_addr, DMA_ATTR_NON_CONSISTENT); + dma, lp->dma_addr, LIB82596_DMA_ATTR); return i; } diff --git a/drivers/net/ethernet/i825xx/sni_82596.c b/drivers/net/ethernet/i825xx/sni_82596.c index 6eb6c2ff7f09..6436a98c5953 100644 --- a/drivers/net/ethernet/i825xx/sni_82596.c +++ b/drivers/net/ethernet/i825xx/sni_82596.c @@ -24,6 +24,8 @@ static const char sni_82596_string[] = "snirm_82596"; +#define LIB82596_DMA_ATTR 0 + #define DMA_WBACK(priv, addr, len) do { } while (0) #define DMA_INV(priv, addr, len) do { } while (0) #define DMA_WBACK_INV(priv, addr, len) do { } while (0) @@ -152,7 +154,7 @@ static int sni_82596_driver_remove(struct platform_device *pdev) unregister_netdev(dev); dma_free_attrs(dev->dev.parent, sizeof(struct i596_private), lp->dma, - lp->dma_addr, DMA_ATTR_NON_CONSISTENT); + lp->dma_addr, LIB82596_DMA_ATTR); iounmap(lp->ca); iounmap(lp->mpu_port); free_netdev (dev); diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 2b073a3c0b84..f59d9a8e35e2 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -2878,12 +2878,10 @@ static int enable_scrq_irq(struct ibmvnic_adapter *adapter, if (test_bit(0, &adapter->resetting) && adapter->reset_reason == VNIC_RESET_MOBILITY) { - u64 val = (0xff000000) | scrq->hw_irq; + struct irq_desc *desc = irq_to_desc(scrq->irq); + struct irq_chip *chip = irq_desc_get_chip(desc); - rc = plpar_hcall_norets(H_EOI, val); - if (rc) - dev_err(dev, "H_EOI FAILED irq 0x%llx. rc=%ld\n", - val, rc); + chip->irq_eoi(&desc->irq_data); } rc = plpar_hcall_norets(H_VIOCTL, adapter->vdev->unit_address, diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index d7d56e42a6aa..42f57ab8fb8e 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6294,6 +6294,174 @@ fl_out: pm_runtime_put_sync(netdev->dev.parent); } +/* S0ix implementation */ +static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 mac_data; + u16 phy_data; + + /* Disable the periodic inband message, + * don't request PCIe clock in K1 page770_17[10:9] = 10b + */ + e1e_rphy(hw, HV_PM_CTRL, &phy_data); + phy_data &= ~HV_PM_CTRL_K1_CLK_REQ; + phy_data |= BIT(10); + e1e_wphy(hw, HV_PM_CTRL, phy_data); + + /* Make sure we don't exit K1 every time a new packet arrives + * 772_29[5] = 1 CS_Mode_Stay_In_K1 + */ + e1e_rphy(hw, I217_CGFREG, &phy_data); + phy_data |= BIT(5); + e1e_wphy(hw, I217_CGFREG, phy_data); + + /* Change the MAC/PHY interface to SMBus + * Force the SMBus in PHY page769_23[0] = 1 + * Force the SMBus in MAC CTRL_EXT[11] = 1 + */ + e1e_rphy(hw, CV_SMB_CTRL, &phy_data); + phy_data |= CV_SMB_CTRL_FORCE_SMBUS; + e1e_wphy(hw, CV_SMB_CTRL, phy_data); + mac_data = er32(CTRL_EXT); + mac_data |= E1000_CTRL_EXT_FORCE_SMBUS; + ew32(CTRL_EXT, mac_data); + + /* DFT control: PHY bit: page769_20[0] = 1 + * Gate PPW via EXTCNF_CTRL - set 0x0F00[7] = 1 + */ + e1e_rphy(hw, I82579_DFT_CTRL, &phy_data); + phy_data |= BIT(0); + e1e_wphy(hw, I82579_DFT_CTRL, phy_data); + + mac_data = er32(EXTCNF_CTRL); + mac_data |= E1000_EXTCNF_CTRL_GATE_PHY_CFG; + ew32(EXTCNF_CTRL, mac_data); + + /* Check MAC Tx/Rx packet buffer pointers. + * Reset MAC Tx/Rx packet buffer pointers to suppress any + * pending traffic indication that would prevent power gating. + */ + mac_data = er32(TDFH); + if (mac_data) + ew32(TDFH, 0); + mac_data = er32(TDFT); + if (mac_data) + ew32(TDFT, 0); + mac_data = er32(TDFHS); + if (mac_data) + ew32(TDFHS, 0); + mac_data = er32(TDFTS); + if (mac_data) + ew32(TDFTS, 0); + mac_data = er32(TDFPC); + if (mac_data) + ew32(TDFPC, 0); + mac_data = er32(RDFH); + if (mac_data) + ew32(RDFH, 0); + mac_data = er32(RDFT); + if (mac_data) + ew32(RDFT, 0); + mac_data = er32(RDFHS); + if (mac_data) + ew32(RDFHS, 0); + mac_data = er32(RDFTS); + if (mac_data) + ew32(RDFTS, 0); + mac_data = er32(RDFPC); + if (mac_data) + ew32(RDFPC, 0); + + /* Enable the Dynamic Power Gating in the MAC */ + mac_data = er32(FEXTNVM7); + mac_data |= BIT(22); + ew32(FEXTNVM7, mac_data); + + /* Disable the time synchronization clock */ + mac_data = er32(FEXTNVM7); + mac_data |= BIT(31); + mac_data &= ~BIT(0); + ew32(FEXTNVM7, mac_data); + + /* Dynamic Power Gating Enable */ + mac_data = er32(CTRL_EXT); + mac_data |= BIT(3); + ew32(CTRL_EXT, mac_data); + + /* Enable the Dynamic Clock Gating in the DMA and MAC */ + mac_data = er32(CTRL_EXT); + mac_data |= E1000_CTRL_EXT_DMA_DYN_CLK_EN; + ew32(CTRL_EXT, mac_data); + + /* No MAC DPG gating SLP_S0 in modern standby + * Switch the logic of the lanphypc to use PMC counter + */ + mac_data = er32(FEXTNVM5); + mac_data |= BIT(7); + ew32(FEXTNVM5, mac_data); +} + +static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 mac_data; + u16 phy_data; + + /* Disable the Dynamic Power Gating in the MAC */ + mac_data = er32(FEXTNVM7); + mac_data &= 0xFFBFFFFF; + ew32(FEXTNVM7, mac_data); + + /* Enable the time synchronization clock */ + mac_data = er32(FEXTNVM7); + mac_data |= BIT(0); + ew32(FEXTNVM7, mac_data); + + /* Disable Dynamic Power Gating */ + mac_data = er32(CTRL_EXT); + mac_data &= 0xFFFFFFF7; + ew32(CTRL_EXT, mac_data); + + /* Disable the Dynamic Clock Gating in the DMA and MAC */ + mac_data = er32(CTRL_EXT); + mac_data &= 0xFFF7FFFF; + ew32(CTRL_EXT, mac_data); + + /* Revert the lanphypc logic to use the internal Gbe counter + * and not the PMC counter + */ + mac_data = er32(FEXTNVM5); + mac_data &= 0xFFFFFF7F; + ew32(FEXTNVM5, mac_data); + + /* Enable the periodic inband message, + * Request PCIe clock in K1 page770_17[10:9] =01b + */ + e1e_rphy(hw, HV_PM_CTRL, &phy_data); + phy_data &= 0xFBFF; + phy_data |= HV_PM_CTRL_K1_CLK_REQ; + e1e_wphy(hw, HV_PM_CTRL, phy_data); + + /* Return back configuration + * 772_29[5] = 0 CS_Mode_Stay_In_K1 + */ + e1e_rphy(hw, I217_CGFREG, &phy_data); + phy_data &= 0xFFDF; + e1e_wphy(hw, I217_CGFREG, phy_data); + + /* Change the MAC/PHY interface to Kumeran + * Unforce the SMBus in PHY page769_23[0] = 0 + * Unforce the SMBus in MAC CTRL_EXT[11] = 0 + */ + e1e_rphy(hw, CV_SMB_CTRL, &phy_data); + phy_data &= ~CV_SMB_CTRL_FORCE_SMBUS; + e1e_wphy(hw, CV_SMB_CTRL, phy_data); + mac_data = er32(CTRL_EXT); + mac_data &= ~E1000_CTRL_EXT_FORCE_SMBUS; + ew32(CTRL_EXT, mac_data); +} + static int e1000e_pm_freeze(struct device *dev) { struct net_device *netdev = dev_get_drvdata(dev); @@ -6649,7 +6817,10 @@ static int e1000e_pm_thaw(struct device *dev) static int e1000e_pm_suspend(struct device *dev) { + struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev)); + struct e1000_adapter *adapter = netdev_priv(netdev); struct pci_dev *pdev = to_pci_dev(dev); + struct e1000_hw *hw = &adapter->hw; int rc; e1000e_flush_lpic(pdev); @@ -6660,14 +6831,25 @@ static int e1000e_pm_suspend(struct device *dev) if (rc) e1000e_pm_thaw(dev); + /* Introduce S0ix implementation */ + if (hw->mac.type >= e1000_pch_cnp) + e1000e_s0ix_entry_flow(adapter); + return rc; } static int e1000e_pm_resume(struct device *dev) { + struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev)); + struct e1000_adapter *adapter = netdev_priv(netdev); struct pci_dev *pdev = to_pci_dev(dev); + struct e1000_hw *hw = &adapter->hw; int rc; + /* Introduce S0ix implementation */ + if (hw->mac.type >= e1000_pch_cnp) + e1000e_s0ix_exit_flow(adapter); + rc = __e1000_resume(pdev); if (rc) return rc; diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h index 47f5ca793970..df59fd1d660c 100644 --- a/drivers/net/ethernet/intel/e1000e/regs.h +++ b/drivers/net/ethernet/intel/e1000e/regs.h @@ -18,6 +18,7 @@ #define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */ #define E1000_FEXTNVM3 0x0003C /* Future Extended NVM 3 - RW */ #define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */ +#define E1000_FEXTNVM5 0x00014 /* Future Extended NVM 5 - RW */ #define E1000_FEXTNVM6 0x00010 /* Future Extended NVM 6 - RW */ #define E1000_FEXTNVM7 0x000E4 /* Future Extended NVM 7 - RW */ #define E1000_FEXTNVM9 0x5BB4 /* Future Extended NVM 9 - RW */ @@ -234,4 +235,7 @@ #define E1000_RXMTRL 0x0B634 /* Time sync Rx EtherType and Msg Type - RW */ #define E1000_RXUDP 0x0B638 /* Time Sync Rx UDP Port - RW */ +/* PHY registers */ +#define I82579_DFT_CTRL PHY_REG(769, 20) + #endif diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 7e16345d836e..0868677d43ed 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -411,7 +411,6 @@ struct igc_adapter { u32 tx_hwtstamp_timeouts; u32 tx_hwtstamp_skipped; u32 rx_hwtstamp_cleared; - u32 *shadow_vfta; u32 rss_queues; u32 rss_indir_tbl_init; diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index f3f2325fe567..f3788f0b95b4 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -282,7 +282,10 @@ #define IGC_RCTL_BAM 0x00008000 /* broadcast enable */ /* Receive Descriptor bit definitions */ -#define IGC_RXD_STAT_EOP 0x02 /* End of Packet */ +#define IGC_RXD_STAT_EOP 0x02 /* End of Packet */ +#define IGC_RXD_STAT_IXSM 0x04 /* Ignore checksum */ +#define IGC_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */ +#define IGC_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ #define IGC_RXDEXT_STATERR_CE 0x01000000 #define IGC_RXDEXT_STATERR_SE 0x02000000 @@ -402,4 +405,7 @@ #define IGC_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet Type of TCP */ #define IGC_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 packet TYPE of SCTP */ +/* Maximum size of the MTA register table in all supported adapters */ +#define MAX_MTA_REG 128 + #endif /* _IGC_DEFINES_H_ */ diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index abb2d72911ff..20f710645746 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -91,6 +91,7 @@ struct igc_mac_info { u16 mta_reg_count; u16 uta_reg_count; + u32 mta_shadow[MAX_MTA_REG]; u16 rar_entry_count; u8 forced_speed_duplex; diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c index 5eeb4c8caf4a..12aa6b5fcb5d 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.c +++ b/drivers/net/ethernet/intel/igc/igc_mac.c @@ -784,3 +784,107 @@ bool igc_enable_mng_pass_thru(struct igc_hw *hw) out: return ret_val; } + +/** + * igc_hash_mc_addr - Generate a multicast hash value + * @hw: pointer to the HW structure + * @mc_addr: pointer to a multicast address + * + * Generates a multicast address hash value which is used to determine + * the multicast filter table array address and new table value. See + * igc_mta_set() + **/ +static u32 igc_hash_mc_addr(struct igc_hw *hw, u8 *mc_addr) +{ + u32 hash_value, hash_mask; + u8 bit_shift = 0; + + /* Register count multiplied by bits per register */ + hash_mask = (hw->mac.mta_reg_count * 32) - 1; + + /* For a mc_filter_type of 0, bit_shift is the number of left-shifts + * where 0xFF would still fall within the hash mask. + */ + while (hash_mask >> bit_shift != 0xFF) + bit_shift++; + + /* The portion of the address that is used for the hash table + * is determined by the mc_filter_type setting. + * The algorithm is such that there is a total of 8 bits of shifting. + * The bit_shift for a mc_filter_type of 0 represents the number of + * left-shifts where the MSB of mc_addr[5] would still fall within + * the hash_mask. Case 0 does this exactly. Since there are a total + * of 8 bits of shifting, then mc_addr[4] will shift right the + * remaining number of bits. Thus 8 - bit_shift. The rest of the + * cases are a variation of this algorithm...essentially raising the + * number of bits to shift mc_addr[5] left, while still keeping the + * 8-bit shifting total. + * + * For example, given the following Destination MAC Address and an + * MTA register count of 128 (thus a 4096-bit vector and 0xFFF mask), + * we can see that the bit_shift for case 0 is 4. These are the hash + * values resulting from each mc_filter_type... + * [0] [1] [2] [3] [4] [5] + * 01 AA 00 12 34 56 + * LSB MSB + * + * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563 + * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6 + * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163 + * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634 + */ + switch (hw->mac.mc_filter_type) { + default: + case 0: + break; + case 1: + bit_shift += 1; + break; + case 2: + bit_shift += 2; + break; + case 3: + bit_shift += 4; + break; + } + + hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) | + (((u16)mc_addr[5]) << bit_shift))); + + return hash_value; +} + +/** + * igc_update_mc_addr_list - Update Multicast addresses + * @hw: pointer to the HW structure + * @mc_addr_list: array of multicast addresses to program + * @mc_addr_count: number of multicast addresses to program + * + * Updates entire Multicast Table Array. + * The caller must have a packed mc_addr_list of multicast addresses. + **/ +void igc_update_mc_addr_list(struct igc_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count) +{ + u32 hash_value, hash_bit, hash_reg; + int i; + + /* clear mta_shadow */ + memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); + + /* update mta_shadow from mc_addr_list */ + for (i = 0; (u32)i < mc_addr_count; i++) { + hash_value = igc_hash_mc_addr(hw, mc_addr_list); + + hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); + hash_bit = hash_value & 0x1F; + + hw->mac.mta_shadow[hash_reg] |= BIT(hash_bit); + mc_addr_list += ETH_ALEN; + } + + /* replace the entire MTA table */ + for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) + array_wr32(IGC_MTA, i, hw->mac.mta_shadow[i]); + wrfl(); +} diff --git a/drivers/net/ethernet/intel/igc/igc_mac.h b/drivers/net/ethernet/intel/igc/igc_mac.h index 782bc995badc..832cccec87cd 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.h +++ b/drivers/net/ethernet/intel/igc/igc_mac.h @@ -29,6 +29,8 @@ s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed, u16 *duplex); bool igc_enable_mng_pass_thru(struct igc_hw *hw); +void igc_update_mc_addr_list(struct igc_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count); enum igc_mng_mode { igc_mng_mode_none = 0, diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 63b62d74f961..6e0af464326e 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -795,6 +795,44 @@ static int igc_set_mac(struct net_device *netdev, void *p) return 0; } +/** + * igc_write_mc_addr_list - write multicast addresses to MTA + * @netdev: network interface device structure + * + * Writes multicast address list to the MTA hash table. + * Returns: -ENOMEM on failure + * 0 on no addresses written + * X on writing X addresses to MTA + **/ +static int igc_write_mc_addr_list(struct net_device *netdev) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; + struct netdev_hw_addr *ha; + u8 *mta_list; + int i; + + if (netdev_mc_empty(netdev)) { + /* nothing to program, so clear mc list */ + igc_update_mc_addr_list(hw, NULL, 0); + return 0; + } + + mta_list = kcalloc(netdev_mc_count(netdev), 6, GFP_ATOMIC); + if (!mta_list) + return -ENOMEM; + + /* The shared function expects a packed array of only addresses. */ + i = 0; + netdev_for_each_mc_addr(ha, netdev) + memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN); + + igc_update_mc_addr_list(hw, mta_list, i); + kfree(mta_list); + + return netdev_mc_count(netdev); +} + static void igc_tx_ctxtdesc(struct igc_ring *tx_ring, struct igc_tx_buffer *first, u32 vlan_macip_lens, u32 type_tucmd, @@ -1163,6 +1201,46 @@ static netdev_tx_t igc_xmit_frame(struct sk_buff *skb, return igc_xmit_frame_ring(skb, igc_tx_queue_mapping(adapter, skb)); } +static void igc_rx_checksum(struct igc_ring *ring, + union igc_adv_rx_desc *rx_desc, + struct sk_buff *skb) +{ + skb_checksum_none_assert(skb); + + /* Ignore Checksum bit is set */ + if (igc_test_staterr(rx_desc, IGC_RXD_STAT_IXSM)) + return; + + /* Rx checksum disabled via ethtool */ + if (!(ring->netdev->features & NETIF_F_RXCSUM)) + return; + + /* TCP/UDP checksum error bit is set */ + if (igc_test_staterr(rx_desc, + IGC_RXDEXT_STATERR_TCPE | + IGC_RXDEXT_STATERR_IPE)) { + /* work around errata with sctp packets where the TCPE aka + * L4E bit is set incorrectly on 64 byte (60 byte w/o crc) + * packets (aka let the stack check the crc32c) + */ + if (!(skb->len == 60 && + test_bit(IGC_RING_FLAG_RX_SCTP_CSUM, &ring->flags))) { + u64_stats_update_begin(&ring->rx_syncp); + ring->rx_stats.csum_err++; + u64_stats_update_end(&ring->rx_syncp); + } + /* let the stack verify checksum errors */ + return; + } + /* It must be a TCP or UDP packet with a valid checksum */ + if (igc_test_staterr(rx_desc, IGC_RXD_STAT_TCPCS | + IGC_RXD_STAT_UDPCS)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + dev_dbg(ring->dev, "cksum success: bits %08X\n", + le32_to_cpu(rx_desc->wb.upper.status_error)); +} + static inline void igc_rx_hash(struct igc_ring *ring, union igc_adv_rx_desc *rx_desc, struct sk_buff *skb) @@ -1189,6 +1267,8 @@ static void igc_process_skb_fields(struct igc_ring *rx_ring, { igc_rx_hash(rx_ring, rx_desc, skb); + igc_rx_checksum(rx_ring, rx_desc, skb); + skb_record_rx_queue(skb, rx_ring->queue_index); skb->protocol = eth_type_trans(skb, rx_ring->netdev); @@ -2518,6 +2598,110 @@ int igc_del_mac_steering_filter(struct igc_adapter *adapter, IGC_MAC_STATE_QUEUE_STEERING | flags); } +/* Add a MAC filter for 'addr' directing matching traffic to 'queue', + * 'flags' is used to indicate what kind of match is made, match is by + * default for the destination address, if matching by source address + * is desired the flag IGC_MAC_STATE_SRC_ADDR can be used. + */ +static int igc_add_mac_filter(struct igc_adapter *adapter, + const u8 *addr, const u8 queue) +{ + struct igc_hw *hw = &adapter->hw; + int rar_entries = hw->mac.rar_entry_count; + int i; + + if (is_zero_ether_addr(addr)) + return -EINVAL; + + /* Search for the first empty entry in the MAC table. + * Do not touch entries at the end of the table reserved for the VF MAC + * addresses. + */ + for (i = 0; i < rar_entries; i++) { + if (!igc_mac_entry_can_be_used(&adapter->mac_table[i], + addr, 0)) + continue; + + ether_addr_copy(adapter->mac_table[i].addr, addr); + adapter->mac_table[i].queue = queue; + adapter->mac_table[i].state |= IGC_MAC_STATE_IN_USE; + + igc_rar_set_index(adapter, i); + return i; + } + + return -ENOSPC; +} + +/* Remove a MAC filter for 'addr' directing matching traffic to + * 'queue', 'flags' is used to indicate what kind of match need to be + * removed, match is by default for the destination address, if + * matching by source address is to be removed the flag + * IGC_MAC_STATE_SRC_ADDR can be used. + */ +static int igc_del_mac_filter(struct igc_adapter *adapter, + const u8 *addr, const u8 queue) +{ + struct igc_hw *hw = &adapter->hw; + int rar_entries = hw->mac.rar_entry_count; + int i; + + if (is_zero_ether_addr(addr)) + return -EINVAL; + + /* Search for matching entry in the MAC table based on given address + * and queue. Do not touch entries at the end of the table reserved + * for the VF MAC addresses. + */ + for (i = 0; i < rar_entries; i++) { + if (!(adapter->mac_table[i].state & IGC_MAC_STATE_IN_USE)) + continue; + if (adapter->mac_table[i].state != 0) + continue; + if (adapter->mac_table[i].queue != queue) + continue; + if (!ether_addr_equal(adapter->mac_table[i].addr, addr)) + continue; + + /* When a filter for the default address is "deleted", + * we return it to its initial configuration + */ + if (adapter->mac_table[i].state & IGC_MAC_STATE_DEFAULT) { + adapter->mac_table[i].state = + IGC_MAC_STATE_DEFAULT | IGC_MAC_STATE_IN_USE; + adapter->mac_table[i].queue = 0; + } else { + adapter->mac_table[i].state = 0; + adapter->mac_table[i].queue = 0; + memset(adapter->mac_table[i].addr, 0, ETH_ALEN); + } + + igc_rar_set_index(adapter, i); + return 0; + } + + return -ENOENT; +} + +static int igc_uc_sync(struct net_device *netdev, const unsigned char *addr) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + int ret; + + ret = igc_add_mac_filter(adapter, addr, adapter->num_rx_queues); + + return min_t(int, ret, 0); +} + +static int igc_uc_unsync(struct net_device *netdev, const unsigned char *addr) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + + igc_del_mac_filter(adapter, addr, adapter->num_rx_queues); + + return 0; +} + /** * igc_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set * @netdev: network interface device structure @@ -2529,6 +2713,44 @@ int igc_del_mac_steering_filter(struct igc_adapter *adapter, */ static void igc_set_rx_mode(struct net_device *netdev) { + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; + u32 rctl = 0, rlpml = MAX_JUMBO_FRAME_SIZE; + int count; + + /* Check for Promiscuous and All Multicast modes */ + if (netdev->flags & IFF_PROMISC) { + rctl |= IGC_RCTL_UPE | IGC_RCTL_MPE; + } else { + if (netdev->flags & IFF_ALLMULTI) { + rctl |= IGC_RCTL_MPE; + } else { + /* Write addresses to the MTA, if the attempt fails + * then we should just turn on promiscuous mode so + * that we can at least receive multicast traffic + */ + count = igc_write_mc_addr_list(netdev); + if (count < 0) + rctl |= IGC_RCTL_MPE; + } + } + + /* Write addresses to available RAR registers, if there is not + * sufficient space to store all the addresses then enable + * unicast promiscuous mode + */ + if (__dev_uc_sync(netdev, igc_uc_sync, igc_uc_unsync)) + rctl |= IGC_RCTL_UPE; + + /* update state of unicast and multicast */ + rctl |= rd32(IGC_RCTL) & ~(IGC_RCTL_UPE | IGC_RCTL_MPE); + wr32(IGC_RCTL, rctl); + +#if (PAGE_SIZE < 8192) + if (adapter->max_frame_size <= IGC_MAX_FRAME_BUILD_SKB) + rlpml = IGC_MAX_FRAME_BUILD_SKB; +#endif + wr32(IGC_RLPML, rlpml); } /** @@ -3982,6 +4204,7 @@ static const struct net_device_ops igc_netdev_ops = { .ndo_open = igc_open, .ndo_stop = igc_close, .ndo_start_xmit = igc_xmit_frame, + .ndo_set_rx_mode = igc_set_rx_mode, .ndo_set_mac_address = igc_set_mac, .ndo_change_mtu = igc_change_mtu, .ndo_get_stats = igc_get_stats, @@ -4210,7 +4433,9 @@ static int igc_probe(struct pci_dev *pdev, goto err_sw_init; /* Add supported features to the features list*/ + netdev->features |= NETIF_F_RXCSUM; netdev->features |= NETIF_F_HW_CSUM; + netdev->features |= NETIF_F_SCTP_CRC; /* setup the private structure */ err = igc_sw_init(adapter); @@ -4348,7 +4573,6 @@ static void igc_remove(struct pci_dev *pdev) pci_release_mem_regions(pdev); kfree(adapter->mac_table); - kfree(adapter->shadow_vfta); free_netdev(netdev); pci_disable_pcie_error_reporting(pdev); diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig index fb942167ee54..3d5caea096fb 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -61,6 +61,7 @@ config MVNETA depends on ARCH_MVEBU || COMPILE_TEST select MVMDIO select PHYLINK + select PAGE_POOL ---help--- This driver supports the network interface units in the Marvell ARMADA XP, ARMADA 370, ARMADA 38x and diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index e49820675c8c..8f9df6efda61 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -37,6 +37,8 @@ #include <net/ip.h> #include <net/ipv6.h> #include <net/tso.h> +#include <net/page_pool.h> +#include <linux/bpf_trace.h> /* Registers */ #define MVNETA_RXQ_CONFIG_REG(q) (0x1400 + ((q) << 2)) @@ -322,6 +324,13 @@ ETH_HLEN + ETH_FCS_LEN, \ cache_line_size()) +#define MVNETA_SKB_HEADROOM (max(XDP_PACKET_HEADROOM, NET_SKB_PAD) + \ + NET_IP_ALIGN) +#define MVNETA_SKB_PAD (SKB_DATA_ALIGN(sizeof(struct skb_shared_info) + \ + MVNETA_SKB_HEADROOM)) +#define MVNETA_SKB_SIZE(len) (SKB_DATA_ALIGN(len) + MVNETA_SKB_PAD) +#define MVNETA_MAX_RX_BUF_SIZE (PAGE_SIZE - MVNETA_SKB_PAD) + #define IS_TSO_HEADER(txq, addr) \ ((addr >= txq->tso_hdrs_phys) && \ (addr < txq->tso_hdrs_phys + txq->size * TSO_HEADER_SIZE)) @@ -346,6 +355,11 @@ struct mvneta_statistic { #define T_REG_64 64 #define T_SW 1 +#define MVNETA_XDP_PASS BIT(0) +#define MVNETA_XDP_DROPPED BIT(1) +#define MVNETA_XDP_TX BIT(2) +#define MVNETA_XDP_REDIR BIT(3) + static const struct mvneta_statistic mvneta_statistics[] = { { 0x3000, T_REG_64, "good_octets_received", }, { 0x3010, T_REG_32, "good_frames_received", }, @@ -425,6 +439,8 @@ struct mvneta_port { u32 cause_rx_tx; struct napi_struct napi; + struct bpf_prog *xdp_prog; + /* Core clock */ struct clk *clk; /* AXI clock */ @@ -545,6 +561,20 @@ struct mvneta_rx_desc { }; #endif +enum mvneta_tx_buf_type { + MVNETA_TYPE_SKB, + MVNETA_TYPE_XDP_TX, + MVNETA_TYPE_XDP_NDO, +}; + +struct mvneta_tx_buf { + enum mvneta_tx_buf_type type; + union { + struct xdp_frame *xdpf; + struct sk_buff *skb; + }; +}; + struct mvneta_tx_queue { /* Number of this TX queue, in the range 0-7 */ u8 id; @@ -560,8 +590,8 @@ struct mvneta_tx_queue { int tx_stop_threshold; int tx_wake_threshold; - /* Array of transmitted skb */ - struct sk_buff **tx_skb; + /* Array of transmitted buffers */ + struct mvneta_tx_buf *buf; /* Index of last TX DMA descriptor that was inserted */ int txq_put_index; @@ -603,6 +633,10 @@ struct mvneta_rx_queue { u32 pkts_coal; u32 time_coal; + /* page_pool */ + struct page_pool *page_pool; + struct xdp_rxq_info xdp_rxq; + /* Virtual address of the RX buffer */ void **buf_virt_addr; @@ -641,7 +675,6 @@ static int txq_number = 8; static int rxq_def; static int rx_copybreak __read_mostly = 256; -static int rx_header_size __read_mostly = 128; /* HW BM need that each port be identify by a unique ID */ static int global_port_id; @@ -1761,24 +1794,25 @@ static void mvneta_txq_bufs_free(struct mvneta_port *pp, int i; for (i = 0; i < num; i++) { + struct mvneta_tx_buf *buf = &txq->buf[txq->txq_get_index]; struct mvneta_tx_desc *tx_desc = txq->descs + txq->txq_get_index; - struct sk_buff *skb = txq->tx_skb[txq->txq_get_index]; - - if (skb) { - bytes_compl += skb->len; - pkts_compl++; - } mvneta_txq_inc_get(txq); - if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr)) + if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr) && + buf->type != MVNETA_TYPE_XDP_TX) dma_unmap_single(pp->dev->dev.parent, tx_desc->buf_phys_addr, tx_desc->data_size, DMA_TO_DEVICE); - if (!skb) - continue; - dev_kfree_skb_any(skb); + if (buf->type == MVNETA_TYPE_SKB && buf->skb) { + bytes_compl += buf->skb->len; + pkts_compl++; + dev_kfree_skb_any(buf->skb); + } else if (buf->type == MVNETA_TYPE_XDP_TX || + buf->type == MVNETA_TYPE_XDP_NDO) { + xdp_return_frame(buf->xdpf); + } } netdev_tx_completed_queue(nq, pkts_compl, bytes_compl); @@ -1812,23 +1846,21 @@ static int mvneta_rx_refill(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, gfp_t gfp_mask) { + enum dma_data_direction dma_dir; dma_addr_t phys_addr; struct page *page; - page = __dev_alloc_page(gfp_mask); + page = page_pool_alloc_pages(rxq->page_pool, + gfp_mask | __GFP_NOWARN); if (!page) return -ENOMEM; - /* map page for use */ - phys_addr = dma_map_page(pp->dev->dev.parent, page, 0, PAGE_SIZE, - DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(pp->dev->dev.parent, phys_addr))) { - __free_page(page); - return -ENOMEM; - } - - phys_addr += pp->rx_offset_correction; + phys_addr = page_pool_get_dma_addr(page) + pp->rx_offset_correction; + dma_dir = page_pool_get_dma_dir(rxq->page_pool); + dma_sync_single_for_device(pp->dev->dev.parent, phys_addr, + MVNETA_MAX_RX_BUF_SIZE, dma_dir); mvneta_rx_desc_fill(rx_desc, phys_addr, page, rxq); + return 0; } @@ -1894,10 +1926,29 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp, if (!data || !(rx_desc->buf_phys_addr)) continue; - dma_unmap_page(pp->dev->dev.parent, rx_desc->buf_phys_addr, - PAGE_SIZE, DMA_FROM_DEVICE); - __free_page(data); + page_pool_put_page(rxq->page_pool, data, false); + } + if (xdp_rxq_info_is_reg(&rxq->xdp_rxq)) + xdp_rxq_info_unreg(&rxq->xdp_rxq); + page_pool_destroy(rxq->page_pool); + rxq->page_pool = NULL; +} + +static void +mvneta_update_stats(struct mvneta_port *pp, u32 pkts, + u32 len, bool tx) +{ + struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); + + u64_stats_update_begin(&stats->syncp); + if (tx) { + stats->tx_packets += pkts; + stats->tx_bytes += len; + } else { + stats->rx_packets += pkts; + stats->rx_bytes += len; } + u64_stats_update_end(&stats->syncp); } static inline @@ -1925,43 +1976,292 @@ int mvneta_rx_refill_queue(struct mvneta_port *pp, struct mvneta_rx_queue *rxq) return i; } +static int +mvneta_xdp_submit_frame(struct mvneta_port *pp, struct mvneta_tx_queue *txq, + struct xdp_frame *xdpf, bool dma_map) +{ + struct mvneta_tx_desc *tx_desc; + struct mvneta_tx_buf *buf; + dma_addr_t dma_addr; + + if (txq->count >= txq->tx_stop_threshold) + return MVNETA_XDP_DROPPED; + + tx_desc = mvneta_txq_next_desc_get(txq); + + buf = &txq->buf[txq->txq_put_index]; + if (dma_map) { + /* ndo_xdp_xmit */ + dma_addr = dma_map_single(pp->dev->dev.parent, xdpf->data, + xdpf->len, DMA_TO_DEVICE); + if (dma_mapping_error(pp->dev->dev.parent, dma_addr)) { + mvneta_txq_desc_put(txq); + return MVNETA_XDP_DROPPED; + } + buf->type = MVNETA_TYPE_XDP_NDO; + } else { + struct page *page = virt_to_page(xdpf->data); + + dma_addr = page_pool_get_dma_addr(page) + + sizeof(*xdpf) + xdpf->headroom; + dma_sync_single_for_device(pp->dev->dev.parent, dma_addr, + xdpf->len, DMA_BIDIRECTIONAL); + buf->type = MVNETA_TYPE_XDP_TX; + } + buf->xdpf = xdpf; + + tx_desc->command = MVNETA_TXD_FLZ_DESC; + tx_desc->buf_phys_addr = dma_addr; + tx_desc->data_size = xdpf->len; + + mvneta_update_stats(pp, 1, xdpf->len, true); + mvneta_txq_inc_put(txq); + txq->pending++; + txq->count++; + + return MVNETA_XDP_TX; +} + +static int +mvneta_xdp_xmit_back(struct mvneta_port *pp, struct xdp_buff *xdp) +{ + struct mvneta_tx_queue *txq; + struct netdev_queue *nq; + struct xdp_frame *xdpf; + int cpu; + u32 ret; + + xdpf = convert_to_xdp_frame(xdp); + if (unlikely(!xdpf)) + return MVNETA_XDP_DROPPED; + + cpu = smp_processor_id(); + txq = &pp->txqs[cpu % txq_number]; + nq = netdev_get_tx_queue(pp->dev, txq->id); + + __netif_tx_lock(nq, cpu); + ret = mvneta_xdp_submit_frame(pp, txq, xdpf, false); + if (ret == MVNETA_XDP_TX) + mvneta_txq_pend_desc_add(pp, txq, 0); + __netif_tx_unlock(nq); + + return ret; +} + +static int +mvneta_xdp_xmit(struct net_device *dev, int num_frame, + struct xdp_frame **frames, u32 flags) +{ + struct mvneta_port *pp = netdev_priv(dev); + int cpu = smp_processor_id(); + struct mvneta_tx_queue *txq; + struct netdev_queue *nq; + int i, drops = 0; + u32 ret; + + if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) + return -EINVAL; + + txq = &pp->txqs[cpu % txq_number]; + nq = netdev_get_tx_queue(pp->dev, txq->id); + + __netif_tx_lock(nq, cpu); + for (i = 0; i < num_frame; i++) { + ret = mvneta_xdp_submit_frame(pp, txq, frames[i], true); + if (ret != MVNETA_XDP_TX) { + xdp_return_frame_rx_napi(frames[i]); + drops++; + } + } + + if (unlikely(flags & XDP_XMIT_FLUSH)) + mvneta_txq_pend_desc_add(pp, txq, 0); + __netif_tx_unlock(nq); + + return num_frame - drops; +} + +static int +mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, + struct bpf_prog *prog, struct xdp_buff *xdp) +{ + u32 ret, act = bpf_prog_run_xdp(prog, xdp); + + switch (act) { + case XDP_PASS: + ret = MVNETA_XDP_PASS; + break; + case XDP_REDIRECT: { + int err; + + err = xdp_do_redirect(pp->dev, xdp, prog); + if (err) { + ret = MVNETA_XDP_DROPPED; + xdp_return_buff(xdp); + } else { + ret = MVNETA_XDP_REDIR; + } + break; + } + case XDP_TX: + ret = mvneta_xdp_xmit_back(pp, xdp); + if (ret != MVNETA_XDP_TX) + xdp_return_buff(xdp); + break; + default: + bpf_warn_invalid_xdp_action(act); + /* fall through */ + case XDP_ABORTED: + trace_xdp_exception(pp->dev, prog, act); + /* fall through */ + case XDP_DROP: + page_pool_recycle_direct(rxq->page_pool, + virt_to_head_page(xdp->data)); + ret = MVNETA_XDP_DROPPED; + break; + } + + return ret; +} + +static int +mvneta_swbm_rx_frame(struct mvneta_port *pp, + struct mvneta_rx_desc *rx_desc, + struct mvneta_rx_queue *rxq, + struct xdp_buff *xdp, + struct bpf_prog *xdp_prog, + struct page *page, u32 *xdp_ret) +{ + unsigned char *data = page_address(page); + int data_len = -MVNETA_MH_SIZE, len; + struct net_device *dev = pp->dev; + enum dma_data_direction dma_dir; + + if (MVNETA_SKB_SIZE(rx_desc->data_size) > PAGE_SIZE) { + len = MVNETA_MAX_RX_BUF_SIZE; + data_len += len; + } else { + len = rx_desc->data_size; + data_len += len - ETH_FCS_LEN; + } + + dma_dir = page_pool_get_dma_dir(rxq->page_pool); + dma_sync_single_for_cpu(dev->dev.parent, + rx_desc->buf_phys_addr, + len, dma_dir); + + /* Prefetch header */ + prefetch(data); + + xdp->data_hard_start = data; + xdp->data = data + MVNETA_SKB_HEADROOM + MVNETA_MH_SIZE; + xdp->data_end = xdp->data + data_len; + xdp_set_data_meta_invalid(xdp); + + if (xdp_prog) { + u32 ret; + + ret = mvneta_run_xdp(pp, rxq, xdp_prog, xdp); + if (ret != MVNETA_XDP_PASS) { + mvneta_update_stats(pp, 1, + xdp->data_end - xdp->data, + false); + rx_desc->buf_phys_addr = 0; + *xdp_ret |= ret; + return ret; + } + } + + rxq->skb = build_skb(xdp->data_hard_start, PAGE_SIZE); + if (unlikely(!rxq->skb)) { + netdev_err(dev, + "Can't allocate skb on queue %d\n", + rxq->id); + dev->stats.rx_dropped++; + rxq->skb_alloc_err++; + return -ENOMEM; + } + page_pool_release_page(rxq->page_pool, page); + + skb_reserve(rxq->skb, + xdp->data - xdp->data_hard_start); + skb_put(rxq->skb, xdp->data_end - xdp->data); + mvneta_rx_csum(pp, rx_desc->status, rxq->skb); + + rxq->left_size = rx_desc->data_size - len; + rx_desc->buf_phys_addr = 0; + + return 0; +} + +static void +mvneta_swbm_add_rx_fragment(struct mvneta_port *pp, + struct mvneta_rx_desc *rx_desc, + struct mvneta_rx_queue *rxq, + struct page *page) +{ + struct net_device *dev = pp->dev; + enum dma_data_direction dma_dir; + int data_len, len; + + if (rxq->left_size > MVNETA_MAX_RX_BUF_SIZE) { + len = MVNETA_MAX_RX_BUF_SIZE; + data_len = len; + } else { + len = rxq->left_size; + data_len = len - ETH_FCS_LEN; + } + dma_dir = page_pool_get_dma_dir(rxq->page_pool); + dma_sync_single_for_cpu(dev->dev.parent, + rx_desc->buf_phys_addr, + len, dma_dir); + if (data_len > 0) { + /* refill descriptor with new buffer later */ + skb_add_rx_frag(rxq->skb, + skb_shinfo(rxq->skb)->nr_frags, + page, MVNETA_SKB_HEADROOM, data_len, + PAGE_SIZE); + } + page_pool_release_page(rxq->page_pool, page); + rx_desc->buf_phys_addr = 0; + rxq->left_size -= len; +} + /* Main rx processing when using software buffer management */ static int mvneta_rx_swbm(struct napi_struct *napi, struct mvneta_port *pp, int budget, struct mvneta_rx_queue *rxq) { + int rcvd_pkts = 0, rcvd_bytes = 0, rx_proc = 0; struct net_device *dev = pp->dev; - int rx_todo, rx_proc; - int refill = 0; - u32 rcvd_pkts = 0; - u32 rcvd_bytes = 0; + struct bpf_prog *xdp_prog; + struct xdp_buff xdp_buf; + int rx_todo, refill; + u32 xdp_ret = 0; /* Get number of received packets */ rx_todo = mvneta_rxq_busy_desc_num_get(pp, rxq); - rx_proc = 0; + + rcu_read_lock(); + xdp_prog = READ_ONCE(pp->xdp_prog); + xdp_buf.rxq = &rxq->xdp_rxq; /* Fairness NAPI loop */ - while ((rcvd_pkts < budget) && (rx_proc < rx_todo)) { + while (rx_proc < budget && rx_proc < rx_todo) { struct mvneta_rx_desc *rx_desc = mvneta_rxq_next_desc_get(rxq); - unsigned char *data; - struct page *page; - dma_addr_t phys_addr; u32 rx_status, index; - int rx_bytes, skb_size, copy_size; - int frag_num, frag_size, frag_offset; + struct page *page; index = rx_desc - rxq->descs; page = (struct page *)rxq->buf_virt_addr[index]; - data = page_address(page); - /* Prefetch header */ - prefetch(data); - phys_addr = rx_desc->buf_phys_addr; rx_status = rx_desc->status; rx_proc++; rxq->refill_num++; if (rx_status & MVNETA_RXD_FIRST_DESC) { + int err; + /* Check errors only for FIRST descriptor */ if (rx_status & MVNETA_RXD_ERR_SUMMARY) { mvneta_rx_error(pp, rx_desc); @@ -1969,85 +2269,18 @@ static int mvneta_rx_swbm(struct napi_struct *napi, /* leave the descriptor untouched */ continue; } - rx_bytes = rx_desc->data_size - - (ETH_FCS_LEN + MVNETA_MH_SIZE); - /* Allocate small skb for each new packet */ - skb_size = max(rx_copybreak, rx_header_size); - rxq->skb = netdev_alloc_skb_ip_align(dev, skb_size); - if (unlikely(!rxq->skb)) { - netdev_err(dev, - "Can't allocate skb on queue %d\n", - rxq->id); - dev->stats.rx_dropped++; - rxq->skb_alloc_err++; + err = mvneta_swbm_rx_frame(pp, rx_desc, rxq, &xdp_buf, + xdp_prog, page, &xdp_ret); + if (err) continue; - } - copy_size = min(skb_size, rx_bytes); - - /* Copy data from buffer to SKB, skip Marvell header */ - memcpy(rxq->skb->data, data + MVNETA_MH_SIZE, - copy_size); - skb_put(rxq->skb, copy_size); - rxq->left_size = rx_bytes - copy_size; - - mvneta_rx_csum(pp, rx_status, rxq->skb); - if (rxq->left_size == 0) { - int size = copy_size + MVNETA_MH_SIZE; - - dma_sync_single_range_for_cpu(dev->dev.parent, - phys_addr, 0, - size, - DMA_FROM_DEVICE); - - /* leave the descriptor and buffer untouched */ - } else { - /* refill descriptor with new buffer later */ - rx_desc->buf_phys_addr = 0; - - frag_num = 0; - frag_offset = copy_size + MVNETA_MH_SIZE; - frag_size = min(rxq->left_size, - (int)(PAGE_SIZE - frag_offset)); - skb_add_rx_frag(rxq->skb, frag_num, page, - frag_offset, frag_size, - PAGE_SIZE); - dma_unmap_page(dev->dev.parent, phys_addr, - PAGE_SIZE, DMA_FROM_DEVICE); - rxq->left_size -= frag_size; - } } else { - /* Middle or Last descriptor */ if (unlikely(!rxq->skb)) { pr_debug("no skb for rx_status 0x%x\n", rx_status); continue; } - if (!rxq->left_size) { - /* last descriptor has only FCS */ - /* and can be discarded */ - dma_sync_single_range_for_cpu(dev->dev.parent, - phys_addr, 0, - ETH_FCS_LEN, - DMA_FROM_DEVICE); - /* leave the descriptor and buffer untouched */ - } else { - /* refill descriptor with new buffer later */ - rx_desc->buf_phys_addr = 0; - - frag_num = skb_shinfo(rxq->skb)->nr_frags; - frag_offset = 0; - frag_size = min(rxq->left_size, - (int)(PAGE_SIZE - frag_offset)); - skb_add_rx_frag(rxq->skb, frag_num, page, - frag_offset, frag_size, - PAGE_SIZE); - - dma_unmap_page(dev->dev.parent, phys_addr, - PAGE_SIZE, DMA_FROM_DEVICE); - - rxq->left_size -= frag_size; - } + mvneta_swbm_add_rx_fragment(pp, rx_desc, rxq, page); } /* Middle or Last descriptor */ if (!(rx_status & MVNETA_RXD_LAST_DESC)) @@ -2072,17 +2305,14 @@ static int mvneta_rx_swbm(struct napi_struct *napi, /* clean uncomplete skb pointer in queue */ rxq->skb = NULL; - rxq->left_size = 0; } + rcu_read_unlock(); - if (rcvd_pkts) { - struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); + if (xdp_ret & MVNETA_XDP_REDIR) + xdp_do_flush_map(); - u64_stats_update_begin(&stats->syncp); - stats->rx_packets += rcvd_pkts; - stats->rx_bytes += rcvd_bytes; - u64_stats_update_end(&stats->syncp); - } + if (rcvd_pkts) + mvneta_update_stats(pp, rcvd_pkts, rcvd_bytes, false); /* return some buffers to hardware queue, one at a time is too slow */ refill = mvneta_rx_refill_queue(pp, rxq); @@ -2206,14 +2436,8 @@ err_drop_frame: napi_gro_receive(napi, skb); } - if (rcvd_pkts) { - struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); - - u64_stats_update_begin(&stats->syncp); - stats->rx_packets += rcvd_pkts; - stats->rx_bytes += rcvd_bytes; - u64_stats_update_end(&stats->syncp); - } + if (rcvd_pkts) + mvneta_update_stats(pp, rcvd_pkts, rcvd_bytes, false); /* Update rxq management counters */ mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_done); @@ -2225,16 +2449,19 @@ static inline void mvneta_tso_put_hdr(struct sk_buff *skb, struct mvneta_port *pp, struct mvneta_tx_queue *txq) { - struct mvneta_tx_desc *tx_desc; int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index]; + struct mvneta_tx_desc *tx_desc; - txq->tx_skb[txq->txq_put_index] = NULL; tx_desc = mvneta_txq_next_desc_get(txq); tx_desc->data_size = hdr_len; tx_desc->command = mvneta_skb_tx_csum(pp, skb); tx_desc->command |= MVNETA_TXD_F_DESC; tx_desc->buf_phys_addr = txq->tso_hdrs_phys + txq->txq_put_index * TSO_HEADER_SIZE; + buf->type = MVNETA_TYPE_SKB; + buf->skb = NULL; + mvneta_txq_inc_put(txq); } @@ -2243,6 +2470,7 @@ mvneta_tso_put_data(struct net_device *dev, struct mvneta_tx_queue *txq, struct sk_buff *skb, char *data, int size, bool last_tcp, bool is_last) { + struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index]; struct mvneta_tx_desc *tx_desc; tx_desc = mvneta_txq_next_desc_get(txq); @@ -2256,7 +2484,8 @@ mvneta_tso_put_data(struct net_device *dev, struct mvneta_tx_queue *txq, } tx_desc->command = 0; - txq->tx_skb[txq->txq_put_index] = NULL; + buf->type = MVNETA_TYPE_SKB; + buf->skb = NULL; if (last_tcp) { /* last descriptor in the TCP packet */ @@ -2264,7 +2493,7 @@ mvneta_tso_put_data(struct net_device *dev, struct mvneta_tx_queue *txq, /* last descriptor in SKB */ if (is_last) - txq->tx_skb[txq->txq_put_index] = skb; + buf->skb = skb; } mvneta_txq_inc_put(txq); return 0; @@ -2349,6 +2578,7 @@ static int mvneta_tx_frag_process(struct mvneta_port *pp, struct sk_buff *skb, int i, nr_frags = skb_shinfo(skb)->nr_frags; for (i = 0; i < nr_frags; i++) { + struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index]; skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; void *addr = skb_frag_address(frag); @@ -2368,12 +2598,13 @@ static int mvneta_tx_frag_process(struct mvneta_port *pp, struct sk_buff *skb, if (i == nr_frags - 1) { /* Last descriptor */ tx_desc->command = MVNETA_TXD_L_DESC | MVNETA_TXD_Z_PAD; - txq->tx_skb[txq->txq_put_index] = skb; + buf->skb = skb; } else { /* Descriptor in the middle: Not First, Not Last */ tx_desc->command = 0; - txq->tx_skb[txq->txq_put_index] = NULL; + buf->skb = NULL; } + buf->type = MVNETA_TYPE_SKB; mvneta_txq_inc_put(txq); } @@ -2401,6 +2632,7 @@ static netdev_tx_t mvneta_tx(struct sk_buff *skb, struct net_device *dev) struct mvneta_port *pp = netdev_priv(dev); u16 txq_id = skb_get_queue_mapping(skb); struct mvneta_tx_queue *txq = &pp->txqs[txq_id]; + struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index]; struct mvneta_tx_desc *tx_desc; int len = skb->len; int frags = 0; @@ -2433,16 +2665,17 @@ static netdev_tx_t mvneta_tx(struct sk_buff *skb, struct net_device *dev) goto out; } + buf->type = MVNETA_TYPE_SKB; if (frags == 1) { /* First and Last descriptor */ tx_cmd |= MVNETA_TXD_FLZ_DESC; tx_desc->command = tx_cmd; - txq->tx_skb[txq->txq_put_index] = skb; + buf->skb = skb; mvneta_txq_inc_put(txq); } else { /* First but not Last */ tx_cmd |= MVNETA_TXD_F_DESC; - txq->tx_skb[txq->txq_put_index] = NULL; + buf->skb = NULL; mvneta_txq_inc_put(txq); tx_desc->command = tx_cmd; /* Continue with other skb fragments */ @@ -2459,7 +2692,6 @@ static netdev_tx_t mvneta_tx(struct sk_buff *skb, struct net_device *dev) out: if (frags > 0) { - struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); struct netdev_queue *nq = netdev_get_tx_queue(dev, txq_id); netdev_tx_sent_queue(nq, len); @@ -2474,10 +2706,7 @@ out: else txq->pending += frags; - u64_stats_update_begin(&stats->syncp); - stats->tx_packets++; - stats->tx_bytes += len; - u64_stats_update_end(&stats->syncp); + mvneta_update_stats(pp, 1, len, true); } else { dev->stats.tx_dropped++; dev_kfree_skb_any(skb); @@ -2830,11 +3059,55 @@ static int mvneta_poll(struct napi_struct *napi, int budget) return rx_done; } +static int mvneta_create_page_pool(struct mvneta_port *pp, + struct mvneta_rx_queue *rxq, int size) +{ + struct bpf_prog *xdp_prog = READ_ONCE(pp->xdp_prog); + struct page_pool_params pp_params = { + .order = 0, + .flags = PP_FLAG_DMA_MAP, + .pool_size = size, + .nid = cpu_to_node(0), + .dev = pp->dev->dev.parent, + .dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE, + }; + int err; + + rxq->page_pool = page_pool_create(&pp_params); + if (IS_ERR(rxq->page_pool)) { + err = PTR_ERR(rxq->page_pool); + rxq->page_pool = NULL; + return err; + } + + err = xdp_rxq_info_reg(&rxq->xdp_rxq, pp->dev, rxq->id); + if (err < 0) + goto err_free_pp; + + err = xdp_rxq_info_reg_mem_model(&rxq->xdp_rxq, MEM_TYPE_PAGE_POOL, + rxq->page_pool); + if (err) + goto err_unregister_rxq; + + return 0; + +err_unregister_rxq: + xdp_rxq_info_unreg(&rxq->xdp_rxq); +err_free_pp: + page_pool_destroy(rxq->page_pool); + rxq->page_pool = NULL; + return err; +} + /* Handle rxq fill: allocates rxq skbs; called when initializing a port */ static int mvneta_rxq_fill(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, int num) { - int i; + int i, err; + + err = mvneta_create_page_pool(pp, rxq, num); + if (err < 0) + return err; for (i = 0; i < num; i++) { memset(rxq->descs + i, 0, sizeof(struct mvneta_rx_desc)); @@ -2908,7 +3181,7 @@ static void mvneta_rxq_hw_init(struct mvneta_port *pp, /* Set Offset */ mvneta_rxq_offset_set(pp, rxq, 0); mvneta_rxq_buf_size_set(pp, rxq, PAGE_SIZE < SZ_64K ? - PAGE_SIZE : + MVNETA_MAX_RX_BUF_SIZE : MVNETA_RX_BUF_SIZE(pp->pkt_size)); mvneta_rxq_bm_disable(pp, rxq); mvneta_rxq_fill(pp, rxq, rxq->size); @@ -2989,9 +3262,8 @@ static int mvneta_txq_sw_init(struct mvneta_port *pp, txq->last_desc = txq->size - 1; - txq->tx_skb = kmalloc_array(txq->size, sizeof(*txq->tx_skb), - GFP_KERNEL); - if (!txq->tx_skb) { + txq->buf = kmalloc_array(txq->size, sizeof(*txq->buf), GFP_KERNEL); + if (!txq->buf) { dma_free_coherent(pp->dev->dev.parent, txq->size * MVNETA_DESC_ALIGNED_SIZE, txq->descs, txq->descs_phys); @@ -3003,7 +3275,7 @@ static int mvneta_txq_sw_init(struct mvneta_port *pp, txq->size * TSO_HEADER_SIZE, &txq->tso_hdrs_phys, GFP_KERNEL); if (!txq->tso_hdrs) { - kfree(txq->tx_skb); + kfree(txq->buf); dma_free_coherent(pp->dev->dev.parent, txq->size * MVNETA_DESC_ALIGNED_SIZE, txq->descs, txq->descs_phys); @@ -3056,7 +3328,7 @@ static void mvneta_txq_sw_deinit(struct mvneta_port *pp, { struct netdev_queue *nq = netdev_get_tx_queue(pp->dev, txq->id); - kfree(txq->tx_skb); + kfree(txq->buf); if (txq->tso_hdrs) dma_free_coherent(pp->dev->dev.parent, @@ -3263,6 +3535,11 @@ static int mvneta_change_mtu(struct net_device *dev, int mtu) mtu = ALIGN(MVNETA_RX_PKT_SIZE(mtu), 8); } + if (pp->xdp_prog && mtu > MVNETA_MAX_RX_BUF_SIZE) { + netdev_info(dev, "Illegal MTU value %d for XDP mode\n", mtu); + return -EINVAL; + } + dev->mtu = mtu; if (!netif_running(dev)) { @@ -3932,6 +4209,47 @@ static int mvneta_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return phylink_mii_ioctl(pp->phylink, ifr, cmd); } +static int mvneta_xdp_setup(struct net_device *dev, struct bpf_prog *prog, + struct netlink_ext_ack *extack) +{ + bool need_update, running = netif_running(dev); + struct mvneta_port *pp = netdev_priv(dev); + struct bpf_prog *old_prog; + + if (prog && dev->mtu > MVNETA_MAX_RX_BUF_SIZE) { + NL_SET_ERR_MSG_MOD(extack, "Jumbo frames not supported on XDP"); + return -EOPNOTSUPP; + } + + need_update = !!pp->xdp_prog != !!prog; + if (running && need_update) + mvneta_stop(dev); + + old_prog = xchg(&pp->xdp_prog, prog); + if (old_prog) + bpf_prog_put(old_prog); + + if (running && need_update) + return mvneta_open(dev); + + return 0; +} + +static int mvneta_xdp(struct net_device *dev, struct netdev_bpf *xdp) +{ + struct mvneta_port *pp = netdev_priv(dev); + + switch (xdp->command) { + case XDP_SETUP_PROG: + return mvneta_xdp_setup(dev, xdp->prog, xdp->extack); + case XDP_QUERY_PROG: + xdp->prog_id = pp->xdp_prog ? pp->xdp_prog->aux->id : 0; + return 0; + default: + return -EINVAL; + } +} + /* Ethtool methods */ /* Set link ksettings (phy address, speed) for ethtools */ @@ -4328,6 +4646,8 @@ static const struct net_device_ops mvneta_netdev_ops = { .ndo_fix_features = mvneta_fix_features, .ndo_get_stats64 = mvneta_get_stats64, .ndo_do_ioctl = mvneta_ioctl, + .ndo_bpf = mvneta_xdp, + .ndo_xdp_xmit = mvneta_xdp_xmit, }; static const struct ethtool_ops mvneta_eth_tool_ops = { @@ -4618,7 +4938,7 @@ static int mvneta_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); pp->id = global_port_id++; - pp->rx_offset_correction = 0; /* not relevant for SW BM */ + pp->rx_offset_correction = MVNETA_SKB_HEADROOM; /* Obtain access to BM resources if enabled and already initialized */ bm_node = of_parse_phandle(dn, "buffer-manager", 0); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index c61069340f4f..703adb96429e 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -261,6 +261,7 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, ge_mode = 0; switch (state->interface) { case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_GMII: ge_mode = 1; break; case PHY_INTERFACE_MODE_REVMII: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mr.c b/drivers/net/ethernet/mellanox/mlx5/core/mr.c index 9231b39d18b2..c501bf2a0252 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mr.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/mr.c @@ -112,17 +112,11 @@ int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, u32 out[MLX5_ST_SZ_DW(destroy_mkey_out)] = {0}; u32 in[MLX5_ST_SZ_DW(destroy_mkey_in)] = {0}; struct xarray *mkeys = &dev->priv.mkey_table; - struct mlx5_core_mkey *deleted_mkey; unsigned long flags; xa_lock_irqsave(mkeys, flags); - deleted_mkey = __xa_erase(mkeys, mlx5_base_mkey(mkey->key)); + __xa_erase(mkeys, mlx5_base_mkey(mkey->key)); xa_unlock_irqrestore(mkeys, flags); - if (!deleted_mkey) { - mlx5_core_dbg(dev, "failed xarray delete of mkey 0x%x\n", - mlx5_base_mkey(mkey->key)); - return -ENOENT; - } MLX5_SET(destroy_mkey_in, in, opcode, MLX5_CMD_OP_DESTROY_MKEY); MLX5_SET(destroy_mkey_in, in, mkey_index, mlx5_mkey_to_idx(mkey->key)); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c index 4187f2b112b8..e8b656075c6f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c @@ -788,12 +788,10 @@ again: * it means that all the previous stes are the same, * if so, this rule is duplicated. */ - if (mlx5dr_ste_is_last_in_rule(nic_matcher, - matched_ste->ste_chain_location)) { - mlx5dr_info(dmn, "Duplicate rule inserted, aborting!!\n"); - return NULL; - } - return matched_ste; + if (!mlx5dr_ste_is_last_in_rule(nic_matcher, ste_location)) + return matched_ste; + + mlx5dr_dbg(dmn, "Duplicate rule inserted\n"); } if (!skip_rehash && dr_rule_need_enlarge_hash(cur_htbl, dmn, nic_dmn)) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c index d2c7ce67c300..08215fed193d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c @@ -50,6 +50,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE]; char mcia_pl[MLXSW_REG_MCIA_LEN]; u16 i2c_addr; + u8 page = 0; int status; int err; @@ -62,11 +63,21 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW; if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) { - i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH; - offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH; + page = MLXSW_REG_MCIA_PAGE_GET(offset); + offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page; + /* When reading upper pages 1, 2 and 3 the offset starts at + * 128. Please refer to "QSFP+ Memory Map" figure in SFF-8436 + * specification for graphical depiction. + * MCIA register accepts buffer size <= 48. Page of size 128 + * should be read by chunks of size 48, 48, 32. Align the size + * of the last chunk to avoid reading after the end of the + * page. + */ + if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) + size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset; } - mlxsw_reg_mcia_pack(mcia_pl, module, 0, 0, offset, size, i2c_addr); + mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, offset, size, i2c_addr); err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); if (err) @@ -168,7 +179,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, switch (module_id) { case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: modinfo->type = ETH_MODULE_SFF_8436; - modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; + modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; break; case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: @@ -176,10 +187,10 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, module_rev_id >= MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) { modinfo->type = ETH_MODULE_SFF_8636; - modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; + modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; } else { modinfo->type = ETH_MODULE_SFF_8436; - modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; + modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; } break; case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 7b538e698a3d..adb63a266fc7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -4111,6 +4111,7 @@ MLXSW_ITEM32(reg, ptys, an_status, 0x04, 28, 4); #define MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4 BIT(9) #define MLXSW_REG_PTYS_EXT_ETH_SPEED_100GAUI_2_100GBASE_CR2_KR2 BIT(10) #define MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4 BIT(12) +#define MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8 BIT(15) /* reg_ptys_ext_eth_proto_cap * Extended Ethernet port supported speeds and protocols. @@ -8411,6 +8412,7 @@ MLXSW_ITEM32(reg, mcia, device_address, 0x04, 0, 16); MLXSW_ITEM32(reg, mcia, size, 0x08, 0, 16); #define MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH 256 +#define MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH 128 #define MLXSW_REG_MCIA_EEPROM_SIZE 48 #define MLXSW_REG_MCIA_I2C_ADDR_LOW 0x50 #define MLXSW_REG_MCIA_I2C_ADDR_HIGH 0x51 @@ -8446,6 +8448,14 @@ enum mlxsw_reg_mcia_eeprom_module_info { */ MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE); +/* This is used to access the optional upper pages (1-3) in the QSFP+ + * memory map. Page 1 is available on offset 256 through 383, page 2 - + * on offset 384 through 511, page 3 - on offset 512 through 639. + */ +#define MLXSW_REG_MCIA_PAGE_GET(off) (((off) - \ + MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) / \ + MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH + 1) + static inline void mlxsw_reg_mcia_pack(char *payload, u8 module, u8 lock, u8 page_number, u16 device_addr, u8 size, u8 i2c_device_addr) diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h index 33a9fc9ef6a4..85f919fe851b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/resources.h +++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h @@ -26,7 +26,7 @@ enum mlxsw_res_id { MLXSW_RES_ID_MAX_LAG_MEMBERS, MLXSW_RES_ID_LOCAL_PORTS_IN_1X, MLXSW_RES_ID_LOCAL_PORTS_IN_2X, - MLXSW_RES_ID_MAX_BUFFER_SIZE, + MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER, MLXSW_RES_ID_CELL_SIZE, MLXSW_RES_ID_MAX_HEADROOM_SIZE, MLXSW_RES_ID_ACL_MAX_TCAM_REGIONS, @@ -82,7 +82,7 @@ static u16 mlxsw_res_ids[] = { [MLXSW_RES_ID_MAX_LAG_MEMBERS] = 0x2521, [MLXSW_RES_ID_LOCAL_PORTS_IN_1X] = 0x2610, [MLXSW_RES_ID_LOCAL_PORTS_IN_2X] = 0x2611, - [MLXSW_RES_ID_MAX_BUFFER_SIZE] = 0x2802, /* Bytes */ + [MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER] = 0x2805, /* Bytes */ [MLXSW_RES_ID_CELL_SIZE] = 0x2803, /* Bytes */ [MLXSW_RES_ID_MAX_HEADROOM_SIZE] = 0x2811, /* Bytes */ [MLXSW_RES_ID_ACL_MAX_TCAM_REGIONS] = 0x2901, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 3c5154e559b2..1275d21e8fbd 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2912,9 +2912,22 @@ mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4[] = { #define MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN \ ARRAY_SIZE(mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4) +static const enum ethtool_link_mode_bit_indices +mlxsw_sp2_mask_ethtool_400gaui_8[] = { + ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT, +}; + +#define MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN \ + ARRAY_SIZE(mlxsw_sp2_mask_ethtool_400gaui_8) + #define MLXSW_SP_PORT_MASK_WIDTH_1X BIT(0) #define MLXSW_SP_PORT_MASK_WIDTH_2X BIT(1) #define MLXSW_SP_PORT_MASK_WIDTH_4X BIT(2) +#define MLXSW_SP_PORT_MASK_WIDTH_8X BIT(3) static u8 mlxsw_sp_port_mask_width_get(u8 width) { @@ -2925,6 +2938,8 @@ static u8 mlxsw_sp_port_mask_width_get(u8 width) return MLXSW_SP_PORT_MASK_WIDTH_2X; case 4: return MLXSW_SP_PORT_MASK_WIDTH_4X; + case 8: + return MLXSW_SP_PORT_MASK_WIDTH_8X; default: WARN_ON_ONCE(1); return 0; @@ -2946,7 +2961,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_100, }, { @@ -2955,7 +2971,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_1000, }, { @@ -2964,7 +2981,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_2_5GBASE_X_2_5GMII_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_2500, }, { @@ -2973,7 +2991,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_5000, }, { @@ -2982,14 +3001,16 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_10000, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_XLAUI_4_XLPPI_4_40G, .mask_ethtool = mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X, + .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_40000, }, { @@ -2998,7 +3019,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_25000, }, { @@ -3006,7 +3028,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .mask_ethtool = mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_50000, }, { @@ -3020,7 +3043,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4, .mask_ethtool = mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X, + .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_100000, }, { @@ -3034,9 +3058,17 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4, .mask_ethtool = mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X, + .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_200000, }, + { + .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8, + .mask_ethtool = mlxsw_sp2_mask_ethtool_400gaui_8, + .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN, + .mask_width = MLXSW_SP_PORT_MASK_WIDTH_8X, + .speed = SPEED_400000, + }, }; #define MLXSW_SP2_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp2_port_link_mode) @@ -5170,14 +5202,61 @@ static int mlxsw_sp2_resources_kvd_register(struct mlxsw_core *mlxsw_core) &kvd_size_params); } +static int mlxsw_sp_resources_span_register(struct mlxsw_core *mlxsw_core) +{ + struct devlink *devlink = priv_to_devlink(mlxsw_core); + struct devlink_resource_size_params span_size_params; + u32 max_span; + + if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SPAN)) + return -EIO; + + max_span = MLXSW_CORE_RES_GET(mlxsw_core, MAX_SPAN); + devlink_resource_size_params_init(&span_size_params, max_span, max_span, + 1, DEVLINK_RESOURCE_UNIT_ENTRY); + + return devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_SPAN, + max_span, MLXSW_SP_RESOURCE_SPAN, + DEVLINK_RESOURCE_ID_PARENT_TOP, + &span_size_params); +} + static int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core) { - return mlxsw_sp1_resources_kvd_register(mlxsw_core); + int err; + + err = mlxsw_sp1_resources_kvd_register(mlxsw_core); + if (err) + return err; + + err = mlxsw_sp_resources_span_register(mlxsw_core); + if (err) + goto err_resources_span_register; + + return 0; + +err_resources_span_register: + devlink_resources_unregister(priv_to_devlink(mlxsw_core), NULL); + return err; } static int mlxsw_sp2_resources_register(struct mlxsw_core *mlxsw_core) { - return mlxsw_sp2_resources_kvd_register(mlxsw_core); + int err; + + err = mlxsw_sp2_resources_kvd_register(mlxsw_core); + if (err) + return err; + + err = mlxsw_sp_resources_span_register(mlxsw_core); + if (err) + goto err_resources_span_register; + + return 0; + +err_resources_span_register: + devlink_resources_unregister(priv_to_devlink(mlxsw_core), NULL); + return err; } static int mlxsw_sp_kvd_sizes_get(struct mlxsw_core *mlxsw_core, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 8f99d70d6b8b..a5fdd84b4ca7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -48,6 +48,8 @@ #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_CHUNKS "chunks" #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_LARGE_CHUNKS "large_chunks" +#define MLXSW_SP_RESOURCE_NAME_SPAN "span_agents" + enum mlxsw_sp_resource_id { MLXSW_SP_RESOURCE_KVD = 1, MLXSW_SP_RESOURCE_KVD_LINEAR, @@ -56,6 +58,7 @@ enum mlxsw_sp_resource_id { MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE, MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS, MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS, + MLXSW_SP_RESOURCE_SPAN, }; struct mlxsw_sp_port; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index b9eeae37a4dc..5fd9a72c8471 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -35,6 +35,7 @@ struct mlxsw_sp_sb_cm { }; #define MLXSW_SP_SB_INFI -1U +#define MLXSW_SP_SB_REST -2U struct mlxsw_sp_sb_pm { u32 min_buff; @@ -421,19 +422,16 @@ static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp) .freeze_size = _freeze_size, \ } -#define MLXSW_SP1_SB_PR_INGRESS_SIZE 12440000 -#define MLXSW_SP1_SB_PR_EGRESS_SIZE 13232000 #define MLXSW_SP1_SB_PR_CPU_SIZE (256 * 1000) /* Order according to mlxsw_sp1_sb_pool_dess */ static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = { - MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, - MLXSW_SP1_SB_PR_INGRESS_SIZE), + MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), - MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, - MLXSW_SP1_SB_PR_EGRESS_SIZE, true, false), + MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST, + true, false), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), @@ -445,19 +443,16 @@ static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = { MLXSW_SP1_SB_PR_CPU_SIZE, true, false), }; -#define MLXSW_SP2_SB_PR_INGRESS_SIZE 35297568 -#define MLXSW_SP2_SB_PR_EGRESS_SIZE 35297568 #define MLXSW_SP2_SB_PR_CPU_SIZE (256 * 1000) /* Order according to mlxsw_sp2_sb_pool_dess */ static const struct mlxsw_sp_sb_pr mlxsw_sp2_sb_prs[] = { - MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, - MLXSW_SP2_SB_PR_INGRESS_SIZE), + MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), - MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, - MLXSW_SP2_SB_PR_EGRESS_SIZE, true, false), + MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST, + true, false), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), @@ -471,11 +466,33 @@ static const struct mlxsw_sp_sb_pr mlxsw_sp2_sb_prs[] = { static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_sb_pr *prs, + const struct mlxsw_sp_sb_pool_des *pool_dess, size_t prs_len) { + /* Round down, unlike mlxsw_sp_bytes_cells(). */ + u32 sb_cells = mlxsw_sp->sb->sb_size / mlxsw_sp->sb->cell_size; + u32 rest_cells[2] = {sb_cells, sb_cells}; int i; int err; + /* Calculate how much space to give to the "REST" pools in either + * direction. + */ + for (i = 0; i < prs_len; i++) { + enum mlxsw_reg_sbxx_dir dir = pool_dess[i].dir; + u32 size = prs[i].size; + u32 size_cells; + + if (size == MLXSW_SP_SB_INFI || size == MLXSW_SP_SB_REST) + continue; + + size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size); + if (WARN_ON_ONCE(size_cells > rest_cells[dir])) + continue; + + rest_cells[dir] -= size_cells; + } + for (i = 0; i < prs_len; i++) { u32 size = prs[i].size; u32 size_cells; @@ -483,6 +500,10 @@ static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, if (size == MLXSW_SP_SB_INFI) { err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, 0, true); + } else if (size == MLXSW_SP_SB_REST) { + size_cells = rest_cells[pool_dess[i].dir]; + err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, + size_cells, false); } else { size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size); err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, @@ -904,7 +925,7 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, CELL_SIZE)) return -EIO; - if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_BUFFER_SIZE)) + if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, GUARANTEED_SHARED_BUFFER)) return -EIO; if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_HEADROOM_SIZE)) @@ -915,7 +936,7 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) return -ENOMEM; mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE); mlxsw_sp->sb->sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, - MAX_BUFFER_SIZE); + GUARANTEED_SHARED_BUFFER); max_headroom_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_HEADROOM_SIZE); /* Round down, because this limit must not be overstepped. */ @@ -926,6 +947,7 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) if (err) goto err_sb_ports_init; err = mlxsw_sp_sb_prs_init(mlxsw_sp, mlxsw_sp->sb_vals->prs, + mlxsw_sp->sb_vals->pool_dess, mlxsw_sp->sb_vals->pool_count); if (err) goto err_sb_prs_init; @@ -1013,7 +1035,8 @@ int mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core, mode = (enum mlxsw_reg_sbpr_mode) threshold_type; pr = &mlxsw_sp->sb_vals->prs[pool_index]; - if (size > MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE)) { + if (size > MLXSW_CORE_RES_GET(mlxsw_sp->core, + GUARANTEED_SHARED_BUFFER)) { NL_SET_ERR_MSG_MOD(extack, "Exceeded shared buffer size"); return -EINVAL; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c index bdf53cf350f6..68cc6737d45c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c @@ -305,7 +305,8 @@ mlxsw_sp_qdisc_red_check_params(struct mlxsw_sp_port *mlxsw_sp_port, p->max); return -EINVAL; } - if (p->max > MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE)) { + if (p->max > MLXSW_CORE_RES_GET(mlxsw_sp->core, + GUARANTEED_SHARED_BUFFER)) { dev_err(mlxsw_sp->bus_info->dev, "spectrum: RED: max value %u is too big\n", p->max); return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c index 560a60e522f9..200d324e6d99 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c @@ -14,8 +14,23 @@ #include "spectrum_span.h" #include "spectrum_switchdev.h" +static u64 mlxsw_sp_span_occ_get(void *priv) +{ + const struct mlxsw_sp *mlxsw_sp = priv; + u64 occ = 0; + int i; + + for (i = 0; i < mlxsw_sp->span.entries_count; i++) { + if (mlxsw_sp->span.entries[i].ref_count) + occ++; + } + + return occ; +} + int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp) { + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); int i; if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_SPAN)) @@ -36,13 +51,19 @@ int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp) curr->id = i; } + devlink_resource_occ_get_register(devlink, MLXSW_SP_RESOURCE_SPAN, + mlxsw_sp_span_occ_get, mlxsw_sp); + return 0; } void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp) { + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); int i; + devlink_resource_occ_get_unregister(devlink, MLXSW_SP_RESOURCE_SPAN); + for (i = 0; i < mlxsw_sp->span.entries_count; i++) { struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c index 899450b28621..7c03b661ae7e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c @@ -99,6 +99,7 @@ static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port, devlink = priv_to_devlink(mlxsw_sp->core); in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, local_port); + skb_push(skb, ETH_HLEN); devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port); consume_skb(skb); } diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index 141571e2ec11..ebb81d6d4ca1 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -15,6 +15,7 @@ #include <linux/etherdevice.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_mdio.h> #include <linux/of_net.h> #include <linux/phy.h> #include <linux/platform_device.h> @@ -391,6 +392,7 @@ struct rx_status_t { struct netdata_local { struct platform_device *pdev; struct net_device *ndev; + struct device_node *phy_node; spinlock_t lock; void __iomem *net_base; u32 msg_enable; @@ -749,22 +751,26 @@ static void lpc_handle_link_change(struct net_device *ndev) static int lpc_mii_probe(struct net_device *ndev) { struct netdata_local *pldat = netdev_priv(ndev); - struct phy_device *phydev = phy_find_first(pldat->mii_bus); - - if (!phydev) { - netdev_err(ndev, "no PHY found\n"); - return -ENODEV; - } + struct phy_device *phydev; /* Attach to the PHY */ if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII) netdev_info(ndev, "using MII interface\n"); else netdev_info(ndev, "using RMII interface\n"); + + if (pldat->phy_node) + phydev = of_phy_find_device(pldat->phy_node); + else + phydev = phy_find_first(pldat->mii_bus); + if (!phydev) { + netdev_err(ndev, "no PHY found\n"); + return -ENODEV; + } + phydev = phy_connect(ndev, phydev_name(phydev), &lpc_handle_link_change, lpc_phy_interface_mode(&pldat->pdev->dev)); - if (IS_ERR(phydev)) { netdev_err(ndev, "Could not attach to PHY\n"); return PTR_ERR(phydev); @@ -783,6 +789,7 @@ static int lpc_mii_probe(struct net_device *ndev) static int lpc_mii_init(struct netdata_local *pldat) { + struct device_node *node; int err = -ENXIO; pldat->mii_bus = mdiobus_alloc(); @@ -812,7 +819,10 @@ static int lpc_mii_init(struct netdata_local *pldat) platform_set_drvdata(pldat->pdev, pldat->mii_bus); - if (mdiobus_register(pldat->mii_bus)) + node = of_get_child_by_name(pldat->pdev->dev.of_node, "mdio"); + err = of_mdiobus_register(pldat->mii_bus, node); + of_node_put(node); + if (err) goto err_out_unregister_bus; if (lpc_mii_probe(pldat->ndev) != 0) @@ -1345,6 +1355,8 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) netdev_dbg(ndev, "DMA buffer V address :0x%p\n", pldat->dma_buff_base_v); + pldat->phy_node = of_parse_phandle(np, "phy-handle", 0); + /* Get MAC address from current HW setting (POR state is all zeros) */ __lpc_get_mac(pldat, ndev->dev_addr); @@ -1356,9 +1368,6 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) if (!is_valid_ether_addr(ndev->dev_addr)) eth_hw_addr_random(ndev); - /* Reset the ethernet controller */ - __lpc_eth_reset(pldat); - /* then shut everything down to save power */ __lpc_eth_shutdown(pldat); diff --git a/drivers/net/ethernet/pensando/ionic/ionic.h b/drivers/net/ethernet/pensando/ionic/ionic.h index 7a7060677f15..98e102af7756 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic.h +++ b/drivers/net/ethernet/pensando/ionic/ionic.h @@ -12,7 +12,7 @@ struct ionic_lif; #define IONIC_DRV_NAME "ionic" #define IONIC_DRV_DESCRIPTION "Pensando Ethernet NIC Driver" -#define IONIC_DRV_VERSION "0.15.0-k" +#define IONIC_DRV_VERSION "0.18.0-k" #define PCI_VENDOR_ID_PENSANDO 0x1dd8 @@ -46,6 +46,8 @@ struct ionic { DECLARE_BITMAP(intrs, IONIC_INTR_CTRL_REGS_MAX); struct work_struct nb_work; struct notifier_block nb; + struct timer_list watchdog_timer; + int watchdog_period; }; struct ionic_admin_ctx { diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c index d168a6435322..5f9d2ec70446 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -11,6 +11,16 @@ #include "ionic_dev.h" #include "ionic_lif.h" +static void ionic_watchdog_cb(struct timer_list *t) +{ + struct ionic *ionic = from_timer(ionic, t, watchdog_timer); + + mod_timer(&ionic->watchdog_timer, + round_jiffies(jiffies + ionic->watchdog_period)); + + ionic_heartbeat_check(ionic); +} + void ionic_init_devinfo(struct ionic *ionic) { struct ionic_dev *idev = &ionic->idev; @@ -72,6 +82,11 @@ int ionic_dev_setup(struct ionic *ionic) return -EFAULT; } + timer_setup(&ionic->watchdog_timer, ionic_watchdog_cb, 0); + ionic->watchdog_period = IONIC_WATCHDOG_SECS * HZ; + mod_timer(&ionic->watchdog_timer, + round_jiffies(jiffies + ionic->watchdog_period)); + idev->db_pages = bar->vaddr; idev->phy_db_pages = bar->bus_addr; @@ -80,10 +95,53 @@ int ionic_dev_setup(struct ionic *ionic) void ionic_dev_teardown(struct ionic *ionic) { - /* place holder */ + del_timer_sync(&ionic->watchdog_timer); } /* Devcmd Interface */ +int ionic_heartbeat_check(struct ionic *ionic) +{ + struct ionic_dev *idev = &ionic->idev; + unsigned long hb_time; + u32 fw_status; + u32 hb; + + /* wait a little more than one second before testing again */ + hb_time = jiffies; + if (time_before(hb_time, (idev->last_hb_time + ionic->watchdog_period))) + return 0; + + /* firmware is useful only if fw_status is non-zero */ + fw_status = ioread32(&idev->dev_info_regs->fw_status); + if (!fw_status) + return -ENXIO; + + /* early FW has no heartbeat, else FW will return non-zero */ + hb = ioread32(&idev->dev_info_regs->fw_heartbeat); + if (!hb) + return 0; + + /* are we stalled? */ + if (hb == idev->last_hb) { + /* only complain once for each stall seen */ + if (idev->last_hb_time != 1) { + dev_info(ionic->dev, "FW heartbeat stalled at %d\n", + idev->last_hb); + idev->last_hb_time = 1; + } + + return -ENXIO; + } + + if (idev->last_hb_time == 1) + dev_info(ionic->dev, "FW heartbeat restored at %d\n", hb); + + idev->last_hb = hb; + idev->last_hb_time = hb_time; + + return 0; +} + u8 ionic_dev_cmd_status(struct ionic_dev *idev) { return ioread8(&idev->dev_cmd_regs->comp.comp.status); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 9610aeb7d5f4..4665c5dc5324 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -16,6 +16,7 @@ #define IONIC_MIN_TXRX_DESC 16 #define IONIC_DEF_TXRX_DESC 4096 #define IONIC_LIFS_MAX 1024 +#define IONIC_WATCHDOG_SECS 5 #define IONIC_ITR_COAL_USEC_DEFAULT 64 #define IONIC_DEV_CMD_REG_VERSION 1 @@ -123,6 +124,9 @@ struct ionic_dev { union ionic_dev_info_regs __iomem *dev_info_regs; union ionic_dev_cmd_regs __iomem *dev_cmd_regs; + unsigned long last_hb_time; + u32 last_hb; + u64 __iomem *db_pages; dma_addr_t phy_db_pages; @@ -151,12 +155,19 @@ typedef void (*ionic_desc_cb)(struct ionic_queue *q, struct ionic_desc_info *desc_info, struct ionic_cq_info *cq_info, void *cb_arg); +struct ionic_page_info { + struct page *page; + dma_addr_t dma_addr; +}; + struct ionic_desc_info { void *desc; void *sg_desc; struct ionic_desc_info *next; unsigned int index; unsigned int left; + unsigned int npages; + struct ionic_page_info pages[IONIC_RX_MAX_SG_ELEMS + 1]; ionic_desc_cb cb; void *cb_arg; }; @@ -295,5 +306,6 @@ void ionic_q_post(struct ionic_queue *q, bool ring_doorbell, ionic_desc_cb cb, void ionic_q_rewind(struct ionic_queue *q, struct ionic_desc_info *start); void ionic_q_service(struct ionic_queue *q, struct ionic_cq_info *cq_info, unsigned int stop_index); +int ionic_heartbeat_check(struct ionic *ionic); #endif /* _IONIC_DEV_H_ */ diff --git a/drivers/net/ethernet/pensando/ionic/ionic_if.h b/drivers/net/ethernet/pensando/ionic/ionic_if.h index 5bfdda19f64d..dbdb7c5ae8f1 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_if.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_if.h @@ -111,7 +111,7 @@ struct ionic_admin_cmd { }; /** - * struct admin_comp - General admin command completion format + * struct ionic_admin_comp - General admin command completion format * @status: The status of the command (enum status_code) * @comp_index: The index in the descriptor ring for which this * is the completion. @@ -134,7 +134,7 @@ static inline u8 color_match(u8 color, u8 done_color) } /** - * struct nop_cmd - NOP command + * struct ionic_nop_cmd - NOP command * @opcode: opcode */ struct ionic_nop_cmd { @@ -143,7 +143,7 @@ struct ionic_nop_cmd { }; /** - * struct nop_comp - NOP command completion + * struct ionic_nop_comp - NOP command completion * @status: The status of the command (enum status_code) */ struct ionic_nop_comp { @@ -152,7 +152,7 @@ struct ionic_nop_comp { }; /** - * struct dev_init_cmd - Device init command + * struct ionic_dev_init_cmd - Device init command * @opcode: opcode * @type: device type */ @@ -172,7 +172,7 @@ struct ionic_dev_init_comp { }; /** - * struct dev_reset_cmd - Device reset command + * struct ionic_dev_reset_cmd - Device reset command * @opcode: opcode */ struct ionic_dev_reset_cmd { @@ -192,7 +192,7 @@ struct ionic_dev_reset_comp { #define IONIC_IDENTITY_VERSION_1 1 /** - * struct dev_identify_cmd - Driver/device identify command + * struct ionic_dev_identify_cmd - Driver/device identify command * @opcode: opcode * @ver: Highest version of identify supported by driver */ @@ -284,7 +284,7 @@ enum ionic_lif_type { }; /** - * struct lif_identify_cmd - lif identify command + * struct ionic_lif_identify_cmd - lif identify command * @opcode: opcode * @type: lif type (enum lif_type) * @ver: version of identify returned by device @@ -297,7 +297,7 @@ struct ionic_lif_identify_cmd { }; /** - * struct lif_identify_comp - lif identify command completion + * struct ionic_lif_identify_comp - lif identify command completion * @status: status of the command (enum status_code) * @ver: version of identify returned by device */ @@ -325,7 +325,7 @@ enum ionic_logical_qtype { }; /** - * struct lif_logical_qtype - Descriptor of logical to hardware queue type. + * struct ionic_lif_logical_qtype - Descriptor of logical to hardware queue type. * @qtype: Hardware Queue Type. * @qid_count: Number of Queue IDs of the logical type. * @qid_base: Minimum Queue ID of the logical type. @@ -349,7 +349,7 @@ enum ionic_lif_state { * @name: lif name * @mtu: mtu * @mac: station mac address - * @features: features (enum eth_hw_features) + * @features: features (enum ionic_eth_hw_features) * @queue_count: queue counts per queue-type */ union ionic_lif_config { @@ -367,7 +367,7 @@ union ionic_lif_config { }; /** - * struct lif_identity - lif identity information (type-specific) + * struct ionic_lif_identity - lif identity information (type-specific) * * @capabilities LIF capabilities * @@ -441,11 +441,11 @@ union ionic_lif_identity { }; /** - * struct lif_init_cmd - LIF init command + * struct ionic_lif_init_cmd - LIF init command * @opcode: opcode * @type: LIF type (enum lif_type) * @index: LIF index - * @info_pa: destination address for lif info (struct lif_info) + * @info_pa: destination address for lif info (struct ionic_lif_info) */ struct ionic_lif_init_cmd { u8 opcode; @@ -457,7 +457,7 @@ struct ionic_lif_init_cmd { }; /** - * struct lif_init_comp - LIF init command completion + * struct ionic_lif_init_comp - LIF init command completion * @status: The status of the command (enum status_code) */ struct ionic_lif_init_comp { @@ -468,7 +468,7 @@ struct ionic_lif_init_comp { }; /** - * struct q_init_cmd - Queue init command + * struct ionic_q_init_cmd - Queue init command * @opcode: opcode * @type: Logical queue type * @ver: Queue version (defines opcode/descriptor scope) @@ -525,7 +525,7 @@ struct ionic_q_init_cmd { }; /** - * struct q_init_comp - Queue init command completion + * struct ionic_q_init_comp - Queue init command completion * @status: The status of the command (enum status_code) * @ver: Queue version (defines opcode/descriptor scope) * @comp_index: The index in the descriptor ring for which this @@ -556,7 +556,7 @@ enum ionic_txq_desc_opcode { }; /** - * struct txq_desc - Ethernet Tx queue descriptor format + * struct ionic_txq_desc - Ethernet Tx queue descriptor format * @opcode: Tx operation, see TXQ_DESC_OPCODE_*: * * IONIC_TXQ_DESC_OPCODE_CSUM_NONE: @@ -735,7 +735,7 @@ static inline void decode_txq_desc_cmd(u64 cmd, u8 *opcode, u8 *flags, #define IONIC_RX_MAX_SG_ELEMS 8 /** - * struct txq_sg_desc - Transmit scatter-gather (SG) list + * struct ionic_txq_sg_desc - Transmit scatter-gather (SG) list * @addr: DMA address of SG element data buffer * @len: Length of SG element data buffer, in bytes */ @@ -748,7 +748,7 @@ struct ionic_txq_sg_desc { }; /** - * struct txq_comp - Ethernet transmit queue completion descriptor + * struct ionic_txq_comp - Ethernet transmit queue completion descriptor * @status: The status of the command (enum status_code) * @comp_index: The index in the descriptor ring for which this * is the completion. @@ -768,7 +768,7 @@ enum ionic_rxq_desc_opcode { }; /** - * struct rxq_desc - Ethernet Rx queue descriptor format + * struct ionic_rxq_desc - Ethernet Rx queue descriptor format * @opcode: Rx operation, see RXQ_DESC_OPCODE_*: * * RXQ_DESC_OPCODE_SIMPLE: @@ -789,7 +789,7 @@ struct ionic_rxq_desc { }; /** - * struct rxq_sg_desc - Receive scatter-gather (SG) list + * struct ionic_rxq_sg_desc - Receive scatter-gather (SG) list * @addr: DMA address of SG element data buffer * @len: Length of SG element data buffer, in bytes */ @@ -802,7 +802,7 @@ struct ionic_rxq_sg_desc { }; /** - * struct rxq_comp - Ethernet receive queue completion descriptor + * struct ionic_rxq_comp - Ethernet receive queue completion descriptor * @status: The status of the command (enum status_code) * @num_sg_elems: Number of SG elements used by this descriptor * @comp_index: The index in the descriptor ring for which this @@ -896,7 +896,7 @@ enum ionic_eth_hw_features { }; /** - * struct q_control_cmd - Queue control command + * struct ionic_q_control_cmd - Queue control command * @opcode: opcode * @type: Queue type * @lif_index: LIF index @@ -1033,8 +1033,8 @@ enum ionic_port_loopback_mode { /** * Transceiver Status information - * @state: Transceiver status (enum xcvr_state) - * @phy: Physical connection type (enum phy_type) + * @state: Transceiver status (enum ionic_xcvr_state) + * @phy: Physical connection type (enum ionic_phy_type) * @pid: Transceiver link mode (enum pid) * @sprom: Transceiver sprom contents */ @@ -1051,9 +1051,9 @@ struct ionic_xcvr_status { * @mtu: mtu * @state: port admin state (enum port_admin_state) * @an_enable: autoneg enable - * @fec_type: fec type (enum port_fec_type) - * @pause_type: pause type (enum port_pause_type) - * @loopback_mode: loopback mode (enum port_loopback_mode) + * @fec_type: fec type (enum ionic_port_fec_type) + * @pause_type: pause type (enum ionic_port_pause_type) + * @loopback_mode: loopback mode (enum ionic_port_loopback_mode) */ union ionic_port_config { struct { @@ -1080,7 +1080,7 @@ union ionic_port_config { /** * Port Status information - * @status: link status (enum port_oper_status) + * @status: link status (enum ionic_port_oper_status) * @id: port id * @speed: link speed (in Mbps) * @xcvr: tranceiver status @@ -1094,7 +1094,7 @@ struct ionic_port_status { }; /** - * struct port_identify_cmd - Port identify command + * struct ionic_port_identify_cmd - Port identify command * @opcode: opcode * @index: port index * @ver: Highest version of identify supported by driver @@ -1107,7 +1107,7 @@ struct ionic_port_identify_cmd { }; /** - * struct port_identify_comp - Port identify command completion + * struct ionic_port_identify_comp - Port identify command completion * @status: The status of the command (enum status_code) * @ver: Version of identify returned by device */ @@ -1118,10 +1118,10 @@ struct ionic_port_identify_comp { }; /** - * struct port_init_cmd - Port initialization command + * struct ionic_port_init_cmd - Port initialization command * @opcode: opcode * @index: port index - * @info_pa: destination address for port info (struct port_info) + * @info_pa: destination address for port info (struct ionic_port_info) */ struct ionic_port_init_cmd { u8 opcode; @@ -1132,7 +1132,7 @@ struct ionic_port_init_cmd { }; /** - * struct port_init_comp - Port initialization command completion + * struct ionic_port_init_comp - Port initialization command completion * @status: The status of the command (enum status_code) */ struct ionic_port_init_comp { @@ -1141,7 +1141,7 @@ struct ionic_port_init_comp { }; /** - * struct port_reset_cmd - Port reset command + * struct ionic_port_reset_cmd - Port reset command * @opcode: opcode * @index: port index */ @@ -1152,7 +1152,7 @@ struct ionic_port_reset_cmd { }; /** - * struct port_reset_comp - Port reset command completion + * struct ionic_port_reset_comp - Port reset command completion * @status: The status of the command (enum status_code) */ struct ionic_port_reset_comp { @@ -1183,7 +1183,7 @@ enum ionic_port_attr { }; /** - * struct port_setattr_cmd - Set port attributes on the NIC + * struct ionic_port_setattr_cmd - Set port attributes on the NIC * @opcode: Opcode * @index: port index * @attr: Attribute type (enum ionic_port_attr) @@ -1207,7 +1207,7 @@ struct ionic_port_setattr_cmd { }; /** - * struct port_setattr_comp - Port set attr command completion + * struct ionic_port_setattr_comp - Port set attr command completion * @status: The status of the command (enum status_code) * @color: Color bit */ @@ -1218,7 +1218,7 @@ struct ionic_port_setattr_comp { }; /** - * struct port_getattr_cmd - Get port attributes from the NIC + * struct ionic_port_getattr_cmd - Get port attributes from the NIC * @opcode: Opcode * @index: port index * @attr: Attribute type (enum ionic_port_attr) @@ -1231,7 +1231,7 @@ struct ionic_port_getattr_cmd { }; /** - * struct port_getattr_comp - Port get attr command completion + * struct ionic_port_getattr_comp - Port get attr command completion * @status: The status of the command (enum status_code) * @color: Color bit */ @@ -1252,10 +1252,10 @@ struct ionic_port_getattr_comp { }; /** - * struct lif_status - Lif status register + * struct ionic_lif_status - Lif status register * @eid: most recent NotifyQ event id * @port_num: port the lif is connected to - * @link_status: port status (enum port_oper_status) + * @link_status: port status (enum ionic_port_oper_status) * @link_speed: speed of link in Mbps * @link_down_count: number of times link status changes */ @@ -1270,7 +1270,7 @@ struct ionic_lif_status { }; /** - * struct lif_reset_cmd - LIF reset command + * struct ionic_lif_reset_cmd - LIF reset command * @opcode: opcode * @index: LIF index */ @@ -1290,7 +1290,7 @@ enum ionic_dev_state { }; /** - * enum dev_attr - List of device attributes + * enum ionic_dev_attr - List of device attributes */ enum ionic_dev_attr { IONIC_DEV_ATTR_STATE = 0, @@ -1299,10 +1299,10 @@ enum ionic_dev_attr { }; /** - * struct dev_setattr_cmd - Set Device attributes on the NIC + * struct ionic_dev_setattr_cmd - Set Device attributes on the NIC * @opcode: Opcode - * @attr: Attribute type (enum dev_attr) - * @state: Device state (enum dev_state) + * @attr: Attribute type (enum ionic_dev_attr) + * @state: Device state (enum ionic_dev_state) * @name: The bus info, e.g. PCI slot-device-function, 0 terminated * @features: Device features */ @@ -1319,7 +1319,7 @@ struct ionic_dev_setattr_cmd { }; /** - * struct dev_setattr_comp - Device set attr command completion + * struct ionic_dev_setattr_comp - Device set attr command completion * @status: The status of the command (enum status_code) * @features: Device features * @color: Color bit @@ -1335,9 +1335,9 @@ struct ionic_dev_setattr_comp { }; /** - * struct dev_getattr_cmd - Get Device attributes from the NIC + * struct ionic_dev_getattr_cmd - Get Device attributes from the NIC * @opcode: opcode - * @attr: Attribute type (enum dev_attr) + * @attr: Attribute type (enum ionic_dev_attr) */ struct ionic_dev_getattr_cmd { u8 opcode; @@ -1346,7 +1346,7 @@ struct ionic_dev_getattr_cmd { }; /** - * struct dev_setattr_comp - Device set attr command completion + * struct ionic_dev_setattr_comp - Device set attr command completion * @status: The status of the command (enum status_code) * @features: Device features * @color: Color bit @@ -1376,7 +1376,7 @@ enum ionic_rss_hash_types { }; /** - * enum lif_attr - List of LIF attributes + * enum ionic_lif_attr - List of LIF attributes */ enum ionic_lif_attr { IONIC_LIF_ATTR_STATE = 0, @@ -1389,15 +1389,15 @@ enum ionic_lif_attr { }; /** - * struct lif_setattr_cmd - Set LIF attributes on the NIC + * struct ionic_lif_setattr_cmd - Set LIF attributes on the NIC * @opcode: Opcode - * @type: Attribute type (enum lif_attr) + * @type: Attribute type (enum ionic_lif_attr) * @index: LIF index * @state: lif state (enum lif_state) * @name: The netdev name string, 0 terminated * @mtu: Mtu * @mac: Station mac - * @features: Features (enum eth_hw_features) + * @features: Features (enum ionic_eth_hw_features) * @rss: RSS properties * @types: The hash types to enable (see rss_hash_types). * @key: The hash secret key. @@ -1426,11 +1426,11 @@ struct ionic_lif_setattr_cmd { }; /** - * struct lif_setattr_comp - LIF set attr command completion + * struct ionic_lif_setattr_comp - LIF set attr command completion * @status: The status of the command (enum status_code) * @comp_index: The index in the descriptor ring for which this * is the completion. - * @features: features (enum eth_hw_features) + * @features: features (enum ionic_eth_hw_features) * @color: Color bit */ struct ionic_lif_setattr_comp { @@ -1445,9 +1445,9 @@ struct ionic_lif_setattr_comp { }; /** - * struct lif_getattr_cmd - Get LIF attributes from the NIC + * struct ionic_lif_getattr_cmd - Get LIF attributes from the NIC * @opcode: Opcode - * @attr: Attribute type (enum lif_attr) + * @attr: Attribute type (enum ionic_lif_attr) * @index: LIF index */ struct ionic_lif_getattr_cmd { @@ -1458,7 +1458,7 @@ struct ionic_lif_getattr_cmd { }; /** - * struct lif_getattr_comp - LIF get attr command completion + * struct ionic_lif_getattr_comp - LIF get attr command completion * @status: The status of the command (enum status_code) * @comp_index: The index in the descriptor ring for which this * is the completion. @@ -1466,7 +1466,7 @@ struct ionic_lif_getattr_cmd { * @name: The netdev name string, 0 terminated * @mtu: Mtu * @mac: Station mac - * @features: Features (enum eth_hw_features) + * @features: Features (enum ionic_eth_hw_features) * @color: Color bit */ struct ionic_lif_getattr_comp { @@ -1492,7 +1492,7 @@ enum ionic_rx_mode { }; /** - * struct rx_mode_set_cmd - Set LIF's Rx mode command + * struct ionic_rx_mode_set_cmd - Set LIF's Rx mode command * @opcode: opcode * @lif_index: LIF index * @rx_mode: Rx mode flags: @@ -1519,7 +1519,7 @@ enum ionic_rx_filter_match_type { }; /** - * struct rx_filter_add_cmd - Add LIF Rx filter command + * struct ionic_rx_filter_add_cmd - Add LIF Rx filter command * @opcode: opcode * @qtype: Queue type * @lif_index: LIF index @@ -1550,7 +1550,7 @@ struct ionic_rx_filter_add_cmd { }; /** - * struct rx_filter_add_comp - Add LIF Rx filter command completion + * struct ionic_rx_filter_add_comp - Add LIF Rx filter command completion * @status: The status of the command (enum status_code) * @comp_index: The index in the descriptor ring for which this * is the completion. @@ -1567,7 +1567,7 @@ struct ionic_rx_filter_add_comp { }; /** - * struct rx_filter_del_cmd - Delete LIF Rx filter command + * struct ionic_rx_filter_del_cmd - Delete LIF Rx filter command * @opcode: opcode * @lif_index: LIF index * @filter_id: Filter ID @@ -1583,7 +1583,7 @@ struct ionic_rx_filter_del_cmd { typedef struct ionic_admin_comp ionic_rx_filter_del_comp; /** - * struct qos_identify_cmd - QoS identify command + * struct ionic_qos_identify_cmd - QoS identify command * @opcode: opcode * @ver: Highest version of identify supported by driver * @@ -1595,7 +1595,7 @@ struct ionic_qos_identify_cmd { }; /** - * struct qos_identify_comp - QoS identify command completion + * struct ionic_qos_identify_comp - QoS identify command completion * @status: The status of the command (enum status_code) * @ver: Version of identify returned by device */ @@ -1610,7 +1610,7 @@ struct ionic_qos_identify_comp { #define IONIC_QOS_DSCP_MAX_VALUES 64 /** - * enum qos_class + * enum ionic_qos_class */ enum ionic_qos_class { IONIC_QOS_CLASS_DEFAULT = 0, @@ -1623,7 +1623,7 @@ enum ionic_qos_class { }; /** - * enum qos_class_type - Traffic classification criteria + * enum ionic_qos_class_type - Traffic classification criteria */ enum ionic_qos_class_type { IONIC_QOS_CLASS_TYPE_NONE = 0, @@ -1632,7 +1632,7 @@ enum ionic_qos_class_type { }; /** - * enum qos_sched_type - Qos class scheduling type + * enum ionic_qos_sched_type - Qos class scheduling type */ enum ionic_qos_sched_type { IONIC_QOS_SCHED_TYPE_STRICT = 0, /* Strict priority */ @@ -1640,15 +1640,15 @@ enum ionic_qos_sched_type { }; /** - * union qos_config - Qos configuration structure + * union ionic_qos_config - Qos configuration structure * @flags: Configuration flags * IONIC_QOS_CONFIG_F_ENABLE enable * IONIC_QOS_CONFIG_F_DROP drop/nodrop * IONIC_QOS_CONFIG_F_RW_DOT1Q_PCP enable dot1q pcp rewrite * IONIC_QOS_CONFIG_F_RW_IP_DSCP enable ip dscp rewrite - * @sched_type: Qos class scheduling type (enum qos_sched_type) - * @class_type: Qos class type (enum qos_class_type) - * @pause_type: Qos pause type (enum qos_pause_type) + * @sched_type: Qos class scheduling type (enum ionic_qos_sched_type) + * @class_type: Qos class type (enum ionic_qos_class_type) + * @pause_type: Qos pause type (enum ionic_qos_pause_type) * @name: Qos class name * @mtu: MTU of the class * @pfc_dot1q_pcp: Pcp value for pause frames (valid iff F_NODROP) @@ -1697,7 +1697,7 @@ union ionic_qos_config { }; /** - * union qos_identity - QoS identity structure + * union ionic_qos_identity - QoS identity structure * @version: Version of the identify structure * @type: QoS system type * @nclasses: Number of usable QoS classes @@ -1730,7 +1730,7 @@ struct ionic_qos_init_cmd { typedef struct ionic_admin_comp ionic_qos_init_comp; /** - * struct qos_reset_cmd - Qos config reset command + * struct ionic_qos_reset_cmd - Qos config reset command * @opcode: Opcode */ struct ionic_qos_reset_cmd { @@ -1742,7 +1742,7 @@ struct ionic_qos_reset_cmd { typedef struct ionic_admin_comp ionic_qos_reset_comp; /** - * struct fw_download_cmd - Firmware download command + * struct ionic_fw_download_cmd - Firmware download command * @opcode: opcode * @addr: dma address of the firmware buffer * @offset: offset of the firmware buffer within the full image @@ -1765,9 +1765,9 @@ enum ionic_fw_control_oper { }; /** - * struct fw_control_cmd - Firmware control command + * struct ionic_fw_control_cmd - Firmware control command * @opcode: opcode - * @oper: firmware control operation (enum fw_control_oper) + * @oper: firmware control operation (enum ionic_fw_control_oper) * @slot: slot to activate */ struct ionic_fw_control_cmd { @@ -1779,7 +1779,7 @@ struct ionic_fw_control_cmd { }; /** - * struct fw_control_comp - Firmware control copletion + * struct ionic_fw_control_comp - Firmware control copletion * @opcode: opcode * @slot: slot where the firmware was installed */ @@ -1797,13 +1797,13 @@ struct ionic_fw_control_comp { ******************************************************************/ /** - * struct rdma_reset_cmd - Reset RDMA LIF cmd + * struct ionic_rdma_reset_cmd - Reset RDMA LIF cmd * @opcode: opcode * @lif_index: lif index * * There is no rdma specific dev command completion struct. Completion uses - * the common struct admin_comp. Only the status is indicated. Nonzero status - * means the LIF does not support rdma. + * the common struct ionic_admin_comp. Only the status is indicated. + * Nonzero status means the LIF does not support rdma. **/ struct ionic_rdma_reset_cmd { u8 opcode; @@ -1813,7 +1813,7 @@ struct ionic_rdma_reset_cmd { }; /** - * struct rdma_queue_cmd - Create RDMA Queue command + * struct ionic_rdma_queue_cmd - Create RDMA Queue command * @opcode: opcode, 52, 53 * @lif_index lif index * @qid_ver: (qid | (rdma version << 24)) @@ -1839,7 +1839,7 @@ struct ionic_rdma_reset_cmd { * memory registration. * * There is no rdma specific dev command completion struct. Completion uses - * the common struct admin_comp. Only the status is indicated. + * the common struct ionic_admin_comp. Only the status is indicated. **/ struct ionic_rdma_queue_cmd { u8 opcode; @@ -1860,7 +1860,7 @@ struct ionic_rdma_queue_cmd { ******************************************************************/ /** - * struct notifyq_event + * struct ionic_notifyq_event * @eid: event number * @ecode: event code * @data: unspecified data about the event @@ -1875,7 +1875,7 @@ struct ionic_notifyq_event { }; /** - * struct link_change_event + * struct ionic_link_change_event * @eid: event number * @ecode: event code = EVENT_OPCODE_LINK_CHANGE * @link_status: link up or down, with error bits (enum port_status) @@ -1892,7 +1892,7 @@ struct ionic_link_change_event { }; /** - * struct reset_event + * struct ionic_reset_event * @eid: event number * @ecode: event code = EVENT_OPCODE_RESET * @reset_code: reset type @@ -1910,7 +1910,7 @@ struct ionic_reset_event { }; /** - * struct heartbeat_event + * struct ionic_heartbeat_event * @eid: event number * @ecode: event code = EVENT_OPCODE_HEARTBEAT * @@ -1923,7 +1923,7 @@ struct ionic_heartbeat_event { }; /** - * struct log_event + * struct ionic_log_event * @eid: event number * @ecode: event code = EVENT_OPCODE_LOG * @data: log data @@ -1937,7 +1937,7 @@ struct ionic_log_event { }; /** - * struct port_stats + * struct ionic_port_stats */ struct ionic_port_stats { __le64 frames_rx_ok; @@ -2067,7 +2067,7 @@ struct ionic_mgmt_port_stats { }; /** - * struct port_identity - port identity structure + * struct ionic_port_identity - port identity structure * @version: identity structure version * @type: type of port (enum port_type) * @num_lanes: number of lanes for the port @@ -2099,7 +2099,7 @@ union ionic_port_identity { }; /** - * struct port_info - port info structure + * struct ionic_port_info - port info structure * @port_status: port status * @port_stats: port stats */ @@ -2110,7 +2110,7 @@ struct ionic_port_info { }; /** - * struct lif_stats + * struct ionic_lif_stats */ struct ionic_lif_stats { /* RX */ @@ -2264,7 +2264,7 @@ struct ionic_lif_stats { }; /** - * struct lif_info - lif info structure + * struct ionic_lif_info - lif info structure */ struct ionic_lif_info { union ionic_lif_config config; @@ -2357,7 +2357,7 @@ union ionic_dev_info_regs { }; /** - * union dev_cmd_regs - Device command register format (read-write) + * union ionic_dev_cmd_regs - Device command register format (read-write) * @doorbell: Device Cmd Doorbell, write-only. * Write a 1 to signal device to process cmd, * poll done for completion. @@ -2379,7 +2379,7 @@ union ionic_dev_cmd_regs { }; /** - * union dev_regs - Device register format in for bar 0 page 0 + * union ionic_dev_regs - Device register format in for bar 0 page 0 * @info: Device info registers * @devcmd: Device command registers */ @@ -2433,7 +2433,7 @@ union ionic_adminq_comp { #define IONIC_ASIC_TYPE_CAPRI 0 /** - * struct doorbell - Doorbell register layout + * struct ionic_doorbell - Doorbell register layout * @p_index: Producer index * @ring: Selects the specific ring of the queue to update. * Type-specific meaning: diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 559b96ae48f5..a9bb12ce5f13 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -622,12 +622,14 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) .lif_index = cpu_to_le16(lif->index), .type = q->type, .index = cpu_to_le32(q->index), - .flags = cpu_to_le16(IONIC_QINIT_F_IRQ), + .flags = cpu_to_le16(IONIC_QINIT_F_IRQ | + IONIC_QINIT_F_SG), .intr_index = cpu_to_le16(cq->bound_intr->index), .pid = cpu_to_le16(q->pid), .ring_size = ilog2(q->num_descs), .ring_base = cpu_to_le64(q->base_pa), .cq_ring_base = cpu_to_le64(cq->base_pa), + .sg_ring_base = cpu_to_le64(q->sg_base_pa), }, }; int err; @@ -1460,13 +1462,14 @@ static int ionic_txrx_alloc(struct ionic_lif *lif) lif->txqcqs[i].qcq->stats = lif->txqcqs[i].stats; } - flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_INTR; + flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_SG | IONIC_QCQ_F_INTR; for (i = 0; i < lif->nxqs; i++) { err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags, lif->nrxq_descs, sizeof(struct ionic_rxq_desc), sizeof(struct ionic_rxq_comp), - 0, lif->kern_pid, &lif->rxqcqs[i].qcq); + sizeof(struct ionic_rxq_sg_desc), + lif->kern_pid, &lif->rxqcqs[i].qcq); if (err) goto err_out; @@ -1686,7 +1689,7 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index /* Convert the default coalesce value to actual hw resolution */ lif->rx_coalesce_usecs = IONIC_ITR_COAL_USEC_DEFAULT; - lif->rx_coalesce_hw = ionic_coal_hw_to_usec(lif->ionic, + lif->rx_coalesce_hw = ionic_coal_usec_to_hw(lif->ionic, lif->rx_coalesce_usecs); snprintf(lif->name, sizeof(lif->name), "lif%u", index); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h index cf243a9d0168..a55fd1f8c31b 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h @@ -184,6 +184,8 @@ struct ionic_lif { #define lif_to_txqcq(lif, i) ((lif)->txqcqs[i].qcq) #define lif_to_rxqcq(lif, i) ((lif)->rxqcqs[i].qcq) +#define lif_to_txstats(lif, i) ((lif)->txqcqs[i].stats->tx) +#define lif_to_rxstats(lif, i) ((lif)->rxqcqs[i].stats->rx) #define lif_to_txq(lif, i) (&lif_to_txqcq((lif), i)->q) #define lif_to_rxq(lif, i) (&lif_to_txqcq((lif), i)->q) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c index 15e432386b35..52eb303e903f 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c @@ -245,6 +245,10 @@ static int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) goto err_out; } + err = ionic_heartbeat_check(lif->ionic); + if (err) + goto err_out; + memcpy(adminq->head->desc, &ctx->cmd, sizeof(ctx->cmd)); dev_dbg(&lif->netdev->dev, "post admin queue command:\n"); @@ -305,6 +309,14 @@ int ionic_napi(struct napi_struct *napi, int budget, ionic_cq_cb cb, return work_done; } +static void ionic_dev_cmd_clean(struct ionic *ionic) +{ + union ionic_dev_cmd_regs *regs = ionic->idev.dev_cmd_regs; + + iowrite32(0, ®s->doorbell); + memset_io(®s->cmd, 0, sizeof(regs->cmd)); +} + int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds) { struct ionic_dev *idev = &ionic->idev; @@ -314,6 +326,7 @@ int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds) int opcode; int done; int err; + int hb; WARN_ON(in_interrupt()); @@ -328,7 +341,8 @@ try_again: if (done) break; msleep(20); - } while (!done && time_before(jiffies, max_wait)); + hb = ionic_heartbeat_check(ionic); + } while (!done && !hb && time_before(jiffies, max_wait)); duration = jiffies - start_time; opcode = idev->dev_cmd_regs->cmd.cmd.opcode; @@ -336,7 +350,15 @@ try_again: ionic_opcode_to_str(opcode), opcode, done, duration / HZ, duration); + if (!done && hb) { + ionic_dev_cmd_clean(ionic); + dev_warn(ionic->dev, "DEVCMD %s (%d) failed - FW halted\n", + ionic_opcode_to_str(opcode), opcode); + return -ENXIO; + } + if (!done && !time_before(jiffies, max_wait)) { + ionic_dev_cmd_clean(ionic); dev_warn(ionic->dev, "DEVCMD %s (%d) timeout after %ld secs\n", ionic_opcode_to_str(opcode), opcode, max_seconds); return -ETIMEDOUT; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_stats.c b/drivers/net/ethernet/pensando/ionic/ionic_stats.c index e2907884f843..03916b6d47f2 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_stats.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_stats.c @@ -117,7 +117,8 @@ static u64 ionic_sw_stats_get_count(struct ionic_lif *lif) /* rx stats */ total += MAX_Q(lif) * IONIC_NUM_RX_STATS; - if (test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { + if (test_bit(IONIC_LIF_UP, lif->state) && + test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { /* tx debug stats */ total += MAX_Q(lif) * (IONIC_NUM_DBG_CQ_STATS + IONIC_NUM_TX_Q_STATS + @@ -149,7 +150,8 @@ static void ionic_sw_stats_get_strings(struct ionic_lif *lif, u8 **buf) *buf += ETH_GSTRING_LEN; } - if (test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { + if (test_bit(IONIC_LIF_UP, lif->state) && + test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { for (i = 0; i < IONIC_NUM_TX_Q_STATS; i++) { snprintf(*buf, ETH_GSTRING_LEN, "txq_%d_%s", @@ -187,7 +189,8 @@ static void ionic_sw_stats_get_strings(struct ionic_lif *lif, u8 **buf) *buf += ETH_GSTRING_LEN; } - if (test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { + if (test_bit(IONIC_LIF_UP, lif->state) && + test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { for (i = 0; i < IONIC_NUM_DBG_CQ_STATS; i++) { snprintf(*buf, ETH_GSTRING_LEN, "rxq_%d_cq_%s", @@ -223,6 +226,8 @@ static void ionic_sw_stats_get_values(struct ionic_lif *lif, u64 **buf) { struct ionic_lif_sw_stats lif_stats; struct ionic_qcq *txqcq, *rxqcq; + struct ionic_tx_stats *txstats; + struct ionic_rx_stats *rxstats; int i, q_num; ionic_get_lif_stats(lif, &lif_stats); @@ -233,15 +238,17 @@ static void ionic_sw_stats_get_values(struct ionic_lif *lif, u64 **buf) } for (q_num = 0; q_num < MAX_Q(lif); q_num++) { - txqcq = lif_to_txqcq(lif, q_num); + txstats = &lif_to_txstats(lif, q_num); for (i = 0; i < IONIC_NUM_TX_STATS; i++) { - **buf = IONIC_READ_STAT64(&txqcq->stats->tx, + **buf = IONIC_READ_STAT64(txstats, &ionic_tx_stats_desc[i]); (*buf)++; } - if (test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { + if (test_bit(IONIC_LIF_UP, lif->state) && + test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { + txqcq = lif_to_txqcq(lif, q_num); for (i = 0; i < IONIC_NUM_TX_Q_STATS; i++) { **buf = IONIC_READ_STAT64(&txqcq->q, &ionic_txq_stats_desc[i]); @@ -258,22 +265,24 @@ static void ionic_sw_stats_get_values(struct ionic_lif *lif, u64 **buf) (*buf)++; } for (i = 0; i < IONIC_MAX_NUM_SG_CNTR; i++) { - **buf = txqcq->stats->tx.sg_cntr[i]; + **buf = txstats->sg_cntr[i]; (*buf)++; } } } for (q_num = 0; q_num < MAX_Q(lif); q_num++) { - rxqcq = lif_to_rxqcq(lif, q_num); + rxstats = &lif_to_rxstats(lif, q_num); for (i = 0; i < IONIC_NUM_RX_STATS; i++) { - **buf = IONIC_READ_STAT64(&rxqcq->stats->rx, + **buf = IONIC_READ_STAT64(rxstats, &ionic_rx_stats_desc[i]); (*buf)++; } - if (test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { + if (test_bit(IONIC_LIF_UP, lif->state) && + test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { + rxqcq = lif_to_rxqcq(lif, q_num); for (i = 0; i < IONIC_NUM_DBG_CQ_STATS; i++) { **buf = IONIC_READ_STAT64(&rxqcq->cq, &ionic_dbg_cq_stats_desc[i]); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index ab6663d94f42..0aeac3157160 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -34,52 +34,110 @@ static inline struct netdev_queue *q_to_ndq(struct ionic_queue *q) return netdev_get_tx_queue(q->lif->netdev, q->index); } -static void ionic_rx_recycle(struct ionic_queue *q, struct ionic_desc_info *desc_info, - struct sk_buff *skb) +static struct sk_buff *ionic_rx_skb_alloc(struct ionic_queue *q, + unsigned int len, bool frags) { - struct ionic_rxq_desc *old = desc_info->desc; - struct ionic_rxq_desc *new = q->head->desc; + struct ionic_lif *lif = q->lif; + struct ionic_rx_stats *stats; + struct net_device *netdev; + struct sk_buff *skb; + + netdev = lif->netdev; + stats = q_to_rx_stats(q); + + if (frags) + skb = napi_get_frags(&q_to_qcq(q)->napi); + else + skb = netdev_alloc_skb_ip_align(netdev, len); - new->addr = old->addr; - new->len = old->len; + if (unlikely(!skb)) { + net_warn_ratelimited("%s: SKB alloc failed on %s!\n", + netdev->name, q->name); + stats->alloc_err++; + return NULL; + } - ionic_rxq_post(q, true, ionic_rx_clean, skb); + return skb; } -static bool ionic_rx_copybreak(struct ionic_queue *q, struct ionic_desc_info *desc_info, - struct ionic_cq_info *cq_info, struct sk_buff **skb) +static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, + struct ionic_desc_info *desc_info, + struct ionic_cq_info *cq_info) { struct ionic_rxq_comp *comp = cq_info->cq_desc; - struct ionic_rxq_desc *desc = desc_info->desc; - struct net_device *netdev = q->lif->netdev; struct device *dev = q->lif->ionic->dev; - struct sk_buff *new_skb; - u16 clen, dlen; - - clen = le16_to_cpu(comp->len); - dlen = le16_to_cpu(desc->len); - if (clen > q->lif->rx_copybreak) { - dma_unmap_single(dev, (dma_addr_t)le64_to_cpu(desc->addr), - dlen, DMA_FROM_DEVICE); - return false; - } + struct ionic_page_info *page_info; + struct sk_buff *skb; + unsigned int i; + u16 frag_len; + u16 len; - new_skb = netdev_alloc_skb_ip_align(netdev, clen); - if (!new_skb) { - dma_unmap_single(dev, (dma_addr_t)le64_to_cpu(desc->addr), - dlen, DMA_FROM_DEVICE); - return false; - } + page_info = &desc_info->pages[0]; + len = le16_to_cpu(comp->len); - dma_sync_single_for_cpu(dev, (dma_addr_t)le64_to_cpu(desc->addr), - clen, DMA_FROM_DEVICE); + prefetch(page_address(page_info->page) + NET_IP_ALIGN); - memcpy(new_skb->data, (*skb)->data, clen); + skb = ionic_rx_skb_alloc(q, len, true); + if (unlikely(!skb)) + return NULL; - ionic_rx_recycle(q, desc_info, *skb); - *skb = new_skb; + i = comp->num_sg_elems + 1; + do { + if (unlikely(!page_info->page)) { + struct napi_struct *napi = &q_to_qcq(q)->napi; - return true; + napi->skb = NULL; + dev_kfree_skb(skb); + return NULL; + } + + frag_len = min(len, (u16)PAGE_SIZE); + len -= frag_len; + + dma_unmap_page(dev, dma_unmap_addr(page_info, dma_addr), + PAGE_SIZE, DMA_FROM_DEVICE); + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + page_info->page, 0, frag_len, PAGE_SIZE); + page_info->page = NULL; + page_info++; + i--; + } while (i > 0); + + return skb; +} + +static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q, + struct ionic_desc_info *desc_info, + struct ionic_cq_info *cq_info) +{ + struct ionic_rxq_comp *comp = cq_info->cq_desc; + struct device *dev = q->lif->ionic->dev; + struct ionic_page_info *page_info; + struct sk_buff *skb; + u16 len; + + page_info = &desc_info->pages[0]; + len = le16_to_cpu(comp->len); + + skb = ionic_rx_skb_alloc(q, len, false); + if (unlikely(!skb)) + return NULL; + + if (unlikely(!page_info->page)) { + dev_kfree_skb(skb); + return NULL; + } + + dma_sync_single_for_cpu(dev, dma_unmap_addr(page_info, dma_addr), + len, DMA_FROM_DEVICE); + skb_copy_to_linear_data(skb, page_address(page_info->page), len); + dma_sync_single_for_device(dev, dma_unmap_addr(page_info, dma_addr), + len, DMA_FROM_DEVICE); + + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, q->lif->netdev); + + return skb; } static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_info, @@ -87,35 +145,34 @@ static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_i { struct ionic_rxq_comp *comp = cq_info->cq_desc; struct ionic_qcq *qcq = q_to_qcq(q); - struct sk_buff *skb = cb_arg; struct ionic_rx_stats *stats; struct net_device *netdev; + struct sk_buff *skb; stats = q_to_rx_stats(q); netdev = q->lif->netdev; - if (comp->status) { - ionic_rx_recycle(q, desc_info, skb); + if (comp->status) return; - } - if (unlikely(test_bit(IONIC_LIF_QUEUE_RESET, q->lif->state))) { - /* no packet processing while resetting */ - ionic_rx_recycle(q, desc_info, skb); + /* no packet processing while resetting */ + if (unlikely(test_bit(IONIC_LIF_QUEUE_RESET, q->lif->state))) return; - } stats->pkts++; stats->bytes += le16_to_cpu(comp->len); - ionic_rx_copybreak(q, desc_info, cq_info, &skb); + if (le16_to_cpu(comp->len) <= q->lif->rx_copybreak) + skb = ionic_rx_copybreak(q, desc_info, cq_info); + else + skb = ionic_rx_frags(q, desc_info, cq_info); - skb_put(skb, le16_to_cpu(comp->len)); - skb->protocol = eth_type_trans(skb, netdev); + if (unlikely(!skb)) + return; skb_record_rx_queue(skb, q->index); - if (netdev->features & NETIF_F_RXHASH) { + if (likely(netdev->features & NETIF_F_RXHASH)) { switch (comp->pkt_type_color & IONIC_RXQ_COMP_PKT_TYPE_MASK) { case IONIC_PKT_TYPE_IPV4: case IONIC_PKT_TYPE_IPV6: @@ -132,7 +189,7 @@ static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_i } } - if (netdev->features & NETIF_F_RXCSUM) { + if (likely(netdev->features & NETIF_F_RXCSUM)) { if (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_CALC) { skb->ip_summed = CHECKSUM_COMPLETE; skb->csum = (__wsum)le16_to_cpu(comp->csum); @@ -142,18 +199,21 @@ static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_i stats->csum_none++; } - if ((comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_TCP_BAD) || - (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_UDP_BAD) || - (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_IP_BAD)) + if (unlikely((comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_TCP_BAD) || + (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_UDP_BAD) || + (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_IP_BAD))) stats->csum_error++; - if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { + if (likely(netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) { if (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_VLAN) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), le16_to_cpu(comp->vlan_tci)); } - napi_gro_receive(&qcq->napi, skb); + if (le16_to_cpu(comp->len) <= q->lif->rx_copybreak) + napi_gro_receive(&qcq->napi, skb); + else + napi_gro_frags(&qcq->napi); } static bool ionic_rx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info) @@ -213,66 +273,125 @@ void ionic_rx_flush(struct ionic_cq *cq) work_done, IONIC_INTR_CRED_RESET_COALESCE); } -static struct sk_buff *ionic_rx_skb_alloc(struct ionic_queue *q, unsigned int len, - dma_addr_t *dma_addr) +static struct page *ionic_rx_page_alloc(struct ionic_queue *q, + dma_addr_t *dma_addr) { struct ionic_lif *lif = q->lif; struct ionic_rx_stats *stats; struct net_device *netdev; - struct sk_buff *skb; struct device *dev; + struct page *page; netdev = lif->netdev; dev = lif->ionic->dev; stats = q_to_rx_stats(q); - skb = netdev_alloc_skb_ip_align(netdev, len); - if (!skb) { - net_warn_ratelimited("%s: SKB alloc failed on %s!\n", - netdev->name, q->name); + page = alloc_page(GFP_ATOMIC); + if (unlikely(!page)) { + net_err_ratelimited("%s: Page alloc failed on %s!\n", + netdev->name, q->name); stats->alloc_err++; return NULL; } - *dma_addr = dma_map_single(dev, skb->data, len, DMA_FROM_DEVICE); - if (dma_mapping_error(dev, *dma_addr)) { - dev_kfree_skb(skb); - net_warn_ratelimited("%s: DMA single map failed on %s!\n", - netdev->name, q->name); + *dma_addr = dma_map_page(dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(dev, *dma_addr))) { + __free_page(page); + net_err_ratelimited("%s: DMA single map failed on %s!\n", + netdev->name, q->name); stats->dma_map_err++; return NULL; } - return skb; + return page; +} + +static void ionic_rx_page_free(struct ionic_queue *q, struct page *page, + dma_addr_t dma_addr) +{ + struct ionic_lif *lif = q->lif; + struct net_device *netdev; + struct device *dev; + + netdev = lif->netdev; + dev = lif->ionic->dev; + + if (unlikely(!page)) { + net_err_ratelimited("%s: Trying to free unallocated buffer on %s!\n", + netdev->name, q->name); + return; + } + + dma_unmap_page(dev, dma_addr, PAGE_SIZE, DMA_FROM_DEVICE); + + __free_page(page); } -#define IONIC_RX_RING_DOORBELL_STRIDE ((1 << 2) - 1) +#define IONIC_RX_RING_DOORBELL_STRIDE ((1 << 5) - 1) +#define IONIC_RX_RING_HEAD_BUF_SZ 2048 void ionic_rx_fill(struct ionic_queue *q) { struct net_device *netdev = q->lif->netdev; + struct ionic_desc_info *desc_info; + struct ionic_page_info *page_info; + struct ionic_rxq_sg_desc *sg_desc; + struct ionic_rxq_sg_elem *sg_elem; struct ionic_rxq_desc *desc; - struct sk_buff *skb; - dma_addr_t dma_addr; + unsigned int nfrags; bool ring_doorbell; + unsigned int i, j; unsigned int len; - unsigned int i; len = netdev->mtu + ETH_HLEN; + nfrags = round_up(len, PAGE_SIZE) / PAGE_SIZE; for (i = ionic_q_space_avail(q); i; i--) { - skb = ionic_rx_skb_alloc(q, len, &dma_addr); - if (!skb) - return; + desc_info = q->head; + desc = desc_info->desc; + sg_desc = desc_info->sg_desc; + page_info = &desc_info->pages[0]; + + if (page_info->page) { /* recycle the buffer */ + ring_doorbell = ((q->head->index + 1) & + IONIC_RX_RING_DOORBELL_STRIDE) == 0; + ionic_rxq_post(q, ring_doorbell, ionic_rx_clean, NULL); + continue; + } - desc = q->head->desc; - desc->addr = cpu_to_le64(dma_addr); - desc->len = cpu_to_le16(len); - desc->opcode = IONIC_RXQ_DESC_OPCODE_SIMPLE; + /* fill main descriptor - pages[0] */ + desc->opcode = (nfrags > 1) ? IONIC_RXQ_DESC_OPCODE_SG : + IONIC_RXQ_DESC_OPCODE_SIMPLE; + desc_info->npages = nfrags; + page_info->page = ionic_rx_page_alloc(q, &page_info->dma_addr); + if (unlikely(!page_info->page)) { + desc->addr = 0; + desc->len = 0; + return; + } + desc->addr = cpu_to_le64(page_info->dma_addr); + desc->len = cpu_to_le16(PAGE_SIZE); + page_info++; + + /* fill sg descriptors - pages[1..n] */ + for (j = 0; j < nfrags - 1; j++) { + if (page_info->page) /* recycle the sg buffer */ + continue; + + sg_elem = &sg_desc->elems[j]; + page_info->page = ionic_rx_page_alloc(q, &page_info->dma_addr); + if (unlikely(!page_info->page)) { + sg_elem->addr = 0; + sg_elem->len = 0; + return; + } + sg_elem->addr = cpu_to_le64(page_info->dma_addr); + sg_elem->len = cpu_to_le16(PAGE_SIZE); + page_info++; + } ring_doorbell = ((q->head->index + 1) & IONIC_RX_RING_DOORBELL_STRIDE) == 0; - - ionic_rxq_post(q, ring_doorbell, ionic_rx_clean, skb); + ionic_rxq_post(q, ring_doorbell, ionic_rx_clean, NULL); } } @@ -283,15 +402,26 @@ static void ionic_rx_fill_cb(void *arg) void ionic_rx_empty(struct ionic_queue *q) { - struct device *dev = q->lif->ionic->dev; + struct ionic_rxq_sg_desc *sg_desc; struct ionic_desc_info *cur; struct ionic_rxq_desc *desc; + unsigned int i; for (cur = q->tail; cur != q->head; cur = cur->next) { desc = cur->desc; - dma_unmap_single(dev, le64_to_cpu(desc->addr), - le16_to_cpu(desc->len), DMA_FROM_DEVICE); - dev_kfree_skb(cur->cb_arg); + desc->addr = 0; + desc->len = 0; + + sg_desc = cur->sg_desc; + for (i = 0; i < cur->npages; i++) { + if (likely(cur->pages[i].page)) { + ionic_rx_page_free(q, cur->pages[i].page, + cur->pages[i].dma_addr); + cur->pages[i].page = NULL; + cur->pages[i].dma_addr = 0; + } + } + cur->cb_arg = NULL; } } diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 74f81fe03810..91978ce92e20 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -741,12 +741,6 @@ static void rtl_unlock_config_regs(struct rtl8169_private *tp) RTL_W8(tp, Cfg9346, Cfg9346_Unlock); } -static void rtl_tx_performance_tweak(struct rtl8169_private *tp, u16 force) -{ - pcie_capability_clear_and_set_word(tp->pci_dev, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_READRQ, force); -} - static bool rtl_is_8125(struct rtl8169_private *tp) { return tp->mac_version >= RTL_GIGA_MAC_VER_60; @@ -1564,7 +1558,7 @@ static netdev_features_t rtl8169_fix_features(struct net_device *dev, if (dev->mtu > JUMBO_1K && tp->mac_version > RTL_GIGA_MAC_VER_06) - features &= ~NETIF_F_IP_CSUM; + features &= ~(NETIF_F_CSUM_MASK | NETIF_F_ALL_TSO); return features; } @@ -4032,14 +4026,12 @@ static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp) { RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); RTL_W8(tp, Config4, RTL_R8(tp, Config4) | Jumbo_En1); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_512B); } static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp) { RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~Jumbo_En1); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); } static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp) @@ -4057,7 +4049,6 @@ static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp) RTL_W8(tp, MaxTxPacketSize, 0x3f); RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); RTL_W8(tp, Config4, RTL_R8(tp, Config4) | 0x01); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_512B); } static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp) @@ -4065,32 +4056,15 @@ static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp) RTL_W8(tp, MaxTxPacketSize, 0x0c); RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~0x01); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); -} - -static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp) -{ - rtl_tx_performance_tweak(tp, - PCI_EXP_DEVCTL_READRQ_512B | PCI_EXP_DEVCTL_NOSNOOP_EN); -} - -static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp) -{ - rtl_tx_performance_tweak(tp, - PCI_EXP_DEVCTL_READRQ_4096B | PCI_EXP_DEVCTL_NOSNOOP_EN); } static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp) { - r8168b_0_hw_jumbo_enable(tp); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) | (1 << 0)); } static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp) { - r8168b_0_hw_jumbo_disable(tp); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0)); } @@ -4098,9 +4072,6 @@ static void rtl_hw_jumbo_enable(struct rtl8169_private *tp) { rtl_unlock_config_regs(tp); switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_11: - r8168b_0_hw_jumbo_enable(tp); - break; case RTL_GIGA_MAC_VER_12: case RTL_GIGA_MAC_VER_17: r8168b_1_hw_jumbo_enable(tp); @@ -4124,9 +4095,6 @@ static void rtl_hw_jumbo_disable(struct rtl8169_private *tp) { rtl_unlock_config_regs(tp); switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_11: - r8168b_0_hw_jumbo_disable(tp); - break; case RTL_GIGA_MAC_VER_12: case RTL_GIGA_MAC_VER_17: r8168b_1_hw_jumbo_disable(tp); @@ -4146,6 +4114,14 @@ static void rtl_hw_jumbo_disable(struct rtl8169_private *tp) rtl_lock_config_regs(tp); } +static void rtl_jumbo_config(struct rtl8169_private *tp, int mtu) +{ + if (mtu > ETH_DATA_LEN) + rtl_hw_jumbo_enable(tp); + else + rtl_hw_jumbo_disable(tp); +} + DECLARE_RTL_COND(rtl_chipcmd_cond) { return RTL_R8(tp, ChipCmd) & CmdReset; @@ -4439,21 +4415,9 @@ static void rtl8168g_set_pause_thresholds(struct rtl8169_private *tp, rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, high); } -static void rtl_hw_start_8168bb(struct rtl8169_private *tp) +static void rtl_hw_start_8168b(struct rtl8169_private *tp) { RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); - - if (tp->dev->mtu <= ETH_DATA_LEN) { - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B | - PCI_EXP_DEVCTL_NOSNOOP_EN); - } -} - -static void rtl_hw_start_8168bef(struct rtl8169_private *tp) -{ - rtl_hw_start_8168bb(tp); - - RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0)); } static void __rtl_hw_start_8168cp(struct rtl8169_private *tp) @@ -4462,9 +4426,6 @@ static void __rtl_hw_start_8168cp(struct rtl8169_private *tp) RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); - if (tp->dev->mtu <= ETH_DATA_LEN) - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_disable_clock_request(tp); } @@ -4490,9 +4451,6 @@ static void rtl_hw_start_8168cp_2(struct rtl8169_private *tp) rtl_set_def_aspm_entry_latency(tp); RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); - - if (tp->dev->mtu <= ETH_DATA_LEN) - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); } static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp) @@ -4503,9 +4461,6 @@ static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp) /* Magic. */ RTL_W8(tp, DBG_REG, 0x20); - - if (tp->dev->mtu <= ETH_DATA_LEN) - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); } static void rtl_hw_start_8168c_1(struct rtl8169_private *tp) @@ -4556,19 +4511,6 @@ static void rtl_hw_start_8168d(struct rtl8169_private *tp) rtl_set_def_aspm_entry_latency(tp); rtl_disable_clock_request(tp); - - if (tp->dev->mtu <= ETH_DATA_LEN) - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); -} - -static void rtl_hw_start_8168dp(struct rtl8169_private *tp) -{ - rtl_set_def_aspm_entry_latency(tp); - - if (tp->dev->mtu <= ETH_DATA_LEN) - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - - rtl_disable_clock_request(tp); } static void rtl_hw_start_8168d_4(struct rtl8169_private *tp) @@ -4582,8 +4524,6 @@ static void rtl_hw_start_8168d_4(struct rtl8169_private *tp) rtl_set_def_aspm_entry_latency(tp); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_ephy_init(tp, e_info_8168d_4); rtl_enable_clock_request(tp); @@ -4611,9 +4551,6 @@ static void rtl_hw_start_8168e_1(struct rtl8169_private *tp) rtl_ephy_init(tp, e_info_8168e_1); - if (tp->dev->mtu <= ETH_DATA_LEN) - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_disable_clock_request(tp); /* Reset tx FIFO pointer */ @@ -4636,9 +4573,6 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp) rtl_ephy_init(tp, e_info_8168e_2); - if (tp->dev->mtu <= ETH_DATA_LEN) - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000); rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000); rtl_set_fifo_size(tp, 0x10, 0x10, 0x02, 0x06); @@ -4664,8 +4598,6 @@ static void rtl_hw_start_8168f(struct rtl8169_private *tp) { rtl_set_def_aspm_entry_latency(tp); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000); rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000); rtl_set_fifo_size(tp, 0x10, 0x10, 0x02, 0x06); @@ -4728,8 +4660,6 @@ static void rtl_hw_start_8168g(struct rtl8169_private *tp) rtl_set_def_aspm_entry_latency(tp); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_reset_packet_filter(tp); rtl_eri_write(tp, 0x2f8, ERIAR_MASK_0011, 0x1d8f); @@ -4966,8 +4896,6 @@ static void rtl_hw_start_8168h_1(struct rtl8169_private *tp) rtl_set_def_aspm_entry_latency(tp); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_reset_packet_filter(tp); rtl_eri_set_bits(tp, 0xdc, ERIAR_MASK_1111, BIT(4)); @@ -5025,8 +4953,6 @@ static void rtl_hw_start_8168ep(struct rtl8169_private *tp) rtl_set_def_aspm_entry_latency(tp); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_reset_packet_filter(tp); rtl_eri_set_bits(tp, 0xd4, ERIAR_MASK_1111, 0x1f80); @@ -5129,8 +5055,6 @@ static void rtl_hw_start_8102e_1(struct rtl8169_private *tp) RTL_W8(tp, DBG_REG, FIX_NAK_1); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - RTL_W8(tp, Config1, LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable); RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); @@ -5146,8 +5070,6 @@ static void rtl_hw_start_8102e_2(struct rtl8169_private *tp) { rtl_set_def_aspm_entry_latency(tp); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - RTL_W8(tp, Config1, MEMMAP | IOMAP | VPD | PMEnable); RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); } @@ -5208,8 +5130,6 @@ static void rtl_hw_start_8402(struct rtl8169_private *tp) rtl_ephy_init(tp, e_info_8402); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_set_fifo_size(tp, 0x00, 0x00, 0x02, 0x06); rtl_reset_packet_filter(tp); rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000); @@ -5363,13 +5283,13 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_08] = rtl_hw_start_8102e_3, [RTL_GIGA_MAC_VER_09] = rtl_hw_start_8102e_2, [RTL_GIGA_MAC_VER_10] = NULL, - [RTL_GIGA_MAC_VER_11] = rtl_hw_start_8168bb, - [RTL_GIGA_MAC_VER_12] = rtl_hw_start_8168bef, + [RTL_GIGA_MAC_VER_11] = rtl_hw_start_8168b, + [RTL_GIGA_MAC_VER_12] = rtl_hw_start_8168b, [RTL_GIGA_MAC_VER_13] = NULL, [RTL_GIGA_MAC_VER_14] = NULL, [RTL_GIGA_MAC_VER_15] = NULL, [RTL_GIGA_MAC_VER_16] = NULL, - [RTL_GIGA_MAC_VER_17] = rtl_hw_start_8168bef, + [RTL_GIGA_MAC_VER_17] = rtl_hw_start_8168b, [RTL_GIGA_MAC_VER_18] = rtl_hw_start_8168cp_1, [RTL_GIGA_MAC_VER_19] = rtl_hw_start_8168c_1, [RTL_GIGA_MAC_VER_20] = rtl_hw_start_8168c_2, @@ -5383,7 +5303,7 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_28] = rtl_hw_start_8168d_4, [RTL_GIGA_MAC_VER_29] = rtl_hw_start_8105e_1, [RTL_GIGA_MAC_VER_30] = rtl_hw_start_8105e_2, - [RTL_GIGA_MAC_VER_31] = rtl_hw_start_8168dp, + [RTL_GIGA_MAC_VER_31] = rtl_hw_start_8168d, [RTL_GIGA_MAC_VER_32] = rtl_hw_start_8168e_1, [RTL_GIGA_MAC_VER_33] = rtl_hw_start_8168e_1, [RTL_GIGA_MAC_VER_34] = rtl_hw_start_8168e_2, @@ -5425,11 +5345,6 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) static void rtl_hw_start_8168(struct rtl8169_private *tp) { - if (tp->mac_version == RTL_GIGA_MAC_VER_13 || - tp->mac_version == RTL_GIGA_MAC_VER_16) - pcie_capability_set_word(tp->pci_dev, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_NOSNOOP_EN); - if (rtl_is_8168evl_up(tp)) RTL_W8(tp, MaxTxPacketSize, EarlySize); else @@ -5485,6 +5400,8 @@ static void rtl_hw_start(struct rtl8169_private *tp) rtl_set_rx_tx_desc_registers(tp); rtl_lock_config_regs(tp); + rtl_jumbo_config(tp, tp->dev->mtu); + /* Initially a 10 us delay. Turned it into a PCI commit. - FR */ RTL_R16(tp, CPlusCmd); RTL_W8(tp, ChipCmd, CmdTxEnb | CmdRxEnb); @@ -5498,10 +5415,7 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) { struct rtl8169_private *tp = netdev_priv(dev); - if (new_mtu > ETH_DATA_LEN) - rtl_hw_jumbo_enable(tp); - else - rtl_hw_jumbo_disable(tp); + rtl_jumbo_config(tp, new_mtu); dev->mtu = new_mtu; netdev_update_features(dev); @@ -5579,18 +5493,15 @@ static int rtl8169_rx_fill(struct rtl8169_private *tp) data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i); if (!data) { - rtl8169_make_unusable_by_asic(tp->RxDescArray + i); - goto err_out; + rtl8169_rx_clear(tp); + return -ENOMEM; } tp->Rx_databuff[i] = data; } rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1); - return 0; -err_out: - rtl8169_rx_clear(tp); - return -ENOMEM; + return 0; } static int rtl8169_init_ring(struct rtl8169_private *tp) diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index f9e6744d8fd6..869a498e3b5e 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -252,7 +252,6 @@ #define NETSEC_XDP_CONSUMED BIT(0) #define NETSEC_XDP_TX BIT(1) #define NETSEC_XDP_REDIR BIT(2) -#define NETSEC_XDP_RX_OK (NETSEC_XDP_PASS | NETSEC_XDP_TX | NETSEC_XDP_REDIR) enum ring_id { NETSEC_RING_TX = 0, @@ -661,6 +660,7 @@ static bool netsec_clean_tx_dring(struct netsec_priv *priv) bytes += desc->skb->len; dev_kfree_skb(desc->skb); } else { + bytes += desc->xdpf->len; xdp_return_frame(desc->xdpf); } next: @@ -847,8 +847,8 @@ static u32 netsec_xdp_queue_one(struct netsec_priv *priv, enum dma_data_direction dma_dir = page_pool_get_dma_dir(rx_ring->page_pool); - dma_handle = page_pool_get_dma_addr(page) + - NETSEC_RXBUF_HEADROOM; + dma_handle = page_pool_get_dma_addr(page) + xdpf->headroom + + sizeof(*xdpf); dma_sync_single_for_device(priv->dev, dma_handle, xdpf->len, dma_dir); tx_desc.buf_type = TYPE_NETSEC_XDP_TX; @@ -858,6 +858,7 @@ static u32 netsec_xdp_queue_one(struct netsec_priv *priv, tx_desc.addr = xdpf->data; tx_desc.len = xdpf->len; + netdev_sent_queue(priv->ndev, xdpf->len); netsec_set_tx_de(priv, tx_ring, &tx_ctrl, &tx_desc, xdpf); return NETSEC_XDP_TX; @@ -1030,7 +1031,7 @@ static int netsec_process_rx(struct netsec_priv *priv, int budget) next: if ((skb && napi_gro_receive(&priv->napi, skb) != GRO_DROP) || - xdp_result & NETSEC_XDP_RX_OK) { + xdp_result) { ndev->stats.rx_packets++; ndev->stats.rx_bytes += xdp.data_end - xdp.data; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index f97a4096f8fc..ddcc191febdb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -651,7 +651,8 @@ static void sun8i_dwmac_set_filter(struct mac_device_info *hw, } } } else { - netdev_info(dev, "Too many address, switching to promiscuous\n"); + if (!(readl(ioaddr + EMAC_RX_FRM_FLT) & EMAC_FRM_FLT_RXALL)) + netdev_info(dev, "Too many address, switching to promiscuous\n"); v = EMAC_FRM_FLT_RXALL; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index e552d7958114..bec929daf703 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -448,7 +448,7 @@ static void dwmac4_set_filter(struct mac_device_info *hw, value |= GMAC_PACKET_FILTER_HPF; /* Handle multiple unicast addresses */ - if (netdev_uc_count(dev) > GMAC_MAX_PERFECT_ADDRESSES) { + if (netdev_uc_count(dev) > hw->unicast_filter_entries) { /* Switch to promiscuous mode if more than 128 addrs * are required */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c index 3f4f3132e16b..e436fa160c7d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c @@ -515,6 +515,7 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index, if (!enable) { val |= PPSCMDx(index, 0x5); + val |= PPSEN0; writel(val, ioaddr + MAC_PPS_CONTROL); return 0; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 8b76745a7ec4..28705dbe5801 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2610,7 +2610,7 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) } if (priv->hw->pcs) - stmmac_pcs_ctrl_ane(priv, priv->hw, 1, priv->hw->ps, 0); + stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, priv->hw->ps, 0); /* set TX and RX rings length */ stmmac_set_rings_length(priv); @@ -4755,8 +4755,10 @@ int stmmac_suspend(struct device *dev) stmmac_mac_set(priv, priv->ioaddr, false); pinctrl_pm_select_sleep_state(priv->device); /* Disable clock in case of PWM is off */ - clk_disable(priv->plat->pclk); - clk_disable(priv->plat->stmmac_clk); + if (priv->plat->clk_ptp_ref) + clk_disable_unprepare(priv->plat->clk_ptp_ref); + clk_disable_unprepare(priv->plat->pclk); + clk_disable_unprepare(priv->plat->stmmac_clk); } mutex_unlock(&priv->lock); @@ -4819,8 +4821,10 @@ int stmmac_resume(struct device *dev) } else { pinctrl_pm_select_default_state(priv->device); /* enable the clk previously disabled */ - clk_enable(priv->plat->stmmac_clk); - clk_enable(priv->plat->pclk); + clk_prepare_enable(priv->plat->stmmac_clk); + clk_prepare_enable(priv->plat->pclk); + if (priv->plat->clk_ptp_ref) + clk_prepare_enable(priv->plat->clk_ptp_ref); /* reset the phy so that it's ready */ if (priv->mii) stmmac_mdio_reset(priv->mii); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c index 173493db038c..df638b18b72c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c @@ -164,7 +164,7 @@ static int stmmac_enable(struct ptp_clock_info *ptp, /* structure describing a PTP hardware clock */ static struct ptp_clock_info stmmac_ptp_clock_ops = { .owner = THIS_MODULE, - .name = "stmmac_ptp_clock", + .name = "stmmac ptp", .max_adj = 62500000, .n_alarm = 0, .n_ext_ts = 0, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c index 68c59cfb8f70..0b5db52149bc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c @@ -487,8 +487,8 @@ static int stmmac_filter_check(struct stmmac_priv *priv) static int stmmac_test_hfilt(struct stmmac_priv *priv) { - unsigned char gd_addr[ETH_ALEN] = {0x01, 0x00, 0xcc, 0xcc, 0xdd, 0xdd}; - unsigned char bd_addr[ETH_ALEN] = {0x09, 0x00, 0xaa, 0xaa, 0xbb, 0xbb}; + unsigned char gd_addr[ETH_ALEN] = {0x01, 0xee, 0xdd, 0xcc, 0xbb, 0xaa}; + unsigned char bd_addr[ETH_ALEN] = {0x01, 0x01, 0x02, 0x03, 0x04, 0x05}; struct stmmac_packet_attrs attr = { }; int ret; @@ -496,6 +496,9 @@ static int stmmac_test_hfilt(struct stmmac_priv *priv) if (ret) return ret; + if (netdev_mc_count(priv->dev) >= priv->hw->multicast_filter_bins) + return -EOPNOTSUPP; + ret = dev_mc_add(priv->dev, gd_addr); if (ret) return ret; @@ -573,6 +576,8 @@ static int stmmac_test_mcfilt(struct stmmac_priv *priv) if (stmmac_filter_check(priv)) return -EOPNOTSUPP; + if (!priv->hw->multicast_filter_bins) + return -EOPNOTSUPP; /* Remove all MC addresses */ __dev_mc_unsync(priv->dev, NULL); @@ -611,6 +616,8 @@ static int stmmac_test_ucfilt(struct stmmac_priv *priv) if (stmmac_filter_check(priv)) return -EOPNOTSUPP; + if (!priv->hw->multicast_filter_bins) + return -EOPNOTSUPP; /* Remove all UC addresses */ __dev_uc_unsync(priv->dev, NULL); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index e231098061b6..f9a9a9d82233 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -510,7 +510,7 @@ static struct stmmac_flow_entry *tc_find_flow(struct stmmac_priv *priv, return NULL; } -struct { +static struct { int (*fn)(struct stmmac_priv *priv, struct flow_cls_offload *cls, struct stmmac_flow_entry *entry); } tc_flow_parsers[] = { diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index a65edd2770e6..37ba708ac781 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -722,7 +722,7 @@ static void cpdma_chan_set_descs(struct cpdma_ctlr *ctlr, * cpdma_chan_split_pool - Splits ctrl pool between all channels. * Has to be called under ctlr lock */ -int cpdma_chan_split_pool(struct cpdma_ctlr *ctlr) +static int cpdma_chan_split_pool(struct cpdma_ctlr *ctlr) { int tx_per_ch_desc = 0, rx_per_ch_desc = 0; int free_rx_num = 0, free_tx_num = 0; diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index 8fc33867e524..af8eabe7a6d4 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -572,6 +572,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev) .name = _name, \ /* PHY_BASIC_FEATURES */ \ .flags = PHY_IS_INTERNAL, \ + .soft_reset = genphy_soft_reset, \ .config_init = bcm7xxx_config_init, \ .suspend = bcm7xxx_suspend, \ .resume = bcm7xxx_config_init, \ diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 4313c74b4fd8..7d68b28bb893 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -359,9 +359,9 @@ static int bcm5482_config_init(struct phy_device *phydev) /* * Select 1000BASE-X register set (primary SerDes) */ - reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE); - bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE, - reg | BCM5482_SHD_MODE_1000BX); + reg = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); + bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, + reg | BCM54XX_SHD_MODE_1000BX); /* * LED1=ACTIVITYLED, LED3=LINKSPD[2] @@ -427,12 +427,47 @@ static int bcm5481_config_aneg(struct phy_device *phydev) return ret; } +static int bcm54616s_probe(struct phy_device *phydev) +{ + int val, intf_sel; + + val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); + if (val < 0) + return val; + + /* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0] + * is 01b, and the link between PHY and its link partner can be + * either 1000Base-X or 100Base-FX. + * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX + * support is still missing as of now. + */ + intf_sel = (val & BCM54XX_SHD_INTF_SEL_MASK) >> 1; + if (intf_sel == 1) { + val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL); + if (val < 0) + return val; + + /* Bit 0 of the SerDes 100-FX Control register, when set + * to 1, sets the MII/RGMII -> 100BASE-FX configuration. + * When this bit is set to 0, it sets the GMII/RGMII -> + * 1000BASE-X configuration. + */ + if (!(val & BCM54616S_100FX_MODE)) + phydev->dev_flags |= PHY_BCM_FLAGS_MODE_1000BX; + } + + return 0; +} + static int bcm54616s_config_aneg(struct phy_device *phydev) { int ret; /* Aneg firsly. */ - ret = genphy_config_aneg(phydev); + if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) + ret = genphy_c37_config_aneg(phydev); + else + ret = genphy_config_aneg(phydev); /* Then we can set up the delay. */ bcm54xx_config_clock_delay(phydev); @@ -440,6 +475,18 @@ static int bcm54616s_config_aneg(struct phy_device *phydev) return ret; } +static int bcm54616s_read_status(struct phy_device *phydev) +{ + int err; + + if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) + err = genphy_c37_read_status(phydev); + else + err = genphy_read_status(phydev); + + return err; +} + static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) { int val; @@ -631,6 +678,8 @@ static struct phy_driver broadcom_drivers[] = { .config_aneg = bcm54616s_config_aneg, .ack_interrupt = bcm_phy_ack_intr, .config_intr = bcm_phy_config_intr, + .read_status = bcm54616s_read_status, + .probe = bcm54616s_probe, }, { .phy_id = PHY_ID_BCM5464, .phy_id_mask = 0xfffffff0, diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 37fceaf9fa10..5816a06a9439 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -95,6 +95,10 @@ #define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK (0x1f << 8) #define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT 8 +/* CFG3 bits */ +#define DP83867_CFG3_INT_OE BIT(7) +#define DP83867_CFG3_ROBUST_AUTO_MDIX BIT(9) + /* CFG4 bits */ #define DP83867_CFG4_PORT_MIRROR_EN BIT(0) @@ -295,7 +299,7 @@ static int dp83867_probe(struct phy_device *phydev) phydev->priv = dp83867; - return 0; + return dp83867_of_init(phydev); } static int dp83867_config_init(struct phy_device *phydev) @@ -304,10 +308,6 @@ static int dp83867_config_init(struct phy_device *phydev) int ret, val, bs; u16 delay; - ret = dp83867_of_init(phydev); - if (ret) - return ret; - /* RX_DV/RX_CTRL strapped in mode 1 or mode 2 workaround */ if (dp83867->rxctrl_strap_quirk) phy_clear_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4, @@ -410,12 +410,13 @@ static int dp83867_config_init(struct phy_device *phydev) phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_SGMIICTL, val); } + val = phy_read(phydev, DP83867_CFG3); /* Enable Interrupt output INT_OE in CFG3 register */ - if (phy_interrupt_is_valid(phydev)) { - val = phy_read(phydev, DP83867_CFG3); - val |= BIT(7); - phy_write(phydev, DP83867_CFG3, val); - } + if (phy_interrupt_is_valid(phydev)) + val |= DP83867_CFG3_INT_OE; + + val |= DP83867_CFG3_ROBUST_AUTO_MDIX; + phy_write(phydev, DP83867_CFG3, val); if (dp83867->port_mirroring != DP83867_PORT_MIRROING_KEEP) dp83867_config_port_mirroring(phydev); diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index a7796134e3be..0a814fde136a 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -53,12 +53,15 @@ #define MII_M1011_PHY_SCR 0x10 #define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11) -#define MII_M1011_PHY_SCR_DOWNSHIFT_SHIFT 12 -#define MII_M1011_PHY_SRC_DOWNSHIFT_MASK 0x7800 +#define MII_M1011_PHY_SRC_DOWNSHIFT_MASK GENMASK(14, 12) +#define MII_M1011_PHY_SCR_DOWNSHIFT_MAX 8 #define MII_M1011_PHY_SCR_MDI (0x0 << 5) #define MII_M1011_PHY_SCR_MDI_X (0x1 << 5) #define MII_M1011_PHY_SCR_AUTO_CROSS (0x3 << 5) +#define MII_M1011_PHY_SSR 0x11 +#define MII_M1011_PHY_SSR_DOWNSHIFT BIT(5) + #define MII_M1111_PHY_LED_CONTROL 0x18 #define MII_M1111_PHY_LED_DIRECT 0x4100 #define MII_M1111_PHY_LED_COMBINE 0x411c @@ -273,23 +276,6 @@ static int marvell_set_polarity(struct phy_device *phydev, int polarity) return val != reg; } -static int marvell_set_downshift(struct phy_device *phydev, bool enable, - u8 retries) -{ - int reg; - - reg = phy_read(phydev, MII_M1011_PHY_SCR); - if (reg < 0) - return reg; - - reg &= MII_M1011_PHY_SRC_DOWNSHIFT_MASK; - reg |= ((retries - 1) << MII_M1011_PHY_SCR_DOWNSHIFT_SHIFT); - if (enable) - reg |= MII_M1011_PHY_SCR_DOWNSHIFT_EN; - - return phy_write(phydev, MII_M1011_PHY_SCR, reg); -} - static int marvell_config_aneg(struct phy_device *phydev) { int changed = 0; @@ -658,41 +644,6 @@ static int marvell_config_init(struct phy_device *phydev) return marvell_of_reg_init(phydev); } -static int m88e1116r_config_init(struct phy_device *phydev) -{ - int err; - - err = genphy_soft_reset(phydev); - if (err < 0) - return err; - - msleep(500); - - err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); - if (err < 0) - return err; - - err = marvell_set_polarity(phydev, phydev->mdix_ctrl); - if (err < 0) - return err; - - err = marvell_set_downshift(phydev, true, 8); - if (err < 0) - return err; - - if (phy_interface_is_rgmii(phydev)) { - err = m88e1121_config_aneg_rgmii_delays(phydev); - if (err < 0) - return err; - } - - err = genphy_soft_reset(phydev); - if (err < 0) - return err; - - return marvell_config_init(phydev); -} - static int m88e3016_config_init(struct phy_device *phydev) { int ret; @@ -833,6 +784,114 @@ static int m88e1111_config_init(struct phy_device *phydev) return genphy_soft_reset(phydev); } +static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data) +{ + int val, cnt, enable; + + val = phy_read(phydev, MII_M1011_PHY_SCR); + if (val < 0) + return val; + + enable = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_EN, val); + cnt = FIELD_GET(MII_M1011_PHY_SRC_DOWNSHIFT_MASK, val) + 1; + + *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE; + + return 0; +} + +static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt) +{ + int val; + + if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX) + return -E2BIG; + + if (!cnt) + return phy_clear_bits(phydev, MII_M1011_PHY_SCR, + MII_M1011_PHY_SCR_DOWNSHIFT_EN); + + val = MII_M1011_PHY_SCR_DOWNSHIFT_EN; + val |= FIELD_PREP(MII_M1011_PHY_SRC_DOWNSHIFT_MASK, cnt - 1); + + return phy_modify(phydev, MII_M1011_PHY_SCR, + MII_M1011_PHY_SCR_DOWNSHIFT_EN | + MII_M1011_PHY_SRC_DOWNSHIFT_MASK, + val); +} + +static int m88e1111_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return m88e1111_get_downshift(phydev, data); + default: + return -EOPNOTSUPP; + } +} + +static int m88e1111_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return m88e1111_set_downshift(phydev, *(const u8 *)data); + default: + return -EOPNOTSUPP; + } +} + +static void m88e1111_link_change_notify(struct phy_device *phydev) +{ + int status; + + if (phydev->state != PHY_RUNNING) + return; + + /* we may be on fiber page currently */ + status = phy_read_paged(phydev, MII_MARVELL_COPPER_PAGE, + MII_M1011_PHY_SSR); + + if (status > 0 && status & MII_M1011_PHY_SSR_DOWNSHIFT) + phydev_warn(phydev, "Downshift occurred! Cabling may be defective.\n"); +} + +static int m88e1116r_config_init(struct phy_device *phydev) +{ + int err; + + err = genphy_soft_reset(phydev); + if (err < 0) + return err; + + msleep(500); + + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); + if (err < 0) + return err; + + err = marvell_set_polarity(phydev, phydev->mdix_ctrl); + if (err < 0) + return err; + + err = m88e1111_set_downshift(phydev, 8); + if (err < 0) + return err; + + if (phy_interface_is_rgmii(phydev)) { + err = m88e1121_config_aneg_rgmii_delays(phydev); + if (err < 0) + return err; + } + + err = genphy_soft_reset(phydev); + if (err < 0) + return err; + + return marvell_config_init(phydev); +} + static int m88e1318_config_init(struct phy_device *phydev) { if (phy_interrupt_is_valid(phydev)) { @@ -1117,6 +1176,8 @@ static int m88e1540_get_tunable(struct phy_device *phydev, switch (tuna->id) { case ETHTOOL_PHY_FAST_LINK_DOWN: return m88e1540_get_fld(phydev, data); + case ETHTOOL_PHY_DOWNSHIFT: + return m88e1111_get_downshift(phydev, data); default: return -EOPNOTSUPP; } @@ -1128,6 +1189,8 @@ static int m88e1540_set_tunable(struct phy_device *phydev, switch (tuna->id) { case ETHTOOL_PHY_FAST_LINK_DOWN: return m88e1540_set_fld(phydev, data); + case ETHTOOL_PHY_DOWNSHIFT: + return m88e1111_set_downshift(phydev, *(const u8 *)data); default: return -EOPNOTSUPP; } @@ -2220,6 +2283,9 @@ static struct phy_driver marvell_drivers[] = { .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, + .get_tunable = m88e1111_get_tunable, + .set_tunable = m88e1111_set_tunable, + .link_change_notify = m88e1111_link_change_notify, }, { .phy_id = MARVELL_PHY_ID_88E1318S, @@ -2359,6 +2425,7 @@ static struct phy_driver marvell_drivers[] = { .get_stats = marvell_get_stats, .get_tunable = m88e1540_get_tunable, .set_tunable = m88e1540_set_tunable, + .link_change_notify = m88e1111_link_change_notify, }, { .phy_id = MARVELL_PHY_ID_88E1545, @@ -2421,6 +2488,7 @@ static struct phy_driver marvell_drivers[] = { .get_stats = marvell_get_stats, .get_tunable = m88e1540_get_tunable, .set_tunable = m88e1540_set_tunable, + .link_change_notify = m88e1111_link_change_notify, }, }; diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 2fea5541c35a..63dedec0433d 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -341,6 +341,35 @@ static int ksz8041_config_aneg(struct phy_device *phydev) return genphy_config_aneg(phydev); } +static int ksz8051_ksz8795_match_phy_device(struct phy_device *phydev, + const u32 ksz_phy_id) +{ + int ret; + + if ((phydev->phy_id & MICREL_PHY_ID_MASK) != ksz_phy_id) + return 0; + + ret = phy_read(phydev, MII_BMSR); + if (ret < 0) + return ret; + + /* KSZ8051 PHY and KSZ8794/KSZ8795/KSZ8765 switch share the same + * exact PHY ID. However, they can be told apart by the extended + * capability registers presence. The KSZ8051 PHY has them while + * the switch does not. + */ + ret &= BMSR_ERCAP; + if (ksz_phy_id == PHY_ID_KSZ8051) + return ret; + else + return !ret; +} + +static int ksz8051_match_phy_device(struct phy_device *phydev) +{ + return ksz8051_ksz8795_match_phy_device(phydev, PHY_ID_KSZ8051); +} + static int ksz8081_config_init(struct phy_device *phydev) { /* KSZPHY_OMSO_FACTORY_TEST is set at de-assertion of the reset line @@ -364,6 +393,11 @@ static int ksz8061_config_init(struct phy_device *phydev) return kszphy_config_init(phydev); } +static int ksz8795_match_phy_device(struct phy_device *phydev) +{ + return ksz8051_ksz8795_match_phy_device(phydev, PHY_ID_KSZ87XX); +} + static int ksz9021_load_values_from_of(struct phy_device *phydev, const struct device_node *of_node, u16 reg, @@ -1017,8 +1051,6 @@ static struct phy_driver ksphy_driver[] = { .suspend = genphy_suspend, .resume = genphy_resume, }, { - .phy_id = PHY_ID_KSZ8051, - .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8051", /* PHY_BASIC_FEATURES */ .driver_data = &ksz8051_type, @@ -1029,6 +1061,7 @@ static struct phy_driver ksphy_driver[] = { .get_sset_count = kszphy_get_sset_count, .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, + .match_phy_device = ksz8051_match_phy_device, .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -1141,13 +1174,12 @@ static struct phy_driver ksphy_driver[] = { .suspend = genphy_suspend, .resume = genphy_resume, }, { - .phy_id = PHY_ID_KSZ8795, - .phy_id_mask = MICREL_PHY_ID_MASK, - .name = "Micrel KSZ8795", + .name = "Micrel KSZ87XX Switch", /* PHY_BASIC_FEATURES */ .config_init = kszphy_config_init, .config_aneg = ksz8873mll_config_aneg, .read_status = ksz8873mll_read_status, + .match_phy_device = ksz8795_match_phy_device, .suspend = genphy_suspend, .resume = genphy_resume, }, { diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index 7935593debb1..a1caeee12236 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -323,6 +323,8 @@ int genphy_c45_read_pma(struct phy_device *phydev) { int val; + linkmode_zero(phydev->lp_advertising); + val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1); if (val < 0) return val; diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index 9412669b579c..5458ed1b87a8 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -8,7 +8,7 @@ const char *phy_speed_to_str(int speed) { - BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 69, + BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 74, "Enum ethtool_link_mode_bit_indices and phylib are out of sync. " "If a speed or mode has been added please update phy_speed_to_str " "and the PHY settings array.\n"); @@ -42,6 +42,8 @@ const char *phy_speed_to_str(int speed) return "100Gbps"; case SPEED_200000: return "200Gbps"; + case SPEED_400000: + return "400Gbps"; case SPEED_UNKNOWN: return "Unknown"; default: @@ -70,6 +72,12 @@ EXPORT_SYMBOL_GPL(phy_duplex_to_str); .bit = ETHTOOL_LINK_MODE_ ## b ## _BIT} static const struct phy_setting settings[] = { + /* 400G */ + PHY_SETTING( 400000, FULL, 400000baseCR8_Full ), + PHY_SETTING( 400000, FULL, 400000baseKR8_Full ), + PHY_SETTING( 400000, FULL, 400000baseLR8_ER8_FR8_Full ), + PHY_SETTING( 400000, FULL, 400000baseDR8_Full ), + PHY_SETTING( 400000, FULL, 400000baseSR8_Full ), /* 200G */ PHY_SETTING( 200000, FULL, 200000baseCR4_Full ), PHY_SETTING( 200000, FULL, 200000baseKR4_Full ), @@ -689,11 +697,17 @@ EXPORT_SYMBOL_GPL(phy_modify_mmd); static int __phy_read_page(struct phy_device *phydev) { + if (WARN_ONCE(!phydev->drv->read_page, "read_page callback not available, PHY driver not loaded?\n")) + return -EOPNOTSUPP; + return phydev->drv->read_page(phydev); } static int __phy_write_page(struct phy_device *phydev, int page) { + if (WARN_ONCE(!phydev->drv->write_page, "write_page callback not available, PHY driver not loaded?\n")) + return -EOPNOTSUPP; + return phydev->drv->write_page(phydev, page); } diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 119e6f466056..105d389b58e7 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -572,9 +572,6 @@ int phy_start_aneg(struct phy_device *phydev) if (AUTONEG_DISABLE == phydev->autoneg) phy_sanitize_settings(phydev); - /* Invalidate LP advertising flags */ - linkmode_zero(phydev->lp_advertising); - err = phy_config_aneg(phydev); if (err < 0) goto out_unlock; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 9d2bbb13293e..fa71998fea51 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1270,7 +1270,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, phydev_err(phydev, "error creating 'phy_standalone' sysfs entry\n"); } - phydev->dev_flags = flags; + phydev->dev_flags |= flags; phydev->interface = interface; @@ -1608,6 +1608,40 @@ static int genphy_config_advert(struct phy_device *phydev) } /** + * genphy_c37_config_advert - sanitize and advertise auto-negotiation parameters + * @phydev: target phy_device struct + * + * Description: Writes MII_ADVERTISE with the appropriate values, + * after sanitizing the values to make sure we only advertise + * what is supported. Returns < 0 on error, 0 if the PHY's advertisement + * hasn't changed, and > 0 if it has changed. This function is intended + * for Clause 37 1000Base-X mode. + */ +static int genphy_c37_config_advert(struct phy_device *phydev) +{ + u16 adv = 0; + + /* Only allow advertising what this PHY supports */ + linkmode_and(phydev->advertising, phydev->advertising, + phydev->supported); + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + phydev->advertising)) + adv |= ADVERTISE_1000XFULL; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, + phydev->advertising)) + adv |= ADVERTISE_1000XPAUSE; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, + phydev->advertising)) + adv |= ADVERTISE_1000XPSE_ASYM; + + return phy_modify_changed(phydev, MII_ADVERTISE, + ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE | + ADVERTISE_1000XHALF | ADVERTISE_1000XPSE_ASYM, + adv); +} + +/** * genphy_config_eee_advert - disable unwanted eee mode advertisement * @phydev: target phy_device struct * @@ -1716,6 +1750,54 @@ int __genphy_config_aneg(struct phy_device *phydev, bool changed) EXPORT_SYMBOL(__genphy_config_aneg); /** + * genphy_c37_config_aneg - restart auto-negotiation or write BMCR + * @phydev: target phy_device struct + * + * Description: If auto-negotiation is enabled, we configure the + * advertising, and then restart auto-negotiation. If it is not + * enabled, then we write the BMCR. This function is intended + * for use with Clause 37 1000Base-X mode. + */ +int genphy_c37_config_aneg(struct phy_device *phydev) +{ + int err, changed; + + if (phydev->autoneg != AUTONEG_ENABLE) + return genphy_setup_forced(phydev); + + err = phy_modify(phydev, MII_BMCR, BMCR_SPEED1000 | BMCR_SPEED100, + BMCR_SPEED1000); + if (err) + return err; + + changed = genphy_c37_config_advert(phydev); + if (changed < 0) /* error */ + return changed; + + if (!changed) { + /* Advertisement hasn't changed, but maybe aneg was never on to + * begin with? Or maybe phy was isolated? + */ + int ctl = phy_read(phydev, MII_BMCR); + + if (ctl < 0) + return ctl; + + if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) + changed = 1; /* do restart aneg */ + } + + /* Only restart aneg if we are advertising something different + * than we were before. + */ + if (changed > 0) + return genphy_restart_aneg(phydev); + + return 0; +} +EXPORT_SYMBOL(genphy_c37_config_aneg); + +/** * genphy_aneg_done - return auto-negotiation status * @phydev: target phy_device struct * @@ -1787,7 +1869,14 @@ int genphy_read_lpa(struct phy_device *phydev) { int lpa, lpagb; - if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) { + if (phydev->autoneg == AUTONEG_ENABLE) { + if (!phydev->autoneg_complete) { + mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, + 0); + mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, 0); + return 0; + } + if (phydev->is_gigabit_capable) { lpagb = phy_read(phydev, MII_STAT1000); if (lpagb < 0) @@ -1815,6 +1904,8 @@ int genphy_read_lpa(struct phy_device *phydev) return lpa; mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa); + } else { + linkmode_zero(phydev->lp_advertising); } return 0; @@ -1878,6 +1969,63 @@ int genphy_read_status(struct phy_device *phydev) EXPORT_SYMBOL(genphy_read_status); /** + * genphy_c37_read_status - check the link status and update current link state + * @phydev: target phy_device struct + * + * Description: Check the link, then figure out the current state + * by comparing what we advertise with what the link partner + * advertises. This function is for Clause 37 1000Base-X mode. + */ +int genphy_c37_read_status(struct phy_device *phydev) +{ + int lpa, err, old_link = phydev->link; + + /* Update the link, but return if there was an error */ + err = genphy_update_link(phydev); + if (err) + return err; + + /* why bother the PHY if nothing can have changed */ + if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) + return 0; + + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; + + if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) { + lpa = phy_read(phydev, MII_LPA); + if (lpa < 0) + return lpa; + + linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + phydev->lp_advertising, lpa & LPA_LPACK); + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + phydev->lp_advertising, lpa & LPA_1000XFULL); + linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, + phydev->lp_advertising, lpa & LPA_1000XPAUSE); + linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, + phydev->lp_advertising, + lpa & LPA_1000XPAUSE_ASYM); + + phy_resolve_aneg_linkmode(phydev); + } else if (phydev->autoneg == AUTONEG_DISABLE) { + int bmcr = phy_read(phydev, MII_BMCR); + + if (bmcr < 0) + return bmcr; + + if (bmcr & BMCR_FULLDPLX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + } + + return 0; +} +EXPORT_SYMBOL(genphy_c37_read_status); + +/** * genphy_soft_reset - software reset the PHY via BMCR_RESET bit * @phydev: target phy_device struct * diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index a5a57ca94c1a..be7a2c0fa59b 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -117,9 +117,7 @@ static int phylink_is_empty_linkmode(const unsigned long *linkmode) phylink_set(tmp, Pause); phylink_set(tmp, Asym_Pause); - bitmap_andnot(tmp, linkmode, tmp, __ETHTOOL_LINK_MODE_MASK_NBITS); - - return linkmode_empty(tmp); + return linkmode_subset(linkmode, tmp); } static const char *phylink_an_mode_str(unsigned int mode) @@ -550,33 +548,24 @@ static const struct sfp_upstream_ops sfp_phylink_ops; static int phylink_register_sfp(struct phylink *pl, struct fwnode_handle *fwnode) { - struct fwnode_reference_args ref; + struct sfp_bus *bus; int ret; - if (!fwnode) - return 0; - - ret = fwnode_property_get_reference_args(fwnode, "sfp", NULL, - 0, 0, &ref); - if (ret < 0) { - if (ret == -ENOENT) - return 0; - - phylink_err(pl, "unable to parse \"sfp\" node: %d\n", - ret); + bus = sfp_register_upstream_node(fwnode, pl, &sfp_phylink_ops); + if (IS_ERR(bus)) { + ret = PTR_ERR(bus); + phylink_err(pl, "unable to attach SFP bus: %d\n", ret); return ret; } - pl->sfp_bus = sfp_register_upstream(ref.fwnode, pl, &sfp_phylink_ops); - if (!pl->sfp_bus) - return -ENOMEM; + pl->sfp_bus = bus; return 0; } /** * phylink_create() - create a phylink instance - * @ndev: a pointer to the &struct net_device + * @config: a pointer to the target &struct phylink_config * @fwnode: a pointer to a &struct fwnode_handle describing the network * interface * @iface: the desired link mode defined by &typedef phy_interface_t @@ -1728,8 +1717,7 @@ static int phylink_sfp_module_insert(void *upstream, if (phy_interface_mode_is_8023z(iface) && pl->phydev) return -EINVAL; - changed = !bitmap_equal(pl->supported, support, - __ETHTOOL_LINK_MODE_MASK_NBITS); + changed = !linkmode_equal(pl->supported, support); if (changed) { linkmode_copy(pl->supported, support); linkmode_copy(pl->link_config.advertising, config.advertising); diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c index b23fc41896ef..d037aab6a71d 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c @@ -4,6 +4,7 @@ #include <linux/list.h> #include <linux/mutex.h> #include <linux/phylink.h> +#include <linux/property.h> #include <linux/rtnetlink.h> #include <linux/slab.h> @@ -445,45 +446,63 @@ static void sfp_upstream_clear(struct sfp_bus *bus) } /** - * sfp_register_upstream() - Register the neighbouring device - * @fwnode: firmware node for the SFP bus + * sfp_register_upstream_node() - parse and register the neighbouring device + * @fwnode: firmware node for the parent device (MAC or PHY) * @upstream: the upstream private data * @ops: the upstream's &struct sfp_upstream_ops * - * Register the upstream device (eg, PHY) with the SFP bus. MAC drivers - * should use phylink, which will call this function for them. Returns - * a pointer to the allocated &struct sfp_bus. + * Parse the parent device's firmware node for a SFP bus, and register the + * SFP bus using sfp_register_upstream(). * - * On error, returns %NULL. + * Returns: on success, a pointer to the sfp_bus structure, + * %NULL if no SFP is specified, + * on failure, an error pointer value: + * corresponding to the errors detailed for + * fwnode_property_get_reference_args(). + * %-ENOMEM if we failed to allocate the bus. + * an error from the upstream's connect_phy() method. */ -struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode, - void *upstream, - const struct sfp_upstream_ops *ops) +struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode, + void *upstream, + const struct sfp_upstream_ops *ops) { - struct sfp_bus *bus = sfp_bus_get(fwnode); - int ret = 0; + struct fwnode_reference_args ref; + struct sfp_bus *bus; + int ret; - if (bus) { - rtnl_lock(); - bus->upstream_ops = ops; - bus->upstream = upstream; + ret = fwnode_property_get_reference_args(fwnode, "sfp", NULL, + 0, 0, &ref); + if (ret == -ENOENT) + return NULL; + else if (ret < 0) + return ERR_PTR(ret); - if (bus->sfp) { - ret = sfp_register_bus(bus); - if (ret) - sfp_upstream_clear(bus); - } - rtnl_unlock(); + bus = sfp_bus_get(ref.fwnode); + fwnode_handle_put(ref.fwnode); + if (!bus) + return ERR_PTR(-ENOMEM); + + rtnl_lock(); + bus->upstream_ops = ops; + bus->upstream = upstream; + + if (bus->sfp) { + ret = sfp_register_bus(bus); + if (ret) + sfp_upstream_clear(bus); + } else { + ret = 0; } + rtnl_unlock(); if (ret) { sfp_bus_put(bus); - bus = NULL; + bus = ERR_PTR(ret); } return bus; } -EXPORT_SYMBOL_GPL(sfp_register_upstream); +EXPORT_SYMBOL_GPL(sfp_register_upstream_node); /** * sfp_unregister_upstream() - Unregister sfp bus diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 0413d182d782..dab6cccfeb52 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -526,8 +526,8 @@ static void tun_flow_update(struct tun_struct *tun, u32 rxhash, e = tun_flow_find(head, rxhash); if (likely(e)) { /* TODO: keep queueing to old queue until it's empty? */ - if (e->queue_index != queue_index) - e->queue_index = queue_index; + if (READ_ONCE(e->queue_index) != queue_index) + WRITE_ONCE(e->queue_index, queue_index); if (e->updated != jiffies) e->updated = jiffies; sock_rps_record_flow_hash(e->rps_rxhash); diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index a505b2ab88b8..74849da031fa 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -186,7 +186,7 @@ struct hso_tiocmget { int intr_completed; struct usb_endpoint_descriptor *endp; struct urb *urb; - struct hso_serial_state_notification serial_state_notification; + struct hso_serial_state_notification *serial_state_notification; u16 prev_UART_state_bitmap; struct uart_icount icount; }; @@ -1432,7 +1432,7 @@ static int tiocmget_submit_urb(struct hso_serial *serial, usb_rcvintpipe(usb, tiocmget->endp-> bEndpointAddress & 0x7F), - &tiocmget->serial_state_notification, + tiocmget->serial_state_notification, sizeof(struct hso_serial_state_notification), tiocmget_intr_callback, serial, tiocmget->endp->bInterval); @@ -1479,7 +1479,7 @@ static void tiocmget_intr_callback(struct urb *urb) /* wIndex should be the USB interface number of the port to which the * notification applies, which should always be the Modem port. */ - serial_state_notification = &tiocmget->serial_state_notification; + serial_state_notification = tiocmget->serial_state_notification; if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE || serial_state_notification->bNotification != B_NOTIFICATION || le16_to_cpu(serial_state_notification->wValue) != W_VALUE || @@ -2565,6 +2565,8 @@ static void hso_free_tiomget(struct hso_serial *serial) usb_free_urb(tiocmget->urb); tiocmget->urb = NULL; serial->tiocmget = NULL; + kfree(tiocmget->serial_state_notification); + tiocmget->serial_state_notification = NULL; kfree(tiocmget); } } @@ -2615,10 +2617,13 @@ static struct hso_device *hso_create_bulk_serial_device( num_urbs = 2; serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget), GFP_KERNEL); + serial->tiocmget->serial_state_notification + = kzalloc(sizeof(struct hso_serial_state_notification), + GFP_KERNEL); /* it isn't going to break our heart if serial->tiocmget * allocation fails don't bother checking this. */ - if (serial->tiocmget) { + if (serial->tiocmget && serial->tiocmget->serial_state_notification) { tiocmget = serial->tiocmget; tiocmget->endp = hso_get_ep(interface, USB_ENDPOINT_XFER_INT, diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 58f5a219fb65..f8c0818e56c9 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -3782,10 +3782,14 @@ static int lan78xx_probe(struct usb_interface *intf, /* driver requires remote-wakeup capability during autosuspend. */ intf->needs_remote_wakeup = 1; + ret = lan78xx_phy_init(dev); + if (ret < 0) + goto out4; + ret = register_netdev(netdev); if (ret != 0) { netif_err(dev, probe, netdev, "couldn't register the device\n"); - goto out4; + goto out5; } usb_set_intfdata(intf, dev); @@ -3798,14 +3802,10 @@ static int lan78xx_probe(struct usb_interface *intf, pm_runtime_set_autosuspend_delay(&udev->dev, DEFAULT_AUTOSUSPEND_DELAY); - ret = lan78xx_phy_init(dev); - if (ret < 0) - goto out5; - return 0; out5: - unregister_netdev(netdev); + phy_disconnect(netdev->phydev); out4: usb_free_urb(dev->urb_intr); out3: @@ -3992,9 +3992,6 @@ static int lan78xx_suspend(struct usb_interface *intf, pm_message_t message) struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); u32 buf; int ret; - int event; - - event = message.event; if (!dev->suspend_count++) { spin_lock_irq(&dev->txq.lock); diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 3d77cd402ba9..596428ec71df 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1327,6 +1327,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1040, 2)}, /* Telit LE922A */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x1050, 2)}, /* Telit FN980 */ {QMI_FIXED_INTF(0x1bc7, 0x1100, 3)}, /* Telit ME910 */ {QMI_FIXED_INTF(0x1bc7, 0x1101, 3)}, /* Telit ME910 dual modem */ {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */ diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 54a83f734ede..283b35a76cf0 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -24,9 +24,11 @@ #include <linux/suspend.h> #include <linux/atomic.h> #include <linux/acpi.h> +#include <linux/firmware.h> +#include <crypto/hash.h> /* Information for net-next */ -#define NETNEXT_VERSION "10" +#define NETNEXT_VERSION "11" /* Information for net */ #define NET_VERSION "10" @@ -54,8 +56,11 @@ #define PLA_BDC_CR 0xd1a0 #define PLA_TEREDO_TIMER 0xd2cc #define PLA_REALWOW_TIMER 0xd2e8 +#define PLA_UPHY_TIMER 0xd388 #define PLA_SUSPEND_FLAG 0xd38a #define PLA_INDICATE_FALG 0xd38c +#define PLA_MACDBG_PRE 0xd38c /* RTL_VER_04 only */ +#define PLA_MACDBG_POST 0xd38e /* RTL_VER_04 only */ #define PLA_EXTRA_STATUS 0xd398 #define PLA_EFUSE_DATA 0xdd00 #define PLA_EFUSE_CMD 0xdd02 @@ -110,7 +115,12 @@ #define USB_CONNECT_TIMER 0xcbf8 #define USB_MSC_TIMER 0xcbfc #define USB_BURST_SIZE 0xcfc0 +#define USB_FW_FIX_EN0 0xcfca +#define USB_FW_FIX_EN1 0xcfcc #define USB_LPM_CONFIG 0xcfd8 +#define USB_CSTMR 0xcfef /* RTL8153A */ +#define USB_FW_CTRL 0xd334 /* RTL8153B */ +#define USB_FC_TIMER 0xd340 #define USB_USB_CTRL 0xd406 #define USB_PHY_CTRL 0xd408 #define USB_TX_AGG 0xd40a @@ -126,6 +136,7 @@ #define USB_LPM_CTRL 0xd41a #define USB_BMU_RESET 0xd4b0 #define USB_U1U2_TIMER 0xd4da +#define USB_FW_TASK 0xd4e8 /* RTL8153B */ #define USB_UPS_CTRL 0xd800 #define USB_POWER_CUT 0xd80a #define USB_MISC_0 0xd81a @@ -133,18 +144,19 @@ #define USB_AFE_CTRL2 0xd824 #define USB_UPS_CFG 0xd842 #define USB_UPS_FLAGS 0xd848 +#define USB_WDT1_CTRL 0xe404 #define USB_WDT11_CTRL 0xe43c -#define USB_BP_BA 0xfc26 -#define USB_BP_0 0xfc28 -#define USB_BP_1 0xfc2a -#define USB_BP_2 0xfc2c -#define USB_BP_3 0xfc2e -#define USB_BP_4 0xfc30 -#define USB_BP_5 0xfc32 -#define USB_BP_6 0xfc34 -#define USB_BP_7 0xfc36 -#define USB_BP_EN 0xfc38 -#define USB_BP_8 0xfc38 +#define USB_BP_BA PLA_BP_BA +#define USB_BP_0 PLA_BP_0 +#define USB_BP_1 PLA_BP_1 +#define USB_BP_2 PLA_BP_2 +#define USB_BP_3 PLA_BP_3 +#define USB_BP_4 PLA_BP_4 +#define USB_BP_5 PLA_BP_5 +#define USB_BP_6 PLA_BP_6 +#define USB_BP_7 PLA_BP_7 +#define USB_BP_EN PLA_BP_EN /* RTL8153A */ +#define USB_BP_8 0xfc38 /* RTL8153B */ #define USB_BP_9 0xfc3a #define USB_BP_10 0xfc3c #define USB_BP_11 0xfc3e @@ -175,6 +187,7 @@ #define OCP_PHY_STATE 0xa708 /* nway state for 8153 */ #define OCP_PHY_PATCH_STAT 0xb800 #define OCP_PHY_PATCH_CMD 0xb820 +#define OCP_PHY_LOCK 0xb82e #define OCP_ADC_IOFFSET 0xbcfc #define OCP_ADC_CFG 0xbc06 #define OCP_SYSCLK_CFG 0xc416 @@ -185,6 +198,7 @@ #define SRAM_10M_AMP1 0x8080 #define SRAM_10M_AMP2 0x8082 #define SRAM_IMPEDANCE 0x8084 +#define SRAM_PHY_LOCK 0xb82e /* PLA_RCR */ #define RCR_AAP 0x00000001 @@ -346,7 +360,12 @@ /* PLA_INDICATE_FALG */ #define UPCOMING_RUNTIME_D3 BIT(0) +/* PLA_MACDBG_PRE and PLA_MACDBG_POST */ +#define DEBUG_OE BIT(0) +#define DEBUG_LTSSM 0x0082 + /* PLA_EXTRA_STATUS */ +#define U3P3_CHECK_EN BIT(7) /* RTL_VER_05 only */ #define LINK_CHANGE_FLAG BIT(8) /* USB_USB2PHY */ @@ -368,6 +387,12 @@ #define STAT_SPEED_HIGH 0x0000 #define STAT_SPEED_FULL 0x0002 +/* USB_FW_FIX_EN0 */ +#define FW_FIX_SUSPEND BIT(14) + +/* USB_FW_FIX_EN1 */ +#define FW_IP_RESET_EN BIT(9) + /* USB_LPM_CONFIG */ #define LPM_U1U2_EN BIT(0) @@ -392,12 +417,24 @@ #define OWN_UPDATE BIT(0) #define OWN_CLEAR BIT(1) +/* USB_FW_TASK */ +#define FC_PATCH_TASK BIT(1) + /* USB_UPS_CTRL */ #define POWER_CUT 0x0100 /* USB_PM_CTRL_STATUS */ #define RESUME_INDICATE 0x0001 +/* USB_CSTMR */ +#define FORCE_SUPER BIT(0) + +/* USB_FW_CTRL */ +#define FLOW_CTRL_PATCH_OPT BIT(1) + +/* USB_FC_TIMER */ +#define CTRL_TIMER_EN BIT(15) + /* USB_USB_CTRL */ #define RX_AGG_DISABLE 0x0010 #define RX_ZERO_EN 0x0080 @@ -419,6 +456,9 @@ #define COALESCE_HIGH 250000U #define COALESCE_SLOW 524280U +/* USB_WDT1_CTRL */ +#define WTD1_EN BIT(0) + /* USB_WDT11_CTRL */ #define TIMER11_EN 0x0001 @@ -539,6 +579,9 @@ enum spd_duplex { /* OCP_PHY_PATCH_CMD */ #define PATCH_REQUEST BIT(4) +/* OCP_PHY_LOCK */ +#define PATCH_LOCK BIT(0) + /* OCP_ADC_CFG */ #define CKADSEL_L 0x0100 #define ADC_EN 0x0080 @@ -563,6 +606,9 @@ enum spd_duplex { /* SRAM_IMPEDANCE */ #define RX_DRIVING_MASK 0x6000 +/* SRAM_PHY_LOCK */ +#define PHY_PATCH_LOCK 0x0001 + /* MAC PASSTHRU */ #define AD_MASK 0xfee0 #define BND_MASK 0x0004 @@ -570,6 +616,8 @@ enum spd_duplex { #define EFUSE 0xcfdb #define PASS_THRU_MASK 0x1 +#define BP4_SUPER_ONLY 0x1578 /* RTL_VER_04 only */ + enum rtl_register_content { _1000bps = 0x10, _100bps = 0x08, @@ -766,6 +814,19 @@ struct r8152 { u32 ctap_short_off:1; } ups_info; +#define RTL_VER_SIZE 32 + + struct rtl_fw { + const char *fw_name; + const struct firmware *fw; + + char version[RTL_VER_SIZE]; + int (*pre_fw)(struct r8152 *tp); + int (*post_fw)(struct r8152 *tp); + + bool retry; + } rtl_fw; + atomic_t rx_count; bool eee_en; @@ -788,6 +849,131 @@ struct r8152 { u8 autoneg; }; +/** + * struct fw_block - block type and total length + * @type: type of the current block, such as RTL_FW_END, RTL_FW_PLA, + * RTL_FW_USB and so on. + * @length: total length of the current block. + */ +struct fw_block { + __le32 type; + __le32 length; +} __packed; + +/** + * struct fw_header - header of the firmware file + * @checksum: checksum of sha256 which is calculated from the whole file + * except the checksum field of the file. That is, calculate sha256 + * from the version field to the end of the file. + * @version: version of this firmware. + * @blocks: the first firmware block of the file + */ +struct fw_header { + u8 checksum[32]; + char version[RTL_VER_SIZE]; + struct fw_block blocks[0]; +} __packed; + +/** + * struct fw_mac - a firmware block used by RTL_FW_PLA and RTL_FW_USB. + * The layout of the firmware block is: + * <struct fw_mac> + <info> + <firmware data>. + * @fw_offset: offset of the firmware binary data. The start address of + * the data would be the address of struct fw_mac + @fw_offset. + * @fw_reg: the register to load the firmware. Depends on chip. + * @bp_ba_addr: the register to write break point base address. Depends on + * chip. + * @bp_ba_value: break point base address. Depends on chip. + * @bp_en_addr: the register to write break point enabled mask. Depends + * on chip. + * @bp_en_value: break point enabled mask. Depends on the firmware. + * @bp_start: the start register of break points. Depends on chip. + * @bp_num: the break point number which needs to be set for this firmware. + * Depends on the firmware. + * @bp: break points. Depends on firmware. + * @fw_ver_reg: the register to store the fw version. + * @fw_ver_data: the firmware version of the current type. + * @info: additional information for debugging, and is followed by the + * binary data of firmware. + */ +struct fw_mac { + struct fw_block blk_hdr; + __le16 fw_offset; + __le16 fw_reg; + __le16 bp_ba_addr; + __le16 bp_ba_value; + __le16 bp_en_addr; + __le16 bp_en_value; + __le16 bp_start; + __le16 bp_num; + __le16 bp[16]; /* any value determined by firmware */ + __le32 reserved; + __le16 fw_ver_reg; + u8 fw_ver_data; + char info[0]; +} __packed; + +/** + * struct fw_phy_patch_key - a firmware block used by RTL_FW_PHY_START. + * This is used to set patch key when loading the firmware of PHY. + * @key_reg: the register to write the patch key. + * @key_data: patch key. + */ +struct fw_phy_patch_key { + struct fw_block blk_hdr; + __le16 key_reg; + __le16 key_data; + __le32 reserved; +} __packed; + +/** + * struct fw_phy_nc - a firmware block used by RTL_FW_PHY_NC. + * The layout of the firmware block is: + * <struct fw_phy_nc> + <info> + <firmware data>. + * @fw_offset: offset of the firmware binary data. The start address of + * the data would be the address of struct fw_phy_nc + @fw_offset. + * @fw_reg: the register to load the firmware. Depends on chip. + * @ba_reg: the register to write the base address. Depends on chip. + * @ba_data: base address. Depends on chip. + * @patch_en_addr: the register of enabling patch mode. Depends on chip. + * @patch_en_value: patch mode enabled mask. Depends on the firmware. + * @mode_reg: the regitster of switching the mode. + * @mod_pre: the mode needing to be set before loading the firmware. + * @mod_post: the mode to be set when finishing to load the firmware. + * @bp_start: the start register of break points. Depends on chip. + * @bp_num: the break point number which needs to be set for this firmware. + * Depends on the firmware. + * @bp: break points. Depends on firmware. + * @info: additional information for debugging, and is followed by the + * binary data of firmware. + */ +struct fw_phy_nc { + struct fw_block blk_hdr; + __le16 fw_offset; + __le16 fw_reg; + __le16 ba_reg; + __le16 ba_data; + __le16 patch_en_addr; + __le16 patch_en_value; + __le16 mode_reg; + __le16 mode_pre; + __le16 mode_post; + __le16 reserved; + __le16 bp_start; + __le16 bp_num; + __le16 bp[4]; + char info[0]; +} __packed; + +enum rtl_fw_type { + RTL_FW_END = 0, + RTL_FW_PLA, + RTL_FW_USB, + RTL_FW_PHY_START, + RTL_FW_PHY_STOP, + RTL_FW_PHY_NC, +}; + enum rtl_version { RTL_VER_UNKNOWN = 0, RTL_VER_01, @@ -3226,6 +3412,688 @@ static void rtl_reset_bmu(struct r8152 *tp) ocp_write_byte(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data); } +/* Clear the bp to stop the firmware before loading a new one */ +static void rtl_clear_bp(struct r8152 *tp, u16 type) +{ + switch (tp->version) { + case RTL_VER_01: + case RTL_VER_02: + case RTL_VER_07: + break; + case RTL_VER_03: + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + ocp_write_byte(tp, type, PLA_BP_EN, 0); + break; + case RTL_VER_08: + case RTL_VER_09: + default: + if (type == MCU_TYPE_USB) { + ocp_write_byte(tp, MCU_TYPE_USB, USB_BP2_EN, 0); + + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_8, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_9, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_10, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_11, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_12, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_13, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_14, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_15, 0); + } else { + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0); + } + break; + } + + ocp_write_word(tp, type, PLA_BP_0, 0); + ocp_write_word(tp, type, PLA_BP_1, 0); + ocp_write_word(tp, type, PLA_BP_2, 0); + ocp_write_word(tp, type, PLA_BP_3, 0); + ocp_write_word(tp, type, PLA_BP_4, 0); + ocp_write_word(tp, type, PLA_BP_5, 0); + ocp_write_word(tp, type, PLA_BP_6, 0); + ocp_write_word(tp, type, PLA_BP_7, 0); + + /* wait 3 ms to make sure the firmware is stopped */ + usleep_range(3000, 6000); + ocp_write_word(tp, type, PLA_BP_BA, 0); +} + +static int r8153_patch_request(struct r8152 *tp, bool request) +{ + u16 data; + int i; + + data = ocp_reg_read(tp, OCP_PHY_PATCH_CMD); + if (request) + data |= PATCH_REQUEST; + else + data &= ~PATCH_REQUEST; + ocp_reg_write(tp, OCP_PHY_PATCH_CMD, data); + + for (i = 0; request && i < 5000; i++) { + usleep_range(1000, 2000); + if (ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY) + break; + } + + if (request && !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) { + netif_err(tp, drv, tp->netdev, "patch request fail\n"); + r8153_patch_request(tp, false); + return -ETIME; + } else { + return 0; + } +} + +static int r8153_pre_ram_code(struct r8152 *tp, u16 key_addr, u16 patch_key) +{ + if (r8153_patch_request(tp, true)) { + dev_err(&tp->intf->dev, "patch request fail\n"); + return -ETIME; + } + + sram_write(tp, key_addr, patch_key); + sram_write(tp, SRAM_PHY_LOCK, PHY_PATCH_LOCK); + + return 0; +} + +static int r8153_post_ram_code(struct r8152 *tp, u16 key_addr) +{ + u16 data; + + sram_write(tp, 0x0000, 0x0000); + + data = ocp_reg_read(tp, OCP_PHY_LOCK); + data &= ~PATCH_LOCK; + ocp_reg_write(tp, OCP_PHY_LOCK, data); + + sram_write(tp, key_addr, 0x0000); + + r8153_patch_request(tp, false); + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, tp->ocp_base); + + return 0; +} + +static bool rtl8152_is_fw_phy_nc_ok(struct r8152 *tp, struct fw_phy_nc *phy) +{ + u32 length; + u16 fw_offset, fw_reg, ba_reg, patch_en_addr, mode_reg, bp_start; + bool rc = false; + + switch (tp->version) { + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + fw_reg = 0xa014; + ba_reg = 0xa012; + patch_en_addr = 0xa01a; + mode_reg = 0xb820; + bp_start = 0xa000; + break; + default: + goto out; + } + + fw_offset = __le16_to_cpu(phy->fw_offset); + if (fw_offset < sizeof(*phy)) { + dev_err(&tp->intf->dev, "fw_offset too small\n"); + goto out; + } + + length = __le32_to_cpu(phy->blk_hdr.length); + if (length < fw_offset) { + dev_err(&tp->intf->dev, "invalid fw_offset\n"); + goto out; + } + + length -= __le16_to_cpu(phy->fw_offset); + if (!length || (length & 1)) { + dev_err(&tp->intf->dev, "invalid block length\n"); + goto out; + } + + if (__le16_to_cpu(phy->fw_reg) != fw_reg) { + dev_err(&tp->intf->dev, "invalid register to load firmware\n"); + goto out; + } + + if (__le16_to_cpu(phy->ba_reg) != ba_reg) { + dev_err(&tp->intf->dev, "invalid base address register\n"); + goto out; + } + + if (__le16_to_cpu(phy->patch_en_addr) != patch_en_addr) { + dev_err(&tp->intf->dev, + "invalid patch mode enabled register\n"); + goto out; + } + + if (__le16_to_cpu(phy->mode_reg) != mode_reg) { + dev_err(&tp->intf->dev, + "invalid register to switch the mode\n"); + goto out; + } + + if (__le16_to_cpu(phy->bp_start) != bp_start) { + dev_err(&tp->intf->dev, + "invalid start register of break point\n"); + goto out; + } + + if (__le16_to_cpu(phy->bp_num) > 4) { + dev_err(&tp->intf->dev, "invalid break point number\n"); + goto out; + } + + rc = true; +out: + return rc; +} + +static bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac) +{ + u16 fw_reg, bp_ba_addr, bp_en_addr, bp_start, fw_offset; + bool rc = false; + u32 length, type; + int i, max_bp; + + type = __le32_to_cpu(mac->blk_hdr.type); + if (type == RTL_FW_PLA) { + switch (tp->version) { + case RTL_VER_01: + case RTL_VER_02: + case RTL_VER_07: + fw_reg = 0xf800; + bp_ba_addr = PLA_BP_BA; + bp_en_addr = 0; + bp_start = PLA_BP_0; + max_bp = 8; + break; + case RTL_VER_03: + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + case RTL_VER_08: + case RTL_VER_09: + fw_reg = 0xf800; + bp_ba_addr = PLA_BP_BA; + bp_en_addr = PLA_BP_EN; + bp_start = PLA_BP_0; + max_bp = 8; + break; + default: + goto out; + } + } else if (type == RTL_FW_USB) { + switch (tp->version) { + case RTL_VER_03: + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + fw_reg = 0xf800; + bp_ba_addr = USB_BP_BA; + bp_en_addr = USB_BP_EN; + bp_start = USB_BP_0; + max_bp = 8; + break; + case RTL_VER_08: + case RTL_VER_09: + fw_reg = 0xe600; + bp_ba_addr = USB_BP_BA; + bp_en_addr = USB_BP2_EN; + bp_start = USB_BP_0; + max_bp = 16; + break; + case RTL_VER_01: + case RTL_VER_02: + case RTL_VER_07: + default: + goto out; + } + } else { + goto out; + } + + fw_offset = __le16_to_cpu(mac->fw_offset); + if (fw_offset < sizeof(*mac)) { + dev_err(&tp->intf->dev, "fw_offset too small\n"); + goto out; + } + + length = __le32_to_cpu(mac->blk_hdr.length); + if (length < fw_offset) { + dev_err(&tp->intf->dev, "invalid fw_offset\n"); + goto out; + } + + length -= fw_offset; + if (length < 4 || (length & 3)) { + dev_err(&tp->intf->dev, "invalid block length\n"); + goto out; + } + + if (__le16_to_cpu(mac->fw_reg) != fw_reg) { + dev_err(&tp->intf->dev, "invalid register to load firmware\n"); + goto out; + } + + if (__le16_to_cpu(mac->bp_ba_addr) != bp_ba_addr) { + dev_err(&tp->intf->dev, "invalid base address register\n"); + goto out; + } + + if (__le16_to_cpu(mac->bp_en_addr) != bp_en_addr) { + dev_err(&tp->intf->dev, "invalid enabled mask register\n"); + goto out; + } + + if (__le16_to_cpu(mac->bp_start) != bp_start) { + dev_err(&tp->intf->dev, + "invalid start register of break point\n"); + goto out; + } + + if (__le16_to_cpu(mac->bp_num) > max_bp) { + dev_err(&tp->intf->dev, "invalid break point number\n"); + goto out; + } + + for (i = __le16_to_cpu(mac->bp_num); i < max_bp; i++) { + if (mac->bp[i]) { + dev_err(&tp->intf->dev, "unused bp%u is not zero\n", i); + goto out; + } + } + + rc = true; +out: + return rc; +} + +/* Verify the checksum for the firmware file. It is calculated from the version + * field to the end of the file. Compare the result with the checksum field to + * make sure the file is correct. + */ +static long rtl8152_fw_verify_checksum(struct r8152 *tp, + struct fw_header *fw_hdr, size_t size) +{ + unsigned char checksum[sizeof(fw_hdr->checksum)]; + struct crypto_shash *alg; + struct shash_desc *sdesc; + size_t len; + long rc; + + alg = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(alg)) { + rc = PTR_ERR(alg); + goto out; + } + + if (crypto_shash_digestsize(alg) != sizeof(fw_hdr->checksum)) { + rc = -EFAULT; + dev_err(&tp->intf->dev, "digestsize incorrect (%u)\n", + crypto_shash_digestsize(alg)); + goto free_shash; + } + + len = sizeof(*sdesc) + crypto_shash_descsize(alg); + sdesc = kmalloc(len, GFP_KERNEL); + if (!sdesc) { + rc = -ENOMEM; + goto free_shash; + } + sdesc->tfm = alg; + + len = size - sizeof(fw_hdr->checksum); + rc = crypto_shash_digest(sdesc, fw_hdr->version, len, checksum); + kfree(sdesc); + if (rc) + goto free_shash; + + if (memcmp(fw_hdr->checksum, checksum, sizeof(fw_hdr->checksum))) { + dev_err(&tp->intf->dev, "checksum fail\n"); + rc = -EFAULT; + } + +free_shash: + crypto_free_shash(alg); +out: + return rc; +} + +static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) +{ + const struct firmware *fw = rtl_fw->fw; + struct fw_header *fw_hdr = (struct fw_header *)fw->data; + struct fw_mac *pla = NULL, *usb = NULL; + struct fw_phy_patch_key *start = NULL; + struct fw_phy_nc *phy_nc = NULL; + struct fw_block *stop = NULL; + long ret = -EFAULT; + int i; + + if (fw->size < sizeof(*fw_hdr)) { + dev_err(&tp->intf->dev, "file too small\n"); + goto fail; + } + + ret = rtl8152_fw_verify_checksum(tp, fw_hdr, fw->size); + if (ret) + goto fail; + + ret = -EFAULT; + + for (i = sizeof(*fw_hdr); i < fw->size;) { + struct fw_block *block = (struct fw_block *)&fw->data[i]; + u32 type; + + if ((i + sizeof(*block)) > fw->size) + goto fail; + + type = __le32_to_cpu(block->type); + switch (type) { + case RTL_FW_END: + if (__le32_to_cpu(block->length) != sizeof(*block)) + goto fail; + goto fw_end; + case RTL_FW_PLA: + if (pla) { + dev_err(&tp->intf->dev, + "multiple PLA firmware encountered"); + goto fail; + } + + pla = (struct fw_mac *)block; + if (!rtl8152_is_fw_mac_ok(tp, pla)) { + dev_err(&tp->intf->dev, + "check PLA firmware failed\n"); + goto fail; + } + break; + case RTL_FW_USB: + if (usb) { + dev_err(&tp->intf->dev, + "multiple USB firmware encountered"); + goto fail; + } + + usb = (struct fw_mac *)block; + if (!rtl8152_is_fw_mac_ok(tp, usb)) { + dev_err(&tp->intf->dev, + "check USB firmware failed\n"); + goto fail; + } + break; + case RTL_FW_PHY_START: + if (start || phy_nc || stop) { + dev_err(&tp->intf->dev, + "check PHY_START fail\n"); + goto fail; + } + + if (__le32_to_cpu(block->length) != sizeof(*start)) { + dev_err(&tp->intf->dev, + "Invalid length for PHY_START\n"); + goto fail; + } + + start = (struct fw_phy_patch_key *)block; + break; + case RTL_FW_PHY_STOP: + if (stop || !start) { + dev_err(&tp->intf->dev, + "Check PHY_STOP fail\n"); + goto fail; + } + + if (__le32_to_cpu(block->length) != sizeof(*block)) { + dev_err(&tp->intf->dev, + "Invalid length for PHY_STOP\n"); + goto fail; + } + + stop = block; + break; + case RTL_FW_PHY_NC: + if (!start || stop) { + dev_err(&tp->intf->dev, + "check PHY_NC fail\n"); + goto fail; + } + + if (phy_nc) { + dev_err(&tp->intf->dev, + "multiple PHY NC encountered\n"); + goto fail; + } + + phy_nc = (struct fw_phy_nc *)block; + if (!rtl8152_is_fw_phy_nc_ok(tp, phy_nc)) { + dev_err(&tp->intf->dev, + "check PHY NC firmware failed\n"); + goto fail; + } + + break; + default: + dev_warn(&tp->intf->dev, "Unknown type %u is found\n", + type); + break; + } + + /* next block */ + i += ALIGN(__le32_to_cpu(block->length), 8); + } + +fw_end: + if ((phy_nc || start) && !stop) { + dev_err(&tp->intf->dev, "without PHY_STOP\n"); + goto fail; + } + + return 0; +fail: + return ret; +} + +static void rtl8152_fw_phy_nc_apply(struct r8152 *tp, struct fw_phy_nc *phy) +{ + u16 mode_reg, bp_index; + u32 length, i, num; + __le16 *data; + + mode_reg = __le16_to_cpu(phy->mode_reg); + sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_pre)); + sram_write(tp, __le16_to_cpu(phy->ba_reg), + __le16_to_cpu(phy->ba_data)); + + length = __le32_to_cpu(phy->blk_hdr.length); + length -= __le16_to_cpu(phy->fw_offset); + num = length / 2; + data = (__le16 *)((u8 *)phy + __le16_to_cpu(phy->fw_offset)); + + ocp_reg_write(tp, OCP_SRAM_ADDR, __le16_to_cpu(phy->fw_reg)); + for (i = 0; i < num; i++) + ocp_reg_write(tp, OCP_SRAM_DATA, __le16_to_cpu(data[i])); + + sram_write(tp, __le16_to_cpu(phy->patch_en_addr), + __le16_to_cpu(phy->patch_en_value)); + + bp_index = __le16_to_cpu(phy->bp_start); + num = __le16_to_cpu(phy->bp_num); + for (i = 0; i < num; i++) { + sram_write(tp, bp_index, __le16_to_cpu(phy->bp[i])); + bp_index += 2; + } + + sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_post)); + + dev_dbg(&tp->intf->dev, "successfully applied %s\n", phy->info); +} + +static void rtl8152_fw_mac_apply(struct r8152 *tp, struct fw_mac *mac) +{ + u16 bp_en_addr, bp_index, type, bp_num, fw_ver_reg; + u32 length; + u8 *data; + int i; + + switch (__le32_to_cpu(mac->blk_hdr.type)) { + case RTL_FW_PLA: + type = MCU_TYPE_PLA; + break; + case RTL_FW_USB: + type = MCU_TYPE_USB; + break; + default: + return; + } + + rtl_clear_bp(tp, type); + + /* Enable backup/restore of MACDBG. This is required after clearing PLA + * break points and before applying the PLA firmware. + */ + if (tp->version == RTL_VER_04 && type == MCU_TYPE_PLA && + !(ocp_read_word(tp, MCU_TYPE_PLA, PLA_MACDBG_POST) & DEBUG_OE)) { + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MACDBG_PRE, DEBUG_LTSSM); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MACDBG_POST, DEBUG_LTSSM); + } + + length = __le32_to_cpu(mac->blk_hdr.length); + length -= __le16_to_cpu(mac->fw_offset); + + data = (u8 *)mac; + data += __le16_to_cpu(mac->fw_offset); + + generic_ocp_write(tp, __le16_to_cpu(mac->fw_reg), 0xff, length, data, + type); + + ocp_write_word(tp, type, __le16_to_cpu(mac->bp_ba_addr), + __le16_to_cpu(mac->bp_ba_value)); + + bp_index = __le16_to_cpu(mac->bp_start); + bp_num = __le16_to_cpu(mac->bp_num); + for (i = 0; i < bp_num; i++) { + ocp_write_word(tp, type, bp_index, __le16_to_cpu(mac->bp[i])); + bp_index += 2; + } + + bp_en_addr = __le16_to_cpu(mac->bp_en_addr); + if (bp_en_addr) + ocp_write_word(tp, type, bp_en_addr, + __le16_to_cpu(mac->bp_en_value)); + + fw_ver_reg = __le16_to_cpu(mac->fw_ver_reg); + if (fw_ver_reg) + ocp_write_byte(tp, MCU_TYPE_USB, fw_ver_reg, + mac->fw_ver_data); + + dev_dbg(&tp->intf->dev, "successfully applied %s\n", mac->info); +} + +static void rtl8152_apply_firmware(struct r8152 *tp) +{ + struct rtl_fw *rtl_fw = &tp->rtl_fw; + const struct firmware *fw; + struct fw_header *fw_hdr; + struct fw_phy_patch_key *key; + u16 key_addr = 0; + int i; + + if (IS_ERR_OR_NULL(rtl_fw->fw)) + return; + + fw = rtl_fw->fw; + fw_hdr = (struct fw_header *)fw->data; + + if (rtl_fw->pre_fw) + rtl_fw->pre_fw(tp); + + for (i = offsetof(struct fw_header, blocks); i < fw->size;) { + struct fw_block *block = (struct fw_block *)&fw->data[i]; + + switch (__le32_to_cpu(block->type)) { + case RTL_FW_END: + goto post_fw; + case RTL_FW_PLA: + case RTL_FW_USB: + rtl8152_fw_mac_apply(tp, (struct fw_mac *)block); + break; + case RTL_FW_PHY_START: + key = (struct fw_phy_patch_key *)block; + key_addr = __le16_to_cpu(key->key_reg); + r8153_pre_ram_code(tp, key_addr, + __le16_to_cpu(key->key_data)); + break; + case RTL_FW_PHY_STOP: + WARN_ON(!key_addr); + r8153_post_ram_code(tp, key_addr); + break; + case RTL_FW_PHY_NC: + rtl8152_fw_phy_nc_apply(tp, (struct fw_phy_nc *)block); + break; + default: + break; + } + + i += ALIGN(__le32_to_cpu(block->length), 8); + } + +post_fw: + if (rtl_fw->post_fw) + rtl_fw->post_fw(tp); + + strscpy(rtl_fw->version, fw_hdr->version, RTL_VER_SIZE); + dev_info(&tp->intf->dev, "load %s successfully\n", rtl_fw->version); +} + +static void rtl8152_release_firmware(struct r8152 *tp) +{ + struct rtl_fw *rtl_fw = &tp->rtl_fw; + + if (!IS_ERR_OR_NULL(rtl_fw->fw)) { + release_firmware(rtl_fw->fw); + rtl_fw->fw = NULL; + } +} + +static int rtl8152_request_firmware(struct r8152 *tp) +{ + struct rtl_fw *rtl_fw = &tp->rtl_fw; + long rc; + + if (rtl_fw->fw || !rtl_fw->fw_name) { + dev_info(&tp->intf->dev, "skip request firmware\n"); + rc = 0; + goto result; + } + + rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, &tp->intf->dev); + if (rc < 0) + goto result; + + rc = rtl8152_check_firmware(tp, rtl_fw); + if (rc < 0) + release_firmware(rtl_fw->fw); + +result: + if (rc) { + rtl_fw->fw = ERR_PTR(rc); + + dev_warn(&tp->intf->dev, + "unable to load firmware patch %s (%ld)\n", + rtl_fw->fw_name, rc); + } + + return rc; +} + static void r8152_aldps_en(struct r8152 *tp, bool enable) { if (enable) { @@ -3370,6 +4238,7 @@ static void rtl8152_disable(struct r8152 *tp) static void r8152b_hw_phy_cfg(struct r8152 *tp) { + rtl8152_apply_firmware(tp); rtl_eee_enable(tp, tp->eee_en); r8152_aldps_en(tp, true); r8152b_enable_fc(tp); @@ -3497,31 +4366,124 @@ static void r8152b_enter_oob(struct r8152 *tp) ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); } -static int r8153_patch_request(struct r8152 *tp, bool request) +static int r8153_pre_firmware_1(struct r8152 *tp) { - u16 data; int i; - data = ocp_reg_read(tp, OCP_PHY_PATCH_CMD); - if (request) - data |= PATCH_REQUEST; - else - data &= ~PATCH_REQUEST; - ocp_reg_write(tp, OCP_PHY_PATCH_CMD, data); + /* Wait till the WTD timer is ready. It would take at most 104 ms. */ + for (i = 0; i < 104; i++) { + u32 ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_WDT1_CTRL); - for (i = 0; request && i < 5000; i++) { - usleep_range(1000, 2000); - if (ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY) + if (!(ocp_data & WTD1_EN)) break; + usleep_range(1000, 2000); } - if (request && !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) { - netif_err(tp, drv, tp->netdev, "patch request fail\n"); - r8153_patch_request(tp, false); - return -ETIME; - } else { - return 0; + return 0; +} + +static int r8153_post_firmware_1(struct r8152 *tp) +{ + /* set USB_BP_4 to support USB_SPEED_SUPER only */ + if (ocp_read_byte(tp, MCU_TYPE_USB, USB_CSTMR) & FORCE_SUPER) + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_4, BP4_SUPER_ONLY); + + /* reset UPHY timer to 36 ms */ + ocp_write_word(tp, MCU_TYPE_PLA, PLA_UPHY_TIMER, 36000 / 16); + + return 0; +} + +static int r8153_pre_firmware_2(struct r8152 *tp) +{ + u32 ocp_data; + + r8153_pre_firmware_1(tp); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0); + ocp_data &= ~FW_FIX_SUSPEND; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0, ocp_data); + + return 0; +} + +static int r8153_post_firmware_2(struct r8152 *tp) +{ + u32 ocp_data; + + /* enable bp0 if support USB_SPEED_SUPER only */ + if (ocp_read_byte(tp, MCU_TYPE_USB, USB_CSTMR) & FORCE_SUPER) { + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BP_EN); + ocp_data |= BIT(0); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, ocp_data); + } + + /* reset UPHY timer to 36 ms */ + ocp_write_word(tp, MCU_TYPE_PLA, PLA_UPHY_TIMER, 36000 / 16); + + /* enable U3P3 check, set the counter to 4 */ + ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, U3P3_CHECK_EN | 4); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0); + ocp_data |= FW_FIX_SUSPEND; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0, ocp_data); + + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY); + ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND; + ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data); + + return 0; +} + +static int r8153_post_firmware_3(struct r8152 *tp) +{ + u32 ocp_data; + + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY); + ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND; + ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1); + ocp_data |= FW_IP_RESET_EN; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data); + + return 0; +} + +static int r8153b_pre_firmware_1(struct r8152 *tp) +{ + /* enable fc timer and set timer to 1 second. */ + ocp_write_word(tp, MCU_TYPE_USB, USB_FC_TIMER, + CTRL_TIMER_EN | (1000 / 8)); + + return 0; +} + +static int r8153b_post_firmware_1(struct r8152 *tp) +{ + u32 ocp_data; + + /* enable bp0 for RTL8153-BND */ + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_1); + if (ocp_data & BND_MASK) { + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BP_EN); + ocp_data |= BIT(0); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, ocp_data); } + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_CTRL); + ocp_data |= FLOW_CTRL_PATCH_OPT; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_CTRL, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK); + ocp_data |= FC_PATCH_TASK; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1); + ocp_data |= FW_IP_RESET_EN; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data); + + return 0; } static void r8153_aldps_en(struct r8152 *tp, bool enable) @@ -3558,6 +4520,8 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) /* disable EEE before updating the PHY parameters */ rtl_eee_enable(tp, false); + rtl8152_apply_firmware(tp); + if (tp->version == RTL_VER_03) { data = ocp_reg_read(tp, OCP_EEE_CFG); data &= ~CTAP_SHORT_EN; @@ -3630,6 +4594,8 @@ static void r8153b_hw_phy_cfg(struct r8152 *tp) /* disable EEE before updating the PHY parameters */ rtl_eee_enable(tp, false); + rtl8152_apply_firmware(tp); + r8153b_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags)); data = sram_read(tp, SRAM_GREEN_CFG); @@ -4156,11 +5122,22 @@ static void rtl_hw_phy_work_func_t(struct work_struct *work) mutex_lock(&tp->control); + if (rtl8152_request_firmware(tp) == -ENODEV && tp->rtl_fw.retry) { + tp->rtl_fw.retry = false; + tp->rtl_fw.fw = NULL; + + /* Delay execution in case request_firmware() is not ready yet. + */ + queue_delayed_work(system_long_wq, &tp->hw_phy_work, HZ * 10); + goto ignore_once; + } + tp->rtl_ops.hw_phy_cfg(tp); rtl8152_set_speed(tp, tp->autoneg, tp->speed, tp->duplex, tp->advertising); +ignore_once: mutex_unlock(&tp->control); usb_autopm_put_interface(tp->intf); @@ -4198,6 +5175,11 @@ static int rtl8152_open(struct net_device *netdev) struct r8152 *tp = netdev_priv(netdev); int res = 0; + if (work_busy(&tp->hw_phy_work.work) & WORK_BUSY_PENDING) { + cancel_delayed_work_sync(&tp->hw_phy_work); + rtl_hw_phy_work_func_t(&tp->hw_phy_work.work); + } + res = alloc_all_mem(tp); if (res) goto out; @@ -4844,6 +5826,9 @@ static void rtl8152_get_drvinfo(struct net_device *netdev, strlcpy(info->driver, MODULENAME, sizeof(info->driver)); strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); usb_make_path(tp->udev, info->bus_info, sizeof(info->bus_info)); + if (!IS_ERR_OR_NULL(tp->rtl_fw.fw)) + strlcpy(info->fw_version, tp->rtl_fw.version, + sizeof(info->fw_version)); } static @@ -5468,6 +6453,47 @@ static int rtl_ops_init(struct r8152 *tp) return ret; } +#define FIRMWARE_8153A_2 "rtl_nic/rtl8153a-2.fw" +#define FIRMWARE_8153A_3 "rtl_nic/rtl8153a-3.fw" +#define FIRMWARE_8153A_4 "rtl_nic/rtl8153a-4.fw" +#define FIRMWARE_8153B_2 "rtl_nic/rtl8153b-2.fw" + +MODULE_FIRMWARE(FIRMWARE_8153A_2); +MODULE_FIRMWARE(FIRMWARE_8153A_3); +MODULE_FIRMWARE(FIRMWARE_8153A_4); +MODULE_FIRMWARE(FIRMWARE_8153B_2); + +static int rtl_fw_init(struct r8152 *tp) +{ + struct rtl_fw *rtl_fw = &tp->rtl_fw; + + switch (tp->version) { + case RTL_VER_04: + rtl_fw->fw_name = FIRMWARE_8153A_2; + rtl_fw->pre_fw = r8153_pre_firmware_1; + rtl_fw->post_fw = r8153_post_firmware_1; + break; + case RTL_VER_05: + rtl_fw->fw_name = FIRMWARE_8153A_3; + rtl_fw->pre_fw = r8153_pre_firmware_2; + rtl_fw->post_fw = r8153_post_firmware_2; + break; + case RTL_VER_06: + rtl_fw->fw_name = FIRMWARE_8153A_4; + rtl_fw->post_fw = r8153_post_firmware_3; + break; + case RTL_VER_09: + rtl_fw->fw_name = FIRMWARE_8153B_2; + rtl_fw->pre_fw = r8153b_pre_firmware_1; + rtl_fw->post_fw = r8153b_post_firmware_1; + break; + default: + break; + } + + return 0; +} + static u8 rtl_get_version(struct usb_interface *intf) { struct usb_device *udev = interface_to_usbdev(intf); @@ -5575,6 +6601,8 @@ static int rtl8152_probe(struct usb_interface *intf, if (ret) goto out; + rtl_fw_init(tp); + mutex_init(&tp->control); INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t); INIT_DELAYED_WORK(&tp->hw_phy_work, rtl_hw_phy_work_func_t); @@ -5646,6 +6674,10 @@ static int rtl8152_probe(struct usb_interface *intf, intf->needs_remote_wakeup = 1; tp->rtl_ops.init(tp); +#if IS_BUILTIN(CONFIG_USB_RTL8152) + /* Retry in case request_firmware() is not ready yet. */ + tp->rtl_fw.retry = true; +#endif queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0); set_ethernet_addr(tp); @@ -5691,6 +6723,7 @@ static void rtl8152_disconnect(struct usb_interface *intf) tasklet_kill(&tp->tx_tl); cancel_delayed_work_sync(&tp->hw_phy_work); tp->rtl_ops.unload(tp); + rtl8152_release_firmware(tp); free_netdev(tp->netdev); } } diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c index c5d4a0060124..681e0def6356 100644 --- a/drivers/net/usb/sr9800.c +++ b/drivers/net/usb/sr9800.c @@ -335,7 +335,7 @@ static void sr_set_multicast(struct net_device *net) static int sr_mdio_read(struct net_device *net, int phy_id, int loc) { struct usbnet *dev = netdev_priv(net); - __le16 res; + __le16 res = 0; mutex_lock(&dev->phy_mutex); sr_set_sw_mii(dev); diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index dc45d16e8d21..383d4fa555a8 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2118,12 +2118,15 @@ static int ath10k_init_uart(struct ath10k *ar) return ret; } - if (!uart_print && ar->hw_params.uart_pin_workaround) { - ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, - ar->hw_params.uart_pin); - if (ret) { - ath10k_warn(ar, "failed to set UART TX pin: %d", ret); - return ret; + if (!uart_print) { + if (ar->hw_params.uart_pin_workaround) { + ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, + ar->hw_params.uart_pin); + if (ret) { + ath10k_warn(ar, "failed to set UART TX pin: %d", + ret); + return ret; + } } return 0; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 7573af2d88ce..c2db758b9d54 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -162,12 +162,13 @@ int iwl_acpi_get_mcc(struct device *dev, char *mcc) wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg) || tbl_rev != 0) { + if (IS_ERR(wifi_pkg)) { ret = PTR_ERR(wifi_pkg); goto out_free; } - if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || + tbl_rev != 0) { ret = -EINVAL; goto out_free; } @@ -224,12 +225,13 @@ int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg) || tbl_rev != 0) { + if (IS_ERR(wifi_pkg)) { ret = PTR_ERR(wifi_pkg); goto out_free; } - if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || + tbl_rev != 0) { ret = -EINVAL; goto out_free; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 5c8602de9168..87421807e040 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -646,6 +646,7 @@ static struct scatterlist *alloc_sgtable(int size) if (new_page) __free_page(new_page); } + kfree(table); return NULL; } alloc_size = min_t(int, size, PAGE_SIZE); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-io.h index f8e4f0f5de0c..f09e368c7040 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.h @@ -112,38 +112,38 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf); */ static inline u32 iwl_umac_prph(struct iwl_trans *trans, u32 ofs) { - return ofs + trans->cfg->trans.umac_prph_offset; + return ofs + trans->trans_cfg->umac_prph_offset; } static inline u32 iwl_read_umac_prph_no_grab(struct iwl_trans *trans, u32 ofs) { return iwl_read_prph_no_grab(trans, ofs + - trans->cfg->trans.umac_prph_offset); + trans->trans_cfg->umac_prph_offset); } static inline u32 iwl_read_umac_prph(struct iwl_trans *trans, u32 ofs) { - return iwl_read_prph(trans, ofs + trans->cfg->trans.umac_prph_offset); + return iwl_read_prph(trans, ofs + trans->trans_cfg->umac_prph_offset); } static inline void iwl_write_umac_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val) { - iwl_write_prph_no_grab(trans, ofs + trans->cfg->trans.umac_prph_offset, + iwl_write_prph_no_grab(trans, ofs + trans->trans_cfg->umac_prph_offset, val); } static inline void iwl_write_umac_prph(struct iwl_trans *trans, u32 ofs, u32 val) { - iwl_write_prph(trans, ofs + trans->cfg->trans.umac_prph_offset, val); + iwl_write_prph(trans, ofs + trans->trans_cfg->umac_prph_offset, val); } static inline int iwl_poll_umac_prph_bit(struct iwl_trans *trans, u32 addr, u32 bits, u32 mask, int timeout) { return iwl_poll_prph_bit(trans, addr + - trans->cfg->trans.umac_prph_offset, + trans->trans_cfg->umac_prph_offset, bits, mask, timeout); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 32a5e4e5461f..d9eb2b286438 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -420,6 +420,9 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) }; int ret; + if (mvm->trans->cfg->tx_with_siso_diversity) + init_cfg.init_flags |= cpu_to_le32(BIT(IWL_INIT_PHY)); + lockdep_assert_held(&mvm->mutex); mvm->rfkill_safe_init_done = false; @@ -694,12 +697,13 @@ static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, ACPI_WRDS_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg) || tbl_rev != 0) { + if (IS_ERR(wifi_pkg)) { ret = PTR_ERR(wifi_pkg); goto out_free; } - if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || + tbl_rev != 0) { ret = -EINVAL; goto out_free; } @@ -731,13 +735,14 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, ACPI_EWRD_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg) || tbl_rev != 0) { + if (IS_ERR(wifi_pkg)) { ret = PTR_ERR(wifi_pkg); goto out_free; } if ((wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) || - (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER)) { + (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) || + tbl_rev != 0) { ret = -EINVAL; goto out_free; } @@ -791,11 +796,16 @@ static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm) wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, ACPI_WGDS_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg) || tbl_rev > 1) { + if (IS_ERR(wifi_pkg)) { ret = PTR_ERR(wifi_pkg); goto out_free; } + if (tbl_rev != 0) { + ret = -EINVAL; + goto out_free; + } + mvm->geo_rev = tbl_rev; for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { for (j = 0; j < ACPI_GEO_TABLE_SIZE; j++) { @@ -889,15 +899,17 @@ static bool iwl_mvm_sar_geo_support(struct iwl_mvm *mvm) * firmware versions. Unfortunately, we don't have a TLV API * flag to rely on, so rely on the major version which is in * the first byte of ucode_ver. This was implemented - * initially on version 38 and then backported to29 and 17. - * The intention was to have it in 36 as well, but not all - * 8000 family got this feature enabled. The 8000 family is - * the only one using version 36, so skip this version - * entirely. + * initially on version 38 and then backported to 17. It was + * also backported to 29, but only for 7265D devices. The + * intention was to have it in 36 as well, but not all 8000 + * family got this feature enabled. The 8000 family is the + * only one using version 36, so skip this version entirely. */ return IWL_UCODE_SERIAL(mvm->fw->ucode_ver) >= 38 || - IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 29 || - IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 17; + IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 17 || + (IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 29 && + ((mvm->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == + CSR_HW_REV_TYPE_7265D)); } int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) @@ -1020,11 +1032,16 @@ static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, ACPI_PPAG_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg) || tbl_rev != 0) { + if (IS_ERR(wifi_pkg)) { ret = PTR_ERR(wifi_pkg); goto out_free; } + if (tbl_rev != 0) { + ret = -EINVAL; + goto out_free; + } + enabled = &wifi_pkg->package.elements[1]; if (enabled->type != ACPI_TYPE_INTEGER || (enabled->integer.value != 0 && enabled->integer.value != 1)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index cd1b10042fbf..d31f96c3f925 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4881,11 +4881,11 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, if (!iwl_mvm_has_new_rx_api(mvm)) return; - notif->cookie = mvm->queue_sync_cookie; - - if (notif->sync) + if (notif->sync) { + notif->cookie = mvm->queue_sync_cookie; atomic_set(&mvm->queue_sync_counter, mvm->trans->num_rx_queues); + } ret = iwl_mvm_notify_rx_queue(mvm, qmask, (u8 *)notif, size, !notif->sync); @@ -4905,7 +4905,8 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, out: atomic_set(&mvm->queue_sync_counter, 0); - mvm->queue_sync_cookie++; + if (notif->sync) + mvm->queue_sync_cookie++; } static void iwl_mvm_sync_rx_queues(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index 75fa8a6aafee..74980382e64c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -107,13 +107,9 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, /* allocate ucode sections in dram and set addresses */ ret = iwl_pcie_init_fw_sec(trans, fw, &prph_scratch->dram); - if (ret) { - dma_free_coherent(trans->dev, - sizeof(*prph_scratch), - prph_scratch, - trans_pcie->prph_scratch_dma_addr); - return ret; - } + if (ret) + goto err_free_prph_scratch; + /* Allocate prph information * currently we don't assign to the prph info anything, but it would get @@ -121,16 +117,20 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, prph_info = dma_alloc_coherent(trans->dev, sizeof(*prph_info), &trans_pcie->prph_info_dma_addr, GFP_KERNEL); - if (!prph_info) - return -ENOMEM; + if (!prph_info) { + ret = -ENOMEM; + goto err_free_prph_scratch; + } /* Allocate context info */ ctxt_info_gen3 = dma_alloc_coherent(trans->dev, sizeof(*ctxt_info_gen3), &trans_pcie->ctxt_info_dma_addr, GFP_KERNEL); - if (!ctxt_info_gen3) - return -ENOMEM; + if (!ctxt_info_gen3) { + ret = -ENOMEM; + goto err_free_prph_info; + } ctxt_info_gen3->prph_info_base_addr = cpu_to_le64(trans_pcie->prph_info_dma_addr); @@ -186,6 +186,20 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, iwl_set_bit(trans, CSR_GP_CNTRL, CSR_AUTO_FUNC_INIT); return 0; + +err_free_prph_info: + dma_free_coherent(trans->dev, + sizeof(*prph_info), + prph_info, + trans_pcie->prph_info_dma_addr); + +err_free_prph_scratch: + dma_free_coherent(trans->dev, + sizeof(*prph_scratch), + prph_scratch, + trans_pcie->prph_scratch_dma_addr); + return ret; + } void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index e29c47744ef5..6f4bb7ce71a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -513,31 +513,33 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24FD, 0x9074, iwl8265_2ac_cfg)}, /* 9000 Series */ - {IWL_PCI_DEVICE(0x02F0, 0x0030, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x0034, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x0038, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x003C, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x0060, iwl9461_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x0064, iwl9461_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x00A0, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x00A4, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x0230, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x0234, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x0238, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x023C, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x0260, iwl9461_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x0264, iwl9461_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x02A0, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x02A4, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x1551, iwl9560_killer_s_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x1552, iwl9560_killer_i_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x2030, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x2034, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x4030, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x4034, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x40A4, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x4234, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)}, - {IWL_PCI_DEVICE(0x02F0, 0x42A4, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x0030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x0034, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x0038, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x003C, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x0060, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x0064, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x00A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x00A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x0230, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x0234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x0238, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x023C, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x0260, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x0264, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x02A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x02A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x1030, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x1551, killer1550s_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x1552, killer1550i_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x2030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x2034, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x4030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x4034, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x40A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x4234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x42A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x06F0, 0x0030, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)}, {IWL_PCI_DEVICE(0x06F0, 0x0034, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)}, {IWL_PCI_DEVICE(0x06F0, 0x0038, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)}, @@ -643,34 +645,34 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2720, 0x40A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x42A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x0030, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x0034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x0038, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x003C, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x0060, iwl9460_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x0064, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x00A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x00A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x0230, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x0234, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x0238, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x023C, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x0260, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x0264, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x02A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x02A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x1010, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x30DC, 0x1030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x1210, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x30DC, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x1552, iwl9560_killer_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x2030, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x2034, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x4030, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x4034, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x40A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x4234, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x42A4, iwl9462_2ac_cfg_soc)}, + + {IWL_PCI_DEVICE(0x30DC, 0x0030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x0034, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x0038, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x003C, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x0060, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x0064, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x00A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x00A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x0230, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x0234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x0238, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x023C, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x0260, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x0264, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x02A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x02A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x1030, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x1551, killer1550s_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x1552, killer1550i_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x2030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x2034, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x4030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x4034, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x40A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x4234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x30DC, 0x42A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_160_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_160_cfg_shared_clk)}, @@ -726,62 +728,60 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x34F0, 0x4234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x42A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, - {IWL_PCI_DEVICE(0x3DF0, 0x0030, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x0034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x0038, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x003C, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x0060, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x0064, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x00A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x00A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x0230, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x0234, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x0238, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x023C, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x0260, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x0264, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x02A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x02A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x1010, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x3DF0, 0x1030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x1210, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x3DF0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x2030, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x2034, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x4030, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x4034, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x40A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x4234, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x42A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x0030, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x0034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x0038, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x003C, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x0060, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x0064, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x00A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x00A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x0230, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x0234, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x0238, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x023C, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x0260, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x0264, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x02A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x02A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x1010, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x43F0, 0x1030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x1210, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x43F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x2030, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x2034, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x4030, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x4034, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x40A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x4234, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0034, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0038, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x003C, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0060, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0064, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x00A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x00A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0230, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0238, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x023C, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0260, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0264, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x02A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x02A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x1030, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x1551, killer1550s_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x1552, killer1550i_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x2030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x2034, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x4030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x4034, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x40A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x4234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x42A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + + {IWL_PCI_DEVICE(0x43F0, 0x0030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x0034, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x0038, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x003C, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x0060, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x0064, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x00A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x00A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x0230, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x0234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x0238, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x023C, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x0260, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x0264, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x02A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x02A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x1030, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x1551, killer1550s_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x1552, killer1550i_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x2030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x2034, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x4030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x4034, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x40A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x4234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x42A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0030, iwl9560_2ac_160_cfg_soc)}, @@ -821,34 +821,34 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x9DF0, 0x40A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x42A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0030, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0038, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x003C, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0060, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0064, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x00A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x00A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0230, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0234, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0238, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x023C, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0260, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0264, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x02A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x02A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x1010, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0xA0F0, 0x1030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x1210, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0xA0F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x2030, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x2034, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x4030, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x4034, iwl9560_2ac_160_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x40A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x4234, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x42A4, iwl9462_2ac_cfg_soc)}, + + {IWL_PCI_DEVICE(0xA0F0, 0x0030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0034, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0038, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x003C, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0060, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0064, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x00A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x00A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0230, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0238, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x023C, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0260, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0264, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x02A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x02A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1030, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1551, killer1550s_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1552, killer1550i_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x2030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x2034, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x4030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x4034, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x40A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x4234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x42A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0xA370, 0x0030, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x0034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x0038, iwl9560_2ac_160_cfg_soc)}, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index f8a1f985a1d8..6961f00ff812 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3272,11 +3272,17 @@ static struct iwl_trans_dump_data ptr = cmdq->write_ptr; for (i = 0; i < cmdq->n_window; i++) { u8 idx = iwl_pcie_get_cmd_index(cmdq, ptr); + u8 tfdidx; u32 caplen, cmdlen; + if (trans->trans_cfg->use_tfh) + tfdidx = idx; + else + tfdidx = ptr; + cmdlen = iwl_trans_pcie_get_cmdlen(trans, - cmdq->tfds + - tfd_size * ptr); + (u8 *)cmdq->tfds + + tfd_size * tfdidx); caplen = min_t(u32, TFD_MAX_PAYLOAD_SIZE, cmdlen); if (cmdlen) { @@ -3450,6 +3456,15 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, spin_lock_init(&trans_pcie->reg_lock); mutex_init(&trans_pcie->mutex); init_waitqueue_head(&trans_pcie->ucode_write_waitq); + + trans_pcie->rba.alloc_wq = alloc_workqueue("rb_allocator", + WQ_HIGHPRI | WQ_UNBOUND, 1); + if (!trans_pcie->rba.alloc_wq) { + ret = -ENOMEM; + goto out_free_trans; + } + INIT_WORK(&trans_pcie->rba.rx_alloc, iwl_pcie_rx_allocator_work); + trans_pcie->tso_hdr_page = alloc_percpu(struct iwl_tso_hdr_page); if (!trans_pcie->tso_hdr_page) { ret = -ENOMEM; @@ -3584,10 +3599,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie->inta_mask = CSR_INI_SET_MASK; } - trans_pcie->rba.alloc_wq = alloc_workqueue("rb_allocator", - WQ_HIGHPRI | WQ_UNBOUND, 1); - INIT_WORK(&trans_pcie->rba.rx_alloc, iwl_pcie_rx_allocator_work); - #ifdef CONFIG_IWLWIFI_DEBUGFS trans_pcie->fw_mon_data.state = IWL_FW_MON_DBGFS_STATE_CLOSED; mutex_init(&trans_pcie->fw_mon_data.mutex); @@ -3599,6 +3610,8 @@ out_free_ict: iwl_pcie_free_ict(trans); out_no_pci: free_percpu(trans_pcie->tso_hdr_page); + destroy_workqueue(trans_pcie->rba.alloc_wq); +out_free_trans: iwl_trans_free(trans); return ERR_PTR(ret); } diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 3888ad0f797b..31ae6c4be3a7 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -4051,7 +4051,7 @@ static int __init init_mac80211_hwsim(void) err = dev_alloc_name(hwsim_mon, hwsim_mon->name); if (err < 0) { rtnl_unlock(); - goto out_free_radios; + goto out_free_mon; } err = register_netdevice(hwsim_mon); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index 2b216edd0c7d..a90a518b40d3 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -23,7 +23,6 @@ #include <linux/leds.h> #include <linux/mutex.h> #include <linux/etherdevice.h> -#include <linux/input-polldev.h> #include <linux/kfifo.h> #include <linux/hrtimer.h> #include <linux/average.h> diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c index 4d4e3888ef20..f2395309ec00 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c @@ -555,7 +555,7 @@ static ssize_t rt2x00debug_write_restart_hw(struct file *file, { struct rt2x00debug_intf *intf = file->private_data; struct rt2x00_dev *rt2x00dev = intf->rt2x00dev; - static unsigned long last_reset; + static unsigned long last_reset = INITIAL_JIFFIES; if (!rt2x00_has_cap_restart_hw(rt2x00dev)) return -EOPNOTSUPP; diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 240f762b3749..68dd7bb07ca6 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -626,6 +626,38 @@ err: return err; } +static void xenvif_disconnect_queue(struct xenvif_queue *queue) +{ + if (queue->tx_irq) { + unbind_from_irqhandler(queue->tx_irq, queue); + if (queue->tx_irq == queue->rx_irq) + queue->rx_irq = 0; + queue->tx_irq = 0; + } + + if (queue->rx_irq) { + unbind_from_irqhandler(queue->rx_irq, queue); + queue->rx_irq = 0; + } + + if (queue->task) { + kthread_stop(queue->task); + queue->task = NULL; + } + + if (queue->dealloc_task) { + kthread_stop(queue->dealloc_task); + queue->dealloc_task = NULL; + } + + if (queue->napi.poll) { + netif_napi_del(&queue->napi); + queue->napi.poll = NULL; + } + + xenvif_unmap_frontend_data_rings(queue); +} + int xenvif_connect_data(struct xenvif_queue *queue, unsigned long tx_ring_ref, unsigned long rx_ring_ref, @@ -651,13 +683,27 @@ int xenvif_connect_data(struct xenvif_queue *queue, netif_napi_add(queue->vif->dev, &queue->napi, xenvif_poll, XENVIF_NAPI_WEIGHT); + queue->stalled = true; + + task = kthread_run(xenvif_kthread_guest_rx, queue, + "%s-guest-rx", queue->name); + if (IS_ERR(task)) + goto kthread_err; + queue->task = task; + + task = kthread_run(xenvif_dealloc_kthread, queue, + "%s-dealloc", queue->name); + if (IS_ERR(task)) + goto kthread_err; + queue->dealloc_task = task; + if (tx_evtchn == rx_evtchn) { /* feature-split-event-channels == 0 */ err = bind_interdomain_evtchn_to_irqhandler( queue->vif->domid, tx_evtchn, xenvif_interrupt, 0, queue->name, queue); if (err < 0) - goto err_unmap; + goto err; queue->tx_irq = queue->rx_irq = err; disable_irq(queue->tx_irq); } else { @@ -668,7 +714,7 @@ int xenvif_connect_data(struct xenvif_queue *queue, queue->vif->domid, tx_evtchn, xenvif_tx_interrupt, 0, queue->tx_irq_name, queue); if (err < 0) - goto err_unmap; + goto err; queue->tx_irq = err; disable_irq(queue->tx_irq); @@ -678,48 +724,18 @@ int xenvif_connect_data(struct xenvif_queue *queue, queue->vif->domid, rx_evtchn, xenvif_rx_interrupt, 0, queue->rx_irq_name, queue); if (err < 0) - goto err_tx_unbind; + goto err; queue->rx_irq = err; disable_irq(queue->rx_irq); } - queue->stalled = true; - - task = kthread_create(xenvif_kthread_guest_rx, - (void *)queue, "%s-guest-rx", queue->name); - if (IS_ERR(task)) { - pr_warn("Could not allocate kthread for %s\n", queue->name); - err = PTR_ERR(task); - goto err_rx_unbind; - } - queue->task = task; - get_task_struct(task); - - task = kthread_create(xenvif_dealloc_kthread, - (void *)queue, "%s-dealloc", queue->name); - if (IS_ERR(task)) { - pr_warn("Could not allocate kthread for %s\n", queue->name); - err = PTR_ERR(task); - goto err_rx_unbind; - } - queue->dealloc_task = task; - - wake_up_process(queue->task); - wake_up_process(queue->dealloc_task); - return 0; -err_rx_unbind: - unbind_from_irqhandler(queue->rx_irq, queue); - queue->rx_irq = 0; -err_tx_unbind: - unbind_from_irqhandler(queue->tx_irq, queue); - queue->tx_irq = 0; -err_unmap: - xenvif_unmap_frontend_data_rings(queue); - netif_napi_del(&queue->napi); +kthread_err: + pr_warn("Could not allocate kthread for %s\n", queue->name); + err = PTR_ERR(task); err: - module_put(THIS_MODULE); + xenvif_disconnect_queue(queue); return err; } @@ -747,30 +763,7 @@ void xenvif_disconnect_data(struct xenvif *vif) for (queue_index = 0; queue_index < num_queues; ++queue_index) { queue = &vif->queues[queue_index]; - netif_napi_del(&queue->napi); - - if (queue->task) { - kthread_stop(queue->task); - put_task_struct(queue->task); - queue->task = NULL; - } - - if (queue->dealloc_task) { - kthread_stop(queue->dealloc_task); - queue->dealloc_task = NULL; - } - - if (queue->tx_irq) { - if (queue->tx_irq == queue->rx_irq) - unbind_from_irqhandler(queue->tx_irq, queue); - else { - unbind_from_irqhandler(queue->tx_irq, queue); - unbind_from_irqhandler(queue->rx_irq, queue); - } - queue->tx_irq = 0; - } - - xenvif_unmap_frontend_data_rings(queue); + xenvif_disconnect_queue(queue); } xenvif_mcast_addr_list_free(vif); |