Commit 908aef9a authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'net-vertexcom-mse102x-improve-rx-handling'

Stefan Wahren says:

====================
net: vertexcom: mse102x: Improve RX handling

This series is the second part of two series for the Vertexcom driver.
It contains some improvements for the RX handling of the Vertexcom MSE102x.
====================

Link: https://patch.msgid.link/20250509120435.43646-1-wahrenst@gmx.net


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 6bf78849 8ea6e51e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ examples:
            compatible = "vertexcom,mse1021";
            reg = <0>;
            interrupt-parent = <&gpio>;
            interrupts = <23 IRQ_TYPE_EDGE_RISING>;
            interrupts = <23 IRQ_TYPE_LEVEL_HIGH>;
            spi-cpha;
            spi-cpol;
            spi-max-frequency = <7142857>;
+46 −34
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@

#include <linux/if_vlan.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
@@ -16,6 +17,7 @@
#include <linux/cache.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/string_choices.h>

#include <linux/spi/spi.h>
#include <linux/of_net.h>
@@ -45,7 +47,6 @@

struct mse102x_stats {
	u64 xfer_err;
	u64 invalid_cmd;
	u64 invalid_ctr;
	u64 invalid_dft;
	u64 invalid_len;
@@ -56,7 +57,6 @@ struct mse102x_stats {

static const char mse102x_gstrings_stats[][ETH_GSTRING_LEN] = {
	"SPI transfer errors",
	"Invalid command",
	"Invalid CTR",
	"Invalid DFT",
	"Invalid frame length",
@@ -85,6 +85,8 @@ struct mse102x_net_spi {
	struct spi_message	spi_msg;
	struct spi_transfer	spi_xfer;

	bool			valid_cmd_received;

#ifdef CONFIG_DEBUG_FS
	struct dentry		*device_root;
#endif
@@ -108,6 +110,8 @@ static int mse102x_info_show(struct seq_file *s, void *what)
		   (unsigned long)mses->spi_xfer.effective_speed_hz);
	seq_printf(s, "SPI mode                : %x\n",
		   mses->spidev->mode);
	seq_printf(s, "Received valid CMD once : %s\n",
		   str_yes_no(mses->valid_cmd_received));

	return 0;
}
@@ -194,10 +198,10 @@ static int mse102x_rx_cmd_spi(struct mse102x_net *mse, u8 *rxb)
	} else if (*cmd != cpu_to_be16(DET_CMD)) {
		net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n",
				    __func__, *cmd);
		mse->stats.invalid_cmd++;
		ret = -EIO;
	} else {
		memcpy(rxb, trx + 2, 2);
		mses->valid_cmd_received = true;
	}

	return ret;
@@ -306,7 +310,7 @@ static void mse102x_dump_packet(const char *msg, int len, const char *data)
		       data, len, true);
}

static void mse102x_rx_pkt_spi(struct mse102x_net *mse)
static irqreturn_t mse102x_rx_pkt_spi(struct mse102x_net *mse)
{
	struct sk_buff *skb;
	unsigned int rxalign;
@@ -315,19 +319,12 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse)
	__be16 rx = 0;
	u16 cmd_resp;
	u8 *rxpkt;
	int ret;

	mse102x_tx_cmd_spi(mse, CMD_CTR);
	ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx);
	cmd_resp = be16_to_cpu(rx);

	if (ret || ((cmd_resp & CMD_MASK) != CMD_RTS)) {
	if (mse102x_rx_cmd_spi(mse, (u8 *)&rx)) {
		usleep_range(50, 100);

		mse102x_tx_cmd_spi(mse, CMD_CTR);
		ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx);
		if (ret)
			return;
		return IRQ_NONE;
	}

	cmd_resp = be16_to_cpu(rx);
	if ((cmd_resp & CMD_MASK) != CMD_RTS) {
@@ -338,10 +335,6 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse)
		goto drop;
	}

		net_dbg_ratelimited("%s: Unexpected response to first CMD\n",
				    __func__);
	}

	rxlen = cmd_resp & LEN_MASK;
	if (rxlen < ETH_ZLEN || rxlen > VLAN_ETH_FRAME_LEN) {
		net_dbg_ratelimited("%s: Invalid frame length: %d\n", __func__,
@@ -360,7 +353,7 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse)
	rxalign = ALIGN(rxlen + DET_SOF_LEN + DET_DFT_LEN, 4);
	skb = netdev_alloc_skb_ip_align(mse->ndev, rxalign);
	if (!skb)
		return;
		return IRQ_NONE;

	/* 2 bytes Start of frame (before ethernet header)
	 * 2 bytes Data frame tail (after ethernet frame)
@@ -370,7 +363,7 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse)
	if (mse102x_rx_frame_spi(mse, rxpkt, rxlen, drop)) {
		mse->ndev->stats.rx_errors++;
		dev_kfree_skb(skb);
		return;
		return IRQ_HANDLED;
	}

	if (netif_msg_pktdata(mse))
@@ -381,6 +374,8 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse)

	mse->ndev->stats.rx_packets++;
	mse->ndev->stats.rx_bytes += rxlen;

	return IRQ_HANDLED;
}

static int mse102x_tx_pkt_spi(struct mse102x_net *mse, struct sk_buff *txb,
@@ -512,20 +507,36 @@ static irqreturn_t mse102x_irq(int irq, void *_mse)
{
	struct mse102x_net *mse = _mse;
	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
	irqreturn_t ret;

	mutex_lock(&mses->lock);
	mse102x_rx_pkt_spi(mse);
	ret = mse102x_rx_pkt_spi(mse);
	mutex_unlock(&mses->lock);

	return IRQ_HANDLED;
	return ret;
}

static int mse102x_net_open(struct net_device *ndev)
{
	struct irq_data *irq_data = irq_get_irq_data(ndev->irq);
	struct mse102x_net *mse = netdev_priv(ndev);
	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
	int ret;

	if (!irq_data) {
		netdev_err(ndev, "Invalid IRQ: %d\n", ndev->irq);
		return -EINVAL;
	}

	switch (irqd_get_trigger_type(irq_data)) {
	case IRQ_TYPE_LEVEL_HIGH:
	case IRQ_TYPE_LEVEL_LOW:
		break;
	default:
		netdev_warn_once(ndev, "Only IRQ type level recommended, please update your device tree firmware.\n");
		break;
	}

	ret = request_threaded_irq(ndev->irq, NULL, mse102x_irq, IRQF_ONESHOT,
				   ndev->name, mse);
	if (ret < 0) {
@@ -543,6 +554,7 @@ static int mse102x_net_open(struct net_device *ndev)
	 * So poll for possible packet(s) to re-arm the interrupt.
	 */
	mutex_lock(&mses->lock);
	if (mse102x_rx_pkt_spi(mse) == IRQ_NONE)
		mse102x_rx_pkt_spi(mse);
	mutex_unlock(&mses->lock);