Commit 7e89350c authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'dpaa2-switch-next'



Ioana Ciornei says:

====================
dpaa2-switch: integrate the MAC endpoint support

This patch set integrates the already available MAC support into the
dpaa2-switch driver as well.

The first 4 patches are fixing up some minor problems or optimizing the
code, while the remaining ones are actually integrating the dpaa2-mac
support into the switch driver by calling the dpaa2_mac_* provided
functions. While at it, we also export the MAC statistics in ethtool
like we do for dpaa2-eth.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b820c114 f0653a89
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -914,7 +914,8 @@ void fsl_mc_device_remove(struct fsl_mc_device *mc_dev)
}
EXPORT_SYMBOL_GPL(fsl_mc_device_remove);

struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev)
struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev,
					  u16 if_id)
{
	struct fsl_mc_device *mc_bus_dev, *endpoint;
	struct fsl_mc_obj_desc endpoint_desc = {{ 0 }};
@@ -925,6 +926,7 @@ struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev)
	mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
	strcpy(endpoint1.type, mc_dev->obj_desc.type);
	endpoint1.id = mc_dev->obj_desc.id;
	endpoint1.if_id = if_id;

	err = dprc_get_connection(mc_bus_dev->mc_io, 0,
				  mc_bus_dev->mc_handle,
+1 −1
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@ fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o dpaa2-mac.o dpmac.o dpa
fsl-dpaa2-eth-${CONFIG_FSL_DPAA2_ETH_DCB} += dpaa2-eth-dcb.o
fsl-dpaa2-eth-${CONFIG_DEBUG_FS} += dpaa2-eth-debugfs.o
fsl-dpaa2-ptp-objs	:= dpaa2-ptp.o dprtc.o
fsl-dpaa2-switch-objs	:= dpaa2-switch.o dpaa2-switch-ethtool.o dpsw.o dpaa2-switch-flower.o
fsl-dpaa2-switch-objs	:= dpaa2-switch.o dpaa2-switch-ethtool.o dpsw.o dpaa2-switch-flower.o dpaa2-mac.o dpmac.o

# Needed by the tracing framework
CFLAGS_dpaa2-eth.o := -I$(src)
+1 −1
Original line number Diff line number Diff line
@@ -4138,7 +4138,7 @@ static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv)
	int err;

	dpni_dev = to_fsl_mc_device(priv->net_dev->dev.parent);
	dpmac_dev = fsl_mc_get_endpoint(dpni_dev);
	dpmac_dev = fsl_mc_get_endpoint(dpni_dev, 0);

	if (PTR_ERR(dpmac_dev) == -EPROBE_DEFER)
		return PTR_ERR(dpmac_dev);
+39 −17
Original line number Diff line number Diff line
@@ -15,18 +15,18 @@ static struct {
	enum dpsw_counter id;
	char name[ETH_GSTRING_LEN];
} dpaa2_switch_ethtool_counters[] =  {
	{DPSW_CNT_ING_FRAME,		"rx frames"},
	{DPSW_CNT_ING_BYTE,		"rx bytes"},
	{DPSW_CNT_ING_FLTR_FRAME,	"rx filtered frames"},
	{DPSW_CNT_ING_FRAME_DISCARD,	"rx discarded frames"},
	{DPSW_CNT_ING_BCAST_FRAME,	"rx b-cast frames"},
	{DPSW_CNT_ING_BCAST_BYTES,	"rx b-cast bytes"},
	{DPSW_CNT_ING_MCAST_FRAME,	"rx m-cast frames"},
	{DPSW_CNT_ING_MCAST_BYTE,	"rx m-cast bytes"},
	{DPSW_CNT_EGR_FRAME,		"tx frames"},
	{DPSW_CNT_EGR_BYTE,		"tx bytes"},
	{DPSW_CNT_EGR_FRAME_DISCARD,	"tx discarded frames"},
	{DPSW_CNT_ING_NO_BUFF_DISCARD,	"rx discarded no buffer frames"},
	{DPSW_CNT_ING_FRAME,		"[hw] rx frames"},
	{DPSW_CNT_ING_BYTE,		"[hw] rx bytes"},
	{DPSW_CNT_ING_FLTR_FRAME,	"[hw] rx filtered frames"},
	{DPSW_CNT_ING_FRAME_DISCARD,	"[hw] rx discarded frames"},
	{DPSW_CNT_ING_BCAST_FRAME,	"[hw] rx bcast frames"},
	{DPSW_CNT_ING_BCAST_BYTES,	"[hw] rx bcast bytes"},
	{DPSW_CNT_ING_MCAST_FRAME,	"[hw] rx mcast frames"},
	{DPSW_CNT_ING_MCAST_BYTE,	"[hw] rx mcast bytes"},
	{DPSW_CNT_EGR_FRAME,		"[hw] tx frames"},
	{DPSW_CNT_EGR_BYTE,		"[hw] tx bytes"},
	{DPSW_CNT_EGR_FRAME_DISCARD,	"[hw] tx discarded frames"},
	{DPSW_CNT_ING_NO_BUFF_DISCARD,	"[hw] rx nobuffer discards"},
};

#define DPAA2_SWITCH_NUM_COUNTERS	ARRAY_SIZE(dpaa2_switch_ethtool_counters)
@@ -62,6 +62,10 @@ dpaa2_switch_get_link_ksettings(struct net_device *netdev,
	struct dpsw_link_state state = {0};
	int err = 0;

	if (dpaa2_switch_port_is_type_phy(port_priv))
		return phylink_ethtool_ksettings_get(port_priv->mac->phylink,
						     link_ksettings);

	err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0,
				     port_priv->ethsw_data->dpsw_handle,
				     port_priv->idx,
@@ -95,6 +99,10 @@ dpaa2_switch_set_link_ksettings(struct net_device *netdev,
	bool if_running;
	int err = 0, ret;

	if (dpaa2_switch_port_is_type_phy(port_priv))
		return phylink_ethtool_ksettings_set(port_priv->mac->phylink,
						     link_ksettings);

	/* Interface needs to be down to change link settings */
	if_running = netif_running(netdev);
	if (if_running) {
@@ -134,11 +142,17 @@ dpaa2_switch_set_link_ksettings(struct net_device *netdev,
	return err;
}

static int dpaa2_switch_ethtool_get_sset_count(struct net_device *dev, int sset)
static int
dpaa2_switch_ethtool_get_sset_count(struct net_device *netdev, int sset)
{
	struct ethsw_port_priv *port_priv = netdev_priv(netdev);
	int num_ss_stats = DPAA2_SWITCH_NUM_COUNTERS;

	switch (sset) {
	case ETH_SS_STATS:
		return DPAA2_SWITCH_NUM_COUNTERS;
		if (port_priv->mac)
			num_ss_stats += dpaa2_mac_get_sset_count();
		return num_ss_stats;
	default:
		return -EOPNOTSUPP;
	}
@@ -147,14 +161,19 @@ static int dpaa2_switch_ethtool_get_sset_count(struct net_device *dev, int sset)
static void dpaa2_switch_ethtool_get_strings(struct net_device *netdev,
					     u32 stringset, u8 *data)
{
	struct ethsw_port_priv *port_priv = netdev_priv(netdev);
	u8 *p = data;
	int i;

	switch (stringset) {
	case ETH_SS_STATS:
		for (i = 0; i < DPAA2_SWITCH_NUM_COUNTERS; i++)
			memcpy(data + i * ETH_GSTRING_LEN,
			       dpaa2_switch_ethtool_counters[i].name,
		for (i = 0; i < DPAA2_SWITCH_NUM_COUNTERS; i++) {
			memcpy(p, dpaa2_switch_ethtool_counters[i].name,
			       ETH_GSTRING_LEN);
			p += ETH_GSTRING_LEN;
		}
		if (port_priv->mac)
			dpaa2_mac_get_strings(p);
		break;
	}
}
@@ -176,6 +195,9 @@ static void dpaa2_switch_ethtool_get_stats(struct net_device *netdev,
			netdev_err(netdev, "dpsw_if_get_counter[%s] err %d\n",
				   dpaa2_switch_ethtool_counters[i].name, err);
	}

	if (port_priv->mac)
		dpaa2_mac_get_ethtool_stats(port_priv->mac, data + i);
}

const struct ethtool_ops dpaa2_switch_port_ethtool_ops = {
+108 −43
Original line number Diff line number Diff line
@@ -594,12 +594,18 @@ static int dpaa2_switch_port_change_mtu(struct net_device *netdev, int mtu)
	return 0;
}

static int dpaa2_switch_port_carrier_state_sync(struct net_device *netdev)
static int dpaa2_switch_port_link_state_update(struct net_device *netdev)
{
	struct ethsw_port_priv *port_priv = netdev_priv(netdev);
	struct dpsw_link_state state;
	int err;

	/* When we manage the MAC/PHY using phylink there is no need
	 * to manually update the netif_carrier.
	 */
	if (dpaa2_switch_port_is_type_phy(port_priv))
		return 0;

	/* Interrupts are received even though no one issued an 'ifconfig up'
	 * on the switch interface. Ignore these link state update interrupts
	 */
@@ -677,12 +683,14 @@ static int dpaa2_switch_port_open(struct net_device *netdev)
	struct ethsw_core *ethsw = port_priv->ethsw_data;
	int err;

	if (!dpaa2_switch_port_is_type_phy(port_priv)) {
		/* Explicitly set carrier off, otherwise
		 * netif_carrier_ok() will return true and cause 'ip link show'
		 * to report the LOWER_UP flag, even though the link
		 * notification wasn't even received.
		 */
		netif_carrier_off(netdev);
	}

	err = dpsw_if_enable(port_priv->ethsw_data->mc_io, 0,
			     port_priv->ethsw_data->dpsw_handle,
@@ -692,23 +700,12 @@ static int dpaa2_switch_port_open(struct net_device *netdev)
		return err;
	}

	/* sync carrier state */
	err = dpaa2_switch_port_carrier_state_sync(netdev);
	if (err) {
		netdev_err(netdev,
			   "dpaa2_switch_port_carrier_state_sync err %d\n", err);
		goto err_carrier_sync;
	}

	dpaa2_switch_enable_ctrl_if_napi(ethsw);

	return 0;
	if (dpaa2_switch_port_is_type_phy(port_priv))
		phylink_start(port_priv->mac->phylink);

err_carrier_sync:
	dpsw_if_disable(port_priv->ethsw_data->mc_io, 0,
			port_priv->ethsw_data->dpsw_handle,
			port_priv->idx);
	return err;
	return 0;
}

static int dpaa2_switch_port_stop(struct net_device *netdev)
@@ -717,6 +714,13 @@ static int dpaa2_switch_port_stop(struct net_device *netdev)
	struct ethsw_core *ethsw = port_priv->ethsw_data;
	int err;

	if (dpaa2_switch_port_is_type_phy(port_priv)) {
		phylink_stop(port_priv->mac->phylink);
	} else {
		netif_tx_stop_all_queues(netdev);
		netif_carrier_off(netdev);
	}

	err = dpsw_if_disable(port_priv->ethsw_data->mc_io, 0,
			      port_priv->ethsw_data->dpsw_handle,
			      port_priv->idx);
@@ -1419,41 +1423,103 @@ bool dpaa2_switch_port_dev_check(const struct net_device *netdev)
	return netdev->netdev_ops == &dpaa2_switch_port_ops;
}

static void dpaa2_switch_links_state_update(struct ethsw_core *ethsw)
static int dpaa2_switch_port_connect_mac(struct ethsw_port_priv *port_priv)
{
	int i;
	struct fsl_mc_device *dpsw_port_dev, *dpmac_dev;
	struct dpaa2_mac *mac;
	int err;

	for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
		dpaa2_switch_port_carrier_state_sync(ethsw->ports[i]->netdev);
		dpaa2_switch_port_set_mac_addr(ethsw->ports[i]);
	dpsw_port_dev = to_fsl_mc_device(port_priv->netdev->dev.parent);
	dpmac_dev = fsl_mc_get_endpoint(dpsw_port_dev, port_priv->idx);

	if (PTR_ERR(dpmac_dev) == -EPROBE_DEFER)
		return PTR_ERR(dpmac_dev);

	if (IS_ERR(dpmac_dev) || dpmac_dev->dev.type != &fsl_mc_bus_dpmac_type)
		return 0;

	mac = kzalloc(sizeof(*mac), GFP_KERNEL);
	if (!mac)
		return -ENOMEM;

	mac->mc_dev = dpmac_dev;
	mac->mc_io = port_priv->ethsw_data->mc_io;
	mac->net_dev = port_priv->netdev;

	err = dpaa2_mac_open(mac);
	if (err)
		goto err_free_mac;
	port_priv->mac = mac;

	if (dpaa2_switch_port_is_type_phy(port_priv)) {
		err = dpaa2_mac_connect(mac);
		if (err) {
			netdev_err(port_priv->netdev,
				   "Error connecting to the MAC endpoint %pe\n",
				   ERR_PTR(err));
			goto err_close_mac;
		}
	}

	return 0;

err_close_mac:
	dpaa2_mac_close(mac);
	port_priv->mac = NULL;
err_free_mac:
	kfree(mac);
	return err;
}

static void dpaa2_switch_port_disconnect_mac(struct ethsw_port_priv *port_priv)
{
	if (dpaa2_switch_port_is_type_phy(port_priv))
		dpaa2_mac_disconnect(port_priv->mac);

	if (!dpaa2_switch_port_has_mac(port_priv))
		return;

	dpaa2_mac_close(port_priv->mac);
	kfree(port_priv->mac);
	port_priv->mac = NULL;
}

static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg)
{
	struct device *dev = (struct device *)arg;
	struct ethsw_core *ethsw = dev_get_drvdata(dev);

	/* Mask the events and the if_id reserved bits to be cleared on read */
	u32 status = DPSW_IRQ_EVENT_LINK_CHANGED | 0xFFFF0000;
	int err;
	struct ethsw_port_priv *port_priv;
	u32 status = ~0;
	int err, if_id;

	err = dpsw_get_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,
				  DPSW_IRQ_INDEX_IF, &status);
	if (err) {
		dev_err(dev, "Can't get irq status (err %d)\n", err);

		err = dpsw_clear_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,
					    DPSW_IRQ_INDEX_IF, 0xFFFFFFFF);
		if (err)
			dev_err(dev, "Can't clear irq status (err %d)\n", err);
		goto out;
	}

	if (status & DPSW_IRQ_EVENT_LINK_CHANGED)
		dpaa2_switch_links_state_update(ethsw);
	if_id = (status & 0xFFFF0000) >> 16;
	port_priv = ethsw->ports[if_id];

	if (status & DPSW_IRQ_EVENT_LINK_CHANGED) {
		dpaa2_switch_port_link_state_update(port_priv->netdev);
		dpaa2_switch_port_set_mac_addr(port_priv);
	}

	if (status & DPSW_IRQ_EVENT_ENDPOINT_CHANGED) {
		if (dpaa2_switch_port_has_mac(port_priv))
			dpaa2_switch_port_disconnect_mac(port_priv);
		else
			dpaa2_switch_port_connect_mac(port_priv);
	}

out:
	err = dpsw_clear_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,
				    DPSW_IRQ_INDEX_IF, status);
	if (err)
		dev_err(dev, "Can't clear irq status (err %d)\n", err);

	return IRQ_HANDLED;
}

@@ -3133,6 +3199,7 @@ static int dpaa2_switch_remove(struct fsl_mc_device *sw_dev)
	for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
		port_priv = ethsw->ports[i];
		unregister_netdev(port_priv->netdev);
		dpaa2_switch_port_disconnect_mac(port_priv);
		free_netdev(port_priv->netdev);
	}

@@ -3212,6 +3279,10 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw,
		goto err_port_probe;
	port_priv->learn_ena = false;

	err = dpaa2_switch_port_connect_mac(port_priv);
	if (err)
		goto err_port_probe;

	return 0;

err_port_probe:
@@ -3288,12 +3359,6 @@ static int dpaa2_switch_probe(struct fsl_mc_device *sw_dev)
			       &ethsw->fq[i].napi, dpaa2_switch_poll,
			       NAPI_POLL_WEIGHT);

	err = dpsw_enable(ethsw->mc_io, 0, ethsw->dpsw_handle);
	if (err) {
		dev_err(ethsw->dev, "dpsw_enable err %d\n", err);
		goto err_free_netdev;
	}

	/* Setup IRQs */
	err = dpaa2_switch_setup_irqs(sw_dev);
	if (err)
Loading