Commit 753a026c authored by Clément Léger's avatar Clément Léger Committed by Jakub Kicinski
Browse files

net: ocelot: add FDMA support



Ethernet frames can be extracted or injected autonomously to or from
the device’s DDR3/DDR3L memory and/or PCIe memory space. Linked list
data structures in memory are used for injecting or extracting Ethernet
frames. The FDMA generates interrupts when frame extraction or
injection is done and when the linked lists need updating.

The FDMA is shared between all the ethernet ports of the switch and
uses a linked list of descriptors (DCB) to inject and extract packets.
Before adding descriptors, the FDMA channels must be stopped. It would
be inefficient to do that each time a descriptor would be added so the
channels are restarted only once they stopped.

Both channels uses ring-like structure to feed the DCBs to the FDMA.
head and tail are never touched by hardware and are completely handled
by the driver. On top of that, page recycling has been added and is
mostly taken from gianfar driver.

Reviewed-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Co-developed-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: default avatarClément Léger <clement.leger@bootlin.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent de5841e1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12,5 +12,6 @@ mscc_ocelot_switch_lib-y := \
mscc_ocelot_switch_lib-$(CONFIG_BRIDGE_MRP) += ocelot_mrp.o
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot.o
mscc_ocelot-y := \
	ocelot_fdma.o \
	ocelot_vsc7514.o \
	ocelot_net.o
+894 −0

File added.

Preview size limit exceeded, changes collapsed.

+166 −0

File added.

Preview size limit exceeded, changes collapsed.

+21 −4
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <net/pkt_cls.h>
#include "ocelot.h"
#include "ocelot_vcap.h"
#include "ocelot_fdma.h"

#define OCELOT_MAC_QUIRKS	OCELOT_QUIRK_QSGMII_PORTS_MUST_BE_UP

@@ -457,7 +458,8 @@ static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
	int port = priv->chip_port;
	u32 rew_op = 0;

	if (!ocelot_can_inject(ocelot, 0))
	if (!static_branch_unlikely(&ocelot_fdma_enabled) &&
	    !ocelot_can_inject(ocelot, 0))
		return NETDEV_TX_BUSY;

	/* Check if timestamping is needed */
@@ -475,9 +477,13 @@ static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
		rew_op = ocelot_ptp_rew_op(skb);
	}

	if (static_branch_unlikely(&ocelot_fdma_enabled)) {
		ocelot_fdma_inject_frame(ocelot, port, rew_op, skb, dev);
	} else {
		ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);

	kfree_skb(skb);
		consume_skb(skb);
	}

	return NETDEV_TX_OK;
}
@@ -1699,14 +1705,20 @@ int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target,
	if (err)
		goto out;

	if (ocelot->fdma)
		ocelot_fdma_netdev_init(ocelot, dev);

	err = register_netdev(dev);
	if (err) {
		dev_err(ocelot->dev, "register_netdev failed\n");
		goto out;
		goto out_fdma_deinit;
	}

	return 0;

out_fdma_deinit:
	if (ocelot->fdma)
		ocelot_fdma_netdev_deinit(ocelot, dev);
out:
	ocelot->ports[port] = NULL;
	free_netdev(dev);
@@ -1719,9 +1731,14 @@ void ocelot_release_port(struct ocelot_port *ocelot_port)
	struct ocelot_port_private *priv = container_of(ocelot_port,
						struct ocelot_port_private,
						port);
	struct ocelot *ocelot = ocelot_port->ocelot;
	struct ocelot_fdma *fdma = ocelot->fdma;

	unregister_netdev(priv->dev);

	if (fdma)
		ocelot_fdma_netdev_deinit(ocelot, priv->dev);

	if (priv->phylink) {
		rtnl_lock();
		phylink_disconnect_phy(priv->phylink);
+10 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading