linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
@ 2023-09-08 14:29 Parthiban Veerasooran
  2023-09-08 14:29 ` [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface Parthiban Veerasooran
                   ` (7 more replies)
  0 siblings, 8 replies; 85+ messages in thread
From: Parthiban Veerasooran @ 2023-09-08 14:29 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	andrew
  Cc: netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	Parthiban Veerasooran

This patch series contain the below updates,
- Adds support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface in the
  net/ethernet/oa_tc6.c.
- Adds driver support for Microchip LAN8650/1 Rev.B0 10BASE-T1S MACPHY
  Ethernet driver in the net/ethernet/microchip/lan865x.c.

Parthiban Veerasooran (6):
  net: ethernet: implement OPEN Alliance control transaction interface
  net: ethernet: add mac-phy interrupt support with reset complete
    handling
  net: ethernet: implement OA TC6 configuration function
  net: ethernet: implement data transaction interface
  microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  microchip: lan865x: add device-tree support for Microchip's LAN865X
    MACPHY

 .../bindings/net/microchip,lan865x.yaml       |  54 ++
 Documentation/networking/oa-tc6-framework.rst | 231 +++++
 MAINTAINERS                                   |  15 +
 drivers/net/ethernet/microchip/Kconfig        |  10 +
 drivers/net/ethernet/microchip/Makefile       |   3 +
 drivers/net/ethernet/microchip/lan865x.c      | 589 +++++++++++++
 drivers/net/ethernet/oa_tc6.c                 | 807 ++++++++++++++++++
 include/linux/oa_tc6.h                        | 130 +++
 8 files changed, 1839 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/microchip,lan865x.yaml
 create mode 100644 Documentation/networking/oa-tc6-framework.rst
 create mode 100644 drivers/net/ethernet/microchip/lan865x.c
 create mode 100644 drivers/net/ethernet/oa_tc6.c
 create mode 100644 include/linux/oa_tc6.h

-- 
2.34.1


^ permalink raw reply	[flat|nested] 85+ messages in thread

* [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-08 14:29 [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface Parthiban Veerasooran
@ 2023-09-08 14:29 ` Parthiban Veerasooran
  2023-09-09 13:33   ` Andrew Lunn
                     ` (3 more replies)
  2023-09-08 14:29 ` [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling Parthiban Veerasooran
                   ` (6 subsequent siblings)
  7 siblings, 4 replies; 85+ messages in thread
From: Parthiban Veerasooran @ 2023-09-08 14:29 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	andrew
  Cc: netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	Parthiban Veerasooran

Implement register read/write interface according to the control
communication specified in the OPEN Alliance 10BASE-T1x MACPHY Serial
Interface document. Control transactions consist of one or more control
commands. Control commands are used by the SPI host to read and write
registers within the MAC-PHY. Each control commands are composed of a
32-bit control command header followed by register data.

Control write commands can write either a single register or multiple
consecutive registers. When multiple consecutive registers are written,
the address is automatically post-incremented by the MAC-PHY. The write
command and data is also echoed from the MAC-PHY back to the SPI host to
enable the SPI host to identify which register write failed in the case
of any bus errors.

Control read commands can read either a single register or multiple
consecutive registers. When multiple consecutive registers are read, the
address is automatically post-incremented by the MAC-PHY.

The register data being read or written can be protected against simple
bit errors. When enabled by setting the Protection Enable (PROTE) bit in
the CONFIG0 register, protection is accomplished by duplication of each
32-bit word containing register data with its ones’ complement. Errors
are detected at the receiver by performing a simple exclusive-OR (XOR) of
each received 32-bit word containing register data with its received
complement and detecting if there are any zeros in the result.

Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
 Documentation/networking/oa-tc6-framework.rst | 231 ++++++++++++++++++
 MAINTAINERS                                   |   8 +
 drivers/net/ethernet/oa_tc6.c                 | 222 +++++++++++++++++
 include/linux/oa_tc6.h                        |  31 +++
 4 files changed, 492 insertions(+)
 create mode 100644 Documentation/networking/oa-tc6-framework.rst
 create mode 100644 drivers/net/ethernet/oa_tc6.c
 create mode 100644 include/linux/oa_tc6.h

diff --git a/Documentation/networking/oa-tc6-framework.rst b/Documentation/networking/oa-tc6-framework.rst
new file mode 100644
index 000000000000..5a8af2398f3c
--- /dev/null
+++ b/Documentation/networking/oa-tc6-framework.rst
@@ -0,0 +1,231 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+=========================================================================
+OPEN Alliance 10BASE-T1x MAC-PHY Serial Interface (TC6) Framework Support
+=========================================================================
+
+:Copyright: |copy| 2023 MICROCHIP
+
+Introduction
+------------
+
+The IEEE 802.3cg project defines two 10 Mbit/s PHYs operating over a
+single pair of conductors. The 10BASE-T1L (Clause 146) is a long reach
+PHY supporting full duplex point-to-point operation over 1 km of single
+balanced pair of conductors. The 10BASE-T1S (Clause 147) is a short reach
+PHY supporting full / half duplex point-to-point operation over 15 m of
+single balanced pair of conductors, or half duplex multidrop bus
+operation over 25 m of single balanced pair of conductors.
+
+Furthermore, the IEEE 802.3cg project defines the new Physical Layer
+Collision Avoidance (PLCA) Reconciliation Sublayer (Clause 148) meant to
+provide improved determinism to the CSMA/CD media access method. PLCA
+works in conjunction with the 10BASE-T1S PHY operating in multidrop mode.
+
+The aforementioned PHYs are intended to cover the low-speed / low-cost
+applications in industrial and automotive environment. The large number
+of pins (16) required by the MII interface, which is specified by the
+IEEE 802.3 in Clause 22, is one of the major cost factors that need to be
+addressed to fulfil this objective.
+
+The MAC-PHY solution integrates an IEEE Clause 4 MAC and a 10BASE-T1x PHY
+exposing a low pin count Serial Peripheral Interface (SPI) to the host
+microcontroller. This also enables the addition of Ethernet functionality
+to existing low-end microcontrollers which do not integrate a MAC
+controller.
+
+Overview
+--------
+
+The MAC-PHY is specified to carry both data (Ethernet frames) and control
+(register access) transactions over a single full-duplex serial
+peripheral interface.
+
+Protocol Overview
+-----------------
+
+Two types of transactions are defined in the protocol: data transactions
+for Ethernet frame transfers and control transactions for register
+read/write transfers. A chunk is the basic element of data transactions
+and is composed of 4 bytes of overhead plus the configured payload size
+for each chunk. Ethernet frames are transferred over one or more data
+chunks. Control transactions consist of one or more register read/write
+control commands.
+
+SPI transactions are initiated by the SPI host with the assertion of CSn
+low to the MAC-PHY and ends with the deassertion of CSn high. In between
+each SPI transaction, the SPI host may need time for additional
+processing and to setup the next SPI data or control transaction.
+
+SPI data transactions consist of an equal number of transmit (TX) and
+receive (RX) chunks. Chunks in both transmit and receive directions may
+or may not contain valid frame data independent from each other, allowing
+for the simultaneous transmission and reception of different length
+frames.
+
+Each transmit data chunk begins with a 32-bit data header followed by a
+data chunk payload on MOSI. The data header indicates whether transmit
+frame data is present and provides the information to determine which
+bytes of the payload contain valid frame data.
+
+In parallel, receive data chunks are received on MISO. Each receive data
+chunk consists of a data chunk payload ending with a 32-bit data footer.
+The data footer indicates if there is receive frame data present within
+the payload or not and provides the information to determine which bytes
+of the payload contain valid frame data.
+
+Reference
+---------
+
+10BASE-T1x MAC-PHY Serial Interface Specification,
+
+Link: https://www.opensig.org/about/specifications/
+
+Hardware Architecture
+---------------------
+
+.. code-block:: none
+                    +-------------------------------------+
+                    |                MAC-PHY              |
+  +----------+      | +-----------+  +-------+  +-------+ |
+  | SPI Host |<---->| | SPI Slave |  |  MAC  |  |  PHY  | |
+  +----------+      | +-----------+  +-------+  +-------+ |
+                    +-------------------------------------+
+
+Software Architecture
+---------------------
+
+.. code-block:: none
+
+  +----------------------------------------------------------+
+  |                 Networking Subsystem                     |
+  +----------------------------------------------------------+
+             |                               |
+             |                               |
+  +----------------------+     +-----------------------------+
+  |     MAC Driver       |<--->| OPEN Alliance TC6 Framework |
+  +----------------------+     +-----------------------------+
+             |                               |
+             |                               |
+  +----------------------+     +-----------------------------+
+  |      PHYLIB          |     |       SPI Subsystem         |
+  +----------------------+     +-----------------------------+
+                                             |
+                                             |
+  +----------------------------------------------------------+
+  |                10BASE-T1x MAC-PHY Device                 |
+  +----------------------------------------------------------+
+
+Implementation
+--------------
+
+MAC Driver
+~~~~~~~~~~
+- Initializes and configures the OA TC6 framework for the MAC-PHY.
+
+- Initializes PHYLIB interface.
+
+- Registers and configures the network device.
+
+- Sends the tx ethernet frame from n/w subsystem to OA TC6 framework.
+
+OPEN Alliance TC6 Framework
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+- Registers macphy interrupt which is used to indicate receive data
+  available, any communication errors and tx credit count availability in
+  case it was 0 already.
+
+- Prepares SPI chunks from the tx ethernet frame enqueued by the MAC
+  driver and sends to MAC-PHY.
+
+- Receives SPI chunks from MAC-PHY and prepares ethernet frame and sends
+  to n/w subsystem.
+
+- Prepares and performs control read/write commands.
+
+Data Transaction
+~~~~~~~~~~~~~~~~
+
+Tx ethernet frame from the n/w layer is divided into multiple chunks in
+the oa_tc6_prepare_tx_chunks() function. Each tx chunk will have 4 bytes
+header and 64/32 bytes chunk payload.
+
+.. code-block:: none
+
+  +---------------------------------------------------+
+  |                     Tx Chunk                      |
+  | +---------------------------+  +----------------+ |   MOSI
+  | | 64/32 bytes chunk payload |  | 4 bytes header | |------------>
+  | +---------------------------+  +----------------+ |
+  +---------------------------------------------------+
+
+The number of buffers available in the MAC-PHY to store the incoming tx
+chunk payloads is represented as tx credit count (txc). This txc can be
+read either from the Buffer Status Register or footer (Refer below in the
+rx case for the footer info) received from the MAC-PHY. The number of txc
+is needed to transport the ethernet frame is calculated from the size of
+the ethernet frame. The header in the each chunk is updated with the
+chunk payload details like data not control, data valid, start valid,
+start word offset, end byte offset, end valid and parity bit.
+
+Once the tx chunks are ready, oa_tc6_handler() task is triggered to
+perform SPI transfer. This task checks for the txc availability in the
+MAC-PHY and sends the number of chunks equal to the txc. If there is no
+txc is available then the task waits for the interrupt to indicate the
+txc availability. If the available txc is less than the needed txc then
+the SPI transfer is performed for the available txc and the rx chunks
+footer is processed for the txc availability again. For every SPI
+transfer the received rx chunks will be processed for the rx ethernet
+frame (if any), txc and rca.
+
+Rx ethernet frame from the MAC-PHY is framed from the rx chunks received
+from the MAC-PHY and will be transferred to the n/w layer. Each rx chunk
+will have 64/32 bytes chunk payload and 4 bytes footer.
+
+.. code-block:: none
+
+  +---------------------------------------------------+
+  |                     Rx Chunk                      |
+  | +----------------+  +---------------------------+ |   MISO
+  | | 4 bytes footer |  | 64/32 bytes chunk payload | |------------>
+  | +----------------+  +---------------------------+ |
+  +---------------------------------------------------+
+
+In case of interrupt, the oa_tc6_handler() task performs an empty chunk
+SPI transfer to get the reason for the interrupt in the received chunk
+footer. The reason can be receive chunk available (rca) or extended block
+status (exst) or txc availability. Based on this the corresponding
+operation is performed. If it is for rca then the SPI transfer is
+performed with the empty chunks equal to the rca to get the rx chunks.
+Rx ethernet frame is framed from the rx chunks received and transferred
+to n/w layer. If it is for exst then the STATUS0 register will be read
+for the error detail.
+
+In the beginning the interrupt occurs for indicating the reset complete
+from the MAC-PHY and is ready for the configuration. oa_tc6_handler() task
+handles this interrupt to get and clear the reset complete status.
+
+Control Transaction
+~~~~~~~~~~~~~~~~~~~
+
+Control transactions are performed to read/write the registers in the
+MAC-PHY. Each control command headers are 4 bytes length with the
+necessary details to read/write the registers.
+
+In case of a register write command, the write command header has the
+information like data not control, write not read, address increment
+disable, memory map selector, address, length and parity followed by the
+data to be written. If the protected mode is enabled in the CONFIG0
+register then each data to be written will be sent first followed by its
+ones' complement value to ensure the error free transfer. For every write
+command, both the write command header and the data will be echoed back in
+the rx path to confirm the error free transaction.
+
+In case of a register read command, the read command is preferred with the
+above mentioned details and the echoed rx data will be processed for the
+register data. In case of protected mode enabled the echoed rx data
+contains the ones' complemented data also for verifying the data error.
+
+oa_tc6_perform_ctrl() function prepares control commands based on the
+read/write request, performs SPI transfer, checks for the error and
+returns read register data in case of control read command.
diff --git a/MAINTAINERS b/MAINTAINERS
index 9cc15c50c2c6..c54454c7e7a1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15835,6 +15835,14 @@ L:	linux-rdma@vger.kernel.org
 S:	Supported
 F:	drivers/infiniband/ulp/opa_vnic
 
+OPEN ALLIANCE 10BASE-T1S MACPHY SERIAL INTERFACE FRAMEWORK
+M:	Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	Documentation/networking/oa-tc6-framework.rst
+F:	drivers/include/linux/oa_tc6.h
+F:	drivers/net/ethernet/oa_tc6.c
+
 OPEN FIRMWARE AND FLATTENED DEVICE TREE
 M:	Rob Herring <robh+dt@kernel.org>
 M:	Frank Rowand <frowand.list@gmail.com>
diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
new file mode 100644
index 000000000000..613cf034430a
--- /dev/null
+++ b/drivers/net/ethernet/oa_tc6.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OPEN Alliance 10BASE‑T1x MAC‑PHY Serial Interface framework
+ *
+ * Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/oa_tc6.h>
+
+static int oa_tc6_spi_transfer(struct spi_device *spi, u8 *ptx, u8 *prx,
+			       u16 len)
+{
+	struct spi_transfer xfer = {
+		.tx_buf = ptx,
+		.rx_buf = prx,
+		.len = len,
+	};
+	struct spi_message msg;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+
+	return spi_sync(spi, &msg);
+}
+
+static bool oa_tc6_get_parity(u32 p)
+{
+	bool parity = true;
+
+	/* This function returns an odd parity bit */
+	while (p) {
+		parity = !parity;
+		p = p & (p - 1);
+	}
+	return parity;
+}
+
+static void oa_tc6_prepare_ctrl_buf(struct oa_tc6 *tc6, u32 addr, u32 val[],
+				    u8 len, bool wnr, u8 *buf, bool ctrl_prot)
+{
+	u32 hdr;
+
+	/* Prepare the control header with the required details */
+	hdr = FIELD_PREP(CTRL_HDR_DNC, 0) |
+	      FIELD_PREP(CTRL_HDR_WNR, wnr) |
+	      FIELD_PREP(CTRL_HDR_AID, 0) |
+	      FIELD_PREP(CTRL_HDR_MMS, addr >> 16) |
+	      FIELD_PREP(CTRL_HDR_ADDR, addr) |
+	      FIELD_PREP(CTRL_HDR_LEN, len - 1);
+	hdr |= FIELD_PREP(CTRL_HDR_P, oa_tc6_get_parity(hdr));
+	*(u32 *)buf = cpu_to_be32(hdr);
+
+	if (wnr) {
+		for (u8 i = 0; i < len; i++) {
+			u16 pos;
+
+			if (!ctrl_prot) {
+				/* Send the value to be written followed by the
+				 * header.
+				 */
+				pos = (i + 1) * TC6_HDR_SIZE;
+				*(u32 *)&buf[pos] = cpu_to_be32(val[i]);
+			} else {
+				/* If protected then send complemented value
+				 * also followed by actual value.
+				 */
+				pos = TC6_HDR_SIZE + (i * (TC6_HDR_SIZE * 2));
+				*(u32 *)&buf[pos] = cpu_to_be32(val[i]);
+				pos = (i + 1) * (TC6_HDR_SIZE * 2);
+				*(u32 *)&buf[pos] = cpu_to_be32(~val[i]);
+			}
+		}
+	}
+}
+
+static int oa_tc6_check_control(struct oa_tc6 *tc6, u8 *ptx, u8 *prx, u8 len,
+				bool wnr, bool ctrl_prot)
+{
+	/* 1st 4 bytes of rx chunk data can be discarded */
+	u32 rx_hdr = *(u32 *)&prx[TC6_HDR_SIZE];
+	u32 tx_hdr = *(u32 *)ptx;
+	u32 rx_data_complement;
+	u32 tx_data;
+	u32 rx_data;
+	u16 pos1;
+	u16 pos2;
+
+	/* If tx hdr and echoed hdr are not equal then there might be an issue
+	 * with the connection between SPI host and MAC-PHY. Here this case is
+	 * considered as MAC-PHY is not connected.
+	 */
+	if (tx_hdr != rx_hdr)
+		return -ENODEV;
+
+	if (wnr) {
+		if (!ctrl_prot) {
+			/* In case of ctrl write, both tx data & echoed
+			 * data are compared for the error.
+			 */
+			pos1 = TC6_HDR_SIZE;
+			pos2 = TC6_HDR_SIZE * 2;
+			for (u8 i = 0; i < len; i++) {
+				tx_data = *(u32 *)&ptx[pos1 + (i * TC6_HDR_SIZE)];
+				rx_data = *(u32 *)&prx[pos2 + (i * TC6_HDR_SIZE)];
+				if (tx_data != rx_data)
+					return -ENODEV;
+			}
+			return 0;
+		}
+	} else {
+		if (!ctrl_prot)
+			return 0;
+	}
+
+	/* In case of ctrl read or ctrl write in protected mode, the rx data and
+	 * the complement of rx data are compared for the error.
+	 */
+	pos1 = TC6_HDR_SIZE * 2;
+	pos2 = TC6_HDR_SIZE * 3;
+	for (u8 i = 0; i < len; i++) {
+		rx_data = *(u32 *)&prx[pos1 + (i * TC6_HDR_SIZE * 2)];
+		rx_data_complement = *(u32 *)&prx[pos2 + (i * TC6_HDR_SIZE * 2)];
+		if (rx_data != ~rx_data_complement)
+			return -ENODEV;
+	}
+
+	return 0;
+}
+
+int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
+			bool wnr, bool ctrl_prot)
+{
+	u8 *tx_buf;
+	u8 *rx_buf;
+	u16 size;
+	u16 pos;
+	int ret;
+
+	if (ctrl_prot)
+		size = (TC6_HDR_SIZE * 2) + (len * (TC6_HDR_SIZE * 2));
+	else
+		size = (TC6_HDR_SIZE * 2) + (len * TC6_HDR_SIZE);
+
+	tx_buf = kzalloc(size, GFP_KERNEL);
+	if (!tx_buf)
+		return -ENOMEM;
+
+	rx_buf = kzalloc(size, GFP_KERNEL);
+	if (!rx_buf) {
+		ret = -ENOMEM;
+		goto err_rx_buf_kzalloc;
+	}
+
+	/* Prepare control command */
+	oa_tc6_prepare_ctrl_buf(tc6, addr, val, len, wnr, tx_buf, ctrl_prot);
+
+	/* Perform SPI transfer */
+	ret = oa_tc6_spi_transfer(tc6->spi, tx_buf, rx_buf, size);
+	if (ret)
+		goto err_ctrl;
+
+	/* Check echoed/received control reply */
+	ret = oa_tc6_check_control(tc6, tx_buf, rx_buf, len, wnr, ctrl_prot);
+	if (ret)
+		goto err_ctrl;
+
+	if (!wnr) {
+		/* Copy read data from the rx data in case of ctrl read */
+		for (u8 i = 0; i < len; i++) {
+			if (!ctrl_prot) {
+				pos = (TC6_HDR_SIZE * 2) + (i * TC6_HDR_SIZE);
+				val[i] = be32_to_cpu(*(u32 *)&rx_buf[pos]);
+			} else {
+				pos = (TC6_HDR_SIZE * 2) +
+				       (i * (TC6_HDR_SIZE * 2));
+				val[i] = be32_to_cpu(*(u32 *)&rx_buf[pos]);
+			}
+		}
+	}
+
+err_ctrl:
+	kfree(rx_buf);
+err_rx_buf_kzalloc:
+	kfree(tx_buf);
+	return ret;
+}
+
+int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len)
+{
+	return oa_tc6_perform_ctrl(tc6, addr, val, len, true, tc6->ctrl_prot);
+}
+EXPORT_SYMBOL_GPL(oa_tc6_write_register);
+
+int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len)
+{
+	return oa_tc6_perform_ctrl(tc6, addr, val, len, false, tc6->ctrl_prot);
+}
+EXPORT_SYMBOL_GPL(oa_tc6_read_register);
+
+struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
+{
+	struct oa_tc6 *tc6;
+
+	if (!spi)
+		return NULL;
+
+	tc6 = kzalloc(sizeof(*tc6), GFP_KERNEL);
+	if (!tc6)
+		return NULL;
+
+	tc6->spi = spi;
+
+	return tc6;
+}
+EXPORT_SYMBOL_GPL(oa_tc6_init);
+
+void oa_tc6_deinit(struct oa_tc6 *tc6)
+{
+	kfree(tc6);
+}
+EXPORT_SYMBOL_GPL(oa_tc6_deinit);
diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
new file mode 100644
index 000000000000..5e0a58ab1dcd
--- /dev/null
+++ b/include/linux/oa_tc6.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * OPEN Alliance 10BASE‑T1x MAC‑PHY Serial Interface framework
+ *
+ * Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
+ */
+
+#include <linux/spi/spi.h>
+
+/* Control header */
+#define CTRL_HDR_DNC	BIT(31)		/* Data-Not-Control */
+#define CTRL_HDR_HDRB	BIT(30)		/* Received Header Bad */
+#define CTRL_HDR_WNR	BIT(29)		/* Write-Not-Read */
+#define CTRL_HDR_AID	BIT(28)		/* Address Increment Disable */
+#define CTRL_HDR_MMS	GENMASK(27, 24)	/* Memory Map Selector */
+#define CTRL_HDR_ADDR	GENMASK(23, 8)	/* Address */
+#define CTRL_HDR_LEN	GENMASK(7, 1)	/* Length */
+#define CTRL_HDR_P	BIT(0)		/* Parity Bit */
+
+#define TC6_HDR_SIZE	4		/* Ctrl command header size as per OA */
+#define TC6_FTR_SIZE	4		/* Ctrl command footer size ss per OA */
+
+struct oa_tc6 {
+	struct spi_device *spi;
+	bool ctrl_prot;
+};
+
+struct oa_tc6 *oa_tc6_init(struct spi_device *spi);
+void oa_tc6_deinit(struct oa_tc6 *tc6);
+int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
+int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-08 14:29 [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface Parthiban Veerasooran
  2023-09-08 14:29 ` [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface Parthiban Veerasooran
@ 2023-09-08 14:29 ` Parthiban Veerasooran
  2023-09-09 13:39   ` Andrew Lunn
                     ` (3 more replies)
  2023-09-08 14:29 ` [RFC PATCH net-next 3/6] net: ethernet: implement OA TC6 configuration function Parthiban Veerasooran
                   ` (5 subsequent siblings)
  7 siblings, 4 replies; 85+ messages in thread
From: Parthiban Veerasooran @ 2023-09-08 14:29 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	andrew
  Cc: netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	Parthiban Veerasooran

Register MAC-PHY interrupt and handle reset complete interrupt. Reset
complete bit is set when the MAC-PHY reset complete and ready for
configuration. When it is set, it will generate a non-maskable interrupt
to alert the SPI host. Additionally reset complete bit in the STS0
register has to be written by one upon reset complete to clear the
interrupt.

Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
 drivers/net/ethernet/oa_tc6.c | 141 ++++++++++++++++++++++++++++++++--
 include/linux/oa_tc6.h        |  16 +++-
 2 files changed, 150 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
index 613cf034430a..0019f70345b6 100644
--- a/drivers/net/ethernet/oa_tc6.c
+++ b/drivers/net/ethernet/oa_tc6.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/bitfield.h>
+#include <linux/interrupt.h>
 #include <linux/oa_tc6.h>
 
 static int oa_tc6_spi_transfer(struct spi_device *spi, u8 *ptx, u8 *prx,
@@ -160,10 +161,16 @@ int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
 	if (ret)
 		goto err_ctrl;
 
-	/* Check echoed/received control reply */
-	ret = oa_tc6_check_control(tc6, tx_buf, rx_buf, len, wnr, ctrl_prot);
-	if (ret)
-		goto err_ctrl;
+	/* In case of reset write, the echoed control command doesn't have any
+	 * valid data. So no need to check for error.
+	 */
+	if (addr != OA_TC6_RESET) {
+		/* Check echoed/received control reply */
+		ret = oa_tc6_check_control(tc6, tx_buf, rx_buf, len, wnr,
+					   ctrl_prot);
+		if (ret)
+			goto err_ctrl;
+	}
 
 	if (!wnr) {
 		/* Copy read data from the rx data in case of ctrl read */
@@ -186,6 +193,88 @@ int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
 	return ret;
 }
 
+static int oa_tc6_handler(void *data)
+{
+	struct oa_tc6 *tc6 = data;
+	u32 regval;
+	int ret;
+
+	while (likely(!kthread_should_stop())) {
+		wait_event_interruptible(tc6->tc6_wq, tc6->int_flag ||
+					 kthread_should_stop());
+		if (tc6->int_flag) {
+			tc6->int_flag = false;
+			ret = oa_tc6_perform_ctrl(tc6, OA_TC6_STS0, &regval, 1,
+						  false, false);
+			if (ret) {
+				dev_err(&tc6->spi->dev, "Failed to read STS0\n");
+				continue;
+			}
+			/* Check for reset complete interrupt status */
+			if (regval & RESETC) {
+				regval = RESETC;
+				/* SPI host should write RESETC bit with one to
+				 * clear the reset interrupt status.
+				 */
+				ret = oa_tc6_perform_ctrl(tc6, OA_TC6_STS0,
+							  &regval, 1, true,
+							  false);
+				if (ret) {
+					dev_err(&tc6->spi->dev,
+						"Failed to write STS0\n");
+					continue;
+				}
+				complete(&tc6->rst_complete);
+			}
+		}
+	}
+	return 0;
+}
+
+static irqreturn_t macphy_irq(int irq, void *dev_id)
+{
+	struct oa_tc6 *tc6 = dev_id;
+
+	/* Wake tc6 task to perform interrupt action */
+	tc6->int_flag = true;
+	wake_up_interruptible(&tc6->tc6_wq);
+
+	return IRQ_HANDLED;
+}
+
+static int oa_tc6_sw_reset(struct oa_tc6 *tc6)
+{
+	long timeleft;
+	u32 regval;
+	int ret;
+
+	/* Perform software reset with both protected and unprotected control
+	 * commands because the driver doesn't know the current status of the
+	 * MAC-PHY.
+	 */
+	regval = SW_RESET;
+	reinit_completion(&tc6->rst_complete);
+	ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1, true, false);
+	if (ret) {
+		dev_err(&tc6->spi->dev, "RESET register write failed\n");
+		return ret;
+	}
+
+	ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1, true, true);
+	if (ret) {
+		dev_err(&tc6->spi->dev, "RESET register write failed\n");
+		return ret;
+	}
+	timeleft = wait_for_completion_interruptible_timeout(&tc6->rst_complete,
+							     msecs_to_jiffies(1));
+	if (timeleft <= 0) {
+		dev_err(&tc6->spi->dev, "MAC-PHY reset failed\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len)
 {
 	return oa_tc6_perform_ctrl(tc6, addr, val, len, true, tc6->ctrl_prot);
@@ -201,6 +290,7 @@ EXPORT_SYMBOL_GPL(oa_tc6_read_register);
 struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
 {
 	struct oa_tc6 *tc6;
+	int ret;
 
 	if (!spi)
 		return NULL;
@@ -211,12 +301,51 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
 
 	tc6->spi = spi;
 
+	/* Used for triggering the OA TC6 task */
+	init_waitqueue_head(&tc6->tc6_wq);
+
+	init_completion(&tc6->rst_complete);
+
+	/* This task performs the SPI transfer */
+	tc6->tc6_task = kthread_run(oa_tc6_handler, tc6, "OA TC6 Task");
+	if (IS_ERR(tc6->tc6_task))
+		goto err_tc6_task;
+
+	/* Set the highest priority to the tc6 task as it is time critical */
+	sched_set_fifo(tc6->tc6_task);
+
+	/* Register MAC-PHY interrupt service routine */
+	ret = devm_request_irq(&spi->dev, spi->irq, macphy_irq, 0, "macphy int",
+			       tc6);
+	if ((ret != -ENOTCONN) && ret < 0) {
+		dev_err(&spi->dev, "Error attaching macphy irq %d\n", ret);
+		goto err_macphy_irq;
+	}
+
+	/* Perform MAC-PHY software reset */
+	if (oa_tc6_sw_reset(tc6))
+		goto err_macphy_reset;
+
 	return tc6;
+
+err_macphy_reset:
+	devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
+err_macphy_irq:
+	kthread_stop(tc6->tc6_task);
+err_tc6_task:
+	kfree(tc6);
+	return NULL;
 }
 EXPORT_SYMBOL_GPL(oa_tc6_init);
 
-void oa_tc6_deinit(struct oa_tc6 *tc6)
+int oa_tc6_deinit(struct oa_tc6 *tc6)
 {
-	kfree(tc6);
+	int ret;
+
+	devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
+	ret = kthread_stop(tc6->tc6_task);
+	if (!ret)
+		kfree(tc6);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(oa_tc6_deinit);
diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
index 5e0a58ab1dcd..315f061c2dfe 100644
--- a/include/linux/oa_tc6.h
+++ b/include/linux/oa_tc6.h
@@ -17,15 +17,29 @@
 #define CTRL_HDR_LEN	GENMASK(7, 1)	/* Length */
 #define CTRL_HDR_P	BIT(0)		/* Parity Bit */
 
+/* Open Alliance TC6 Standard Control and Status Registers */
+#define OA_TC6_RESET	0x0003		/* Reset Control and Status Register */
+#define OA_TC6_STS0	0x0008		/* Status Register #0 */
+
+/* RESET register field */
+#define SW_RESET	BIT(0)		/* Software Reset */
+
+/* STATUS0 register field */
+#define RESETC		BIT(6)		/* Reset Complete */
+
 #define TC6_HDR_SIZE	4		/* Ctrl command header size as per OA */
 #define TC6_FTR_SIZE	4		/* Ctrl command footer size ss per OA */
 
 struct oa_tc6 {
 	struct spi_device *spi;
 	bool ctrl_prot;
+	struct task_struct *tc6_task;
+	wait_queue_head_t tc6_wq;
+	bool int_flag;
+	struct completion rst_complete;
 };
 
 struct oa_tc6 *oa_tc6_init(struct spi_device *spi);
-void oa_tc6_deinit(struct oa_tc6 *tc6);
+int oa_tc6_deinit(struct oa_tc6 *tc6);
 int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
 int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [RFC PATCH net-next 3/6] net: ethernet: implement OA TC6 configuration function
  2023-09-08 14:29 [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface Parthiban Veerasooran
  2023-09-08 14:29 ` [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface Parthiban Veerasooran
  2023-09-08 14:29 ` [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling Parthiban Veerasooran
@ 2023-09-08 14:29 ` Parthiban Veerasooran
  2023-09-14  0:46   ` Andrew Lunn
  2023-09-08 14:29 ` [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface Parthiban Veerasooran
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 85+ messages in thread
From: Parthiban Veerasooran @ 2023-09-08 14:29 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	andrew
  Cc: netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	Parthiban Veerasooran

Read STDCAP register for the MAC-PHY capability and check against the
configuration parameters such as chunk payload, tx cut through and rx cut
through to configure the MAC-PHY. It also configures the control command
protected/unprotected mode.

In cut through mode configuration the MAC-PHY doesn't buffer the incoming
data. In tx case, it passes the data to the network if the configured cps
of data available. In rx case, it passes the data to the SPI host if the
configured cps of data available from the network. Also disables all the
errors mask in the IMASK0 register to check for the errors.

Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
 drivers/net/ethernet/oa_tc6.c | 39 +++++++++++++++++++++++++++++++++++
 include/linux/oa_tc6.h        | 28 ++++++++++++++++++++++---
 2 files changed, 64 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
index 0019f70345b6..65a7317f768d 100644
--- a/drivers/net/ethernet/oa_tc6.c
+++ b/drivers/net/ethernet/oa_tc6.c
@@ -287,6 +287,45 @@ int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len)
 }
 EXPORT_SYMBOL_GPL(oa_tc6_read_register);
 
+int oa_tc6_configure(struct oa_tc6 *tc6, u8 cps, bool ctrl_prot, bool tx_cut_thr,
+		     bool rx_cut_thr)
+{
+	u32 regval;
+	int ret;
+
+	/* Read and configure the IMASK0 register for unmasking the interrupts */
+	ret = oa_tc6_read_register(tc6, OA_TC6_IMASK0, &regval, 1);
+	if (ret)
+		return ret;
+
+	regval &= TXPEM & TXBOEM & TXBUEM & RXBOEM & LOFEM & HDREM;
+	ret = oa_tc6_write_register(tc6, OA_TC6_IMASK0, &regval, 1);
+	if (ret)
+		return ret;
+
+	/* Configure the CONFIG0 register with the required configurations */
+	regval = SYNC;
+	if (ctrl_prot)
+		regval |= PROTE;
+	if (tx_cut_thr)
+		regval |= TXCTE;
+	if (rx_cut_thr)
+		regval |= RXCTE;
+	regval |= FIELD_PREP(CPS, ilog2(cps) / ilog2(2));
+
+	ret = oa_tc6_write_register(tc6, OA_TC6_CONFIG0, &regval, 1);
+	if (ret)
+		return ret;
+
+	tc6->cps = cps;
+	tc6->ctrl_prot = ctrl_prot;
+	tc6->tx_cut_thr = tx_cut_thr;
+	tc6->rx_cut_thr = rx_cut_thr;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(oa_tc6_configure);
+
 struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
 {
 	struct oa_tc6 *tc6;
diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
index 315f061c2dfe..fa29c4e09720 100644
--- a/include/linux/oa_tc6.h
+++ b/include/linux/oa_tc6.h
@@ -19,11 +19,28 @@
 
 /* Open Alliance TC6 Standard Control and Status Registers */
 #define OA_TC6_RESET	0x0003		/* Reset Control and Status Register */
+#define OA_TC6_CONFIG0	0x0004		/* Configuration Register #0 */
 #define OA_TC6_STS0	0x0008		/* Status Register #0 */
+#define OA_TC6_IMASK0	0x000C		/* Interrupt Mask Register #0 */
 
 /* RESET register field */
 #define SW_RESET	BIT(0)		/* Software Reset */
 
+/* CONFIG0 register fields */
+#define SYNC		BIT(15)		/* Configuration Synchronization */
+#define TXCTE		BIT(9)		/* Tx cut-through enable */
+#define RXCTE		BIT(8)		/* Rx cut-through enable */
+#define PROTE		BIT(5)		/* Ctrl read/write Protection Enable */
+#define CPS		GENMASK(2, 0)	/* Chunk Payload Size */
+
+/* Unmasking interrupt fields in IMASK0 */
+#define HDREM		~BIT(5)		/* Header Error Mask */
+#define LOFEM		~BIT(4)		/* Loss of Framing Error Mask */
+#define RXBOEM		~BIT(3)		/* Rx Buffer Overflow Error Mask */
+#define TXBUEM		~BIT(2)		/* Tx Buffer Underflow Error Mask */
+#define TXBOEM		~BIT(1)		/* Tx Buffer Overflow Error Mask */
+#define TXPEM		~BIT(0)		/* Tx Protocol Error Mask */
+
 /* STATUS0 register field */
 #define RESETC		BIT(6)		/* Reset Complete */
 
@@ -31,15 +48,20 @@
 #define TC6_FTR_SIZE	4		/* Ctrl command footer size ss per OA */
 
 struct oa_tc6 {
-	struct spi_device *spi;
-	bool ctrl_prot;
+	struct completion rst_complete;
 	struct task_struct *tc6_task;
 	wait_queue_head_t tc6_wq;
+	struct spi_device *spi;
+	bool tx_cut_thr;
+	bool rx_cut_thr;
+	bool ctrl_prot;
 	bool int_flag;
-	struct completion rst_complete;
+	u8 cps;
 };
 
 struct oa_tc6 *oa_tc6_init(struct spi_device *spi);
 int oa_tc6_deinit(struct oa_tc6 *tc6);
 int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
 int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
+int oa_tc6_configure(struct oa_tc6 *tc6, u8 cps, bool ctrl_prot, bool tx_cut_thr,
+		     bool rx_cut_thr);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface
  2023-09-08 14:29 [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface Parthiban Veerasooran
                   ` (2 preceding siblings ...)
  2023-09-08 14:29 ` [RFC PATCH net-next 3/6] net: ethernet: implement OA TC6 configuration function Parthiban Veerasooran
@ 2023-09-08 14:29 ` Parthiban Veerasooran
  2023-09-10 17:58   ` Simon Horman
                     ` (2 more replies)
  2023-09-08 14:29 ` [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY Parthiban Veerasooran
                   ` (3 subsequent siblings)
  7 siblings, 3 replies; 85+ messages in thread
From: Parthiban Veerasooran @ 2023-09-08 14:29 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	andrew
  Cc: netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	Parthiban Veerasooran

The ethernet frame to be sent to MAC-PHY is converted into multiple
transmit data chunks. A transmit data chunk consists of a 4-byte data
header followed by the transmit data chunk payload.

The received ethernet frame from the network is converted into multiple
receive data chunks by the MAC-PHY and a receive data chunk consists of
the receive data chunk payload followed by a 4-byte data footer at the
end.

The MAC-PHY shall support a default data chunk payload size of 64 bytes.
Data chunk payload sizes of 32, 16, or 8 bytes may also be supported. The
data chunk payload is always a multiple of 4 bytes.

The 4-byte data header occurs at the beginning of each transmit data
chunk on MOSI and the 4-byte data footer occurs at the end of each
receive data chunk on MISO. The data header and footer contain the
information needed to determine the validity and location of the transmit
and receive frame data within the data chunk payload. Ethernet frames
shall be aligned to a 32-bit boundary within the data chunk payload.

Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
 drivers/net/ethernet/oa_tc6.c | 425 +++++++++++++++++++++++++++++++++-
 include/linux/oa_tc6.h        |  65 +++++-
 2 files changed, 485 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
index 65a7317f768d..20138b178185 100644
--- a/drivers/net/ethernet/oa_tc6.c
+++ b/drivers/net/ethernet/oa_tc6.c
@@ -5,6 +5,7 @@
  * Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
  */
 
+#include <linux/etherdevice.h>
 #include <linux/bitfield.h>
 #include <linux/interrupt.h>
 #include <linux/oa_tc6.h>
@@ -193,17 +194,224 @@ int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
 	return ret;
 }
 
+static u16 oa_tc6_prepare_empty_chunk(struct oa_tc6 *tc6, u8 *buf, u8 cp_count)
+{
+	u32 hdr;
+
+	/* Prepare empty chunks used for getting interrupt information or if
+	 * receive data available.
+	 */
+	for (u8 i = 0; i < cp_count; i++) {
+		hdr = FIELD_PREP(DATA_HDR_DNC, 1);
+		hdr |= FIELD_PREP(DATA_HDR_P, oa_tc6_get_parity(hdr));
+		hdr = cpu_to_be32(hdr);
+		*(u32 *)&buf[i * (tc6->cps + TC6_HDR_SIZE)] = hdr;
+		memset(&buf[TC6_HDR_SIZE + (i * (tc6->cps + TC6_HDR_SIZE))], 0,
+		       tc6->cps);
+	}
+
+	return cp_count * (tc6->cps + TC6_HDR_SIZE);
+}
+
+static void oa_tc6_rx_eth_ready(struct oa_tc6 *tc6)
+{
+	struct sk_buff *skb = NULL;
+
+	/* Send the received ethernet packet to network layer */
+	skb = netdev_alloc_skb(tc6->netdev, tc6->rxd_bytes + NET_IP_ALIGN);
+	if (!skb) {
+		tc6->netdev->stats.rx_dropped++;
+		netdev_err(tc6->netdev, "Out of memory for rx'd frame");
+	} else {
+		skb_reserve(skb, NET_IP_ALIGN);
+		memcpy(skb_put(skb, tc6->rxd_bytes), &tc6->eth_rx_buf[0],
+		       tc6->rxd_bytes);
+		skb->protocol = eth_type_trans(skb, tc6->netdev);
+		tc6->netdev->stats.rx_packets++;
+		tc6->netdev->stats.rx_bytes += tc6->rxd_bytes;
+		netif_rx(skb);
+	}
+}
+
+static int oa_tc6_process_exst(struct oa_tc6 *tc6)
+{
+	u32 regval;
+	int ret;
+
+	ret = oa_tc6_read_register(tc6, OA_TC6_STS0, &regval, 1);
+	if (ret) {
+		netdev_err(tc6->netdev, "STS0 register read failed.\n");
+		return ret;
+	}
+	if (regval & TXPE)
+		netdev_err(tc6->netdev, "Transmit protocol error\n");
+	if (regval & TXBOE)
+		netdev_err(tc6->netdev, "Transmit buffer overflow\n");
+	if (regval & TXBUE)
+		netdev_err(tc6->netdev, "Transmit buffer underflow\n");
+	if (regval & RXBOE)
+		netdev_err(tc6->netdev, "Receive buffer overflow\n");
+	if (regval & LOFE)
+		netdev_err(tc6->netdev, "Loss of frame\n");
+	if (regval & HDRE)
+		netdev_err(tc6->netdev, "Header error\n");
+	if (regval & TXFCSE)
+		netdev_err(tc6->netdev, "Transmit Frame Check Sequence Error\n");
+	ret = oa_tc6_write_register(tc6, OA_TC6_STS0, &regval, 1);
+	if (ret)
+		netdev_err(tc6->netdev, "STS0 register write failed.\n");
+	return ret;
+}
+
+static int oa_tc6_process_rx_chunks(struct oa_tc6 *tc6, u8 *buf, u16 len)
+{
+	u8 cp_count;
+	u8 *payload;
+	u32 ftr;
+	u16 ebo;
+	u16 sbo;
+
+	/* Calculate the number of chunks received */
+	cp_count = len / (tc6->cps + TC6_FTR_SIZE);
+
+	for (u8 i = 0; i < cp_count; i++) {
+		/* Get the footer and payload */
+		ftr = *(u32 *)&buf[tc6->cps + (i * (tc6->cps + TC6_FTR_SIZE))];
+		ftr = be32_to_cpu(ftr);
+		payload = &buf[(i * (tc6->cps + TC6_FTR_SIZE))];
+		/* Check for footer parity error */
+		if (oa_tc6_get_parity(ftr)) {
+			netdev_err(tc6->netdev, "Footer: Parity error\n");
+			goto err_exit;
+		}
+		/* If EXST set in the footer then read STS0 register to get the
+		 * status information.
+		 */
+		if (FIELD_GET(DATA_FTR_EXST, ftr)) {
+			if (oa_tc6_process_exst(tc6))
+				netdev_err(tc6->netdev, "Failed to process EXST\n");
+			goto err_exit;
+		}
+		if (FIELD_GET(DATA_FTR_HDRB, ftr)) {
+			netdev_err(tc6->netdev, "Footer: Received header bad\n");
+			goto err_exit;
+		}
+		if (!FIELD_GET(DATA_FTR_SYNC, ftr)) {
+			netdev_err(tc6->netdev, "Footer: Configuration unsync\n");
+			goto err_exit;
+		}
+		/* If Frame Drop is set, indicates that the MAC has detected a
+		 * condition for which the SPI host should drop the received
+		 * ethernet frame.
+		 */
+		if (FIELD_GET(DATA_FTR_FD, ftr) && FIELD_GET(DATA_FTR_EV, ftr)) {
+			netdev_warn(tc6->netdev, "Footer: Frame drop\n");
+			if (FIELD_GET(DATA_FTR_SV, ftr)) {
+				goto start_new_frame;
+			} else {
+				if (tc6->rx_eth_started) {
+					tc6->rxd_bytes = 0;
+					tc6->rx_eth_started = false;
+					tc6->netdev->stats.rx_dropped++;
+				}
+				continue;
+			}
+		}
+		/* Check for data valid */
+		if (FIELD_GET(DATA_FTR_DV, ftr)) {
+			/* Check whether both start valid and end valid are in a
+			 * single chunk payload means a single chunk payload may
+			 * contain an entire ethernet frame.
+			 */
+			if (FIELD_GET(DATA_FTR_SV, ftr) &&
+			    FIELD_GET(DATA_FTR_EV, ftr)) {
+				sbo = FIELD_GET(DATA_FTR_SWO, ftr) * 4;
+				ebo = FIELD_GET(DATA_FTR_EBO, ftr) + 1;
+				if (ebo <= sbo) {
+					memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
+					       &payload[0], ebo);
+					tc6->rxd_bytes += ebo;
+					oa_tc6_rx_eth_ready(tc6);
+					tc6->rxd_bytes = 0;
+					memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
+					       &payload[sbo], tc6->cps - sbo);
+					tc6->rxd_bytes += (tc6->cps - sbo);
+					goto exit;
+				} else {
+					memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
+					       &payload[sbo], ebo - sbo);
+					tc6->rxd_bytes += (ebo - sbo);
+					oa_tc6_rx_eth_ready(tc6);
+					tc6->rxd_bytes = 0;
+					goto exit;
+				}
+			}
+start_new_frame:
+			/* Check for start valid to start capturing the incoming
+			 * ethernet frame.
+			 */
+			if (FIELD_GET(DATA_FTR_SV, ftr) && !tc6->rx_eth_started) {
+				tc6->rxd_bytes = 0;
+				tc6->rx_eth_started = true;
+				sbo = FIELD_GET(DATA_FTR_SWO, ftr) * 4;
+				memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
+				       &payload[sbo], tc6->cps - sbo);
+				tc6->rxd_bytes += (tc6->cps - sbo);
+				goto exit;
+			}
+
+			/* Check for end valid and calculate the copy length */
+			if (tc6->rx_eth_started) {
+				if (FIELD_GET(DATA_FTR_EV, ftr))
+					ebo = FIELD_GET(DATA_FTR_EBO, ftr) + 1;
+				else
+					ebo = tc6->cps;
+
+				memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
+				       &payload[0], ebo);
+				tc6->rxd_bytes += ebo;
+				if (FIELD_GET(DATA_FTR_EV, ftr)) {
+					/* If End Valid set then send the
+					 * received ethernet frame to n/w.
+					 */
+					oa_tc6_rx_eth_ready(tc6);
+					tc6->rxd_bytes = 0;
+					tc6->rx_eth_started = false;
+				}
+			}
+		}
+
+exit:
+		tc6->txc = FIELD_GET(DATA_FTR_TXC, ftr);
+		tc6->rca = FIELD_GET(DATA_FTR_RCA, ftr);
+	}
+	return FTR_OK;
+
+err_exit:
+	if (tc6->rx_eth_started) {
+		tc6->rxd_bytes = 0;
+		tc6->rx_eth_started = false;
+		tc6->netdev->stats.rx_dropped++;
+	}
+	return FTR_ERR;
+}
+
 static int oa_tc6_handler(void *data)
 {
 	struct oa_tc6 *tc6 = data;
+	bool txc_wait = false;
+	u16 tx_pos = 0;
 	u32 regval;
+	u16 len;
 	int ret;
 
 	while (likely(!kthread_should_stop())) {
-		wait_event_interruptible(tc6->tc6_wq, tc6->int_flag ||
+		wait_event_interruptible(tc6->tc6_wq, tc6->tx_flag ||
+					 tc6->int_flag || tc6->rca ||
 					 kthread_should_stop());
-		if (tc6->int_flag) {
+		if (tc6->int_flag && !tc6->reset) {
 			tc6->int_flag = false;
+			tc6->reset = true;
 			ret = oa_tc6_perform_ctrl(tc6, OA_TC6_STS0, &regval, 1,
 						  false, false);
 			if (ret) {
@@ -227,10 +435,170 @@ static int oa_tc6_handler(void *data)
 				complete(&tc6->rst_complete);
 			}
 		}
+
+		if (tc6->int_flag || tc6->rca) {
+			/* If rca is updated from the previous footer then
+			 * prepare the empty chunks equal to rca and perform
+			 * SPI transfer to receive the ethernet frame.
+			 */
+			if (tc6->rca) {
+				len = oa_tc6_prepare_empty_chunk(tc6,
+								 tc6->spi_tx_buf,
+								 tc6->rca);
+			} else {
+				/* If there is an interrupt then perform a SPI
+				 * transfer with a empty chunk to get the
+				 * details.
+				 */
+				tc6->int_flag = false;
+				len = oa_tc6_prepare_empty_chunk(tc6,
+								 tc6->spi_tx_buf,
+								 1);
+			}
+			/* Perform SPI transfer */
+			ret = oa_tc6_spi_transfer(tc6->spi, tc6->spi_tx_buf,
+						  tc6->spi_rx_buf, len);
+			if (ret) {
+				netdev_err(tc6->netdev, "SPI transfer failed\n");
+				continue;
+			}
+			/* Process the received chunks to get the ethernet frame
+			 * or interrupt details.
+			 */
+			if (oa_tc6_process_rx_chunks(tc6, tc6->spi_rx_buf, len))
+				continue;
+		}
+
+		/* If there is a tx ethernet frame available */
+		if (tc6->tx_flag || txc_wait) {
+			tc6->tx_flag = false;
+			txc_wait = false;
+			len = 0;
+			if (!tc6->txc) {
+				/* If there is no txc available to transport the
+				 * tx ethernet frames then wait for the MAC-PHY
+				 * interrupt to get the txc availability.
+				 */
+				txc_wait = true;
+				continue;
+			} else if (tc6->txc >= tc6->txc_needed) {
+				len = tc6->txc_needed * (tc6->cps + TC6_HDR_SIZE);
+			} else {
+				len = tc6->txc * (tc6->cps + TC6_HDR_SIZE);
+			}
+			memcpy(&tc6->spi_tx_buf[0], &tc6->eth_tx_buf[tx_pos],
+			       len);
+			ret = oa_tc6_spi_transfer(tc6->spi, tc6->spi_tx_buf,
+						  tc6->spi_rx_buf, len);
+			if (ret) {
+				netdev_err(tc6->netdev, "SPI transfer failed\n");
+				continue;
+			}
+			/* Process the received chunks to get the ethernet frame
+			 * or status.
+			 */
+			if (oa_tc6_process_rx_chunks(tc6, tc6->spi_rx_buf,
+						     len)) {
+				/* In case of error while processing rx chunks
+				 * discard the incomplete tx ethernet frame and
+				 * resend it.
+				 */
+				tx_pos = 0;
+				tc6->txc_needed = tc6->total_txc_needed;
+			} else {
+				tx_pos += len;
+				tc6->txc_needed = tc6->txc_needed -
+						  (len / (tc6->cps + TC6_HDR_SIZE));
+				/* If the complete ethernet frame is transmitted
+				 * then return the skb and update the details to
+				 * n/w layer.
+				 */
+				if (!tc6->txc_needed) {
+					tc6->netdev->stats.tx_packets++;
+					tc6->netdev->stats.tx_bytes += tc6->tx_skb->len;
+					dev_kfree_skb(tc6->tx_skb);
+					tx_pos = 0;
+					tc6->tx_skb = NULL;
+					if (netif_queue_stopped(tc6->netdev))
+						netif_wake_queue(tc6->netdev);
+				} else if (tc6->txc) {
+					/* If txc is available again and updated
+					 * from the previous footer then perform
+					 * tx again.
+					 */
+					tc6->tx_flag = true;
+				} else {
+					/* If there is no txc then wait for the
+					 * interrupt to indicate txc
+					 * availability.
+					 */
+					txc_wait = true;
+				}
+			}
+		}
 	}
 	return 0;
 }
 
+static void oa_tc6_prepare_tx_chunks(struct oa_tc6 *tc6, u8 *buf,
+				     struct sk_buff *skb)
+{
+	bool frame_started = false;
+	u16 copied_bytes = 0;
+	u16 copy_len;
+	u32 hdr;
+
+	/* Calculate the number tx credit counts needed to transport the tx
+	 * ethernet frame.
+	 */
+	tc6->txc_needed = (skb->len / tc6->cps) + ((skb->len % tc6->cps) ? 1 : 0);
+	tc6->total_txc_needed = tc6->txc_needed;
+
+	for (u8 i = 0; i < tc6->txc_needed; i++) {
+		/* Prepare the header for each chunks to be transmitted */
+		hdr = FIELD_PREP(DATA_HDR_DNC, 1) |
+		      FIELD_PREP(DATA_HDR_DV, 1);
+		if (!frame_started) {
+			hdr |= FIELD_PREP(DATA_HDR_SV, 1) |
+			       FIELD_PREP(DATA_HDR_SWO, 0);
+			frame_started = true;
+		}
+		if ((tc6->cps + copied_bytes) >= skb->len) {
+			copy_len = skb->len - copied_bytes;
+			hdr |= FIELD_PREP(DATA_HDR_EBO, copy_len - 1) |
+			       FIELD_PREP(DATA_HDR_EV, 1);
+		} else {
+			copy_len = tc6->cps;
+		}
+		copied_bytes += copy_len;
+		hdr |= FIELD_PREP(DATA_HDR_P, oa_tc6_get_parity(hdr));
+		hdr = cpu_to_be32(hdr);
+		*(u32 *)&buf[i * (tc6->cps + TC6_HDR_SIZE)] = hdr;
+		/* Copy the ethernet frame in the chunk payload section */
+		memcpy(&buf[TC6_HDR_SIZE + (i * (tc6->cps + TC6_HDR_SIZE))],
+		       &skb->data[copied_bytes - copy_len], copy_len);
+	}
+}
+
+netdev_tx_t oa_tc6_send_eth_pkt(struct oa_tc6 *tc6, struct sk_buff *skb)
+{
+	if (tc6->tx_skb) {
+		netif_stop_queue(tc6->netdev);
+		return NETDEV_TX_BUSY;
+	}
+
+	tc6->tx_skb = skb;
+	/* Prepare tx chunks using the tx ethernet frame */
+	oa_tc6_prepare_tx_chunks(tc6, tc6->eth_tx_buf, skb);
+
+	/* Wake tc6 task to perform tx transfer */
+	tc6->tx_flag = true;
+	wake_up_interruptible(&tc6->tc6_wq);
+
+	return NETDEV_TX_OK;
+}
+EXPORT_SYMBOL_GPL(oa_tc6_send_eth_pkt);
+
 static irqreturn_t macphy_irq(int irq, void *dev_id)
 {
 	struct oa_tc6 *tc6 = dev_id;
@@ -293,6 +661,14 @@ int oa_tc6_configure(struct oa_tc6 *tc6, u8 cps, bool ctrl_prot, bool tx_cut_thr
 	u32 regval;
 	int ret;
 
+	/* Read BUFSTS register to get the current txc and rca. */
+	ret = oa_tc6_read_register(tc6, OA_TC6_BUFSTS, &regval, 1);
+	if (ret)
+		return ret;
+
+	tc6->txc = FIELD_GET(TXC, regval);
+	tc6->rca = FIELD_GET(RCA, regval);
+
 	/* Read and configure the IMASK0 register for unmasking the interrupts */
 	ret = oa_tc6_read_register(tc6, OA_TC6_IMASK0, &regval, 1);
 	if (ret)
@@ -326,7 +702,7 @@ int oa_tc6_configure(struct oa_tc6 *tc6, u8 cps, bool ctrl_prot, bool tx_cut_thr
 }
 EXPORT_SYMBOL_GPL(oa_tc6_configure);
 
-struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
+struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev)
 {
 	struct oa_tc6 *tc6;
 	int ret;
@@ -334,11 +710,39 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
 	if (!spi)
 		return NULL;
 
+	if (!netdev)
+		return NULL;
+
 	tc6 = kzalloc(sizeof(*tc6), GFP_KERNEL);
 	if (!tc6)
 		return NULL;
 
 	tc6->spi = spi;
+	tc6->netdev = netdev;
+
+	/* Allocate memory for the tx buffer used for SPI transfer. */
+	tc6->spi_tx_buf = kzalloc(MAX_ETH_LEN + (OA_TC6_MAX_CPS * TC6_HDR_SIZE),
+				  GFP_KERNEL);
+	if (!tc6->spi_tx_buf)
+		goto err_spi_tx_buf_alloc;
+
+	/* Allocate memory for the rx buffer used for SPI transfer. */
+	tc6->spi_rx_buf = kzalloc(MAX_ETH_LEN + (OA_TC6_MAX_CPS * TC6_FTR_SIZE),
+				  GFP_KERNEL);
+	if (!tc6->spi_rx_buf)
+		goto err_spi_rx_buf_alloc;
+
+	/* Allocate memory for the tx ethernet chunks to transfer on SPI. */
+	tc6->eth_tx_buf = kzalloc(MAX_ETH_LEN + (OA_TC6_MAX_CPS * TC6_HDR_SIZE),
+				  GFP_KERNEL);
+	if (!tc6->eth_tx_buf)
+		goto err_eth_tx_buf_alloc;
+
+	/* Allocate memory for the rx ethernet packet. */
+	tc6->eth_rx_buf = kzalloc(MAX_ETH_LEN + (OA_TC6_MAX_CPS * TC6_FTR_SIZE),
+				  GFP_KERNEL);
+	if (!tc6->eth_rx_buf)
+		goto err_eth_rx_buf_alloc;
 
 	/* Used for triggering the OA TC6 task */
 	init_waitqueue_head(&tc6->tc6_wq);
@@ -372,6 +776,14 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
 err_macphy_irq:
 	kthread_stop(tc6->tc6_task);
 err_tc6_task:
+	kfree(tc6->eth_rx_buf);
+err_eth_rx_buf_alloc:
+	kfree(tc6->eth_tx_buf);
+err_eth_tx_buf_alloc:
+	kfree(tc6->spi_rx_buf);
+err_spi_rx_buf_alloc:
+	kfree(tc6->spi_tx_buf);
+err_spi_tx_buf_alloc:
 	kfree(tc6);
 	return NULL;
 }
@@ -383,8 +795,13 @@ int oa_tc6_deinit(struct oa_tc6 *tc6)
 
 	devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
 	ret = kthread_stop(tc6->tc6_task);
-	if (!ret)
+	if (!ret) {
+		kfree(tc6->eth_rx_buf);
+		kfree(tc6->eth_tx_buf);
+		kfree(tc6->spi_rx_buf);
+		kfree(tc6->spi_tx_buf);
 		kfree(tc6);
+	}
 	return ret;
 }
 EXPORT_SYMBOL_GPL(oa_tc6_deinit);
diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
index fa29c4e09720..61ac1cdfa7d6 100644
--- a/include/linux/oa_tc6.h
+++ b/include/linux/oa_tc6.h
@@ -6,6 +6,7 @@
  */
 
 #include <linux/spi/spi.h>
+#include <linux/netdevice.h>
 
 /* Control header */
 #define CTRL_HDR_DNC	BIT(31)		/* Data-Not-Control */
@@ -17,10 +18,36 @@
 #define CTRL_HDR_LEN	GENMASK(7, 1)	/* Length */
 #define CTRL_HDR_P	BIT(0)		/* Parity Bit */
 
+/* Data header */
+#define DATA_HDR_DNC	BIT(31)		/* Data-Not-Control */
+#define DATA_HDR_SEQ	BIT(30)		/* Data Chunk Sequence */
+#define DATA_HDR_NORX	BIT(29)		/* No Receive */
+#define DATA_HDR_DV	BIT(21)		/* Data Valid */
+#define DATA_HDR_SV	BIT(20)		/* Start Valid */
+#define DATA_HDR_SWO	GENMASK(19, 16)	/* Start Word Offset */
+#define DATA_HDR_EV	BIT(14)		/* End Valid */
+#define DATA_HDR_EBO	GENMASK(13, 8)	/* End Byte Offset */
+#define DATA_HDR_P	BIT(0)		/* Header Parity Bit */
+
+/* Data footer */
+#define DATA_FTR_EXST	BIT(31)		/* Extended Status */
+#define DATA_FTR_HDRB	BIT(30)		/* Received Header Bad */
+#define DATA_FTR_SYNC	BIT(29)		/* Configuration Synchronized */
+#define DATA_FTR_RCA	GENMASK(28, 24)	/* Receive Chunks Available */
+#define DATA_FTR_DV	BIT(21)		/* Data Valid */
+#define DATA_FTR_SV	BIT(20)		/* Start Valid */
+#define DATA_FTR_SWO	GENMASK(19, 16)	/* Start Word Offset */
+#define DATA_FTR_FD	BIT(15)		/* Frame Drop */
+#define DATA_FTR_EV	BIT(14)		/* End Valid */
+#define DATA_FTR_EBO	GENMASK(13, 8)	/* End Byte Offset */
+#define DATA_FTR_TXC	GENMASK(5, 1)	/* Transmit Credits */
+#define DATA_FTR_P	BIT(0)		/* Footer Parity Bit */
+
 /* Open Alliance TC6 Standard Control and Status Registers */
 #define OA_TC6_RESET	0x0003		/* Reset Control and Status Register */
 #define OA_TC6_CONFIG0	0x0004		/* Configuration Register #0 */
 #define OA_TC6_STS0	0x0008		/* Status Register #0 */
+#define OA_TC6_BUFSTS	0x000B          /* Buffer Status Register */
 #define OA_TC6_IMASK0	0x000C		/* Interrupt Mask Register #0 */
 
 /* RESET register field */
@@ -33,6 +60,17 @@
 #define PROTE		BIT(5)		/* Ctrl read/write Protection Enable */
 #define CPS		GENMASK(2, 0)	/* Chunk Payload Size */
 
+/* STATUS0 register fields */
+#define CDPE		BIT(12)		/* Control Data Protection Error */
+#define TXFCSE		BIT(11)		/* Transmit Frame Check Sequence Error */
+#define RESETC		BIT(6)		/* Reset Complete */
+#define HDRE		BIT(5)		/* Header Error */
+#define LOFE		BIT(4)		/* Loss of Framing Error */
+#define RXBOE		BIT(3)		/* Receive Buffer Overflow Error */
+#define TXBUE		BIT(2)		/* Transmit Buffer Underflow Error */
+#define TXBOE		BIT(1)		/* Transmit Buffer Overflow Error */
+#define TXPE		BIT(0)		/* Transmit Protocol Error */
+
 /* Unmasking interrupt fields in IMASK0 */
 #define HDREM		~BIT(5)		/* Header Error Mask */
 #define LOFEM		~BIT(4)		/* Loss of Framing Error Mask */
@@ -44,24 +82,49 @@
 /* STATUS0 register field */
 #define RESETC		BIT(6)		/* Reset Complete */
 
+/* BUFSTS register fields */
+#define TXC		GENMASK(15, 8)	/* Transmit Credits Available */
+#define RCA		GENMASK(7, 0)	/* Receive Chunks Available */
+
 #define TC6_HDR_SIZE	4		/* Ctrl command header size as per OA */
 #define TC6_FTR_SIZE	4		/* Ctrl command footer size ss per OA */
 
+#define FTR_OK		0
+#define FTR_ERR		1
+
+#define MAX_ETH_LEN	1536
+#define OA_TC6_MAX_CPS	64
+
 struct oa_tc6 {
 	struct completion rst_complete;
 	struct task_struct *tc6_task;
+	struct net_device *netdev;
 	wait_queue_head_t tc6_wq;
 	struct spi_device *spi;
+	struct sk_buff *tx_skb;
+	u8 total_txc_needed;
+	bool rx_eth_started;
 	bool tx_cut_thr;
 	bool rx_cut_thr;
 	bool ctrl_prot;
+	u8 *spi_tx_buf;
+	u8 *spi_rx_buf;
+	u8 *eth_tx_buf;
+	u8 *eth_rx_buf;
 	bool int_flag;
+	u16 rxd_bytes;
+	u8 txc_needed;
+	bool tx_flag;
+	bool reset;
 	u8 cps;
+	u8 txc;
+	u8 rca;
 };
 
-struct oa_tc6 *oa_tc6_init(struct spi_device *spi);
+struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev);
 int oa_tc6_deinit(struct oa_tc6 *tc6);
 int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
 int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
 int oa_tc6_configure(struct oa_tc6 *tc6, u8 cps, bool ctrl_prot, bool tx_cut_thr,
 		     bool rx_cut_thr);
+netdev_tx_t oa_tc6_send_eth_pkt(struct oa_tc6 *tc6, struct sk_buff *skb);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  2023-09-08 14:29 [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface Parthiban Veerasooran
                   ` (3 preceding siblings ...)
  2023-09-08 14:29 ` [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface Parthiban Veerasooran
@ 2023-09-08 14:29 ` Parthiban Veerasooran
  2023-09-10 17:44   ` Simon Horman
                     ` (4 more replies)
  2023-09-08 14:29 ` [RFC PATCH net-next 6/6] microchip: lan865x: add device-tree " Parthiban Veerasooran
                   ` (2 subsequent siblings)
  7 siblings, 5 replies; 85+ messages in thread
From: Parthiban Veerasooran @ 2023-09-08 14:29 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	andrew
  Cc: netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	Parthiban Veerasooran

The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE‑T1x
MAC‑PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
MAC integration provides the low pin count standard SPI interface to any
microcontroller therefore providing Ethernet functionality without
requiring MAC integration within the microcontroller. The LAN8650/1
operates as an SPI client supporting SCLK clock rates up to a maximum of
25 MHz. This SPI interface supports the transfer of both data (Ethernet
frames) and control (register access).

By default, the chunk data payload is 64 bytes in size. A smaller payload
data size of 32 bytes is also supported and may be configured in the
Chunk Payload Size (CPS) field of the Configuration 0 (OA_CONFIG0)
register. Changing the chunk payload size requires the LAN8650/1 be reset
and shall not be done during normal operation.

The Ethernet Media Access Controller (MAC) module implements a 10 Mbps
half duplex Ethernet MAC, compatible with the IEEE 802.3 standard.
10BASE-T1S physical layer transceiver integrated into the LAN8650/1. The
PHY and MAC are connected via an internal Media Independent Interface
(MII).

Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
 MAINTAINERS                              |   6 +
 drivers/net/ethernet/microchip/Kconfig   |  10 +
 drivers/net/ethernet/microchip/Makefile  |   3 +
 drivers/net/ethernet/microchip/lan865x.c | 589 +++++++++++++++++++++++
 4 files changed, 608 insertions(+)
 create mode 100644 drivers/net/ethernet/microchip/lan865x.c

diff --git a/MAINTAINERS b/MAINTAINERS
index c54454c7e7a1..666c042a15b2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13879,6 +13879,12 @@ L:	netdev@vger.kernel.org
 S:	Maintained
 F:	drivers/net/ethernet/microchip/lan743x_*
 
+MICROCHIP LAN8650/1 10BASE-T1S MACPHY ETHERNET DRIVER
+M:	Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	drivers/net/ethernet/microchip/lan865x.c
+
 MICROCHIP LAN87xx/LAN937x T1 PHY DRIVER
 M:	Arun Ramadoss <arun.ramadoss@microchip.com>
 R:	UNGLinuxDriver@microchip.com
diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
index 329e374b9539..d99be51b99f1 100644
--- a/drivers/net/ethernet/microchip/Kconfig
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -59,4 +59,14 @@ source "drivers/net/ethernet/microchip/lan966x/Kconfig"
 source "drivers/net/ethernet/microchip/sparx5/Kconfig"
 source "drivers/net/ethernet/microchip/vcap/Kconfig"
 
+config LAN865X
+	tristate "LAN865x support"
+	depends on SPI
+	help
+      	  Support for the Microchip LAN8650/1 Rev.B0 Ethernet chip. It uses OPEN
+	  Alliance 10BASE-T1x Serial Interface specification.
+
+      	  To compile this driver as a module, choose M here. The module will be
+          called lan865x.
+
 endif # NET_VENDOR_MICROCHIP
diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile
index bbd349264e6f..315e850b2b26 100644
--- a/drivers/net/ethernet/microchip/Makefile
+++ b/drivers/net/ethernet/microchip/Makefile
@@ -12,3 +12,6 @@ lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o
 obj-$(CONFIG_LAN966X_SWITCH) += lan966x/
 obj-$(CONFIG_SPARX5_SWITCH) += sparx5/
 obj-$(CONFIG_VCAP) += vcap/
+
+obj-$(CONFIG_LAN865X) += lan865x_t1s.o
+lan865x_t1s-objs := lan865x.o ../oa_tc6.o
diff --git a/drivers/net/ethernet/microchip/lan865x.c b/drivers/net/ethernet/microchip/lan865x.c
new file mode 100644
index 000000000000..3c8ebf4c258f
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan865x.c
@@ -0,0 +1,589 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Microchip's LAN865x 10BASE-T1S MAC-PHY driver
+ *
+ * Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/etherdevice.h>
+#include <linux/mdio.h>
+#include <linux/phy.h>
+#include <linux/of.h>
+#include <linux/oa_tc6.h>
+
+#define DRV_NAME		"lan865x"
+#define DRV_VERSION		"0.1"
+
+#define REG_STDR_RESET		0x00000003
+#define REG_MAC_ADDR_BO		0x00010022
+#define REG_MAC_ADDR_L		0x00010024
+#define REG_MAC_ADDR_H		0x00010025
+#define REG_MAC_NW_CTRL         0x00010000
+#define REG_MAC_NW_CONFIG	0x00010001
+#define REG_MAC_HASHL		0x00010020
+#define REG_MAC_HASHH		0x00010021
+#define REG_MAC_ADDR_BO		0x00010022
+#define REG_MAC_ADDR_L		0x00010024
+#define REG_MAC_ADDR_H		0x00010025
+
+#define CCS_Q0_TX_CFG		0x000A0081
+#define CCS_Q0_RX_CFG		0x000A0082
+
+/* Buffer configuration for 32-bytes chunk payload */
+#define CCS_Q0_TX_CFG_32	0x70000000
+#define CCS_Q0_RX_CFG_32	0x30000C00
+
+#define NW_RX_STATUS		BIT(2)
+#define NW_TX_STATUS		BIT(3)
+#define NW_DISABLE		0x0
+
+#define MAC_PROMISCUOUS_MODE	BIT(4)
+#define MAC_MULTICAST_MODE	BIT(6)
+#define MAC_UNICAST_MODE	BIT(7)
+
+#define TX_TIMEOUT		(4 * HZ)
+#define LAN865X_MSG_DEFAULT	\
+	(NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_LINK)
+
+struct lan865x_priv {
+	struct net_device *netdev;
+	struct spi_device *spi;
+	struct oa_tc6 *tc6;
+	struct mii_bus *mdiobus;
+	struct phy_device *phydev;
+	struct device *dev;
+	u32 msg_enable;
+	bool txcte;
+	bool rxcte;
+	u32 cps;
+	bool protected;
+};
+
+static void lan865x_handle_link_change(struct net_device *netdev)
+{
+	struct lan865x_priv *priv = netdev_priv(netdev);
+
+	phy_print_status(priv->phydev);
+}
+
+static int lan865x_mdiobus_read(struct mii_bus *bus, int phy_id, int idx)
+{
+	struct lan865x_priv *priv = bus->priv;
+	u32 regval;
+	bool ret;
+
+	ret = oa_tc6_read_register(priv->tc6, 0xFF00 | (idx & 0xFF), &regval, 1);
+	if (ret)
+		return -ENODEV;
+
+	return regval;
+}
+
+static int lan865x_mdiobus_write(struct mii_bus *bus, int phy_id, int idx,
+				 u16 regval)
+{
+	struct lan865x_priv *priv = bus->priv;
+	u32 value = regval;
+	bool ret;
+
+	ret = oa_tc6_write_register(priv->tc6, 0xFF00 | (idx & 0xFF), &value, 1);
+	if (ret)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int lan865x_phy_init(struct lan865x_priv *priv)
+{
+	int ret;
+
+	priv->mdiobus = mdiobus_alloc();
+	if (!priv->mdiobus) {
+		netdev_err(priv->netdev, "MDIO bus alloc failed\n");
+		return -ENODEV;
+	}
+
+	priv->mdiobus->phy_mask = ~(u32)BIT(1);
+	priv->mdiobus->priv = priv;
+	priv->mdiobus->read = lan865x_mdiobus_read;
+	priv->mdiobus->write = lan865x_mdiobus_write;
+	priv->mdiobus->name = "lan865x-mdiobus";
+	priv->mdiobus->parent = priv->dev;
+
+	snprintf(priv->mdiobus->id, ARRAY_SIZE(priv->mdiobus->id),
+		 "%s", dev_name(&priv->spi->dev));
+
+	ret = mdiobus_register(priv->mdiobus);
+	if (ret) {
+		netdev_err(priv->netdev, "Could not register MDIO bus\n");
+		mdiobus_free(priv->mdiobus);
+		return ret;
+	}
+	priv->phydev = phy_find_first(priv->mdiobus);
+	if (!priv->phydev) {
+		netdev_err(priv->netdev, "No PHY found\n");
+		mdiobus_unregister(priv->mdiobus);
+		mdiobus_free(priv->mdiobus);
+		return -ENODEV;
+	}
+	priv->phydev->is_internal = true;
+	ret = phy_connect_direct(priv->netdev, priv->phydev,
+				 &lan865x_handle_link_change,
+				 PHY_INTERFACE_MODE_INTERNAL);
+	if (ret) {
+		netdev_err(priv->netdev, "Can't attach PHY to %s\n", priv->mdiobus->id);
+		return ret;
+	}
+	phy_attached_info(priv->phydev);
+	return ret;
+}
+
+static int lan865x_set_hw_macaddr(struct net_device *netdev)
+{
+	u32 regval;
+	bool ret;
+	struct lan865x_priv *priv = netdev_priv(netdev);
+	const u8 *mac = netdev->dev_addr;
+
+	ret = oa_tc6_read_register(priv->tc6, REG_MAC_NW_CTRL, &regval, 1);
+	if (ret)
+		goto error_mac;
+	if ((regval & NW_TX_STATUS) | (regval & NW_RX_STATUS)) {
+		if (netif_msg_drv(priv))
+			netdev_warn(netdev, "Hardware must be disabled for MAC setting\n");
+		return -EBUSY;
+	}
+	/* MAC address setting */
+	regval = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) |
+		mac[0];
+	ret = oa_tc6_write_register(priv->tc6, REG_MAC_ADDR_L, &regval, 1);
+	if (ret)
+		goto error_mac;
+
+	regval = (mac[5] << 8) | mac[4];
+	ret = oa_tc6_write_register(priv->tc6, REG_MAC_ADDR_H, &regval, 1);
+	if (ret)
+		goto error_mac;
+
+	regval = (mac[5] << 24) | (mac[4] << 16) |
+		(mac[3] << 8) | mac[2];
+	ret = oa_tc6_write_register(priv->tc6, REG_MAC_ADDR_BO, &regval, 1);
+	if (ret)
+		goto error_mac;
+
+	return 0;
+
+error_mac:
+	return -ENODEV;
+}
+
+static int
+lan865x_set_link_ksettings(struct net_device *netdev,
+			   const struct ethtool_link_ksettings *cmd)
+{
+	struct lan865x_priv *priv = netdev_priv(netdev);
+	int ret = 0;
+
+	if (cmd->base.autoneg != AUTONEG_DISABLE ||
+	    cmd->base.speed != SPEED_10 || cmd->base.duplex != DUPLEX_HALF) {
+		if (netif_msg_link(priv))
+			netdev_warn(netdev, "Unsupported link setting");
+		ret = -EOPNOTSUPP;
+	} else {
+		if (netif_msg_link(priv))
+			netdev_warn(netdev, "Hardware must be disabled to set link mode");
+		ret = -EBUSY;
+	}
+	return ret;
+}
+
+static int
+lan865x_get_link_ksettings(struct net_device *netdev,
+			   struct ethtool_link_ksettings *cmd)
+{
+	ethtool_link_ksettings_zero_link_mode(cmd, supported);
+	ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Half);
+	ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
+
+	cmd->base.speed = SPEED_10;
+	cmd->base.duplex = DUPLEX_HALF;
+	cmd->base.port	= PORT_TP;
+	cmd->base.autoneg = AUTONEG_DISABLE;
+
+	return 0;
+}
+
+static void lan865x_set_msglevel(struct net_device *netdev, u32 val)
+{
+	struct lan865x_priv *priv = netdev_priv(netdev);
+
+	priv->msg_enable = val;
+}
+
+static u32 lan865x_get_msglevel(struct net_device *netdev)
+{
+	struct lan865x_priv *priv = netdev_priv(netdev);
+
+	return priv->msg_enable;
+}
+
+static void
+lan865x_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
+{
+	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strscpy(info->version, DRV_VERSION, sizeof(info->version));
+	strscpy(info->bus_info,
+		dev_name(netdev->dev.parent), sizeof(info->bus_info));
+}
+
+static const struct ethtool_ops lan865x_ethtool_ops = {
+	.get_drvinfo	= lan865x_get_drvinfo,
+	.get_msglevel	= lan865x_get_msglevel,
+	.set_msglevel	= lan865x_set_msglevel,
+	.get_link_ksettings = lan865x_get_link_ksettings,
+	.set_link_ksettings = lan865x_set_link_ksettings,
+};
+
+static void lan865x_tx_timeout(struct net_device *netdev, unsigned int txqueue)
+{
+	netdev->stats.tx_errors++;
+}
+
+static int lan865x_set_mac_address(struct net_device *netdev, void *addr)
+{
+	struct sockaddr *address = addr;
+
+	if (netif_running(netdev))
+		return -EBUSY;
+	if (!is_valid_ether_addr(address->sa_data))
+		return -EADDRNOTAVAIL;
+
+	eth_hw_addr_set(netdev, address->sa_data);
+	return lan865x_set_hw_macaddr(netdev);
+}
+
+static u32 lan865x_hash(u8 addr[ETH_ALEN])
+{
+	return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f;
+}
+
+static void lan865x_set_multicast_list(struct net_device *netdev)
+{
+	struct lan865x_priv *priv = netdev_priv(netdev);
+	u32 regval = 0;
+
+	if (netdev->flags & IFF_PROMISC) {
+		/* Enabling promiscuous mode */
+		regval |= MAC_PROMISCUOUS_MODE;
+		regval &= (~MAC_MULTICAST_MODE);
+		regval &= (~MAC_UNICAST_MODE);
+	} else if (netdev->flags & IFF_ALLMULTI) {
+		/* Enabling all multicast mode */
+		regval &= (~MAC_PROMISCUOUS_MODE);
+		regval |= MAC_MULTICAST_MODE;
+		regval &= (~MAC_UNICAST_MODE);
+	} else if (!netdev_mc_empty(netdev)) {
+		/* Enabling specific multicast addresses */
+		struct netdev_hw_addr *ha;
+		u32 hash_lo = 0;
+		u32 hash_hi = 0;
+
+		netdev_for_each_mc_addr(ha, netdev) {
+			u32 bit_num = lan865x_hash(ha->addr);
+			u32 mask = 1 << (bit_num & 0x1f);
+
+			if (bit_num & 0x20)
+				hash_hi |= mask;
+			else
+				hash_lo |= mask;
+		}
+		if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHH, &hash_hi, 1)) {
+			if (netif_msg_timer(priv))
+				netdev_err(netdev, "Failed to write reg_hashh");
+			return;
+		}
+		if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHL, &hash_lo, 1)) {
+			if (netif_msg_timer(priv))
+				netdev_err(netdev, "Failed to write reg_hashl");
+			return;
+		}
+		regval &= (~MAC_PROMISCUOUS_MODE);
+		regval &= (~MAC_MULTICAST_MODE);
+		regval |= MAC_UNICAST_MODE;
+	} else {
+		/* enabling local mac address only */
+		if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHH, &regval, 1)) {
+			if (netif_msg_timer(priv))
+				netdev_err(netdev, "Failed to write reg_hashh");
+			return;
+		}
+		if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHL, &regval, 1)) {
+			if (netif_msg_timer(priv))
+				netdev_err(netdev, "Failed to write reg_hashl");
+			return;
+		}
+	}
+	if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CONFIG, &regval, 1)) {
+		if (netif_msg_timer(priv))
+			netdev_err(netdev, "Failed to enable promiscuous mode");
+	}
+}
+
+static netdev_tx_t lan865x_send_packet(struct sk_buff *skb,
+				       struct net_device *netdev)
+{
+	struct lan865x_priv *priv = netdev_priv(netdev);
+
+	return oa_tc6_send_eth_pkt(priv->tc6, skb);
+}
+
+static int lan865x_hw_disable(struct lan865x_priv *priv)
+{
+	u32 regval = NW_DISABLE;
+
+	if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CTRL, &regval, 1))
+		return -ENODEV;
+
+	return 0;
+}
+
+static int lan865x_net_close(struct net_device *netdev)
+{
+	struct lan865x_priv *priv = netdev_priv(netdev);
+	int ret;
+
+	netif_stop_queue(netdev);
+	ret = lan865x_hw_disable(priv);
+	if (ret) {
+		if (netif_msg_ifup(priv))
+			netdev_err(netdev, "Failed to disable the hardware\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int lan865x_hw_enable(struct lan865x_priv *priv)
+{
+	u32 regval = NW_TX_STATUS | NW_RX_STATUS;
+
+	if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CTRL, &regval, 1))
+		return -ENODEV;
+
+	return 0;
+}
+
+static int lan865x_net_open(struct net_device *netdev)
+{
+	struct lan865x_priv *priv = netdev_priv(netdev);
+	int ret;
+
+	if (!is_valid_ether_addr(netdev->dev_addr)) {
+		if (netif_msg_ifup(priv))
+			netdev_err(netdev, "Invalid MAC address %pm", netdev->dev_addr);
+		return -EADDRNOTAVAIL;
+	}
+	if (lan865x_hw_disable(priv)) {
+		if (netif_msg_ifup(priv))
+			netdev_err(netdev, "Failed to disable the hardware\n");
+		return -ENODEV;
+	}
+	ret = lan865x_set_hw_macaddr(netdev);
+	if (ret != 0)
+		return ret;
+
+	if (lan865x_hw_enable(priv) != 0) {
+		if (netif_msg_ifup(priv))
+			netdev_err(netdev, "Failed to enable hardware\n");
+		return -ENODEV;
+	}
+	netif_start_queue(netdev);
+
+	return 0;
+}
+
+static const struct net_device_ops lan865x_netdev_ops = {
+	.ndo_open		= lan865x_net_open,
+	.ndo_stop		= lan865x_net_close,
+	.ndo_start_xmit		= lan865x_send_packet,
+	.ndo_set_rx_mode	= lan865x_set_multicast_list,
+	.ndo_set_mac_address	= lan865x_set_mac_address,
+	.ndo_tx_timeout		= lan865x_tx_timeout,
+	.ndo_validate_addr	= eth_validate_addr,
+};
+
+static int lan865x_get_dt_data(struct lan865x_priv *priv)
+{
+	struct spi_device *spi = priv->spi;
+	int ret;
+
+	if (of_property_present(spi->dev.of_node, "oa-chunk-size")) {
+		ret = of_property_read_u32(spi->dev.of_node, "oa-chunk-size",
+					   &priv->cps);
+		if (ret < 0)
+			return ret;
+	} else {
+		priv->cps = 64;
+		dev_info(&spi->dev, "Property oa-chunk-size is not found in dt and proceeding with the size 64\n");
+	}
+
+	if (of_property_present(spi->dev.of_node, "oa-tx-cut-through"))
+		priv->txcte = true;
+	else
+		dev_info(&spi->dev, "Property oa-tx-cut-through is not found in dt and proceeding with tx store and forward mode\n");
+
+	if (of_property_present(spi->dev.of_node, "oa-rx-cut-through"))
+		priv->rxcte = true;
+	else
+		dev_info(&spi->dev, "Property oa-rx-cut-through is not found in dt and proceeding with rx store and forward mode\n");
+
+	if (of_property_present(spi->dev.of_node, "oa-protected"))
+		priv->protected = true;
+	else
+		dev_info(&spi->dev, "Property oa-protected is not found in dt and proceeding with protection enabled\n");
+
+	return 0;
+}
+
+static int lan865x_probe(struct spi_device *spi)
+{
+	struct net_device *netdev;
+	struct lan865x_priv *priv;
+	u32 regval;
+	int ret;
+
+	netdev = alloc_etherdev(sizeof(struct lan865x_priv));
+	if (!netdev)
+		return -ENOMEM;
+
+	priv = netdev_priv(netdev);
+	priv->netdev = netdev;
+	priv->spi = spi;
+	priv->msg_enable = 0;
+	spi_set_drvdata(spi, priv);
+	SET_NETDEV_DEV(netdev, &spi->dev);
+
+	ret = lan865x_get_dt_data(priv);
+	if (ret)
+		return ret;
+
+	spi->rt = true;
+	spi_setup(spi);
+
+	priv->tc6 = oa_tc6_init(spi, netdev);
+	if (!priv->tc6) {
+		ret = -ENOMEM;
+		goto error_oa_tc6_init;
+	}
+
+	if (priv->cps == 32) {
+		regval = CCS_Q0_TX_CFG_32;
+		ret = oa_tc6_write_register(priv->tc6, CCS_Q0_TX_CFG, &regval, 1);
+		if (ret)
+			return ret;
+
+		regval = CCS_Q0_RX_CFG_32;
+		ret = oa_tc6_write_register(priv->tc6, CCS_Q0_RX_CFG, &regval, 1);
+		if (ret)
+			return ret;
+	}
+
+	if (oa_tc6_configure(priv->tc6, priv->cps, priv->protected, priv->txcte,
+			     priv->rxcte))
+		goto err_macphy_config;
+
+	ret = lan865x_phy_init(priv);
+	if (ret)
+		goto error_phy;
+
+	if (device_get_ethdev_address(&spi->dev, netdev))
+		eth_hw_addr_random(netdev);
+
+	ret = lan865x_set_hw_macaddr(netdev);
+	if (ret) {
+		if (netif_msg_probe(priv))
+			dev_err(&spi->dev, "Failed to configure MAC");
+		goto error_set_mac;
+	}
+
+	netdev->if_port = IF_PORT_10BASET;
+	netdev->irq = spi->irq;
+	netdev->netdev_ops = &lan865x_netdev_ops;
+	netdev->watchdog_timeo = TX_TIMEOUT;
+	netdev->ethtool_ops = &lan865x_ethtool_ops;
+	ret = register_netdev(netdev);
+	if (ret) {
+		if (netif_msg_probe(priv))
+			dev_err(&spi->dev, "Register netdev failed (ret = %d)",
+				ret);
+		goto error_netdev_register;
+	}
+
+	phy_start(priv->phydev);
+	return 0;
+
+error_netdev_register:
+error_set_mac:
+	phy_disconnect(priv->phydev);
+	mdiobus_unregister(priv->mdiobus);
+	mdiobus_free(priv->mdiobus);
+error_phy:
+err_macphy_config:
+	oa_tc6_deinit(priv->tc6);
+error_oa_tc6_init:
+	free_netdev(priv->netdev);
+	return ret;
+}
+
+static void lan865x_remove(struct spi_device *spi)
+{
+	struct lan865x_priv *priv = spi_get_drvdata(spi);
+
+	phy_stop(priv->phydev);
+	phy_disconnect(priv->phydev);
+	mdiobus_unregister(priv->mdiobus);
+	mdiobus_free(priv->mdiobus);
+	unregister_netdev(priv->netdev);
+	if (oa_tc6_deinit(priv->tc6))
+		dev_err(&spi->dev, "Failed to deinitialize oa tc6\n");
+	free_netdev(priv->netdev);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id lan865x_dt_ids[] = {
+	{ .compatible = "microchip,lan865x" },
+	{ /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, lan865x_dt_ids);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id lan865x_acpi_ids[] = {
+	{ .id = "LAN865X",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, lan865x_acpi_ids);
+#endif
+
+static struct spi_driver lan865x_driver = {
+	.driver = {
+		.name = DRV_NAME,
+#ifdef CONFIG_OF
+		.of_match_table = lan865x_dt_ids,
+#endif
+#ifdef CONFIG_ACPI
+		   .acpi_match_table = ACPI_PTR(lan865x_acpi_ids),
+#endif
+	 },
+	.probe = lan865x_probe,
+	.remove = lan865x_remove,
+};
+module_spi_driver(lan865x_driver);
+
+MODULE_DESCRIPTION(DRV_NAME " 10Base-T1S MACPHY Ethernet Driver");
+MODULE_AUTHOR("Parthiban Veerasooran <parthiban.veerasooran@microchip.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:" DRV_NAME);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 85+ messages in thread

* [RFC PATCH net-next 6/6] microchip: lan865x: add device-tree support for Microchip's LAN865X MACPHY
  2023-09-08 14:29 [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface Parthiban Veerasooran
                   ` (4 preceding siblings ...)
  2023-09-08 14:29 ` [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY Parthiban Veerasooran
@ 2023-09-08 14:29 ` Parthiban Veerasooran
  2023-09-10 10:55   ` Krzysztof Kozlowski
  2023-09-14  2:07   ` Andrew Lunn
  2023-09-10 10:55 ` [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface Krzysztof Kozlowski
  2023-09-15 13:56 ` Alexander Dahl
  7 siblings, 2 replies; 85+ messages in thread
From: Parthiban Veerasooran @ 2023-09-08 14:29 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	andrew
  Cc: netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	Parthiban Veerasooran

Add device-tree support for Microchip's LAN865X MACPHY for configuring
the OPEN Alliance 10BASE-T1x MACPHY Serial Interface parameters.

Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
 .../bindings/net/microchip,lan865x.yaml       | 54 +++++++++++++++++++
 MAINTAINERS                                   |  1 +
 2 files changed, 55 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/microchip,lan865x.yaml

diff --git a/Documentation/devicetree/bindings/net/microchip,lan865x.yaml b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
new file mode 100644
index 000000000000..3465b2c97690
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/microchip,lan865x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip LAN8650/1 10BASE-T1S MACPHY Ethernet Controllers
+
+maintainers:
+  - Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
+
+description: |
+  Device tree properties for LAN8650/1 10BASE-T1S MACPHY Ethernet
+  controller.
+
+allOf:
+  - $ref: ethernet-controller.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - microchip,lan865x
+  reg:
+    maxItems: 1
+
+  local-mac-address: true
+  oa-chunk-size: true
+  oa-tx-cut-through: true
+  oa-rx-cut-through: true
+  oa-protected: true
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ethernet@1{
+            compatible = "microchip,lan865x";
+            reg = <1>; /* CE0 */
+            local-mac-address = [04 05 06 01 02 03];
+            oa-chunk-size = <64>;
+            oa-tx-cut-through;
+            oa-rx-cut-through;
+            oa-protected;
+       };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 666c042a15b2..2bbb7f17d74e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13883,6 +13883,7 @@ MICROCHIP LAN8650/1 10BASE-T1S MACPHY ETHERNET DRIVER
 M:	Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
 L:	netdev@vger.kernel.org
 S:	Maintained
+F:	Documentation/devicetree/bindings/net/microchip,lan865x.yaml
 F:	drivers/net/ethernet/microchip/lan865x.c
 
 MICROCHIP LAN87xx/LAN937x T1 PHY DRIVER
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-08 14:29 ` [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface Parthiban Veerasooran
@ 2023-09-09 13:33   ` Andrew Lunn
  2023-09-12 13:03     ` Parthiban.Veerasooran
  2023-09-13  1:36   ` Andrew Lunn
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-09 13:33 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

On Fri, Sep 08, 2023 at 07:59:14PM +0530, Parthiban Veerasooran wrote:
> Implement register read/write interface according to the control
> communication specified in the OPEN Alliance 10BASE-T1x MACPHY Serial
> Interface document. Control transactions consist of one or more control
> commands. Control commands are used by the SPI host to read and write
> registers within the MAC-PHY. Each control commands are composed of a
> 32-bit control command header followed by register data.
> 
> Control write commands can write either a single register or multiple
> consecutive registers. When multiple consecutive registers are written,
> the address is automatically post-incremented by the MAC-PHY. The write
> command and data is also echoed from the MAC-PHY back to the SPI host to
> enable the SPI host to identify which register write failed in the case
> of any bus errors.
> 
> Control read commands can read either a single register or multiple
> consecutive registers. When multiple consecutive registers are read, the
> address is automatically post-incremented by the MAC-PHY.
> 
> The register data being read or written can be protected against simple
> bit errors. When enabled by setting the Protection Enable (PROTE) bit in
> the CONFIG0 register, protection is accomplished by duplication of each
> 32-bit word containing register data with its ones’ complement. Errors
> are detected at the receiver by performing a simple exclusive-OR (XOR) of
> each received 32-bit word containing register data with its received
> complement and detecting if there are any zeros in the result.
> 
> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
> ---
>  Documentation/networking/oa-tc6-framework.rst | 231 ++++++++++++++++++
>  MAINTAINERS                                   |   8 +
>  drivers/net/ethernet/oa_tc6.c                 | 222 +++++++++++++++++
>  include/linux/oa_tc6.h                        |  31 +++

I'm surprised there is no kconfig and Makefile changes here. I would
expect this is compiled as a module, which the vendor code can then
make use of. 

     Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-08 14:29 ` [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling Parthiban Veerasooran
@ 2023-09-09 13:39   ` Andrew Lunn
  2023-09-12 12:44     ` Parthiban.Veerasooran
  2023-09-11 12:51   ` Ziyang Xuan (William)
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-09 13:39 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> +	/* Register MAC-PHY interrupt service routine */
> +	ret = devm_request_irq(&spi->dev, spi->irq, macphy_irq, 0, "macphy int",
> +			       tc6);

It looks like using threaded interrupts could save a lot of
complexity. Let the IRQ core handle all the tasklet stuff for you.

	Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 6/6] microchip: lan865x: add device-tree support for Microchip's LAN865X MACPHY
  2023-09-08 14:29 ` [RFC PATCH net-next 6/6] microchip: lan865x: add device-tree " Parthiban Veerasooran
@ 2023-09-10 10:55   ` Krzysztof Kozlowski
  2023-09-12 12:15     ` Parthiban.Veerasooran
  2023-09-14  2:07   ` Andrew Lunn
  1 sibling, 1 reply; 85+ messages in thread
From: Krzysztof Kozlowski @ 2023-09-10 10:55 UTC (permalink / raw)
  To: Parthiban Veerasooran, davem, edumazet, kuba, pabeni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, steen.hegelund,
	rdunlap, horms, casper.casan, andrew
  Cc: netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

On 08/09/2023 16:29, Parthiban Veerasooran wrote:
> Add device-tree support for Microchip's LAN865X MACPHY for configuring
> the OPEN Alliance 10BASE-T1x MACPHY Serial Interface parameters.

Please use subject prefixes matching the subsystem. You can get them for
example with `git log --oneline -- DIRECTORY_OR_FILE` on the directory
your patch is touching.

> 
> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
> ---
>  .../bindings/net/microchip,lan865x.yaml       | 54 +++++++++++++++++++
>  MAINTAINERS                                   |  1 +
>  2 files changed, 55 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/net/microchip,lan865x.yaml
> 
> diff --git a/Documentation/devicetree/bindings/net/microchip,lan865x.yaml b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
> new file mode 100644
> index 000000000000..3465b2c97690
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
> @@ -0,0 +1,54 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/net/microchip,lan865x.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Microchip LAN8650/1 10BASE-T1S MACPHY Ethernet Controllers
> +
> +maintainers:
> +  - Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
> +
> +description: |
> +  Device tree properties for LAN8650/1 10BASE-T1S MACPHY Ethernet

Drop "Device tree properties for" and instead describe the hardware.

> +  controller.
> +
> +allOf:
> +  - $ref: ethernet-controller.yaml#
> +
> +properties:
> +  compatible:
> +    items:

No need for items. Just enum.


> +      - enum:
> +          - microchip,lan865x

No wildcards in compatibles.

Missing blank line.



> +  reg:
> +    maxItems: 1
> +
> +  local-mac-address: true
> +  oa-chunk-size: true
> +  oa-tx-cut-through: true
> +  oa-rx-cut-through: true
> +  oa-protected: true

What are all these? Where are they defined that you skip description,
type and vendor prefix?

> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    spi {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        ethernet@1{

Missing space

> +            compatible = "microchip,lan865x";
> +            reg = <1>; /* CE0 */

CE0? chip-select? What does this comment mean in this context?

> +            local-mac-address = [04 05 06 01 02 03];
> +            oa-chunk-size = <64>;
> +            oa-tx-cut-through;
> +            oa-rx-cut-through;
> +            oa-protected;



Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
  2023-09-08 14:29 [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface Parthiban Veerasooran
                   ` (5 preceding siblings ...)
  2023-09-08 14:29 ` [RFC PATCH net-next 6/6] microchip: lan865x: add device-tree " Parthiban Veerasooran
@ 2023-09-10 10:55 ` Krzysztof Kozlowski
  2023-09-13 13:26   ` Parthiban.Veerasooran
  2023-09-15 13:56 ` Alexander Dahl
  7 siblings, 1 reply; 85+ messages in thread
From: Krzysztof Kozlowski @ 2023-09-10 10:55 UTC (permalink / raw)
  To: Parthiban Veerasooran, davem, edumazet, kuba, pabeni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, steen.hegelund,
	rdunlap, horms, casper.casan, andrew
  Cc: netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

On 08/09/2023 16:29, Parthiban Veerasooran wrote:
> This patch series contain the below updates,
> - Adds support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface in the
>   net/ethernet/oa_tc6.c.
> - Adds driver support for Microchip LAN8650/1 Rev.B0 10BASE-T1S MACPHY
>   Ethernet driver in the net/ethernet/microchip/lan865x.c.

And why is this RFC? Do you mean by that it is buggy and not finished,
so we should not review?

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  2023-09-08 14:29 ` [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY Parthiban Veerasooran
@ 2023-09-10 17:44   ` Simon Horman
  2023-09-12 10:53     ` Parthiban.Veerasooran
  2023-09-11 13:17   ` Ziyang Xuan (William)
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 85+ messages in thread
From: Simon Horman @ 2023-09-10 17:44 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, casper.casan, andrew,
	netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

On Fri, Sep 08, 2023 at 07:59:18PM +0530, Parthiban Veerasooran wrote:
> The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE‑T1x
> MAC‑PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
> MAC integration provides the low pin count standard SPI interface to any
> microcontroller therefore providing Ethernet functionality without
> requiring MAC integration within the microcontroller. The LAN8650/1
> operates as an SPI client supporting SCLK clock rates up to a maximum of
> 25 MHz. This SPI interface supports the transfer of both data (Ethernet
> frames) and control (register access).
> 
> By default, the chunk data payload is 64 bytes in size. A smaller payload
> data size of 32 bytes is also supported and may be configured in the
> Chunk Payload Size (CPS) field of the Configuration 0 (OA_CONFIG0)
> register. Changing the chunk payload size requires the LAN8650/1 be reset
> and shall not be done during normal operation.
> 
> The Ethernet Media Access Controller (MAC) module implements a 10 Mbps
> half duplex Ethernet MAC, compatible with the IEEE 802.3 standard.
> 10BASE-T1S physical layer transceiver integrated into the LAN8650/1. The
> PHY and MAC are connected via an internal Media Independent Interface
> (MII).
> 
> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>

Hi Parthiban,

thanks for your patches.
Some minor feedback on this one follows.

...

> diff --git a/drivers/net/ethernet/microchip/lan865x.c b/drivers/net/ethernet/microchip/lan865x.c

...

> +static int lan865x_set_hw_macaddr(struct net_device *netdev)
> +{
> +	u32 regval;
> +	bool ret;
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +	const u8 *mac = netdev->dev_addr;

Please arrange local variables in Networking code in reverse xmas tree
order - longest line to shortest.

This tool can be of assistance here:
https://github.com/ecree-solarflare/xmastree

...

> +static int lan865x_probe(struct spi_device *spi)
> +{
> +	struct net_device *netdev;
> +	struct lan865x_priv *priv;
> +	u32 regval;
> +	int ret;
> +
> +	netdev = alloc_etherdev(sizeof(struct lan865x_priv));
> +	if (!netdev)
> +		return -ENOMEM;
> +
> +	priv = netdev_priv(netdev);
> +	priv->netdev = netdev;
> +	priv->spi = spi;
> +	priv->msg_enable = 0;
> +	spi_set_drvdata(spi, priv);
> +	SET_NETDEV_DEV(netdev, &spi->dev);
> +
> +	ret = lan865x_get_dt_data(priv);
> +	if (ret)
> +		return ret;
> +
> +	spi->rt = true;
> +	spi_setup(spi);
> +
> +	priv->tc6 = oa_tc6_init(spi, netdev);
> +	if (!priv->tc6) {
> +		ret = -ENOMEM;
> +		goto error_oa_tc6_init;
> +	}
> +
> +	if (priv->cps == 32) {
> +		regval = CCS_Q0_TX_CFG_32;
> +		ret = oa_tc6_write_register(priv->tc6, CCS_Q0_TX_CFG, &regval, 1);
> +		if (ret)
> +			return ret;
> +
> +		regval = CCS_Q0_RX_CFG_32;
> +		ret = oa_tc6_write_register(priv->tc6, CCS_Q0_RX_CFG, &regval, 1);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (oa_tc6_configure(priv->tc6, priv->cps, priv->protected, priv->txcte,
> +			     priv->rxcte))
> +		goto err_macphy_config;

Jumping to err_macphy_config will result in this function returning ret.
However, ret will be 0 at this point. Perhaps it should be set to an
error value.

Flagged by Smatch.

> +
> +	ret = lan865x_phy_init(priv);
> +	if (ret)
> +		goto error_phy;
> +
> +	if (device_get_ethdev_address(&spi->dev, netdev))
> +		eth_hw_addr_random(netdev);
> +
> +	ret = lan865x_set_hw_macaddr(netdev);
> +	if (ret) {
> +		if (netif_msg_probe(priv))
> +			dev_err(&spi->dev, "Failed to configure MAC");
> +		goto error_set_mac;
> +	}
> +
> +	netdev->if_port = IF_PORT_10BASET;
> +	netdev->irq = spi->irq;
> +	netdev->netdev_ops = &lan865x_netdev_ops;
> +	netdev->watchdog_timeo = TX_TIMEOUT;
> +	netdev->ethtool_ops = &lan865x_ethtool_ops;
> +	ret = register_netdev(netdev);
> +	if (ret) {
> +		if (netif_msg_probe(priv))
> +			dev_err(&spi->dev, "Register netdev failed (ret = %d)",
> +				ret);
> +		goto error_netdev_register;
> +	}
> +
> +	phy_start(priv->phydev);
> +	return 0;
> +
> +error_netdev_register:
> +error_set_mac:
> +	phy_disconnect(priv->phydev);
> +	mdiobus_unregister(priv->mdiobus);
> +	mdiobus_free(priv->mdiobus);
> +error_phy:
> +err_macphy_config:
> +	oa_tc6_deinit(priv->tc6);
> +error_oa_tc6_init:
> +	free_netdev(priv->netdev);
> +	return ret;
> +}


...

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface
  2023-09-08 14:29 ` [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface Parthiban Veerasooran
@ 2023-09-10 17:58   ` Simon Horman
  2023-09-12 13:47     ` Parthiban.Veerasooran
  2023-09-11 12:59   ` Ziyang Xuan (William)
  2023-09-14  1:18   ` Andrew Lunn
  2 siblings, 1 reply; 85+ messages in thread
From: Simon Horman @ 2023-09-10 17:58 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, casper.casan, andrew,
	netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

On Fri, Sep 08, 2023 at 07:59:17PM +0530, Parthiban Veerasooran wrote:
> The ethernet frame to be sent to MAC-PHY is converted into multiple
> transmit data chunks. A transmit data chunk consists of a 4-byte data
> header followed by the transmit data chunk payload.
> 
> The received ethernet frame from the network is converted into multiple
> receive data chunks by the MAC-PHY and a receive data chunk consists of
> the receive data chunk payload followed by a 4-byte data footer at the
> end.
> 
> The MAC-PHY shall support a default data chunk payload size of 64 bytes.
> Data chunk payload sizes of 32, 16, or 8 bytes may also be supported. The
> data chunk payload is always a multiple of 4 bytes.
> 
> The 4-byte data header occurs at the beginning of each transmit data
> chunk on MOSI and the 4-byte data footer occurs at the end of each
> receive data chunk on MISO. The data header and footer contain the
> information needed to determine the validity and location of the transmit
> and receive frame data within the data chunk payload. Ethernet frames
> shall be aligned to a 32-bit boundary within the data chunk payload.
> 
> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>

Hi Parthiban,

this patch seems to introduce new Sparse warnings.
Please consider addressing those, and ideally the warnings
flagged in the existing oa_tc6.c code.

Thanks in advance!

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-08 14:29 ` [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling Parthiban Veerasooran
  2023-09-09 13:39   ` Andrew Lunn
@ 2023-09-11 12:51   ` Ziyang Xuan (William)
  2023-09-12 12:10     ` Andrew Lunn
  2023-09-12 12:28     ` Parthiban.Veerasooran
  2023-09-13  2:39   ` Andrew Lunn
  2023-09-13  8:44   ` Lukasz Majewski
  3 siblings, 2 replies; 85+ messages in thread
From: Ziyang Xuan (William) @ 2023-09-11 12:51 UTC (permalink / raw)
  To: Parthiban Veerasooran, davem, edumazet, kuba, pabeni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, steen.hegelund,
	rdunlap, horms, casper.casan, andrew
  Cc: netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> Register MAC-PHY interrupt and handle reset complete interrupt. Reset
> complete bit is set when the MAC-PHY reset complete and ready for
> configuration. When it is set, it will generate a non-maskable interrupt
> to alert the SPI host. Additionally reset complete bit in the STS0
> register has to be written by one upon reset complete to clear the
> interrupt.
> 
> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
> ---
>  drivers/net/ethernet/oa_tc6.c | 141 ++++++++++++++++++++++++++++++++--
>  include/linux/oa_tc6.h        |  16 +++-
>  2 files changed, 150 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
> index 613cf034430a..0019f70345b6 100644
> --- a/drivers/net/ethernet/oa_tc6.c
> +++ b/drivers/net/ethernet/oa_tc6.c
> @@ -6,6 +6,7 @@
>   */
>  
>  #include <linux/bitfield.h>
> +#include <linux/interrupt.h>
>  #include <linux/oa_tc6.h>
>  
>  static int oa_tc6_spi_transfer(struct spi_device *spi, u8 *ptx, u8 *prx,
> @@ -160,10 +161,16 @@ int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
>  	if (ret)
>  		goto err_ctrl;
>  
> -	/* Check echoed/received control reply */
> -	ret = oa_tc6_check_control(tc6, tx_buf, rx_buf, len, wnr, ctrl_prot);
> -	if (ret)
> -		goto err_ctrl;
> +	/* In case of reset write, the echoed control command doesn't have any
> +	 * valid data. So no need to check for error.
> +	 */
> +	if (addr != OA_TC6_RESET) {
> +		/* Check echoed/received control reply */
> +		ret = oa_tc6_check_control(tc6, tx_buf, rx_buf, len, wnr,
> +					   ctrl_prot);
> +		if (ret)
> +			goto err_ctrl;
> +	}
>  
>  	if (!wnr) {
>  		/* Copy read data from the rx data in case of ctrl read */
> @@ -186,6 +193,88 @@ int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
>  	return ret;
>  }
>  
> +static int oa_tc6_handler(void *data)
> +{
> +	struct oa_tc6 *tc6 = data;
> +	u32 regval;
> +	int ret;
> +
> +	while (likely(!kthread_should_stop())) {
> +		wait_event_interruptible(tc6->tc6_wq, tc6->int_flag ||
> +					 kthread_should_stop());
> +		if (tc6->int_flag) {
> +			tc6->int_flag = false;
> +			ret = oa_tc6_perform_ctrl(tc6, OA_TC6_STS0, &regval, 1,
> +						  false, false);
> +			if (ret) {
> +				dev_err(&tc6->spi->dev, "Failed to read STS0\n");
> +				continue;
> +			}
> +			/* Check for reset complete interrupt status */
> +			if (regval & RESETC) {
> +				regval = RESETC;
> +				/* SPI host should write RESETC bit with one to
> +				 * clear the reset interrupt status.
> +				 */
> +				ret = oa_tc6_perform_ctrl(tc6, OA_TC6_STS0,
> +							  &regval, 1, true,
> +							  false);
> +				if (ret) {
> +					dev_err(&tc6->spi->dev,
> +						"Failed to write STS0\n");
> +					continue;
> +				}
> +				complete(&tc6->rst_complete);
> +			}
> +		}
> +	}
> +	return 0;
> +}
> +
> +static irqreturn_t macphy_irq(int irq, void *dev_id)
> +{
> +	struct oa_tc6 *tc6 = dev_id;
> +
> +	/* Wake tc6 task to perform interrupt action */
> +	tc6->int_flag = true;
> +	wake_up_interruptible(&tc6->tc6_wq);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int oa_tc6_sw_reset(struct oa_tc6 *tc6)
> +{
> +	long timeleft;
> +	u32 regval;
> +	int ret;
> +
> +	/* Perform software reset with both protected and unprotected control
> +	 * commands because the driver doesn't know the current status of the
> +	 * MAC-PHY.
> +	 */
> +	regval = SW_RESET;
> +	reinit_completion(&tc6->rst_complete);
> +	ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1, true, false);
> +	if (ret) {
> +		dev_err(&tc6->spi->dev, "RESET register write failed\n");
> +		return ret;
> +	}
> +
> +	ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1, true, true);
> +	if (ret) {
> +		dev_err(&tc6->spi->dev, "RESET register write failed\n");
> +		return ret;
> +	}
> +	timeleft = wait_for_completion_interruptible_timeout(&tc6->rst_complete,
> +							     msecs_to_jiffies(1));
> +	if (timeleft <= 0) {
> +		dev_err(&tc6->spi->dev, "MAC-PHY reset failed\n");
> +		return -ENODEV;
> +	}
> +
> +	return 0;
> +}
> +
>  int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len)
>  {
>  	return oa_tc6_perform_ctrl(tc6, addr, val, len, true, tc6->ctrl_prot);
> @@ -201,6 +290,7 @@ EXPORT_SYMBOL_GPL(oa_tc6_read_register);
>  struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
>  {
>  	struct oa_tc6 *tc6;
> +	int ret;
>  
>  	if (!spi)
>  		return NULL;
> @@ -211,12 +301,51 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
>  
>  	tc6->spi = spi;
>  
> +	/* Used for triggering the OA TC6 task */
> +	init_waitqueue_head(&tc6->tc6_wq);
> +
> +	init_completion(&tc6->rst_complete);
> +
> +	/* This task performs the SPI transfer */
> +	tc6->tc6_task = kthread_run(oa_tc6_handler, tc6, "OA TC6 Task");
> +	if (IS_ERR(tc6->tc6_task))
> +		goto err_tc6_task;
> +
> +	/* Set the highest priority to the tc6 task as it is time critical */
> +	sched_set_fifo(tc6->tc6_task);
> +
> +	/* Register MAC-PHY interrupt service routine */
> +	ret = devm_request_irq(&spi->dev, spi->irq, macphy_irq, 0, "macphy int",
> +			       tc6);
> +	if ((ret != -ENOTCONN) && ret < 0) {
> +		dev_err(&spi->dev, "Error attaching macphy irq %d\n", ret);
> +		goto err_macphy_irq;
> +	}
> +
> +	/* Perform MAC-PHY software reset */
> +	if (oa_tc6_sw_reset(tc6))
> +		goto err_macphy_reset;
> +
>  	return tc6;
> +
> +err_macphy_reset:
> +	devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
> +err_macphy_irq:
> +	kthread_stop(tc6->tc6_task);
> +err_tc6_task:
> +	kfree(tc6);
> +	return NULL;
>  }
>  EXPORT_SYMBOL_GPL(oa_tc6_init);
>  
> -void oa_tc6_deinit(struct oa_tc6 *tc6)
> +int oa_tc6_deinit(struct oa_tc6 *tc6)
>  {
> -	kfree(tc6);
> +	int ret;
> +
> +	devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
> +	ret = kthread_stop(tc6->tc6_task);

kthread_stop() will the result of threadfn(). Here mean that if threadfn()
return non-zero, deinit() will fail. But the KTHREAD_SHOULD_STOP already be set.
And oa_tc6_handler() will end. Please check it is what you want.

> +	if (!ret)
> +		kfree(tc6);
> +	return ret;
>  }
>  EXPORT_SYMBOL_GPL(oa_tc6_deinit);
> diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
> index 5e0a58ab1dcd..315f061c2dfe 100644
> --- a/include/linux/oa_tc6.h
> +++ b/include/linux/oa_tc6.h
> @@ -17,15 +17,29 @@
>  #define CTRL_HDR_LEN	GENMASK(7, 1)	/* Length */
>  #define CTRL_HDR_P	BIT(0)		/* Parity Bit */
>  
> +/* Open Alliance TC6 Standard Control and Status Registers */
> +#define OA_TC6_RESET	0x0003		/* Reset Control and Status Register */
> +#define OA_TC6_STS0	0x0008		/* Status Register #0 */
> +
> +/* RESET register field */
> +#define SW_RESET	BIT(0)		/* Software Reset */
> +
> +/* STATUS0 register field */
> +#define RESETC		BIT(6)		/* Reset Complete */
> +
>  #define TC6_HDR_SIZE	4		/* Ctrl command header size as per OA */
>  #define TC6_FTR_SIZE	4		/* Ctrl command footer size ss per OA */
>  
>  struct oa_tc6 {
>  	struct spi_device *spi;
>  	bool ctrl_prot;
> +	struct task_struct *tc6_task;
> +	wait_queue_head_t tc6_wq;
> +	bool int_flag;
> +	struct completion rst_complete;
>  };
>  
>  struct oa_tc6 *oa_tc6_init(struct spi_device *spi);
> -void oa_tc6_deinit(struct oa_tc6 *tc6);
> +int oa_tc6_deinit(struct oa_tc6 *tc6);
>  int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
>  int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
> 

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface
  2023-09-08 14:29 ` [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface Parthiban Veerasooran
  2023-09-10 17:58   ` Simon Horman
@ 2023-09-11 12:59   ` Ziyang Xuan (William)
  2023-09-12 10:32     ` Parthiban.Veerasooran
  2023-09-14  1:18   ` Andrew Lunn
  2 siblings, 1 reply; 85+ messages in thread
From: Ziyang Xuan (William) @ 2023-09-11 12:59 UTC (permalink / raw)
  To: Parthiban Veerasooran, davem, edumazet, kuba, pabeni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, steen.hegelund,
	rdunlap, horms, casper.casan, andrew
  Cc: netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> The ethernet frame to be sent to MAC-PHY is converted into multiple
> transmit data chunks. A transmit data chunk consists of a 4-byte data
> header followed by the transmit data chunk payload.
> 
> The received ethernet frame from the network is converted into multiple
> receive data chunks by the MAC-PHY and a receive data chunk consists of
> the receive data chunk payload followed by a 4-byte data footer at the
> end.
> 
> The MAC-PHY shall support a default data chunk payload size of 64 bytes.
> Data chunk payload sizes of 32, 16, or 8 bytes may also be supported. The
> data chunk payload is always a multiple of 4 bytes.
> 
> The 4-byte data header occurs at the beginning of each transmit data
> chunk on MOSI and the 4-byte data footer occurs at the end of each
> receive data chunk on MISO. The data header and footer contain the
> information needed to determine the validity and location of the transmit
> and receive frame data within the data chunk payload. Ethernet frames
> shall be aligned to a 32-bit boundary within the data chunk payload.
> 
> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
> ---
>  drivers/net/ethernet/oa_tc6.c | 425 +++++++++++++++++++++++++++++++++-
>  include/linux/oa_tc6.h        |  65 +++++-
>  2 files changed, 485 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
> index 65a7317f768d..20138b178185 100644
> --- a/drivers/net/ethernet/oa_tc6.c
> +++ b/drivers/net/ethernet/oa_tc6.c
> @@ -5,6 +5,7 @@
>   * Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
>   */
>  
> +#include <linux/etherdevice.h>
>  #include <linux/bitfield.h>
>  #include <linux/interrupt.h>
>  #include <linux/oa_tc6.h>
> @@ -193,17 +194,224 @@ int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
>  	return ret;
>  }
>  
> +static u16 oa_tc6_prepare_empty_chunk(struct oa_tc6 *tc6, u8 *buf, u8 cp_count)
> +{
> +	u32 hdr;
> +
> +	/* Prepare empty chunks used for getting interrupt information or if
> +	 * receive data available.
> +	 */
> +	for (u8 i = 0; i < cp_count; i++) {
> +		hdr = FIELD_PREP(DATA_HDR_DNC, 1);
> +		hdr |= FIELD_PREP(DATA_HDR_P, oa_tc6_get_parity(hdr));
> +		hdr = cpu_to_be32(hdr);
> +		*(u32 *)&buf[i * (tc6->cps + TC6_HDR_SIZE)] = hdr;
> +		memset(&buf[TC6_HDR_SIZE + (i * (tc6->cps + TC6_HDR_SIZE))], 0,
> +		       tc6->cps);
> +	}
> +
> +	return cp_count * (tc6->cps + TC6_HDR_SIZE);
> +}
> +
> +static void oa_tc6_rx_eth_ready(struct oa_tc6 *tc6)
> +{
> +	struct sk_buff *skb = NULL;
Unnecessary initialization for skb.

> +
> +	/* Send the received ethernet packet to network layer */
> +	skb = netdev_alloc_skb(tc6->netdev, tc6->rxd_bytes + NET_IP_ALIGN);
> +	if (!skb) {
> +		tc6->netdev->stats.rx_dropped++;
> +		netdev_err(tc6->netdev, "Out of memory for rx'd frame");
> +	} else {
> +		skb_reserve(skb, NET_IP_ALIGN);
> +		memcpy(skb_put(skb, tc6->rxd_bytes), &tc6->eth_rx_buf[0],
> +		       tc6->rxd_bytes);
> +		skb->protocol = eth_type_trans(skb, tc6->netdev);
> +		tc6->netdev->stats.rx_packets++;
> +		tc6->netdev->stats.rx_bytes += tc6->rxd_bytes;
> +		netif_rx(skb);
netif_rx() may fail, I think it is good to add check and statistics.

> +	}
> +}
> +
> +static int oa_tc6_process_exst(struct oa_tc6 *tc6)
> +{
> +	u32 regval;
> +	int ret;
> +
> +	ret = oa_tc6_read_register(tc6, OA_TC6_STS0, &regval, 1);
> +	if (ret) {
> +		netdev_err(tc6->netdev, "STS0 register read failed.\n");
> +		return ret;
> +	}
> +	if (regval & TXPE)
> +		netdev_err(tc6->netdev, "Transmit protocol error\n");
> +	if (regval & TXBOE)
> +		netdev_err(tc6->netdev, "Transmit buffer overflow\n");
> +	if (regval & TXBUE)
> +		netdev_err(tc6->netdev, "Transmit buffer underflow\n");
> +	if (regval & RXBOE)
> +		netdev_err(tc6->netdev, "Receive buffer overflow\n");
> +	if (regval & LOFE)
> +		netdev_err(tc6->netdev, "Loss of frame\n");
> +	if (regval & HDRE)
> +		netdev_err(tc6->netdev, "Header error\n");
> +	if (regval & TXFCSE)
> +		netdev_err(tc6->netdev, "Transmit Frame Check Sequence Error\n");
> +	ret = oa_tc6_write_register(tc6, OA_TC6_STS0, &regval, 1);
> +	if (ret)
> +		netdev_err(tc6->netdev, "STS0 register write failed.\n");
> +	return ret;
> +}
> +
> +static int oa_tc6_process_rx_chunks(struct oa_tc6 *tc6, u8 *buf, u16 len)
> +{
> +	u8 cp_count;
> +	u8 *payload;
> +	u32 ftr;
> +	u16 ebo;
> +	u16 sbo;
> +
> +	/* Calculate the number of chunks received */
> +	cp_count = len / (tc6->cps + TC6_FTR_SIZE);
> +
> +	for (u8 i = 0; i < cp_count; i++) {
> +		/* Get the footer and payload */
> +		ftr = *(u32 *)&buf[tc6->cps + (i * (tc6->cps + TC6_FTR_SIZE))];
> +		ftr = be32_to_cpu(ftr);
> +		payload = &buf[(i * (tc6->cps + TC6_FTR_SIZE))];
> +		/* Check for footer parity error */
> +		if (oa_tc6_get_parity(ftr)) {
> +			netdev_err(tc6->netdev, "Footer: Parity error\n");
> +			goto err_exit;
> +		}
> +		/* If EXST set in the footer then read STS0 register to get the
> +		 * status information.
> +		 */
> +		if (FIELD_GET(DATA_FTR_EXST, ftr)) {
> +			if (oa_tc6_process_exst(tc6))
> +				netdev_err(tc6->netdev, "Failed to process EXST\n");
> +			goto err_exit;
> +		}
> +		if (FIELD_GET(DATA_FTR_HDRB, ftr)) {
> +			netdev_err(tc6->netdev, "Footer: Received header bad\n");
> +			goto err_exit;
> +		}
> +		if (!FIELD_GET(DATA_FTR_SYNC, ftr)) {
> +			netdev_err(tc6->netdev, "Footer: Configuration unsync\n");
> +			goto err_exit;
> +		}
> +		/* If Frame Drop is set, indicates that the MAC has detected a
> +		 * condition for which the SPI host should drop the received
> +		 * ethernet frame.
> +		 */
> +		if (FIELD_GET(DATA_FTR_FD, ftr) && FIELD_GET(DATA_FTR_EV, ftr)) {
> +			netdev_warn(tc6->netdev, "Footer: Frame drop\n");
> +			if (FIELD_GET(DATA_FTR_SV, ftr)) {
> +				goto start_new_frame;
> +			} else {
> +				if (tc6->rx_eth_started) {
> +					tc6->rxd_bytes = 0;
> +					tc6->rx_eth_started = false;
> +					tc6->netdev->stats.rx_dropped++;
> +				}
> +				continue;
> +			}
> +		}
> +		/* Check for data valid */
> +		if (FIELD_GET(DATA_FTR_DV, ftr)) {
> +			/* Check whether both start valid and end valid are in a
> +			 * single chunk payload means a single chunk payload may
> +			 * contain an entire ethernet frame.
> +			 */
> +			if (FIELD_GET(DATA_FTR_SV, ftr) &&
> +			    FIELD_GET(DATA_FTR_EV, ftr)) {
> +				sbo = FIELD_GET(DATA_FTR_SWO, ftr) * 4;
> +				ebo = FIELD_GET(DATA_FTR_EBO, ftr) + 1;
> +				if (ebo <= sbo) {
> +					memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
> +					       &payload[0], ebo);
> +					tc6->rxd_bytes += ebo;
> +					oa_tc6_rx_eth_ready(tc6);
> +					tc6->rxd_bytes = 0;
> +					memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
> +					       &payload[sbo], tc6->cps - sbo);
> +					tc6->rxd_bytes += (tc6->cps - sbo);
> +					goto exit;
> +				} else {
> +					memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
> +					       &payload[sbo], ebo - sbo);
> +					tc6->rxd_bytes += (ebo - sbo);
> +					oa_tc6_rx_eth_ready(tc6);
> +					tc6->rxd_bytes = 0;
> +					goto exit;
> +				}
> +			}
> +start_new_frame:
> +			/* Check for start valid to start capturing the incoming
> +			 * ethernet frame.
> +			 */
> +			if (FIELD_GET(DATA_FTR_SV, ftr) && !tc6->rx_eth_started) {
> +				tc6->rxd_bytes = 0;
> +				tc6->rx_eth_started = true;
> +				sbo = FIELD_GET(DATA_FTR_SWO, ftr) * 4;
> +				memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
> +				       &payload[sbo], tc6->cps - sbo);
> +				tc6->rxd_bytes += (tc6->cps - sbo);
> +				goto exit;
> +			}
> +
> +			/* Check for end valid and calculate the copy length */
> +			if (tc6->rx_eth_started) {
> +				if (FIELD_GET(DATA_FTR_EV, ftr))
> +					ebo = FIELD_GET(DATA_FTR_EBO, ftr) + 1;
> +				else
> +					ebo = tc6->cps;
> +
> +				memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
> +				       &payload[0], ebo);
> +				tc6->rxd_bytes += ebo;
> +				if (FIELD_GET(DATA_FTR_EV, ftr)) {
> +					/* If End Valid set then send the
> +					 * received ethernet frame to n/w.
> +					 */
> +					oa_tc6_rx_eth_ready(tc6);
> +					tc6->rxd_bytes = 0;
> +					tc6->rx_eth_started = false;
> +				}
> +			}
> +		}
> +
> +exit:
> +		tc6->txc = FIELD_GET(DATA_FTR_TXC, ftr);
> +		tc6->rca = FIELD_GET(DATA_FTR_RCA, ftr);
> +	}
> +	return FTR_OK;
> +
> +err_exit:
> +	if (tc6->rx_eth_started) {
> +		tc6->rxd_bytes = 0;
> +		tc6->rx_eth_started = false;
> +		tc6->netdev->stats.rx_dropped++;
> +	}
> +	return FTR_ERR;
> +}
> +
>  static int oa_tc6_handler(void *data)
>  {
>  	struct oa_tc6 *tc6 = data;
> +	bool txc_wait = false;
> +	u16 tx_pos = 0;
>  	u32 regval;
> +	u16 len;
>  	int ret;
>  
>  	while (likely(!kthread_should_stop())) {
> -		wait_event_interruptible(tc6->tc6_wq, tc6->int_flag ||
> +		wait_event_interruptible(tc6->tc6_wq, tc6->tx_flag ||
> +					 tc6->int_flag || tc6->rca ||
>  					 kthread_should_stop());
> -		if (tc6->int_flag) {
> +		if (tc6->int_flag && !tc6->reset) {
>  			tc6->int_flag = false;
> +			tc6->reset = true;
>  			ret = oa_tc6_perform_ctrl(tc6, OA_TC6_STS0, &regval, 1,
>  						  false, false);
>  			if (ret) {
> @@ -227,10 +435,170 @@ static int oa_tc6_handler(void *data)
>  				complete(&tc6->rst_complete);
>  			}
>  		}
> +
> +		if (tc6->int_flag || tc6->rca) {
> +			/* If rca is updated from the previous footer then
> +			 * prepare the empty chunks equal to rca and perform
> +			 * SPI transfer to receive the ethernet frame.
> +			 */
> +			if (tc6->rca) {
> +				len = oa_tc6_prepare_empty_chunk(tc6,
> +								 tc6->spi_tx_buf,
> +								 tc6->rca);
> +			} else {
> +				/* If there is an interrupt then perform a SPI
> +				 * transfer with a empty chunk to get the
> +				 * details.
> +				 */
> +				tc6->int_flag = false;
> +				len = oa_tc6_prepare_empty_chunk(tc6,
> +								 tc6->spi_tx_buf,
> +								 1);
> +			}
> +			/* Perform SPI transfer */
> +			ret = oa_tc6_spi_transfer(tc6->spi, tc6->spi_tx_buf,
> +						  tc6->spi_rx_buf, len);
> +			if (ret) {
> +				netdev_err(tc6->netdev, "SPI transfer failed\n");
> +				continue;
> +			}
> +			/* Process the received chunks to get the ethernet frame
> +			 * or interrupt details.
> +			 */
> +			if (oa_tc6_process_rx_chunks(tc6, tc6->spi_rx_buf, len))
> +				continue;
> +		}
> +
> +		/* If there is a tx ethernet frame available */
> +		if (tc6->tx_flag || txc_wait) {
> +			tc6->tx_flag = false;
> +			txc_wait = false;
> +			len = 0;
> +			if (!tc6->txc) {
> +				/* If there is no txc available to transport the
> +				 * tx ethernet frames then wait for the MAC-PHY
> +				 * interrupt to get the txc availability.
> +				 */
> +				txc_wait = true;
> +				continue;
> +			} else if (tc6->txc >= tc6->txc_needed) {
> +				len = tc6->txc_needed * (tc6->cps + TC6_HDR_SIZE);
> +			} else {
> +				len = tc6->txc * (tc6->cps + TC6_HDR_SIZE);
> +			}
> +			memcpy(&tc6->spi_tx_buf[0], &tc6->eth_tx_buf[tx_pos],
> +			       len);
> +			ret = oa_tc6_spi_transfer(tc6->spi, tc6->spi_tx_buf,
> +						  tc6->spi_rx_buf, len);
> +			if (ret) {
> +				netdev_err(tc6->netdev, "SPI transfer failed\n");
> +				continue;
> +			}
> +			/* Process the received chunks to get the ethernet frame
> +			 * or status.
> +			 */
> +			if (oa_tc6_process_rx_chunks(tc6, tc6->spi_rx_buf,
> +						     len)) {
> +				/* In case of error while processing rx chunks
> +				 * discard the incomplete tx ethernet frame and
> +				 * resend it.
> +				 */
> +				tx_pos = 0;
> +				tc6->txc_needed = tc6->total_txc_needed;
> +			} else {
> +				tx_pos += len;
> +				tc6->txc_needed = tc6->txc_needed -
> +						  (len / (tc6->cps + TC6_HDR_SIZE));
> +				/* If the complete ethernet frame is transmitted
> +				 * then return the skb and update the details to
> +				 * n/w layer.
> +				 */
> +				if (!tc6->txc_needed) {
> +					tc6->netdev->stats.tx_packets++;
> +					tc6->netdev->stats.tx_bytes += tc6->tx_skb->len;
> +					dev_kfree_skb(tc6->tx_skb);
> +					tx_pos = 0;
> +					tc6->tx_skb = NULL;
> +					if (netif_queue_stopped(tc6->netdev))
> +						netif_wake_queue(tc6->netdev);
> +				} else if (tc6->txc) {
> +					/* If txc is available again and updated
> +					 * from the previous footer then perform
> +					 * tx again.
> +					 */
> +					tc6->tx_flag = true;
> +				} else {
> +					/* If there is no txc then wait for the
> +					 * interrupt to indicate txc
> +					 * availability.
> +					 */
> +					txc_wait = true;
> +				}
> +			}
> +		}
>  	}
>  	return 0;
>  }
>  
> +static void oa_tc6_prepare_tx_chunks(struct oa_tc6 *tc6, u8 *buf,
> +				     struct sk_buff *skb)
> +{
> +	bool frame_started = false;
> +	u16 copied_bytes = 0;
> +	u16 copy_len;
> +	u32 hdr;
> +
> +	/* Calculate the number tx credit counts needed to transport the tx
> +	 * ethernet frame.
> +	 */
> +	tc6->txc_needed = (skb->len / tc6->cps) + ((skb->len % tc6->cps) ? 1 : 0);
> +	tc6->total_txc_needed = tc6->txc_needed;
> +
> +	for (u8 i = 0; i < tc6->txc_needed; i++) {
> +		/* Prepare the header for each chunks to be transmitted */
> +		hdr = FIELD_PREP(DATA_HDR_DNC, 1) |
> +		      FIELD_PREP(DATA_HDR_DV, 1);
> +		if (!frame_started) {
> +			hdr |= FIELD_PREP(DATA_HDR_SV, 1) |
> +			       FIELD_PREP(DATA_HDR_SWO, 0);
> +			frame_started = true;
> +		}
> +		if ((tc6->cps + copied_bytes) >= skb->len) {
> +			copy_len = skb->len - copied_bytes;
> +			hdr |= FIELD_PREP(DATA_HDR_EBO, copy_len - 1) |
> +			       FIELD_PREP(DATA_HDR_EV, 1);
> +		} else {
> +			copy_len = tc6->cps;
> +		}
> +		copied_bytes += copy_len;
> +		hdr |= FIELD_PREP(DATA_HDR_P, oa_tc6_get_parity(hdr));
> +		hdr = cpu_to_be32(hdr);
> +		*(u32 *)&buf[i * (tc6->cps + TC6_HDR_SIZE)] = hdr;
> +		/* Copy the ethernet frame in the chunk payload section */
> +		memcpy(&buf[TC6_HDR_SIZE + (i * (tc6->cps + TC6_HDR_SIZE))],
> +		       &skb->data[copied_bytes - copy_len], copy_len);
> +	}
> +}
> +
> +netdev_tx_t oa_tc6_send_eth_pkt(struct oa_tc6 *tc6, struct sk_buff *skb)
> +{
> +	if (tc6->tx_skb) {
> +		netif_stop_queue(tc6->netdev);
> +		return NETDEV_TX_BUSY;
> +	}
> +
> +	tc6->tx_skb = skb;
> +	/* Prepare tx chunks using the tx ethernet frame */
> +	oa_tc6_prepare_tx_chunks(tc6, tc6->eth_tx_buf, skb);
> +
> +	/* Wake tc6 task to perform tx transfer */
> +	tc6->tx_flag = true;
> +	wake_up_interruptible(&tc6->tc6_wq);
> +
> +	return NETDEV_TX_OK;
> +}
> +EXPORT_SYMBOL_GPL(oa_tc6_send_eth_pkt);
> +
>  static irqreturn_t macphy_irq(int irq, void *dev_id)
>  {
>  	struct oa_tc6 *tc6 = dev_id;
> @@ -293,6 +661,14 @@ int oa_tc6_configure(struct oa_tc6 *tc6, u8 cps, bool ctrl_prot, bool tx_cut_thr
>  	u32 regval;
>  	int ret;
>  
> +	/* Read BUFSTS register to get the current txc and rca. */
> +	ret = oa_tc6_read_register(tc6, OA_TC6_BUFSTS, &regval, 1);
> +	if (ret)
> +		return ret;
> +
> +	tc6->txc = FIELD_GET(TXC, regval);
> +	tc6->rca = FIELD_GET(RCA, regval);
> +
>  	/* Read and configure the IMASK0 register for unmasking the interrupts */
>  	ret = oa_tc6_read_register(tc6, OA_TC6_IMASK0, &regval, 1);
>  	if (ret)
> @@ -326,7 +702,7 @@ int oa_tc6_configure(struct oa_tc6 *tc6, u8 cps, bool ctrl_prot, bool tx_cut_thr
>  }
>  EXPORT_SYMBOL_GPL(oa_tc6_configure);
>  
> -struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
> +struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev)
>  {
>  	struct oa_tc6 *tc6;
>  	int ret;
> @@ -334,11 +710,39 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
>  	if (!spi)
>  		return NULL;
>  
> +	if (!netdev)
> +		return NULL;
> +
>  	tc6 = kzalloc(sizeof(*tc6), GFP_KERNEL);
>  	if (!tc6)
>  		return NULL;
>  
>  	tc6->spi = spi;
> +	tc6->netdev = netdev;
> +
> +	/* Allocate memory for the tx buffer used for SPI transfer. */
> +	tc6->spi_tx_buf = kzalloc(MAX_ETH_LEN + (OA_TC6_MAX_CPS * TC6_HDR_SIZE),
> +				  GFP_KERNEL);
> +	if (!tc6->spi_tx_buf)
> +		goto err_spi_tx_buf_alloc;
> +
> +	/* Allocate memory for the rx buffer used for SPI transfer. */
> +	tc6->spi_rx_buf = kzalloc(MAX_ETH_LEN + (OA_TC6_MAX_CPS * TC6_FTR_SIZE),
> +				  GFP_KERNEL);
> +	if (!tc6->spi_rx_buf)
> +		goto err_spi_rx_buf_alloc;
> +
> +	/* Allocate memory for the tx ethernet chunks to transfer on SPI. */
> +	tc6->eth_tx_buf = kzalloc(MAX_ETH_LEN + (OA_TC6_MAX_CPS * TC6_HDR_SIZE),
> +				  GFP_KERNEL);
> +	if (!tc6->eth_tx_buf)
> +		goto err_eth_tx_buf_alloc;
> +
> +	/* Allocate memory for the rx ethernet packet. */
> +	tc6->eth_rx_buf = kzalloc(MAX_ETH_LEN + (OA_TC6_MAX_CPS * TC6_FTR_SIZE),
> +				  GFP_KERNEL);
> +	if (!tc6->eth_rx_buf)
> +		goto err_eth_rx_buf_alloc;
>  
>  	/* Used for triggering the OA TC6 task */
>  	init_waitqueue_head(&tc6->tc6_wq);
> @@ -372,6 +776,14 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
>  err_macphy_irq:
>  	kthread_stop(tc6->tc6_task);
>  err_tc6_task:
> +	kfree(tc6->eth_rx_buf);
> +err_eth_rx_buf_alloc:
> +	kfree(tc6->eth_tx_buf);
> +err_eth_tx_buf_alloc:
> +	kfree(tc6->spi_rx_buf);
> +err_spi_rx_buf_alloc:
> +	kfree(tc6->spi_tx_buf);
> +err_spi_tx_buf_alloc:
>  	kfree(tc6);
>  	return NULL;
>  }
> @@ -383,8 +795,13 @@ int oa_tc6_deinit(struct oa_tc6 *tc6)
>  
>  	devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
>  	ret = kthread_stop(tc6->tc6_task);
> -	if (!ret)
> +	if (!ret) {
> +		kfree(tc6->eth_rx_buf);
> +		kfree(tc6->eth_tx_buf);
> +		kfree(tc6->spi_rx_buf);
> +		kfree(tc6->spi_tx_buf);
>  		kfree(tc6);
> +	}
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(oa_tc6_deinit);
> diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
> index fa29c4e09720..61ac1cdfa7d6 100644
> --- a/include/linux/oa_tc6.h
> +++ b/include/linux/oa_tc6.h
> @@ -6,6 +6,7 @@
>   */
>  
>  #include <linux/spi/spi.h>
> +#include <linux/netdevice.h>
>  
>  /* Control header */
>  #define CTRL_HDR_DNC	BIT(31)		/* Data-Not-Control */
> @@ -17,10 +18,36 @@
>  #define CTRL_HDR_LEN	GENMASK(7, 1)	/* Length */
>  #define CTRL_HDR_P	BIT(0)		/* Parity Bit */
>  
> +/* Data header */
> +#define DATA_HDR_DNC	BIT(31)		/* Data-Not-Control */
> +#define DATA_HDR_SEQ	BIT(30)		/* Data Chunk Sequence */
> +#define DATA_HDR_NORX	BIT(29)		/* No Receive */
> +#define DATA_HDR_DV	BIT(21)		/* Data Valid */
> +#define DATA_HDR_SV	BIT(20)		/* Start Valid */
> +#define DATA_HDR_SWO	GENMASK(19, 16)	/* Start Word Offset */
> +#define DATA_HDR_EV	BIT(14)		/* End Valid */
> +#define DATA_HDR_EBO	GENMASK(13, 8)	/* End Byte Offset */
> +#define DATA_HDR_P	BIT(0)		/* Header Parity Bit */
> +
> +/* Data footer */
> +#define DATA_FTR_EXST	BIT(31)		/* Extended Status */
> +#define DATA_FTR_HDRB	BIT(30)		/* Received Header Bad */
> +#define DATA_FTR_SYNC	BIT(29)		/* Configuration Synchronized */
> +#define DATA_FTR_RCA	GENMASK(28, 24)	/* Receive Chunks Available */
> +#define DATA_FTR_DV	BIT(21)		/* Data Valid */
> +#define DATA_FTR_SV	BIT(20)		/* Start Valid */
> +#define DATA_FTR_SWO	GENMASK(19, 16)	/* Start Word Offset */
> +#define DATA_FTR_FD	BIT(15)		/* Frame Drop */
> +#define DATA_FTR_EV	BIT(14)		/* End Valid */
> +#define DATA_FTR_EBO	GENMASK(13, 8)	/* End Byte Offset */
> +#define DATA_FTR_TXC	GENMASK(5, 1)	/* Transmit Credits */
> +#define DATA_FTR_P	BIT(0)		/* Footer Parity Bit */
> +
>  /* Open Alliance TC6 Standard Control and Status Registers */
>  #define OA_TC6_RESET	0x0003		/* Reset Control and Status Register */
>  #define OA_TC6_CONFIG0	0x0004		/* Configuration Register #0 */
>  #define OA_TC6_STS0	0x0008		/* Status Register #0 */
> +#define OA_TC6_BUFSTS	0x000B          /* Buffer Status Register */
>  #define OA_TC6_IMASK0	0x000C		/* Interrupt Mask Register #0 */
>  
>  /* RESET register field */
> @@ -33,6 +60,17 @@
>  #define PROTE		BIT(5)		/* Ctrl read/write Protection Enable */
>  #define CPS		GENMASK(2, 0)	/* Chunk Payload Size */
>  
> +/* STATUS0 register fields */
> +#define CDPE		BIT(12)		/* Control Data Protection Error */
> +#define TXFCSE		BIT(11)		/* Transmit Frame Check Sequence Error */
> +#define RESETC		BIT(6)		/* Reset Complete */
> +#define HDRE		BIT(5)		/* Header Error */
> +#define LOFE		BIT(4)		/* Loss of Framing Error */
> +#define RXBOE		BIT(3)		/* Receive Buffer Overflow Error */
> +#define TXBUE		BIT(2)		/* Transmit Buffer Underflow Error */
> +#define TXBOE		BIT(1)		/* Transmit Buffer Overflow Error */
> +#define TXPE		BIT(0)		/* Transmit Protocol Error */
> +
>  /* Unmasking interrupt fields in IMASK0 */
>  #define HDREM		~BIT(5)		/* Header Error Mask */
>  #define LOFEM		~BIT(4)		/* Loss of Framing Error Mask */
> @@ -44,24 +82,49 @@
>  /* STATUS0 register field */
>  #define RESETC		BIT(6)		/* Reset Complete */
>  
> +/* BUFSTS register fields */
> +#define TXC		GENMASK(15, 8)	/* Transmit Credits Available */
> +#define RCA		GENMASK(7, 0)	/* Receive Chunks Available */
> +
>  #define TC6_HDR_SIZE	4		/* Ctrl command header size as per OA */
>  #define TC6_FTR_SIZE	4		/* Ctrl command footer size ss per OA */
>  
> +#define FTR_OK		0
> +#define FTR_ERR		1
> +
> +#define MAX_ETH_LEN	1536
> +#define OA_TC6_MAX_CPS	64
> +
>  struct oa_tc6 {
>  	struct completion rst_complete;
>  	struct task_struct *tc6_task;
> +	struct net_device *netdev;
>  	wait_queue_head_t tc6_wq;
>  	struct spi_device *spi;
> +	struct sk_buff *tx_skb;
> +	u8 total_txc_needed;
> +	bool rx_eth_started;
>  	bool tx_cut_thr;
>  	bool rx_cut_thr;
>  	bool ctrl_prot;
> +	u8 *spi_tx_buf;
> +	u8 *spi_rx_buf;
> +	u8 *eth_tx_buf;
> +	u8 *eth_rx_buf;
>  	bool int_flag;
> +	u16 rxd_bytes;
> +	u8 txc_needed;
> +	bool tx_flag;
> +	bool reset;
>  	u8 cps;
> +	u8 txc;
> +	u8 rca;
>  };
>  
> -struct oa_tc6 *oa_tc6_init(struct spi_device *spi);
> +struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev);
>  int oa_tc6_deinit(struct oa_tc6 *tc6);
>  int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
>  int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
>  int oa_tc6_configure(struct oa_tc6 *tc6, u8 cps, bool ctrl_prot, bool tx_cut_thr,
>  		     bool rx_cut_thr);
> +netdev_tx_t oa_tc6_send_eth_pkt(struct oa_tc6 *tc6, struct sk_buff *skb);
> 

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  2023-09-08 14:29 ` [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY Parthiban Veerasooran
  2023-09-10 17:44   ` Simon Horman
@ 2023-09-11 13:17   ` Ziyang Xuan (William)
  2023-09-12 11:41     ` Parthiban.Veerasooran
  2023-09-14  1:51   ` Andrew Lunn
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 85+ messages in thread
From: Ziyang Xuan (William) @ 2023-09-11 13:17 UTC (permalink / raw)
  To: Parthiban Veerasooran, davem, edumazet, kuba, pabeni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, steen.hegelund,
	rdunlap, horms, casper.casan, andrew
  Cc: netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE‑T1x
> MAC‑PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
> MAC integration provides the low pin count standard SPI interface to any
> microcontroller therefore providing Ethernet functionality without
> requiring MAC integration within the microcontroller. The LAN8650/1
> operates as an SPI client supporting SCLK clock rates up to a maximum of
> 25 MHz. This SPI interface supports the transfer of both data (Ethernet
> frames) and control (register access).
> 
> By default, the chunk data payload is 64 bytes in size. A smaller payload
> data size of 32 bytes is also supported and may be configured in the
> Chunk Payload Size (CPS) field of the Configuration 0 (OA_CONFIG0)
> register. Changing the chunk payload size requires the LAN8650/1 be reset
> and shall not be done during normal operation.
> 
> The Ethernet Media Access Controller (MAC) module implements a 10 Mbps
> half duplex Ethernet MAC, compatible with the IEEE 802.3 standard.
> 10BASE-T1S physical layer transceiver integrated into the LAN8650/1. The
> PHY and MAC are connected via an internal Media Independent Interface
> (MII).
> 
> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
> ---
>  MAINTAINERS                              |   6 +
>  drivers/net/ethernet/microchip/Kconfig   |  10 +
>  drivers/net/ethernet/microchip/Makefile  |   3 +
>  drivers/net/ethernet/microchip/lan865x.c | 589 +++++++++++++++++++++++
>  4 files changed, 608 insertions(+)
>  create mode 100644 drivers/net/ethernet/microchip/lan865x.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index c54454c7e7a1..666c042a15b2 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -13879,6 +13879,12 @@ L:	netdev@vger.kernel.org
>  S:	Maintained
>  F:	drivers/net/ethernet/microchip/lan743x_*
>  
> +MICROCHIP LAN8650/1 10BASE-T1S MACPHY ETHERNET DRIVER
> +M:	Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
> +L:	netdev@vger.kernel.org
> +S:	Maintained
> +F:	drivers/net/ethernet/microchip/lan865x.c
> +
>  MICROCHIP LAN87xx/LAN937x T1 PHY DRIVER
>  M:	Arun Ramadoss <arun.ramadoss@microchip.com>
>  R:	UNGLinuxDriver@microchip.com
> diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
> index 329e374b9539..d99be51b99f1 100644
> --- a/drivers/net/ethernet/microchip/Kconfig
> +++ b/drivers/net/ethernet/microchip/Kconfig
> @@ -59,4 +59,14 @@ source "drivers/net/ethernet/microchip/lan966x/Kconfig"
>  source "drivers/net/ethernet/microchip/sparx5/Kconfig"
>  source "drivers/net/ethernet/microchip/vcap/Kconfig"
>  
> +config LAN865X
> +	tristate "LAN865x support"
> +	depends on SPI
> +	help
> +      	  Support for the Microchip LAN8650/1 Rev.B0 Ethernet chip. It uses OPEN
> +	  Alliance 10BASE-T1x Serial Interface specification.
> +
> +      	  To compile this driver as a module, choose M here. The module will be
> +          called lan865x.
> +
>  endif # NET_VENDOR_MICROCHIP
> diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile
> index bbd349264e6f..315e850b2b26 100644
> --- a/drivers/net/ethernet/microchip/Makefile
> +++ b/drivers/net/ethernet/microchip/Makefile
> @@ -12,3 +12,6 @@ lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o
>  obj-$(CONFIG_LAN966X_SWITCH) += lan966x/
>  obj-$(CONFIG_SPARX5_SWITCH) += sparx5/
>  obj-$(CONFIG_VCAP) += vcap/
> +
> +obj-$(CONFIG_LAN865X) += lan865x_t1s.o
> +lan865x_t1s-objs := lan865x.o ../oa_tc6.o
> diff --git a/drivers/net/ethernet/microchip/lan865x.c b/drivers/net/ethernet/microchip/lan865x.c
> new file mode 100644
> index 000000000000..3c8ebf4c258f
> --- /dev/null
> +++ b/drivers/net/ethernet/microchip/lan865x.c
> @@ -0,0 +1,589 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Microchip's LAN865x 10BASE-T1S MAC-PHY driver
> + *
> + * Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/etherdevice.h>
> +#include <linux/mdio.h>
> +#include <linux/phy.h>
> +#include <linux/of.h>
> +#include <linux/oa_tc6.h>
> +
> +#define DRV_NAME		"lan865x"
> +#define DRV_VERSION		"0.1"
> +
> +#define REG_STDR_RESET		0x00000003
> +#define REG_MAC_ADDR_BO		0x00010022
> +#define REG_MAC_ADDR_L		0x00010024
> +#define REG_MAC_ADDR_H		0x00010025
> +#define REG_MAC_NW_CTRL         0x00010000
> +#define REG_MAC_NW_CONFIG	0x00010001
> +#define REG_MAC_HASHL		0x00010020
> +#define REG_MAC_HASHH		0x00010021
> +#define REG_MAC_ADDR_BO		0x00010022
> +#define REG_MAC_ADDR_L		0x00010024
> +#define REG_MAC_ADDR_H		0x00010025
> +
> +#define CCS_Q0_TX_CFG		0x000A0081
> +#define CCS_Q0_RX_CFG		0x000A0082
> +
> +/* Buffer configuration for 32-bytes chunk payload */
> +#define CCS_Q0_TX_CFG_32	0x70000000
> +#define CCS_Q0_RX_CFG_32	0x30000C00
> +
> +#define NW_RX_STATUS		BIT(2)
> +#define NW_TX_STATUS		BIT(3)
> +#define NW_DISABLE		0x0
> +
> +#define MAC_PROMISCUOUS_MODE	BIT(4)
> +#define MAC_MULTICAST_MODE	BIT(6)
> +#define MAC_UNICAST_MODE	BIT(7)
> +
> +#define TX_TIMEOUT		(4 * HZ)
> +#define LAN865X_MSG_DEFAULT	\
> +	(NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_LINK)
> +
> +struct lan865x_priv {
> +	struct net_device *netdev;
> +	struct spi_device *spi;
> +	struct oa_tc6 *tc6;
> +	struct mii_bus *mdiobus;
> +	struct phy_device *phydev;
> +	struct device *dev;
> +	u32 msg_enable;
> +	bool txcte;
> +	bool rxcte;
> +	u32 cps;
> +	bool protected;
> +};
> +
> +static void lan865x_handle_link_change(struct net_device *netdev)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +
> +	phy_print_status(priv->phydev);
> +}
> +
> +static int lan865x_mdiobus_read(struct mii_bus *bus, int phy_id, int idx)
> +{
> +	struct lan865x_priv *priv = bus->priv;
> +	u32 regval;
> +	bool ret;
> +
> +	ret = oa_tc6_read_register(priv->tc6, 0xFF00 | (idx & 0xFF), &regval, 1);
> +	if (ret)
> +		return -ENODEV;
> +
> +	return regval;
> +}
> +
> +static int lan865x_mdiobus_write(struct mii_bus *bus, int phy_id, int idx,
> +				 u16 regval)
> +{
> +	struct lan865x_priv *priv = bus->priv;
> +	u32 value = regval;
> +	bool ret;
> +
> +	ret = oa_tc6_write_register(priv->tc6, 0xFF00 | (idx & 0xFF), &value, 1);
> +	if (ret)
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +
> +static int lan865x_phy_init(struct lan865x_priv *priv)
> +{
> +	int ret;
> +
> +	priv->mdiobus = mdiobus_alloc();
> +	if (!priv->mdiobus) {
> +		netdev_err(priv->netdev, "MDIO bus alloc failed\n");
> +		return -ENODEV;
> +	}
> +
> +	priv->mdiobus->phy_mask = ~(u32)BIT(1);
> +	priv->mdiobus->priv = priv;
> +	priv->mdiobus->read = lan865x_mdiobus_read;
> +	priv->mdiobus->write = lan865x_mdiobus_write;
> +	priv->mdiobus->name = "lan865x-mdiobus";
> +	priv->mdiobus->parent = priv->dev;
> +
> +	snprintf(priv->mdiobus->id, ARRAY_SIZE(priv->mdiobus->id),
> +		 "%s", dev_name(&priv->spi->dev));
> +
> +	ret = mdiobus_register(priv->mdiobus);
> +	if (ret) {
> +		netdev_err(priv->netdev, "Could not register MDIO bus\n");
> +		mdiobus_free(priv->mdiobus);
> +		return ret;
> +	}
> +	priv->phydev = phy_find_first(priv->mdiobus);
> +	if (!priv->phydev) {
> +		netdev_err(priv->netdev, "No PHY found\n");
> +		mdiobus_unregister(priv->mdiobus);
> +		mdiobus_free(priv->mdiobus);
> +		return -ENODEV;
> +	}
> +	priv->phydev->is_internal = true;
> +	ret = phy_connect_direct(priv->netdev, priv->phydev,
> +				 &lan865x_handle_link_change,
> +				 PHY_INTERFACE_MODE_INTERNAL);
> +	if (ret) {
> +		netdev_err(priv->netdev, "Can't attach PHY to %s\n", priv->mdiobus->id);
> +		return ret;
Here return directly without above resources recycle. Please check if it is correct.
If it is needed, it is recommended to use error labels to avoid duplicate code.

> +	}
> +	phy_attached_info(priv->phydev);
> +	return ret;
> +}
> +
> +static int lan865x_set_hw_macaddr(struct net_device *netdev)
> +{
> +	u32 regval;
> +	bool ret;
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +	const u8 *mac = netdev->dev_addr;
> +
> +	ret = oa_tc6_read_register(priv->tc6, REG_MAC_NW_CTRL, &regval, 1);
> +	if (ret)
> +		goto error_mac;
> +	if ((regval & NW_TX_STATUS) | (regval & NW_RX_STATUS)) {
> +		if (netif_msg_drv(priv))
> +			netdev_warn(netdev, "Hardware must be disabled for MAC setting\n");
> +		return -EBUSY;
> +	}
> +	/* MAC address setting */
> +	regval = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) |
> +		mac[0];
> +	ret = oa_tc6_write_register(priv->tc6, REG_MAC_ADDR_L, &regval, 1);
> +	if (ret)
> +		goto error_mac;
> +
> +	regval = (mac[5] << 8) | mac[4];
> +	ret = oa_tc6_write_register(priv->tc6, REG_MAC_ADDR_H, &regval, 1);
> +	if (ret)
> +		goto error_mac;
> +
> +	regval = (mac[5] << 24) | (mac[4] << 16) |
> +		(mac[3] << 8) | mac[2];
> +	ret = oa_tc6_write_register(priv->tc6, REG_MAC_ADDR_BO, &regval, 1);
> +	if (ret)
> +		goto error_mac;
> +
> +	return 0;
> +
> +error_mac:
> +	return -ENODEV;

No resource recycle, goto and error label are not needed. What's more,
the same label corresponds to different errors.

> +}
> +
> +static int
> +lan865x_set_link_ksettings(struct net_device *netdev,
> +			   const struct ethtool_link_ksettings *cmd)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +	int ret = 0;
> +
> +	if (cmd->base.autoneg != AUTONEG_DISABLE ||
> +	    cmd->base.speed != SPEED_10 || cmd->base.duplex != DUPLEX_HALF) {
> +		if (netif_msg_link(priv))
> +			netdev_warn(netdev, "Unsupported link setting");
> +		ret = -EOPNOTSUPP;
> +	} else {
> +		if (netif_msg_link(priv))
> +			netdev_warn(netdev, "Hardware must be disabled to set link mode");
> +		ret = -EBUSY;
> +	}
> +	return ret;
> +}
> +
> +static int
> +lan865x_get_link_ksettings(struct net_device *netdev,
> +			   struct ethtool_link_ksettings *cmd)
> +{
> +	ethtool_link_ksettings_zero_link_mode(cmd, supported);
> +	ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Half);
> +	ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
> +
> +	cmd->base.speed = SPEED_10;
> +	cmd->base.duplex = DUPLEX_HALF;
> +	cmd->base.port	= PORT_TP;
> +	cmd->base.autoneg = AUTONEG_DISABLE;
> +
> +	return 0;
> +}
> +
> +static void lan865x_set_msglevel(struct net_device *netdev, u32 val)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +
> +	priv->msg_enable = val;
> +}
> +
> +static u32 lan865x_get_msglevel(struct net_device *netdev)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +
> +	return priv->msg_enable;
> +}
> +
> +static void
> +lan865x_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
> +{
> +	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
> +	strscpy(info->version, DRV_VERSION, sizeof(info->version));
> +	strscpy(info->bus_info,
> +		dev_name(netdev->dev.parent), sizeof(info->bus_info));
> +}
> +
> +static const struct ethtool_ops lan865x_ethtool_ops = {
> +	.get_drvinfo	= lan865x_get_drvinfo,
> +	.get_msglevel	= lan865x_get_msglevel,
> +	.set_msglevel	= lan865x_set_msglevel,
> +	.get_link_ksettings = lan865x_get_link_ksettings,
> +	.set_link_ksettings = lan865x_set_link_ksettings,
> +};
> +
> +static void lan865x_tx_timeout(struct net_device *netdev, unsigned int txqueue)
> +{
> +	netdev->stats.tx_errors++;
> +}
> +
> +static int lan865x_set_mac_address(struct net_device *netdev, void *addr)
> +{
> +	struct sockaddr *address = addr;
> +
> +	if (netif_running(netdev))
> +		return -EBUSY;
> +	if (!is_valid_ether_addr(address->sa_data))
> +		return -EADDRNOTAVAIL;
> +
> +	eth_hw_addr_set(netdev, address->sa_data);
> +	return lan865x_set_hw_macaddr(netdev);
> +}
> +
> +static u32 lan865x_hash(u8 addr[ETH_ALEN])
> +{
> +	return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f;
> +}
> +
> +static void lan865x_set_multicast_list(struct net_device *netdev)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +	u32 regval = 0;
> +
> +	if (netdev->flags & IFF_PROMISC) {
> +		/* Enabling promiscuous mode */
> +		regval |= MAC_PROMISCUOUS_MODE;
> +		regval &= (~MAC_MULTICAST_MODE);
> +		regval &= (~MAC_UNICAST_MODE);
> +	} else if (netdev->flags & IFF_ALLMULTI) {
> +		/* Enabling all multicast mode */
> +		regval &= (~MAC_PROMISCUOUS_MODE);
> +		regval |= MAC_MULTICAST_MODE;
> +		regval &= (~MAC_UNICAST_MODE);
> +	} else if (!netdev_mc_empty(netdev)) {
> +		/* Enabling specific multicast addresses */
> +		struct netdev_hw_addr *ha;
> +		u32 hash_lo = 0;
> +		u32 hash_hi = 0;
> +
> +		netdev_for_each_mc_addr(ha, netdev) {
> +			u32 bit_num = lan865x_hash(ha->addr);
> +			u32 mask = 1 << (bit_num & 0x1f);
> +
> +			if (bit_num & 0x20)
> +				hash_hi |= mask;
> +			else
> +				hash_lo |= mask;
> +		}
> +		if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHH, &hash_hi, 1)) {
> +			if (netif_msg_timer(priv))
> +				netdev_err(netdev, "Failed to write reg_hashh");
> +			return;
> +		}
> +		if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHL, &hash_lo, 1)) {
> +			if (netif_msg_timer(priv))
> +				netdev_err(netdev, "Failed to write reg_hashl");
> +			return;
> +		}
> +		regval &= (~MAC_PROMISCUOUS_MODE);
> +		regval &= (~MAC_MULTICAST_MODE);
> +		regval |= MAC_UNICAST_MODE;
> +	} else {
> +		/* enabling local mac address only */
> +		if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHH, &regval, 1)) {
> +			if (netif_msg_timer(priv))
> +				netdev_err(netdev, "Failed to write reg_hashh");
> +			return;
> +		}
> +		if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHL, &regval, 1)) {
> +			if (netif_msg_timer(priv))
> +				netdev_err(netdev, "Failed to write reg_hashl");
> +			return;
> +		}
> +	}
> +	if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CONFIG, &regval, 1)) {
> +		if (netif_msg_timer(priv))
> +			netdev_err(netdev, "Failed to enable promiscuous mode");
> +	}
> +}
> +
> +static netdev_tx_t lan865x_send_packet(struct sk_buff *skb,
> +				       struct net_device *netdev)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +
> +	return oa_tc6_send_eth_pkt(priv->tc6, skb);
> +}
> +
> +static int lan865x_hw_disable(struct lan865x_priv *priv)
> +{
> +	u32 regval = NW_DISABLE;
> +
> +	if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CTRL, &regval, 1))
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +
> +static int lan865x_net_close(struct net_device *netdev)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +	int ret;
> +
> +	netif_stop_queue(netdev);
> +	ret = lan865x_hw_disable(priv);
> +	if (ret) {
> +		if (netif_msg_ifup(priv))
> +			netdev_err(netdev, "Failed to disable the hardware\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int lan865x_hw_enable(struct lan865x_priv *priv)
> +{
> +	u32 regval = NW_TX_STATUS | NW_RX_STATUS;
> +
> +	if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CTRL, &regval, 1))
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +
> +static int lan865x_net_open(struct net_device *netdev)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +	int ret;
> +
> +	if (!is_valid_ether_addr(netdev->dev_addr)) {
> +		if (netif_msg_ifup(priv))
> +			netdev_err(netdev, "Invalid MAC address %pm", netdev->dev_addr);
> +		return -EADDRNOTAVAIL;
> +	}
> +	if (lan865x_hw_disable(priv)) {
> +		if (netif_msg_ifup(priv))
> +			netdev_err(netdev, "Failed to disable the hardware\n");
> +		return -ENODEV;
> +	}
> +	ret = lan865x_set_hw_macaddr(netdev);
> +	if (ret != 0)
> +		return ret;
> +
> +	if (lan865x_hw_enable(priv) != 0) {
> +		if (netif_msg_ifup(priv))
> +			netdev_err(netdev, "Failed to enable hardware\n");
> +		return -ENODEV;
> +	}
> +	netif_start_queue(netdev);
> +
> +	return 0;
> +}
> +
> +static const struct net_device_ops lan865x_netdev_ops = {
> +	.ndo_open		= lan865x_net_open,
> +	.ndo_stop		= lan865x_net_close,
> +	.ndo_start_xmit		= lan865x_send_packet,
> +	.ndo_set_rx_mode	= lan865x_set_multicast_list,
> +	.ndo_set_mac_address	= lan865x_set_mac_address,
> +	.ndo_tx_timeout		= lan865x_tx_timeout,
> +	.ndo_validate_addr	= eth_validate_addr,
> +};
> +
> +static int lan865x_get_dt_data(struct lan865x_priv *priv)
> +{
> +	struct spi_device *spi = priv->spi;
> +	int ret;
> +
> +	if (of_property_present(spi->dev.of_node, "oa-chunk-size")) {
> +		ret = of_property_read_u32(spi->dev.of_node, "oa-chunk-size",
> +					   &priv->cps);
> +		if (ret < 0)
> +			return ret;
> +	} else {
> +		priv->cps = 64;
> +		dev_info(&spi->dev, "Property oa-chunk-size is not found in dt and proceeding with the size 64\n");
> +	}
> +
> +	if (of_property_present(spi->dev.of_node, "oa-tx-cut-through"))
> +		priv->txcte = true;
> +	else
> +		dev_info(&spi->dev, "Property oa-tx-cut-through is not found in dt and proceeding with tx store and forward mode\n");
> +
> +	if (of_property_present(spi->dev.of_node, "oa-rx-cut-through"))
> +		priv->rxcte = true;
> +	else
> +		dev_info(&spi->dev, "Property oa-rx-cut-through is not found in dt and proceeding with rx store and forward mode\n");
> +
> +	if (of_property_present(spi->dev.of_node, "oa-protected"))
> +		priv->protected = true;
> +	else
> +		dev_info(&spi->dev, "Property oa-protected is not found in dt and proceeding with protection enabled\n");
> +
> +	return 0;
> +}
> +
> +static int lan865x_probe(struct spi_device *spi)
> +{
> +	struct net_device *netdev;
> +	struct lan865x_priv *priv;
> +	u32 regval;
> +	int ret;
> +
> +	netdev = alloc_etherdev(sizeof(struct lan865x_priv));
> +	if (!netdev)
> +		return -ENOMEM;
> +
> +	priv = netdev_priv(netdev);
> +	priv->netdev = netdev;
> +	priv->spi = spi;
> +	priv->msg_enable = 0;
> +	spi_set_drvdata(spi, priv);
> +	SET_NETDEV_DEV(netdev, &spi->dev);
> +
> +	ret = lan865x_get_dt_data(priv);
> +	if (ret)
> +		return ret;

Has not free allocated netdev.

> +
> +	spi->rt = true;
> +	spi_setup(spi);
> +
> +	priv->tc6 = oa_tc6_init(spi, netdev);
> +	if (!priv->tc6) {
> +		ret = -ENOMEM;
> +		goto error_oa_tc6_init;
> +	}
> +
> +	if (priv->cps == 32) {
> +		regval = CCS_Q0_TX_CFG_32;
> +		ret = oa_tc6_write_register(priv->tc6, CCS_Q0_TX_CFG, &regval, 1);
> +		if (ret)
> +			return ret;

No resources recycle. Please check.

> +
> +		regval = CCS_Q0_RX_CFG_32;
> +		ret = oa_tc6_write_register(priv->tc6, CCS_Q0_RX_CFG, &regval, 1);
> +		if (ret)
> +			return ret;

No resources recycle. Please check.

> +	}
> +
> +	if (oa_tc6_configure(priv->tc6, priv->cps, priv->protected, priv->txcte,
> +			     priv->rxcte))
> +		goto err_macphy_config;
> +
> +	ret = lan865x_phy_init(priv);
> +	if (ret)
> +		goto error_phy;
> +
> +	if (device_get_ethdev_address(&spi->dev, netdev))
> +		eth_hw_addr_random(netdev);
> +
> +	ret = lan865x_set_hw_macaddr(netdev);
> +	if (ret) {
> +		if (netif_msg_probe(priv))
> +			dev_err(&spi->dev, "Failed to configure MAC");
> +		goto error_set_mac;
> +	}
> +
> +	netdev->if_port = IF_PORT_10BASET;
> +	netdev->irq = spi->irq;
> +	netdev->netdev_ops = &lan865x_netdev_ops;
> +	netdev->watchdog_timeo = TX_TIMEOUT;
> +	netdev->ethtool_ops = &lan865x_ethtool_ops;
> +	ret = register_netdev(netdev);
> +	if (ret) {
> +		if (netif_msg_probe(priv))
> +			dev_err(&spi->dev, "Register netdev failed (ret = %d)",
> +				ret);
> +		goto error_netdev_register;
> +	}
> +
> +	phy_start(priv->phydev);
> +	return 0;
> +
> +error_netdev_register:
> +error_set_mac:
> +	phy_disconnect(priv->phydev);
> +	mdiobus_unregister(priv->mdiobus);
> +	mdiobus_free(priv->mdiobus);
> +error_phy:
> +err_macphy_config:
> +	oa_tc6_deinit(priv->tc6);
> +error_oa_tc6_init:
> +	free_netdev(priv->netdev);
> +	return ret;
> +}
> +
> +static void lan865x_remove(struct spi_device *spi)
> +{
> +	struct lan865x_priv *priv = spi_get_drvdata(spi);
> +
> +	phy_stop(priv->phydev);
> +	phy_disconnect(priv->phydev);
> +	mdiobus_unregister(priv->mdiobus);
> +	mdiobus_free(priv->mdiobus);
> +	unregister_netdev(priv->netdev);
> +	if (oa_tc6_deinit(priv->tc6))
> +		dev_err(&spi->dev, "Failed to deinitialize oa tc6\n");
> +	free_netdev(priv->netdev);
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id lan865x_dt_ids[] = {
> +	{ .compatible = "microchip,lan865x" },
> +	{ /* Sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, lan865x_dt_ids);
> +#endif
> +
> +#ifdef CONFIG_ACPI
> +static const struct acpi_device_id lan865x_acpi_ids[] = {
> +	{ .id = "LAN865X",
> +	},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(acpi, lan865x_acpi_ids);
> +#endif
> +
> +static struct spi_driver lan865x_driver = {
> +	.driver = {
> +		.name = DRV_NAME,
> +#ifdef CONFIG_OF
> +		.of_match_table = lan865x_dt_ids,
> +#endif
> +#ifdef CONFIG_ACPI
> +		   .acpi_match_table = ACPI_PTR(lan865x_acpi_ids),
> +#endif
> +	 },
> +	.probe = lan865x_probe,
> +	.remove = lan865x_remove,
> +};
> +module_spi_driver(lan865x_driver);
> +
> +MODULE_DESCRIPTION(DRV_NAME " 10Base-T1S MACPHY Ethernet Driver");
> +MODULE_AUTHOR("Parthiban Veerasooran <parthiban.veerasooran@microchip.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("spi:" DRV_NAME);
> 

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface
  2023-09-11 12:59   ` Ziyang Xuan (William)
@ 2023-09-12 10:32     ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-12 10:32 UTC (permalink / raw)
  To: william.xuanziyang
  Cc: netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	andrew

Hi William,

Thank you for reviewing the patch.

On 11/09/23 6:29 pm, Ziyang Xuan (William) wrote:
> [Some people who received this message don't often get email from william.xuanziyang@huawei.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
> 
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> The ethernet frame to be sent to MAC-PHY is converted into multiple
>> transmit data chunks. A transmit data chunk consists of a 4-byte data
>> header followed by the transmit data chunk payload.
>>
>> The received ethernet frame from the network is converted into multiple
>> receive data chunks by the MAC-PHY and a receive data chunk consists of
>> the receive data chunk payload followed by a 4-byte data footer at the
>> end.
>>
>> The MAC-PHY shall support a default data chunk payload size of 64 bytes.
>> Data chunk payload sizes of 32, 16, or 8 bytes may also be supported. The
>> data chunk payload is always a multiple of 4 bytes.
>>
>> The 4-byte data header occurs at the beginning of each transmit data
>> chunk on MOSI and the 4-byte data footer occurs at the end of each
>> receive data chunk on MISO. The data header and footer contain the
>> information needed to determine the validity and location of the transmit
>> and receive frame data within the data chunk payload. Ethernet frames
>> shall be aligned to a 32-bit boundary within the data chunk payload.
>>
>> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
>> ---
>>   drivers/net/ethernet/oa_tc6.c | 425 +++++++++++++++++++++++++++++++++-
>>   include/linux/oa_tc6.h        |  65 +++++-
>>   2 files changed, 485 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
>> index 65a7317f768d..20138b178185 100644
>> --- a/drivers/net/ethernet/oa_tc6.c
>> +++ b/drivers/net/ethernet/oa_tc6.c
>> @@ -5,6 +5,7 @@
>>    * Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
>>    */
>>
>> +#include <linux/etherdevice.h>
>>   #include <linux/bitfield.h>
>>   #include <linux/interrupt.h>
>>   #include <linux/oa_tc6.h>
>> @@ -193,17 +194,224 @@ int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
>>        return ret;
>>   }
>>
>> +static u16 oa_tc6_prepare_empty_chunk(struct oa_tc6 *tc6, u8 *buf, u8 cp_count)
>> +{
>> +     u32 hdr;
>> +
>> +     /* Prepare empty chunks used for getting interrupt information or if
>> +      * receive data available.
>> +      */
>> +     for (u8 i = 0; i < cp_count; i++) {
>> +             hdr = FIELD_PREP(DATA_HDR_DNC, 1);
>> +             hdr |= FIELD_PREP(DATA_HDR_P, oa_tc6_get_parity(hdr));
>> +             hdr = cpu_to_be32(hdr);
>> +             *(u32 *)&buf[i * (tc6->cps + TC6_HDR_SIZE)] = hdr;
>> +             memset(&buf[TC6_HDR_SIZE + (i * (tc6->cps + TC6_HDR_SIZE))], 0,
>> +                    tc6->cps);
>> +     }
>> +
>> +     return cp_count * (tc6->cps + TC6_HDR_SIZE);
>> +}
>> +
>> +static void oa_tc6_rx_eth_ready(struct oa_tc6 *tc6)
>> +{
>> +     struct sk_buff *skb = NULL;
> Unnecessary initialization for skb.
Ah yes, will remove it in the next revision.
> 
>> +
>> +     /* Send the received ethernet packet to network layer */
>> +     skb = netdev_alloc_skb(tc6->netdev, tc6->rxd_bytes + NET_IP_ALIGN);
>> +     if (!skb) {
>> +             tc6->netdev->stats.rx_dropped++;
>> +             netdev_err(tc6->netdev, "Out of memory for rx'd frame");
>> +     } else {
>> +             skb_reserve(skb, NET_IP_ALIGN);
>> +             memcpy(skb_put(skb, tc6->rxd_bytes), &tc6->eth_rx_buf[0],
>> +                    tc6->rxd_bytes);
>> +             skb->protocol = eth_type_trans(skb, tc6->netdev);
>> +             tc6->netdev->stats.rx_packets++;
>> +             tc6->netdev->stats.rx_bytes += tc6->rxd_bytes;
>> +             netif_rx(skb);
> netif_rx() may fail, I think it is good to add check and statistics.
Sure, will do it in the next revision.

Best Regards,
Parthiban V
> 
>> +     }
>> +}
>> +
>> +static int oa_tc6_process_exst(struct oa_tc6 *tc6)
>> +{
>> +     u32 regval;
>> +     int ret;
>> +
>> +     ret = oa_tc6_read_register(tc6, OA_TC6_STS0, &regval, 1);
>> +     if (ret) {
>> +             netdev_err(tc6->netdev, "STS0 register read failed.\n");
>> +             return ret;
>> +     }
>> +     if (regval & TXPE)
>> +             netdev_err(tc6->netdev, "Transmit protocol error\n");
>> +     if (regval & TXBOE)
>> +             netdev_err(tc6->netdev, "Transmit buffer overflow\n");
>> +     if (regval & TXBUE)
>> +             netdev_err(tc6->netdev, "Transmit buffer underflow\n");
>> +     if (regval & RXBOE)
>> +             netdev_err(tc6->netdev, "Receive buffer overflow\n");
>> +     if (regval & LOFE)
>> +             netdev_err(tc6->netdev, "Loss of frame\n");
>> +     if (regval & HDRE)
>> +             netdev_err(tc6->netdev, "Header error\n");
>> +     if (regval & TXFCSE)
>> +             netdev_err(tc6->netdev, "Transmit Frame Check Sequence Error\n");
>> +     ret = oa_tc6_write_register(tc6, OA_TC6_STS0, &regval, 1);
>> +     if (ret)
>> +             netdev_err(tc6->netdev, "STS0 register write failed.\n");
>> +     return ret;
>> +}
>> +
>> +static int oa_tc6_process_rx_chunks(struct oa_tc6 *tc6, u8 *buf, u16 len)
>> +{
>> +     u8 cp_count;
>> +     u8 *payload;
>> +     u32 ftr;
>> +     u16 ebo;
>> +     u16 sbo;
>> +
>> +     /* Calculate the number of chunks received */
>> +     cp_count = len / (tc6->cps + TC6_FTR_SIZE);
>> +
>> +     for (u8 i = 0; i < cp_count; i++) {
>> +             /* Get the footer and payload */
>> +             ftr = *(u32 *)&buf[tc6->cps + (i * (tc6->cps + TC6_FTR_SIZE))];
>> +             ftr = be32_to_cpu(ftr);
>> +             payload = &buf[(i * (tc6->cps + TC6_FTR_SIZE))];
>> +             /* Check for footer parity error */
>> +             if (oa_tc6_get_parity(ftr)) {
>> +                     netdev_err(tc6->netdev, "Footer: Parity error\n");
>> +                     goto err_exit;
>> +             }
>> +             /* If EXST set in the footer then read STS0 register to get the
>> +              * status information.
>> +              */
>> +             if (FIELD_GET(DATA_FTR_EXST, ftr)) {
>> +                     if (oa_tc6_process_exst(tc6))
>> +                             netdev_err(tc6->netdev, "Failed to process EXST\n");
>> +                     goto err_exit;
>> +             }
>> +             if (FIELD_GET(DATA_FTR_HDRB, ftr)) {
>> +                     netdev_err(tc6->netdev, "Footer: Received header bad\n");
>> +                     goto err_exit;
>> +             }
>> +             if (!FIELD_GET(DATA_FTR_SYNC, ftr)) {
>> +                     netdev_err(tc6->netdev, "Footer: Configuration unsync\n");
>> +                     goto err_exit;
>> +             }
>> +             /* If Frame Drop is set, indicates that the MAC has detected a
>> +              * condition for which the SPI host should drop the received
>> +              * ethernet frame.
>> +              */
>> +             if (FIELD_GET(DATA_FTR_FD, ftr) && FIELD_GET(DATA_FTR_EV, ftr)) {
>> +                     netdev_warn(tc6->netdev, "Footer: Frame drop\n");
>> +                     if (FIELD_GET(DATA_FTR_SV, ftr)) {
>> +                             goto start_new_frame;
>> +                     } else {
>> +                             if (tc6->rx_eth_started) {
>> +                                     tc6->rxd_bytes = 0;
>> +                                     tc6->rx_eth_started = false;
>> +                                     tc6->netdev->stats.rx_dropped++;
>> +                             }
>> +                             continue;
>> +                     }
>> +             }
>> +             /* Check for data valid */
>> +             if (FIELD_GET(DATA_FTR_DV, ftr)) {
>> +                     /* Check whether both start valid and end valid are in a
>> +                      * single chunk payload means a single chunk payload may
>> +                      * contain an entire ethernet frame.
>> +                      */
>> +                     if (FIELD_GET(DATA_FTR_SV, ftr) &&
>> +                         FIELD_GET(DATA_FTR_EV, ftr)) {
>> +                             sbo = FIELD_GET(DATA_FTR_SWO, ftr) * 4;
>> +                             ebo = FIELD_GET(DATA_FTR_EBO, ftr) + 1;
>> +                             if (ebo <= sbo) {
>> +                                     memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
>> +                                            &payload[0], ebo);
>> +                                     tc6->rxd_bytes += ebo;
>> +                                     oa_tc6_rx_eth_ready(tc6);
>> +                                     tc6->rxd_bytes = 0;
>> +                                     memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
>> +                                            &payload[sbo], tc6->cps - sbo);
>> +                                     tc6->rxd_bytes += (tc6->cps - sbo);
>> +                                     goto exit;
>> +                             } else {
>> +                                     memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
>> +                                            &payload[sbo], ebo - sbo);
>> +                                     tc6->rxd_bytes += (ebo - sbo);
>> +                                     oa_tc6_rx_eth_ready(tc6);
>> +                                     tc6->rxd_bytes = 0;
>> +                                     goto exit;
>> +                             }
>> +                     }
>> +start_new_frame:
>> +                     /* Check for start valid to start capturing the incoming
>> +                      * ethernet frame.
>> +                      */
>> +                     if (FIELD_GET(DATA_FTR_SV, ftr) && !tc6->rx_eth_started) {
>> +                             tc6->rxd_bytes = 0;
>> +                             tc6->rx_eth_started = true;
>> +                             sbo = FIELD_GET(DATA_FTR_SWO, ftr) * 4;
>> +                             memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
>> +                                    &payload[sbo], tc6->cps - sbo);
>> +                             tc6->rxd_bytes += (tc6->cps - sbo);
>> +                             goto exit;
>> +                     }
>> +
>> +                     /* Check for end valid and calculate the copy length */
>> +                     if (tc6->rx_eth_started) {
>> +                             if (FIELD_GET(DATA_FTR_EV, ftr))
>> +                                     ebo = FIELD_GET(DATA_FTR_EBO, ftr) + 1;
>> +                             else
>> +                                     ebo = tc6->cps;
>> +
>> +                             memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
>> +                                    &payload[0], ebo);
>> +                             tc6->rxd_bytes += ebo;
>> +                             if (FIELD_GET(DATA_FTR_EV, ftr)) {
>> +                                     /* If End Valid set then send the
>> +                                      * received ethernet frame to n/w.
>> +                                      */
>> +                                     oa_tc6_rx_eth_ready(tc6);
>> +                                     tc6->rxd_bytes = 0;
>> +                                     tc6->rx_eth_started = false;
>> +                             }
>> +                     }
>> +             }
>> +
>> +exit:
>> +             tc6->txc = FIELD_GET(DATA_FTR_TXC, ftr);
>> +             tc6->rca = FIELD_GET(DATA_FTR_RCA, ftr);
>> +     }
>> +     return FTR_OK;
>> +
>> +err_exit:
>> +     if (tc6->rx_eth_started) {
>> +             tc6->rxd_bytes = 0;
>> +             tc6->rx_eth_started = false;
>> +             tc6->netdev->stats.rx_dropped++;
>> +     }
>> +     return FTR_ERR;
>> +}
>> +
>>   static int oa_tc6_handler(void *data)
>>   {
>>        struct oa_tc6 *tc6 = data;
>> +     bool txc_wait = false;
>> +     u16 tx_pos = 0;
>>        u32 regval;
>> +     u16 len;
>>        int ret;
>>
>>        while (likely(!kthread_should_stop())) {
>> -             wait_event_interruptible(tc6->tc6_wq, tc6->int_flag ||
>> +             wait_event_interruptible(tc6->tc6_wq, tc6->tx_flag ||
>> +                                      tc6->int_flag || tc6->rca ||
>>                                         kthread_should_stop());
>> -             if (tc6->int_flag) {
>> +             if (tc6->int_flag && !tc6->reset) {
>>                        tc6->int_flag = false;
>> +                     tc6->reset = true;
>>                        ret = oa_tc6_perform_ctrl(tc6, OA_TC6_STS0, &regval, 1,
>>                                                  false, false);
>>                        if (ret) {
>> @@ -227,10 +435,170 @@ static int oa_tc6_handler(void *data)
>>                                complete(&tc6->rst_complete);
>>                        }
>>                }
>> +
>> +             if (tc6->int_flag || tc6->rca) {
>> +                     /* If rca is updated from the previous footer then
>> +                      * prepare the empty chunks equal to rca and perform
>> +                      * SPI transfer to receive the ethernet frame.
>> +                      */
>> +                     if (tc6->rca) {
>> +                             len = oa_tc6_prepare_empty_chunk(tc6,
>> +                                                              tc6->spi_tx_buf,
>> +                                                              tc6->rca);
>> +                     } else {
>> +                             /* If there is an interrupt then perform a SPI
>> +                              * transfer with a empty chunk to get the
>> +                              * details.
>> +                              */
>> +                             tc6->int_flag = false;
>> +                             len = oa_tc6_prepare_empty_chunk(tc6,
>> +                                                              tc6->spi_tx_buf,
>> +                                                              1);
>> +                     }
>> +                     /* Perform SPI transfer */
>> +                     ret = oa_tc6_spi_transfer(tc6->spi, tc6->spi_tx_buf,
>> +                                               tc6->spi_rx_buf, len);
>> +                     if (ret) {
>> +                             netdev_err(tc6->netdev, "SPI transfer failed\n");
>> +                             continue;
>> +                     }
>> +                     /* Process the received chunks to get the ethernet frame
>> +                      * or interrupt details.
>> +                      */
>> +                     if (oa_tc6_process_rx_chunks(tc6, tc6->spi_rx_buf, len))
>> +                             continue;
>> +             }
>> +
>> +             /* If there is a tx ethernet frame available */
>> +             if (tc6->tx_flag || txc_wait) {
>> +                     tc6->tx_flag = false;
>> +                     txc_wait = false;
>> +                     len = 0;
>> +                     if (!tc6->txc) {
>> +                             /* If there is no txc available to transport the
>> +                              * tx ethernet frames then wait for the MAC-PHY
>> +                              * interrupt to get the txc availability.
>> +                              */
>> +                             txc_wait = true;
>> +                             continue;
>> +                     } else if (tc6->txc >= tc6->txc_needed) {
>> +                             len = tc6->txc_needed * (tc6->cps + TC6_HDR_SIZE);
>> +                     } else {
>> +                             len = tc6->txc * (tc6->cps + TC6_HDR_SIZE);
>> +                     }
>> +                     memcpy(&tc6->spi_tx_buf[0], &tc6->eth_tx_buf[tx_pos],
>> +                            len);
>> +                     ret = oa_tc6_spi_transfer(tc6->spi, tc6->spi_tx_buf,
>> +                                               tc6->spi_rx_buf, len);
>> +                     if (ret) {
>> +                             netdev_err(tc6->netdev, "SPI transfer failed\n");
>> +                             continue;
>> +                     }
>> +                     /* Process the received chunks to get the ethernet frame
>> +                      * or status.
>> +                      */
>> +                     if (oa_tc6_process_rx_chunks(tc6, tc6->spi_rx_buf,
>> +                                                  len)) {
>> +                             /* In case of error while processing rx chunks
>> +                              * discard the incomplete tx ethernet frame and
>> +                              * resend it.
>> +                              */
>> +                             tx_pos = 0;
>> +                             tc6->txc_needed = tc6->total_txc_needed;
>> +                     } else {
>> +                             tx_pos += len;
>> +                             tc6->txc_needed = tc6->txc_needed -
>> +                                               (len / (tc6->cps + TC6_HDR_SIZE));
>> +                             /* If the complete ethernet frame is transmitted
>> +                              * then return the skb and update the details to
>> +                              * n/w layer.
>> +                              */
>> +                             if (!tc6->txc_needed) {
>> +                                     tc6->netdev->stats.tx_packets++;
>> +                                     tc6->netdev->stats.tx_bytes += tc6->tx_skb->len;
>> +                                     dev_kfree_skb(tc6->tx_skb);
>> +                                     tx_pos = 0;
>> +                                     tc6->tx_skb = NULL;
>> +                                     if (netif_queue_stopped(tc6->netdev))
>> +                                             netif_wake_queue(tc6->netdev);
>> +                             } else if (tc6->txc) {
>> +                                     /* If txc is available again and updated
>> +                                      * from the previous footer then perform
>> +                                      * tx again.
>> +                                      */
>> +                                     tc6->tx_flag = true;
>> +                             } else {
>> +                                     /* If there is no txc then wait for the
>> +                                      * interrupt to indicate txc
>> +                                      * availability.
>> +                                      */
>> +                                     txc_wait = true;
>> +                             }
>> +                     }
>> +             }
>>        }
>>        return 0;
>>   }
>>
>> +static void oa_tc6_prepare_tx_chunks(struct oa_tc6 *tc6, u8 *buf,
>> +                                  struct sk_buff *skb)
>> +{
>> +     bool frame_started = false;
>> +     u16 copied_bytes = 0;
>> +     u16 copy_len;
>> +     u32 hdr;
>> +
>> +     /* Calculate the number tx credit counts needed to transport the tx
>> +      * ethernet frame.
>> +      */
>> +     tc6->txc_needed = (skb->len / tc6->cps) + ((skb->len % tc6->cps) ? 1 : 0);
>> +     tc6->total_txc_needed = tc6->txc_needed;
>> +
>> +     for (u8 i = 0; i < tc6->txc_needed; i++) {
>> +             /* Prepare the header for each chunks to be transmitted */
>> +             hdr = FIELD_PREP(DATA_HDR_DNC, 1) |
>> +                   FIELD_PREP(DATA_HDR_DV, 1);
>> +             if (!frame_started) {
>> +                     hdr |= FIELD_PREP(DATA_HDR_SV, 1) |
>> +                            FIELD_PREP(DATA_HDR_SWO, 0);
>> +                     frame_started = true;
>> +             }
>> +             if ((tc6->cps + copied_bytes) >= skb->len) {
>> +                     copy_len = skb->len - copied_bytes;
>> +                     hdr |= FIELD_PREP(DATA_HDR_EBO, copy_len - 1) |
>> +                            FIELD_PREP(DATA_HDR_EV, 1);
>> +             } else {
>> +                     copy_len = tc6->cps;
>> +             }
>> +             copied_bytes += copy_len;
>> +             hdr |= FIELD_PREP(DATA_HDR_P, oa_tc6_get_parity(hdr));
>> +             hdr = cpu_to_be32(hdr);
>> +             *(u32 *)&buf[i * (tc6->cps + TC6_HDR_SIZE)] = hdr;
>> +             /* Copy the ethernet frame in the chunk payload section */
>> +             memcpy(&buf[TC6_HDR_SIZE + (i * (tc6->cps + TC6_HDR_SIZE))],
>> +                    &skb->data[copied_bytes - copy_len], copy_len);
>> +     }
>> +}
>> +
>> +netdev_tx_t oa_tc6_send_eth_pkt(struct oa_tc6 *tc6, struct sk_buff *skb)
>> +{
>> +     if (tc6->tx_skb) {
>> +             netif_stop_queue(tc6->netdev);
>> +             return NETDEV_TX_BUSY;
>> +     }
>> +
>> +     tc6->tx_skb = skb;
>> +     /* Prepare tx chunks using the tx ethernet frame */
>> +     oa_tc6_prepare_tx_chunks(tc6, tc6->eth_tx_buf, skb);
>> +
>> +     /* Wake tc6 task to perform tx transfer */
>> +     tc6->tx_flag = true;
>> +     wake_up_interruptible(&tc6->tc6_wq);
>> +
>> +     return NETDEV_TX_OK;
>> +}
>> +EXPORT_SYMBOL_GPL(oa_tc6_send_eth_pkt);
>> +
>>   static irqreturn_t macphy_irq(int irq, void *dev_id)
>>   {
>>        struct oa_tc6 *tc6 = dev_id;
>> @@ -293,6 +661,14 @@ int oa_tc6_configure(struct oa_tc6 *tc6, u8 cps, bool ctrl_prot, bool tx_cut_thr
>>        u32 regval;
>>        int ret;
>>
>> +     /* Read BUFSTS register to get the current txc and rca. */
>> +     ret = oa_tc6_read_register(tc6, OA_TC6_BUFSTS, &regval, 1);
>> +     if (ret)
>> +             return ret;
>> +
>> +     tc6->txc = FIELD_GET(TXC, regval);
>> +     tc6->rca = FIELD_GET(RCA, regval);
>> +
>>        /* Read and configure the IMASK0 register for unmasking the interrupts */
>>        ret = oa_tc6_read_register(tc6, OA_TC6_IMASK0, &regval, 1);
>>        if (ret)
>> @@ -326,7 +702,7 @@ int oa_tc6_configure(struct oa_tc6 *tc6, u8 cps, bool ctrl_prot, bool tx_cut_thr
>>   }
>>   EXPORT_SYMBOL_GPL(oa_tc6_configure);
>>
>> -struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
>> +struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev)
>>   {
>>        struct oa_tc6 *tc6;
>>        int ret;
>> @@ -334,11 +710,39 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
>>        if (!spi)
>>                return NULL;
>>
>> +     if (!netdev)
>> +             return NULL;
>> +
>>        tc6 = kzalloc(sizeof(*tc6), GFP_KERNEL);
>>        if (!tc6)
>>                return NULL;
>>
>>        tc6->spi = spi;
>> +     tc6->netdev = netdev;
>> +
>> +     /* Allocate memory for the tx buffer used for SPI transfer. */
>> +     tc6->spi_tx_buf = kzalloc(MAX_ETH_LEN + (OA_TC6_MAX_CPS * TC6_HDR_SIZE),
>> +                               GFP_KERNEL);
>> +     if (!tc6->spi_tx_buf)
>> +             goto err_spi_tx_buf_alloc;
>> +
>> +     /* Allocate memory for the rx buffer used for SPI transfer. */
>> +     tc6->spi_rx_buf = kzalloc(MAX_ETH_LEN + (OA_TC6_MAX_CPS * TC6_FTR_SIZE),
>> +                               GFP_KERNEL);
>> +     if (!tc6->spi_rx_buf)
>> +             goto err_spi_rx_buf_alloc;
>> +
>> +     /* Allocate memory for the tx ethernet chunks to transfer on SPI. */
>> +     tc6->eth_tx_buf = kzalloc(MAX_ETH_LEN + (OA_TC6_MAX_CPS * TC6_HDR_SIZE),
>> +                               GFP_KERNEL);
>> +     if (!tc6->eth_tx_buf)
>> +             goto err_eth_tx_buf_alloc;
>> +
>> +     /* Allocate memory for the rx ethernet packet. */
>> +     tc6->eth_rx_buf = kzalloc(MAX_ETH_LEN + (OA_TC6_MAX_CPS * TC6_FTR_SIZE),
>> +                               GFP_KERNEL);
>> +     if (!tc6->eth_rx_buf)
>> +             goto err_eth_rx_buf_alloc;
>>
>>        /* Used for triggering the OA TC6 task */
>>        init_waitqueue_head(&tc6->tc6_wq);
>> @@ -372,6 +776,14 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
>>   err_macphy_irq:
>>        kthread_stop(tc6->tc6_task);
>>   err_tc6_task:
>> +     kfree(tc6->eth_rx_buf);
>> +err_eth_rx_buf_alloc:
>> +     kfree(tc6->eth_tx_buf);
>> +err_eth_tx_buf_alloc:
>> +     kfree(tc6->spi_rx_buf);
>> +err_spi_rx_buf_alloc:
>> +     kfree(tc6->spi_tx_buf);
>> +err_spi_tx_buf_alloc:
>>        kfree(tc6);
>>        return NULL;
>>   }
>> @@ -383,8 +795,13 @@ int oa_tc6_deinit(struct oa_tc6 *tc6)
>>
>>        devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
>>        ret = kthread_stop(tc6->tc6_task);
>> -     if (!ret)
>> +     if (!ret) {
>> +             kfree(tc6->eth_rx_buf);
>> +             kfree(tc6->eth_tx_buf);
>> +             kfree(tc6->spi_rx_buf);
>> +             kfree(tc6->spi_tx_buf);
>>                kfree(tc6);
>> +     }
>>        return ret;
>>   }
>>   EXPORT_SYMBOL_GPL(oa_tc6_deinit);
>> diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
>> index fa29c4e09720..61ac1cdfa7d6 100644
>> --- a/include/linux/oa_tc6.h
>> +++ b/include/linux/oa_tc6.h
>> @@ -6,6 +6,7 @@
>>    */
>>
>>   #include <linux/spi/spi.h>
>> +#include <linux/netdevice.h>
>>
>>   /* Control header */
>>   #define CTRL_HDR_DNC BIT(31)         /* Data-Not-Control */
>> @@ -17,10 +18,36 @@
>>   #define CTRL_HDR_LEN GENMASK(7, 1)   /* Length */
>>   #define CTRL_HDR_P   BIT(0)          /* Parity Bit */
>>
>> +/* Data header */
>> +#define DATA_HDR_DNC BIT(31)         /* Data-Not-Control */
>> +#define DATA_HDR_SEQ BIT(30)         /* Data Chunk Sequence */
>> +#define DATA_HDR_NORX        BIT(29)         /* No Receive */
>> +#define DATA_HDR_DV  BIT(21)         /* Data Valid */
>> +#define DATA_HDR_SV  BIT(20)         /* Start Valid */
>> +#define DATA_HDR_SWO GENMASK(19, 16) /* Start Word Offset */
>> +#define DATA_HDR_EV  BIT(14)         /* End Valid */
>> +#define DATA_HDR_EBO GENMASK(13, 8)  /* End Byte Offset */
>> +#define DATA_HDR_P   BIT(0)          /* Header Parity Bit */
>> +
>> +/* Data footer */
>> +#define DATA_FTR_EXST        BIT(31)         /* Extended Status */
>> +#define DATA_FTR_HDRB        BIT(30)         /* Received Header Bad */
>> +#define DATA_FTR_SYNC        BIT(29)         /* Configuration Synchronized */
>> +#define DATA_FTR_RCA GENMASK(28, 24) /* Receive Chunks Available */
>> +#define DATA_FTR_DV  BIT(21)         /* Data Valid */
>> +#define DATA_FTR_SV  BIT(20)         /* Start Valid */
>> +#define DATA_FTR_SWO GENMASK(19, 16) /* Start Word Offset */
>> +#define DATA_FTR_FD  BIT(15)         /* Frame Drop */
>> +#define DATA_FTR_EV  BIT(14)         /* End Valid */
>> +#define DATA_FTR_EBO GENMASK(13, 8)  /* End Byte Offset */
>> +#define DATA_FTR_TXC GENMASK(5, 1)   /* Transmit Credits */
>> +#define DATA_FTR_P   BIT(0)          /* Footer Parity Bit */
>> +
>>   /* Open Alliance TC6 Standard Control and Status Registers */
>>   #define OA_TC6_RESET 0x0003          /* Reset Control and Status Register */
>>   #define OA_TC6_CONFIG0       0x0004          /* Configuration Register #0 */
>>   #define OA_TC6_STS0  0x0008          /* Status Register #0 */
>> +#define OA_TC6_BUFSTS        0x000B          /* Buffer Status Register */
>>   #define OA_TC6_IMASK0        0x000C          /* Interrupt Mask Register #0 */
>>
>>   /* RESET register field */
>> @@ -33,6 +60,17 @@
>>   #define PROTE                BIT(5)          /* Ctrl read/write Protection Enable */
>>   #define CPS          GENMASK(2, 0)   /* Chunk Payload Size */
>>
>> +/* STATUS0 register fields */
>> +#define CDPE         BIT(12)         /* Control Data Protection Error */
>> +#define TXFCSE               BIT(11)         /* Transmit Frame Check Sequence Error */
>> +#define RESETC               BIT(6)          /* Reset Complete */
>> +#define HDRE         BIT(5)          /* Header Error */
>> +#define LOFE         BIT(4)          /* Loss of Framing Error */
>> +#define RXBOE                BIT(3)          /* Receive Buffer Overflow Error */
>> +#define TXBUE                BIT(2)          /* Transmit Buffer Underflow Error */
>> +#define TXBOE                BIT(1)          /* Transmit Buffer Overflow Error */
>> +#define TXPE         BIT(0)          /* Transmit Protocol Error */
>> +
>>   /* Unmasking interrupt fields in IMASK0 */
>>   #define HDREM                ~BIT(5)         /* Header Error Mask */
>>   #define LOFEM                ~BIT(4)         /* Loss of Framing Error Mask */
>> @@ -44,24 +82,49 @@
>>   /* STATUS0 register field */
>>   #define RESETC               BIT(6)          /* Reset Complete */
>>
>> +/* BUFSTS register fields */
>> +#define TXC          GENMASK(15, 8)  /* Transmit Credits Available */
>> +#define RCA          GENMASK(7, 0)   /* Receive Chunks Available */
>> +
>>   #define TC6_HDR_SIZE 4               /* Ctrl command header size as per OA */
>>   #define TC6_FTR_SIZE 4               /* Ctrl command footer size ss per OA */
>>
>> +#define FTR_OK               0
>> +#define FTR_ERR              1
>> +
>> +#define MAX_ETH_LEN  1536
>> +#define OA_TC6_MAX_CPS       64
>> +
>>   struct oa_tc6 {
>>        struct completion rst_complete;
>>        struct task_struct *tc6_task;
>> +     struct net_device *netdev;
>>        wait_queue_head_t tc6_wq;
>>        struct spi_device *spi;
>> +     struct sk_buff *tx_skb;
>> +     u8 total_txc_needed;
>> +     bool rx_eth_started;
>>        bool tx_cut_thr;
>>        bool rx_cut_thr;
>>        bool ctrl_prot;
>> +     u8 *spi_tx_buf;
>> +     u8 *spi_rx_buf;
>> +     u8 *eth_tx_buf;
>> +     u8 *eth_rx_buf;
>>        bool int_flag;
>> +     u16 rxd_bytes;
>> +     u8 txc_needed;
>> +     bool tx_flag;
>> +     bool reset;
>>        u8 cps;
>> +     u8 txc;
>> +     u8 rca;
>>   };
>>
>> -struct oa_tc6 *oa_tc6_init(struct spi_device *spi);
>> +struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev);
>>   int oa_tc6_deinit(struct oa_tc6 *tc6);
>>   int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
>>   int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
>>   int oa_tc6_configure(struct oa_tc6 *tc6, u8 cps, bool ctrl_prot, bool tx_cut_thr,
>>                     bool rx_cut_thr);
>> +netdev_tx_t oa_tc6_send_eth_pkt(struct oa_tc6 *tc6, struct sk_buff *skb);
>>


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  2023-09-10 17:44   ` Simon Horman
@ 2023-09-12 10:53     ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-12 10:53 UTC (permalink / raw)
  To: horms
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, casper.casan, andrew,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Simon,

Thank you for reviewing the patch.

On 10/09/23 11:14 pm, Simon Horman wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On Fri, Sep 08, 2023 at 07:59:18PM +0530, Parthiban Veerasooran wrote:
>> The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE‑T1x
>> MAC‑PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
>> MAC integration provides the low pin count standard SPI interface to any
>> microcontroller therefore providing Ethernet functionality without
>> requiring MAC integration within the microcontroller. The LAN8650/1
>> operates as an SPI client supporting SCLK clock rates up to a maximum of
>> 25 MHz. This SPI interface supports the transfer of both data (Ethernet
>> frames) and control (register access).
>>
>> By default, the chunk data payload is 64 bytes in size. A smaller payload
>> data size of 32 bytes is also supported and may be configured in the
>> Chunk Payload Size (CPS) field of the Configuration 0 (OA_CONFIG0)
>> register. Changing the chunk payload size requires the LAN8650/1 be reset
>> and shall not be done during normal operation.
>>
>> The Ethernet Media Access Controller (MAC) module implements a 10 Mbps
>> half duplex Ethernet MAC, compatible with the IEEE 802.3 standard.
>> 10BASE-T1S physical layer transceiver integrated into the LAN8650/1. The
>> PHY and MAC are connected via an internal Media Independent Interface
>> (MII).
>>
>> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
> 
> Hi Parthiban,
> 
> thanks for your patches.
> Some minor feedback on this one follows.
> 
> ...
> 
>> diff --git a/drivers/net/ethernet/microchip/lan865x.c b/drivers/net/ethernet/microchip/lan865x.c
> 
> ...
> 
>> +static int lan865x_set_hw_macaddr(struct net_device *netdev)
>> +{
>> +     u32 regval;
>> +     bool ret;
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +     const u8 *mac = netdev->dev_addr;
> 
> Please arrange local variables in Networking code in reverse xmas tree
> order - longest line to shortest.
> 
> This tool can be of assistance here:
> https://github.com/ecree-solarflare/xmastree
Sure will do it. Somehow this area got escaped from my eyes.
> 
> ...
> 
>> +static int lan865x_probe(struct spi_device *spi)
>> +{
>> +     struct net_device *netdev;
>> +     struct lan865x_priv *priv;
>> +     u32 regval;
>> +     int ret;
>> +
>> +     netdev = alloc_etherdev(sizeof(struct lan865x_priv));
>> +     if (!netdev)
>> +             return -ENOMEM;
>> +
>> +     priv = netdev_priv(netdev);
>> +     priv->netdev = netdev;
>> +     priv->spi = spi;
>> +     priv->msg_enable = 0;
>> +     spi_set_drvdata(spi, priv);
>> +     SET_NETDEV_DEV(netdev, &spi->dev);
>> +
>> +     ret = lan865x_get_dt_data(priv);
>> +     if (ret)
>> +             return ret;
>> +
>> +     spi->rt = true;
>> +     spi_setup(spi);
>> +
>> +     priv->tc6 = oa_tc6_init(spi, netdev);
>> +     if (!priv->tc6) {
>> +             ret = -ENOMEM;
>> +             goto error_oa_tc6_init;
>> +     }
>> +
>> +     if (priv->cps == 32) {
>> +             regval = CCS_Q0_TX_CFG_32;
>> +             ret = oa_tc6_write_register(priv->tc6, CCS_Q0_TX_CFG, &regval, 1);
>> +             if (ret)
>> +                     return ret;
>> +
>> +             regval = CCS_Q0_RX_CFG_32;
>> +             ret = oa_tc6_write_register(priv->tc6, CCS_Q0_RX_CFG, &regval, 1);
>> +             if (ret)
>> +                     return ret;
>> +     }
>> +
>> +     if (oa_tc6_configure(priv->tc6, priv->cps, priv->protected, priv->txcte,
>> +                          priv->rxcte))
>> +             goto err_macphy_config;
> 
> Jumping to err_macphy_config will result in this function returning ret.
> However, ret will be 0 at this point. Perhaps it should be set to an
> error value.
Ah yes, thanks for pointing it out. Will correct in the next version.

Best Regards,
Parthiban V
> 
> Flagged by Smatch.
> 
>> +
>> +     ret = lan865x_phy_init(priv);
>> +     if (ret)
>> +             goto error_phy;
>> +
>> +     if (device_get_ethdev_address(&spi->dev, netdev))
>> +             eth_hw_addr_random(netdev);
>> +
>> +     ret = lan865x_set_hw_macaddr(netdev);
>> +     if (ret) {
>> +             if (netif_msg_probe(priv))
>> +                     dev_err(&spi->dev, "Failed to configure MAC");
>> +             goto error_set_mac;
>> +     }
>> +
>> +     netdev->if_port = IF_PORT_10BASET;
>> +     netdev->irq = spi->irq;
>> +     netdev->netdev_ops = &lan865x_netdev_ops;
>> +     netdev->watchdog_timeo = TX_TIMEOUT;
>> +     netdev->ethtool_ops = &lan865x_ethtool_ops;
>> +     ret = register_netdev(netdev);
>> +     if (ret) {
>> +             if (netif_msg_probe(priv))
>> +                     dev_err(&spi->dev, "Register netdev failed (ret = %d)",
>> +                             ret);
>> +             goto error_netdev_register;
>> +     }
>> +
>> +     phy_start(priv->phydev);
>> +     return 0;
>> +
>> +error_netdev_register:
>> +error_set_mac:
>> +     phy_disconnect(priv->phydev);
>> +     mdiobus_unregister(priv->mdiobus);
>> +     mdiobus_free(priv->mdiobus);
>> +error_phy:
>> +err_macphy_config:
>> +     oa_tc6_deinit(priv->tc6);
>> +error_oa_tc6_init:
>> +     free_netdev(priv->netdev);
>> +     return ret;
>> +}
> 
> 
> ...


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  2023-09-11 13:17   ` Ziyang Xuan (William)
@ 2023-09-12 11:41     ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-12 11:41 UTC (permalink / raw)
  To: william.xuanziyang
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	andrew, netdev, devicetree, linux-kernel, linux-doc,
	Horatiu.Vultur, Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver,
	Thorsten.Kummermehr

Hi William,

On 11/09/23 6:47 pm, Ziyang Xuan (William) wrote:
> [Some people who received this message don't often get email from william.xuanziyang@huawei.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
> 
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE‑T1x
>> MAC‑PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
>> MAC integration provides the low pin count standard SPI interface to any
>> microcontroller therefore providing Ethernet functionality without
>> requiring MAC integration within the microcontroller. The LAN8650/1
>> operates as an SPI client supporting SCLK clock rates up to a maximum of
>> 25 MHz. This SPI interface supports the transfer of both data (Ethernet
>> frames) and control (register access).
>>
>> By default, the chunk data payload is 64 bytes in size. A smaller payload
>> data size of 32 bytes is also supported and may be configured in the
>> Chunk Payload Size (CPS) field of the Configuration 0 (OA_CONFIG0)
>> register. Changing the chunk payload size requires the LAN8650/1 be reset
>> and shall not be done during normal operation.
>>
>> The Ethernet Media Access Controller (MAC) module implements a 10 Mbps
>> half duplex Ethernet MAC, compatible with the IEEE 802.3 standard.
>> 10BASE-T1S physical layer transceiver integrated into the LAN8650/1. The
>> PHY and MAC are connected via an internal Media Independent Interface
>> (MII).
>>
>> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
>> ---
>>   MAINTAINERS                              |   6 +
>>   drivers/net/ethernet/microchip/Kconfig   |  10 +
>>   drivers/net/ethernet/microchip/Makefile  |   3 +
>>   drivers/net/ethernet/microchip/lan865x.c | 589 +++++++++++++++++++++++
>>   4 files changed, 608 insertions(+)
>>   create mode 100644 drivers/net/ethernet/microchip/lan865x.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index c54454c7e7a1..666c042a15b2 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -13879,6 +13879,12 @@ L:   netdev@vger.kernel.org
>>   S:   Maintained
>>   F:   drivers/net/ethernet/microchip/lan743x_*
>>
>> +MICROCHIP LAN8650/1 10BASE-T1S MACPHY ETHERNET DRIVER
>> +M:   Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
>> +L:   netdev@vger.kernel.org
>> +S:   Maintained
>> +F:   drivers/net/ethernet/microchip/lan865x.c
>> +
>>   MICROCHIP LAN87xx/LAN937x T1 PHY DRIVER
>>   M:   Arun Ramadoss <arun.ramadoss@microchip.com>
>>   R:   UNGLinuxDriver@microchip.com
>> diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
>> index 329e374b9539..d99be51b99f1 100644
>> --- a/drivers/net/ethernet/microchip/Kconfig
>> +++ b/drivers/net/ethernet/microchip/Kconfig
>> @@ -59,4 +59,14 @@ source "drivers/net/ethernet/microchip/lan966x/Kconfig"
>>   source "drivers/net/ethernet/microchip/sparx5/Kconfig"
>>   source "drivers/net/ethernet/microchip/vcap/Kconfig"
>>
>> +config LAN865X
>> +     tristate "LAN865x support"
>> +     depends on SPI
>> +     help
>> +               Support for the Microchip LAN8650/1 Rev.B0 Ethernet chip. It uses OPEN
>> +       Alliance 10BASE-T1x Serial Interface specification.
>> +
>> +               To compile this driver as a module, choose M here. The module will be
>> +          called lan865x.
>> +
>>   endif # NET_VENDOR_MICROCHIP
>> diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile
>> index bbd349264e6f..315e850b2b26 100644
>> --- a/drivers/net/ethernet/microchip/Makefile
>> +++ b/drivers/net/ethernet/microchip/Makefile
>> @@ -12,3 +12,6 @@ lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o
>>   obj-$(CONFIG_LAN966X_SWITCH) += lan966x/
>>   obj-$(CONFIG_SPARX5_SWITCH) += sparx5/
>>   obj-$(CONFIG_VCAP) += vcap/
>> +
>> +obj-$(CONFIG_LAN865X) += lan865x_t1s.o
>> +lan865x_t1s-objs := lan865x.o ../oa_tc6.o
>> diff --git a/drivers/net/ethernet/microchip/lan865x.c b/drivers/net/ethernet/microchip/lan865x.c
>> new file mode 100644
>> index 000000000000..3c8ebf4c258f
>> --- /dev/null
>> +++ b/drivers/net/ethernet/microchip/lan865x.c
>> @@ -0,0 +1,589 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Microchip's LAN865x 10BASE-T1S MAC-PHY driver
>> + *
>> + * Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/kernel.h>
>> +#include <linux/etherdevice.h>
>> +#include <linux/mdio.h>
>> +#include <linux/phy.h>
>> +#include <linux/of.h>
>> +#include <linux/oa_tc6.h>
>> +
>> +#define DRV_NAME             "lan865x"
>> +#define DRV_VERSION          "0.1"
>> +
>> +#define REG_STDR_RESET               0x00000003
>> +#define REG_MAC_ADDR_BO              0x00010022
>> +#define REG_MAC_ADDR_L               0x00010024
>> +#define REG_MAC_ADDR_H               0x00010025
>> +#define REG_MAC_NW_CTRL         0x00010000
>> +#define REG_MAC_NW_CONFIG    0x00010001
>> +#define REG_MAC_HASHL                0x00010020
>> +#define REG_MAC_HASHH                0x00010021
>> +#define REG_MAC_ADDR_BO              0x00010022
>> +#define REG_MAC_ADDR_L               0x00010024
>> +#define REG_MAC_ADDR_H               0x00010025
>> +
>> +#define CCS_Q0_TX_CFG                0x000A0081
>> +#define CCS_Q0_RX_CFG                0x000A0082
>> +
>> +/* Buffer configuration for 32-bytes chunk payload */
>> +#define CCS_Q0_TX_CFG_32     0x70000000
>> +#define CCS_Q0_RX_CFG_32     0x30000C00
>> +
>> +#define NW_RX_STATUS         BIT(2)
>> +#define NW_TX_STATUS         BIT(3)
>> +#define NW_DISABLE           0x0
>> +
>> +#define MAC_PROMISCUOUS_MODE BIT(4)
>> +#define MAC_MULTICAST_MODE   BIT(6)
>> +#define MAC_UNICAST_MODE     BIT(7)
>> +
>> +#define TX_TIMEOUT           (4 * HZ)
>> +#define LAN865X_MSG_DEFAULT  \
>> +     (NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_LINK)
>> +
>> +struct lan865x_priv {
>> +     struct net_device *netdev;
>> +     struct spi_device *spi;
>> +     struct oa_tc6 *tc6;
>> +     struct mii_bus *mdiobus;
>> +     struct phy_device *phydev;
>> +     struct device *dev;
>> +     u32 msg_enable;
>> +     bool txcte;
>> +     bool rxcte;
>> +     u32 cps;
>> +     bool protected;
>> +};
>> +
>> +static void lan865x_handle_link_change(struct net_device *netdev)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +
>> +     phy_print_status(priv->phydev);
>> +}
>> +
>> +static int lan865x_mdiobus_read(struct mii_bus *bus, int phy_id, int idx)
>> +{
>> +     struct lan865x_priv *priv = bus->priv;
>> +     u32 regval;
>> +     bool ret;
>> +
>> +     ret = oa_tc6_read_register(priv->tc6, 0xFF00 | (idx & 0xFF), &regval, 1);
>> +     if (ret)
>> +             return -ENODEV;
>> +
>> +     return regval;
>> +}
>> +
>> +static int lan865x_mdiobus_write(struct mii_bus *bus, int phy_id, int idx,
>> +                              u16 regval)
>> +{
>> +     struct lan865x_priv *priv = bus->priv;
>> +     u32 value = regval;
>> +     bool ret;
>> +
>> +     ret = oa_tc6_write_register(priv->tc6, 0xFF00 | (idx & 0xFF), &value, 1);
>> +     if (ret)
>> +             return -ENODEV;
>> +
>> +     return 0;
>> +}
>> +
>> +static int lan865x_phy_init(struct lan865x_priv *priv)
>> +{
>> +     int ret;
>> +
>> +     priv->mdiobus = mdiobus_alloc();
>> +     if (!priv->mdiobus) {
>> +             netdev_err(priv->netdev, "MDIO bus alloc failed\n");
>> +             return -ENODEV;
>> +     }
>> +
>> +     priv->mdiobus->phy_mask = ~(u32)BIT(1);
>> +     priv->mdiobus->priv = priv;
>> +     priv->mdiobus->read = lan865x_mdiobus_read;
>> +     priv->mdiobus->write = lan865x_mdiobus_write;
>> +     priv->mdiobus->name = "lan865x-mdiobus";
>> +     priv->mdiobus->parent = priv->dev;
>> +
>> +     snprintf(priv->mdiobus->id, ARRAY_SIZE(priv->mdiobus->id),
>> +              "%s", dev_name(&priv->spi->dev));
>> +
>> +     ret = mdiobus_register(priv->mdiobus);
>> +     if (ret) {
>> +             netdev_err(priv->netdev, "Could not register MDIO bus\n");
>> +             mdiobus_free(priv->mdiobus);
>> +             return ret;
>> +     }
>> +     priv->phydev = phy_find_first(priv->mdiobus);
>> +     if (!priv->phydev) {
>> +             netdev_err(priv->netdev, "No PHY found\n");
>> +             mdiobus_unregister(priv->mdiobus);
>> +             mdiobus_free(priv->mdiobus);
>> +             return -ENODEV;
>> +     }
>> +     priv->phydev->is_internal = true;
>> +     ret = phy_connect_direct(priv->netdev, priv->phydev,
>> +                              &lan865x_handle_link_change,
>> +                              PHY_INTERFACE_MODE_INTERNAL);
>> +     if (ret) {
>> +             netdev_err(priv->netdev, "Can't attach PHY to %s\n", priv->mdiobus->id);
>> +             return ret;
> Here return directly without above resources recycle. Please check if it is correct.
> If it is needed, it is recommended to use error labels to avoid duplicate code.
Ok noted. Will correct it in the next revision.
> 
>> +     }
>> +     phy_attached_info(priv->phydev);
>> +     return ret;
>> +}
>> +
>> +static int lan865x_set_hw_macaddr(struct net_device *netdev)
>> +{
>> +     u32 regval;
>> +     bool ret;
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +     const u8 *mac = netdev->dev_addr;
>> +
>> +     ret = oa_tc6_read_register(priv->tc6, REG_MAC_NW_CTRL, &regval, 1);
>> +     if (ret)
>> +             goto error_mac;
>> +     if ((regval & NW_TX_STATUS) | (regval & NW_RX_STATUS)) {
>> +             if (netif_msg_drv(priv))
>> +                     netdev_warn(netdev, "Hardware must be disabled for MAC setting\n");
>> +             return -EBUSY;
>> +     }
>> +     /* MAC address setting */
>> +     regval = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) |
>> +             mac[0];
>> +     ret = oa_tc6_write_register(priv->tc6, REG_MAC_ADDR_L, &regval, 1);
>> +     if (ret)
>> +             goto error_mac;
>> +
>> +     regval = (mac[5] << 8) | mac[4];
>> +     ret = oa_tc6_write_register(priv->tc6, REG_MAC_ADDR_H, &regval, 1);
>> +     if (ret)
>> +             goto error_mac;
>> +
>> +     regval = (mac[5] << 24) | (mac[4] << 16) |
>> +             (mac[3] << 8) | mac[2];
>> +     ret = oa_tc6_write_register(priv->tc6, REG_MAC_ADDR_BO, &regval, 1);
>> +     if (ret)
>> +             goto error_mac;
>> +
>> +     return 0;
>> +
>> +error_mac:
>> +     return -ENODEV;
> 
> No resource recycle, goto and error label are not needed. What's more,
> the same label corresponds to different errors.
Ah yes, will correct it in the next revision.
> 
>> +}
>> +
>> +static int
>> +lan865x_set_link_ksettings(struct net_device *netdev,
>> +                        const struct ethtool_link_ksettings *cmd)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +     int ret = 0;
>> +
>> +     if (cmd->base.autoneg != AUTONEG_DISABLE ||
>> +         cmd->base.speed != SPEED_10 || cmd->base.duplex != DUPLEX_HALF) {
>> +             if (netif_msg_link(priv))
>> +                     netdev_warn(netdev, "Unsupported link setting");
>> +             ret = -EOPNOTSUPP;
>> +     } else {
>> +             if (netif_msg_link(priv))
>> +                     netdev_warn(netdev, "Hardware must be disabled to set link mode");
>> +             ret = -EBUSY;
>> +     }
>> +     return ret;
>> +}
>> +
>> +static int
>> +lan865x_get_link_ksettings(struct net_device *netdev,
>> +                        struct ethtool_link_ksettings *cmd)
>> +{
>> +     ethtool_link_ksettings_zero_link_mode(cmd, supported);
>> +     ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Half);
>> +     ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
>> +
>> +     cmd->base.speed = SPEED_10;
>> +     cmd->base.duplex = DUPLEX_HALF;
>> +     cmd->base.port  = PORT_TP;
>> +     cmd->base.autoneg = AUTONEG_DISABLE;
>> +
>> +     return 0;
>> +}
>> +
>> +static void lan865x_set_msglevel(struct net_device *netdev, u32 val)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +
>> +     priv->msg_enable = val;
>> +}
>> +
>> +static u32 lan865x_get_msglevel(struct net_device *netdev)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +
>> +     return priv->msg_enable;
>> +}
>> +
>> +static void
>> +lan865x_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
>> +{
>> +     strscpy(info->driver, DRV_NAME, sizeof(info->driver));
>> +     strscpy(info->version, DRV_VERSION, sizeof(info->version));
>> +     strscpy(info->bus_info,
>> +             dev_name(netdev->dev.parent), sizeof(info->bus_info));
>> +}
>> +
>> +static const struct ethtool_ops lan865x_ethtool_ops = {
>> +     .get_drvinfo    = lan865x_get_drvinfo,
>> +     .get_msglevel   = lan865x_get_msglevel,
>> +     .set_msglevel   = lan865x_set_msglevel,
>> +     .get_link_ksettings = lan865x_get_link_ksettings,
>> +     .set_link_ksettings = lan865x_set_link_ksettings,
>> +};
>> +
>> +static void lan865x_tx_timeout(struct net_device *netdev, unsigned int txqueue)
>> +{
>> +     netdev->stats.tx_errors++;
>> +}
>> +
>> +static int lan865x_set_mac_address(struct net_device *netdev, void *addr)
>> +{
>> +     struct sockaddr *address = addr;
>> +
>> +     if (netif_running(netdev))
>> +             return -EBUSY;
>> +     if (!is_valid_ether_addr(address->sa_data))
>> +             return -EADDRNOTAVAIL;
>> +
>> +     eth_hw_addr_set(netdev, address->sa_data);
>> +     return lan865x_set_hw_macaddr(netdev);
>> +}
>> +
>> +static u32 lan865x_hash(u8 addr[ETH_ALEN])
>> +{
>> +     return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f;
>> +}
>> +
>> +static void lan865x_set_multicast_list(struct net_device *netdev)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +     u32 regval = 0;
>> +
>> +     if (netdev->flags & IFF_PROMISC) {
>> +             /* Enabling promiscuous mode */
>> +             regval |= MAC_PROMISCUOUS_MODE;
>> +             regval &= (~MAC_MULTICAST_MODE);
>> +             regval &= (~MAC_UNICAST_MODE);
>> +     } else if (netdev->flags & IFF_ALLMULTI) {
>> +             /* Enabling all multicast mode */
>> +             regval &= (~MAC_PROMISCUOUS_MODE);
>> +             regval |= MAC_MULTICAST_MODE;
>> +             regval &= (~MAC_UNICAST_MODE);
>> +     } else if (!netdev_mc_empty(netdev)) {
>> +             /* Enabling specific multicast addresses */
>> +             struct netdev_hw_addr *ha;
>> +             u32 hash_lo = 0;
>> +             u32 hash_hi = 0;
>> +
>> +             netdev_for_each_mc_addr(ha, netdev) {
>> +                     u32 bit_num = lan865x_hash(ha->addr);
>> +                     u32 mask = 1 << (bit_num & 0x1f);
>> +
>> +                     if (bit_num & 0x20)
>> +                             hash_hi |= mask;
>> +                     else
>> +                             hash_lo |= mask;
>> +             }
>> +             if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHH, &hash_hi, 1)) {
>> +                     if (netif_msg_timer(priv))
>> +                             netdev_err(netdev, "Failed to write reg_hashh");
>> +                     return;
>> +             }
>> +             if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHL, &hash_lo, 1)) {
>> +                     if (netif_msg_timer(priv))
>> +                             netdev_err(netdev, "Failed to write reg_hashl");
>> +                     return;
>> +             }
>> +             regval &= (~MAC_PROMISCUOUS_MODE);
>> +             regval &= (~MAC_MULTICAST_MODE);
>> +             regval |= MAC_UNICAST_MODE;
>> +     } else {
>> +             /* enabling local mac address only */
>> +             if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHH, &regval, 1)) {
>> +                     if (netif_msg_timer(priv))
>> +                             netdev_err(netdev, "Failed to write reg_hashh");
>> +                     return;
>> +             }
>> +             if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHL, &regval, 1)) {
>> +                     if (netif_msg_timer(priv))
>> +                             netdev_err(netdev, "Failed to write reg_hashl");
>> +                     return;
>> +             }
>> +     }
>> +     if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CONFIG, &regval, 1)) {
>> +             if (netif_msg_timer(priv))
>> +                     netdev_err(netdev, "Failed to enable promiscuous mode");
>> +     }
>> +}
>> +
>> +static netdev_tx_t lan865x_send_packet(struct sk_buff *skb,
>> +                                    struct net_device *netdev)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +
>> +     return oa_tc6_send_eth_pkt(priv->tc6, skb);
>> +}
>> +
>> +static int lan865x_hw_disable(struct lan865x_priv *priv)
>> +{
>> +     u32 regval = NW_DISABLE;
>> +
>> +     if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CTRL, &regval, 1))
>> +             return -ENODEV;
>> +
>> +     return 0;
>> +}
>> +
>> +static int lan865x_net_close(struct net_device *netdev)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +     int ret;
>> +
>> +     netif_stop_queue(netdev);
>> +     ret = lan865x_hw_disable(priv);
>> +     if (ret) {
>> +             if (netif_msg_ifup(priv))
>> +                     netdev_err(netdev, "Failed to disable the hardware\n");
>> +             return ret;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int lan865x_hw_enable(struct lan865x_priv *priv)
>> +{
>> +     u32 regval = NW_TX_STATUS | NW_RX_STATUS;
>> +
>> +     if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CTRL, &regval, 1))
>> +             return -ENODEV;
>> +
>> +     return 0;
>> +}
>> +
>> +static int lan865x_net_open(struct net_device *netdev)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +     int ret;
>> +
>> +     if (!is_valid_ether_addr(netdev->dev_addr)) {
>> +             if (netif_msg_ifup(priv))
>> +                     netdev_err(netdev, "Invalid MAC address %pm", netdev->dev_addr);
>> +             return -EADDRNOTAVAIL;
>> +     }
>> +     if (lan865x_hw_disable(priv)) {
>> +             if (netif_msg_ifup(priv))
>> +                     netdev_err(netdev, "Failed to disable the hardware\n");
>> +             return -ENODEV;
>> +     }
>> +     ret = lan865x_set_hw_macaddr(netdev);
>> +     if (ret != 0)
>> +             return ret;
>> +
>> +     if (lan865x_hw_enable(priv) != 0) {
>> +             if (netif_msg_ifup(priv))
>> +                     netdev_err(netdev, "Failed to enable hardware\n");
>> +             return -ENODEV;
>> +     }
>> +     netif_start_queue(netdev);
>> +
>> +     return 0;
>> +}
>> +
>> +static const struct net_device_ops lan865x_netdev_ops = {
>> +     .ndo_open               = lan865x_net_open,
>> +     .ndo_stop               = lan865x_net_close,
>> +     .ndo_start_xmit         = lan865x_send_packet,
>> +     .ndo_set_rx_mode        = lan865x_set_multicast_list,
>> +     .ndo_set_mac_address    = lan865x_set_mac_address,
>> +     .ndo_tx_timeout         = lan865x_tx_timeout,
>> +     .ndo_validate_addr      = eth_validate_addr,
>> +};
>> +
>> +static int lan865x_get_dt_data(struct lan865x_priv *priv)
>> +{
>> +     struct spi_device *spi = priv->spi;
>> +     int ret;
>> +
>> +     if (of_property_present(spi->dev.of_node, "oa-chunk-size")) {
>> +             ret = of_property_read_u32(spi->dev.of_node, "oa-chunk-size",
>> +                                        &priv->cps);
>> +             if (ret < 0)
>> +                     return ret;
>> +     } else {
>> +             priv->cps = 64;
>> +             dev_info(&spi->dev, "Property oa-chunk-size is not found in dt and proceeding with the size 64\n");
>> +     }
>> +
>> +     if (of_property_present(spi->dev.of_node, "oa-tx-cut-through"))
>> +             priv->txcte = true;
>> +     else
>> +             dev_info(&spi->dev, "Property oa-tx-cut-through is not found in dt and proceeding with tx store and forward mode\n");
>> +
>> +     if (of_property_present(spi->dev.of_node, "oa-rx-cut-through"))
>> +             priv->rxcte = true;
>> +     else
>> +             dev_info(&spi->dev, "Property oa-rx-cut-through is not found in dt and proceeding with rx store and forward mode\n");
>> +
>> +     if (of_property_present(spi->dev.of_node, "oa-protected"))
>> +             priv->protected = true;
>> +     else
>> +             dev_info(&spi->dev, "Property oa-protected is not found in dt and proceeding with protection enabled\n");
>> +
>> +     return 0;
>> +}
>> +
>> +static int lan865x_probe(struct spi_device *spi)
>> +{
>> +     struct net_device *netdev;
>> +     struct lan865x_priv *priv;
>> +     u32 regval;
>> +     int ret;
>> +
>> +     netdev = alloc_etherdev(sizeof(struct lan865x_priv));
>> +     if (!netdev)
>> +             return -ENOMEM;
>> +
>> +     priv = netdev_priv(netdev);
>> +     priv->netdev = netdev;
>> +     priv->spi = spi;
>> +     priv->msg_enable = 0;
>> +     spi_set_drvdata(spi, priv);
>> +     SET_NETDEV_DEV(netdev, &spi->dev);
>> +
>> +     ret = lan865x_get_dt_data(priv);
>> +     if (ret)
>> +             return ret;
> 
> Has not free allocated netdev.
Ok noted, will correct it in the next revision.
> 
>> +
>> +     spi->rt = true;
>> +     spi_setup(spi);
>> +
>> +     priv->tc6 = oa_tc6_init(spi, netdev);
>> +     if (!priv->tc6) {
>> +             ret = -ENOMEM;
>> +             goto error_oa_tc6_init;
>> +     }
>> +
>> +     if (priv->cps == 32) {
>> +             regval = CCS_Q0_TX_CFG_32;
>> +             ret = oa_tc6_write_register(priv->tc6, CCS_Q0_TX_CFG, &regval, 1);
>> +             if (ret)
>> +                     return ret;
> 
> No resources recycle. Please check.
Ok noted, will correct it in the next revision.
> 
>> +
>> +             regval = CCS_Q0_RX_CFG_32;
>> +             ret = oa_tc6_write_register(priv->tc6, CCS_Q0_RX_CFG, &regval, 1);
>> +             if (ret)
>> +                     return ret;
> 
> No resources recycle. Please check.
Ok noted, will correct it in the next revision.

Best Regards,
Parthiban V
> 
>> +     }
>> +
>> +     if (oa_tc6_configure(priv->tc6, priv->cps, priv->protected, priv->txcte,
>> +                          priv->rxcte))
>> +             goto err_macphy_config;
>> +
>> +     ret = lan865x_phy_init(priv);
>> +     if (ret)
>> +             goto error_phy;
>> +
>> +     if (device_get_ethdev_address(&spi->dev, netdev))
>> +             eth_hw_addr_random(netdev);
>> +
>> +     ret = lan865x_set_hw_macaddr(netdev);
>> +     if (ret) {
>> +             if (netif_msg_probe(priv))
>> +                     dev_err(&spi->dev, "Failed to configure MAC");
>> +             goto error_set_mac;
>> +     }
>> +
>> +     netdev->if_port = IF_PORT_10BASET;
>> +     netdev->irq = spi->irq;
>> +     netdev->netdev_ops = &lan865x_netdev_ops;
>> +     netdev->watchdog_timeo = TX_TIMEOUT;
>> +     netdev->ethtool_ops = &lan865x_ethtool_ops;
>> +     ret = register_netdev(netdev);
>> +     if (ret) {
>> +             if (netif_msg_probe(priv))
>> +                     dev_err(&spi->dev, "Register netdev failed (ret = %d)",
>> +                             ret);
>> +             goto error_netdev_register;
>> +     }
>> +
>> +     phy_start(priv->phydev);
>> +     return 0;
>> +
>> +error_netdev_register:
>> +error_set_mac:
>> +     phy_disconnect(priv->phydev);
>> +     mdiobus_unregister(priv->mdiobus);
>> +     mdiobus_free(priv->mdiobus);
>> +error_phy:
>> +err_macphy_config:
>> +     oa_tc6_deinit(priv->tc6);
>> +error_oa_tc6_init:
>> +     free_netdev(priv->netdev);
>> +     return ret;
>> +}
>> +
>> +static void lan865x_remove(struct spi_device *spi)
>> +{
>> +     struct lan865x_priv *priv = spi_get_drvdata(spi);
>> +
>> +     phy_stop(priv->phydev);
>> +     phy_disconnect(priv->phydev);
>> +     mdiobus_unregister(priv->mdiobus);
>> +     mdiobus_free(priv->mdiobus);
>> +     unregister_netdev(priv->netdev);
>> +     if (oa_tc6_deinit(priv->tc6))
>> +             dev_err(&spi->dev, "Failed to deinitialize oa tc6\n");
>> +     free_netdev(priv->netdev);
>> +}
>> +
>> +#ifdef CONFIG_OF
>> +static const struct of_device_id lan865x_dt_ids[] = {
>> +     { .compatible = "microchip,lan865x" },
>> +     { /* Sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, lan865x_dt_ids);
>> +#endif
>> +
>> +#ifdef CONFIG_ACPI
>> +static const struct acpi_device_id lan865x_acpi_ids[] = {
>> +     { .id = "LAN865X",
>> +     },
>> +     {},
>> +};
>> +MODULE_DEVICE_TABLE(acpi, lan865x_acpi_ids);
>> +#endif
>> +
>> +static struct spi_driver lan865x_driver = {
>> +     .driver = {
>> +             .name = DRV_NAME,
>> +#ifdef CONFIG_OF
>> +             .of_match_table = lan865x_dt_ids,
>> +#endif
>> +#ifdef CONFIG_ACPI
>> +                .acpi_match_table = ACPI_PTR(lan865x_acpi_ids),
>> +#endif
>> +      },
>> +     .probe = lan865x_probe,
>> +     .remove = lan865x_remove,
>> +};
>> +module_spi_driver(lan865x_driver);
>> +
>> +MODULE_DESCRIPTION(DRV_NAME " 10Base-T1S MACPHY Ethernet Driver");
>> +MODULE_AUTHOR("Parthiban Veerasooran <parthiban.veerasooran@microchip.com>");
>> +MODULE_LICENSE("GPL");
>> +MODULE_ALIAS("spi:" DRV_NAME);
>>


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-11 12:51   ` Ziyang Xuan (William)
@ 2023-09-12 12:10     ` Andrew Lunn
  2023-09-12 12:28     ` Parthiban.Veerasooran
  1 sibling, 0 replies; 85+ messages in thread
From: Andrew Lunn @ 2023-09-12 12:10 UTC (permalink / raw)
  To: Ziyang Xuan (William)
  Cc: Parthiban Veerasooran, davem, edumazet, kuba, pabeni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, steen.hegelund,
	rdunlap, horms, casper.casan, netdev, devicetree, linux-kernel,
	linux-doc, horatiu.vultur, Woojung.Huh, Nicolas.Ferre,
	UNGLinuxDriver, Thorsten.Kummermehr

> > +int oa_tc6_deinit(struct oa_tc6 *tc6)
> >  {
> > -	kfree(tc6);
> > +	int ret;
> > +
> > +	devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
> > +	ret = kthread_stop(tc6->tc6_task);
> 
> kthread_stop() will the result of threadfn(). Here mean that if threadfn()
> return non-zero, deinit() will fail. But the KTHREAD_SHOULD_STOP already be set.
> And oa_tc6_handler() will end. Please check it is what you want.

Hi Ziyang

Please trim emails when replying to just the relevant text. Otherwise
you need to page down, page down, page down again and again and might
miss parts of your reply.

     Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 6/6] microchip: lan865x: add device-tree support for Microchip's LAN865X MACPHY
  2023-09-10 10:55   ` Krzysztof Kozlowski
@ 2023-09-12 12:15     ` Parthiban.Veerasooran
  2023-09-12 13:17       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-12 12:15 UTC (permalink / raw)
  To: krzysztof.kozlowski
  Cc: netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	andrew

Hi Krzysztof,

Thank you for reviewing the patch.

On 10/09/23 4:25 pm, Krzysztof Kozlowski wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On 08/09/2023 16:29, Parthiban Veerasooran wrote:
>> Add device-tree support for Microchip's LAN865X MACPHY for configuring
>> the OPEN Alliance 10BASE-T1x MACPHY Serial Interface parameters.
> 
> Please use subject prefixes matching the subsystem. You can get them for
> example with `git log --oneline -- DIRECTORY_OR_FILE` on the directory
> your patch is touching.
Ok sure, so it will become like,

dt-bindings: net: add device-tree support for Microchip's LAN865X MACPHY

I will correct it in the next revision.
> 
>>
>> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
>> ---
>>   .../bindings/net/microchip,lan865x.yaml       | 54 +++++++++++++++++++
>>   MAINTAINERS                                   |  1 +
>>   2 files changed, 55 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/net/microchip,lan865x.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/net/microchip,lan865x.yaml b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
>> new file mode 100644
>> index 000000000000..3465b2c97690
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
>> @@ -0,0 +1,54 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/net/microchip,lan865x.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Microchip LAN8650/1 10BASE-T1S MACPHY Ethernet Controllers
>> +
>> +maintainers:
>> +  - Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
>> +
>> +description: |
>> +  Device tree properties for LAN8650/1 10BASE-T1S MACPHY Ethernet
> 
> Drop "Device tree properties for" and instead describe the hardware.
sure, will do it.
> 
>> +  controller.
>> +
>> +allOf:
>> +  - $ref: ethernet-controller.yaml#
>> +
>> +properties:
>> +  compatible:
>> +    items:
> 
> No need for items. Just enum.
Ok noted.
> 
> 
>> +      - enum:
>> +          - microchip,lan865x
> 
> No wildcards in compatibles.
Yes then we don't need enum also isn't it?
> 
> Missing blank line.
Ok will add it.
> 
> 
> 
>> +  reg:
>> +    maxItems: 1
>> +
>> +  local-mac-address: true
>> +  oa-chunk-size: true
>> +  oa-tx-cut-through: true
>> +  oa-rx-cut-through: true
>> +  oa-protected: true
> 
> What are all these? Where are they defined that you skip description,
> type and vendor prefix?
Ok missed it. Will do it in the next revision.
> 
>> +
>> +required:
>> +  - compatible
>> +  - reg
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> +  - |
>> +    spi {
>> +        #address-cells = <1>;
>> +        #size-cells = <0>;
>> +
>> +        ethernet@1{
> 
> Missing space
Ok will add it.
> 
>> +            compatible = "microchip,lan865x";
>> +            reg = <1>; /* CE0 */
> 
> CE0? chip-select? What does this comment mean in this context?
Yes it is chip-select. Will add proper comment.

Best Regards,
Parthiban V
> 
>> +            local-mac-address = [04 05 06 01 02 03];
>> +            oa-chunk-size = <64>;
>> +            oa-tx-cut-through;
>> +            oa-rx-cut-through;
>> +            oa-protected;
> 
> 
> 
> Best regards,
> Krzysztof
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-11 12:51   ` Ziyang Xuan (William)
  2023-09-12 12:10     ` Andrew Lunn
@ 2023-09-12 12:28     ` Parthiban.Veerasooran
  1 sibling, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-12 12:28 UTC (permalink / raw)
  To: william.xuanziyang
  Cc: netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	andrew

Hi Ziyang,

On 11/09/23 6:21 pm, Ziyang Xuan (William) wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> Register MAC-PHY interrupt and handle reset complete interrupt. Reset
>> complete bit is set when the MAC-PHY reset complete and ready for
>> configuration. When it is set, it will generate a non-maskable interrupt
>> to alert the SPI host. Additionally reset complete bit in the STS0
>> register has to be written by one upon reset complete to clear the
>> interrupt.
>>
>> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
>> ---
>>   drivers/net/ethernet/oa_tc6.c | 141 ++++++++++++++++++++++++++++++++--
>>   include/linux/oa_tc6.h        |  16 +++-
>>   2 files changed, 150 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
>> index 613cf034430a..0019f70345b6 100644
>> --- a/drivers/net/ethernet/oa_tc6.c
>> +++ b/drivers/net/ethernet/oa_tc6.c
>> @@ -6,6 +6,7 @@
>>    */
>>
>>   #include <linux/bitfield.h>
>> +#include <linux/interrupt.h>
>>   #include <linux/oa_tc6.h>
>>
>>   static int oa_tc6_spi_transfer(struct spi_device *spi, u8 *ptx, u8 *prx,
>> @@ -160,10 +161,16 @@ int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
>>        if (ret)
>>                goto err_ctrl;
>>
>> -     /* Check echoed/received control reply */
>> -     ret = oa_tc6_check_control(tc6, tx_buf, rx_buf, len, wnr, ctrl_prot);
>> -     if (ret)
>> -             goto err_ctrl;
>> +     /* In case of reset write, the echoed control command doesn't have any
>> +      * valid data. So no need to check for error.
>> +      */
>> +     if (addr != OA_TC6_RESET) {
>> +             /* Check echoed/received control reply */
>> +             ret = oa_tc6_check_control(tc6, tx_buf, rx_buf, len, wnr,
>> +                                        ctrl_prot);
>> +             if (ret)
>> +                     goto err_ctrl;
>> +     }
>>
>>        if (!wnr) {
>>                /* Copy read data from the rx data in case of ctrl read */
>> @@ -186,6 +193,88 @@ int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
>>        return ret;
>>   }
>>
>> +static int oa_tc6_handler(void *data)
>> +{
>> +     struct oa_tc6 *tc6 = data;
>> +     u32 regval;
>> +     int ret;
>> +
>> +     while (likely(!kthread_should_stop())) {
>> +             wait_event_interruptible(tc6->tc6_wq, tc6->int_flag ||
>> +                                      kthread_should_stop());
>> +             if (tc6->int_flag) {
>> +                     tc6->int_flag = false;
>> +                     ret = oa_tc6_perform_ctrl(tc6, OA_TC6_STS0, &regval, 1,
>> +                                               false, false);
>> +                     if (ret) {
>> +                             dev_err(&tc6->spi->dev, "Failed to read STS0\n");
>> +                             continue;
>> +                     }
>> +                     /* Check for reset complete interrupt status */
>> +                     if (regval & RESETC) {
>> +                             regval = RESETC;
>> +                             /* SPI host should write RESETC bit with one to
>> +                              * clear the reset interrupt status.
>> +                              */
>> +                             ret = oa_tc6_perform_ctrl(tc6, OA_TC6_STS0,
>> +                                                       &regval, 1, true,
>> +                                                       false);
>> +                             if (ret) {
>> +                                     dev_err(&tc6->spi->dev,
>> +                                             "Failed to write STS0\n");
>> +                                     continue;
>> +                             }
>> +                             complete(&tc6->rst_complete);
>> +                     }
>> +             }
>> +     }
>> +     return 0;
>> +}
>> +
>> +static irqreturn_t macphy_irq(int irq, void *dev_id)
>> +{
>> +     struct oa_tc6 *tc6 = dev_id;
>> +
>> +     /* Wake tc6 task to perform interrupt action */
>> +     tc6->int_flag = true;
>> +     wake_up_interruptible(&tc6->tc6_wq);
>> +
>> +     return IRQ_HANDLED;
>> +}
>> +
>> +static int oa_tc6_sw_reset(struct oa_tc6 *tc6)
>> +{
>> +     long timeleft;
>> +     u32 regval;
>> +     int ret;
>> +
>> +     /* Perform software reset with both protected and unprotected control
>> +      * commands because the driver doesn't know the current status of the
>> +      * MAC-PHY.
>> +      */
>> +     regval = SW_RESET;
>> +     reinit_completion(&tc6->rst_complete);
>> +     ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1, true, false);
>> +     if (ret) {
>> +             dev_err(&tc6->spi->dev, "RESET register write failed\n");
>> +             return ret;
>> +     }
>> +
>> +     ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1, true, true);
>> +     if (ret) {
>> +             dev_err(&tc6->spi->dev, "RESET register write failed\n");
>> +             return ret;
>> +     }
>> +     timeleft = wait_for_completion_interruptible_timeout(&tc6->rst_complete,
>> +                                                          msecs_to_jiffies(1));
>> +     if (timeleft <= 0) {
>> +             dev_err(&tc6->spi->dev, "MAC-PHY reset failed\n");
>> +             return -ENODEV;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>>   int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len)
>>   {
>>        return oa_tc6_perform_ctrl(tc6, addr, val, len, true, tc6->ctrl_prot);
>> @@ -201,6 +290,7 @@ EXPORT_SYMBOL_GPL(oa_tc6_read_register);
>>   struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
>>   {
>>        struct oa_tc6 *tc6;
>> +     int ret;
>>
>>        if (!spi)
>>                return NULL;
>> @@ -211,12 +301,51 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
>>
>>        tc6->spi = spi;
>>
>> +     /* Used for triggering the OA TC6 task */
>> +     init_waitqueue_head(&tc6->tc6_wq);
>> +
>> +     init_completion(&tc6->rst_complete);
>> +
>> +     /* This task performs the SPI transfer */
>> +     tc6->tc6_task = kthread_run(oa_tc6_handler, tc6, "OA TC6 Task");
>> +     if (IS_ERR(tc6->tc6_task))
>> +             goto err_tc6_task;
>> +
>> +     /* Set the highest priority to the tc6 task as it is time critical */
>> +     sched_set_fifo(tc6->tc6_task);
>> +
>> +     /* Register MAC-PHY interrupt service routine */
>> +     ret = devm_request_irq(&spi->dev, spi->irq, macphy_irq, 0, "macphy int",
>> +                            tc6);
>> +     if ((ret != -ENOTCONN) && ret < 0) {
>> +             dev_err(&spi->dev, "Error attaching macphy irq %d\n", ret);
>> +             goto err_macphy_irq;
>> +     }
>> +
>> +     /* Perform MAC-PHY software reset */
>> +     if (oa_tc6_sw_reset(tc6))
>> +             goto err_macphy_reset;
>> +
>>        return tc6;
>> +
>> +err_macphy_reset:
>> +     devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
>> +err_macphy_irq:
>> +     kthread_stop(tc6->tc6_task);
>> +err_tc6_task:
>> +     kfree(tc6);
>> +     return NULL;
>>   }
>>   EXPORT_SYMBOL_GPL(oa_tc6_init);
>>
>> -void oa_tc6_deinit(struct oa_tc6 *tc6)
>> +int oa_tc6_deinit(struct oa_tc6 *tc6)
>>   {
>> -     kfree(tc6);
>> +     int ret;
>> +
>> +     devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
>> +     ret = kthread_stop(tc6->tc6_task);
> 
> kthread_stop() will the result of threadfn(). Here mean that if threadfn()
> return non-zero, deinit() will fail. But the KTHREAD_SHOULD_STOP already be set.
> And oa_tc6_handler() will end. Please check it is what you want.
Ok will handle it properly in the next revision.

Best Regards,
Parthiban V
> 
>> +     if (!ret)
>> +             kfree(tc6);
>> +     return ret;
>>   }
>>   EXPORT_SYMBOL_GPL(oa_tc6_deinit);
>> diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
>> index 5e0a58ab1dcd..315f061c2dfe 100644
>> --- a/include/linux/oa_tc6.h
>> +++ b/include/linux/oa_tc6.h
>> @@ -17,15 +17,29 @@
>>   #define CTRL_HDR_LEN GENMASK(7, 1)   /* Length */
>>   #define CTRL_HDR_P   BIT(0)          /* Parity Bit */
>>
>> +/* Open Alliance TC6 Standard Control and Status Registers */
>> +#define OA_TC6_RESET 0x0003          /* Reset Control and Status Register */
>> +#define OA_TC6_STS0  0x0008          /* Status Register #0 */
>> +
>> +/* RESET register field */
>> +#define SW_RESET     BIT(0)          /* Software Reset */
>> +
>> +/* STATUS0 register field */
>> +#define RESETC               BIT(6)          /* Reset Complete */
>> +
>>   #define TC6_HDR_SIZE 4               /* Ctrl command header size as per OA */
>>   #define TC6_FTR_SIZE 4               /* Ctrl command footer size ss per OA */
>>
>>   struct oa_tc6 {
>>        struct spi_device *spi;
>>        bool ctrl_prot;
>> +     struct task_struct *tc6_task;
>> +     wait_queue_head_t tc6_wq;
>> +     bool int_flag;
>> +     struct completion rst_complete;
>>   };
>>
>>   struct oa_tc6 *oa_tc6_init(struct spi_device *spi);
>> -void oa_tc6_deinit(struct oa_tc6 *tc6);
>> +int oa_tc6_deinit(struct oa_tc6 *tc6);
>>   int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
>>   int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 value[], u8 len);
>>


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-09 13:39   ` Andrew Lunn
@ 2023-09-12 12:44     ` Parthiban.Veerasooran
  2023-09-13  2:19       ` Andrew Lunn
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-12 12:44 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

Thank you for reviewing the patch.

On 09/09/23 7:09 pm, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> +     /* Register MAC-PHY interrupt service routine */
>> +     ret = devm_request_irq(&spi->dev, spi->irq, macphy_irq, 0, "macphy int",
>> +                            tc6);
> 
> It looks like using threaded interrupts could save a lot of
> complexity. Let the IRQ core handle all the tasklet stuff for you.
Ok. If I understand correctly, I have to use devm_request_threaded_irq() 
instead of devm_request_irq() and let the thread handler registered with 
the devm_request_threaded_irq() function to perform interrupt activity 
directly?

Best Regards,
Parthiban V
> 
>          Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-09 13:33   ` Andrew Lunn
@ 2023-09-12 13:03     ` Parthiban.Veerasooran
  2023-09-13  1:32       ` Andrew Lunn
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-12 13:03 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 09/09/23 7:03 pm, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On Fri, Sep 08, 2023 at 07:59:14PM +0530, Parthiban Veerasooran wrote:
>> Implement register read/write interface according to the control
>> communication specified in the OPEN Alliance 10BASE-T1x MACPHY Serial
>> Interface document. Control transactions consist of one or more control
>> commands. Control commands are used by the SPI host to read and write
>> registers within the MAC-PHY. Each control commands are composed of a
>> 32-bit control command header followed by register data.
>>
>> Control write commands can write either a single register or multiple
>> consecutive registers. When multiple consecutive registers are written,
>> the address is automatically post-incremented by the MAC-PHY. The write
>> command and data is also echoed from the MAC-PHY back to the SPI host to
>> enable the SPI host to identify which register write failed in the case
>> of any bus errors.
>>
>> Control read commands can read either a single register or multiple
>> consecutive registers. When multiple consecutive registers are read, the
>> address is automatically post-incremented by the MAC-PHY.
>>
>> The register data being read or written can be protected against simple
>> bit errors. When enabled by setting the Protection Enable (PROTE) bit in
>> the CONFIG0 register, protection is accomplished by duplication of each
>> 32-bit word containing register data with its ones’ complement. Errors
>> are detected at the receiver by performing a simple exclusive-OR (XOR) of
>> each received 32-bit word containing register data with its received
>> complement and detecting if there are any zeros in the result.
>>
>> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
>> ---
>>   Documentation/networking/oa-tc6-framework.rst | 231 ++++++++++++++++++
>>   MAINTAINERS                                   |   8 +
>>   drivers/net/ethernet/oa_tc6.c                 | 222 +++++++++++++++++
>>   include/linux/oa_tc6.h                        |  31 +++
> 
> I'm surprised there is no kconfig and Makefile changes here. I would
> expect this is compiled as a module, which the vendor code can then
> make use of.
Ok, actually this framework is used by vendor specific driver 
(lan865x.c) later with the Makefile update like below in the directory 
drivers/net/ethernet/microchip/,

obj-$(CONFIG_LAN865X) += lan865x_t1s.o 

lan865x_t1s-objs := lan865x.o ../oa_tc6.o

If I understand you correctly, this framework has to include the module 
initialization as well using the below APIs and has to be compiled as a 
loadable module so that other vendors module can make use of this, isn't it?

module_init(oa_tc6_init);
module_exit(oa_tc6_exit);

Best Regards,
Parthiban V
> 
>       Andrew
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 6/6] microchip: lan865x: add device-tree support for Microchip's LAN865X MACPHY
  2023-09-12 12:15     ` Parthiban.Veerasooran
@ 2023-09-12 13:17       ` Krzysztof Kozlowski
  2023-09-19 10:51         ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Krzysztof Kozlowski @ 2023-09-12 13:17 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	andrew

On 12/09/2023 14:15, Parthiban.Veerasooran@microchip.com wrote:
> Hi Krzysztof,
> 
> Thank you for reviewing the patch.
> 
> On 10/09/23 4:25 pm, Krzysztof Kozlowski wrote:
>> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>>
>> On 08/09/2023 16:29, Parthiban Veerasooran wrote:
>>> Add device-tree support for Microchip's LAN865X MACPHY for configuring
>>> the OPEN Alliance 10BASE-T1x MACPHY Serial Interface parameters.
>>
>> Please use subject prefixes matching the subsystem. You can get them for
>> example with `git log --oneline -- DIRECTORY_OR_FILE` on the directory
>> your patch is touching.
> Ok sure, so it will become like,
> 
> dt-bindings: net: add device-tree support for Microchip's LAN865X MACPHY
> 
> I will correct it in the next revision.

"device-tree support for " is redundant, drop

>>
>>>
>>> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
>>> ---
>>>   .../bindings/net/microchip,lan865x.yaml       | 54 +++++++++++++++++++
>>>   MAINTAINERS                                   |  1 +
>>>   2 files changed, 55 insertions(+)
>>>   create mode 100644 Documentation/devicetree/bindings/net/microchip,lan865x.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/net/microchip,lan865x.yaml b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
>>> new file mode 100644
>>> index 000000000000..3465b2c97690
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
>>> @@ -0,0 +1,54 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/net/microchip,lan865x.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Microchip LAN8650/1 10BASE-T1S MACPHY Ethernet Controllers
>>> +
>>> +maintainers:
>>> +  - Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
>>> +
>>> +description: |
>>> +  Device tree properties for LAN8650/1 10BASE-T1S MACPHY Ethernet
>>
>> Drop "Device tree properties for" and instead describe the hardware.
> sure, will do it.
>>
>>> +  controller.
>>> +
>>> +allOf:
>>> +  - $ref: ethernet-controller.yaml#
>>> +
>>> +properties:
>>> +  compatible:
>>> +    items:
>>
>> No need for items. Just enum.
> Ok noted.
>>
>>
>>> +      - enum:
>>> +          - microchip,lan865x
>>
>> No wildcards in compatibles.
> Yes then we don't need enum also isn't it?

I don't see correlation between these two. Please read the writing
bindings guidelines.


>>
>> Missing blank line.
> Ok will add it.
>>
>>
>>
>>> +  reg:
>>> +    maxItems: 1
>>> +
>>> +  local-mac-address: true
>>> +  oa-chunk-size: true
>>> +  oa-tx-cut-through: true
>>> +  oa-rx-cut-through: true
>>> +  oa-protected: true
>>
>> What are all these? Where are they defined that you skip description,
>> type and vendor prefix?
> Ok missed it. Will do it in the next revision.

No, drop them or explain why they are hardware properties.

>>
>>> +
>>> +required:
>>> +  - compatible
>>> +  - reg
>>> +
>>> +additionalProperties: false
>>> +
>>> +examples:
>>> +  - |
>>> +    spi {
>>> +        #address-cells = <1>;
>>> +        #size-cells = <0>;
>>> +
>>> +        ethernet@1{
>>
>> Missing space
> Ok will add it.
>>
>>> +            compatible = "microchip,lan865x";
>>> +            reg = <1>; /* CE0 */
>>
>> CE0? chip-select? What does this comment mean in this context?
> Yes it is chip-select. Will add proper comment.

Why? isn't reg obvious?

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface
  2023-09-10 17:58   ` Simon Horman
@ 2023-09-12 13:47     ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-12 13:47 UTC (permalink / raw)
  To: horms
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, casper.casan, andrew,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Simon,

Thank you for reviewing the patch.

On 10/09/23 11:28 pm, Simon Horman wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On Fri, Sep 08, 2023 at 07:59:17PM +0530, Parthiban Veerasooran wrote:
>> The ethernet frame to be sent to MAC-PHY is converted into multiple
>> transmit data chunks. A transmit data chunk consists of a 4-byte data
>> header followed by the transmit data chunk payload.
>>
>> The received ethernet frame from the network is converted into multiple
>> receive data chunks by the MAC-PHY and a receive data chunk consists of
>> the receive data chunk payload followed by a 4-byte data footer at the
>> end.
>>
>> The MAC-PHY shall support a default data chunk payload size of 64 bytes.
>> Data chunk payload sizes of 32, 16, or 8 bytes may also be supported. The
>> data chunk payload is always a multiple of 4 bytes.
>>
>> The 4-byte data header occurs at the beginning of each transmit data
>> chunk on MOSI and the 4-byte data footer occurs at the end of each
>> receive data chunk on MISO. The data header and footer contain the
>> information needed to determine the validity and location of the transmit
>> and receive frame data within the data chunk payload. Ethernet frames
>> shall be aligned to a 32-bit boundary within the data chunk payload.
>>
>> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
> 
> Hi Parthiban,
> 
> this patch seems to introduce new Sparse warnings.
> Please consider addressing those, and ideally the warnings
> flagged in the existing oa_tc6.c code.
Sure, will check it in the next revision.

Best Regards,
Parthiban V
> 
> Thanks in advance!
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-12 13:03     ` Parthiban.Veerasooran
@ 2023-09-13  1:32       ` Andrew Lunn
  2023-09-21 12:27         ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-13  1:32 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> If I understand you correctly, this framework has to include the module 
> initialization as well using the below APIs and has to be compiled as a 
> loadable module so that other vendors module can make use of this, isn't it?
> 
> module_init(oa_tc6_init);
> module_exit(oa_tc6_exit);

You should not need these, unless there is actions which need to be
taken when the module is loaded. If there are no actions, it is purely
a library, don't have them. The module dependency tracking code will
see that the MAC driver modules has dependencies on symbols in this
library module, and will load it first. The MAC driver is then loaded,
and the kernel linker will resolve the missing symbols in the MAC
driver to those in the library. It also means that there is only ever
one copy of the library in the kernel, even if there is multiple MAC
drivers using it.

       Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-08 14:29 ` [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface Parthiban Veerasooran
  2023-09-09 13:33   ` Andrew Lunn
@ 2023-09-13  1:36   ` Andrew Lunn
  2023-09-19 11:40     ` Parthiban.Veerasooran
  2023-09-13  2:11   ` Andrew Lunn
  2023-09-13  2:16   ` Andrew Lunn
  3 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-13  1:36 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> +int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
> +			bool wnr, bool ctrl_prot)

Please add some kerneldoc headers for the API method exposed
here. These are what the MAC driver should be using, so they should be
reasonably well documented.

Thanks
	   Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-08 14:29 ` [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface Parthiban Veerasooran
  2023-09-09 13:33   ` Andrew Lunn
  2023-09-13  1:36   ` Andrew Lunn
@ 2023-09-13  2:11   ` Andrew Lunn
  2023-09-19 11:38     ` Parthiban.Veerasooran
  2023-09-13  2:16   ` Andrew Lunn
  3 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-13  2:11 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> +static bool oa_tc6_get_parity(u32 p)
> +{
> +	bool parity = true;
> +
> +	/* This function returns an odd parity bit */
> +	while (p) {
> +		parity = !parity;
> +		p = p & (p - 1);
> +	}
> +	return parity;

Please take a look around and see if you can find another
implementation in the kernel which can be used. If not, you could copy/paste:

https://elixir.bootlin.com/linux/latest/source/lib/bch.c#L348

which is probably more efficient.

> +static void oa_tc6_prepare_ctrl_buf(struct oa_tc6 *tc6, u32 addr, u32 val[],
> +				    u8 len, bool wnr, u8 *buf, bool ctrl_prot)
> +{
> +	u32 hdr;
> +
> +	/* Prepare the control header with the required details */
> +	hdr = FIELD_PREP(CTRL_HDR_DNC, 0) |
> +	      FIELD_PREP(CTRL_HDR_WNR, wnr) |
> +	      FIELD_PREP(CTRL_HDR_AID, 0) |
> +	      FIELD_PREP(CTRL_HDR_MMS, addr >> 16) |
> +	      FIELD_PREP(CTRL_HDR_ADDR, addr) |
> +	      FIELD_PREP(CTRL_HDR_LEN, len - 1);
> +	hdr |= FIELD_PREP(CTRL_HDR_P, oa_tc6_get_parity(hdr));
> +	*(u32 *)buf = cpu_to_be32(hdr);
> +
> +	if (wnr) {

What does wnr mean? Maybe give it a more meaningful name, unless it is
actually something in the standard. Kerneldoc would also help.

> +static int oa_tc6_check_control(struct oa_tc6 *tc6, u8 *ptx, u8 *prx, u8 len,
> +				bool wnr, bool ctrl_prot)
> +{
> +	/* 1st 4 bytes of rx chunk data can be discarded */
> +	u32 rx_hdr = *(u32 *)&prx[TC6_HDR_SIZE];
> +	u32 tx_hdr = *(u32 *)ptx;
> +	u32 rx_data_complement;
> +	u32 tx_data;
> +	u32 rx_data;
> +	u16 pos1;
> +	u16 pos2;
> +
> +	/* If tx hdr and echoed hdr are not equal then there might be an issue
> +	 * with the connection between SPI host and MAC-PHY. Here this case is
> +	 * considered as MAC-PHY is not connected.

I could understand ENODEV on the first transaction during probe. But
after that -EIO seems more appropriate. I've also seen USB use -EPROTO
to indicate a protocol error, which a corrupt message would be.

> +int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
> +			bool wnr, bool ctrl_prot)
> +{
> +	u8 *tx_buf;
> +	u8 *rx_buf;
> +	u16 size;
> +	u16 pos;
> +	int ret;
> +
> +	if (ctrl_prot)
> +		size = (TC6_HDR_SIZE * 2) + (len * (TC6_HDR_SIZE * 2));
> +	else
> +		size = (TC6_HDR_SIZE * 2) + (len * TC6_HDR_SIZE);

Do you have an idea how big the biggest control message is? Rather
than allocate these buffers for every transaction, maybe allocate
maximum size buffers one at startup and keep them in tc6? That will
reduce overhead and simplify the code.

> +struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
> +{
> +	struct oa_tc6 *tc6;
> +
> +	if (!spi)
> +		return NULL;

This is defensive programming which is generally not liked. You cannot
do anything without an SPI device, so just assume it is passed, and if
not, let is explode later and the driver write will quickly fix there
broken code.

> +
> +	tc6 = kzalloc(sizeof(*tc6), GFP_KERNEL);
> +	if (!tc6)
> +		return NULL;
> +
> +	tc6->spi = spi;
> +
> +	return tc6;
> +}
> +EXPORT_SYMBOL_GPL(oa_tc6_init);
> +
> +void oa_tc6_deinit(struct oa_tc6 *tc6)
> +{
> +	kfree(tc6);
> +}
> +EXPORT_SYMBOL_GPL(oa_tc6_deinit);

Maybe consider a devm_ API to make the MAC driver simpler.

      Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-08 14:29 ` [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface Parthiban Veerasooran
                     ` (2 preceding siblings ...)
  2023-09-13  2:11   ` Andrew Lunn
@ 2023-09-13  2:16   ` Andrew Lunn
  2023-09-19 11:13     ` Parthiban.Veerasooran
  3 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-13  2:16 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> +struct oa_tc6 {
> +	struct spi_device *spi;
> +	bool ctrl_prot;
> +};

Should this be considered an opaque structure which the MAC driver
should not access the members?

I don't see anything setting ctrl_prot here. Does it need a setter and
a getter?

	Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-12 12:44     ` Parthiban.Veerasooran
@ 2023-09-13  2:19       ` Andrew Lunn
  2023-09-19 11:04         ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-13  2:19 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> Ok. If I understand correctly, I have to use devm_request_threaded_irq() 
> instead of devm_request_irq() and let the thread handler registered with 
> the devm_request_threaded_irq() function to perform interrupt activity 
> directly?

Yes. I've not looked at all the patches yet, but if the work queue is
not used for anything else, you should be able to remove it, and let
the IRQ core handle all the threading for you.

    Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-08 14:29 ` [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling Parthiban Veerasooran
  2023-09-09 13:39   ` Andrew Lunn
  2023-09-11 12:51   ` Ziyang Xuan (William)
@ 2023-09-13  2:39   ` Andrew Lunn
  2023-09-19 13:07     ` Parthiban.Veerasooran
  2023-09-13  8:44   ` Lukasz Majewski
  3 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-13  2:39 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> +static int oa_tc6_sw_reset(struct oa_tc6 *tc6)
> +{
> +	long timeleft;
> +	u32 regval;
> +	int ret;
> +
> +	/* Perform software reset with both protected and unprotected control
> +	 * commands because the driver doesn't know the current status of the
> +	 * MAC-PHY.
> +	 */
> +	regval = SW_RESET;
> +	reinit_completion(&tc6->rst_complete);
> +	ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1, true, false);
> +	if (ret) {
> +		dev_err(&tc6->spi->dev, "RESET register write failed\n");
> +		return ret;
> +	}
> +
> +	ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1, true, true);
> +	if (ret) {
> +		dev_err(&tc6->spi->dev, "RESET register write failed\n");
> +		return ret;
> +	}
> +	timeleft = wait_for_completion_interruptible_timeout(&tc6->rst_complete,
> +							     msecs_to_jiffies(1));
> +	if (timeleft <= 0) {
> +		dev_err(&tc6->spi->dev, "MAC-PHY reset failed\n");
> +		return -ENODEV;
> +	}

This seems a bit messy and complex. I assume reset is performed once
during probe, and never again? So i wonder if it would be cleaner to
actually just poll for the reset to complete? You can then remove all
this completion code, and the interrupt handler gets simpler?

> +	/* Register MAC-PHY interrupt service routine */
> +	ret = devm_request_irq(&spi->dev, spi->irq, macphy_irq, 0, "macphy int",
> +			       tc6);
> +	if ((ret != -ENOTCONN) && ret < 0) {
> +		dev_err(&spi->dev, "Error attaching macphy irq %d\n", ret);
> +		goto err_macphy_irq;
> +	}

Why is -ENOTCONN special? A comment would be good here.

> -void oa_tc6_deinit(struct oa_tc6 *tc6)
> +int oa_tc6_deinit(struct oa_tc6 *tc6)
>  {
> -	kfree(tc6);
> +	int ret;
> +
> +	devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
> +	ret = kthread_stop(tc6->tc6_task);
> +	if (!ret)
> +		kfree(tc6);
> +	return ret;
>  }

What is the MAC driver supposed to do if this fails?

But this problem probably goes away once you use a threaded interrupt
handler.

w> +/* Open Alliance TC6 Standard Control and Status Registers */
> +#define OA_TC6_RESET	0x0003		/* Reset Control and Status Register */
> +#define OA_TC6_STS0	0x0008		/* Status Register #0 */

Please use the same name as the standard. It use STATUS0, so
OA_TC6_STATUS0. Please make sure all your defines follow the standard.

> +
> +/* RESET register field */
> +#define SW_RESET	BIT(0)		/* Software Reset */

It is pretty normal to put #defines for a register members after the
#define for the register itself:

#define OA_TC6_RESET	0x0003		/* Reset Control and Status Register */
#define OA_TC6_RESET_SWRESET	BIT(0)

#define OA_TC6_STATUS0	0x0008		/* Status Register #0 */
#define OA_TC6_STATUS0_RESETC		BIT(6)		/* Reset Complete */

The naming like this also helps avoid mixups.

    Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-08 14:29 ` [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling Parthiban Veerasooran
                     ` (2 preceding siblings ...)
  2023-09-13  2:39   ` Andrew Lunn
@ 2023-09-13  8:44   ` Lukasz Majewski
  2023-09-13 12:36     ` Andrew Lunn
  3 siblings, 1 reply; 85+ messages in thread
From: Lukasz Majewski @ 2023-09-13  8:44 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	andrew, netdev, devicetree, linux-kernel, linux-doc,
	horatiu.vultur, Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver,
	Thorsten.Kummermehr

[-- Attachment #1: Type: text/plain, Size: 8981 bytes --]

Hi Parthiban,

> Register MAC-PHY interrupt and handle reset complete interrupt. Reset
> complete bit is set when the MAC-PHY reset complete and ready for
> configuration. When it is set, it will generate a non-maskable
> interrupt to alert the SPI host. Additionally reset complete bit in
> the STS0 register has to be written by one upon reset complete to
> clear the interrupt.

I'm using the MicroE module with LAN8651 device connected to nucleo
STM32G4 microcontroller.

Maybe not directly related to Linux, but I would like to ask for some
clarification.

> 
> Signed-off-by: Parthiban Veerasooran
> <Parthiban.Veerasooran@microchip.com> ---
>  drivers/net/ethernet/oa_tc6.c | 141
> ++++++++++++++++++++++++++++++++-- include/linux/oa_tc6.h        |
> 16 +++- 2 files changed, 150 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/net/ethernet/oa_tc6.c
> b/drivers/net/ethernet/oa_tc6.c index 613cf034430a..0019f70345b6
> 100644 --- a/drivers/net/ethernet/oa_tc6.c
> +++ b/drivers/net/ethernet/oa_tc6.c
> @@ -6,6 +6,7 @@
>   */
>  
>  #include <linux/bitfield.h>
> +#include <linux/interrupt.h>
>  #include <linux/oa_tc6.h>
>  
>  static int oa_tc6_spi_transfer(struct spi_device *spi, u8 *ptx, u8
> *prx, @@ -160,10 +161,16 @@ int oa_tc6_perform_ctrl(struct oa_tc6
> *tc6, u32 addr, u32 val[], u8 len, if (ret)
>  		goto err_ctrl;
>  
> -	/* Check echoed/received control reply */
> -	ret = oa_tc6_check_control(tc6, tx_buf, rx_buf, len, wnr,
> ctrl_prot);
> -	if (ret)
> -		goto err_ctrl;
> +	/* In case of reset write, the echoed control command
> doesn't have any
> +	 * valid data. So no need to check for error.
> +	 */
> +	if (addr != OA_TC6_RESET) {
> +		/* Check echoed/received control reply */
> +		ret = oa_tc6_check_control(tc6, tx_buf, rx_buf, len,
> wnr,
> +					   ctrl_prot);
> +		if (ret)
> +			goto err_ctrl;
> +	}
>  
>  	if (!wnr) {
>  		/* Copy read data from the rx data in case of ctrl
> read */ @@ -186,6 +193,88 @@ int oa_tc6_perform_ctrl(struct oa_tc6
> *tc6, u32 addr, u32 val[], u8 len, return ret;
>  }
>  
> +static int oa_tc6_handler(void *data)
> +{
> +	struct oa_tc6 *tc6 = data;
> +	u32 regval;
> +	int ret;
> +
> +	while (likely(!kthread_should_stop())) {
> +		wait_event_interruptible(tc6->tc6_wq, tc6->int_flag
> ||
> +					 kthread_should_stop());
> +		if (tc6->int_flag) {
> +			tc6->int_flag = false;
> +			ret = oa_tc6_perform_ctrl(tc6, OA_TC6_STS0,
> &regval, 1,
> +						  false, false);
> +			if (ret) {
> +				dev_err(&tc6->spi->dev, "Failed to
> read STS0\n");
> +				continue;
> +			}
> +			/* Check for reset complete interrupt status
> */
> +			if (regval & RESETC) {

Just maybe mine small remark. IMHO the reset shall not pollute the IRQ
hander. The RESETC is just set on the initialization phase and only
then shall be served. Please correct me if I'm wrong, but it will not
be handled during "normal" operation.

> +				regval = RESETC;
> +				/* SPI host should write RESETC bit
> with one to
> +				 * clear the reset interrupt status.
> +				 */
> +				ret = oa_tc6_perform_ctrl(tc6,
> OA_TC6_STS0,
> +							  &regval,
> 1, true,
> +							  false);

Is this enough to have the IRQ_N deasserted (i.e. pulled HIGH)?

The documentation states it clearly that one also needs to set SYNC bit
(BIT(15)) in the OA_CONFIG0 register (which would have the 0x8006 value).

Mine problem is that even after writing 0x40 to OA_STATUS0 and 0x8006
to OA_CONFIG0 the IRQ_N is still LOW (it is pulled up via 10K resistor).

(I'm able to read those registers and those show expected values)

> +				if (ret) {
> +					dev_err(&tc6->spi->dev,
> +						"Failed to write
> STS0\n");
> +					continue;
> +				}
> +				complete(&tc6->rst_complete);
> +			}
> +		}
> +	}
> +	return 0;
> +}
> +
> +static irqreturn_t macphy_irq(int irq, void *dev_id)
> +{
> +	struct oa_tc6 *tc6 = dev_id;
> +
> +	/* Wake tc6 task to perform interrupt action */
> +	tc6->int_flag = true;
> +	wake_up_interruptible(&tc6->tc6_wq);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int oa_tc6_sw_reset(struct oa_tc6 *tc6)
> +{
> +	long timeleft;
> +	u32 regval;
> +	int ret;
> +
> +	/* Perform software reset with both protected and
> unprotected control
> +	 * commands because the driver doesn't know the current
> status of the
> +	 * MAC-PHY.
> +	 */
> +	regval = SW_RESET;
> +	reinit_completion(&tc6->rst_complete);
> +	ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1,
> true, false);
> +	if (ret) {
> +		dev_err(&tc6->spi->dev, "RESET register write
> failed\n");
> +		return ret;
> +	}
> +
> +	ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1,
> true, true);
> +	if (ret) {
> +		dev_err(&tc6->spi->dev, "RESET register write
> failed\n");
> +		return ret;
> +	}
> +	timeleft =

Was it on purpose to not use the RST_N pin to perform GPIO based reset?

When I generate reset pulse (and keep it for low for > 5us) the IRQ_N
gets high. After some time it gets low (as expected). But then it
doesn't get high any more.

> wait_for_completion_interruptible_timeout(&tc6->rst_complete,
> +
> msecs_to_jiffies(1));

Please also clarify - does the LAN8651 require up to 1ms "settle down"
(after reset) time before it gets operational again?

> +	if (timeleft <= 0) {
> +		dev_err(&tc6->spi->dev, "MAC-PHY reset failed\n");
> +		return -ENODEV;
> +	}
> +
> +	return 0;
> +}
> +
>  int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 val[],
> u8 len) {
>  	return oa_tc6_perform_ctrl(tc6, addr, val, len, true,
> tc6->ctrl_prot); @@ -201,6 +290,7 @@
> EXPORT_SYMBOL_GPL(oa_tc6_read_register); struct oa_tc6
> *oa_tc6_init(struct spi_device *spi) {
>  	struct oa_tc6 *tc6;
> +	int ret;
>  
>  	if (!spi)
>  		return NULL;
> @@ -211,12 +301,51 @@ struct oa_tc6 *oa_tc6_init(struct spi_device
> *spi) 
>  	tc6->spi = spi;
>  
> +	/* Used for triggering the OA TC6 task */
> +	init_waitqueue_head(&tc6->tc6_wq);
> +
> +	init_completion(&tc6->rst_complete);
> +
> +	/* This task performs the SPI transfer */
> +	tc6->tc6_task = kthread_run(oa_tc6_handler, tc6, "OA TC6
> Task");
> +	if (IS_ERR(tc6->tc6_task))
> +		goto err_tc6_task;
> +
> +	/* Set the highest priority to the tc6 task as it is time
> critical */
> +	sched_set_fifo(tc6->tc6_task);
> +
> +	/* Register MAC-PHY interrupt service routine */
> +	ret = devm_request_irq(&spi->dev, spi->irq, macphy_irq, 0,
> "macphy int",
> +			       tc6);
> +	if ((ret != -ENOTCONN) && ret < 0) {
> +		dev_err(&spi->dev, "Error attaching macphy irq
> %d\n", ret);
> +		goto err_macphy_irq;
> +	}
> +
> +	/* Perform MAC-PHY software reset */
> +	if (oa_tc6_sw_reset(tc6))
> +		goto err_macphy_reset;
> +
>  	return tc6;
> +
> +err_macphy_reset:
> +	devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
> +err_macphy_irq:
> +	kthread_stop(tc6->tc6_task);
> +err_tc6_task:
> +	kfree(tc6);
> +	return NULL;
>  }
>  EXPORT_SYMBOL_GPL(oa_tc6_init);
>  
> -void oa_tc6_deinit(struct oa_tc6 *tc6)
> +int oa_tc6_deinit(struct oa_tc6 *tc6)
>  {
> -	kfree(tc6);
> +	int ret;
> +
> +	devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
> +	ret = kthread_stop(tc6->tc6_task);
> +	if (!ret)
> +		kfree(tc6);
> +	return ret;
>  }
>  EXPORT_SYMBOL_GPL(oa_tc6_deinit);
> diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
> index 5e0a58ab1dcd..315f061c2dfe 100644
> --- a/include/linux/oa_tc6.h
> +++ b/include/linux/oa_tc6.h
> @@ -17,15 +17,29 @@
>  #define CTRL_HDR_LEN	GENMASK(7, 1)	/* Length */
>  #define CTRL_HDR_P	BIT(0)		/* Parity Bit */
>  
> +/* Open Alliance TC6 Standard Control and Status Registers */
> +#define OA_TC6_RESET	0x0003		/* Reset Control
> and Status Register */ +#define OA_TC6_STS0	0x0008
> 	/* Status Register #0 */ +
> +/* RESET register field */
> +#define SW_RESET	BIT(0)		/* Software Reset */
> +
> +/* STATUS0 register field */
> +#define RESETC		BIT(6)		/* Reset
> Complete */ +
>  #define TC6_HDR_SIZE	4		/* Ctrl command header
> size as per OA */ #define TC6_FTR_SIZE	4		/*
> Ctrl command footer size ss per OA */ 
>  struct oa_tc6 {
>  	struct spi_device *spi;
>  	bool ctrl_prot;
> +	struct task_struct *tc6_task;
> +	wait_queue_head_t tc6_wq;
> +	bool int_flag;
> +	struct completion rst_complete;
>  };
>  
>  struct oa_tc6 *oa_tc6_init(struct spi_device *spi);
> -void oa_tc6_deinit(struct oa_tc6 *tc6);
> +int oa_tc6_deinit(struct oa_tc6 *tc6);
>  int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 value[],
> u8 len); int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32
> value[], u8 len);




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Erika Unter
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-13  8:44   ` Lukasz Majewski
@ 2023-09-13 12:36     ` Andrew Lunn
  2023-09-13 13:26       ` Lukasz Majewski
  0 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-13 12:36 UTC (permalink / raw)
  To: Lukasz Majewski
  Cc: Parthiban Veerasooran, davem, edumazet, kuba, pabeni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, steen.hegelund,
	rdunlap, horms, casper.casan, netdev, devicetree, linux-kernel,
	linux-doc, horatiu.vultur, Woojung.Huh, Nicolas.Ferre,
	UNGLinuxDriver, Thorsten.Kummermehr

> Just maybe mine small remark. IMHO the reset shall not pollute the IRQ
> hander. The RESETC is just set on the initialization phase and only
> then shall be served. Please correct me if I'm wrong, but it will not
> be handled during "normal" operation.

This is something i also wondered. Maybe if the firmware in the
MAC-PHY crashes, burns, and a watchdog reset it, could it assert
RESETC? I think maybe a WARN_ON_ONCE() for RESETC in the interrupt
handler would be useful, but otherwise ignore it. Probe can then poll
during its reset.

> > +				regval = RESETC;
> > +				/* SPI host should write RESETC bit
> > with one to
> > +				 * clear the reset interrupt status.
> > +				 */
> > +				ret = oa_tc6_perform_ctrl(tc6,
> > OA_TC6_STS0,
> > +							  &regval,
> > 1, true,
> > +							  false);
> 
> Is this enough to have the IRQ_N deasserted (i.e. pulled HIGH)?
> 
> The documentation states it clearly that one also needs to set SYNC bit
> (BIT(15)) in the OA_CONFIG0 register (which would have the 0x8006 value).
> 
> Mine problem is that even after writing 0x40 to OA_STATUS0 and 0x8006
> to OA_CONFIG0 the IRQ_N is still LOW (it is pulled up via 10K resistor).
> 
> (I'm able to read those registers and those show expected values)

What does STATUS0 and STATUS1 contain? That might be a dumb question,
i've not read the details for interrupt handling yet, but maybe there
is another interrupt pending? Or the interrupt mask needs writing?

> Was it on purpose to not use the RST_N pin to perform GPIO based reset?
> 
> When I generate reset pulse (and keep it for low for > 5us) the IRQ_N
> gets high. After some time it gets low (as expected). But then it
> doesn't get high any more.

Does the standard say RST_N is mandatory to be controlled by software?
I could imagine RST_N is tied to the board global reset when the power
supply is stable. Software reset is then used at probe time.

So this could be a board design decision. I can see this code getting
extended in the future, an optional gpiod passed to the core for it to
use.

> > msecs_to_jiffies(1));
> 
> Please also clarify - does the LAN8651 require up to 1ms "settle down"
> (after reset) time before it gets operational again?

If this is not part of the standard, it really should be in the MAC
driver, or configurable, since different devices might need different
delays. But ideally, if the status bit says it is good to go, i would
really expect it to be good to go. So this probably should be a
LAN8651 quirk.

	Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-13 12:36     ` Andrew Lunn
@ 2023-09-13 13:26       ` Lukasz Majewski
  2023-09-19 13:40         ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Lukasz Majewski @ 2023-09-13 13:26 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Parthiban Veerasooran, davem, edumazet, kuba, pabeni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, steen.hegelund,
	rdunlap, horms, casper.casan, netdev, devicetree, linux-kernel,
	linux-doc, horatiu.vultur, Woojung.Huh, Nicolas.Ferre,
	UNGLinuxDriver, Thorsten.Kummermehr

[-- Attachment #1: Type: text/plain, Size: 4336 bytes --]

Hi Andrew,

> > Just maybe mine small remark. IMHO the reset shall not pollute the
> > IRQ hander. The RESETC is just set on the initialization phase and
> > only then shall be served. Please correct me if I'm wrong, but it
> > will not be handled during "normal" operation.  
> 
> This is something i also wondered. Maybe if the firmware in the
> MAC-PHY crashes, burns, and a watchdog reset it, could it assert
> RESETC? I think maybe a WARN_ON_ONCE() for RESETC in the interrupt
> handler would be useful, but otherwise ignore it. Probe can then poll
> during its reset.
> 
> > > +				regval = RESETC;
> > > +				/* SPI host should write RESETC
> > > bit with one to
> > > +				 * clear the reset interrupt
> > > status.
> > > +				 */
> > > +				ret = oa_tc6_perform_ctrl(tc6,
> > > OA_TC6_STS0,
> > > +
> > > &regval, 1, true,
> > > +
> > > false);  
> > 
> > Is this enough to have the IRQ_N deasserted (i.e. pulled HIGH)?
> > 
> > The documentation states it clearly that one also needs to set SYNC
> > bit (BIT(15)) in the OA_CONFIG0 register (which would have the
> > 0x8006 value).
> > 
> > Mine problem is that even after writing 0x40 to OA_STATUS0 and
> > 0x8006 to OA_CONFIG0 the IRQ_N is still LOW (it is pulled up via
> > 10K resistor).
> > 
> > (I'm able to read those registers and those show expected values)  
> 
> What does STATUS0 and STATUS1 contain?

STATUS0 => 0x40, which is expected.

Then I do write 0x40 to STATUS0 -> bit6 (RESETC) is R/W1C

After reading the same register - I do receive 0x00 (it has been
cleared).

Then I write 0x8006 to OA_CONFIG0.

(Those two steps are regarded as "configuration" of LAN865x device in
the documentation)

In this patch set -> the OA_COFIG0 also has the 0x6 added to indicate
the SPI transfer chunk.

Dump of OA registers:
{0x11, 0x7c1b3, 0x5e5, 0x0, 0x8006, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x3000, 0x1fbf, 0x3ffe0003, 0x0, 0x0}

Status 0 (0x8) -> 0x0
Status 1 (0x9) -> 0x0

> That might be a dumb question,
> i've not read the details for interrupt handling yet, but maybe there
> is another interrupt pending? Or the interrupt mask needs writing?

All the interrupts on MASK{01} are masked. 

Changing it to:
sts &= ~(OA_IMASK0_TXPEM | OA_IMASK0_TXBOEM | OA_IMASK0_TXBUEM |
OA_IMASK0_RXBOEM | OA_IMASK0_LOFEM | OA_IMASK0_HDREM

doesn't fix this problem.

> 
> > Was it on purpose to not use the RST_N pin to perform GPIO based
> > reset?
> > 
> > When I generate reset pulse (and keep it for low for > 5us) the
> > IRQ_N gets high. After some time it gets low (as expected). But
> > then it doesn't get high any more.  
> 
> Does the standard say RST_N is mandatory to be controlled by software?
> I could imagine RST_N is tied to the board global reset when the power
> supply is stable.

It can be GPIO controlled. However, it is not required. I've tied it to
3V3 and also left NC, but no change.

> Software reset is then used at probe time.

I've reconfigured the board to use only SW based reset (i.e. set bit0
in OA_RESET - 0x3).

> 
> So this could be a board design decision. I can see this code getting
> extended in the future, an optional gpiod passed to the core for it to
> use.

I can omit the RST_N control. I'd just expect the IRQ_N to be high
after reset.

> 
> > > msecs_to_jiffies(1));  
> > 
> > Please also clarify - does the LAN8651 require up to 1ms "settle
> > down" (after reset) time before it gets operational again?  
> 
> If this is not part of the standard, it really should be in the MAC
> driver, or configurable, since different devices might need different
> delays. But ideally, if the status bit says it is good to go, i would
> really expect it to be good to go. So this probably should be a
> LAN8651 quirk.

The documentation is silent about the "settle down time". The only
requirements is for RST_N assertion > 5us. However, when the IRQ_N goes
low, and the interrupt is served - it happens that I cannot read ID
from the chip via SPI.

> 
> 	Andrew

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Erika Unter
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
  2023-09-10 10:55 ` [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface Krzysztof Kozlowski
@ 2023-09-13 13:26   ` Parthiban.Veerasooran
  2023-09-13 15:45     ` Krzysztof Kozlowski
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-13 13:26 UTC (permalink / raw)
  To: krzysztof.kozlowski
  Cc: netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	andrew

[-- Attachment #1: Type: text/plain, Size: 3054 bytes --]

Hi Krzysztof,

On 10/09/23 4:25 pm, Krzysztof Kozlowski wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On 08/09/2023 16:29, Parthiban Veerasooran wrote:
>> This patch series contain the below updates,
>> - Adds support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface in the
>>    net/ethernet/oa_tc6.c.
>> - Adds driver support for Microchip LAN8650/1 Rev.B0 10BASE-T1S MACPHY
>>    Ethernet driver in the net/ethernet/microchip/lan865x.c.
> 
> And why is this RFC? Do you mean by that it is buggy and not finished,
> so we should not review?

No, this is not a buggy/unfinished patch series. I have added RFC as 
this is a new framework is being added in the kernel for supporting OPEN 
Alliance 10BASE-T1x MACPHY Serial Interface. So I want to get 
opinion/direction/comments from community members. Your valuable review 
comments are important to make this framework get added in the mainline.

To get more clarity on this activity, I have described my test setup and 
results here. My test setup has two 10BASE-T1S nodes (node 0 and node 
1). Node 0 is with LAN8650 MACPHY and node 1 is with EVB-LAN8670-USB.

---------------------------       ----------------------------
| LAN8650 MACPHY (node 0) |<----->| EVB-LAN8670-USB (node 1) |
---------------------------       ----------------------------

LAN8650 MACPHY has a MAC and 10BASE-T1S PHY embedded within a single 
chip. SPI interface for Host.

EVB-LAN8670-USB has a LAN9500A USB MAC and LAN8670 10BASE-T1S PHY. USB 
interface for Host.

Product links to refer:
LAN8650: https://www.microchip.com/en-us/product/lan8650
EVB-LAN8670-USB: https://www.microchip.com/en-us/development-tool/EV08L38A

Node 0: Acts as PLCA coordinator node.
Node 1: Acts as PLCA drop node.

Note: These products can support CSMA/CD as well.

We have already mainlined EVB-LAN8670-USB drivers. Please refer the 
below links.

Driver for LAN9500A USB MAC in the EVB-LAN8670-USB:
https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/smsc95xx.c#L2106

Driver for LAN8670 10BASE-T1S PHY in the EVB-LAN8670-USB:
https://elixir.bootlin.com/linux/latest/source/drivers/net/phy/microchip_t1s.c#L273

Driver for LAN8650 10BASE-T1S MACPHY's Internal PHY:
https://elixir.bootlin.com/linux/latest/source/drivers/net/phy/microchip_t1s.c#L283

Herewith I have attached the ping and iperf3 test results with this 
driver for your reference. There are two terminals representing node 0 
and node 1. Left terminal is LAN8650 MACPHY and the right one is 
EVB-LAN-8670-USB.

ping_test.png: ping test result between two nodes.
iperf3_tx_test.png: iperf3 tx test where node 0 sends data to node 1.
iperf3_rx_test.png: iperf3 rx test where node 1 sends data to node 0.
iperf3_bidirection_test.png: iperf3 bidirectional test where both nodes 
       are sending and receiving.

Hope this helps to get a clarity on this activity.

Best Regards,
Parthiban V
> 
> Best regards,
> Krzysztof
> 
> 

[-- Attachment #2: ping_test.png --]
[-- Type: image/png, Size: 368489 bytes --]

[-- Attachment #3: iperf3_tx_test.png --]
[-- Type: image/png, Size: 166902 bytes --]

[-- Attachment #4: iperf3_rx_test.png --]
[-- Type: image/png, Size: 213607 bytes --]

[-- Attachment #5: iperf3_bidirection_test.png --]
[-- Type: image/png, Size: 381975 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
  2023-09-13 13:26   ` Parthiban.Veerasooran
@ 2023-09-13 15:45     ` Krzysztof Kozlowski
  2023-09-18  9:23       ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Krzysztof Kozlowski @ 2023-09-13 15:45 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	andrew

On 13/09/2023 15:26, Parthiban.Veerasooran@microchip.com wrote:
> Hi Krzysztof,
> 
> On 10/09/23 4:25 pm, Krzysztof Kozlowski wrote:
>> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>>
>> On 08/09/2023 16:29, Parthiban Veerasooran wrote:
>>> This patch series contain the below updates,
>>> - Adds support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface in the
>>>    net/ethernet/oa_tc6.c.
>>> - Adds driver support for Microchip LAN8650/1 Rev.B0 10BASE-T1S MACPHY
>>>    Ethernet driver in the net/ethernet/microchip/lan865x.c.
>>
>> And why is this RFC? Do you mean by that it is buggy and not finished,
>> so we should not review?
> 
> No, this is not a buggy/unfinished patch series. I have added RFC as 

I don't understand how people name their stuff RFC. Some send totally
buggy and untested bindings under RFC and, after receiving feedback,
respond surprised - it was just RFC!

Other send RFC and expect review.

Just call it a PATCH. PATCH is Requesting for Comments.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 3/6] net: ethernet: implement OA TC6 configuration function
  2023-09-08 14:29 ` [RFC PATCH net-next 3/6] net: ethernet: implement OA TC6 configuration function Parthiban Veerasooran
@ 2023-09-14  0:46   ` Andrew Lunn
  2023-09-19 10:57     ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-14  0:46 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> +int oa_tc6_configure(struct oa_tc6 *tc6, u8 cps, bool ctrl_prot, bool tx_cut_thr,
> +		     bool rx_cut_thr)
> +{
> +	u32 regval;
> +	int ret;
> +
> +	/* Read and configure the IMASK0 register for unmasking the interrupts */
> +	ret = oa_tc6_read_register(tc6, OA_TC6_IMASK0, &regval, 1);
> +	if (ret)
> +		return ret;
> +
> +	regval &= TXPEM & TXBOEM & TXBUEM & RXBOEM & LOFEM & HDREM;
> +	ret = oa_tc6_write_register(tc6, OA_TC6_IMASK0, &regval, 1);

It is not so obvious what this 1 means. Maybe change to regval[1], and
user ARRAY_SIZE(). What also does not help is the function name,
oa_tc6_write_register(). Singular. So it appears to write one register,
not multiple registers. It might even make sense to make
oa_tc6_write_register() truly access a single register, and add
oa_tc6_write_registers() for multiple registers.

> +/* Unmasking interrupt fields in IMASK0 */
> +#define HDREM		~BIT(5)		/* Header Error Mask */
> +#define LOFEM		~BIT(4)		/* Loss of Framing Error Mask */
> +#define RXBOEM		~BIT(3)		/* Rx Buffer Overflow Error Mask */
> +#define TXBUEM		~BIT(2)		/* Tx Buffer Underflow Error Mask */
> +#define TXBOEM		~BIT(1)		/* Tx Buffer Overflow Error Mask */
> +#define TXPEM		~BIT(0)		/* Tx Protocol Error Mask */

Using ~BIT(X) is very usual. I would not do this, Principle of Least
Surprise.

>  struct oa_tc6 {
> -	struct spi_device *spi;
> -	bool ctrl_prot;
> +	struct completion rst_complete;
>  	struct task_struct *tc6_task;
>  	wait_queue_head_t tc6_wq;
> +	struct spi_device *spi;
> +	bool tx_cut_thr;
> +	bool rx_cut_thr;
> +	bool ctrl_prot;
>  	bool int_flag;
> -	struct completion rst_complete;
> +	u8 cps;
>  };

Please try not to move stuff around. It makes the diff bigger than it
should be.

       Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface
  2023-09-08 14:29 ` [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface Parthiban Veerasooran
  2023-09-10 17:58   ` Simon Horman
  2023-09-11 12:59   ` Ziyang Xuan (William)
@ 2023-09-14  1:18   ` Andrew Lunn
  2023-09-18 10:02     ` Parthiban.Veerasooran
  2 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-14  1:18 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> +static void oa_tc6_rx_eth_ready(struct oa_tc6 *tc6)
> +{
> +	struct sk_buff *skb = NULL;
> +
> +	/* Send the received ethernet packet to network layer */
> +	skb = netdev_alloc_skb(tc6->netdev, tc6->rxd_bytes + NET_IP_ALIGN);
> +	if (!skb) {
> +		tc6->netdev->stats.rx_dropped++;
> +		netdev_err(tc6->netdev, "Out of memory for rx'd frame");

Being out of memory is not likely to go away quickly. So i can see
this spamming the kernel log. At minimum make it rate limited, or just
rely on the counter and do not print anything.

> +static int oa_tc6_process_exst(struct oa_tc6 *tc6)
> +{
> +	u32 regval;
> +	int ret;
> +
> +	ret = oa_tc6_read_register(tc6, OA_TC6_STS0, &regval, 1);
> +	if (ret) {
> +		netdev_err(tc6->netdev, "STS0 register read failed.\n");
> +		return ret;
> +	}
> +	if (regval & TXPE)
> +		netdev_err(tc6->netdev, "Transmit protocol error\n");
> +	if (regval & TXBOE)
> +		netdev_err(tc6->netdev, "Transmit buffer overflow\n");
> +	if (regval & TXBUE)
> +		netdev_err(tc6->netdev, "Transmit buffer underflow\n");
> +	if (regval & RXBOE)
> +		netdev_err(tc6->netdev, "Receive buffer overflow\n");
> +	if (regval & LOFE)
> +		netdev_err(tc6->netdev, "Loss of frame\n");
> +	if (regval & HDRE)
> +		netdev_err(tc6->netdev, "Header error\n");
> +	if (regval & TXFCSE)
> +		netdev_err(tc6->netdev, "Transmit Frame Check Sequence Error\n");

Do you expect these problems to magically fix themselves, or is this
going to spam the kernel log until the machine is rebooted?

It seems a counter would be more appropriate, and maybe one rate
limited message if the problem persists.

Please look at all your netdev_err() calls and consider if they are
really needed, should they be netdev_dbg(), or statistics counters.

> +static int oa_tc6_process_rx_chunks(struct oa_tc6 *tc6, u8 *buf, u16 len)
> +{
> +	u8 cp_count;
> +	u8 *payload;
> +	u32 ftr;
> +	u16 ebo;
> +	u16 sbo;
> +
> +	/* Calculate the number of chunks received */
> +	cp_count = len / (tc6->cps + TC6_FTR_SIZE);
> +
> +	for (u8 i = 0; i < cp_count; i++) {
> +		/* Get the footer and payload */
> +		ftr = *(u32 *)&buf[tc6->cps + (i * (tc6->cps + TC6_FTR_SIZE))];
> +		ftr = be32_to_cpu(ftr);
> +		payload = &buf[(i * (tc6->cps + TC6_FTR_SIZE))];
> +		/* Check for footer parity error */
> +		if (oa_tc6_get_parity(ftr)) {
> +			netdev_err(tc6->netdev, "Footer: Parity error\n");
> +			goto err_exit;
> +		}
> +		/* If EXST set in the footer then read STS0 register to get the
> +		 * status information.
> +		 */
> +		if (FIELD_GET(DATA_FTR_EXST, ftr)) {
> +			if (oa_tc6_process_exst(tc6))
> +				netdev_err(tc6->netdev, "Failed to process EXST\n");
> +			goto err_exit;
> +		}
> +		if (FIELD_GET(DATA_FTR_HDRB, ftr)) {
> +			netdev_err(tc6->netdev, "Footer: Received header bad\n");
> +			goto err_exit;
> +		}
> +		if (!FIELD_GET(DATA_FTR_SYNC, ftr)) {
> +			netdev_err(tc6->netdev, "Footer: Configuration unsync\n");
> +			goto err_exit;
> +		}
> +		/* If Frame Drop is set, indicates that the MAC has detected a
> +		 * condition for which the SPI host should drop the received
> +		 * ethernet frame.
> +		 */
> +		if (FIELD_GET(DATA_FTR_FD, ftr) && FIELD_GET(DATA_FTR_EV, ftr)) {
> +			netdev_warn(tc6->netdev, "Footer: Frame drop\n");
> +			if (FIELD_GET(DATA_FTR_SV, ftr)) {
> +				goto start_new_frame;
> +			} else {
> +				if (tc6->rx_eth_started) {
> +					tc6->rxd_bytes = 0;
> +					tc6->rx_eth_started = false;
> +					tc6->netdev->stats.rx_dropped++;
> +				}
> +				continue;
> +			}
> +		}
> +		/* Check for data valid */
> +		if (FIELD_GET(DATA_FTR_DV, ftr)) {
> +			/* Check whether both start valid and end valid are in a
> +			 * single chunk payload means a single chunk payload may
> +			 * contain an entire ethernet frame.
> +			 */
> +			if (FIELD_GET(DATA_FTR_SV, ftr) &&
> +			    FIELD_GET(DATA_FTR_EV, ftr)) {
> +				sbo = FIELD_GET(DATA_FTR_SWO, ftr) * 4;
> +				ebo = FIELD_GET(DATA_FTR_EBO, ftr) + 1;
> +				if (ebo <= sbo) {
> +					memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
> +					       &payload[0], ebo);
> +					tc6->rxd_bytes += ebo;
> +					oa_tc6_rx_eth_ready(tc6);
> +					tc6->rxd_bytes = 0;
> +					memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
> +					       &payload[sbo], tc6->cps - sbo);
> +					tc6->rxd_bytes += (tc6->cps - sbo);
> +					goto exit;
> +				} else {
> +					memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
> +					       &payload[sbo], ebo - sbo);
> +					tc6->rxd_bytes += (ebo - sbo);
> +					oa_tc6_rx_eth_ready(tc6);
> +					tc6->rxd_bytes = 0;
> +					goto exit;
> +				}
> +			}
> +start_new_frame:
> +			/* Check for start valid to start capturing the incoming
> +			 * ethernet frame.
> +			 */
> +			if (FIELD_GET(DATA_FTR_SV, ftr) && !tc6->rx_eth_started) {
> +				tc6->rxd_bytes = 0;
> +				tc6->rx_eth_started = true;
> +				sbo = FIELD_GET(DATA_FTR_SWO, ftr) * 4;
> +				memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
> +				       &payload[sbo], tc6->cps - sbo);
> +				tc6->rxd_bytes += (tc6->cps - sbo);
> +				goto exit;
> +			}
> +
> +			/* Check for end valid and calculate the copy length */
> +			if (tc6->rx_eth_started) {
> +				if (FIELD_GET(DATA_FTR_EV, ftr))
> +					ebo = FIELD_GET(DATA_FTR_EBO, ftr) + 1;
> +				else
> +					ebo = tc6->cps;
> +
> +				memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
> +				       &payload[0], ebo);
> +				tc6->rxd_bytes += ebo;
> +				if (FIELD_GET(DATA_FTR_EV, ftr)) {
> +					/* If End Valid set then send the
> +					 * received ethernet frame to n/w.
> +					 */
> +					oa_tc6_rx_eth_ready(tc6);
> +					tc6->rxd_bytes = 0;
> +					tc6->rx_eth_started = false;
> +				}
> +			}
> +		}
> +
> +exit:
> +		tc6->txc = FIELD_GET(DATA_FTR_TXC, ftr);
> +		tc6->rca = FIELD_GET(DATA_FTR_RCA, ftr);
> +	}
> +	return FTR_OK;
> +
> +err_exit:
> +	if (tc6->rx_eth_started) {
> +		tc6->rxd_bytes = 0;
> +		tc6->rx_eth_started = false;
> +		tc6->netdev->stats.rx_dropped++;
> +	}
> +	return FTR_ERR;
> +}

This is quite a complex function, with a lot of gotos. Please try to
split it up into helpers.

> +
>  static int oa_tc6_handler(void *data)
>  {
>  	struct oa_tc6 *tc6 = data;
> +	bool txc_wait = false;
> +	u16 tx_pos = 0;
>  	u32 regval;
> +	u16 len;
>  	int ret;
>  
>  	while (likely(!kthread_should_stop())) {
> -		wait_event_interruptible(tc6->tc6_wq, tc6->int_flag ||
> +		wait_event_interruptible(tc6->tc6_wq, tc6->tx_flag ||
> +					 tc6->int_flag || tc6->rca ||
>  					 kthread_should_stop());
> -		if (tc6->int_flag) {
> +		if (tc6->int_flag && !tc6->reset) {
>  			tc6->int_flag = false;
> +			tc6->reset = true;
>  			ret = oa_tc6_perform_ctrl(tc6, OA_TC6_STS0, &regval, 1,
>  						  false, false);
>  			if (ret) {
> @@ -227,10 +435,170 @@ static int oa_tc6_handler(void *data)
>  				complete(&tc6->rst_complete);
>  			}
>  		}
> +
> +		if (tc6->int_flag || tc6->rca) {
> +			/* If rca is updated from the previous footer then
> +			 * prepare the empty chunks equal to rca and perform
> +			 * SPI transfer to receive the ethernet frame.
> +			 */
> +			if (tc6->rca) {
> +				len = oa_tc6_prepare_empty_chunk(tc6,
> +								 tc6->spi_tx_buf,
> +								 tc6->rca);
> +			} else {
> +				/* If there is an interrupt then perform a SPI
> +				 * transfer with a empty chunk to get the
> +				 * details.
> +				 */
> +				tc6->int_flag = false;
> +				len = oa_tc6_prepare_empty_chunk(tc6,
> +								 tc6->spi_tx_buf,
> +								 1);
> +			}
> +			/* Perform SPI transfer */
> +			ret = oa_tc6_spi_transfer(tc6->spi, tc6->spi_tx_buf,
> +						  tc6->spi_rx_buf, len);
> +			if (ret) {
> +				netdev_err(tc6->netdev, "SPI transfer failed\n");
> +				continue;
> +			}
> +			/* Process the received chunks to get the ethernet frame
> +			 * or interrupt details.
> +			 */
> +			if (oa_tc6_process_rx_chunks(tc6, tc6->spi_rx_buf, len))
> +				continue;
> +		}
> +
> +		/* If there is a tx ethernet frame available */
> +		if (tc6->tx_flag || txc_wait) {
> +			tc6->tx_flag = false;
> +			txc_wait = false;
> +			len = 0;
> +			if (!tc6->txc) {
> +				/* If there is no txc available to transport the
> +				 * tx ethernet frames then wait for the MAC-PHY
> +				 * interrupt to get the txc availability.
> +				 */
> +				txc_wait = true;
> +				continue;
> +			} else if (tc6->txc >= tc6->txc_needed) {
> +				len = tc6->txc_needed * (tc6->cps + TC6_HDR_SIZE);
> +			} else {
> +				len = tc6->txc * (tc6->cps + TC6_HDR_SIZE);
> +			}
> +			memcpy(&tc6->spi_tx_buf[0], &tc6->eth_tx_buf[tx_pos],
> +			       len);
> +			ret = oa_tc6_spi_transfer(tc6->spi, tc6->spi_tx_buf,
> +						  tc6->spi_rx_buf, len);
> +			if (ret) {
> +				netdev_err(tc6->netdev, "SPI transfer failed\n");
> +				continue;
> +			}
> +			/* Process the received chunks to get the ethernet frame
> +			 * or status.
> +			 */
> +			if (oa_tc6_process_rx_chunks(tc6, tc6->spi_rx_buf,
> +						     len)) {
> +				/* In case of error while processing rx chunks
> +				 * discard the incomplete tx ethernet frame and
> +				 * resend it.
> +				 */
> +				tx_pos = 0;
> +				tc6->txc_needed = tc6->total_txc_needed;
> +			} else {
> +				tx_pos += len;
> +				tc6->txc_needed = tc6->txc_needed -
> +						  (len / (tc6->cps + TC6_HDR_SIZE));
> +				/* If the complete ethernet frame is transmitted
> +				 * then return the skb and update the details to
> +				 * n/w layer.
> +				 */
> +				if (!tc6->txc_needed) {
> +					tc6->netdev->stats.tx_packets++;
> +					tc6->netdev->stats.tx_bytes += tc6->tx_skb->len;
> +					dev_kfree_skb(tc6->tx_skb);
> +					tx_pos = 0;
> +					tc6->tx_skb = NULL;
> +					if (netif_queue_stopped(tc6->netdev))
> +						netif_wake_queue(tc6->netdev);
> +				} else if (tc6->txc) {
> +					/* If txc is available again and updated
> +					 * from the previous footer then perform
> +					 * tx again.
> +					 */
> +					tc6->tx_flag = true;
> +				} else {
> +					/* If there is no txc then wait for the
> +					 * interrupt to indicate txc
> +					 * availability.
> +					 */
> +					txc_wait = true;
> +				}
> +			}
> +		}
>  	}
>  	return 0;
>  }

This is also a huge function. The Linux coding style says:

     Functions should be short and sweet, and do just one thing. They
     should fit on one or two screenfuls of text (the ISO/ANSI screen
     size is 80x24, as we all know), and do one thing and do that
     well.

Please break this up into lots of smaller functions which do just one
thing.

> -struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
> +struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev)
>  {
>  	struct oa_tc6 *tc6;
>  	int ret;
> @@ -334,11 +710,39 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
>  	if (!spi)
>  		return NULL;
>  
> +	if (!netdev)
> +		return NULL;

Hos can this happen? Let is explode if some developer is dumb enough
to pass a NULL.

> +#define MAX_ETH_LEN	1536

Where do 1536 come from? Maybe this needs an OA_TC6 prefix to make it
clear this is specific to this protocol?

      Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  2023-09-08 14:29 ` [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY Parthiban Veerasooran
  2023-09-10 17:44   ` Simon Horman
  2023-09-11 13:17   ` Ziyang Xuan (William)
@ 2023-09-14  1:51   ` Andrew Lunn
  2023-09-19  9:18     ` Parthiban.Veerasooran
  2023-09-14  1:55   ` Andrew Lunn
  2023-09-15 13:01   ` David Wretman
  4 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-14  1:51 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> +#define DRV_VERSION		"0.1"

This is pointless. The ethtool code will fill in the git hash which is
a much more useful value to have.

> +static void lan865x_handle_link_change(struct net_device *netdev)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +
> +	phy_print_status(priv->phydev);
> +}
> +
> +static int lan865x_mdiobus_read(struct mii_bus *bus, int phy_id, int idx)
> +{
> +	struct lan865x_priv *priv = bus->priv;
> +	u32 regval;
> +	bool ret;
> +
> +	ret = oa_tc6_read_register(priv->tc6, 0xFF00 | (idx & 0xFF), &regval, 1);
> +	if (ret)
> +		return -ENODEV;
> +
> +	return regval;
> +}
> +
> +static int lan865x_mdiobus_write(struct mii_bus *bus, int phy_id, int idx,
> +				 u16 regval)
> +{
> +	struct lan865x_priv *priv = bus->priv;
> +	u32 value = regval;
> +	bool ret;
> +
> +	ret = oa_tc6_write_register(priv->tc6, 0xFF00 | (idx & 0xFF), &value, 1);
> +	if (ret)
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +
> +static int lan865x_phy_init(struct lan865x_priv *priv)
> +{
> +	int ret;
> +
> +	priv->mdiobus = mdiobus_alloc();
> +	if (!priv->mdiobus) {
> +		netdev_err(priv->netdev, "MDIO bus alloc failed\n");
> +		return -ENODEV;
> +	}
> +
> +	priv->mdiobus->phy_mask = ~(u32)BIT(1);
> +	priv->mdiobus->priv = priv;
> +	priv->mdiobus->read = lan865x_mdiobus_read;
> +	priv->mdiobus->write = lan865x_mdiobus_write;

The MDIO bus is part of the standard. So i would expect this to be in
the library. From what i remember, there are two different ways to
implement MDIO, either via the PHY registers being directly mapped
into the register space, or indirect like this. And i think there is a
status bit somewhere which tells you which is implemented? So please
move this code into the library, but check the status bit and return
ENODEV if the silicon does not actually implement this access method.

> +static int
> +lan865x_set_link_ksettings(struct net_device *netdev,
> +			   const struct ethtool_link_ksettings *cmd)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +	int ret = 0;
> +
> +	if (cmd->base.autoneg != AUTONEG_DISABLE ||
> +	    cmd->base.speed != SPEED_10 || cmd->base.duplex != DUPLEX_HALF) {
> +		if (netif_msg_link(priv))
> +			netdev_warn(netdev, "Unsupported link setting");
> +		ret = -EOPNOTSUPP;
> +	} else {
> +		if (netif_msg_link(priv))
> +			netdev_warn(netdev, "Hardware must be disabled to set link mode");
> +		ret = -EBUSY;
> +	}
> +	return ret;

I would expect to see a call to phy_ethtool_ksettings_set()
here. phylib should be able to do some of the validation.

> +}
> +
> +static int
> +lan865x_get_link_ksettings(struct net_device *netdev,
> +			   struct ethtool_link_ksettings *cmd)
> +{
> +	ethtool_link_ksettings_zero_link_mode(cmd, supported);
> +	ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Half);
> +	ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
> +
> +	cmd->base.speed = SPEED_10;
> +	cmd->base.duplex = DUPLEX_HALF;
> +	cmd->base.port	= PORT_TP;
> +	cmd->base.autoneg = AUTONEG_DISABLE;
> +
> +	return 0;

phy_ethtool_ksettings_get().

I also think this can be moved along with the MDIO bus and PHY
handling into the library.

> +static int lan865x_set_mac_address(struct net_device *netdev, void *addr)
> +{
> +	struct sockaddr *address = addr;
> +
> +	if (netif_running(netdev))
> +		return -EBUSY;
> +	if (!is_valid_ether_addr(address->sa_data))
> +		return -EADDRNOTAVAIL;

Does the core allow an invalid MAC address be passed to the driver?

> +
> +	eth_hw_addr_set(netdev, address->sa_data);
> +	return lan865x_set_hw_macaddr(netdev);
> +}
> +
> +static u32 lan865x_hash(u8 addr[ETH_ALEN])
> +{
> +	return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f;
> +}
> +
> +static void lan865x_set_multicast_list(struct net_device *netdev)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +	u32 regval = 0;
> +
> +	if (netdev->flags & IFF_PROMISC) {
> +		/* Enabling promiscuous mode */
> +		regval |= MAC_PROMISCUOUS_MODE;
> +		regval &= (~MAC_MULTICAST_MODE);
> +		regval &= (~MAC_UNICAST_MODE);
> +	} else if (netdev->flags & IFF_ALLMULTI) {
> +		/* Enabling all multicast mode */
> +		regval &= (~MAC_PROMISCUOUS_MODE);
> +		regval |= MAC_MULTICAST_MODE;
> +		regval &= (~MAC_UNICAST_MODE);
> +	} else if (!netdev_mc_empty(netdev)) {
> +		/* Enabling specific multicast addresses */
> +		struct netdev_hw_addr *ha;
> +		u32 hash_lo = 0;
> +		u32 hash_hi = 0;
> +
> +		netdev_for_each_mc_addr(ha, netdev) {
> +			u32 bit_num = lan865x_hash(ha->addr);
> +			u32 mask = 1 << (bit_num & 0x1f);
> +
> +			if (bit_num & 0x20)
> +				hash_hi |= mask;
> +			else
> +				hash_lo |= mask;
> +		}
> +		if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHH, &hash_hi, 1)) {
> +			if (netif_msg_timer(priv))
> +				netdev_err(netdev, "Failed to write reg_hashh");
> +			return;
> +		}
> +		if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHL, &hash_lo, 1)) {
> +			if (netif_msg_timer(priv))
> +				netdev_err(netdev, "Failed to write reg_hashl");
> +			return;
> +		}
> +		regval &= (~MAC_PROMISCUOUS_MODE);
> +		regval &= (~MAC_MULTICAST_MODE);
> +		regval |= MAC_UNICAST_MODE;
> +	} else {
> +		/* enabling local mac address only */
> +		if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHH, &regval, 1)) {
> +			if (netif_msg_timer(priv))
> +				netdev_err(netdev, "Failed to write reg_hashh");
> +			return;
> +		}
> +		if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHL, &regval, 1)) {
> +			if (netif_msg_timer(priv))
> +				netdev_err(netdev, "Failed to write reg_hashl");
> +			return;
> +		}
> +	}
> +	if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CONFIG, &regval, 1)) {
> +		if (netif_msg_timer(priv))
> +			netdev_err(netdev, "Failed to enable promiscuous mode");
> +	}
> +}
> +
> +static netdev_tx_t lan865x_send_packet(struct sk_buff *skb,
> +				       struct net_device *netdev)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +
> +	return oa_tc6_send_eth_pkt(priv->tc6, skb);
> +}
> +
> +static int lan865x_hw_disable(struct lan865x_priv *priv)
> +{
> +	u32 regval = NW_DISABLE;
> +
> +	if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CTRL, &regval, 1))
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +
> +static int lan865x_net_close(struct net_device *netdev)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +	int ret;
> +
> +	netif_stop_queue(netdev);
> +	ret = lan865x_hw_disable(priv);
> +	if (ret) {
> +		if (netif_msg_ifup(priv))
> +			netdev_err(netdev, "Failed to disable the hardware\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int lan865x_hw_enable(struct lan865x_priv *priv)
> +{
> +	u32 regval = NW_TX_STATUS | NW_RX_STATUS;
> +
> +	if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CTRL, &regval, 1))
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +
> +static int lan865x_net_open(struct net_device *netdev)
> +{
> +	struct lan865x_priv *priv = netdev_priv(netdev);
> +	int ret;
> +
> +	if (!is_valid_ether_addr(netdev->dev_addr)) {
> +		if (netif_msg_ifup(priv))
> +			netdev_err(netdev, "Invalid MAC address %pm", netdev->dev_addr);
> +		return -EADDRNOTAVAIL;

Using a random MAC address is the normal workaround for not having a
valid MAC address via OTP flash etc.


> +static int lan865x_get_dt_data(struct lan865x_priv *priv)
> +{
> +	struct spi_device *spi = priv->spi;
> +	int ret;
> +
> +	if (of_property_present(spi->dev.of_node, "oa-chunk-size")) {
> +		ret = of_property_read_u32(spi->dev.of_node, "oa-chunk-size",
> +					   &priv->cps);
> +		if (ret < 0)
> +			return ret;
> +	} else {
> +		priv->cps = 64;
> +		dev_info(&spi->dev, "Property oa-chunk-size is not found in dt and proceeding with the size 64\n");
> +	}
> +
> +	if (of_property_present(spi->dev.of_node, "oa-tx-cut-through"))
> +		priv->txcte = true;
> +	else
> +		dev_info(&spi->dev, "Property oa-tx-cut-through is not found in dt and proceeding with tx store and forward mode\n");

Please remove all these dev_info() prints. The device tree binding
should make it clear what the defaults are when not specified in DT.

> +
> +	if (of_property_present(spi->dev.of_node, "oa-rx-cut-through"))
> +		priv->rxcte = true;
> +	else
> +		dev_info(&spi->dev, "Property oa-rx-cut-through is not found in dt and proceeding with rx store and forward mode\n");
> +
> +	if (of_property_present(spi->dev.of_node, "oa-protected"))
> +		priv->protected = true;
> +	else
> +		dev_info(&spi->dev, "Property oa-protected is not found in dt and proceeding with protection enabled\n");

Which of these are proprietary properties, and which are part of the
standard? Please move parsing all the standard properties into the
library.

> +static int lan865x_probe(struct spi_device *spi)
> +{

...

> +
> +	phy_start(priv->phydev);
> +	return 0;

phy_start() is normally done in open, not probe.

	    Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  2023-09-08 14:29 ` [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY Parthiban Veerasooran
                     ` (2 preceding siblings ...)
  2023-09-14  1:51   ` Andrew Lunn
@ 2023-09-14  1:55   ` Andrew Lunn
  2023-09-18 11:23     ` Parthiban.Veerasooran
  2023-09-15 13:01   ` David Wretman
  4 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-14  1:55 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> +#define REG_STDR_RESET		0x00000003

This appears to be a standard register, so you should not need to
define it here.

> +#define REG_MAC_ADDR_BO		0x00010022
> +#define REG_MAC_ADDR_L		0x00010024
> +#define REG_MAC_ADDR_H		0x00010025
> +#define REG_MAC_NW_CTRL         0x00010000
> +#define REG_MAC_NW_CONFIG	0x00010001
> +#define REG_MAC_HASHL		0x00010020
> +#define REG_MAC_HASHH		0x00010021
> +#define REG_MAC_ADDR_BO		0x00010022
> +#define REG_MAC_ADDR_L		0x00010024
> +#define REG_MAC_ADDR_H		0x00010025
> +
> +#define CCS_Q0_TX_CFG		0x000A0081
> +#define CCS_Q0_RX_CFG		0x000A0082

These are proprietary vendor registers, so please add a prefix to make
this clear.

     Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 6/6] microchip: lan865x: add device-tree support for Microchip's LAN865X MACPHY
  2023-09-08 14:29 ` [RFC PATCH net-next 6/6] microchip: lan865x: add device-tree " Parthiban Veerasooran
  2023-09-10 10:55   ` Krzysztof Kozlowski
@ 2023-09-14  2:07   ` Andrew Lunn
  2023-09-19 10:40     ` Parthiban.Veerasooran
  1 sibling, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-14  2:07 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, horatiu.vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> +  oa-chunk-size: true
> +  oa-tx-cut-through: true
> +  oa-rx-cut-through: true
> +  oa-protected: true

Please split this up into properties all OA TC6 devices are expected
to use, and those specific to the LAN865x. Put the generic properties
into a .yaml file, which you then inherit into the device specific
yaml file.

Also, LAN865x specific properties should have a vendor prefix.

	Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  2023-09-08 14:29 ` [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY Parthiban Veerasooran
                     ` (3 preceding siblings ...)
  2023-09-14  1:55   ` Andrew Lunn
@ 2023-09-15 13:01   ` David Wretman
  2023-09-18 11:22     ` Parthiban.Veerasooran
  4 siblings, 1 reply; 85+ messages in thread
From: David Wretman @ 2023-09-15 13:01 UTC (permalink / raw)
  To: parthiban.veerasooran
  Cc: Nicolas.Ferre, Thorsten.Kummermehr, UNGLinuxDriver, Woojung.Huh,
	andrew, casper.casan, conor+dt, corbet, davem, devicetree,
	edumazet, horatiu.vultur, horms, krzysztof.kozlowski+dt, kuba,
	linux-doc, linux-kernel, netdev, pabeni, rdunlap, robh+dt,
	steen.hegelund, David Wretman

---
On Fri, Sep 08, 2023 at 07:59:18PM +0530, Parthiban Veerasooran wrote:
> The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE‑T1x
> MAC‑PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
> MAC integration provides the low pin count standard SPI interface to any
> microcontroller therefore providing Ethernet functionality without
> requiring MAC integration within the microcontroller. The LAN8650/1
> operates as an SPI client supporting SCLK clock rates up to a maximum of
> 25 MHz. This SPI interface supports the transfer of both data (Ethernet
> frames) and control (register access).
> 
> By default, the chunk data payload is 64 bytes in size. A smaller payload
> data size of 32 bytes is also supported and may be configured in the
> Chunk Payload Size (CPS) field of the Configuration 0 (OA_CONFIG0)
> register. Changing the chunk payload size requires the LAN8650/1 be reset
> and shall not be done during normal operation.
> 
> The Ethernet Media Access Controller (MAC) module implements a 10 Mbps
> half duplex Ethernet MAC, compatible with the IEEE 802.3 standard.
> 10BASE-T1S physical layer transceiver integrated into the LAN8650/1. The
> PHY and MAC are connected via an internal Media Independent Interface
> (MII).
> 
> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>

Hi Parthiban,

Thanks for these patches.

One thing I am missing is settings for PLCA parameters. I feel that the
driver is a bit lacking as long as this is missing.

Adding support for the ethtool plca options would make this much more
complete.

Regards,
David


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
  2023-09-08 14:29 [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface Parthiban Veerasooran
                   ` (6 preceding siblings ...)
  2023-09-10 10:55 ` [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface Krzysztof Kozlowski
@ 2023-09-15 13:56 ` Alexander Dahl
  2023-09-15 14:22   ` Andrew Lunn
  2023-09-18  6:12   ` Parthiban.Veerasooran
  7 siblings, 2 replies; 85+ messages in thread
From: Alexander Dahl @ 2023-09-15 13:56 UTC (permalink / raw)
  To: Parthiban Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, steen.hegelund, rdunlap, horms, casper.casan,
	andrew, netdev, devicetree, linux-kernel, linux-doc,
	horatiu.vultur, Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver,
	Thorsten.Kummermehr, Alexandru Tachici

Hello,

this is interesting, by chance I just looked at a chip claiming
similar features today, which already has a driver in kernel: Analog
Devices ADIN1110.

Am Fri, Sep 08, 2023 at 07:59:13PM +0530 schrieb Parthiban Veerasooran:
> This patch series contain the below updates,
> - Adds support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface in the
>   net/ethernet/oa_tc6.c.

So this implements the "10BASE-T1x MAC-PHY Serial Interface
Specification" which is Ethernet over SPI if I understand correctly?
The above mentioned chip claims do use the same interface and the same
standard.  How does its driver work then?  Do you add code for a thing
already present in the kernel or does the other driver do something
completely different and I just misunderstood?

Can the drivers for ADIN1110 and for LAN865X share code because they
use the same specified interface?  The patch set does not look like
it?

(Added the other driver author to Cc.)

Greets
Alex

> - Adds driver support for Microchip LAN8650/1 Rev.B0 10BASE-T1S MACPHY
>   Ethernet driver in the net/ethernet/microchip/lan865x.c.
> 
> Parthiban Veerasooran (6):
>   net: ethernet: implement OPEN Alliance control transaction interface
>   net: ethernet: add mac-phy interrupt support with reset complete
>     handling
>   net: ethernet: implement OA TC6 configuration function
>   net: ethernet: implement data transaction interface
>   microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
>   microchip: lan865x: add device-tree support for Microchip's LAN865X
>     MACPHY
> 
>  .../bindings/net/microchip,lan865x.yaml       |  54 ++
>  Documentation/networking/oa-tc6-framework.rst | 231 +++++
>  MAINTAINERS                                   |  15 +
>  drivers/net/ethernet/microchip/Kconfig        |  10 +
>  drivers/net/ethernet/microchip/Makefile       |   3 +
>  drivers/net/ethernet/microchip/lan865x.c      | 589 +++++++++++++
>  drivers/net/ethernet/oa_tc6.c                 | 807 ++++++++++++++++++
>  include/linux/oa_tc6.h                        | 130 +++
>  8 files changed, 1839 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/net/microchip,lan865x.yaml
>  create mode 100644 Documentation/networking/oa-tc6-framework.rst
>  create mode 100644 drivers/net/ethernet/microchip/lan865x.c
>  create mode 100644 drivers/net/ethernet/oa_tc6.c
>  create mode 100644 include/linux/oa_tc6.h
> 
> -- 
> 2.34.1
> 
> 

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
  2023-09-15 13:56 ` Alexander Dahl
@ 2023-09-15 14:22   ` Andrew Lunn
  2023-09-18  6:16     ` Parthiban.Veerasooran
  2023-09-18  6:12   ` Parthiban.Veerasooran
  1 sibling, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-15 14:22 UTC (permalink / raw)
  To: Parthiban Veerasooran, davem, edumazet, kuba, pabeni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, steen.hegelund,
	rdunlap, horms, casper.casan, netdev, devicetree, linux-kernel,
	linux-doc, horatiu.vultur, Woojung.Huh, Nicolas.Ferre,
	UNGLinuxDriver, Thorsten.Kummermehr, Alexandru Tachici

On Fri, Sep 15, 2023 at 03:56:59PM +0200, Alexander Dahl wrote:
> Hello,
> 
> this is interesting, by chance I just looked at a chip claiming
> similar features today, which already has a driver in kernel: Analog
> Devices ADIN1110.

Ah, interesting. I had no idea this driver/device is an OA TC6 device.

So ideally, we want the adin1110.c to also use the new framework, and
remove the duplicate code. Parthiban, please look at the driver and
make sure the APIs are such that Alexandru Tachici can swap his driver
to using it. Having two implementations should help make it clear what
is the same and what is different.

   Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
  2023-09-15 13:56 ` Alexander Dahl
  2023-09-15 14:22   ` Andrew Lunn
@ 2023-09-18  6:12   ` Parthiban.Veerasooran
  2023-09-18  9:02     ` Fwd: " Parthiban.Veerasooran
  1 sibling, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-18  6:12 UTC (permalink / raw)
  To: ada, alexandru.tachici, andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Alexander,

Thanks for the information. Please see my reply below.

On 15/09/23 7:26 pm, Alexander Dahl wrote:
> [Some people who received this message don't often get email from ada@thorsis.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
> 
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> Hello,
> 
> this is interesting, by chance I just looked at a chip claiming
> similar features today, which already has a driver in kernel: Analog
> Devices ADIN1110.
Microchip's LAN865x is a 10BASE-T1S MACPHY and Analog Devices's ADIN1110 
is a 10BASE-T1L MACPHY. So as you said 10BASE-T1x MAC_PHY Serial 
Interface Specification defined by OPEN Alliance TC6 group can be 
applicable for both of the devices. I also noticed that ADI's datasheet 
says ADIN1110 supports OPEN Alliance 10BASE-T1x MAC-PHY serial
interface.
https://www.analog.com/media/en/technical-documentation/data-sheets/adin1110.pdf

But in my first glance in their driver code, I don't see any code block 
which implements 10BASE-T1x MAC_PHY Serial Interface Specification 
defined by OPEN Alliance TC6 group. Or do I miss anything here?. My code 
reference is below FYR,
https://elixir.bootlin.com/linux/v6.6-rc2/source/drivers/net/ethernet/adi/adin1110.c

OPEN Alliance 10BASE-T1x MAC_PHY Serial Interface Specification cab be 
downloaded from the below link,
https://opensig.org/automotive-ethernet-specifications/

I think Alexandru Tachici from ADI would be able to give us more 
information on this direction.
> 
> Am Fri, Sep 08, 2023 at 07:59:13PM +0530 schrieb Parthiban Veerasooran:
>> This patch series contain the below updates,
>> - Adds support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface in the
>>    net/ethernet/oa_tc6.c.
> 
> So this implements the "10BASE-T1x MAC-PHY Serial Interface
> Specification" which is Ethernet over SPI if I understand correctly?
> The above mentioned chip claims do use the same interface and the same
> standard.  How does its driver work then?  Do you add code for a thing
> already present in the kernel or does the other driver do something
> completely different and I just misunderstood?
As I mentioned above, in my first glance in their driver code, I don't 
see any code block which implements 10BASE-T1x MAC_PHY Serial Interface 
Specification defined by OPEN Alliance TC6 group. Let's Alexandru 
Tachici from ADI gives us more info on this.
> 
> Can the drivers for ADIN1110 and for LAN865X share code because they
> use the same specified interface?  The patch set does not look like
> it?
Of course, if their device supports OPEN Alliance then we can use this 
oa_tc6.c framework to support other 10BASE-T1x MACPHY's as well.
> 
> (Added the other driver author to Cc.)
Ok thanks.

Best Regards,
Parthiban V
> 
> Greets
> Alex
> 
>> - Adds driver support for Microchip LAN8650/1 Rev.B0 10BASE-T1S MACPHY
>>    Ethernet driver in the net/ethernet/microchip/lan865x.c.
>>
>> Parthiban Veerasooran (6):
>>    net: ethernet: implement OPEN Alliance control transaction interface
>>    net: ethernet: add mac-phy interrupt support with reset complete
>>      handling
>>    net: ethernet: implement OA TC6 configuration function
>>    net: ethernet: implement data transaction interface
>>    microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
>>    microchip: lan865x: add device-tree support for Microchip's LAN865X
>>      MACPHY
>>
>>   .../bindings/net/microchip,lan865x.yaml       |  54 ++
>>   Documentation/networking/oa-tc6-framework.rst | 231 +++++
>>   MAINTAINERS                                   |  15 +
>>   drivers/net/ethernet/microchip/Kconfig        |  10 +
>>   drivers/net/ethernet/microchip/Makefile       |   3 +
>>   drivers/net/ethernet/microchip/lan865x.c      | 589 +++++++++++++
>>   drivers/net/ethernet/oa_tc6.c                 | 807 ++++++++++++++++++
>>   include/linux/oa_tc6.h                        | 130 +++
>>   8 files changed, 1839 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/net/microchip,lan865x.yaml
>>   create mode 100644 Documentation/networking/oa-tc6-framework.rst
>>   create mode 100644 drivers/net/ethernet/microchip/lan865x.c
>>   create mode 100644 drivers/net/ethernet/oa_tc6.c
>>   create mode 100644 include/linux/oa_tc6.h
>>
>> --
>> 2.34.1
>>
>>


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
  2023-09-15 14:22   ` Andrew Lunn
@ 2023-09-18  6:16     ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-18  6:16 UTC (permalink / raw)
  To: andrew, alexandru.tachici, ada
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	alexandru.tachici

Hi Andrew,

Sure. Thanks for the suggestion. I hope my previous reply for 
Alexander's email clarifies the below comment as well.

It would be nice if Alexandru Tachici gives us more clarity on their 
device and driver.

Best Regards,
Parthiban V

On 15/09/23 7:52 pm, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On Fri, Sep 15, 2023 at 03:56:59PM +0200, Alexander Dahl wrote:
>> Hello,
>>
>> this is interesting, by chance I just looked at a chip claiming
>> similar features today, which already has a driver in kernel: Analog
>> Devices ADIN1110.
> 
> Ah, interesting. I had no idea this driver/device is an OA TC6 device.
> 
> So ideally, we want the adin1110.c to also use the new framework, and
> remove the duplicate code. Parthiban, please look at the driver and
> make sure the APIs are such that Alexandru Tachici can swap his driver
> to using it. Having two implementations should help make it clear what
> is the same and what is different.
> 
>     Andrew
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Fwd: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
  2023-09-18  6:12   ` Parthiban.Veerasooran
@ 2023-09-18  9:02     ` Parthiban.Veerasooran
  2023-09-19  9:03       ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-18  9:02 UTC (permalink / raw)
  To: lennart, ada, andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Lennart,

I am forwarding this email to you as we are not able to reach the module 
author Alexandru Tachici <alexandru.tachici@analog.com> and getting the 
below email delivery error.

----cut here-----
Delivery has failed to these recipients or groups:

alexandru.tachici@analog.com<mailto:alexandru.tachici@analog.com>
The email address you entered couldn't be found. Please check the
recipient's email address and try to resend the message. If the problem
continues, please contact your email admin.
----cut here------

We got your your email address from the commit 
bc93e19d088bb14e116756ab270deea6ee62d782. Regarding the below topic, are 
you the right contact parson to continue further on this topic or else 
do you have any other contact to approach? Please let us know.

Best Regards,
Parthiban V
-------- Forwarded Message --------
Subject: Re: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 
10BASE-T1x MACPHY Serial Interface
Date: Mon, 18 Sep 2023 11:42:33 +0530
From: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
To: ada@thorsis.com, Alexandru Tachici <alexandru.tachici@analog.com>, 
Andrew Lunn <andrew@lunn.ch>
CC: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, 
pabeni@redhat.com, robh+dt@kernel.org, 
krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org, corbet@lwn.net, 
steen.hegelund@microchip.com, rdunlap@infradead.org, horms@kernel.org, 
casper.casan@gmail.com, netdev@vger.kernel.org, 
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, 
linux-doc@vger.kernel.org, horatiu.vultur@microchip.com, 
Woojung.Huh@microchip.com, Nicolas.Ferre@microchip.com, 
UNGLinuxDriver@microchip.com, Thorsten.Kummermehr@microchip.com

Hi Alexander,

Thanks for the information. Please see my reply below.

On 15/09/23 7:26 pm, Alexander Dahl wrote:
> [Some people who received this message don't often get email from ada@thorsis.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
> 
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> Hello,
> 
> this is interesting, by chance I just looked at a chip claiming
> similar features today, which already has a driver in kernel: Analog
> Devices ADIN1110.
Microchip's LAN865x is a 10BASE-T1S MACPHY and Analog Devices's ADIN1110 
is a 10BASE-T1L MACPHY. So as you said 10BASE-T1x MAC_PHY Serial 
Interface Specification defined by OPEN Alliance TC6 group can be 
applicable for both of the devices. I also noticed that ADI's datasheet 
says ADIN1110 supports OPEN Alliance 10BASE-T1x MAC-PHY serial
interface.
https://www.analog.com/media/en/technical-documentation/data-sheets/adin1110.pdf

But in my first glance in their driver code, I don't see any code block 
which implements 10BASE-T1x MAC_PHY Serial Interface Specification 
defined by OPEN Alliance TC6 group. Or do I miss anything here?. My code 
reference is below FYR,
https://elixir.bootlin.com/linux/v6.6-rc2/source/drivers/net/ethernet/adi/adin1110.c

OPEN Alliance 10BASE-T1x MAC_PHY Serial Interface Specification cab be 
downloaded from the below link,
https://opensig.org/automotive-ethernet-specifications/

I think Alexandru Tachici from ADI would be able to give us more 
information on this direction.
> 
> Am Fri, Sep 08, 2023 at 07:59:13PM +0530 schrieb Parthiban Veerasooran:
>> This patch series contain the below updates,
>> - Adds support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface in the
>>    net/ethernet/oa_tc6.c.
> 
> So this implements the "10BASE-T1x MAC-PHY Serial Interface
> Specification" which is Ethernet over SPI if I understand correctly?
> The above mentioned chip claims do use the same interface and the same
> standard.  How does its driver work then?  Do you add code for a thing
> already present in the kernel or does the other driver do something
> completely different and I just misunderstood?
As I mentioned above, in my first glance in their driver code, I don't 
see any code block which implements 10BASE-T1x MAC_PHY Serial Interface 
Specification defined by OPEN Alliance TC6 group. Let's Alexandru 
Tachici from ADI gives us more info on this.
> 
> Can the drivers for ADIN1110 and for LAN865X share code because they
> use the same specified interface?  The patch set does not look like
> it?
Of course, if their device supports OPEN Alliance then we can use this 
oa_tc6.c framework to support other 10BASE-T1x MACPHY's as well.
> 
> (Added the other driver author to Cc.)
Ok thanks.

Best Regards,
Parthiban V
> 
> Greets
> Alex
> 
>> - Adds driver support for Microchip LAN8650/1 Rev.B0 10BASE-T1S MACPHY
>>    Ethernet driver in the net/ethernet/microchip/lan865x.c.
>>
>> Parthiban Veerasooran (6):
>>    net: ethernet: implement OPEN Alliance control transaction interface
>>    net: ethernet: add mac-phy interrupt support with reset complete
>>      handling
>>    net: ethernet: implement OA TC6 configuration function
>>    net: ethernet: implement data transaction interface
>>    microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
>>    microchip: lan865x: add device-tree support for Microchip's LAN865X
>>      MACPHY
>>
>>   .../bindings/net/microchip,lan865x.yaml       |  54 ++
>>   Documentation/networking/oa-tc6-framework.rst | 231 +++++
>>   MAINTAINERS                                   |  15 +
>>   drivers/net/ethernet/microchip/Kconfig        |  10 +
>>   drivers/net/ethernet/microchip/Makefile       |   3 +
>>   drivers/net/ethernet/microchip/lan865x.c      | 589 +++++++++++++
>>   drivers/net/ethernet/oa_tc6.c                 | 807 ++++++++++++++++++
>>   include/linux/oa_tc6.h                        | 130 +++
>>   8 files changed, 1839 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/net/microchip,lan865x.yaml
>>   create mode 100644 Documentation/networking/oa-tc6-framework.rst
>>   create mode 100644 drivers/net/ethernet/microchip/lan865x.c
>>   create mode 100644 drivers/net/ethernet/oa_tc6.c
>>   create mode 100644 include/linux/oa_tc6.h
>>
>> --
>> 2.34.1
>>
>>


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
  2023-09-13 15:45     ` Krzysztof Kozlowski
@ 2023-09-18  9:23       ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-18  9:23 UTC (permalink / raw)
  To: krzysztof.kozlowski
  Cc: netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	andrew

Hi Krzysztof,

On 13/09/23 9:15 pm, Krzysztof Kozlowski wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On 13/09/2023 15:26, Parthiban.Veerasooran@microchip.com wrote:
>> Hi Krzysztof,
>>
>> On 10/09/23 4:25 pm, Krzysztof Kozlowski wrote:
>>> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>>>
>>> On 08/09/2023 16:29, Parthiban Veerasooran wrote:
>>>> This patch series contain the below updates,
>>>> - Adds support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface in the
>>>>     net/ethernet/oa_tc6.c.
>>>> - Adds driver support for Microchip LAN8650/1 Rev.B0 10BASE-T1S MACPHY
>>>>     Ethernet driver in the net/ethernet/microchip/lan865x.c.
>>>
>>> And why is this RFC? Do you mean by that it is buggy and not finished,
>>> so we should not review?
>>
>> No, this is not a buggy/unfinished patch series. I have added RFC as
> 
> I don't understand how people name their stuff RFC. Some send totally
> buggy and untested bindings under RFC and, after receiving feedback,
> respond surprised - it was just RFC!
> 
> Other send RFC and expect review.
> 
> Just call it a PATCH. PATCH is Requesting for Comments.
Ok, I understand your point. From the next version of patches, I will 
remove RFC.

Best Regards,
Parthiban V
> 
> Best regards,
> Krzysztof
> 
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface
  2023-09-14  1:18   ` Andrew Lunn
@ 2023-09-18 10:02     ` Parthiban.Veerasooran
  2023-09-18 13:01       ` Andrew Lunn
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-18 10:02 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 14/09/23 6:48 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> +static void oa_tc6_rx_eth_ready(struct oa_tc6 *tc6)
>> +{
>> +     struct sk_buff *skb = NULL;
>> +
>> +     /* Send the received ethernet packet to network layer */
>> +     skb = netdev_alloc_skb(tc6->netdev, tc6->rxd_bytes + NET_IP_ALIGN);
>> +     if (!skb) {
>> +             tc6->netdev->stats.rx_dropped++;
>> +             netdev_err(tc6->netdev, "Out of memory for rx'd frame");
> 
> Being out of memory is not likely to go away quickly. So i can see
> this spamming the kernel log. At minimum make it rate limited, or just
> rely on the counter and do not print anything.
Ok then I will use rate limited print like below,
if (printk_ratelimit())
	netdev_err(tc6->netdev, "Out of memory for rx'd frame");
> 
>> +static int oa_tc6_process_exst(struct oa_tc6 *tc6)
>> +{
>> +     u32 regval;
>> +     int ret;
>> +
>> +     ret = oa_tc6_read_register(tc6, OA_TC6_STS0, &regval, 1);
>> +     if (ret) {
>> +             netdev_err(tc6->netdev, "STS0 register read failed.\n");
>> +             return ret;
>> +     }
>> +     if (regval & TXPE)
>> +             netdev_err(tc6->netdev, "Transmit protocol error\n");
>> +     if (regval & TXBOE)
>> +             netdev_err(tc6->netdev, "Transmit buffer overflow\n");
>> +     if (regval & TXBUE)
>> +             netdev_err(tc6->netdev, "Transmit buffer underflow\n");
>> +     if (regval & RXBOE)
>> +             netdev_err(tc6->netdev, "Receive buffer overflow\n");
>> +     if (regval & LOFE)
>> +             netdev_err(tc6->netdev, "Loss of frame\n");
>> +     if (regval & HDRE)
>> +             netdev_err(tc6->netdev, "Header error\n");
>> +     if (regval & TXFCSE)
>> +             netdev_err(tc6->netdev, "Transmit Frame Check Sequence Error\n");
> 
> Do you expect these problems to magically fix themselves, or is this
> going to spam the kernel log until the machine is rebooted?
Yes, with the current implementation the system need to be rebooted. I 
will keep a rate limited print for the user reference so that it will 
not spam the kernel.
> 
> It seems a counter would be more appropriate, and maybe one rate
> limited message if the problem persists.
I prefer a rate limited print.
> 
> Please look at all your netdev_err() calls and consider if they are
> really needed, should they be netdev_dbg(), or statistics counters.
Sure, I will fix all the prints in the next version with the required 
approach.
> 
>> +static int oa_tc6_process_rx_chunks(struct oa_tc6 *tc6, u8 *buf, u16 len)
>> +{
>> +     u8 cp_count;
>> +     u8 *payload;
>> +     u32 ftr;
>> +     u16 ebo;
>> +     u16 sbo;
>> +
>> +     /* Calculate the number of chunks received */
>> +     cp_count = len / (tc6->cps + TC6_FTR_SIZE);
>> +
>> +     for (u8 i = 0; i < cp_count; i++) {
>> +             /* Get the footer and payload */
>> +             ftr = *(u32 *)&buf[tc6->cps + (i * (tc6->cps + TC6_FTR_SIZE))];
>> +             ftr = be32_to_cpu(ftr);
>> +             payload = &buf[(i * (tc6->cps + TC6_FTR_SIZE))];
>> +             /* Check for footer parity error */
>> +             if (oa_tc6_get_parity(ftr)) {
>> +                     netdev_err(tc6->netdev, "Footer: Parity error\n");
>> +                     goto err_exit;
>> +             }
>> +             /* If EXST set in the footer then read STS0 register to get the
>> +              * status information.
>> +              */
>> +             if (FIELD_GET(DATA_FTR_EXST, ftr)) {
>> +                     if (oa_tc6_process_exst(tc6))
>> +                             netdev_err(tc6->netdev, "Failed to process EXST\n");
>> +                     goto err_exit;
>> +             }
>> +             if (FIELD_GET(DATA_FTR_HDRB, ftr)) {
>> +                     netdev_err(tc6->netdev, "Footer: Received header bad\n");
>> +                     goto err_exit;
>> +             }
>> +             if (!FIELD_GET(DATA_FTR_SYNC, ftr)) {
>> +                     netdev_err(tc6->netdev, "Footer: Configuration unsync\n");
>> +                     goto err_exit;
>> +             }
>> +             /* If Frame Drop is set, indicates that the MAC has detected a
>> +              * condition for which the SPI host should drop the received
>> +              * ethernet frame.
>> +              */
>> +             if (FIELD_GET(DATA_FTR_FD, ftr) && FIELD_GET(DATA_FTR_EV, ftr)) {
>> +                     netdev_warn(tc6->netdev, "Footer: Frame drop\n");
>> +                     if (FIELD_GET(DATA_FTR_SV, ftr)) {
>> +                             goto start_new_frame;
>> +                     } else {
>> +                             if (tc6->rx_eth_started) {
>> +                                     tc6->rxd_bytes = 0;
>> +                                     tc6->rx_eth_started = false;
>> +                                     tc6->netdev->stats.rx_dropped++;
>> +                             }
>> +                             continue;
>> +                     }
>> +             }
>> +             /* Check for data valid */
>> +             if (FIELD_GET(DATA_FTR_DV, ftr)) {
>> +                     /* Check whether both start valid and end valid are in a
>> +                      * single chunk payload means a single chunk payload may
>> +                      * contain an entire ethernet frame.
>> +                      */
>> +                     if (FIELD_GET(DATA_FTR_SV, ftr) &&
>> +                         FIELD_GET(DATA_FTR_EV, ftr)) {
>> +                             sbo = FIELD_GET(DATA_FTR_SWO, ftr) * 4;
>> +                             ebo = FIELD_GET(DATA_FTR_EBO, ftr) + 1;
>> +                             if (ebo <= sbo) {
>> +                                     memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
>> +                                            &payload[0], ebo);
>> +                                     tc6->rxd_bytes += ebo;
>> +                                     oa_tc6_rx_eth_ready(tc6);
>> +                                     tc6->rxd_bytes = 0;
>> +                                     memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
>> +                                            &payload[sbo], tc6->cps - sbo);
>> +                                     tc6->rxd_bytes += (tc6->cps - sbo);
>> +                                     goto exit;
>> +                             } else {
>> +                                     memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
>> +                                            &payload[sbo], ebo - sbo);
>> +                                     tc6->rxd_bytes += (ebo - sbo);
>> +                                     oa_tc6_rx_eth_ready(tc6);
>> +                                     tc6->rxd_bytes = 0;
>> +                                     goto exit;
>> +                             }
>> +                     }
>> +start_new_frame:
>> +                     /* Check for start valid to start capturing the incoming
>> +                      * ethernet frame.
>> +                      */
>> +                     if (FIELD_GET(DATA_FTR_SV, ftr) && !tc6->rx_eth_started) {
>> +                             tc6->rxd_bytes = 0;
>> +                             tc6->rx_eth_started = true;
>> +                             sbo = FIELD_GET(DATA_FTR_SWO, ftr) * 4;
>> +                             memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
>> +                                    &payload[sbo], tc6->cps - sbo);
>> +                             tc6->rxd_bytes += (tc6->cps - sbo);
>> +                             goto exit;
>> +                     }
>> +
>> +                     /* Check for end valid and calculate the copy length */
>> +                     if (tc6->rx_eth_started) {
>> +                             if (FIELD_GET(DATA_FTR_EV, ftr))
>> +                                     ebo = FIELD_GET(DATA_FTR_EBO, ftr) + 1;
>> +                             else
>> +                                     ebo = tc6->cps;
>> +
>> +                             memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes],
>> +                                    &payload[0], ebo);
>> +                             tc6->rxd_bytes += ebo;
>> +                             if (FIELD_GET(DATA_FTR_EV, ftr)) {
>> +                                     /* If End Valid set then send the
>> +                                      * received ethernet frame to n/w.
>> +                                      */
>> +                                     oa_tc6_rx_eth_ready(tc6);
>> +                                     tc6->rxd_bytes = 0;
>> +                                     tc6->rx_eth_started = false;
>> +                             }
>> +                     }
>> +             }
>> +
>> +exit:
>> +             tc6->txc = FIELD_GET(DATA_FTR_TXC, ftr);
>> +             tc6->rca = FIELD_GET(DATA_FTR_RCA, ftr);
>> +     }
>> +     return FTR_OK;
>> +
>> +err_exit:
>> +     if (tc6->rx_eth_started) {
>> +             tc6->rxd_bytes = 0;
>> +             tc6->rx_eth_started = false;
>> +             tc6->netdev->stats.rx_dropped++;
>> +     }
>> +     return FTR_ERR;
>> +}
> 
> This is quite a complex function, with a lot of gotos. Please try to
> split it up into helpers.
Yes sure, will do it.
> 
>> +
>>   static int oa_tc6_handler(void *data)
>>   {
>>        struct oa_tc6 *tc6 = data;
>> +     bool txc_wait = false;
>> +     u16 tx_pos = 0;
>>        u32 regval;
>> +     u16 len;
>>        int ret;
>>
>>        while (likely(!kthread_should_stop())) {
>> -             wait_event_interruptible(tc6->tc6_wq, tc6->int_flag ||
>> +             wait_event_interruptible(tc6->tc6_wq, tc6->tx_flag ||
>> +                                      tc6->int_flag || tc6->rca ||
>>                                         kthread_should_stop());
>> -             if (tc6->int_flag) {
>> +             if (tc6->int_flag && !tc6->reset) {
>>                        tc6->int_flag = false;
>> +                     tc6->reset = true;
>>                        ret = oa_tc6_perform_ctrl(tc6, OA_TC6_STS0, &regval, 1,
>>                                                  false, false);
>>                        if (ret) {
>> @@ -227,10 +435,170 @@ static int oa_tc6_handler(void *data)
>>                                complete(&tc6->rst_complete);
>>                        }
>>                }
>> +
>> +             if (tc6->int_flag || tc6->rca) {
>> +                     /* If rca is updated from the previous footer then
>> +                      * prepare the empty chunks equal to rca and perform
>> +                      * SPI transfer to receive the ethernet frame.
>> +                      */
>> +                     if (tc6->rca) {
>> +                             len = oa_tc6_prepare_empty_chunk(tc6,
>> +                                                              tc6->spi_tx_buf,
>> +                                                              tc6->rca);
>> +                     } else {
>> +                             /* If there is an interrupt then perform a SPI
>> +                              * transfer with a empty chunk to get the
>> +                              * details.
>> +                              */
>> +                             tc6->int_flag = false;
>> +                             len = oa_tc6_prepare_empty_chunk(tc6,
>> +                                                              tc6->spi_tx_buf,
>> +                                                              1);
>> +                     }
>> +                     /* Perform SPI transfer */
>> +                     ret = oa_tc6_spi_transfer(tc6->spi, tc6->spi_tx_buf,
>> +                                               tc6->spi_rx_buf, len);
>> +                     if (ret) {
>> +                             netdev_err(tc6->netdev, "SPI transfer failed\n");
>> +                             continue;
>> +                     }
>> +                     /* Process the received chunks to get the ethernet frame
>> +                      * or interrupt details.
>> +                      */
>> +                     if (oa_tc6_process_rx_chunks(tc6, tc6->spi_rx_buf, len))
>> +                             continue;
>> +             }
>> +
>> +             /* If there is a tx ethernet frame available */
>> +             if (tc6->tx_flag || txc_wait) {
>> +                     tc6->tx_flag = false;
>> +                     txc_wait = false;
>> +                     len = 0;
>> +                     if (!tc6->txc) {
>> +                             /* If there is no txc available to transport the
>> +                              * tx ethernet frames then wait for the MAC-PHY
>> +                              * interrupt to get the txc availability.
>> +                              */
>> +                             txc_wait = true;
>> +                             continue;
>> +                     } else if (tc6->txc >= tc6->txc_needed) {
>> +                             len = tc6->txc_needed * (tc6->cps + TC6_HDR_SIZE);
>> +                     } else {
>> +                             len = tc6->txc * (tc6->cps + TC6_HDR_SIZE);
>> +                     }
>> +                     memcpy(&tc6->spi_tx_buf[0], &tc6->eth_tx_buf[tx_pos],
>> +                            len);
>> +                     ret = oa_tc6_spi_transfer(tc6->spi, tc6->spi_tx_buf,
>> +                                               tc6->spi_rx_buf, len);
>> +                     if (ret) {
>> +                             netdev_err(tc6->netdev, "SPI transfer failed\n");
>> +                             continue;
>> +                     }
>> +                     /* Process the received chunks to get the ethernet frame
>> +                      * or status.
>> +                      */
>> +                     if (oa_tc6_process_rx_chunks(tc6, tc6->spi_rx_buf,
>> +                                                  len)) {
>> +                             /* In case of error while processing rx chunks
>> +                              * discard the incomplete tx ethernet frame and
>> +                              * resend it.
>> +                              */
>> +                             tx_pos = 0;
>> +                             tc6->txc_needed = tc6->total_txc_needed;
>> +                     } else {
>> +                             tx_pos += len;
>> +                             tc6->txc_needed = tc6->txc_needed -
>> +                                               (len / (tc6->cps + TC6_HDR_SIZE));
>> +                             /* If the complete ethernet frame is transmitted
>> +                              * then return the skb and update the details to
>> +                              * n/w layer.
>> +                              */
>> +                             if (!tc6->txc_needed) {
>> +                                     tc6->netdev->stats.tx_packets++;
>> +                                     tc6->netdev->stats.tx_bytes += tc6->tx_skb->len;
>> +                                     dev_kfree_skb(tc6->tx_skb);
>> +                                     tx_pos = 0;
>> +                                     tc6->tx_skb = NULL;
>> +                                     if (netif_queue_stopped(tc6->netdev))
>> +                                             netif_wake_queue(tc6->netdev);
>> +                             } else if (tc6->txc) {
>> +                                     /* If txc is available again and updated
>> +                                      * from the previous footer then perform
>> +                                      * tx again.
>> +                                      */
>> +                                     tc6->tx_flag = true;
>> +                             } else {
>> +                                     /* If there is no txc then wait for the
>> +                                      * interrupt to indicate txc
>> +                                      * availability.
>> +                                      */
>> +                                     txc_wait = true;
>> +                             }
>> +                     }
>> +             }
>>        }
>>        return 0;
>>   }
> 
> This is also a huge function. The Linux coding style says:
> 
>       Functions should be short and sweet, and do just one thing. They
>       should fit on one or two screenfuls of text (the ISO/ANSI screen
>       size is 80x24, as we all know), and do one thing and do that
>       well.
> 
Thanks for the info. Sure, will do it.
> Please break this up into lots of smaller functions which do just one
> thing.
> 
>> -struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
>> +struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev)
>>   {
>>        struct oa_tc6 *tc6;
>>        int ret;
>> @@ -334,11 +710,39 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
>>        if (!spi)
>>                return NULL;
>>
>> +     if (!netdev)
>> +             return NULL;
> 
> Hos can this happen? Let is explode if some developer is dumb enough
> to pass a NULL.
> 
>> +#define MAX_ETH_LEN  1536
> 
> Where do 1536 come from? Maybe this needs an OA_TC6 prefix to make it
> clear this is specific to this protocol?
Ah it is a mistake. It is supposed to be an ethernet packet size which 
is 1518 (1500 bytes MTU size + 18 bytes overhead) and it is not from OA. 
It is a mistake and will correct it in the next version.

Best Regards,
Parthiban V
> 
>        Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  2023-09-15 13:01   ` David Wretman
@ 2023-09-18 11:22     ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-18 11:22 UTC (permalink / raw)
  To: david.wretman
  Cc: Nicolas.Ferre, Thorsten.Kummermehr, UNGLinuxDriver, Woojung.Huh,
	andrew, casper.casan, conor+dt, corbet, davem, devicetree,
	edumazet, Horatiu.Vultur, horms, krzysztof.kozlowski+dt, kuba,
	linux-doc, linux-kernel, netdev, pabeni, rdunlap, robh+dt,
	Steen.Hegelund

Hi David,

Thanks for your comments. Please see my reply below,

On 15/09/23 6:31 pm, David Wretman wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> ---
> On Fri, Sep 08, 2023 at 07:59:18PM +0530, Parthiban Veerasooran wrote:
>> The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE‑T1x
>> MAC‑PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
>> MAC integration provides the low pin count standard SPI interface to any
>> microcontroller therefore providing Ethernet functionality without
>> requiring MAC integration within the microcontroller. The LAN8650/1
>> operates as an SPI client supporting SCLK clock rates up to a maximum of
>> 25 MHz. This SPI interface supports the transfer of both data (Ethernet
>> frames) and control (register access).
>>
>> By default, the chunk data payload is 64 bytes in size. A smaller payload
>> data size of 32 bytes is also supported and may be configured in the
>> Chunk Payload Size (CPS) field of the Configuration 0 (OA_CONFIG0)
>> register. Changing the chunk payload size requires the LAN8650/1 be reset
>> and shall not be done during normal operation.
>>
>> The Ethernet Media Access Controller (MAC) module implements a 10 Mbps
>> half duplex Ethernet MAC, compatible with the IEEE 802.3 standard.
>> 10BASE-T1S physical layer transceiver integrated into the LAN8650/1. The
>> PHY and MAC are connected via an internal Media Independent Interface
>> (MII).
>>
>> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
> 
> Hi Parthiban,
> 
> Thanks for these patches.
> 
> One thing I am missing is settings for PLCA parameters. I feel that the
> driver is a bit lacking as long as this is missing.
No it is not missed. The driver still supports for setting the PLCA 
parameters using ethtool. This is just a MAC driver and its internal 
PHY's driver is already mainlined which has PLCA setting support. Please 
have a look in the below link which has the implementation.

https://elixir.bootlin.com/linux/latest/source/drivers/net/phy/microchip_t1s.c#L283

You can use the below ethtool command to set your PLCA settings.

$ ethtool --set-plca-cfg eth1 enable on node-id 0 node-cnt 8 to-tmr 0x20 
burst-cnt 0x0 burst-tmr 0x80
> 
> Adding support for the ethtool plca options would make this much more
> complete.
Hope the above explanation helps. Please let me know if I misunderstand 
your comment.

Best Regards,
Parthiban V
> 
> Regards,
> David
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  2023-09-14  1:55   ` Andrew Lunn
@ 2023-09-18 11:23     ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-18 11:23 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 14/09/23 7:25 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> +#define REG_STDR_RESET               0x00000003
> 
> This appears to be a standard register, so you should not need to
> define it here.
Ah ok, will do it.
> 
>> +#define REG_MAC_ADDR_BO              0x00010022
>> +#define REG_MAC_ADDR_L               0x00010024
>> +#define REG_MAC_ADDR_H               0x00010025
>> +#define REG_MAC_NW_CTRL         0x00010000
>> +#define REG_MAC_NW_CONFIG    0x00010001
>> +#define REG_MAC_HASHL                0x00010020
>> +#define REG_MAC_HASHH                0x00010021
>> +#define REG_MAC_ADDR_BO              0x00010022
>> +#define REG_MAC_ADDR_L               0x00010024
>> +#define REG_MAC_ADDR_H               0x00010025
>> +
>> +#define CCS_Q0_TX_CFG                0x000A0081
>> +#define CCS_Q0_RX_CFG                0x000A0082
> 
> These are proprietary vendor registers, so please add a prefix to make
> this clear.
Sure, will add it in the next version.

Best Regards,
Parthiban V
> 
>       Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface
  2023-09-18 10:02     ` Parthiban.Veerasooran
@ 2023-09-18 13:01       ` Andrew Lunn
  2023-09-19 10:12         ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-18 13:01 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> >> +#define MAX_ETH_LEN  1536
> > 
> > Where do 1536 come from? Maybe this needs an OA_TC6 prefix to make it
> > clear this is specific to this protocol?
> Ah it is a mistake. It is supposed to be an ethernet packet size which 
> is 1518 (1500 bytes MTU size + 18 bytes overhead) and it is not from OA. 
> It is a mistake and will correct it in the next version.

Please try to express this using ETH_DATA_LEN + sizeof(struct
oa_tc6_overhead). Doing it like this will avoid errors like this since
it is also part documentation.

   Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Fwd: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
  2023-09-18  9:02     ` Fwd: " Parthiban.Veerasooran
@ 2023-09-19  9:03       ` Parthiban.Veerasooran
  2023-09-19 16:23         ` Jay Monkman
  2023-09-19 18:09         ` Hennerich, Michael
  0 siblings, 2 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-19  9:03 UTC (permalink / raw)
  To: Michael.Hennerich, Ciprian.Regus, andrew, jtm
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	ada

Hi,

@Andrew: As you pointed out in another email, I have included Jay 
Monkman as well in this email to discuss further.

@Jay Monkman: Yesterday, Andrew noticed that you submitted a patch 
series for NCN26010 which is a 10BASE-T1S MACPHY which uses OPEN 
Alliance spec.

@Michael Hennerich: I am forwarding this email to you so that you will 
get the history behind this conversation. Please have a look in the 
below email for the clarification we need.

Microchip's product link is below,

https://www.microchip.com/en-us/product/lan8650

We already pushed the driver patches for supporting the above 
Microchip's LAN865x MACPHY and the OPEN Alliance spec to the mainline 
and it is under review. Please refer the below link to get a complete 
picture of this patch series.

https://lore.kernel.org/netdev/20230913152625.73e32789@wsk/T/

We have developed 10BASE-T1x MAC_PHY Serial Interface Specification 
defined by OPEN Alliance TC6 group as a separate framework/generic lib 
and included in this patch series so that all the 10BASE-T1x MACPHY 
vendors can make use of it.

As Andrew suggested, it would be nice if we all work together to make it 
better. Please feel free to share your comments/ideas to improve the 
framework.

 From my next reply on-wards I will include Michael.Hennerich, Ciprian 
Regus and Jay Monkman in the "--to" or "--cc" so that we can share our 
ideas and comments.

I have brought everyone in this email so that we all in sync discussing 
the same topic and sharing our ideas. Please stick with this email or 
other patch series email for further communications to share all our ideas.

I hope this helps. Please let me know if you have any query on this.

Best Regards,
Parthiban V

-------- Forwarded Message --------
Subject: Fwd: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 
10BASE-T1x MACPHY Serial Interface
Date: Mon, 18 Sep 2023 14:32:24 +0530
From: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
To: Lennart Franzen <lennart@lfdomain.com>, Alexander Dahl 
<ada@thorsis.com>, Andrew Lunn <andrew@lunn.ch>
CC: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, 
pabeni@redhat.com, robh+dt@kernel.org, 
krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org, corbet@lwn.net, 
steen.hegelund@microchip.com, rdunlap@infradead.org, horms@kernel.org, 
casper.casan@gmail.com, netdev@vger.kernel.org, 
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, 
linux-doc@vger.kernel.org, horatiu.vultur@microchip.com, 
Woojung.Huh@microchip.com, Nicolas.Ferre@microchip.com, 
UNGLinuxDriver@microchip.com, Thorsten.Kummermehr@microchip.com

Hi Lennart,

I am forwarding this email to you as we are not able to reach the module 
author Alexandru Tachici <alexandru.tachici@analog.com> and getting the 
below email delivery error.

----cut here-----
Delivery has failed to these recipients or groups:

alexandru.tachici@analog.com<mailto:alexandru.tachici@analog.com>
The email address you entered couldn't be found. Please check the
recipient's email address and try to resend the message. If the problem
continues, please contact your email admin.
----cut here------

We got your your email address from the commit 
bc93e19d088bb14e116756ab270deea6ee62d782. Regarding the below topic, are 
you the right contact parson to continue further on this topic or else 
do you have any other contact to approach? Please let us know.

Best Regards,
Parthiban V
-------- Forwarded Message --------
Subject: Re: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 
10BASE-T1x MACPHY Serial Interface
Date: Mon, 18 Sep 2023 11:42:33 +0530
From: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
To: ada@thorsis.com, Alexandru Tachici <alexandru.tachici@analog.com>, 
Andrew Lunn <andrew@lunn.ch>
CC: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, 
pabeni@redhat.com, robh+dt@kernel.org, 
krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org, corbet@lwn.net, 
steen.hegelund@microchip.com, rdunlap@infradead.org, horms@kernel.org, 
casper.casan@gmail.com, netdev@vger.kernel.org, 
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, 
linux-doc@vger.kernel.org, horatiu.vultur@microchip.com, 
Woojung.Huh@microchip.com, Nicolas.Ferre@microchip.com, 
UNGLinuxDriver@microchip.com, Thorsten.Kummermehr@microchip.com

Hi Alexander,

Thanks for the information. Please see my reply below.

On 15/09/23 7:26 pm, Alexander Dahl wrote:
> [Some people who received this message don't often get email from ada@thorsis.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
> 
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> Hello,
> 
> this is interesting, by chance I just looked at a chip claiming
> similar features today, which already has a driver in kernel: Analog
> Devices ADIN1110.
Microchip's LAN865x is a 10BASE-T1S MACPHY and Analog Devices's ADIN1110 
is a 10BASE-T1L MACPHY. So as you said 10BASE-T1x MAC_PHY Serial 
Interface Specification defined by OPEN Alliance TC6 group can be 
applicable for both of the devices. I also noticed that ADI's datasheet 
says ADIN1110 supports OPEN Alliance 10BASE-T1x MAC-PHY serial
interface.
https://www.analog.com/media/en/technical-documentation/data-sheets/adin1110.pdf

But in my first glance in their driver code, I don't see any code block 
which implements 10BASE-T1x MAC_PHY Serial Interface Specification 
defined by OPEN Alliance TC6 group. Or do I miss anything here?. My code 
reference is below FYR,
https://elixir.bootlin.com/linux/v6.6-rc2/source/drivers/net/ethernet/adi/adin1110.c

OPEN Alliance 10BASE-T1x MAC_PHY Serial Interface Specification cab be 
downloaded from the below link,
https://opensig.org/automotive-ethernet-specifications/

I think Alexandru Tachici from ADI would be able to give us more 
information on this direction.
> 
> Am Fri, Sep 08, 2023 at 07:59:13PM +0530 schrieb Parthiban Veerasooran:
>> This patch series contain the below updates,
>> - Adds support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface in the
>>    net/ethernet/oa_tc6.c.
> 
> So this implements the "10BASE-T1x MAC-PHY Serial Interface
> Specification" which is Ethernet over SPI if I understand correctly?
> The above mentioned chip claims do use the same interface and the same
> standard.  How does its driver work then?  Do you add code for a thing
> already present in the kernel or does the other driver do something
> completely different and I just misunderstood?
As I mentioned above, in my first glance in their driver code, I don't 
see any code block which implements 10BASE-T1x MAC_PHY Serial Interface 
Specification defined by OPEN Alliance TC6 group. Let's Alexandru 
Tachici from ADI gives us more info on this.
> 
> Can the drivers for ADIN1110 and for LAN865X share code because they
> use the same specified interface?  The patch set does not look like
> it?
Of course, if their device supports OPEN Alliance then we can use this 
oa_tc6.c framework to support other 10BASE-T1x MACPHY's as well.
> 
> (Added the other driver author to Cc.)
Ok thanks.

Best Regards,
Parthiban V
> 
> Greets
> Alex
> 
>> - Adds driver support for Microchip LAN8650/1 Rev.B0 10BASE-T1S MACPHY
>>    Ethernet driver in the net/ethernet/microchip/lan865x.c.
>>
>> Parthiban Veerasooran (6):
>>    net: ethernet: implement OPEN Alliance control transaction interface
>>    net: ethernet: add mac-phy interrupt support with reset complete
>>      handling
>>    net: ethernet: implement OA TC6 configuration function
>>    net: ethernet: implement data transaction interface
>>    microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
>>    microchip: lan865x: add device-tree support for Microchip's LAN865X
>>      MACPHY
>>
>>   .../bindings/net/microchip,lan865x.yaml       |  54 ++
>>   Documentation/networking/oa-tc6-framework.rst | 231 +++++
>>   MAINTAINERS                                   |  15 +
>>   drivers/net/ethernet/microchip/Kconfig        |  10 +
>>   drivers/net/ethernet/microchip/Makefile       |   3 +
>>   drivers/net/ethernet/microchip/lan865x.c      | 589 +++++++++++++
>>   drivers/net/ethernet/oa_tc6.c                 | 807 ++++++++++++++++++
>>   include/linux/oa_tc6.h                        | 130 +++
>>   8 files changed, 1839 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/net/microchip,lan865x.yaml
>>   create mode 100644 Documentation/networking/oa-tc6-framework.rst
>>   create mode 100644 drivers/net/ethernet/microchip/lan865x.c
>>   create mode 100644 drivers/net/ethernet/oa_tc6.c
>>   create mode 100644 include/linux/oa_tc6.h
>>
>> --
>> 2.34.1
>>
>>


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  2023-09-14  1:51   ` Andrew Lunn
@ 2023-09-19  9:18     ` Parthiban.Veerasooran
  2023-09-19 12:50       ` Andrew Lunn
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-19  9:18 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 14/09/23 7:21 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> +#define DRV_VERSION          "0.1"
> 
> This is pointless. The ethtool code will fill in the git hash which is
> a much more useful value to have.
Ah ok, so I can also remove the below code updating this info in the 
lan865x_get_drvinfo() function.

strscpy(info->version, DRV_VERSION, sizeof(info->version));
> 
>> +static void lan865x_handle_link_change(struct net_device *netdev)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +
>> +     phy_print_status(priv->phydev);
>> +}
>> +
>> +static int lan865x_mdiobus_read(struct mii_bus *bus, int phy_id, int idx)
>> +{
>> +     struct lan865x_priv *priv = bus->priv;
>> +     u32 regval;
>> +     bool ret;
>> +
>> +     ret = oa_tc6_read_register(priv->tc6, 0xFF00 | (idx & 0xFF), &regval, 1);
>> +     if (ret)
>> +             return -ENODEV;
>> +
>> +     return regval;
>> +}
>> +
>> +static int lan865x_mdiobus_write(struct mii_bus *bus, int phy_id, int idx,
>> +                              u16 regval)
>> +{
>> +     struct lan865x_priv *priv = bus->priv;
>> +     u32 value = regval;
>> +     bool ret;
>> +
>> +     ret = oa_tc6_write_register(priv->tc6, 0xFF00 | (idx & 0xFF), &value, 1);
>> +     if (ret)
>> +             return -ENODEV;
>> +
>> +     return 0;
>> +}
>> +
>> +static int lan865x_phy_init(struct lan865x_priv *priv)
>> +{
>> +     int ret;
>> +
>> +     priv->mdiobus = mdiobus_alloc();
>> +     if (!priv->mdiobus) {
>> +             netdev_err(priv->netdev, "MDIO bus alloc failed\n");
>> +             return -ENODEV;
>> +     }
>> +
>> +     priv->mdiobus->phy_mask = ~(u32)BIT(1);
>> +     priv->mdiobus->priv = priv;
>> +     priv->mdiobus->read = lan865x_mdiobus_read;
>> +     priv->mdiobus->write = lan865x_mdiobus_write;
> 
> The MDIO bus is part of the standard. So i would expect this to be in
> the library. From what i remember, there are two different ways to
> implement MDIO, either via the PHY registers being directly mapped
> into the register space, or indirect like this. And i think there is a
> status bit somewhere which tells you which is implemented? So please
> move this code into the library, but check the status bit and return
> ENODEV if the silicon does not actually implement this access method.
Sure, I can move this part to oa_tc6 lib. If I understand you correctly 
you are talking about the Standard Capabilities Register (0x0002) 
defined in the OPEN Alliance 10BASE-T1x MAC-PHY Serial Interface spec 
right? If so, the 9th bit of this register tells about Indirect PHY 
Register access Capability. Did you mean this bit? If so, this bit 
describes the below,

IPRAC - Indirect PHY Register Access Capability. Indicates if PHY 
registers are indirectly accessible through the MDIO/MDC registers MDIOACCn.

The MDIOACCn – MDIO Access Register 0-7 is defined under Register Memory 
Map 0 - Standard Control and Status Registers of the OA spec. As you 
said, some vendors may implement this and some may not be. But still we 
have PHY clause 45 registers indirect access through clause 22 registers 
namely 0xd and 0xe. Using them we will be able to create a MDIO virtual 
bus to access PHY clause 45 registers. We already have all the required 
API's provided by Linux for this approach.

https://elixir.bootlin.com/linux/v6.6-rc2/source/drivers/net/phy/phy-core.c#L529

Microchip's LAN865x doesn't support OA provided indirect access of PHY 
registers. But it supports PHY registers indirect access through clause 
22 registers namely 0xd and 0xe. Also it supports direct PHY register 
access within the SPI register memory space.

As the PLCA registers are already standardized and mainlined it will be 
more straight forward if the driver implements the PHY register indirect 
access using clause 22. Otherwise there will be an extra effort for 
mapping those PLCA registers into SPI memory space to access them 
directly. Also every vendor will have their own SPI memory space to map.

https://elixir.bootlin.com/linux/v6.6-rc2/source/drivers/net/phy/mdio-open-alliance.h

So my proposal would be, I stick with this standard implementation of 
indirect PHY register access through clause 22 registers 0xd and 0xe. I 
believe almost all the vendors will have this access. Later we will add 
this feature tested (Since Microchip's LAN865x doesn't support this, I 
can't test) if there is a vendor supports this. What do you think?
> 
>> +static int
>> +lan865x_set_link_ksettings(struct net_device *netdev,
>> +                        const struct ethtool_link_ksettings *cmd)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +     int ret = 0;
>> +
>> +     if (cmd->base.autoneg != AUTONEG_DISABLE ||
>> +         cmd->base.speed != SPEED_10 || cmd->base.duplex != DUPLEX_HALF) {
>> +             if (netif_msg_link(priv))
>> +                     netdev_warn(netdev, "Unsupported link setting");
>> +             ret = -EOPNOTSUPP;
>> +     } else {
>> +             if (netif_msg_link(priv))
>> +                     netdev_warn(netdev, "Hardware must be disabled to set link mode");
>> +             ret = -EBUSY;
>> +     }
>> +     return ret;
> 
> I would expect to see a call to phy_ethtool_ksettings_set()
> here. phylib should be able to do some of the validation.
Ah ok, doing the below will make the life easier.
.set_link_ksettings	= phy_ethtool_set_link_ksettings,
> 
>> +}
>> +
>> +static int
>> +lan865x_get_link_ksettings(struct net_device *netdev,
>> +                        struct ethtool_link_ksettings *cmd)
>> +{
>> +     ethtool_link_ksettings_zero_link_mode(cmd, supported);
>> +     ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Half);
>> +     ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
>> +
>> +     cmd->base.speed = SPEED_10;
>> +     cmd->base.duplex = DUPLEX_HALF;
>> +     cmd->base.port  = PORT_TP;
>> +     cmd->base.autoneg = AUTONEG_DISABLE;
>> +
>> +     return 0;
> 
> phy_ethtool_ksettings_get().
Yes,
.get_link_ksettings	= phy_ethtool_get_link_ksettings,
> 
> I also think this can be moved along with the MDIO bus and PHY
> handling into the library.
Ok will do that.
> 
>> +static int lan865x_set_mac_address(struct net_device *netdev, void *addr)
>> +{
>> +     struct sockaddr *address = addr;
>> +
>> +     if (netif_running(netdev))
>> +             return -EBUSY;
>> +     if (!is_valid_ether_addr(address->sa_data))
>> +             return -EADDRNOTAVAIL;
> 
> Does the core allow an invalid MAC address be passed to the driver?
Ah yes, it is not needed here.
> 
>> +
>> +     eth_hw_addr_set(netdev, address->sa_data);
>> +     return lan865x_set_hw_macaddr(netdev);
>> +}
>> +
>> +static u32 lan865x_hash(u8 addr[ETH_ALEN])
>> +{
>> +     return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f;
>> +}
>> +
>> +static void lan865x_set_multicast_list(struct net_device *netdev)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +     u32 regval = 0;
>> +
>> +     if (netdev->flags & IFF_PROMISC) {
>> +             /* Enabling promiscuous mode */
>> +             regval |= MAC_PROMISCUOUS_MODE;
>> +             regval &= (~MAC_MULTICAST_MODE);
>> +             regval &= (~MAC_UNICAST_MODE);
>> +     } else if (netdev->flags & IFF_ALLMULTI) {
>> +             /* Enabling all multicast mode */
>> +             regval &= (~MAC_PROMISCUOUS_MODE);
>> +             regval |= MAC_MULTICAST_MODE;
>> +             regval &= (~MAC_UNICAST_MODE);
>> +     } else if (!netdev_mc_empty(netdev)) {
>> +             /* Enabling specific multicast addresses */
>> +             struct netdev_hw_addr *ha;
>> +             u32 hash_lo = 0;
>> +             u32 hash_hi = 0;
>> +
>> +             netdev_for_each_mc_addr(ha, netdev) {
>> +                     u32 bit_num = lan865x_hash(ha->addr);
>> +                     u32 mask = 1 << (bit_num & 0x1f);
>> +
>> +                     if (bit_num & 0x20)
>> +                             hash_hi |= mask;
>> +                     else
>> +                             hash_lo |= mask;
>> +             }
>> +             if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHH, &hash_hi, 1)) {
>> +                     if (netif_msg_timer(priv))
>> +                             netdev_err(netdev, "Failed to write reg_hashh");
>> +                     return;
>> +             }
>> +             if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHL, &hash_lo, 1)) {
>> +                     if (netif_msg_timer(priv))
>> +                             netdev_err(netdev, "Failed to write reg_hashl");
>> +                     return;
>> +             }
>> +             regval &= (~MAC_PROMISCUOUS_MODE);
>> +             regval &= (~MAC_MULTICAST_MODE);
>> +             regval |= MAC_UNICAST_MODE;
>> +     } else {
>> +             /* enabling local mac address only */
>> +             if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHH, &regval, 1)) {
>> +                     if (netif_msg_timer(priv))
>> +                             netdev_err(netdev, "Failed to write reg_hashh");
>> +                     return;
>> +             }
>> +             if (oa_tc6_write_register(priv->tc6, REG_MAC_HASHL, &regval, 1)) {
>> +                     if (netif_msg_timer(priv))
>> +                             netdev_err(netdev, "Failed to write reg_hashl");
>> +                     return;
>> +             }
>> +     }
>> +     if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CONFIG, &regval, 1)) {
>> +             if (netif_msg_timer(priv))
>> +                     netdev_err(netdev, "Failed to enable promiscuous mode");
>> +     }
>> +}
>> +
>> +static netdev_tx_t lan865x_send_packet(struct sk_buff *skb,
>> +                                    struct net_device *netdev)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +
>> +     return oa_tc6_send_eth_pkt(priv->tc6, skb);
>> +}
>> +
>> +static int lan865x_hw_disable(struct lan865x_priv *priv)
>> +{
>> +     u32 regval = NW_DISABLE;
>> +
>> +     if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CTRL, &regval, 1))
>> +             return -ENODEV;
>> +
>> +     return 0;
>> +}
>> +
>> +static int lan865x_net_close(struct net_device *netdev)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +     int ret;
>> +
>> +     netif_stop_queue(netdev);
>> +     ret = lan865x_hw_disable(priv);
>> +     if (ret) {
>> +             if (netif_msg_ifup(priv))
>> +                     netdev_err(netdev, "Failed to disable the hardware\n");
>> +             return ret;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int lan865x_hw_enable(struct lan865x_priv *priv)
>> +{
>> +     u32 regval = NW_TX_STATUS | NW_RX_STATUS;
>> +
>> +     if (oa_tc6_write_register(priv->tc6, REG_MAC_NW_CTRL, &regval, 1))
>> +             return -ENODEV;
>> +
>> +     return 0;
>> +}
>> +
>> +static int lan865x_net_open(struct net_device *netdev)
>> +{
>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>> +     int ret;
>> +
>> +     if (!is_valid_ether_addr(netdev->dev_addr)) {
>> +             if (netif_msg_ifup(priv))
>> +                     netdev_err(netdev, "Invalid MAC address %pm", netdev->dev_addr);
>> +             return -EADDRNOTAVAIL;
> 
> Using a random MAC address is the normal workaround for not having a
> valid MAC address via OTP flash etc.
Ah ok, you mean to use eth_hw_addr_random(netdev) instead of returning 
error.
> 
> 
>> +static int lan865x_get_dt_data(struct lan865x_priv *priv)
>> +{
>> +     struct spi_device *spi = priv->spi;
>> +     int ret;
>> +
>> +     if (of_property_present(spi->dev.of_node, "oa-chunk-size")) {
>> +             ret = of_property_read_u32(spi->dev.of_node, "oa-chunk-size",
>> +                                        &priv->cps);
>> +             if (ret < 0)
>> +                     return ret;
>> +     } else {
>> +             priv->cps = 64;
>> +             dev_info(&spi->dev, "Property oa-chunk-size is not found in dt and proceeding with the size 64\n");
>> +     }
>> +
>> +     if (of_property_present(spi->dev.of_node, "oa-tx-cut-through"))
>> +             priv->txcte = true;
>> +     else
>> +             dev_info(&spi->dev, "Property oa-tx-cut-through is not found in dt and proceeding with tx store and forward mode\n");
> 
> Please remove all these dev_info() prints. The device tree binding
> should make it clear what the defaults are when not specified in DT.
Ah ok, will remove them and update device tree binding.
> 
>> +
>> +     if (of_property_present(spi->dev.of_node, "oa-rx-cut-through"))
>> +             priv->rxcte = true;
>> +     else
>> +             dev_info(&spi->dev, "Property oa-rx-cut-through is not found in dt and proceeding with rx store and forward mode\n");
>> +
>> +     if (of_property_present(spi->dev.of_node, "oa-protected"))
>> +             priv->protected = true;
>> +     else
>> +             dev_info(&spi->dev, "Property oa-protected is not found in dt and proceeding with protection enabled\n");
> 
> Which of these are proprietary properties, and which are part of the
> standard? Please move parsing all the standard properties into the
> library.
Ah ok good idea. Will do that.
> 
>> +static int lan865x_probe(struct spi_device *spi)
>> +{
> 
> ...
> 
>> +
>> +     phy_start(priv->phydev);
>> +     return 0;
> 
> phy_start() is normally done in open, not probe.
Ok will move it.

Best Regards,
Parthiban V
> 
>              Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface
  2023-09-18 13:01       ` Andrew Lunn
@ 2023-09-19 10:12         ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-19 10:12 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 18/09/23 6:31 pm, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>>>> +#define MAX_ETH_LEN  1536
>>>
>>> Where do 1536 come from? Maybe this needs an OA_TC6 prefix to make it
>>> clear this is specific to this protocol?
>> Ah it is a mistake. It is supposed to be an ethernet packet size which
>> is 1518 (1500 bytes MTU size + 18 bytes overhead) and it is not from OA.
>> It is a mistake and will correct it in the next version.
> 
> Please try to express this using ETH_DATA_LEN + sizeof(struct
> oa_tc6_overhead). Doing it like this will avoid errors like this since
> it is also part documentation.
Ok, in my case the define would be,

#define MAX_ETH_LEN      (ETH_DATA_LEN + ETH_HLEN + ETH_FCS_LEN)

Best Regards,
Parthiban V

> 
>     Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 6/6] microchip: lan865x: add device-tree support for Microchip's LAN865X MACPHY
  2023-09-14  2:07   ` Andrew Lunn
@ 2023-09-19 10:40     ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-19 10:40 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 14/09/23 7:37 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> +  oa-chunk-size: true
>> +  oa-tx-cut-through: true
>> +  oa-rx-cut-through: true
>> +  oa-protected: true
> 
> Please split this up into properties all OA TC6 devices are expected
> to use, and those specific to the LAN865x. Put the generic properties
> into a .yaml file, which you then inherit into the device specific
> yaml file.
> 
> Also, LAN865x specific properties should have a vendor prefix.
Sure, will do both.

Best Regards,
Parthiban V
> 
>          Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 6/6] microchip: lan865x: add device-tree support for Microchip's LAN865X MACPHY
  2023-09-12 13:17       ` Krzysztof Kozlowski
@ 2023-09-19 10:51         ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-19 10:51 UTC (permalink / raw)
  To: krzysztof.kozlowski
  Cc: netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	andrew

Hi Krzysztof,

On 12/09/23 6:47 pm, Krzysztof Kozlowski wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On 12/09/2023 14:15, Parthiban.Veerasooran@microchip.com wrote:
>> Hi Krzysztof,
>>
>> Thank you for reviewing the patch.
>>
>> On 10/09/23 4:25 pm, Krzysztof Kozlowski wrote:
>>> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>>>
>>> On 08/09/2023 16:29, Parthiban Veerasooran wrote:
>>>> Add device-tree support for Microchip's LAN865X MACPHY for configuring
>>>> the OPEN Alliance 10BASE-T1x MACPHY Serial Interface parameters.
>>>
>>> Please use subject prefixes matching the subsystem. You can get them for
>>> example with `git log --oneline -- DIRECTORY_OR_FILE` on the directory
>>> your patch is touching.
>> Ok sure, so it will become like,
>>
>> dt-bindings: net: add device-tree support for Microchip's LAN865X MACPHY
>>
>> I will correct it in the next revision.
> 
> "device-tree support for " is redundant, drop
Ah ok will do that.
> 
>>>
>>>>
>>>> Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
>>>> ---
>>>>    .../bindings/net/microchip,lan865x.yaml       | 54 +++++++++++++++++++
>>>>    MAINTAINERS                                   |  1 +
>>>>    2 files changed, 55 insertions(+)
>>>>    create mode 100644 Documentation/devicetree/bindings/net/microchip,lan865x.yaml
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/net/microchip,lan865x.yaml b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
>>>> new file mode 100644
>>>> index 000000000000..3465b2c97690
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
>>>> @@ -0,0 +1,54 @@
>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>>> +%YAML 1.2
>>>> +---
>>>> +$id: http://devicetree.org/schemas/net/microchip,lan865x.yaml#
>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>> +
>>>> +title: Microchip LAN8650/1 10BASE-T1S MACPHY Ethernet Controllers
>>>> +
>>>> +maintainers:
>>>> +  - Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
>>>> +
>>>> +description: |
>>>> +  Device tree properties for LAN8650/1 10BASE-T1S MACPHY Ethernet
>>>
>>> Drop "Device tree properties for" and instead describe the hardware.
>> sure, will do it.
>>>
>>>> +  controller.
>>>> +
>>>> +allOf:
>>>> +  - $ref: ethernet-controller.yaml#
>>>> +
>>>> +properties:
>>>> +  compatible:
>>>> +    items:
>>>
>>> No need for items. Just enum.
>> Ok noted.
>>>
>>>
>>>> +      - enum:
>>>> +          - microchip,lan865x
>>>
>>> No wildcards in compatibles.
>> Yes then we don't need enum also isn't it?
> 
> I don't see correlation between these two. Please read the writing
> bindings guidelines.
Ok, will check it out.
> 
> 
>>>
>>> Missing blank line.
>> Ok will add it.
>>>
>>>
>>>
>>>> +  reg:
>>>> +    maxItems: 1
>>>> +
>>>> +  local-mac-address: true
>>>> +  oa-chunk-size: true
>>>> +  oa-tx-cut-through: true
>>>> +  oa-rx-cut-through: true
>>>> +  oa-protected: true
>>>
>>> What are all these? Where are they defined that you skip description,
>>> type and vendor prefix?
>> Ok missed it. Will do it in the next revision.
> 
> No, drop them or explain why they are hardware properties.
Will separate hardware specific and OA specific properties.
> 
>>>
>>>> +
>>>> +required:
>>>> +  - compatible
>>>> +  - reg
>>>> +
>>>> +additionalProperties: false
>>>> +
>>>> +examples:
>>>> +  - |
>>>> +    spi {
>>>> +        #address-cells = <1>;
>>>> +        #size-cells = <0>;
>>>> +
>>>> +        ethernet@1{
>>>
>>> Missing space
>> Ok will add it.
>>>
>>>> +            compatible = "microchip,lan865x";
>>>> +            reg = <1>; /* CE0 */
>>>
>>> CE0? chip-select? What does this comment mean in this context?
>> Yes it is chip-select. Will add proper comment.
> 
> Why? isn't reg obvious?
Sorry, yes it is reg. The comment is wrong. Will remove it.

Best Regards,
Parthiban V
> 
> Best regards,
> Krzysztof
> 
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 3/6] net: ethernet: implement OA TC6 configuration function
  2023-09-14  0:46   ` Andrew Lunn
@ 2023-09-19 10:57     ` Parthiban.Veerasooran
  2023-09-19 12:54       ` Andrew Lunn
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-19 10:57 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 14/09/23 6:16 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> +int oa_tc6_configure(struct oa_tc6 *tc6, u8 cps, bool ctrl_prot, bool tx_cut_thr,
>> +                  bool rx_cut_thr)
>> +{
>> +     u32 regval;
>> +     int ret;
>> +
>> +     /* Read and configure the IMASK0 register for unmasking the interrupts */
>> +     ret = oa_tc6_read_register(tc6, OA_TC6_IMASK0, &regval, 1);
>> +     if (ret)
>> +             return ret;
>> +
>> +     regval &= TXPEM & TXBOEM & TXBUEM & RXBOEM & LOFEM & HDREM;
>> +     ret = oa_tc6_write_register(tc6, OA_TC6_IMASK0, &regval, 1);
> 
> It is not so obvious what this 1 means. Maybe change to regval[1], and
> user ARRAY_SIZE(). What also does not help is the function name,
> oa_tc6_write_register(). Singular. So it appears to write one register,
> not multiple registers. It might even make sense to make
> oa_tc6_write_register() truly access a single register, and add
> oa_tc6_write_registers() for multiple registers.
Ok, I will implement two functions to serve their purposes.
> 
>> +/* Unmasking interrupt fields in IMASK0 */
>> +#define HDREM                ~BIT(5)         /* Header Error Mask */
>> +#define LOFEM                ~BIT(4)         /* Loss of Framing Error Mask */
>> +#define RXBOEM               ~BIT(3)         /* Rx Buffer Overflow Error Mask */
>> +#define TXBUEM               ~BIT(2)         /* Tx Buffer Underflow Error Mask */
>> +#define TXBOEM               ~BIT(1)         /* Tx Buffer Overflow Error Mask */
>> +#define TXPEM                ~BIT(0)         /* Tx Protocol Error Mask */
> 
> Using ~BIT(X) is very usual. I would not do this, Principle of Least
> Surprise.
Sorry, I don't get your point. Could you please explain bit more?
> 
>>   struct oa_tc6 {
>> -     struct spi_device *spi;
>> -     bool ctrl_prot;
>> +     struct completion rst_complete;
>>        struct task_struct *tc6_task;
>>        wait_queue_head_t tc6_wq;
>> +     struct spi_device *spi;
>> +     bool tx_cut_thr;
>> +     bool rx_cut_thr;
>> +     bool ctrl_prot;
>>        bool int_flag;
>> -     struct completion rst_complete;
>> +     u8 cps;
>>   };
> 
> Please try not to move stuff around. It makes the diff bigger than it
> should be.
Ah ok, will take care in the next version.

Best Regards,
Parthiban V

> 
>         Andrew
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-13  2:19       ` Andrew Lunn
@ 2023-09-19 11:04         ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-19 11:04 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 13/09/23 7:49 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> Ok. If I understand correctly, I have to use devm_request_threaded_irq()
>> instead of devm_request_irq() and let the thread handler registered with
>> the devm_request_threaded_irq() function to perform interrupt activity
>> directly?
> 
> Yes. I've not looked at all the patches yet, but if the work queue is
> not used for anything else, you should be able to remove it, and let
> the IRQ core handle all the threading for you.
Sure, will implement it. Thanks.

Best Regards,
Parthiban V
> 
>      Andrew
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-13  2:16   ` Andrew Lunn
@ 2023-09-19 11:13     ` Parthiban.Veerasooran
  2023-09-19 12:58       ` Andrew Lunn
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-19 11:13 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 13/09/23 7:46 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> +struct oa_tc6 {
>> +     struct spi_device *spi;
>> +     bool ctrl_prot;
>> +};
> 
> Should this be considered an opaque structure which the MAC driver
> should not access the members?
> 
> I don't see anything setting ctrl_prot here. Does it need a setter and
> a getter?
Ah ok, it is supposed to be done in the oa_tc6_init() function. Somehow 
missed it. Will correct it in the next version.

Best Regards,
Parthiban V
> 
>          Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-13  2:11   ` Andrew Lunn
@ 2023-09-19 11:38     ` Parthiban.Veerasooran
  2023-09-19 15:13       ` Andrew Lunn
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-19 11:38 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 13/09/23 7:41 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> +static bool oa_tc6_get_parity(u32 p)
>> +{
>> +     bool parity = true;
>> +
>> +     /* This function returns an odd parity bit */
>> +     while (p) {
>> +             parity = !parity;
>> +             p = p & (p - 1);
>> +     }
>> +     return parity;
> 
> Please take a look around and see if you can find another
> implementation in the kernel which can be used. If not, you could copy/paste:
> 
> https://elixir.bootlin.com/linux/latest/source/lib/bch.c#L348
> 
> which is probably more efficient.
Sure, will check out it.
> 
>> +static void oa_tc6_prepare_ctrl_buf(struct oa_tc6 *tc6, u32 addr, u32 val[],
>> +                                 u8 len, bool wnr, u8 *buf, bool ctrl_prot)
>> +{
>> +     u32 hdr;
>> +
>> +     /* Prepare the control header with the required details */
>> +     hdr = FIELD_PREP(CTRL_HDR_DNC, 0) |
>> +           FIELD_PREP(CTRL_HDR_WNR, wnr) |
>> +           FIELD_PREP(CTRL_HDR_AID, 0) |
>> +           FIELD_PREP(CTRL_HDR_MMS, addr >> 16) |
>> +           FIELD_PREP(CTRL_HDR_ADDR, addr) |
>> +           FIELD_PREP(CTRL_HDR_LEN, len - 1);
>> +     hdr |= FIELD_PREP(CTRL_HDR_P, oa_tc6_get_parity(hdr));
>> +     *(u32 *)buf = cpu_to_be32(hdr);
>> +
>> +     if (wnr) {
> 
> What does wnr mean? Maybe give it a more meaningful name, unless it is
> actually something in the standard. Kerneldoc would also help.
Ah, it is "write not read". Shall I name it as "write_not_read" ?
> 
>> +static int oa_tc6_check_control(struct oa_tc6 *tc6, u8 *ptx, u8 *prx, u8 len,
>> +                             bool wnr, bool ctrl_prot)
>> +{
>> +     /* 1st 4 bytes of rx chunk data can be discarded */
>> +     u32 rx_hdr = *(u32 *)&prx[TC6_HDR_SIZE];
>> +     u32 tx_hdr = *(u32 *)ptx;
>> +     u32 rx_data_complement;
>> +     u32 tx_data;
>> +     u32 rx_data;
>> +     u16 pos1;
>> +     u16 pos2;
>> +
>> +     /* If tx hdr and echoed hdr are not equal then there might be an issue
>> +      * with the connection between SPI host and MAC-PHY. Here this case is
>> +      * considered as MAC-PHY is not connected.
> 
> I could understand ENODEV on the first transaction during probe. But
> after that -EIO seems more appropriate. I've also seen USB use -EPROTO
> to indicate a protocol error, which a corrupt message would be.
Ah ok, then in this case I will consider -EIO.
> 
>> +int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
>> +                     bool wnr, bool ctrl_prot)
>> +{
>> +     u8 *tx_buf;
>> +     u8 *rx_buf;
>> +     u16 size;
>> +     u16 pos;
>> +     int ret;
>> +
>> +     if (ctrl_prot)
>> +             size = (TC6_HDR_SIZE * 2) + (len * (TC6_HDR_SIZE * 2));
>> +     else
>> +             size = (TC6_HDR_SIZE * 2) + (len * TC6_HDR_SIZE);
> 
> Do you have an idea how big the biggest control message is? Rather
> than allocate these buffers for every transaction, maybe allocate
> maximum size buffers one at startup and keep them in tc6? That will
> reduce overhead and simplify the code.
Ok, as per OA spec, up to 128 consecutive registers read or write can be 
possible. So the maximum possible size would be 1032. As you suggested 
will allocate this size of memory in the startup.
> 
>> +struct oa_tc6 *oa_tc6_init(struct spi_device *spi)
>> +{
>> +     struct oa_tc6 *tc6;
>> +
>> +     if (!spi)
>> +             return NULL;
> 
> This is defensive programming which is generally not liked. You cannot
> do anything without an SPI device, so just assume it is passed, and if
> not, let is explode later and the driver write will quickly fix there
> broken code.
Ah yes, will remove this check.
> 
>> +
>> +     tc6 = kzalloc(sizeof(*tc6), GFP_KERNEL);
>> +     if (!tc6)
>> +             return NULL;
>> +
>> +     tc6->spi = spi;
>> +
>> +     return tc6;
>> +}
>> +EXPORT_SYMBOL_GPL(oa_tc6_init);
>> +
>> +void oa_tc6_deinit(struct oa_tc6 *tc6)
>> +{
>> +     kfree(tc6);
>> +}
>> +EXPORT_SYMBOL_GPL(oa_tc6_deinit);
> 
> Maybe consider a devm_ API to make the MAC driver simpler.
Sorry I don't get your point. Could you please explain bit more?

Best Regards,
Parthiban V

> 
>        Andrew
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-13  1:36   ` Andrew Lunn
@ 2023-09-19 11:40     ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-19 11:40 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 13/09/23 7:06 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> +int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len,
>> +                     bool wnr, bool ctrl_prot)
> 
> Please add some kerneldoc headers for the API method exposed
> here. These are what the MAC driver should be using, so they should be
> reasonably well documented.
Sure, will do that.

Best Regards,
Parthiban V
> 
> Thanks
>             Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  2023-09-19  9:18     ` Parthiban.Veerasooran
@ 2023-09-19 12:50       ` Andrew Lunn
  2023-09-20 12:53         ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-19 12:50 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> Sure, I can move this part to oa_tc6 lib. If I understand you correctly 
> you are talking about the Standard Capabilities Register (0x0002) 
> defined in the OPEN Alliance 10BASE-T1x MAC-PHY Serial Interface spec 
> right? If so, the 9th bit of this register tells about Indirect PHY 
> Register access Capability. Did you mean this bit? If so, this bit 
> describes the below,
> 
> IPRAC - Indirect PHY Register Access Capability. Indicates if PHY 
> registers are indirectly accessible through the MDIO/MDC registers MDIOACCn.

Yes. If the core relies on any functionality which is optional in the
standard, it should check if the capability bit is set, and do a
dev_erro() and return -ENODEV if a device does not actually have
it. That makes it clear the core needs extending to support a device.

If you are only using mandatory parts of the spec, then no test is
needed.

> > I would expect to see a call to phy_ethtool_ksettings_set()
> > here. phylib should be able to do some of the validation.
> Ah ok, doing the below will make the life easier.
> .set_link_ksettings	= phy_ethtool_set_link_ksettings,

Please do some testing and check that phy_ethtool_set_link_ksettings
doe actually reject all invalid setting. I cannot guarantee it does,
and if it does not, it might actually be a PHY driver bug.

> >> +static int lan865x_net_open(struct net_device *netdev)
> >> +{
> >> +     struct lan865x_priv *priv = netdev_priv(netdev);
> >> +     int ret;
> >> +
> >> +     if (!is_valid_ether_addr(netdev->dev_addr)) {
> >> +             if (netif_msg_ifup(priv))
> >> +                     netdev_err(netdev, "Invalid MAC address %pm", netdev->dev_addr);
> >> +             return -EADDRNOTAVAIL;
> > 
> > Using a random MAC address is the normal workaround for not having a
> > valid MAC address via OTP flash etc.
> Ah ok, you mean to use eth_hw_addr_random(netdev) instead of returning 
> error.

Yes. And this is generally done earlier than open, as part of
probe. You want to avoid surprising userspace when the MAC address
suddenly changes at open time.

	 Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 3/6] net: ethernet: implement OA TC6 configuration function
  2023-09-19 10:57     ` Parthiban.Veerasooran
@ 2023-09-19 12:54       ` Andrew Lunn
  2023-09-20 12:42         ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-19 12:54 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> >> +/* Unmasking interrupt fields in IMASK0 */
> >> +#define HDREM                ~BIT(5)         /* Header Error Mask */
> >> +#define LOFEM                ~BIT(4)         /* Loss of Framing Error Mask */
> >> +#define RXBOEM               ~BIT(3)         /* Rx Buffer Overflow Error Mask */
> >> +#define TXBUEM               ~BIT(2)         /* Tx Buffer Underflow Error Mask */
> >> +#define TXBOEM               ~BIT(1)         /* Tx Buffer Overflow Error Mask */
> >> +#define TXPEM                ~BIT(0)         /* Tx Protocol Error Mask */
> > 
> > Using ~BIT(X) is very usual. I would not do this, Principle of Least
> > Surprise.
> Sorry, I don't get your point. Could you please explain bit more?

Look around kernel header files. How often do you see ~BIT(5)?  My
guess it is approximately 0. So i'm suggesting you remove the ~ and
have the user of the #define assemble the mask and then do the ~ .

     Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-19 11:13     ` Parthiban.Veerasooran
@ 2023-09-19 12:58       ` Andrew Lunn
  2023-09-21 12:36         ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-19 12:58 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

On Tue, Sep 19, 2023 at 11:13:13AM +0000, Parthiban.Veerasooran@microchip.com wrote:
> Hi Andrew,
> 
> On 13/09/23 7:46 am, Andrew Lunn wrote:
> > EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> > 
> >> +struct oa_tc6 {
> >> +     struct spi_device *spi;
> >> +     bool ctrl_prot;
> >> +};
> > 
> > Should this be considered an opaque structure which the MAC driver
> > should not access the members?

Opaque vs not opaque is an important design decision. If the MAC
driver is allowed to directly access this structure, you should
document the locking concept. If the MAC is not supposed to access it
directly, only uses getters/setters, that also needs documenting, and
maybe even make it a void * in the MAC driver.

      Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-13  2:39   ` Andrew Lunn
@ 2023-09-19 13:07     ` Parthiban.Veerasooran
  2023-09-19 13:21       ` Lukasz Majewski
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-19 13:07 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

On 13/09/23 8:09 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> +static int oa_tc6_sw_reset(struct oa_tc6 *tc6)
>> +{
>> +     long timeleft;
>> +     u32 regval;
>> +     int ret;
>> +
>> +     /* Perform software reset with both protected and unprotected control
>> +      * commands because the driver doesn't know the current status of the
>> +      * MAC-PHY.
>> +      */
>> +     regval = SW_RESET;
>> +     reinit_completion(&tc6->rst_complete);
>> +     ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1, true, false);
>> +     if (ret) {
>> +             dev_err(&tc6->spi->dev, "RESET register write failed\n");
>> +             return ret;
>> +     }
>> +
>> +     ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1, true, true);
>> +     if (ret) {
>> +             dev_err(&tc6->spi->dev, "RESET register write failed\n");
>> +             return ret;
>> +     }
>> +     timeleft = wait_for_completion_interruptible_timeout(&tc6->rst_complete,
>> +                                                          msecs_to_jiffies(1));
>> +     if (timeleft <= 0) {
>> +             dev_err(&tc6->spi->dev, "MAC-PHY reset failed\n");
>> +             return -ENODEV;
>> +     }
> 
> This seems a bit messy and complex. I assume reset is performed once
> during probe, and never again? So i wonder if it would be cleaner to
> actually just poll for the reset to complete? You can then remove all
> this completion code, and the interrupt handler gets simpler?
Ok the spec says the below, that's why I implemented like this.

9.2.8.8 RESETC
Reset Complete. This bit is set when the MAC-PHY reset is complete and 
ready for configuration. When it is set, it will generate a non-maskable 
interrupt assertion on IRQn to alert the SPI host. Additionally, setting 
of the RESETC bit shall also set EXST = 1 in the receive data footer 
until this bit is cleared by action of the SPI host writing a ‘1’.

Yes, I agree that the reset is performed once in the beginning. So I 
will poll for the completion and remove this block in the next revision.
> 
>> +     /* Register MAC-PHY interrupt service routine */
>> +     ret = devm_request_irq(&spi->dev, spi->irq, macphy_irq, 0, "macphy int",
>> +                            tc6);
>> +     if ((ret != -ENOTCONN) && ret < 0) {
>> +             dev_err(&spi->dev, "Error attaching macphy irq %d\n", ret);
>> +             goto err_macphy_irq;
>> +     }
> 
> Why is -ENOTCONN special? A comment would be good here.
Ah, it is a mistake. I supposed to use,

if (ret)

I will correct it in the next version.
> 
>> -void oa_tc6_deinit(struct oa_tc6 *tc6)
>> +int oa_tc6_deinit(struct oa_tc6 *tc6)
>>   {
>> -     kfree(tc6);
>> +     int ret;
>> +
>> +     devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
>> +     ret = kthread_stop(tc6->tc6_task);
>> +     if (!ret)
>> +             kfree(tc6);
>> +     return ret;
>>   }
> 
> What is the MAC driver supposed to do if this fails?
> 
> But this problem probably goes away once you use a threaded interrupt
> handler.
Yes, I agree. Will do that.
> 
> w> +/* Open Alliance TC6 Standard Control and Status Registers */
>> +#define OA_TC6_RESET 0x0003          /* Reset Control and Status Register */
>> +#define OA_TC6_STS0  0x0008          /* Status Register #0 */
> 
> Please use the same name as the standard. It use STATUS0, so
> OA_TC6_STATUS0. Please make sure all your defines follow the standard.
Yes sure.
> 
>> +
>> +/* RESET register field */
>> +#define SW_RESET     BIT(0)          /* Software Reset */
> 
> It is pretty normal to put #defines for a register members after the
> #define for the register itself:
> 
> #define OA_TC6_RESET    0x0003          /* Reset Control and Status Register */
> #define OA_TC6_RESET_SWRESET    BIT(0)
> 
> #define OA_TC6_STATUS0  0x0008          /* Status Register #0 */
> #define OA_TC6_STATUS0_RESETC           BIT(6)          /* Reset Complete */
> 
> The naming like this also helps avoid mixups.
Ok, I will follow this in the next version.

Best Regards,
Parthiban V
> 
>      Andrew
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-19 13:07     ` Parthiban.Veerasooran
@ 2023-09-19 13:21       ` Lukasz Majewski
  0 siblings, 0 replies; 85+ messages in thread
From: Lukasz Majewski @ 2023-09-19 13:21 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: andrew, davem, edumazet, kuba, pabeni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, Steen.Hegelund,
	rdunlap, horms, casper.casan, netdev, devicetree, linux-kernel,
	linux-doc, Horatiu.Vultur, Woojung.Huh, Nicolas.Ferre,
	UNGLinuxDriver, Thorsten.Kummermehr

[-- Attachment #1: Type: text/plain, Size: 5234 bytes --]

Hi Parthiban,

> On 13/09/23 8:09 am, Andrew Lunn wrote:
> > EXTERNAL EMAIL: Do not click links or open attachments unless you
> > know the content is safe 
> >> +static int oa_tc6_sw_reset(struct oa_tc6 *tc6)
> >> +{
> >> +     long timeleft;
> >> +     u32 regval;
> >> +     int ret;
> >> +
> >> +     /* Perform software reset with both protected and
> >> unprotected control
> >> +      * commands because the driver doesn't know the current
> >> status of the
> >> +      * MAC-PHY.
> >> +      */
> >> +     regval = SW_RESET;
> >> +     reinit_completion(&tc6->rst_complete);
> >> +     ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1,
> >> true, false);
> >> +     if (ret) {
> >> +             dev_err(&tc6->spi->dev, "RESET register write
> >> failed\n");
> >> +             return ret;
> >> +     }
> >> +
> >> +     ret = oa_tc6_perform_ctrl(tc6, OA_TC6_RESET, &regval, 1,
> >> true, true);
> >> +     if (ret) {
> >> +             dev_err(&tc6->spi->dev, "RESET register write
> >> failed\n");
> >> +             return ret;
> >> +     }
> >> +     timeleft =
> >> wait_for_completion_interruptible_timeout(&tc6->rst_complete,
> >> +
> >> msecs_to_jiffies(1));
> >> +     if (timeleft <= 0) {
> >> +             dev_err(&tc6->spi->dev, "MAC-PHY reset failed\n");
> >> +             return -ENODEV;
> >> +     }  
> > 
> > This seems a bit messy and complex. I assume reset is performed once
> > during probe, and never again? So i wonder if it would be cleaner to
> > actually just poll for the reset to complete? You can then remove
> > all this completion code, and the interrupt handler gets simpler?  
> Ok the spec says the below, that's why I implemented like this.
> 
> 9.2.8.8 RESETC
> Reset Complete. This bit is set when the MAC-PHY reset is complete
> and ready for configuration. When it is set, it will generate a
> non-maskable interrupt assertion on IRQn to alert the SPI host.
> Additionally, setting of the RESETC bit shall also set EXST = 1 in
> the receive data footer until this bit is cleared by action of the
> SPI host writing a ‘1’.

If you don't mind - I would like to ask some extra questions:

1. Could you share which silicon revision of LAN8651 (rev 1 = B0 or rev
2 = B1) are your using?

2. Do you use 10k Ohm pull up resistor between VDD and the IRQ_N line?

3. Are you using any standard development board with LAN865x device?
Could you share how do you connect reset and irq lines and which CPU do
you use?

Thanks in advance for your help.



> 
> Yes, I agree that the reset is performed once in the beginning. So I 
> will poll for the completion and remove this block in the next
> revision.
> >   
> >> +     /* Register MAC-PHY interrupt service routine */
> >> +     ret = devm_request_irq(&spi->dev, spi->irq, macphy_irq, 0,
> >> "macphy int",
> >> +                            tc6);
> >> +     if ((ret != -ENOTCONN) && ret < 0) {
> >> +             dev_err(&spi->dev, "Error attaching macphy irq
> >> %d\n", ret);
> >> +             goto err_macphy_irq;
> >> +     }  
> > 
> > Why is -ENOTCONN special? A comment would be good here.  
> Ah, it is a mistake. I supposed to use,
> 
> if (ret)
> 
> I will correct it in the next version.
> >   
> >> -void oa_tc6_deinit(struct oa_tc6 *tc6)
> >> +int oa_tc6_deinit(struct oa_tc6 *tc6)
> >>   {
> >> -     kfree(tc6);
> >> +     int ret;
> >> +
> >> +     devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6);
> >> +     ret = kthread_stop(tc6->tc6_task);
> >> +     if (!ret)
> >> +             kfree(tc6);
> >> +     return ret;
> >>   }  
> > 
> > What is the MAC driver supposed to do if this fails?
> > 
> > But this problem probably goes away once you use a threaded
> > interrupt handler.  
> Yes, I agree. Will do that.
> >   
> > w> +/* Open Alliance TC6 Standard Control and Status Registers */
> >> +#define OA_TC6_RESET 0x0003          /* Reset Control and Status
> >> Register */ +#define OA_TC6_STS0  0x0008          /* Status
> >> Register #0 */  
> > 
> > Please use the same name as the standard. It use STATUS0, so
> > OA_TC6_STATUS0. Please make sure all your defines follow the
> > standard.  
> Yes sure.
> >   
> >> +
> >> +/* RESET register field */
> >> +#define SW_RESET     BIT(0)          /* Software Reset */  
> > 
> > It is pretty normal to put #defines for a register members after the
> > #define for the register itself:
> > 
> > #define OA_TC6_RESET    0x0003          /* Reset Control and Status
> > Register */ #define OA_TC6_RESET_SWRESET    BIT(0)
> > 
> > #define OA_TC6_STATUS0  0x0008          /* Status Register #0 */
> > #define OA_TC6_STATUS0_RESETC           BIT(6)          /* Reset
> > Complete */
> > 
> > The naming like this also helps avoid mixups.  
> Ok, I will follow this in the next version.
> 
> Best Regards,
> Parthiban V
> > 
> >      Andrew
> >   
> 




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Erika Unter
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-13 13:26       ` Lukasz Majewski
@ 2023-09-19 13:40         ` Parthiban.Veerasooran
  2023-09-19 13:51           ` Lukasz Majewski
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-19 13:40 UTC (permalink / raw)
  To: lukma
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	andrew

Hi Lukasz,

Sorry for the delayed response. Regarding your issue, we just noticed 
that you have also filed an issue in our oa tc6 lib github page. Our oa 
tc6 lib for controllers developer Thorsten will get back to you on this. 
You can get the solution from there.

https://github.com/MicrochipTech/oa-tc6-lib/issues/14

Best Regards,
Parthiban V

On 13/09/23 6:56 pm, Lukasz Majewski wrote:
> Hi Andrew,
> 
>>> Just maybe mine small remark. IMHO the reset shall not pollute the
>>> IRQ hander. The RESETC is just set on the initialization phase and
>>> only then shall be served. Please correct me if I'm wrong, but it
>>> will not be handled during "normal" operation.
>>
>> This is something i also wondered. Maybe if the firmware in the
>> MAC-PHY crashes, burns, and a watchdog reset it, could it assert
>> RESETC? I think maybe a WARN_ON_ONCE() for RESETC in the interrupt
>> handler would be useful, but otherwise ignore it. Probe can then poll
>> during its reset.
>>
>>>> +				regval = RESETC;
>>>> +				/* SPI host should write RESETC
>>>> bit with one to
>>>> +				 * clear the reset interrupt
>>>> status.
>>>> +				 */
>>>> +				ret = oa_tc6_perform_ctrl(tc6,
>>>> OA_TC6_STS0,
>>>> +
>>>> &regval, 1, true,
>>>> +
>>>> false);
>>>
>>> Is this enough to have the IRQ_N deasserted (i.e. pulled HIGH)?
>>>
>>> The documentation states it clearly that one also needs to set SYNC
>>> bit (BIT(15)) in the OA_CONFIG0 register (which would have the
>>> 0x8006 value).
>>>
>>> Mine problem is that even after writing 0x40 to OA_STATUS0 and
>>> 0x8006 to OA_CONFIG0 the IRQ_N is still LOW (it is pulled up via
>>> 10K resistor).
>>>
>>> (I'm able to read those registers and those show expected values)
>>
>> What does STATUS0 and STATUS1 contain?
> 
> STATUS0 => 0x40, which is expected.
> 
> Then I do write 0x40 to STATUS0 -> bit6 (RESETC) is R/W1C
> 
> After reading the same register - I do receive 0x00 (it has been
> cleared).
> 
> Then I write 0x8006 to OA_CONFIG0.
> 
> (Those two steps are regarded as "configuration" of LAN865x device in
> the documentation)
> 
> In this patch set -> the OA_COFIG0 also has the 0x6 added to indicate
> the SPI transfer chunk.
> 
> Dump of OA registers:
> {0x11, 0x7c1b3, 0x5e5, 0x0, 0x8006, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
> 0x3000, 0x1fbf, 0x3ffe0003, 0x0, 0x0}
> 
> Status 0 (0x8) -> 0x0
> Status 1 (0x9) -> 0x0
> 
>> That might be a dumb question,
>> i've not read the details for interrupt handling yet, but maybe there
>> is another interrupt pending? Or the interrupt mask needs writing?
> 
> All the interrupts on MASK{01} are masked.
> 
> Changing it to:
> sts &= ~(OA_IMASK0_TXPEM | OA_IMASK0_TXBOEM | OA_IMASK0_TXBUEM |
> OA_IMASK0_RXBOEM | OA_IMASK0_LOFEM | OA_IMASK0_HDREM
> 
> doesn't fix this problem.
> 
>>
>>> Was it on purpose to not use the RST_N pin to perform GPIO based
>>> reset?
>>>
>>> When I generate reset pulse (and keep it for low for > 5us) the
>>> IRQ_N gets high. After some time it gets low (as expected). But
>>> then it doesn't get high any more.
>>
>> Does the standard say RST_N is mandatory to be controlled by software?
>> I could imagine RST_N is tied to the board global reset when the power
>> supply is stable.
> 
> It can be GPIO controlled. However, it is not required. I've tied it to
> 3V3 and also left NC, but no change.
> 
>> Software reset is then used at probe time.
> 
> I've reconfigured the board to use only SW based reset (i.e. set bit0
> in OA_RESET - 0x3).
> 
>>
>> So this could be a board design decision. I can see this code getting
>> extended in the future, an optional gpiod passed to the core for it to
>> use.
> 
> I can omit the RST_N control. I'd just expect the IRQ_N to be high
> after reset.
> 
>>
>>>> msecs_to_jiffies(1));
>>>
>>> Please also clarify - does the LAN8651 require up to 1ms "settle
>>> down" (after reset) time before it gets operational again?
>>
>> If this is not part of the standard, it really should be in the MAC
>> driver, or configurable, since different devices might need different
>> delays. But ideally, if the status bit says it is good to go, i would
>> really expect it to be good to go. So this probably should be a
>> LAN8651 quirk.
> 
> The documentation is silent about the "settle down time". The only
> requirements is for RST_N assertion > 5us. However, when the IRQ_N goes
> low, and the interrupt is served - it happens that I cannot read ID
> from the chip via SPI.
> 
>>
>> 	Andrew
> 
> Best regards,
> 
> Lukasz Majewski
> 
> --
> 
> DENX Software Engineering GmbH,      Managing Director: Erika Unter
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling
  2023-09-19 13:40         ` Parthiban.Veerasooran
@ 2023-09-19 13:51           ` Lukasz Majewski
  0 siblings, 0 replies; 85+ messages in thread
From: Lukasz Majewski @ 2023-09-19 13:51 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	andrew

[-- Attachment #1: Type: text/plain, Size: 5589 bytes --]

Hi Parthiban,

> Hi Lukasz,
> 
> Sorry for the delayed response. Regarding your issue, we just noticed 
> that you have also filed an issue in our oa tc6 lib github page. Our
> oa tc6 lib for controllers developer Thorsten will get back to you on
> this. You can get the solution from there.
> 
> https://github.com/MicrochipTech/oa-tc6-lib/issues/14

Yes. This is filled by me :-)

I will reach Thorsten directly.

Thanks for the reply.

> 
> Best Regards,
> Parthiban V
> 
> On 13/09/23 6:56 pm, Lukasz Majewski wrote:
> > Hi Andrew,
> >   
> >>> Just maybe mine small remark. IMHO the reset shall not pollute the
> >>> IRQ hander. The RESETC is just set on the initialization phase and
> >>> only then shall be served. Please correct me if I'm wrong, but it
> >>> will not be handled during "normal" operation.  
> >>
> >> This is something i also wondered. Maybe if the firmware in the
> >> MAC-PHY crashes, burns, and a watchdog reset it, could it assert
> >> RESETC? I think maybe a WARN_ON_ONCE() for RESETC in the interrupt
> >> handler would be useful, but otherwise ignore it. Probe can then
> >> poll during its reset.
> >>  
> >>>> +				regval = RESETC;
> >>>> +				/* SPI host should write RESETC
> >>>> bit with one to
> >>>> +				 * clear the reset interrupt
> >>>> status.
> >>>> +				 */
> >>>> +				ret = oa_tc6_perform_ctrl(tc6,
> >>>> OA_TC6_STS0,
> >>>> +
> >>>> &regval, 1, true,
> >>>> +
> >>>> false);  
> >>>
> >>> Is this enough to have the IRQ_N deasserted (i.e. pulled HIGH)?
> >>>
> >>> The documentation states it clearly that one also needs to set
> >>> SYNC bit (BIT(15)) in the OA_CONFIG0 register (which would have
> >>> the 0x8006 value).
> >>>
> >>> Mine problem is that even after writing 0x40 to OA_STATUS0 and
> >>> 0x8006 to OA_CONFIG0 the IRQ_N is still LOW (it is pulled up via
> >>> 10K resistor).
> >>>
> >>> (I'm able to read those registers and those show expected values)
> >>>  
> >>
> >> What does STATUS0 and STATUS1 contain?  
> > 
> > STATUS0 => 0x40, which is expected.
> > 
> > Then I do write 0x40 to STATUS0 -> bit6 (RESETC) is R/W1C
> > 
> > After reading the same register - I do receive 0x00 (it has been
> > cleared).
> > 
> > Then I write 0x8006 to OA_CONFIG0.
> > 
> > (Those two steps are regarded as "configuration" of LAN865x device
> > in the documentation)
> > 
> > In this patch set -> the OA_COFIG0 also has the 0x6 added to
> > indicate the SPI transfer chunk.
> > 
> > Dump of OA registers:
> > {0x11, 0x7c1b3, 0x5e5, 0x0, 0x8006, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
> > 0x3000, 0x1fbf, 0x3ffe0003, 0x0, 0x0}
> > 
> > Status 0 (0x8) -> 0x0
> > Status 1 (0x9) -> 0x0
> >   
> >> That might be a dumb question,
> >> i've not read the details for interrupt handling yet, but maybe
> >> there is another interrupt pending? Or the interrupt mask needs
> >> writing?  
> > 
> > All the interrupts on MASK{01} are masked.
> > 
> > Changing it to:
> > sts &= ~(OA_IMASK0_TXPEM | OA_IMASK0_TXBOEM | OA_IMASK0_TXBUEM |
> > OA_IMASK0_RXBOEM | OA_IMASK0_LOFEM | OA_IMASK0_HDREM
> > 
> > doesn't fix this problem.
> >   
> >>  
> >>> Was it on purpose to not use the RST_N pin to perform GPIO based
> >>> reset?
> >>>
> >>> When I generate reset pulse (and keep it for low for > 5us) the
> >>> IRQ_N gets high. After some time it gets low (as expected). But
> >>> then it doesn't get high any more.  
> >>
> >> Does the standard say RST_N is mandatory to be controlled by
> >> software? I could imagine RST_N is tied to the board global reset
> >> when the power supply is stable.  
> > 
> > It can be GPIO controlled. However, it is not required. I've tied
> > it to 3V3 and also left NC, but no change.
> >   
> >> Software reset is then used at probe time.  
> > 
> > I've reconfigured the board to use only SW based reset (i.e. set
> > bit0 in OA_RESET - 0x3).
> >   
> >>
> >> So this could be a board design decision. I can see this code
> >> getting extended in the future, an optional gpiod passed to the
> >> core for it to use.  
> > 
> > I can omit the RST_N control. I'd just expect the IRQ_N to be high
> > after reset.
> >   
> >>  
> >>>> msecs_to_jiffies(1));  
> >>>
> >>> Please also clarify - does the LAN8651 require up to 1ms "settle
> >>> down" (after reset) time before it gets operational again?  
> >>
> >> If this is not part of the standard, it really should be in the MAC
> >> driver, or configurable, since different devices might need
> >> different delays. But ideally, if the status bit says it is good
> >> to go, i would really expect it to be good to go. So this probably
> >> should be a LAN8651 quirk.  
> > 
> > The documentation is silent about the "settle down time". The only
> > requirements is for RST_N assertion > 5us. However, when the IRQ_N
> > goes low, and the interrupt is served - it happens that I cannot
> > read ID from the chip via SPI.
> >   
> >>
> >> 	Andrew  
> > 
> > Best regards,
> > 
> > Lukasz Majewski
> > 
> > --
> > 
> > DENX Software Engineering GmbH,      Managing Director: Erika Unter
> > HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell,
> > Germany Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email:
> > lukma@denx.de  
> 




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Erika Unter
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-19 11:38     ` Parthiban.Veerasooran
@ 2023-09-19 15:13       ` Andrew Lunn
  2023-09-20 12:40         ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-19 15:13 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> >> +static void oa_tc6_prepare_ctrl_buf(struct oa_tc6 *tc6, u32 addr, u32 val[],
> >> +                                 u8 len, bool wnr, u8 *buf, bool ctrl_prot)
> >> +{
> >> +     u32 hdr;
> >> +
> >> +     /* Prepare the control header with the required details */
> >> +     hdr = FIELD_PREP(CTRL_HDR_DNC, 0) |
> >> +           FIELD_PREP(CTRL_HDR_WNR, wnr) |
> >> +           FIELD_PREP(CTRL_HDR_AID, 0) |
> >> +           FIELD_PREP(CTRL_HDR_MMS, addr >> 16) |
> >> +           FIELD_PREP(CTRL_HDR_ADDR, addr) |
> >> +           FIELD_PREP(CTRL_HDR_LEN, len - 1);
> >> +     hdr |= FIELD_PREP(CTRL_HDR_P, oa_tc6_get_parity(hdr));
> >> +     *(u32 *)buf = cpu_to_be32(hdr);
> >> +
> >> +     if (wnr) {
> > 
> > What does wnr mean? Maybe give it a more meaningful name, unless it is
> > actually something in the standard. Kerneldoc would also help.
> Ah, it is "write not read". Shall I name it as "write_not_read" ?

You might want to describe the high level concept as well in this
file. What i _think_ this is about is that SPI is sort of a full
duplex bus. While you are sending data to the SPI device, the device
could also be sending a data to the CPU? And 'write not read' here
means ignore what we receive from the device?

> Ok, as per OA spec, up to 128 consecutive registers read or write can be 
> possible. So the maximum possible size would be 1032. As you suggested 
> will allocate this size of memory in the startup.

Yes, 1032 bytes it not huge, so allocate it once and keep it for the
lifetime of the device.

> >> +void oa_tc6_deinit(struct oa_tc6 *tc6)
> >> +{
> >> +     kfree(tc6);
> >> +}
> >> +EXPORT_SYMBOL_GPL(oa_tc6_deinit);
> > 
> > Maybe consider a devm_ API to make the MAC driver simpler.
> Sorry I don't get your point. Could you please explain bit more?

At least at this stage in the patch series, all you are doing is
allocating memory. You add more code later, which might invalidate my
point. But if all you are doing is allocating memory, you could use
devm_kmalloc(). The driver core will then take care of releasing the
memory when the driver is unloaded, or probe fails. That makes cleanup
simpler and memory leaks less likely. There are a lot of devm_
helpers, see if you can use them.

	Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: Fwd: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
  2023-09-19  9:03       ` Parthiban.Veerasooran
@ 2023-09-19 16:23         ` Jay Monkman
  2023-09-19 18:09         ` Hennerich, Michael
  1 sibling, 0 replies; 85+ messages in thread
From: Jay Monkman @ 2023-09-19 16:23 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: Piergiorgio Beruto, Michael.Hennerich, Ciprian.Regus, andrew,
	davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	ada


>  From my next reply on-wards I will include Michael.Hennerich, Ciprian 
> Regus and Jay Monkman in the "--to" or "--cc" so that we can share our 
> ideas and comments.

Thanks for including me. Can you also include
Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
He is also involved in developing the driver for onsemi's device.


Jay Monkman

^ permalink raw reply	[flat|nested] 85+ messages in thread

* RE: [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
  2023-09-19  9:03       ` Parthiban.Veerasooran
  2023-09-19 16:23         ` Jay Monkman
@ 2023-09-19 18:09         ` Hennerich, Michael
  1 sibling, 0 replies; 85+ messages in thread
From: Hennerich, Michael @ 2023-09-19 18:09 UTC (permalink / raw)
  To: Parthiban.Veerasooran, Regus, Ciprian, andrew, jtm, piergiorgio.beruto
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	ada



> -----Original Message-----
> From: Parthiban.Veerasooran@microchip.com
> <Parthiban.Veerasooran@microchip.com>
> Sent: Dienstag, 19. September 2023 11:04
> To: Hennerich, Michael <Michael.Hennerich@analog.com>; Regus, Ciprian
> <Ciprian.Regus@analog.com>; andrew@lunn.ch; jtm@lopingdog.com
> Cc: davem@davemloft.net; edumazet@google.com; kuba@kernel.org;
> pabeni@redhat.com; robh+dt@kernel.org;
> krzysztof.kozlowski+dt@linaro.org; conor+dt@kernel.org; corbet@lwn.net;
> Steen.Hegelund@microchip.com; rdunlap@infradead.org;
> horms@kernel.org; casper.casan@gmail.com; netdev@vger.kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> doc@vger.kernel.org; Horatiu.Vultur@microchip.com;
> Woojung.Huh@microchip.com; Nicolas.Ferre@microchip.com;
> UNGLinuxDriver@microchip.com; Thorsten.Kummermehr@microchip.com;
> ada@thorsis.com
> Subject: Fwd: [RFC PATCH net-next 0/6] Add support for OPEN Alliance
> 10BASE-T1x MACPHY Serial Interface
> 
> 
> Hi,
> 
> @Andrew: As you pointed out in another email, I have included Jay
> Monkman as well in this email to discuss further.
> 
> @Jay Monkman: Yesterday, Andrew noticed that you submitted a patch
> series for NCN26010 which is a 10BASE-T1S MACPHY which uses OPEN
> Alliance spec.
> 
> @Michael Hennerich: I am forwarding this email to you so that you will get
> the history behind this conversation. Please have a look in the below email
> for the clarification we need.
> 
> Microchip's product link is below,
> 
> https://urldefense.com/v3/__https://www.microchip.com/en-
> us/product/lan8650__;!!A3Ni8CS0y2Y!5NnVuSzLYTgWJs0VW1cJjMAU2tR1j6
> ucjHFmGLl52wzcuOYJoxo3Itq5kSPqVg90KxBFbe_wLoTJeEofKEWagrJ46WjzIF
> 7hQuY$
> 
> We already pushed the driver patches for supporting the above Microchip's
> LAN865x MACPHY and the OPEN Alliance spec to the mainline and it is under
> review. Please refer the below link to get a complete picture of this patch
> series.
> 
> https://urldefense.com/v3/__https://lore.kernel.org/netdev/202309131526
> 25.73e32789@wsk/T/__;!!A3Ni8CS0y2Y!5NnVuSzLYTgWJs0VW1cJjMAU2tR1
> j6ucjHFmGLl52wzcuOYJoxo3Itq5kSPqVg90KxBFbe_wLoTJeEofKEWagrJ46Wjz
> AjlY1vs$
> 
> We have developed 10BASE-T1x MAC_PHY Serial Interface Specification
> defined by OPEN Alliance TC6 group as a separate framework/generic lib and
> included in this patch series so that all the 10BASE-T1x MACPHY vendors can
> make use of it.
> 
> As Andrew suggested, it would be nice if we all work together to make it
> better. Please feel free to share your comments/ideas to improve the
> framework.

There was some side conversation off-list to this topic as well - our developer Alexandru who mainlined 
the ADIN1110 driver also worked on the TC6-10BASE-T1x MACPHY version.
Since this came after he finished the standard SPI version, the non OA version was mainlined 
first. He aimed to send his implementation to the mailing list almost a year ago, but wanted to polish it a bit
more. And how this always happens he got sidetracked by some other project and then unfortunately left.

Our Open Alliance implementation was tested and also this wiki landing page was created:
https://wiki.analog.com/resources/tools-software/linux-drivers/net-mac-phy/open_alliance

The patches and files can be found on the tip of this branch here:
https://github.com/analogdevicesinc/linux/commits/adin1110-open-alliance

So this might be an alternative implementation. I'm sure we'll settle a common one.
Ciprian will take over responsibilities from Alexandru.

Best regards,
Michael

 
> 
>  From my next reply on-wards I will include Michael.Hennerich, Ciprian Regus
> and Jay Monkman in the "--to" or "--cc" so that we can share our ideas and
> comments.
> 
> I have brought everyone in this email so that we all in sync discussing the
> same topic and sharing our ideas. Please stick with this email or other patch
> series email for further communications to share all our ideas.
> 
> I hope this helps. Please let me know if you have any query on this.
> 
> Best Regards,
> Parthiban V
> 
> -------- Forwarded Message --------
> Subject: Fwd: [RFC PATCH net-next 0/6] Add support for OPEN Alliance
> 10BASE-T1x MACPHY Serial Interface
> Date: Mon, 18 Sep 2023 14:32:24 +0530
> From: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
> To: Lennart Franzen <lennart@lfdomain.com>, Alexander Dahl
> <ada@thorsis.com>, Andrew Lunn <andrew@lunn.ch>
> CC: davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
> pabeni@redhat.com, robh+dt@kernel.org,
> krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org, corbet@lwn.net,
> steen.hegelund@microchip.com, rdunlap@infradead.org,
> horms@kernel.org, casper.casan@gmail.com, netdev@vger.kernel.org,
> devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-
> doc@vger.kernel.org, horatiu.vultur@microchip.com,
> Woojung.Huh@microchip.com, Nicolas.Ferre@microchip.com,
> UNGLinuxDriver@microchip.com, Thorsten.Kummermehr@microchip.com
> 
> Hi Lennart,
> 
> I am forwarding this email to you as we are not able to reach the module
> author Alexandru Tachici <alexandru.tachici@analog.com> and getting the
> below email delivery error.
> 
> ----cut here-----
> Delivery has failed to these recipients or groups:
> 
> alexandru.tachici@analog.com<mailto:alexandru.tachici@analog.com>
> The email address you entered couldn't be found. Please check the
> recipient's email address and try to resend the message. If the problem
> continues, please contact your email admin.
> ----cut here------
> 
> We got your your email address from the commit
> bc93e19d088bb14e116756ab270deea6ee62d782. Regarding the below
> topic, are you the right contact parson to continue further on this topic or
> else do you have any other contact to approach? Please let us know.
> 
> Best Regards,
> Parthiban V
> -------- Forwarded Message --------
> Subject: Re: [RFC PATCH net-next 0/6] Add support for OPEN Alliance
> 10BASE-T1x MACPHY Serial Interface
> Date: Mon, 18 Sep 2023 11:42:33 +0530
> From: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
> To: ada@thorsis.com, Alexandru Tachici <alexandru.tachici@analog.com>,
> Andrew Lunn <andrew@lunn.ch>
> CC: davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
> pabeni@redhat.com, robh+dt@kernel.org,
> krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org, corbet@lwn.net,
> steen.hegelund@microchip.com, rdunlap@infradead.org,
> horms@kernel.org, casper.casan@gmail.com, netdev@vger.kernel.org,
> devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-
> doc@vger.kernel.org, horatiu.vultur@microchip.com,
> Woojung.Huh@microchip.com, Nicolas.Ferre@microchip.com,
> UNGLinuxDriver@microchip.com, Thorsten.Kummermehr@microchip.com
> 
> Hi Alexander,
> 
> Thanks for the information. Please see my reply below.
> 
> On 15/09/23 7:26 pm, Alexander Dahl wrote:
> > [Some people who received this message don't often get email from
> > ada@thorsis.com. Learn why this is important at
> > https://urldefense.com/v3/__https://aka.ms/LearnAboutSenderIdentificat
> >
> ion__;!!A3Ni8CS0y2Y!5NnVuSzLYTgWJs0VW1cJjMAU2tR1j6ucjHFmGLl52wzc
> uOYJox
> > o3Itq5kSPqVg90KxBFbe_wLoTJeEofKEWagrJ46WjzdmvJN08$  ]
> >
> > EXTERNAL EMAIL: Do not click links or open attachments unless you know
> > the content is safe
> >
> > Hello,
> >
> > this is interesting, by chance I just looked at a chip claiming
> > similar features today, which already has a driver in kernel: Analog
> > Devices ADIN1110.
> Microchip's LAN865x is a 10BASE-T1S MACPHY and Analog Devices's
> ADIN1110 is a 10BASE-T1L MACPHY. So as you said 10BASE-T1x MAC_PHY
> Serial Interface Specification defined by OPEN Alliance TC6 group can be
> applicable for both of the devices. I also noticed that ADI's datasheet says
> ADIN1110 supports OPEN Alliance 10BASE-T1x MAC-PHY serial interface.
> https://www.analog.com/media/en/technical-documentation/data-
> sheets/adin1110.pdf
> 
> But in my first glance in their driver code, I don't see any code block which
> implements 10BASE-T1x MAC_PHY Serial Interface Specification defined by
> OPEN Alliance TC6 group. Or do I miss anything here?. My code reference is
> below FYR,
> https://urldefense.com/v3/__https://elixir.bootlin.com/linux/v6.6-
> rc2/source/drivers/net/ethernet/adi/adin1110.c__;!!A3Ni8CS0y2Y!5NnVuSzL
> YTgWJs0VW1cJjMAU2tR1j6ucjHFmGLl52wzcuOYJoxo3Itq5kSPqVg90KxBFbe_
> wLoTJeEofKEWagrJ46Wjz-SM4EnA$
> 
> OPEN Alliance 10BASE-T1x MAC_PHY Serial Interface Specification cab be
> downloaded from the below link,
> https://urldefense.com/v3/__https://opensig.org/automotive-ethernet-
> specifications/__;!!A3Ni8CS0y2Y!5NnVuSzLYTgWJs0VW1cJjMAU2tR1j6ucjHF
> mGLl52wzcuOYJoxo3Itq5kSPqVg90KxBFbe_wLoTJeEofKEWagrJ46Wjz3BeXFz
> c$
> 
> I think Alexandru Tachici from ADI would be able to give us more information
> on this direction.
> >
> > Am Fri, Sep 08, 2023 at 07:59:13PM +0530 schrieb Parthiban Veerasooran:
> >> This patch series contain the below updates,
> >> - Adds support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface in
> the
> >>    net/ethernet/oa_tc6.c.
> >
> > So this implements the "10BASE-T1x MAC-PHY Serial Interface
> > Specification" which is Ethernet over SPI if I understand correctly?
> > The above mentioned chip claims do use the same interface and the same
> > standard.  How does its driver work then?  Do you add code for a thing
> > already present in the kernel or does the other driver do something
> > completely different and I just misunderstood?
> As I mentioned above, in my first glance in their driver code, I don't see any
> code block which implements 10BASE-T1x MAC_PHY Serial Interface
> Specification defined by OPEN Alliance TC6 group. Let's Alexandru Tachici
> from ADI gives us more info on this.
> >
> > Can the drivers for ADIN1110 and for LAN865X share code because they
> > use the same specified interface?  The patch set does not look like
> > it?
> Of course, if their device supports OPEN Alliance then we can use this
> oa_tc6.c framework to support other 10BASE-T1x MACPHY's as well.
> >
> > (Added the other driver author to Cc.)
> Ok thanks.
> 
> Best Regards,
> Parthiban V
> >
> > Greets
> > Alex
> >
> >> - Adds driver support for Microchip LAN8650/1 Rev.B0 10BASE-T1S
> MACPHY
> >>    Ethernet driver in the net/ethernet/microchip/lan865x.c.
> >>
> >> Parthiban Veerasooran (6):
> >>    net: ethernet: implement OPEN Alliance control transaction interface
> >>    net: ethernet: add mac-phy interrupt support with reset complete
> >>      handling
> >>    net: ethernet: implement OA TC6 configuration function
> >>    net: ethernet: implement data transaction interface
> >>    microchip: lan865x: add driver support for Microchip's LAN865X
> MACPHY
> >>    microchip: lan865x: add device-tree support for Microchip's LAN865X
> >>      MACPHY
> >>
> >>   .../bindings/net/microchip,lan865x.yaml       |  54 ++
> >>   Documentation/networking/oa-tc6-framework.rst | 231 +++++
> >>   MAINTAINERS                                   |  15 +
> >>   drivers/net/ethernet/microchip/Kconfig        |  10 +
> >>   drivers/net/ethernet/microchip/Makefile       |   3 +
> >>   drivers/net/ethernet/microchip/lan865x.c      | 589 +++++++++++++
> >>   drivers/net/ethernet/oa_tc6.c                 | 807 ++++++++++++++++++
> >>   include/linux/oa_tc6.h                        | 130 +++
> >>   8 files changed, 1839 insertions(+)
> >>   create mode 100644
> Documentation/devicetree/bindings/net/microchip,lan865x.yaml
> >>   create mode 100644 Documentation/networking/oa-tc6-framework.rst
> >>   create mode 100644 drivers/net/ethernet/microchip/lan865x.c
> >>   create mode 100644 drivers/net/ethernet/oa_tc6.c
> >>   create mode 100644 include/linux/oa_tc6.h
> >>
> >> --
> >> 2.34.1
> >>
> >>


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-19 15:13       ` Andrew Lunn
@ 2023-09-20 12:40         ` Parthiban.Veerasooran
  2023-09-20 13:37           ` Andrew Lunn
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-20 12:40 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	Ciprian.Regus, jtm

Hi Andrew,

On 19/09/23 8:43 pm, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>>>> +static void oa_tc6_prepare_ctrl_buf(struct oa_tc6 *tc6, u32 addr, u32 val[],
>>>> +                                 u8 len, bool wnr, u8 *buf, bool ctrl_prot)
>>>> +{
>>>> +     u32 hdr;
>>>> +
>>>> +     /* Prepare the control header with the required details */
>>>> +     hdr = FIELD_PREP(CTRL_HDR_DNC, 0) |
>>>> +           FIELD_PREP(CTRL_HDR_WNR, wnr) |
>>>> +           FIELD_PREP(CTRL_HDR_AID, 0) |
>>>> +           FIELD_PREP(CTRL_HDR_MMS, addr >> 16) |
>>>> +           FIELD_PREP(CTRL_HDR_ADDR, addr) |
>>>> +           FIELD_PREP(CTRL_HDR_LEN, len - 1);
>>>> +     hdr |= FIELD_PREP(CTRL_HDR_P, oa_tc6_get_parity(hdr));
>>>> +     *(u32 *)buf = cpu_to_be32(hdr);
>>>> +
>>>> +     if (wnr) {
>>>
>>> What does wnr mean? Maybe give it a more meaningful name, unless it is
>>> actually something in the standard. Kerneldoc would also help.
>> Ah, it is "write not read". Shall I name it as "write_not_read" ?
> 
> You might want to describe the high level concept as well in this
> file. What i _think_ this is about is that SPI is sort of a full
> duplex bus. While you are sending data to the SPI device, the device
> could also be sending a data to the CPU? And 'write not read' here
> means ignore what we receive from the device?
Ah ok, I think there is a misunderstanding here. This is related to OPEN 
Alliance protocol. Control transactions consist of one or more control 
commands. Control commands are used by the SPI host to read and write 
registers within the MAC-PHY. Each control commands are composed of a 
32-bit control command header followed by register data. WNR (write not 
read) bit in the control command header indicates if data is to be 
written to registers (when set) or read from registers (when clear). so 
basically it indicates the type of the control command on the registers.
> 
>> Ok, as per OA spec, up to 128 consecutive registers read or write can be
>> possible. So the maximum possible size would be 1032. As you suggested
>> will allocate this size of memory in the startup.
> 
> Yes, 1032 bytes it not huge, so allocate it once and keep it for the
> lifetime of the device.
Sure, will do that.
> 
>>>> +void oa_tc6_deinit(struct oa_tc6 *tc6)
>>>> +{
>>>> +     kfree(tc6);
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(oa_tc6_deinit);
>>>
>>> Maybe consider a devm_ API to make the MAC driver simpler.
>> Sorry I don't get your point. Could you please explain bit more?
> 
> At least at this stage in the patch series, all you are doing is
> allocating memory. You add more code later, which might invalidate my
> point. But if all you are doing is allocating memory, you could use
> devm_kmalloc(). The driver core will then take care of releasing the
> memory when the driver is unloaded, or probe fails. That makes cleanup
> simpler and memory leaks less likely. There are a lot of devm_
> helpers, see if you can use them.
Sure, noted.

Best Regards,
Parthiban V
> 
>          Andrew
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 3/6] net: ethernet: implement OA TC6 configuration function
  2023-09-19 12:54       ` Andrew Lunn
@ 2023-09-20 12:42         ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-20 12:42 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 19/09/23 6:24 pm, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>>>> +/* Unmasking interrupt fields in IMASK0 */
>>>> +#define HDREM                ~BIT(5)         /* Header Error Mask */
>>>> +#define LOFEM                ~BIT(4)         /* Loss of Framing Error Mask */
>>>> +#define RXBOEM               ~BIT(3)         /* Rx Buffer Overflow Error Mask */
>>>> +#define TXBUEM               ~BIT(2)         /* Tx Buffer Underflow Error Mask */
>>>> +#define TXBOEM               ~BIT(1)         /* Tx Buffer Overflow Error Mask */
>>>> +#define TXPEM                ~BIT(0)         /* Tx Protocol Error Mask */
>>>
>>> Using ~BIT(X) is very usual. I would not do this, Principle of Least
>>> Surprise.
>> Sorry, I don't get your point. Could you please explain bit more?
> 
> Look around kernel header files. How often do you see ~BIT(5)?  My
> guess it is approximately 0. So i'm suggesting you remove the ~ and
> have the user of the #define assemble the mask and then do the ~ .
Ah ok ok, thanks for the clarification.

Best Regards,
Parthiban V
> 
>       Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY
  2023-09-19 12:50       ` Andrew Lunn
@ 2023-09-20 12:53         ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-20 12:53 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	Ciprian.Regus, jtm

Hi Andrew,

On 19/09/23 6:20 pm, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> Sure, I can move this part to oa_tc6 lib. If I understand you correctly
>> you are talking about the Standard Capabilities Register (0x0002)
>> defined in the OPEN Alliance 10BASE-T1x MAC-PHY Serial Interface spec
>> right? If so, the 9th bit of this register tells about Indirect PHY
>> Register access Capability. Did you mean this bit? If so, this bit
>> describes the below,
>>
>> IPRAC - Indirect PHY Register Access Capability. Indicates if PHY
>> registers are indirectly accessible through the MDIO/MDC registers MDIOACCn.
> 
> Yes. If the core relies on any functionality which is optional in the
> standard, it should check if the capability bit is set, and do a
> dev_erro() and return -ENODEV if a device does not actually have
> it. That makes it clear the core needs extending to support a device.
Ok, will do that.
> 
> If you are only using mandatory parts of the spec, then no test is
> needed.
Ok.
> 
>>> I would expect to see a call to phy_ethtool_ksettings_set()
>>> here. phylib should be able to do some of the validation.
>> Ah ok, doing the below will make the life easier.
>> .set_link_ksettings   = phy_ethtool_set_link_ksettings,
> 
> Please do some testing and check that phy_ethtool_set_link_ksettings
> doe actually reject all invalid setting. I cannot guarantee it does,
> and if it does not, it might actually be a PHY driver bug.
Yes sure.
> 
>>>> +static int lan865x_net_open(struct net_device *netdev)
>>>> +{
>>>> +     struct lan865x_priv *priv = netdev_priv(netdev);
>>>> +     int ret;
>>>> +
>>>> +     if (!is_valid_ether_addr(netdev->dev_addr)) {
>>>> +             if (netif_msg_ifup(priv))
>>>> +                     netdev_err(netdev, "Invalid MAC address %pm", netdev->dev_addr);
>>>> +             return -EADDRNOTAVAIL;
>>>
>>> Using a random MAC address is the normal workaround for not having a
>>> valid MAC address via OTP flash etc.
>> Ah ok, you mean to use eth_hw_addr_random(netdev) instead of returning
>> error.
> 
> Yes. And this is generally done earlier than open, as part of
> probe. You want to avoid surprising userspace when the MAC address
> suddenly changes at open time.
Ah ok ok, will move that to probe.

Best Regards,
Parthiban V
> 
>           Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-20 12:40         ` Parthiban.Veerasooran
@ 2023-09-20 13:37           ` Andrew Lunn
  2023-09-21  9:15             ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-20 13:37 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	Ciprian.Regus, jtm

> Ah ok, I think there is a misunderstanding here. This is related to OPEN 
> Alliance protocol. Control transactions consist of one or more control 
> commands. Control commands are used by the SPI host to read and write 
> registers within the MAC-PHY. Each control commands are composed of a 
> 32-bit control command header followed by register data. WNR (write not 
> read) bit in the control command header indicates if data is to be 
> written to registers (when set) or read from registers (when clear). so 
> basically it indicates the type of the control command on the registers.

OK, so this clearly indicates the names are bad and documentation is
missing if i got this completely wrong. Adding kerneldoc to these
functions should help.

	Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-20 13:37           ` Andrew Lunn
@ 2023-09-21  9:15             ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-21  9:15 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr,
	Ciprian.Regus, jtm

Hi Andrew,

On 20/09/23 7:07 pm, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> Ah ok, I think there is a misunderstanding here. This is related to OPEN
>> Alliance protocol. Control transactions consist of one or more control
>> commands. Control commands are used by the SPI host to read and write
>> registers within the MAC-PHY. Each control commands are composed of a
>> 32-bit control command header followed by register data. WNR (write not
>> read) bit in the control command header indicates if data is to be
>> written to registers (when set) or read from registers (when clear). so
>> basically it indicates the type of the control command on the registers.
> 
> OK, so this clearly indicates the names are bad and documentation is
> missing if i got this completely wrong. Adding kerneldoc to these
> functions should help.
Sure, I will do that.
> 
>          Andrew
> 
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-13  1:32       ` Andrew Lunn
@ 2023-09-21 12:27         ` Parthiban.Veerasooran
  2023-09-21 19:16           ` Andrew Lunn
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-21 12:27 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 13/09/23 7:02 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> If I understand you correctly, this framework has to include the module
>> initialization as well using the below APIs and has to be compiled as a
>> loadable module so that other vendors module can make use of this, isn't it?
>>
>> module_init(oa_tc6_init);
>> module_exit(oa_tc6_exit);
> 
> You should not need these, unless there is actions which need to be
> taken when the module is loaded. If there are no actions, it is purely
> a library, don't have them. The module dependency tracking code will
> see that the MAC driver modules has dependencies on symbols in this
> library module, and will load it first. The MAC driver is then loaded,
> and the kernel linker will resolve the missing symbols in the MAC
> driver to those in the library. It also means that there is only ever
> one copy of the library in the kernel, even if there is multiple MAC
> drivers using it.
Ah ok. Actually I missed including this library in the Kconfig and Makefile.

So drivers/net/ethernet/Kconfig file should contain the below,

config OA_TC6
          tristate "OPEN Alliance TC6 10BASE-T1x MAC-PHY support"
          depends on SPI
          select PHYLIB 

          help
            This library implements OPEN Alliance TC6 10BASE-T1x MAC-PHY
            Serial Interface protocol for supporting 10BASE-T1x MAC-PHYs.

The drivers/net/ethernet/Makefile file should contain the below,

obj-$(CONFIG_OA_TC6) += oa_tc6.o

Is this you expected right?

Best Regards,
Parthiban V
> 
>         Andrew
> 


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-19 12:58       ` Andrew Lunn
@ 2023-09-21 12:36         ` Parthiban.Veerasooran
  2023-09-21 19:19           ` Andrew Lunn
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-21 12:36 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 19/09/23 6:28 pm, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On Tue, Sep 19, 2023 at 11:13:13AM +0000, Parthiban.Veerasooran@microchip.com wrote:
>> Hi Andrew,
>>
>> On 13/09/23 7:46 am, Andrew Lunn wrote:
>>> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>>>
>>>> +struct oa_tc6 {
>>>> +     struct spi_device *spi;
>>>> +     bool ctrl_prot;
>>>> +};
>>>
>>> Should this be considered an opaque structure which the MAC driver
>>> should not access the members?
> 
> Opaque vs not opaque is an important design decision. If the MAC
> driver is allowed to directly access this structure, you should
> document the locking concept. If the MAC is not supposed to access it
> directly, only uses getters/setters, that also needs documenting, and
> maybe even make it a void * in the MAC driver.
Sorry that I missed to reply in the previous email. Thanks for the 
details on this topic.

Yes, as "struct oa_tc6" and its members are not or going to be accessed 
in the MAC driver, I will consider this as an opaque structure and 
declare it as void *opaque_oa_tc6 in the MAC driver private structure 
"struct lan865x_priv" and will pass to the APIs exported from oa_tc6.c lib.

Is my understanding correct?

Best Regards,
Parthiban V
> 
>        Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-21 12:27         ` Parthiban.Veerasooran
@ 2023-09-21 19:16           ` Andrew Lunn
  2023-09-22  4:31             ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-21 19:16 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> So drivers/net/ethernet/Kconfig file should contain the below,
> 
> config OA_TC6
>           tristate "OPEN Alliance TC6 10BASE-T1x MAC-PHY support"
>           depends on SPI
>           select PHYLIB 
> 
>           help
>             This library implements OPEN Alliance TC6 10BASE-T1x MAC-PHY
>             Serial Interface protocol for supporting 10BASE-T1x MAC-PHYs.
> 
> The drivers/net/ethernet/Makefile file should contain the below,
> 
> obj-$(CONFIG_OA_TC6) += oa_tc6.o

That looks about right, but i'm not a kconfig expert.

I would expect drivers using this to then have a

	depends on OA_TC6

	Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-21 12:36         ` Parthiban.Veerasooran
@ 2023-09-21 19:19           ` Andrew Lunn
  2023-09-22  4:39             ` Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Andrew Lunn @ 2023-09-21 19:19 UTC (permalink / raw)
  To: Parthiban.Veerasooran
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

> Yes, as "struct oa_tc6" and its members are not or going to be accessed 
> in the MAC driver, I will consider this as an opaque structure and 
> declare it as void *opaque_oa_tc6 in the MAC driver private structure 
> "struct lan865x_priv" and will pass to the APIs exported from oa_tc6.c lib.
> 
> Is my understanding correct?

Yes.

If the structure is going to be truly opaque, i suggest having it in
the C file, not the H file.

	Andrew

^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-21 19:16           ` Andrew Lunn
@ 2023-09-22  4:31             ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-22  4:31 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 22/09/23 12:46 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> So drivers/net/ethernet/Kconfig file should contain the below,
>>
>> config OA_TC6
>>            tristate "OPEN Alliance TC6 10BASE-T1x MAC-PHY support"
>>            depends on SPI
>>            select PHYLIB
>>
>>            help
>>              This library implements OPEN Alliance TC6 10BASE-T1x MAC-PHY
>>              Serial Interface protocol for supporting 10BASE-T1x MAC-PHYs.
>>
>> The drivers/net/ethernet/Makefile file should contain the below,
>>
>> obj-$(CONFIG_OA_TC6) += oa_tc6.o
> 
> That looks about right, but i'm not a kconfig expert.
> 
> I would expect drivers using this to then have a
> 
>          depends on OA_TC6
Yes, that's for sure. The MAC driver (Ex: lan865x.c) Kconfig file will 
contain the above "depends on OA_TC6" if it supports OPEN Alliance TC6.

Best Regards,
Parthiban V
> 
>          Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-21 19:19           ` Andrew Lunn
@ 2023-09-22  4:39             ` Parthiban.Veerasooran
  2023-09-26 12:54               ` Fwd: " Parthiban.Veerasooran
  0 siblings, 1 reply; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-22  4:39 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

On 22/09/23 12:49 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> Yes, as "struct oa_tc6" and its members are not or going to be accessed
>> in the MAC driver, I will consider this as an opaque structure and
>> declare it as void *opaque_oa_tc6 in the MAC driver private structure
>> "struct lan865x_priv" and will pass to the APIs exported from oa_tc6.c lib.
>>
>> Is my understanding correct?
> 
> Yes.
> 
> If the structure is going to be truly opaque, i suggest having it in
> the C file, not the H file.

Yes for sure, I will move it to oa_tc6.c file.

Andrew, thanks a lot for all your comments. They are all really helping 
me to know/learn many things to improve my patches and coding style. 
Please keep supporting.

Best Regards,
Parthiban V
> 
>          Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

* Fwd: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface
  2023-09-22  4:39             ` Parthiban.Veerasooran
@ 2023-09-26 12:54               ` Parthiban.Veerasooran
  0 siblings, 0 replies; 85+ messages in thread
From: Parthiban.Veerasooran @ 2023-09-26 12:54 UTC (permalink / raw)
  To: andrew
  Cc: davem, edumazet, kuba, pabeni, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, corbet, Steen.Hegelund, rdunlap, horms, casper.casan,
	netdev, devicetree, linux-kernel, linux-doc, Horatiu.Vultur,
	Woojung.Huh, Nicolas.Ferre, UNGLinuxDriver, Thorsten.Kummermehr

Hi Andrew,

As I didn't receive any more comments for past couple days, shall I 
start preparing v2 patch series with comments already given?

Best Regards,
Parthiban V

-------- Forwarded Message --------
Subject: Re: [RFC PATCH net-next 1/6] net: ethernet: implement OPEN 
Alliance control transaction interface
Date: Fri, 22 Sep 2023 10:09:09 +0530
From: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
To: Andrew Lunn <andrew@lunn.ch>
CC: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, 
pabeni@redhat.com, robh+dt@kernel.org, 
krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org, corbet@lwn.net, 
Steen.Hegelund@microchip.com, rdunlap@infradead.org, horms@kernel.org, 
casper.casan@gmail.com, netdev@vger.kernel.org, 
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, 
linux-doc@vger.kernel.org, Horatiu.Vultur@microchip.com, 
Woojung.Huh@microchip.com, Nicolas.Ferre@microchip.com, 
UNGLinuxDriver@microchip.com, Thorsten.Kummermehr@microchip.com

Hi Andrew,

On 22/09/23 12:49 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> Yes, as "struct oa_tc6" and its members are not or going to be accessed
>> in the MAC driver, I will consider this as an opaque structure and
>> declare it as void *opaque_oa_tc6 in the MAC driver private structure
>> "struct lan865x_priv" and will pass to the APIs exported from oa_tc6.c lib.
>>
>> Is my understanding correct?
> 
> Yes.
> 
> If the structure is going to be truly opaque, i suggest having it in
> the C file, not the H file.

Yes for sure, I will move it to oa_tc6.c file.

Andrew, thanks a lot for all your comments. They are all really helping 
me to know/learn many things to improve my patches and coding style. 
Please keep supporting.

Best Regards,
Parthiban V
> 
>          Andrew


^ permalink raw reply	[flat|nested] 85+ messages in thread

end of thread, other threads:[~2023-09-26 12:54 UTC | newest]

Thread overview: 85+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-08 14:29 [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface Parthiban Veerasooran
2023-09-08 14:29 ` [RFC PATCH net-next 1/6] net: ethernet: implement OPEN Alliance control transaction interface Parthiban Veerasooran
2023-09-09 13:33   ` Andrew Lunn
2023-09-12 13:03     ` Parthiban.Veerasooran
2023-09-13  1:32       ` Andrew Lunn
2023-09-21 12:27         ` Parthiban.Veerasooran
2023-09-21 19:16           ` Andrew Lunn
2023-09-22  4:31             ` Parthiban.Veerasooran
2023-09-13  1:36   ` Andrew Lunn
2023-09-19 11:40     ` Parthiban.Veerasooran
2023-09-13  2:11   ` Andrew Lunn
2023-09-19 11:38     ` Parthiban.Veerasooran
2023-09-19 15:13       ` Andrew Lunn
2023-09-20 12:40         ` Parthiban.Veerasooran
2023-09-20 13:37           ` Andrew Lunn
2023-09-21  9:15             ` Parthiban.Veerasooran
2023-09-13  2:16   ` Andrew Lunn
2023-09-19 11:13     ` Parthiban.Veerasooran
2023-09-19 12:58       ` Andrew Lunn
2023-09-21 12:36         ` Parthiban.Veerasooran
2023-09-21 19:19           ` Andrew Lunn
2023-09-22  4:39             ` Parthiban.Veerasooran
2023-09-26 12:54               ` Fwd: " Parthiban.Veerasooran
2023-09-08 14:29 ` [RFC PATCH net-next 2/6] net: ethernet: add mac-phy interrupt support with reset complete handling Parthiban Veerasooran
2023-09-09 13:39   ` Andrew Lunn
2023-09-12 12:44     ` Parthiban.Veerasooran
2023-09-13  2:19       ` Andrew Lunn
2023-09-19 11:04         ` Parthiban.Veerasooran
2023-09-11 12:51   ` Ziyang Xuan (William)
2023-09-12 12:10     ` Andrew Lunn
2023-09-12 12:28     ` Parthiban.Veerasooran
2023-09-13  2:39   ` Andrew Lunn
2023-09-19 13:07     ` Parthiban.Veerasooran
2023-09-19 13:21       ` Lukasz Majewski
2023-09-13  8:44   ` Lukasz Majewski
2023-09-13 12:36     ` Andrew Lunn
2023-09-13 13:26       ` Lukasz Majewski
2023-09-19 13:40         ` Parthiban.Veerasooran
2023-09-19 13:51           ` Lukasz Majewski
2023-09-08 14:29 ` [RFC PATCH net-next 3/6] net: ethernet: implement OA TC6 configuration function Parthiban Veerasooran
2023-09-14  0:46   ` Andrew Lunn
2023-09-19 10:57     ` Parthiban.Veerasooran
2023-09-19 12:54       ` Andrew Lunn
2023-09-20 12:42         ` Parthiban.Veerasooran
2023-09-08 14:29 ` [RFC PATCH net-next 4/6] net: ethernet: implement data transaction interface Parthiban Veerasooran
2023-09-10 17:58   ` Simon Horman
2023-09-12 13:47     ` Parthiban.Veerasooran
2023-09-11 12:59   ` Ziyang Xuan (William)
2023-09-12 10:32     ` Parthiban.Veerasooran
2023-09-14  1:18   ` Andrew Lunn
2023-09-18 10:02     ` Parthiban.Veerasooran
2023-09-18 13:01       ` Andrew Lunn
2023-09-19 10:12         ` Parthiban.Veerasooran
2023-09-08 14:29 ` [RFC PATCH net-next 5/6] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY Parthiban Veerasooran
2023-09-10 17:44   ` Simon Horman
2023-09-12 10:53     ` Parthiban.Veerasooran
2023-09-11 13:17   ` Ziyang Xuan (William)
2023-09-12 11:41     ` Parthiban.Veerasooran
2023-09-14  1:51   ` Andrew Lunn
2023-09-19  9:18     ` Parthiban.Veerasooran
2023-09-19 12:50       ` Andrew Lunn
2023-09-20 12:53         ` Parthiban.Veerasooran
2023-09-14  1:55   ` Andrew Lunn
2023-09-18 11:23     ` Parthiban.Veerasooran
2023-09-15 13:01   ` David Wretman
2023-09-18 11:22     ` Parthiban.Veerasooran
2023-09-08 14:29 ` [RFC PATCH net-next 6/6] microchip: lan865x: add device-tree " Parthiban Veerasooran
2023-09-10 10:55   ` Krzysztof Kozlowski
2023-09-12 12:15     ` Parthiban.Veerasooran
2023-09-12 13:17       ` Krzysztof Kozlowski
2023-09-19 10:51         ` Parthiban.Veerasooran
2023-09-14  2:07   ` Andrew Lunn
2023-09-19 10:40     ` Parthiban.Veerasooran
2023-09-10 10:55 ` [RFC PATCH net-next 0/6] Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface Krzysztof Kozlowski
2023-09-13 13:26   ` Parthiban.Veerasooran
2023-09-13 15:45     ` Krzysztof Kozlowski
2023-09-18  9:23       ` Parthiban.Veerasooran
2023-09-15 13:56 ` Alexander Dahl
2023-09-15 14:22   ` Andrew Lunn
2023-09-18  6:16     ` Parthiban.Veerasooran
2023-09-18  6:12   ` Parthiban.Veerasooran
2023-09-18  9:02     ` Fwd: " Parthiban.Veerasooran
2023-09-19  9:03       ` Parthiban.Veerasooran
2023-09-19 16:23         ` Jay Monkman
2023-09-19 18:09         ` Hennerich, Michael

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).