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

Andrew Lunn andrew at lunn.ch
Fri May 6 09:44:11 PDT 2022


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



More information about the linux-arm-kernel mailing list