All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jiri Pirko <jiri@resnulli.us>
To: Vadym Kochan <vadym.kochan@plvision.eu>
Cc: "David S. Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>, Jiri Pirko <jiri@mellanox.com>,
	Ido Schimmel <idosch@mellanox.com>, Andrew Lunn <andrew@lunn.ch>,
	Oleksandr Mazur <oleksandr.mazur@plvision.eu>,
	Serhiy Boiko <serhiy.boiko@plvision.eu>,
	Serhiy Pshyk <serhiy.pshyk@plvision.eu>,
	Volodymyr Mytnyk <volodymyr.mytnyk@plvision.eu>,
	Taras Chornyi <taras.chornyi@plvision.eu>,
	Andrii Savka <andrii.savka@plvision.eu>,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	Mickey Rachamim <mickeyr@marvell.com>
Subject: Re: [net-next 1/6] net: marvell: prestera: Add driver for Prestera family ASIC devices
Date: Wed, 3 Jun 2020 16:16:32 +0200	[thread overview]
Message-ID: <20200603141632.GA2274@nanopsycho.orion> (raw)
In-Reply-To: <20200528151245.7592-2-vadym.kochan@plvision.eu>

Thu, May 28, 2020 at 05:12:40PM CEST, vadym.kochan@plvision.eu wrote:

[...]

>+}
>+
>+int prestera_hw_port_info_get(const struct prestera_port *port,
>+			      u16 *fp_id, u32 *hw_id, u32 *dev_id)

Please unify the ordering of "hw_id" and "dev_id" with the rest of the
functions having the same args.



>+{
>+	struct prestera_msg_port_info_resp resp;
>+	struct prestera_msg_port_info_req req = {
>+		.port = port->id
>+	};
>+	int err;
>+
>+	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_INFO_GET,
>+			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
>+	if (err)
>+		return err;
>+
>+	*hw_id = resp.hw_id;
>+	*dev_id = resp.dev_id;
>+	*fp_id = resp.fp_id;
>+
>+	return 0;
>+}
>+
>+int prestera_hw_switch_mac_set(struct prestera_switch *sw, char *mac)
>+{
>+	struct prestera_msg_switch_attr_req req = {
>+		.attr = PRESTERA_CMD_SWITCH_ATTR_MAC,
>+	};
>+
>+	memcpy(req.param.mac, mac, sizeof(req.param.mac));
>+
>+	return prestera_cmd(sw, PRESTERA_CMD_TYPE_SWITCH_ATTR_SET,
>+			    &req.cmd, sizeof(req));
>+}
>+
>+int prestera_hw_switch_init(struct prestera_switch *sw)
>+{
>+	struct prestera_msg_switch_init_resp resp;
>+	struct prestera_msg_common_req req;
>+	int err;
>+
>+	INIT_LIST_HEAD(&sw->event_handlers);
>+
>+	err = prestera_cmd_ret_wait(sw, PRESTERA_CMD_TYPE_SWITCH_INIT,
>+				    &req.cmd, sizeof(req),
>+				    &resp.ret, sizeof(resp),
>+				    PRESTERA_SWITCH_INIT_TIMEOUT);
>+	if (err)
>+		return err;
>+
>+	sw->id = resp.switch_id;
>+	sw->port_count = resp.port_count;
>+	sw->mtu_min = PRESTERA_MIN_MTU;
>+	sw->mtu_max = resp.mtu_max;
>+	sw->dev->recv_msg = prestera_evt_recv;
>+	sw->dev->recv_pkt = prestera_pkt_recv;
>+
>+	return 0;
>+}
>+
>+int prestera_hw_port_state_set(const struct prestera_port *port,
>+			       bool admin_state)
>+{
>+	struct prestera_msg_port_attr_req req = {
>+		.attr = PRESTERA_CMD_PORT_ATTR_ADMIN_STATE,
>+		.port = port->hw_id,
>+		.dev = port->dev_id,
>+		.param = {.admin_state = admin_state}
>+	};
>+
>+	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
>+			    &req.cmd, sizeof(req));
>+}
>+
>+int prestera_hw_port_mtu_set(const struct prestera_port *port, u32 mtu)
>+{
>+	struct prestera_msg_port_attr_req req = {
>+		.attr = PRESTERA_CMD_PORT_ATTR_MTU,
>+		.port = port->hw_id,
>+		.dev = port->dev_id,
>+		.param = {.mtu = mtu}
>+	};
>+
>+	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
>+			    &req.cmd, sizeof(req));
>+}
>+
>+int prestera_hw_port_mac_set(const struct prestera_port *port, char *mac)
>+{
>+	struct prestera_msg_port_attr_req req = {
>+		.attr = PRESTERA_CMD_PORT_ATTR_MAC,
>+		.port = port->hw_id,
>+		.dev = port->dev_id
>+	};
>+	memcpy(&req.param.mac, mac, sizeof(req.param.mac));
>+
>+	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
>+			    &req.cmd, sizeof(req));
>+}
>+
>+int prestera_hw_port_cap_get(const struct prestera_port *port,
>+			     struct prestera_port_caps *caps)
>+{
>+	struct prestera_msg_port_attr_resp resp;
>+	struct prestera_msg_port_attr_req req = {
>+		.attr = PRESTERA_CMD_PORT_ATTR_CAPABILITY,
>+		.port = port->hw_id,
>+		.dev = port->dev_id
>+	};
>+	int err;
>+
>+	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
>+			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
>+	if (err)
>+		return err;
>+
>+	caps->supp_link_modes = resp.param.cap.link_mode;
>+	caps->supp_fec = resp.param.cap.fec;
>+	caps->type = resp.param.cap.type;
>+	caps->transceiver = resp.param.cap.transceiver;
>+
>+	return err;
>+}
>+
>+int prestera_hw_port_autoneg_set(const struct prestera_port *port,
>+				 bool autoneg, u64 link_modes, u8 fec)
>+{
>+	struct prestera_msg_port_attr_req req = {
>+		.attr = PRESTERA_CMD_PORT_ATTR_AUTONEG,
>+		.port = port->hw_id,
>+		.dev = port->dev_id,
>+		.param = {.autoneg = {.link_mode = link_modes,
>+				      .enable = autoneg,
>+				      .fec = fec}
>+		}
>+	};
>+
>+	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
>+			    &req.cmd, sizeof(req));
>+}
>+
>+int prestera_hw_port_stats_get(const struct prestera_port *port,
>+			       struct prestera_port_stats *st)
>+{
>+	struct prestera_msg_port_stats_resp resp;
>+	struct prestera_msg_port_attr_req req = {
>+		.attr = PRESTERA_CMD_PORT_ATTR_STATS,
>+		.port = port->hw_id,
>+		.dev = port->dev_id
>+	};
>+	u64 *hw = resp.stats;
>+	int err;
>+
>+	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
>+			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
>+	if (err)
>+		return err;
>+
>+	st->good_octets_received = hw[PRESTERA_PORT_GOOD_OCTETS_RCV_CNT];
>+	st->bad_octets_received = hw[PRESTERA_PORT_BAD_OCTETS_RCV_CNT];
>+	st->mac_trans_error = hw[PRESTERA_PORT_MAC_TRANSMIT_ERR_CNT];
>+	st->broadcast_frames_received = hw[PRESTERA_PORT_BRDC_PKTS_RCV_CNT];
>+	st->multicast_frames_received = hw[PRESTERA_PORT_MC_PKTS_RCV_CNT];
>+	st->frames_64_octets = hw[PRESTERA_PORT_PKTS_64L_CNT];
>+	st->frames_65_to_127_octets = hw[PRESTERA_PORT_PKTS_65TO127L_CNT];
>+	st->frames_128_to_255_octets = hw[PRESTERA_PORT_PKTS_128TO255L_CNT];
>+	st->frames_256_to_511_octets = hw[PRESTERA_PORT_PKTS_256TO511L_CNT];
>+	st->frames_512_to_1023_octets = hw[PRESTERA_PORT_PKTS_512TO1023L_CNT];
>+	st->frames_1024_to_max_octets = hw[PRESTERA_PORT_PKTS_1024TOMAXL_CNT];
>+	st->excessive_collision = hw[PRESTERA_PORT_EXCESSIVE_COLLISIONS_CNT];
>+	st->multicast_frames_sent = hw[PRESTERA_PORT_MC_PKTS_SENT_CNT];
>+	st->broadcast_frames_sent = hw[PRESTERA_PORT_BRDC_PKTS_SENT_CNT];
>+	st->fc_sent = hw[PRESTERA_PORT_FC_SENT_CNT];
>+	st->fc_received = hw[PRESTERA_PORT_GOOD_FC_RCV_CNT];
>+	st->buffer_overrun = hw[PRESTERA_PORT_DROP_EVENTS_CNT];
>+	st->undersize = hw[PRESTERA_PORT_UNDERSIZE_PKTS_CNT];
>+	st->fragments = hw[PRESTERA_PORT_FRAGMENTS_PKTS_CNT];
>+	st->oversize = hw[PRESTERA_PORT_OVERSIZE_PKTS_CNT];
>+	st->jabber = hw[PRESTERA_PORT_JABBER_PKTS_CNT];
>+	st->rx_error_frame_received = hw[PRESTERA_PORT_MAC_RCV_ERROR_CNT];
>+	st->bad_crc = hw[PRESTERA_PORT_BAD_CRC_CNT];
>+	st->collisions = hw[PRESTERA_PORT_COLLISIONS_CNT];
>+	st->late_collision = hw[PRESTERA_PORT_LATE_COLLISIONS_CNT];
>+	st->unicast_frames_received = hw[PRESTERA_PORT_GOOD_UC_PKTS_RCV_CNT];
>+	st->unicast_frames_sent = hw[PRESTERA_PORT_GOOD_UC_PKTS_SENT_CNT];
>+	st->sent_multiple = hw[PRESTERA_PORT_MULTIPLE_PKTS_SENT_CNT];
>+	st->sent_deferred = hw[PRESTERA_PORT_DEFERRED_PKTS_SENT_CNT];
>+	st->good_octets_sent = hw[PRESTERA_PORT_GOOD_OCTETS_SENT_CNT];
>+
>+	return 0;
>+}
>+
>+int prestera_hw_rxtx_init(struct prestera_switch *sw,
>+			  struct prestera_rxtx_params *params)
>+{
>+	struct prestera_msg_rxtx_resp resp;
>+	struct prestera_msg_rxtx_req req;
>+	int err;
>+
>+	req.use_sdma = params->use_sdma;
>+
>+	err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_RXTX_INIT,
>+			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
>+	if (err)
>+		return err;
>+
>+	params->map_addr = resp.map_addr;
>+	return 0;
>+}
>+
>+int prestera_hw_rxtx_port_init(struct prestera_port *port)
>+{
>+	struct prestera_msg_rxtx_port_req req = {
>+		.port = port->hw_id,
>+		.dev = port->dev_id,
>+	};
>+
>+	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_RXTX_PORT_INIT,
>+			    &req.cmd, sizeof(req));
>+}
>+
>+int prestera_hw_event_handler_register(struct prestera_switch *sw,
>+				       enum prestera_event_type type,
>+				       prestera_event_cb_t fn,
>+				       void *arg)
>+{
>+	struct prestera_fw_event_handler *eh;
>+
>+	eh = __find_event_handler(sw, type);
>+	if (eh)
>+		return -EEXIST;
>+	eh = kmalloc(sizeof(*eh), GFP_KERNEL);
>+	if (!eh)
>+		return -ENOMEM;
>+
>+	eh->type = type;
>+	eh->func = fn;
>+	eh->arg = arg;
>+
>+	INIT_LIST_HEAD(&eh->list);
>+
>+	list_add_rcu(&eh->list, &sw->event_handlers);
>+
>+	return 0;
>+}
>+
>+void prestera_hw_event_handler_unregister(struct prestera_switch *sw,
>+					  enum prestera_event_type type,
>+					  prestera_event_cb_t fn)
>+{
>+	struct prestera_fw_event_handler *eh;
>+
>+	eh = __find_event_handler(sw, type);
>+	if (!eh)
>+		return;
>+
>+	list_del_rcu(&eh->list);
>+	synchronize_rcu();
>+	kfree(eh);

Try to avoid use of synchronice rcu. You can rather do:
kfree_rcu(eh, rcu);


>+}
>diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.h b/drivers/net/ethernet/marvell/prestera/prestera_hw.h
>new file mode 100644
>index 000000000000..acb0e31d6684
>--- /dev/null
>+++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.h
>@@ -0,0 +1,71 @@
>+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
>+ *
>+ * Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved.
>+ *
>+ */
>+
>+#ifndef _PRESTERA_HW_H_
>+#define _PRESTERA_HW_H_
>+
>+#include <linux/types.h>
>+
>+enum {
>+	PRESTERA_PORT_TYPE_NONE,
>+	PRESTERA_PORT_TYPE_TP,
>+
>+	PRESTERA_PORT_TYPE_MAX,
>+};
>+
>+enum {
>+	PRESTERA_PORT_FEC_OFF,
>+
>+	PRESTERA_PORT_FEC_MAX,
>+};
>+
>+struct prestera_switch;
>+struct prestera_port;
>+struct prestera_port_stats;
>+struct prestera_port_caps;
>+enum prestera_event_type;
>+struct prestera_event;
>+
>+typedef void (*prestera_event_cb_t)
>+	(struct prestera_switch *sw, struct prestera_event *evt, void *arg);
>+
>+struct prestera_rxtx_params;
>+
>+/* Switch API */
>+int prestera_hw_switch_init(struct prestera_switch *sw);
>+int prestera_hw_switch_mac_set(struct prestera_switch *sw, char *mac);
>+
>+/* Port API */
>+int prestera_hw_port_info_get(const struct prestera_port *port,
>+			      u16 *fp_id, u32 *hw_id, u32 *dev_id);
>+int prestera_hw_port_state_set(const struct prestera_port *port,
>+			       bool admin_state);
>+int prestera_hw_port_mtu_set(const struct prestera_port *port, u32 mtu);
>+int prestera_hw_port_mtu_get(const struct prestera_port *port, u32 *mtu);
>+int prestera_hw_port_mac_set(const struct prestera_port *port, char *mac);
>+int prestera_hw_port_mac_get(const struct prestera_port *port, char *mac);
>+int prestera_hw_port_cap_get(const struct prestera_port *port,
>+			     struct prestera_port_caps *caps);
>+int prestera_hw_port_autoneg_set(const struct prestera_port *port,
>+				 bool autoneg, u64 link_modes, u8 fec);
>+int prestera_hw_port_stats_get(const struct prestera_port *port,
>+			       struct prestera_port_stats *stats);
>+
>+/* Event handlers */
>+int prestera_hw_event_handler_register(struct prestera_switch *sw,
>+				       enum prestera_event_type type,
>+				       prestera_event_cb_t fn,
>+				       void *arg);
>+void prestera_hw_event_handler_unregister(struct prestera_switch *sw,
>+					  enum prestera_event_type type,
>+					  prestera_event_cb_t fn);
>+
>+/* RX/TX */
>+int prestera_hw_rxtx_init(struct prestera_switch *sw,
>+			  struct prestera_rxtx_params *params);
>+int prestera_hw_rxtx_port_init(struct prestera_port *port);
>+
>+#endif /* _PRESTERA_HW_H_ */
>diff --git a/drivers/net/ethernet/marvell/prestera/prestera_main.c b/drivers/net/ethernet/marvell/prestera/prestera_main.c
>new file mode 100644
>index 000000000000..b5241e9b784a
>--- /dev/null
>+++ b/drivers/net/ethernet/marvell/prestera/prestera_main.c
>@@ -0,0 +1,506 @@
>+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
>+/* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */
>+
>+#include <linux/kernel.h>
>+#include <linux/module.h>
>+#include <linux/list.h>
>+#include <linux/netdevice.h>
>+#include <linux/netdev_features.h>
>+#include <linux/etherdevice.h>
>+#include <linux/jiffies.h>
>+#include <linux/of.h>
>+#include <linux/of_net.h>
>+
>+#include "prestera.h"
>+#include "prestera_hw.h"
>+#include "prestera_rxtx.h"
>+
>+#define PRESTERA_MTU_DEFAULT 1536
>+
>+#define PRESTERA_STATS_DELAY_MS	msecs_to_jiffies(1000)
>+
>+static struct workqueue_struct *prestera_wq;
>+
>+struct prestera_port *prestera_port_find_by_hwid(struct prestera_switch *sw,
>+						 u32 dev_id, u32 hw_id)

This is confusing. The called is calling this like:
	port = prestera_port_find_by_hwid(sdma->sw, hw_id, hw_port);

You are mixing hw_id and dev_id.



>+{
>+	struct prestera_port *port;
>+
>+	rcu_read_lock();
>+
>+	list_for_each_entry_rcu(port, &sw->port_list, list) {
>+		if (port->dev_id == dev_id && port->hw_id == hw_id) {

Note this is the fast path. I'm not sure what the values of dev_id or
hw_id are, but didn't you consider having the port pointers in 2 dim
array? Or, if the values are totally arbitrary, at least a hash table
would be nice here.


>+			rcu_read_unlock();
>+			return port;

As Ido already pointed out, this is invalid use of rcu read.
If you really need to do rcu read lock, the caller should hold it while
calling this function and until it finisher work with port struct.


>+		}
>+	}
>+
>+	rcu_read_unlock();
>+
>+	return NULL;
>+}
>+
>+static struct prestera_port *prestera_find_port(struct prestera_switch *sw,
>+						u32 port_id)
>+{
>+	struct prestera_port *port;
>+
>+	rcu_read_lock();
>+
>+	list_for_each_entry_rcu(port, &sw->port_list, list) {
>+		if (port->id == port_id)
>+			break;
>+	}
>+
>+	rcu_read_unlock();
>+
>+	return port;
>+}
>+
>+static int prestera_port_state_set(struct net_device *dev, bool is_up)
>+{
>+	struct prestera_port *port = netdev_priv(dev);
>+	int err;
>+
>+	if (!is_up)
>+		netif_stop_queue(dev);
>+
>+	err = prestera_hw_port_state_set(port, is_up);
>+
>+	if (is_up && !err)
>+		netif_start_queue(dev);
>+
>+	return err;
>+}
>+
>+static int prestera_port_open(struct net_device *dev)
>+{
>+	return prestera_port_state_set(dev, true);
>+}
>+
>+static int prestera_port_close(struct net_device *dev)
>+{
>+	return prestera_port_state_set(dev, false);
>+}
>+
>+static netdev_tx_t prestera_port_xmit(struct sk_buff *skb,
>+				      struct net_device *dev)
>+{
>+	return prestera_rxtx_xmit(netdev_priv(dev), skb);
>+}
>+
>+static int prestera_is_valid_mac_addr(struct prestera_port *port, u8 *addr)
>+{
>+	if (!is_valid_ether_addr(addr))
>+		return -EADDRNOTAVAIL;
>+
>+	if (memcmp(port->sw->base_mac, addr, ETH_ALEN - 1))
>+		return -EINVAL;
>+
>+	return 0;
>+}
>+
>+static int prestera_port_set_mac_address(struct net_device *dev, void *p)
>+{
>+	struct prestera_port *port = netdev_priv(dev);
>+	struct sockaddr *addr = p;
>+	int err;
>+
>+	err = prestera_is_valid_mac_addr(port, addr->sa_data);
>+	if (err)
>+		return err;
>+
>+	err = prestera_hw_port_mac_set(port, addr->sa_data);
>+	if (err)
>+		return err;
>+
>+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
>+	return 0;
>+}
>+
>+static int prestera_port_change_mtu(struct net_device *dev, int mtu)
>+{
>+	struct prestera_port *port = netdev_priv(dev);
>+	int err;
>+
>+	err = prestera_hw_port_mtu_set(port, mtu);
>+	if (err)
>+		return err;
>+
>+	dev->mtu = mtu;
>+	return 0;
>+}
>+
>+static void prestera_port_get_stats64(struct net_device *dev,
>+				      struct rtnl_link_stats64 *stats)
>+{
>+	struct prestera_port *port = netdev_priv(dev);
>+	struct prestera_port_stats *port_stats = &port->cached_hw_stats.stats;
>+
>+	stats->rx_packets = port_stats->broadcast_frames_received +
>+				port_stats->multicast_frames_received +
>+				port_stats->unicast_frames_received;
>+
>+	stats->tx_packets = port_stats->broadcast_frames_sent +
>+				port_stats->multicast_frames_sent +
>+				port_stats->unicast_frames_sent;
>+
>+	stats->rx_bytes = port_stats->good_octets_received;
>+
>+	stats->tx_bytes = port_stats->good_octets_sent;
>+
>+	stats->rx_errors = port_stats->rx_error_frame_received;
>+	stats->tx_errors = port_stats->mac_trans_error;
>+
>+	stats->rx_dropped = port_stats->buffer_overrun;
>+	stats->tx_dropped = 0;
>+
>+	stats->multicast = port_stats->multicast_frames_received;
>+	stats->collisions = port_stats->excessive_collision;
>+
>+	stats->rx_crc_errors = port_stats->bad_crc;
>+}
>+
>+static void prestera_port_get_hw_stats(struct prestera_port *port)
>+{
>+	prestera_hw_port_stats_get(port, &port->cached_hw_stats.stats);
>+}
>+
>+static void prestera_port_stats_update(struct work_struct *work)
>+{
>+	struct prestera_port *port =
>+		container_of(work, struct prestera_port,
>+			     cached_hw_stats.caching_dw.work);
>+
>+	prestera_port_get_hw_stats(port);
>+
>+	queue_delayed_work(prestera_wq, &port->cached_hw_stats.caching_dw,
>+			   PRESTERA_STATS_DELAY_MS);
>+}
>+
>+static const struct net_device_ops netdev_ops = {
>+	.ndo_open = prestera_port_open,
>+	.ndo_stop = prestera_port_close,
>+	.ndo_start_xmit = prestera_port_xmit,
>+	.ndo_change_mtu = prestera_port_change_mtu,
>+	.ndo_get_stats64 = prestera_port_get_stats64,
>+	.ndo_set_mac_address = prestera_port_set_mac_address,
>+};
>+
>+static int prestera_port_autoneg_set(struct prestera_port *port, bool enable,
>+				     u64 link_modes, u8 fec)
>+{
>+	bool refresh = false;
>+	int err = 0;
>+
>+	if (port->caps.type != PRESTERA_PORT_TYPE_TP)
>+		return enable ? -EINVAL : 0;
>+
>+	if (port->adver_link_modes != link_modes || port->adver_fec != fec) {
>+		port->adver_fec = fec ?: BIT(PRESTERA_PORT_FEC_OFF);
>+		port->adver_link_modes = link_modes;
>+		refresh = true;
>+	}
>+
>+	if (port->autoneg == enable && !(port->autoneg && refresh))
>+		return 0;
>+
>+	err = prestera_hw_port_autoneg_set(port, enable, port->adver_link_modes,
>+					   port->adver_fec);
>+	if (err)
>+		return -EINVAL;
>+
>+	port->autoneg = enable;
>+	return 0;
>+}
>+
>+static int prestera_port_create(struct prestera_switch *sw, u32 id)
>+{
>+	struct prestera_port *port;
>+	struct net_device *dev;
>+	int err;
>+
>+	dev = alloc_etherdev(sizeof(*port));
>+	if (!dev)
>+		return -ENOMEM;
>+
>+	port = netdev_priv(dev);
>+
>+	port->dev = dev;
>+	port->id = id;
>+	port->sw = sw;
>+
>+	err = prestera_hw_port_info_get(port, &port->fp_id,
>+					&port->hw_id, &port->dev_id);
>+	if (err) {
>+		dev_err(prestera_dev(sw), "Failed to get port(%u) info\n", id);
>+		goto err_port_init;
>+	}
>+
>+	dev->features |= NETIF_F_NETNS_LOCAL;
>+	dev->netdev_ops = &netdev_ops;
>+
>+	netif_carrier_off(dev);
>+
>+	dev->mtu = min_t(unsigned int, sw->mtu_max, PRESTERA_MTU_DEFAULT);
>+	dev->min_mtu = sw->mtu_min;
>+	dev->max_mtu = sw->mtu_max;
>+
>+	err = prestera_hw_port_mtu_set(port, dev->mtu);
>+	if (err) {
>+		dev_err(prestera_dev(sw), "Failed to set port(%u) mtu(%d)\n",
>+			id, dev->mtu);
>+		goto err_port_init;
>+	}
>+
>+	/* Only 0xFF mac addrs are supported */
>+	if (port->fp_id >= 0xFF)
>+		goto err_port_init;
>+
>+	memcpy(dev->dev_addr, sw->base_mac, dev->addr_len - 1);
>+	dev->dev_addr[dev->addr_len - 1] = (char)port->fp_id;
>+
>+	err = prestera_hw_port_mac_set(port, dev->dev_addr);
>+	if (err) {
>+		dev_err(prestera_dev(sw), "Failed to set port(%u) mac addr\n", id);
>+		goto err_port_init;
>+	}
>+
>+	err = prestera_hw_port_cap_get(port, &port->caps);
>+	if (err) {
>+		dev_err(prestera_dev(sw), "Failed to get port(%u) caps\n", id);
>+		goto err_port_init;
>+	}
>+
>+	port->adver_fec = BIT(PRESTERA_PORT_FEC_OFF);
>+	prestera_port_autoneg_set(port, true, port->caps.supp_link_modes,
>+				  port->caps.supp_fec);
>+
>+	err = prestera_hw_port_state_set(port, false);
>+	if (err) {
>+		dev_err(prestera_dev(sw), "Failed to set port(%u) down\n", id);
>+		goto err_port_init;
>+	}
>+
>+	err = prestera_rxtx_port_init(port);
>+	if (err)
>+		goto err_port_init;
>+
>+	INIT_DELAYED_WORK(&port->cached_hw_stats.caching_dw,
>+			  &prestera_port_stats_update);
>+
>+	list_add_rcu(&port->list, &sw->port_list);

I still am not sure I fully follow. We discussed this before. Can one
of the following cases happen?

1) a packet is RXed while adding ports
2) a packet is RXed while removing ports

If yes, the rcu makes sense here. If no, you are okay with a simple
list.


>+
>+	err = register_netdev(dev);
>+	if (err)
>+		goto err_register_netdev;
>+
>+	return 0;
>+
>+err_register_netdev:
>+	list_del_rcu(&port->list);
>+err_port_init:
>+	free_netdev(dev);
>+	return err;
>+}
>+
>+static void prestera_port_destroy(struct prestera_port *port)
>+{
>+	struct net_device *dev = port->dev;
>+
>+	cancel_delayed_work_sync(&port->cached_hw_stats.caching_dw);
>+	unregister_netdev(dev);
>+
>+	list_del_rcu(&port->list);
>+
>+	free_netdev(dev);
>+}
>+
>+static void prestera_destroy_ports(struct prestera_switch *sw)
>+{
>+	struct prestera_port *port, *tmp;
>+	struct list_head remove_list;
>+
>+	INIT_LIST_HEAD(&remove_list);
>+
>+	list_splice_init(&sw->port_list, &remove_list);

Why do you need a separate remove list? Why don't you iterate sw->port_list
directly?


>+
>+	list_for_each_entry_safe(port, tmp, &remove_list, list)
>+		prestera_port_destroy(port);
>+}
>+

[...]


>+static int prestera_rxtx_process_skb(struct prestera_sdma *sdma,
>+				     struct sk_buff *skb)
>+{
>+	const struct prestera_port *port;
>+	struct prestera_dsa dsa;

What "DSA" stands for? Anything to do with net/dsa/ ?


>+	u32 hw_port, hw_id;
>+	int err;
>+
>+	skb_pull(skb, ETH_HLEN);
>+
>+	/* ethertype field is part of the dsa header */
>+	err = prestera_dsa_parse(&dsa, skb->data - ETH_TLEN);
>+	if (err)
>+		return err;
>+
>+	hw_port = dsa.port_num;
>+	hw_id = dsa.hw_dev_num;
>+
>+	port = prestera_port_find_by_hwid(sdma->sw, hw_id, hw_port);
>+	if (unlikely(!port)) {
>+		pr_warn_ratelimited("prestera: received pkt for non-existent port(%u, %u)\n",

Drop the "prestera: " prefix.


>+				    hw_id, hw_port);
>+		return -EEXIST;
>+	}
>+

[...]

  parent reply	other threads:[~2020-06-03 14:16 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-28 15:12 [net-next 0/6] net: marvell: prestera: Add Switchdev driver for Prestera family ASIC device 98DX326x (AC3x) Vadym Kochan
2020-05-28 15:12 ` [net-next 1/6] net: marvell: prestera: Add driver for Prestera family ASIC devices Vadym Kochan
2020-05-30  0:18   ` David Miller
2020-05-30  0:46     ` Vadym Kochan
2020-05-30  2:20       ` Andrew Lunn
2020-05-30 15:48   ` Ido Schimmel
2020-06-01 10:50     ` Vadym Kochan
2020-06-03  9:23       ` Ido Schimmel
2020-06-20 12:56         ` Vadym Kochan
2020-06-21  8:57           ` Ido Schimmel
2020-06-03 14:16   ` Jiri Pirko [this message]
2020-06-10 13:41     ` Vadym Kochan
2020-06-03 14:29   ` Jiri Pirko
2020-06-03 14:36     ` Jiri Pirko
2020-05-28 15:12 ` [net-next 2/6] net: marvell: prestera: Add PCI interface support Vadym Kochan
2020-06-03  9:59   ` Ido Schimmel
2020-05-28 15:12 ` [net-next 3/6] net: marvell: prestera: Add basic devlink support Vadym Kochan
2020-06-03 10:07   ` Ido Schimmel
2020-06-03 14:36   ` Jiri Pirko
2020-05-28 15:12 ` [net-next 4/6] net: marvell: prestera: Add ethtool interface support Vadym Kochan
2020-05-28 15:12 ` [net-next 5/6] net: marvell: prestera: Add Switchdev driver implementation Vadym Kochan
2020-05-28 15:12 ` [net-next 6/6] dt-bindings: marvell,prestera: Add description for device-tree bindings Vadym Kochan
2020-05-30 14:29 ` [net-next 0/6] net: marvell: prestera: Add Switchdev driver for Prestera family ASIC device 98DX326x (AC3x) Ido Schimmel
2020-05-30 14:52   ` Vadym Kochan
2020-05-30 15:54     ` Ido Schimmel
2020-06-01  6:24       ` Jiri Pirko
2020-06-20 13:25         ` Vadym Kochan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200603141632.GA2274@nanopsycho.orion \
    --to=jiri@resnulli.us \
    --cc=andrew@lunn.ch \
    --cc=andrii.savka@plvision.eu \
    --cc=davem@davemloft.net \
    --cc=idosch@mellanox.com \
    --cc=jiri@mellanox.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mickeyr@marvell.com \
    --cc=netdev@vger.kernel.org \
    --cc=oleksandr.mazur@plvision.eu \
    --cc=serhiy.boiko@plvision.eu \
    --cc=serhiy.pshyk@plvision.eu \
    --cc=taras.chornyi@plvision.eu \
    --cc=vadym.kochan@plvision.eu \
    --cc=volodymyr.mytnyk@plvision.eu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.