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

Puranjay Mohan p-mohan at ti.com
Mon May 9 03:20:24 PDT 2022


Hi Andrew,
Thanks for your comments.

On 06/05/22 22:14, Andrew Lunn wrote:
>> +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.

I will use netdev_err() in next version.

> 
> checkpatch probably also warned about that?

unfortunately it didn't.

> 
>> +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.

Actually, this is when the device is configured as a bridge, the host
mac address has to be set to zero to while bringing it back to emac
mode. I will add a comment to explain this.


> 
>> +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

will add in next version

> 
>> +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.

Okay, I will make this change in the whole driver.

> 
>> +
>> +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.

These were just the default values that we added.
What do you suggest I put here?

> 
>> +	}
>> +
>> +	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 == 4
> 
> Or reg 0 appears twice?

In both of the cases that you mentioned, the device tree schema check
will fail, hence, we can safely assume that this will be 0 and 1 only.

> 
>    Andrew

Thanks,
Puranjay Mohan



More information about the linux-arm-kernel mailing list