On 07/25/2018 06:12 PM, Andrew Lunn wrote:
>>  LANTIQ MIPS ARCHITECTURE
>>  M:  John Crispin <j...@phrozen.org>
>> diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
>> index 2b81b97e994f..f1280aa3f9bd 100644
>> --- a/drivers/net/dsa/Kconfig
>> +++ b/drivers/net/dsa/Kconfig
>> @@ -23,6 +23,14 @@ config NET_DSA_LOOP
>>        This enables support for a fake mock-up switch chip which
>>        exercises the DSA APIs.
>>  
>> +config NET_DSA_GSWIP
>> +    tristate "Intel / Lantiq GSWIP"
> 
> Minor nit pick. Could you make this NET_DSA_LANTIQ_GSWIP. We generally
> have some manufacture ID in the name. And change the text to Lantiq /
> Intel GSWIP.

done

>> +static const struct gswip_rmon_cnt_desc gswip_rmon_cnt[] = {
>> +    /** Receive Packet Count (only packets that are accepted and not 
>> discarded). */
>> +    MIB_DESC(1, 0x1F, "RxGoodPkts"),
>> +    /** Receive Unicast Packet Count. */
>> +    MIB_DESC(1, 0x23, "RxUnicastPkts"),
>> +    /** Receive Multicast Packet Count. */
>> +    MIB_DESC(1, 0x22, "RxMulticastPkts"),
>> +    /** Receive FCS Error Packet Count. */
>> +    MIB_DESC(1, 0x21, "RxFCSErrorPkts"),
>> +    /** Receive Undersize Good Packet Count. */
>> +    MIB_DESC(1, 0x1D, "RxUnderSizeGoodPkts"),
>> +    /** Receive Undersize Error Packet Count. */
>> +    MIB_DESC(1, 0x1E, "RxUnderSizeErrorPkts"),
>> +    /** Receive Oversize Good Packet Count. */
>> +    MIB_DESC(1, 0x1B, "RxOversizeGoodPkts"),
>> +    /** Receive Oversize Error Packet Count. */
>> +    MIB_DESC(1, 0x1C, "RxOversizeErrorPkts"),
>> +    /** Receive Good Pause Packet Count. */
>> +    MIB_DESC(1, 0x20, "RxGoodPausePkts"),
>> +    /** Receive Align Error Packet Count. */
>> +    MIB_DESC(1, 0x1A, "RxAlignErrorPkts"),
>> +    /** Receive Size 64 Packet Count. */
>> +    MIB_DESC(1, 0x12, "Rx64BytePkts"),
>> +    /** Receive Size 65-127 Packet Count. */
>> +    MIB_DESC(1, 0x13, "Rx127BytePkts"),
>> +    /** Receive Size 128-255 Packet Count. */
>> +    MIB_DESC(1, 0x14, "Rx255BytePkts"),
>> +    /** Receive Size 256-511 Packet Count. */
>> +    MIB_DESC(1, 0x15, "Rx511BytePkts"),
>> +    /** Receive Size 512-1023 Packet Count. */
>> +    MIB_DESC(1, 0x16, "Rx1023BytePkts"),
>> +    /** Receive Size 1024-1522 (or more, if configured) Packet Count. */
>> +    MIB_DESC(1, 0x17, "RxMaxBytePkts"),
>> +    /** Receive Dropped Packet Count. */
>> +    MIB_DESC(1, 0x18, "RxDroppedPkts"),
>> +    /** Filtered Packet Count. */
>> +    MIB_DESC(1, 0x19, "RxFilteredPkts"),
>> +    /** Receive Good Byte Count (64 bit). */
>> +    MIB_DESC(2, 0x24, "RxGoodBytes"),
>> +    /** Receive Bad Byte Count (64 bit). */
>> +    MIB_DESC(2, 0x26, "RxBadBytes"),
>> +    /** Transmit Dropped Packet Count, based on Congestion Management. */
>> +    MIB_DESC(1, 0x11, "TxAcmDroppedPkts"),
>> +    /** Transmit Packet Count. */
>> +    MIB_DESC(1, 0x0C, "TxGoodPkts"),
>> +    /** Transmit Unicast Packet Count. */
>> +    MIB_DESC(1, 0x06, "TxUnicastPkts"),
>> +    /** Transmit Multicast Packet Count. */
>> +    MIB_DESC(1, 0x07, "TxMulticastPkts"),
>> +    /** Transmit Size 64 Packet Count. */
>> +    MIB_DESC(1, 0x00, "Tx64BytePkts"),
>> +    /** Transmit Size 65-127 Packet Count. */
>> +    MIB_DESC(1, 0x01, "Tx127BytePkts"),
>> +    /** Transmit Size 128-255 Packet Count. */
>> +    MIB_DESC(1, 0x02, "Tx255BytePkts"),
>> +    /** Transmit Size 256-511 Packet Count. */
>> +    MIB_DESC(1, 0x03, "Tx511BytePkts"),
>> +    /** Transmit Size 512-1023 Packet Count. */
>> +    MIB_DESC(1, 0x04, "Tx1023BytePkts"),
>> +    /** Transmit Size 1024-1522 (or more, if configured) Packet Count. */
>> +    MIB_DESC(1, 0x05, "TxMaxBytePkts"),
>> +    /** Transmit Single Collision Count. */
>> +    MIB_DESC(1, 0x08, "TxSingleCollCount"),
>> +    /** Transmit Multiple Collision Count. */
>> +    MIB_DESC(1, 0x09, "TxMultCollCount"),
>> +    /** Transmit Late Collision Count. */
>> +    MIB_DESC(1, 0x0A, "TxLateCollCount"),
>> +    /** Transmit Excessive Collision Count. */
>> +    MIB_DESC(1, 0x0B, "TxExcessCollCount"),
>> +    /** Transmit Pause Packet Count. */
>> +    MIB_DESC(1, 0x0D, "TxPauseCount"),
>> +    /** Transmit Drop Packet Count. */
>> +    MIB_DESC(1, 0x10, "TxDroppedPkts"),
>> +    /** Transmit Good Byte Count (64 bit). */
>> +    MIB_DESC(2, 0x0E, "TxGoodBytes"),
> 
> Most of the comments here don't add anything useful. Maybe remove
> them?

Ok I removed them. Are the names ok, or should they follow any Linux
definition?

>> +};
>> +
>> +static u32 gswip_switch_r(struct gswip_priv *priv, u32 offset)
>> +{
>> +    return __raw_readl(priv->gswip + (offset * 4));
>> +}
>> +
>> +static void gswip_switch_w(struct gswip_priv *priv, u32 val, u32 offset)
>> +{
>> +    return __raw_writel(val, priv->gswip + (offset * 4));
>> +}
> 
> Since this is MIPS, i assume re-ordering cannot happen, there are
> barriers, etc?

As far as I know this is not a problem on this bus and no barriers are
needed here.

>> +static int xrx200_mdio_poll(struct gswip_priv *priv)
>> +{
>> +    int cnt = 10000;
>> +
>> +    while (likely(cnt--)) {
>> +            u32 ctrl = gswip_mdio_r(priv, GSWIP_MDIO_CTRL);
>> +
>> +            if ((ctrl & GSWIP_MDIO_CTRL_BUSY) == 0)
>> +                    return 0;
>> +            cpu_relax();
>> +    }
>> +
>> +    return 1;
>> +}
> 
> Please return ETIMEOUT when needed. Maybe use one of the variants of
> readx_poll_timeout().

I am returning ETIMEOUT now.

When I would use readx_poll_timeout() I can not use the gswip_mdio_r()
function, because it takes two arguments and would have to use readl
directly. I do not think that this would make the code much better
readable.


>> +
>> +static int xrx200_mdio_wr(struct mii_bus *bus, int addr, int reg, u16 val)
>> +{
>> +    struct gswip_priv *priv = bus->priv;
>> +
>> +    if (xrx200_mdio_poll(priv))
>> +            return -EIO;
> 
> EIO is wrong, it should be a timeout. Solved above...

OK I replaced this now with this code:

err = gswip_mdio_poll(priv);
if (err)
        return err;

>> +
>> +    gswip_mdio_w(priv, val, GSWIP_MDIO_WRITE);
>> +    gswip_mdio_w(priv, GSWIP_MDIO_CTRL_BUSY | GSWIP_MDIO_CTRL_WR |
>> +            ((addr & GSWIP_MDIO_CTRL_PHYAD_MASK) << 
>> GSWIP_MDIO_CTRL_PHYAD_SHIFT) |
>> +            (reg & GSWIP_MDIO_CTRL_REGAD_MASK),
>> +            GSWIP_MDIO_CTRL);
>> +
>> +    return 0;
>> +}
>> +
> 
>> +static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np)
>> +{
>> +    struct dsa_switch *ds = priv->ds;
>> +
>> +    ds->slave_mii_bus = devm_mdiobus_alloc(priv->dev);
>> +    if (!ds->slave_mii_bus)
>> +            return -ENOMEM;
>> +
>> +    ds->slave_mii_bus->priv = priv;
>> +    ds->slave_mii_bus->read = xrx200_mdio_rd;
>> +    ds->slave_mii_bus->write = xrx200_mdio_wr;
>> +    ds->slave_mii_bus->name = "lantiq,xrx200-mdio";
>> +    snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
> 
> You should be able to do better than that.

I replaced this now with this code:
snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s-mii",
dev_name(priv->dev));

>> +    ds->slave_mii_bus->parent = priv->dev;
>> +    ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask;
>> +
>> +    return of_mdiobus_register(ds->slave_mii_bus, mdio_np);
>> +}
>> +
>> +static void gswip_wait_pce_tbl_ready(struct gswip_priv *priv)
>> +{
>> +    while (gswip_switch_r(priv, GSWIP_PCE_TBL_CTRL) & 
>> GSWIP_PCE_TBL_CTRL_BAS)
>> +            cond_resched();
> 
> Please add some form of timeout.

I introduced a new function gswip_switch_r_timeout() which uses
readx_poll_timeout().

>> +}
>> +
>> +static int gswip_port_enable(struct dsa_switch *ds, int port,
>> +                         struct phy_device *phy)
>> +{
>> +    struct gswip_priv *priv = (struct gswip_priv *)ds->priv;
> 
> Casts like this are not needed.

removed

>> +    /* RMON Counter Enable for port */
>> +    gswip_switch_w(priv, GSWIP_BM_PCFG_CNTEN, GSWIP_BM_PCFGp(port));
>> +
>> +    /* enable port fetch/store dma & VLAN Modification */
>> +    gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_EN |
>> +                               GSWIP_FDMA_PCTRL_VLANMOD_BOTH,
>> +                     GSWIP_FDMA_PCTRLp(port));
>> +    gswip_switch_mask(priv, 0, GSWIP_SDMA_PCTRL_EN,
>> +                      GSWIP_SDMA_PCTRLp(port));
>> +    gswip_switch_mask(priv, 0, GSWIP_PCE_PCTRL_0_INGRESS,
>> +                      GSWIP_PCE_PCTRL_0p(port));
>> +
>> +    return 0;
>> +}
>> +
> 
>> +static int gswip_setup(struct dsa_switch *ds)
>> +{
>> +    struct gswip_priv *priv = ds->priv;
>> +    int i;
>> +
>> +    gswip_switch_w(priv, GSWIP_ETHSW_SWRES_R0, GSWIP_ETHSW_SWRES);
>> +    usleep_range(5000, 10000);
>> +    gswip_switch_w(priv, 0, GSWIP_ETHSW_SWRES);
>> +
>> +    /* disable port fetch/store dma, assume CPU port is last port */
> 
> Since this comes from device tree, you should really verify that and
> return EINVAL if not, in the probe() function.

I defined a struct hw_info which describes the details of this switch,
max port numbers and CPU port, as this is hard coded and this is then
compared to the device tree settings.

>> +    for (i = 0; i <= priv->cpu_port; i++)
>> +            gswip_port_disable(ds, i, NULL);
>> +
>> +    /* enable Switch */
>> +    gswip_mdio_mask(priv, 0, GSWIP_MDIO_GLOB_ENABLE, GSWIP_MDIO_GLOB);
>> +
>> +    xrx200_pci_microcode(priv);
>> +
>> +    /* Default unknown Broadcast/Multicast/Unicast port maps */
>> +    gswip_switch_w(priv, BIT(priv->cpu_port), GSWIP_PCE_PMAP1);
>> +    gswip_switch_w(priv, BIT(priv->cpu_port), GSWIP_PCE_PMAP2);
>> +    gswip_switch_w(priv, BIT(priv->cpu_port), GSWIP_PCE_PMAP3);
>> +
>> +    /* disable auto polling */
>> +    gswip_mdio_w(priv, 0x0, GSWIP_MDIO_MDC_CFG0);
>> +
>> +    /* enable special tag insertion on cpu port */
>> +    gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_STEN,
>> +                      GSWIP_FDMA_PCTRLp(priv->cpu_port));
>> +
>> +    gswip_switch_mask(priv, 0, GSWIP_MAC_CTRL_2_MLEN,
>> +                      GSWIP_MAC_CTRL_2p(priv->cpu_port));
>> +    gswip_switch_w(priv, VLAN_ETH_FRAME_LEN + 8, GSWIP_MAC_FLEN);
>> +    gswip_switch_mask(priv, 0, GSWIP_BM_QUEUE_GCTRL_GL_MOD,
>> +                      GSWIP_BM_QUEUE_GCTRL);
>> +
>> +    /* VLAN aware Switching */
>> +    gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_0_VLAN, GSWIP_PCE_GCTRL_0);
>> +
>> +    /* Mac Address Table Lock */
>> +    gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_1_MAC_GLOCK |
>> +                               GSWIP_PCE_GCTRL_1_MAC_GLOCK_MOD,
>> +                      GSWIP_PCE_GCTRL_1);
>> +
>> +    gswip_port_enable(ds, priv->cpu_port, NULL);
>> +    return 0;
>> +}
>> +
>> +static void gswip_adjust_link(struct dsa_switch *ds, int port,
>> +                          struct phy_device *phydev)
>> +{
>> +    struct gswip_priv *priv = (struct gswip_priv *)ds->priv;
>> +    u16 phyaddr = phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK;
>> +    u16 miirate = 0;
>> +    u16 miimode;
>> +    u16 lcl_adv = 0, rmt_adv = 0;
>> +    u8 flowctrl;
>> +
>> +    /* do not run this for the CPU port 6 */
>> +    if (port >= priv->cpu_port)
> 
> Please use  dsa_is_cpu_port(ds, port)

done

>> +            return;
>> +
>> +    miimode = gswip_mdio_r(priv, GSWIP_MII_CFGp(port));
>> +    miimode &= GSWIP_MII_CFG_MODE_MASK;
>> +
>> +    switch (phydev->speed) {
>> +    case SPEED_1000:
>> +            phyaddr |= GSWIP_MDIO_PHY_SPEED_G1;
>> +            miirate = GSWIP_MII_CFG_RATE_M125;
>> +            break;
>> +
>> +    case SPEED_100:
>> +            phyaddr |= GSWIP_MDIO_PHY_SPEED_M100;
>> +            switch (miimode) {
>> +            case GSWIP_MII_CFG_MODE_RMIIM:
>> +            case GSWIP_MII_CFG_MODE_RMIIP:
>> +                    miirate = GSWIP_MII_CFG_RATE_M50;
>> +                    break;
>> +            default:
>> +                    miirate = GSWIP_MII_CFG_RATE_M25;
>> +                    break;
>> +            }
>> +            break;
>> +
>> +    default:
>> +            phyaddr |= GSWIP_MDIO_PHY_SPEED_M10;
>> +            miirate = GSWIP_MII_CFG_RATE_M2P5;
>> +            break;
>> +    }
>> +
>> +    if (phydev->link)
>> +            phyaddr |= GSWIP_MDIO_PHY_LINK_UP;
>> +    else
>> +            phyaddr |= GSWIP_MDIO_PHY_LINK_DOWN;
>> +
>> +    if (phydev->duplex == DUPLEX_FULL)
>> +            phyaddr |= GSWIP_MDIO_PHY_FDUP_EN;
>> +    else
>> +            phyaddr |= GSWIP_MDIO_PHY_FDUP_DIS;
>> +
>> +    if (phydev->pause)
>> +            rmt_adv = LPA_PAUSE_CAP;
>> +    if (phydev->asym_pause)
>> +            rmt_adv |= LPA_PAUSE_ASYM;
>> +
>> +    if (phydev->advertising & ADVERTISED_Pause)
>> +            lcl_adv |= ADVERTISE_PAUSE_CAP;
>> +    if (phydev->advertising & ADVERTISED_Asym_Pause)
>> +            lcl_adv |= ADVERTISE_PAUSE_ASYM;
>> +
>> +    flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
>> +
>> +    if (flowctrl & FLOW_CTRL_TX)
>> +            phyaddr |= GSWIP_MDIO_PHY_FCONTX_EN;
>> +    else
>> +            phyaddr |= GSWIP_MDIO_PHY_FCONTX_DIS;
>> +    if (flowctrl & FLOW_CTRL_RX)
>> +            phyaddr |= GSWIP_MDIO_PHY_FCONRX_EN;
>> +    else
>> +            phyaddr |= GSWIP_MDIO_PHY_FCONRX_DIS;
>> +
>> +    gswip_mdio_mask(priv, GSWIP_MDIO_PHY_MASK, phyaddr,
>> +                    GSWIP_MDIO_PHYp(port));
> 
> The names make this unclear. The callback is used to configure the MAC
> layer when something happens at the PHY layer. phyaddr does not appear
> to be an address, not should it be doing anything to a PHY.

I renamed this to phyconf, as this contains multiple configuration
values. This tells the mac what settings the phy wants to use.

> 
>> +    gswip_mii_mask(priv, GSWIP_MII_CFG_RATE_MASK, miirate,
>> +                   GSWIP_MII_CFGp(port));
>> +}
>> +
>> +static u32 gswip_bcm_ram_entry_read(struct gswip_priv *priv, u32 table,
>> +                                u32 index)
>> +{
>> +    u32 result;
>> +
>> +    gswip_switch_w(priv, index, GSWIP_BM_RAM_ADDR);
>> +    gswip_switch_mask(priv, GSWIP_BM_RAM_CTRL_ADDR_MASK |
>> +                            GSWIP_BM_RAM_CTRL_OPMOD,
>> +                          table | GSWIP_BM_RAM_CTRL_BAS,
>> +                          GSWIP_BM_RAM_CTRL);
>> +
>> +    while (gswip_switch_r(priv, GSWIP_BM_RAM_CTRL) & GSWIP_BM_RAM_CTRL_BAS)
>> +            cond_resched();
> 
> Please add a timeout.

I introduced a new funtion gswip_switch_r_timeout() which uses
readx_poll_timeout().

>> +
>> +    result = gswip_switch_r(priv, GSWIP_BM_RAM_VAL(0));
>> +    result |= gswip_switch_r(priv, GSWIP_BM_RAM_VAL(1)) << 16;
>> +
>> +    return result;
>> +}
>> +
> 
>> +static int gswip_probe(struct platform_device *pdev)
>> +{
>> +    struct gswip_priv *priv;
>> +    struct resource *gswip_res, *mdio_res, *mii_res;
>> +    struct device_node *mdio_np;
>> +    struct device *dev = &pdev->dev;
>> +    int err;
>> +
>> +    priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>> +    if (!priv)
>> +            return -ENOMEM;
>> +
>> +    gswip_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +    priv->gswip = devm_ioremap_resource(dev, gswip_res);
>> +    if (!priv->gswip)
>> +            return -ENOMEM;
>> +
>> +    mdio_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>> +    priv->mdio = devm_ioremap_resource(dev, mdio_res);
>> +    if (!priv->mdio)
>> +            return -ENOMEM;
>> +
>> +    mii_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
>> +    priv->mii = devm_ioremap_resource(dev, mii_res);
>> +    if (!priv->mii)
>> +            return -ENOMEM;
>> +
>> +    priv->ds = dsa_switch_alloc(dev, DSA_MAX_PORTS);
> 
> If you know how many ports there are, it is better to pass it.

done

>> +    if (!priv->ds)
>> +            return -ENOMEM;
>> +
>> +    priv->ds->priv = priv;
>> +    priv->ds->ops = &gswip_switch_ops;
>> +    priv->dev = dev;
>> +    priv->cpu_port = 6;
>> +
>> +    /* bring up the mdio bus */
>> +    mdio_np = of_find_compatible_node(pdev->dev.of_node, NULL,
>> +                                      "lantiq,xrx200-mdio");
>> +    if (mdio_np) {
>> +            err = gswip_mdio(priv, mdio_np);
>> +            if (err) {
>> +                    dev_err(dev, "mdio probe failed\n");
>> +                    return err;
>> +            }
>> +    }
>> +
>> +    platform_set_drvdata(pdev, priv);
>> +
>> +    err = dsa_register_switch(priv->ds);
>> +    if (err) {
>> +            dev_err(dev, "dsa switch register failed: %i\n", err);
>> +            if (mdio_np)
>> +                    mdiobus_unregister(priv->ds->slave_mii_bus);
>> +    }
>> +
>> +    return err;
>> +}
> 
>> +static const struct of_device_id gswip_of_match[] = {
>> +    { .compatible = "lantiq,xrx200-gswip" },
>> +    {},
>> +};
> 
> Please add device tree documentation.

Will do that.

> 
>> +MODULE_DEVICE_TABLE(of, xrx200_match);
>> +
>> +static struct platform_driver gswip_driver = {
>> +    .probe = gswip_probe,
>> +    .remove = gswip_remove,
>> +    .driver = {
>> +            .name = "gswip",
>> +            .of_match_table = gswip_of_match,
>> +    },
>> +};
>> +#define MC_ENTRY(val, msk, ns, out, len, type, flags, ipv4_len) \
>> +    { val, msk, (ns << 10 | out << 4 | len >> 1),\
>> +            (len & 1) << 15 | type << 13 | flags << 9 | ipv4_len << 8 }
>> +static const struct gswip_pce_microcode gswip_pce_microcode[] = {
> 
> How big is this table? I'm wondering if it should be loaded from
> /lib/firmware. Or can it be marked __initdata?

This is sort of a firmware, but it is also in the GPL driver.
Currently the probe function is not marked __init so we can not make
this easily __initdata.
It has 64 entries of 8 bytes each so, 512 bytes, I think we can put this
into the code.

Hauke

Reply via email to