diff options
Diffstat (limited to 'drivers/net/dsa/mv88e6xxx')
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/chip.c | 399 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/global2.c | 40 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/global2.h | 1 |
3 files changed, 230 insertions, 210 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 30383c4f8fd0..64a2f2f83735 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -611,10 +611,10 @@ static void mv88e6185_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, } static const u8 mv88e6xxx_phy_interface_modes[] = { - [MV88E6XXX_PORT_STS_CMODE_MII_PHY] = PHY_INTERFACE_MODE_MII, + [MV88E6XXX_PORT_STS_CMODE_MII_PHY] = PHY_INTERFACE_MODE_REVMII, [MV88E6XXX_PORT_STS_CMODE_MII] = PHY_INTERFACE_MODE_MII, [MV88E6XXX_PORT_STS_CMODE_GMII] = PHY_INTERFACE_MODE_GMII, - [MV88E6XXX_PORT_STS_CMODE_RMII_PHY] = PHY_INTERFACE_MODE_RMII, + [MV88E6XXX_PORT_STS_CMODE_RMII_PHY] = PHY_INTERFACE_MODE_REVRMII, [MV88E6XXX_PORT_STS_CMODE_RMII] = PHY_INTERFACE_MODE_RMII, [MV88E6XXX_PORT_STS_CMODE_100BASEX] = PHY_INTERFACE_MODE_100BASEX, [MV88E6XXX_PORT_STS_CMODE_1000BASEX] = PHY_INTERFACE_MODE_1000BASEX, @@ -3354,9 +3354,14 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) * If this is the upstream port for this switch, enable * forwarding of unknown unicasts and multicasts. */ - reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP | - MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | + reg = MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | MV88E6XXX_PORT_CTL0_STATE_FORWARDING; + /* Forward any IPv4 IGMP or IPv6 MLD frames received + * by a USER port to the CPU port to allow snooping. + */ + if (dsa_is_user_port(ds, port)) + reg |= MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP; + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); if (err) return err; @@ -3680,185 +3685,6 @@ static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) return mv88e6xxx_software_reset(chip); } -static void mv88e6xxx_teardown(struct dsa_switch *ds) -{ - mv88e6xxx_teardown_devlink_params(ds); - dsa_devlink_resources_unregister(ds); - mv88e6xxx_teardown_devlink_regions_global(ds); -} - -static int mv88e6xxx_setup(struct dsa_switch *ds) -{ - struct mv88e6xxx_chip *chip = ds->priv; - u8 cmode; - int err; - int i; - - chip->ds = ds; - ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); - - /* Since virtual bridges are mapped in the PVT, the number we support - * depends on the physical switch topology. We need to let DSA figure - * that out and therefore we cannot set this at dsa_register_switch() - * time. - */ - if (mv88e6xxx_has_pvt(chip)) - ds->max_num_bridges = MV88E6XXX_MAX_PVT_SWITCHES - - ds->dst->last_switch - 1; - - mv88e6xxx_reg_lock(chip); - - if (chip->info->ops->setup_errata) { - err = chip->info->ops->setup_errata(chip); - if (err) - goto unlock; - } - - /* Cache the cmode of each port. */ - for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { - if (chip->info->ops->port_get_cmode) { - err = chip->info->ops->port_get_cmode(chip, i, &cmode); - if (err) - goto unlock; - - chip->ports[i].cmode = cmode; - } - } - - err = mv88e6xxx_vtu_setup(chip); - if (err) - goto unlock; - - /* Must be called after mv88e6xxx_vtu_setup (which flushes the - * VTU, thereby also flushing the STU). - */ - err = mv88e6xxx_stu_setup(chip); - if (err) - goto unlock; - - /* Setup Switch Port Registers */ - for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { - if (dsa_is_unused_port(ds, i)) - continue; - - /* Prevent the use of an invalid port. */ - if (mv88e6xxx_is_invalid_port(chip, i)) { - dev_err(chip->dev, "port %d is invalid\n", i); - err = -EINVAL; - goto unlock; - } - - err = mv88e6xxx_setup_port(chip, i); - if (err) - goto unlock; - } - - err = mv88e6xxx_irl_setup(chip); - if (err) - goto unlock; - - err = mv88e6xxx_mac_setup(chip); - if (err) - goto unlock; - - err = mv88e6xxx_phy_setup(chip); - if (err) - goto unlock; - - err = mv88e6xxx_pvt_setup(chip); - if (err) - goto unlock; - - err = mv88e6xxx_atu_setup(chip); - if (err) - goto unlock; - - err = mv88e6xxx_broadcast_setup(chip, 0); - if (err) - goto unlock; - - err = mv88e6xxx_pot_setup(chip); - if (err) - goto unlock; - - err = mv88e6xxx_rmu_setup(chip); - if (err) - goto unlock; - - err = mv88e6xxx_rsvd2cpu_setup(chip); - if (err) - goto unlock; - - err = mv88e6xxx_trunk_setup(chip); - if (err) - goto unlock; - - err = mv88e6xxx_devmap_setup(chip); - if (err) - goto unlock; - - err = mv88e6xxx_pri_setup(chip); - if (err) - goto unlock; - - /* Setup PTP Hardware Clock and timestamping */ - if (chip->info->ptp_support) { - err = mv88e6xxx_ptp_setup(chip); - if (err) - goto unlock; - - err = mv88e6xxx_hwtstamp_setup(chip); - if (err) - goto unlock; - } - - err = mv88e6xxx_stats_setup(chip); - if (err) - goto unlock; - -unlock: - mv88e6xxx_reg_unlock(chip); - - if (err) - return err; - - /* Have to be called without holding the register lock, since - * they take the devlink lock, and we later take the locks in - * the reverse order when getting/setting parameters or - * resource occupancy. - */ - err = mv88e6xxx_setup_devlink_resources(ds); - if (err) - return err; - - err = mv88e6xxx_setup_devlink_params(ds); - if (err) - goto out_resources; - - err = mv88e6xxx_setup_devlink_regions_global(ds); - if (err) - goto out_params; - - return 0; - -out_params: - mv88e6xxx_teardown_devlink_params(ds); -out_resources: - dsa_devlink_resources_unregister(ds); - - return err; -} - -static int mv88e6xxx_port_setup(struct dsa_switch *ds, int port) -{ - return mv88e6xxx_setup_devlink_regions_port(ds, port); -} - -static void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port) -{ - mv88e6xxx_teardown_devlink_regions_port(ds, port); -} - /* prod_id for switch families which do not have a PHY model number */ static const u16 family_prod_id_table[] = { [MV88E6XXX_FAMILY_6341] = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, @@ -3984,6 +3810,9 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, bus->read_c45 = mv88e6xxx_mdio_read_c45; bus->write_c45 = mv88e6xxx_mdio_write_c45; bus->parent = chip->dev; + bus->phy_mask = ~GENMASK(chip->info->phy_base_addr + + mv88e6xxx_num_ports(chip) - 1, + chip->info->phy_base_addr); if (!external) { err = mv88e6xxx_g2_irq_mdio_setup(chip, bus); @@ -4027,9 +3856,9 @@ static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) } } -static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, - struct device_node *np) +static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip) { + struct device_node *np = chip->dev->of_node; struct device_node *child; int err; @@ -4062,6 +3891,194 @@ static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, return 0; } +static void mv88e6xxx_teardown(struct dsa_switch *ds) +{ + struct mv88e6xxx_chip *chip = ds->priv; + + mv88e6xxx_teardown_devlink_params(ds); + dsa_devlink_resources_unregister(ds); + mv88e6xxx_teardown_devlink_regions_global(ds); + mv88e6xxx_mdios_unregister(chip); +} + +static int mv88e6xxx_setup(struct dsa_switch *ds) +{ + struct mv88e6xxx_chip *chip = ds->priv; + u8 cmode; + int err; + int i; + + err = mv88e6xxx_mdios_register(chip); + if (err) + return err; + + chip->ds = ds; + ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); + + /* Since virtual bridges are mapped in the PVT, the number we support + * depends on the physical switch topology. We need to let DSA figure + * that out and therefore we cannot set this at dsa_register_switch() + * time. + */ + if (mv88e6xxx_has_pvt(chip)) + ds->max_num_bridges = MV88E6XXX_MAX_PVT_SWITCHES - + ds->dst->last_switch - 1; + + mv88e6xxx_reg_lock(chip); + + if (chip->info->ops->setup_errata) { + err = chip->info->ops->setup_errata(chip); + if (err) + goto unlock; + } + + /* Cache the cmode of each port. */ + for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { + if (chip->info->ops->port_get_cmode) { + err = chip->info->ops->port_get_cmode(chip, i, &cmode); + if (err) + goto unlock; + + chip->ports[i].cmode = cmode; + } + } + + err = mv88e6xxx_vtu_setup(chip); + if (err) + goto unlock; + + /* Must be called after mv88e6xxx_vtu_setup (which flushes the + * VTU, thereby also flushing the STU). + */ + err = mv88e6xxx_stu_setup(chip); + if (err) + goto unlock; + + /* Setup Switch Port Registers */ + for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { + if (dsa_is_unused_port(ds, i)) + continue; + + /* Prevent the use of an invalid port. */ + if (mv88e6xxx_is_invalid_port(chip, i)) { + dev_err(chip->dev, "port %d is invalid\n", i); + err = -EINVAL; + goto unlock; + } + + err = mv88e6xxx_setup_port(chip, i); + if (err) + goto unlock; + } + + err = mv88e6xxx_irl_setup(chip); + if (err) + goto unlock; + + err = mv88e6xxx_mac_setup(chip); + if (err) + goto unlock; + + err = mv88e6xxx_phy_setup(chip); + if (err) + goto unlock; + + err = mv88e6xxx_pvt_setup(chip); + if (err) + goto unlock; + + err = mv88e6xxx_atu_setup(chip); + if (err) + goto unlock; + + err = mv88e6xxx_broadcast_setup(chip, 0); + if (err) + goto unlock; + + err = mv88e6xxx_pot_setup(chip); + if (err) + goto unlock; + + err = mv88e6xxx_rmu_setup(chip); + if (err) + goto unlock; + + err = mv88e6xxx_rsvd2cpu_setup(chip); + if (err) + goto unlock; + + err = mv88e6xxx_trunk_setup(chip); + if (err) + goto unlock; + + err = mv88e6xxx_devmap_setup(chip); + if (err) + goto unlock; + + err = mv88e6xxx_pri_setup(chip); + if (err) + goto unlock; + + /* Setup PTP Hardware Clock and timestamping */ + if (chip->info->ptp_support) { + err = mv88e6xxx_ptp_setup(chip); + if (err) + goto unlock; + + err = mv88e6xxx_hwtstamp_setup(chip); + if (err) + goto unlock; + } + + err = mv88e6xxx_stats_setup(chip); + if (err) + goto unlock; + +unlock: + mv88e6xxx_reg_unlock(chip); + + if (err) + goto out_mdios; + + /* Have to be called without holding the register lock, since + * they take the devlink lock, and we later take the locks in + * the reverse order when getting/setting parameters or + * resource occupancy. + */ + err = mv88e6xxx_setup_devlink_resources(ds); + if (err) + goto out_mdios; + + err = mv88e6xxx_setup_devlink_params(ds); + if (err) + goto out_resources; + + err = mv88e6xxx_setup_devlink_regions_global(ds); + if (err) + goto out_params; + + return 0; + +out_params: + mv88e6xxx_teardown_devlink_params(ds); +out_resources: + dsa_devlink_resources_unregister(ds); +out_mdios: + mv88e6xxx_mdios_unregister(chip); + + return err; +} + +static int mv88e6xxx_port_setup(struct dsa_switch *ds, int port) +{ + return mv88e6xxx_setup_devlink_regions_port(ds, port); +} + +static void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port) +{ + mv88e6xxx_teardown_devlink_regions_port(ds, port); +} + static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) { struct mv88e6xxx_chip *chip = ds->priv; @@ -5177,6 +5194,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { .set_cpu_port = mv88e6095_g1_set_cpu_port, .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6390_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6185_g1_vtu_getnext, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, @@ -5596,7 +5614,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = { * .port_set_upstream_port method. */ .set_egress_port = mv88e6393x_set_egress_port, - .watchdog_ops = &mv88e6390_watchdog_ops, + .watchdog_ops = &mv88e6393x_watchdog_ops, .mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, @@ -7228,18 +7246,12 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) if (err) goto out_g1_atu_prob_irq; - err = mv88e6xxx_mdios_register(chip, np); - if (err) - goto out_g1_vtu_prob_irq; - err = mv88e6xxx_register_switch(chip); if (err) - goto out_mdio; + goto out_g1_vtu_prob_irq; return 0; -out_mdio: - mv88e6xxx_mdios_unregister(chip); out_g1_vtu_prob_irq: mv88e6xxx_g1_vtu_prob_irq_free(chip); out_g1_atu_prob_irq: @@ -7276,7 +7288,6 @@ static void mv88e6xxx_remove(struct mdio_device *mdiodev) mv88e6xxx_phy_destroy(chip); mv88e6xxx_unregister_switch(chip); - mv88e6xxx_mdios_unregister(chip); mv88e6xxx_g1_vtu_prob_irq_free(chip); mv88e6xxx_g1_atu_prob_irq_free(chip); diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index ed3b2f88e783..615896893076 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -943,6 +943,26 @@ const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = { .irq_free = mv88e6390_watchdog_free, }; +static int mv88e6393x_watchdog_action(struct mv88e6xxx_chip *chip, int irq) +{ + mv88e6390_watchdog_action(chip, irq); + + /* Fix for clearing the force WD event bit. + * Unreleased erratum on mv88e6393x. + */ + mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL, + MV88E6390_G2_WDOG_CTL_UPDATE | + MV88E6390_G2_WDOG_CTL_PTR_EVENT); + + return IRQ_HANDLED; +} + +const struct mv88e6xxx_irq_ops mv88e6393x_watchdog_ops = { + .irq_action = mv88e6393x_watchdog_action, + .irq_setup = mv88e6390_watchdog_setup, + .irq_free = mv88e6390_watchdog_free, +}; + static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id) { struct mv88e6xxx_chip *chip = dev_id; @@ -1176,31 +1196,19 @@ out: int mv88e6xxx_g2_irq_mdio_setup(struct mv88e6xxx_chip *chip, struct mii_bus *bus) { - int phy, irq, err, err_phy; + int phy, irq; for (phy = 0; phy < chip->info->num_internal_phys; phy++) { irq = irq_find_mapping(chip->g2_irq.domain, phy); - if (irq < 0) { - err = irq; - goto out; - } + if (irq < 0) + return irq; + bus->irq[chip->info->phy_base_addr + phy] = irq; } return 0; -out: - err_phy = phy; - - for (phy = 0; phy < err_phy; phy++) - irq_dispose_mapping(bus->irq[phy]); - - return err; } void mv88e6xxx_g2_irq_mdio_free(struct mv88e6xxx_chip *chip, struct mii_bus *bus) { - int phy; - - for (phy = 0; phy < chip->info->num_internal_phys; phy++) - irq_dispose_mapping(bus->irq[phy]); } diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index e973114d6890..7e091965582b 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -369,6 +369,7 @@ int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target, extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops; extern const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops; extern const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops; +extern const struct mv88e6xxx_irq_ops mv88e6393x_watchdog_ops; extern const struct mv88e6xxx_avb_ops mv88e6165_avb_ops; extern const struct mv88e6xxx_avb_ops mv88e6352_avb_ops; |