diff options
Diffstat (limited to 'drivers/net/ethernet/mscc')
| -rw-r--r-- | drivers/net/ethernet/mscc/ocelot.c | 26 | ||||
| -rw-r--r-- | drivers/net/ethernet/mscc/ocelot_net.c | 12 | ||||
| -rw-r--r-- | drivers/net/ethernet/mscc/ocelot_vsc7514.c | 249 | 
3 files changed, 167 insertions, 120 deletions
| diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 867c680f5917..8518e1d60da4 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -421,10 +421,15 @@ int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port,  	if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP &&  	    ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { +		spin_lock(&ocelot_port->ts_id_lock); +  		shinfo->tx_flags |= SKBTX_IN_PROGRESS;  		/* Store timestamp ID in cb[0] of sk_buff */ -		skb->cb[0] = ocelot_port->ts_id % 4; +		skb->cb[0] = ocelot_port->ts_id; +		ocelot_port->ts_id = (ocelot_port->ts_id + 1) % 4;  		skb_queue_tail(&ocelot_port->tx_skbs, skb); + +		spin_unlock(&ocelot_port->ts_id_lock);  		return 0;  	}  	return -ENODATA; @@ -859,7 +864,7 @@ void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state)  	switch (state) {  	case BR_STATE_FORWARDING:  		ocelot->bridge_fwd_mask |= BIT(port); -		/* Fallthrough */ +		fallthrough;  	case BR_STATE_LEARNING:  		port_cfg |= ANA_PORT_PORT_CFG_LEARN_ENA;  		break; @@ -1300,6 +1305,7 @@ void ocelot_init_port(struct ocelot *ocelot, int port)  	struct ocelot_port *ocelot_port = ocelot->ports[port];  	skb_queue_head_init(&ocelot_port->tx_skbs); +	spin_lock_init(&ocelot_port->ts_id_lock);  	/* Basic L2 initialization */ @@ -1544,18 +1550,18 @@ EXPORT_SYMBOL(ocelot_init);  void ocelot_deinit(struct ocelot *ocelot)  { -	struct ocelot_port *port; -	int i; -  	cancel_delayed_work(&ocelot->stats_work);  	destroy_workqueue(ocelot->stats_queue);  	mutex_destroy(&ocelot->stats_lock); - -	for (i = 0; i < ocelot->num_phys_ports; i++) { -		port = ocelot->ports[i]; -		skb_queue_purge(&port->tx_skbs); -	}  }  EXPORT_SYMBOL(ocelot_deinit); +void ocelot_deinit_port(struct ocelot *ocelot, int port) +{ +	struct ocelot_port *ocelot_port = ocelot->ports[port]; + +	skb_queue_purge(&ocelot_port->tx_skbs); +} +EXPORT_SYMBOL(ocelot_deinit_port); +  MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c index 0668d23cdbfa..8490e42e9e2d 100644 --- a/drivers/net/ethernet/mscc/ocelot_net.c +++ b/drivers/net/ethernet/mscc/ocelot_net.c @@ -330,6 +330,7 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)  	u8 grp = 0; /* Send everything on CPU group 0 */  	unsigned int i, count, last;  	int port = priv->chip_port; +	bool do_tstamp;  	val = ocelot_read(ocelot, QS_INJ_STATUS);  	if (!(val & QS_INJ_STATUS_FIFO_RDY(BIT(grp))) || @@ -344,10 +345,12 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)  	info.vid = skb_vlan_tag_get(skb);  	/* Check if timestamping is needed */ +	do_tstamp = (ocelot_port_add_txtstamp_skb(ocelot_port, skb) == 0); +  	if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP) {  		info.rew_op = ocelot_port->ptp_cmd;  		if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) -			info.rew_op |= (ocelot_port->ts_id  % 4) << 3; +			info.rew_op |= skb->cb[0] << 3;  	}  	ocelot_gen_ifh(ifh, &info); @@ -380,12 +383,9 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)  	dev->stats.tx_packets++;  	dev->stats.tx_bytes += skb->len; -	if (!ocelot_port_add_txtstamp_skb(ocelot_port, skb)) { -		ocelot_port->ts_id++; -		return NETDEV_TX_OK; -	} +	if (!do_tstamp) +		dev_kfree_skb_any(skb); -	dev_kfree_skb_any(skb);  	return NETDEV_TX_OK;  } diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c index 65408bc994c4..dfb1535f26f2 100644 --- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c +++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c @@ -806,17 +806,17 @@ static const struct vcap_field vsc7514_vcap_is2_keys[] = {  	[VCAP_IS2_HK_DIP_EQ_SIP]		= {123,   1},  	/* IP4_TCP_UDP (TYPE=100) */  	[VCAP_IS2_HK_TCP]			= {124,   1}, -	[VCAP_IS2_HK_L4_SPORT]			= {125,  16}, -	[VCAP_IS2_HK_L4_DPORT]			= {141,  16}, +	[VCAP_IS2_HK_L4_DPORT]			= {125,  16}, +	[VCAP_IS2_HK_L4_SPORT]			= {141,  16},  	[VCAP_IS2_HK_L4_RNG]			= {157,   8},  	[VCAP_IS2_HK_L4_SPORT_EQ_DPORT]		= {165,   1},  	[VCAP_IS2_HK_L4_SEQUENCE_EQ0]		= {166,   1}, -	[VCAP_IS2_HK_L4_URG]			= {167,   1}, -	[VCAP_IS2_HK_L4_ACK]			= {168,   1}, -	[VCAP_IS2_HK_L4_PSH]			= {169,   1}, -	[VCAP_IS2_HK_L4_RST]			= {170,   1}, -	[VCAP_IS2_HK_L4_SYN]			= {171,   1}, -	[VCAP_IS2_HK_L4_FIN]			= {172,   1}, +	[VCAP_IS2_HK_L4_FIN]			= {167,   1}, +	[VCAP_IS2_HK_L4_SYN]			= {168,   1}, +	[VCAP_IS2_HK_L4_RST]			= {169,   1}, +	[VCAP_IS2_HK_L4_PSH]			= {170,   1}, +	[VCAP_IS2_HK_L4_ACK]			= {171,   1}, +	[VCAP_IS2_HK_L4_URG]			= {172,   1},  	[VCAP_IS2_HK_L4_1588_DOM]		= {173,   8},  	[VCAP_IS2_HK_L4_1588_VER]		= {181,   4},  	/* IP4_OTHER (TYPE=101) */ @@ -896,11 +896,137 @@ static struct ptp_clock_info ocelot_ptp_clock_info = {  	.enable		= ocelot_ptp_enable,  }; +static void mscc_ocelot_release_ports(struct ocelot *ocelot) +{ +	int port; + +	for (port = 0; port < ocelot->num_phys_ports; port++) { +		struct ocelot_port_private *priv; +		struct ocelot_port *ocelot_port; + +		ocelot_port = ocelot->ports[port]; +		if (!ocelot_port) +			continue; + +		ocelot_deinit_port(ocelot, port); + +		priv = container_of(ocelot_port, struct ocelot_port_private, +				    port); + +		unregister_netdev(priv->dev); +		free_netdev(priv->dev); +	} +} + +static int mscc_ocelot_init_ports(struct platform_device *pdev, +				  struct device_node *ports) +{ +	struct ocelot *ocelot = platform_get_drvdata(pdev); +	struct device_node *portnp; +	int err; + +	ocelot->ports = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports, +				     sizeof(struct ocelot_port *), GFP_KERNEL); +	if (!ocelot->ports) +		return -ENOMEM; + +	/* No NPI port */ +	ocelot_configure_cpu(ocelot, -1, OCELOT_TAG_PREFIX_NONE, +			     OCELOT_TAG_PREFIX_NONE); + +	for_each_available_child_of_node(ports, portnp) { +		struct ocelot_port_private *priv; +		struct ocelot_port *ocelot_port; +		struct device_node *phy_node; +		phy_interface_t phy_mode; +		struct phy_device *phy; +		struct regmap *target; +		struct resource *res; +		struct phy *serdes; +		char res_name[8]; +		u32 port; + +		if (of_property_read_u32(portnp, "reg", &port)) +			continue; + +		snprintf(res_name, sizeof(res_name), "port%d", port); + +		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, +						   res_name); +		target = ocelot_regmap_init(ocelot, res); +		if (IS_ERR(target)) +			continue; + +		phy_node = of_parse_phandle(portnp, "phy-handle", 0); +		if (!phy_node) +			continue; + +		phy = of_phy_find_device(phy_node); +		of_node_put(phy_node); +		if (!phy) +			continue; + +		err = ocelot_probe_port(ocelot, port, target, phy); +		if (err) { +			of_node_put(portnp); +			return err; +		} + +		ocelot_port = ocelot->ports[port]; +		priv = container_of(ocelot_port, struct ocelot_port_private, +				    port); + +		of_get_phy_mode(portnp, &phy_mode); + +		ocelot_port->phy_mode = phy_mode; + +		switch (ocelot_port->phy_mode) { +		case PHY_INTERFACE_MODE_NA: +			continue; +		case PHY_INTERFACE_MODE_SGMII: +			break; +		case PHY_INTERFACE_MODE_QSGMII: +			/* Ensure clock signals and speed is set on all +			 * QSGMII links +			 */ +			ocelot_port_writel(ocelot_port, +					   DEV_CLOCK_CFG_LINK_SPEED +					   (OCELOT_SPEED_1000), +					   DEV_CLOCK_CFG); +			break; +		default: +			dev_err(ocelot->dev, +				"invalid phy mode for port%d, (Q)SGMII only\n", +				port); +			of_node_put(portnp); +			return -EINVAL; +		} + +		serdes = devm_of_phy_get(ocelot->dev, portnp, NULL); +		if (IS_ERR(serdes)) { +			err = PTR_ERR(serdes); +			if (err == -EPROBE_DEFER) +				dev_dbg(ocelot->dev, "deferring probe\n"); +			else +				dev_err(ocelot->dev, +					"missing SerDes phys for port%d\n", +					port); + +			of_node_put(portnp); +			return err; +		} + +		priv->serdes = serdes; +	} + +	return 0; +} +  static int mscc_ocelot_probe(struct platform_device *pdev)  {  	struct device_node *np = pdev->dev.of_node; -	struct device_node *ports, *portnp;  	int err, irq_xtr, irq_ptp_rdy; +	struct device_node *ports;  	struct ocelot *ocelot;  	struct regmap *hsio;  	unsigned int i; @@ -985,20 +1111,24 @@ static int mscc_ocelot_probe(struct platform_device *pdev)  	ports = of_get_child_by_name(np, "ethernet-ports");  	if (!ports) { -		dev_err(&pdev->dev, "no ethernet-ports child node found\n"); +		dev_err(ocelot->dev, "no ethernet-ports child node found\n");  		return -ENODEV;  	}  	ocelot->num_phys_ports = of_get_child_count(ports); -	ocelot->ports = devm_kcalloc(&pdev->dev, ocelot->num_phys_ports, -				     sizeof(struct ocelot_port *), GFP_KERNEL); -  	ocelot->vcap_is2_keys = vsc7514_vcap_is2_keys;  	ocelot->vcap_is2_actions = vsc7514_vcap_is2_actions;  	ocelot->vcap = vsc7514_vcap_props; -	ocelot_init(ocelot); +	err = ocelot_init(ocelot); +	if (err) +		goto out_put_ports; + +	err = mscc_ocelot_init_ports(pdev, ports); +	if (err) +		goto out_put_ports; +  	if (ocelot->ptp) {  		err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info);  		if (err) { @@ -1008,96 +1138,6 @@ static int mscc_ocelot_probe(struct platform_device *pdev)  		}  	} -	/* No NPI port */ -	ocelot_configure_cpu(ocelot, -1, OCELOT_TAG_PREFIX_NONE, -			     OCELOT_TAG_PREFIX_NONE); - -	for_each_available_child_of_node(ports, portnp) { -		struct ocelot_port_private *priv; -		struct ocelot_port *ocelot_port; -		struct device_node *phy_node; -		phy_interface_t phy_mode; -		struct phy_device *phy; -		struct regmap *target; -		struct resource *res; -		struct phy *serdes; -		char res_name[8]; -		u32 port; - -		if (of_property_read_u32(portnp, "reg", &port)) -			continue; - -		snprintf(res_name, sizeof(res_name), "port%d", port); - -		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, -						   res_name); -		target = ocelot_regmap_init(ocelot, res); -		if (IS_ERR(target)) -			continue; - -		phy_node = of_parse_phandle(portnp, "phy-handle", 0); -		if (!phy_node) -			continue; - -		phy = of_phy_find_device(phy_node); -		of_node_put(phy_node); -		if (!phy) -			continue; - -		err = ocelot_probe_port(ocelot, port, target, phy); -		if (err) { -			of_node_put(portnp); -			goto out_put_ports; -		} - -		ocelot_port = ocelot->ports[port]; -		priv = container_of(ocelot_port, struct ocelot_port_private, -				    port); - -		of_get_phy_mode(portnp, &phy_mode); - -		ocelot_port->phy_mode = phy_mode; - -		switch (ocelot_port->phy_mode) { -		case PHY_INTERFACE_MODE_NA: -			continue; -		case PHY_INTERFACE_MODE_SGMII: -			break; -		case PHY_INTERFACE_MODE_QSGMII: -			/* Ensure clock signals and speed is set on all -			 * QSGMII links -			 */ -			ocelot_port_writel(ocelot_port, -					   DEV_CLOCK_CFG_LINK_SPEED -					   (OCELOT_SPEED_1000), -					   DEV_CLOCK_CFG); -			break; -		default: -			dev_err(ocelot->dev, -				"invalid phy mode for port%d, (Q)SGMII only\n", -				port); -			of_node_put(portnp); -			err = -EINVAL; -			goto out_put_ports; -		} - -		serdes = devm_of_phy_get(ocelot->dev, portnp, NULL); -		if (IS_ERR(serdes)) { -			err = PTR_ERR(serdes); -			if (err == -EPROBE_DEFER) -				dev_dbg(ocelot->dev, "deferring probe\n"); -			else -				dev_err(ocelot->dev, -					"missing SerDes phys for port%d\n", -					port); - -			of_node_put(portnp); -			goto out_put_ports; -		} - -		priv->serdes = serdes; -	} -  	register_netdevice_notifier(&ocelot_netdevice_nb);  	register_switchdev_notifier(&ocelot_switchdev_nb);  	register_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb); @@ -1114,6 +1154,7 @@ static int mscc_ocelot_remove(struct platform_device *pdev)  	struct ocelot *ocelot = platform_get_drvdata(pdev);  	ocelot_deinit_timestamp(ocelot); +	mscc_ocelot_release_ports(ocelot);  	ocelot_deinit(ocelot);  	unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);  	unregister_switchdev_notifier(&ocelot_switchdev_nb); |