Re: [PATCH 2/2] net: ti: icssg-prueth: Add ICSSG ethernet driver

From: Andrew Lunn
Date: Fri May 06 2022 - 12:44:23 EST


> +void icssg_config_ipg(struct prueth_emac *emac)
> +{
> + struct prueth *prueth = emac->prueth;
> + int slice = prueth_emac_slice(emac);
> +
> + switch (emac->speed) {
> + case SPEED_1000:
> + icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_1G);
> + break;
> + case SPEED_100:
> + icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_100M);
> + break;
> + default:
> + /* Other links speeds not supported */
> + pr_err("Unsupported link speed\n");

dev_err() or netdev_err(). You then get an idea which device somebody
is trying to configure into an unsupported mode.

checkpatch probably also warned about that?

> +static void icssg_init_emac_mode(struct prueth *prueth)
> +{
> + u8 mac[ETH_ALEN] = { 0 };
> +
> + if (prueth->emacs_initialized)
> + return;
> +
> + regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, SMEM_VLAN_OFFSET_MASK, 0);
> + regmap_write(prueth->miig_rt, FDB_GEN_CFG2, 0);
> + /* Clear host MAC address */
> + icssg_class_set_host_mac_addr(prueth->miig_rt, mac);

Seems an odd thing to do, set it to 00:00:00:00:00:00. You probably
want to add a comment why you do this odd thing.

> +int emac_set_port_state(struct prueth_emac *emac,
> + enum icssg_port_state_cmd cmd)
> +{
> + struct icssg_r30_cmd *p;
> + int ret = -ETIMEDOUT;
> + int timeout = 10;
> + int i;
> +
> + p = emac->dram.va + MGR_R30_CMD_OFFSET;
> +
> + if (cmd >= ICSSG_EMAC_PORT_MAX_COMMANDS) {
> + netdev_err(emac->ndev, "invalid port command\n");
> + return -EINVAL;
> + }
> +
> + /* only one command at a time allowed to firmware */
> + mutex_lock(&emac->cmd_lock);
> +
> + for (i = 0; i < 4; i++)
> + writel(emac_r32_bitmask[cmd].cmd[i], &p->cmd[i]);
> +
> + /* wait for done */
> + while (timeout) {
> + if (emac_r30_is_done(emac)) {
> + ret = 0;
> + break;
> + }
> +
> + usleep_range(1000, 2000);
> + timeout--;
> + }

linux/iopoll.h

> +void icssg_config_set_speed(struct prueth_emac *emac)
> +{
> + u8 fw_speed;
> +
> + switch (emac->speed) {
> + case SPEED_1000:
> + fw_speed = FW_LINK_SPEED_1G;
> + break;
> + case SPEED_100:
> + fw_speed = FW_LINK_SPEED_100M;
> + break;
> + default:
> + /* Other links speeds not supported */
> + pr_err("Unsupported link speed\n");

dev_err() or netdev_err().


> +static int emac_get_link_ksettings(struct net_device *ndev,
> + struct ethtool_link_ksettings *ecmd)
> +{
> + struct prueth_emac *emac = netdev_priv(ndev);
> +
> + if (!emac->phydev)
> + return -EOPNOTSUPP;
> +
> + phy_ethtool_ksettings_get(emac->phydev, ecmd);
> + return 0;
> +}

phy_ethtool_get_link_ksettings().

You should keep phydev in ndev, not your priv structure.

> +
> +static int emac_set_link_ksettings(struct net_device *ndev,
> + const struct ethtool_link_ksettings *ecmd)
> +{
> + struct prueth_emac *emac = netdev_priv(ndev);
> +
> + if (!emac->phydev)
> + return -EOPNOTSUPP;
> +
> + return phy_ethtool_ksettings_set(emac->phydev, ecmd);

phy_ethtool_set_link_ksettings()

> +static int emac_nway_reset(struct net_device *ndev)
> +{
> + struct prueth_emac *emac = netdev_priv(ndev);
> +
> + if (!emac->phydev)
> + return -EOPNOTSUPP;
> +
> + return genphy_restart_aneg(emac->phydev);

phy_ethtool_nway_reset()

> +static void emac_get_ethtool_stats(struct net_device *ndev,
> + struct ethtool_stats *stats, u64 *data)
> +{
> + struct prueth_emac *emac = netdev_priv(ndev);
> + struct prueth *prueth = emac->prueth;
> + int i;
> + int slice = prueth_emac_slice(emac);
> + u32 base = stats_base[slice];
> + u32 val;

Reverse Christmas tree. Move i to the end. There are other places in
the driver you need to fix up as well.

> +static int debug_level = -1;
> +module_param(debug_level, int, 0644);
> +MODULE_PARM_DESC(debug_level, "PRUETH debug level (NETIF_MSG bits)");

Module parameters are not liked any more. Yes, lots of drivers have
this one, but you have the ethtool setting, so you should not need
this.

> +/* called back by PHY layer if there is change in link state of hw port*/
> +static void emac_adjust_link(struct net_device *ndev)
> +{
> + struct prueth_emac *emac = netdev_priv(ndev);
> + struct phy_device *phydev = emac->phydev;
> + struct prueth *prueth = emac->prueth;
> + bool new_state = false;
> + unsigned long flags;
> +
> + if (phydev->link) {
> + /* check the mode of operation - full/half duplex */
> + if (phydev->duplex != emac->duplex) {
> + new_state = true;
> + emac->duplex = phydev->duplex;
> + }
> + if (phydev->speed != emac->speed) {
> + new_state = true;
> + emac->speed = phydev->speed;
> + }
> + if (!emac->link) {
> + new_state = true;
> + emac->link = 1;
> + }
> + } else if (emac->link) {
> + new_state = true;
> + emac->link = 0;
> + /* defaults for no link */
> +
> + /* f/w should support 100 & 1000 */
> + emac->speed = SPEED_1000;
> +
> + /* half duplex may not supported by f/w */
> + emac->duplex = DUPLEX_FULL;

Why set speed and duplex when you have just lost the link? They are
meaningless until the link comes back.

> + }
> +
> + if (new_state) {
> + phy_print_status(phydev);
> +
> + /* update RGMII and MII configuration based on PHY negotiated
> + * values
> + */
> + if (emac->link) {
> + /* Set the RGMII cfg for gig en and full duplex */
> + icssg_update_rgmii_cfg(prueth->miig_rt, emac);
> +
> + /* update the Tx IPG based on 100M/1G speed */
> + spin_lock_irqsave(&emac->lock, flags);
> + icssg_config_ipg(emac);
> + spin_unlock_irqrestore(&emac->lock, flags);
> + icssg_config_set_speed(emac);
> + emac_set_port_state(emac, ICSSG_EMAC_PORT_FORWARD);
> +
> + } else {
> + emac_set_port_state(emac, ICSSG_EMAC_PORT_DISABLE);
> + }
> + }
> +
> + if (emac->link) {
> + /* link ON */
> + netif_carrier_on(ndev);

phylib will do this for you.

> + /* reactivate the transmit queue */
> + netif_tx_wake_all_queues(ndev);

Not something you see other drivers do. Why is it here?

> + } else {
> + /* link OFF */
> + netif_carrier_off(ndev);
> + netif_tx_stop_all_queues(ndev);

Same as above, for both.

> +static int emac_ndo_open(struct net_device *ndev)
> +{
> + struct prueth_emac *emac = netdev_priv(ndev);
> + int ret, i, num_data_chn = emac->tx_ch_num;
> + struct prueth *prueth = emac->prueth;
> + int slice = prueth_emac_slice(emac);
> + struct device *dev = prueth->dev;
> + int max_rx_flows;
> + int rx_flow;
> +
> + /* clear SMEM and MSMC settings for all slices */
> + if (!prueth->emacs_initialized) {
> + memset_io(prueth->msmcram.va, 0, prueth->msmcram.size);
> + memset_io(prueth->shram.va, 0, ICSSG_CONFIG_OFFSET_SLICE1 * PRUETH_NUM_MACS);
> + }
> +
> + /* set h/w MAC as user might have re-configured */
> + ether_addr_copy(emac->mac_addr, ndev->dev_addr);
> +
> + icssg_class_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr);
> + icssg_ft1_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr);
> +
> + icssg_class_default(prueth->miig_rt, slice, 0);
> +
> + netif_carrier_off(ndev);

It should default to off. phylib will turn it on for you when you get
link.

> +static int emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
> +{
> + struct prueth_emac *emac = netdev_priv(ndev);
> +
> + if (!emac->phydev)
> + return -EOPNOTSUPP;
> +
> + return phy_mii_ioctl(emac->phydev, ifr, cmd);
> +}

phy_do_ioctl()

> +extern const struct ethtool_ops icssg_ethtool_ops;

Should really by in a header file.

> +static int prueth_probe(struct platform_device *pdev)
> +{
> + struct prueth *prueth;
> + struct device *dev = &pdev->dev;
> + struct device_node *np = dev->of_node;
> + struct device_node *eth_ports_node;
> + struct device_node *eth_node;
> + struct device_node *eth0_node, *eth1_node;
> + const struct of_device_id *match;
> + struct pruss *pruss;
> + int i, ret;
> + u32 msmc_ram_size;
> + struct genpool_data_align gp_data = {
> + .align = SZ_64K,
> + };
> +
> + match = of_match_device(prueth_dt_match, dev);
> + if (!match)
> + return -ENODEV;
> +
> + prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL);
> + if (!prueth)
> + return -ENOMEM;
> +
> + dev_set_drvdata(dev, prueth);
> + prueth->pdev = pdev;
> + prueth->pdata = *(const struct prueth_pdata *)match->data;
> +
> + prueth->dev = dev;
> + eth_ports_node = of_get_child_by_name(np, "ethernet-ports");
> + if (!eth_ports_node)
> + return -ENOENT;
> +
> + for_each_child_of_node(eth_ports_node, eth_node) {
> + u32 reg;
> +
> + if (strcmp(eth_node->name, "port"))
> + continue;
> + ret = of_property_read_u32(eth_node, "reg", &reg);
> + if (ret < 0) {
> + dev_err(dev, "%pOF error reading port_id %d\n",
> + eth_node, ret);
> + }
> +
> + if (reg == 0)
> + eth0_node = eth_node;
> + else if (reg == 1)
> + eth1_node = eth_node;

and if reg == 42?

Or reg 0 appears twice?

Andrew