diff mbox series

[net-next,v3,03/12] net: ethernet: oa_tc6: implement register read operation

Message ID 20240306085017.21731-4-Parthiban.Veerasooran@microchip.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 940 this patch: 940
netdev/build_tools success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 1 maintainers not CCed: parthiban.veerasooran@microchip.com
netdev/build_clang success Errors and warnings before: 956 this patch: 956
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 956 this patch: 956
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 115 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-03-06--15-00 (tests: 891)

Commit Message

Parthiban Veerasooran March 6, 2024, 8:50 a.m. UTC
Implement register read operation according to the control communication
specified in the OPEN Alliance 10BASE-T1x MACPHY Serial Interface
document. Control read commands are used by the SPI host to read
registers within the MAC-PHY. Each control read commands are composed of
a 32 bits control command header.

The MAC-PHY ignores all data from the SPI host following the control
header for the remainder of the control read command. 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. Reading any unimplemented
or undefined registers shall return zero.

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

Comments

Andrew Lunn March 7, 2024, 12:19 a.m. UTC | #1
>  enum oa_tc6_register_op {
> +	OA_TC6_CTRL_REG_READ = 0,
>  	OA_TC6_CTRL_REG_WRITE = 1,
>  };

I thought it looked a little odd when the enum was added in the
previous patch with the first value of 1, and only one value. Now it
makes more sense.

The actual value appears to not matter? It is always 

> +	if (reg_op == OA_TC6_CTRL_REG_WRITE)

So i would drop the numbering, and leave it to the compiler. The
patches will then look less odd.

> +static int oa_tc6_check_ctrl_read_reply(struct oa_tc6 *tc6, u8 size)
> +{
> +	u32 *tx_buf = tc6->spi_ctrl_tx_buf;
> +	u32 *rx_buf = tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE;
> +
> +	/* The echoed control read header must match with the one that was
> +	 * transmitted.
> +	 */
> +	if (*tx_buf != *rx_buf)
> +		return -ENODEV;

Another case where -EPROTO might be better?

	Andrew
Parthiban Veerasooran March 7, 2024, 7:04 a.m. UTC | #2
Hi Andrew,

On 07/03/24 5:49 am, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>>   enum oa_tc6_register_op {
>> +     OA_TC6_CTRL_REG_READ = 0,
>>        OA_TC6_CTRL_REG_WRITE = 1,
>>   };
> 
> I thought it looked a little odd when the enum was added in the
> previous patch with the first value of 1, and only one value. Now it
> makes more sense.
Ok.
> 
> The actual value appears to not matter? It is always
> 
>> +     if (reg_op == OA_TC6_CTRL_REG_WRITE)
> 
> So i would drop the numbering, and leave it to the compiler. The
> patches will then look less odd.
"drop the numbering", do you refer to this patch alone or previous patch 
also? If it is for this patch alone then it makes sense as they are 
going to be 0 and 1 anyway. But if we drop the numbering in the previous 
patch it will become 0 which will create an issue in the below line as 
it needs 1,

FIELD_PREP(OA_TC6_CTRL_HEADER_WRITE, reg_op)

Could you clarify? or do I have any misunderstanding here?
> 
>> +static int oa_tc6_check_ctrl_read_reply(struct oa_tc6 *tc6, u8 size)
>> +{
>> +     u32 *tx_buf = tc6->spi_ctrl_tx_buf;
>> +     u32 *rx_buf = tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE;
>> +
>> +     /* The echoed control read header must match with the one that was
>> +      * transmitted.
>> +      */
>> +     if (*tx_buf != *rx_buf)
>> +             return -ENODEV;
> 
> Another case where -EPROTO might be better?
Yes, I will use -EPROTO in the next version as it is likely "Protocol error"

Best regards,
Parthiban V
> 
>          Andrew
>
Andrew Lunn March 7, 2024, 1:22 p.m. UTC | #3
On Thu, Mar 07, 2024 at 07:04:20AM +0000, Parthiban.Veerasooran@microchip.com wrote:
> Hi Andrew,
> 
> On 07/03/24 5:49 am, Andrew Lunn wrote:
> > EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> > 
> >>   enum oa_tc6_register_op {
> >> +     OA_TC6_CTRL_REG_READ = 0,
> >>        OA_TC6_CTRL_REG_WRITE = 1,
> >>   };
> > 
> > I thought it looked a little odd when the enum was added in the
> > previous patch with the first value of 1, and only one value. Now it
> > makes more sense.
> Ok.
> > 
> > The actual value appears to not matter? It is always
> > 
> >> +     if (reg_op == OA_TC6_CTRL_REG_WRITE)
> > 
> > So i would drop the numbering, and leave it to the compiler. The
> > patches will then look less odd.
> "drop the numbering", do you refer to this patch alone or previous patch 
> also? If it is for this patch alone then it makes sense as they are 
> going to be 0 and 1 anyway. But if we drop the numbering in the previous 
> patch it will become 0 which will create an issue in the below line as 
> it needs 1,
> 
> FIELD_PREP(OA_TC6_CTRL_HEADER_WRITE, reg_op)

That is why i asked: 

> The actual value appears to not matter? It is always
> 
> +     if (reg_op == OA_TC6_CTRL_REG_WRITE)

So the actual value does matter, so keep it in the previous patch.
Does the value of OA_TC6_CTRL_REG_READ matter? Is it also used in
FIELD_PREP etc? If not, taking away the = 0 will emphasise that 
OA_TC6_CTRL_REG_WRITE has to be 1.

	Andrew
Parthiban Veerasooran March 8, 2024, 7:12 a.m. UTC | #4
Hi Andrew,

On 07/03/24 6:52 pm, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On Thu, Mar 07, 2024 at 07:04:20AM +0000, Parthiban.Veerasooran@microchip.com wrote:
>> Hi Andrew,
>>
>> On 07/03/24 5:49 am, Andrew Lunn wrote:
>>> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>>>
>>>>    enum oa_tc6_register_op {
>>>> +     OA_TC6_CTRL_REG_READ = 0,
>>>>         OA_TC6_CTRL_REG_WRITE = 1,
>>>>    };
>>>
>>> I thought it looked a little odd when the enum was added in the
>>> previous patch with the first value of 1, and only one value. Now it
>>> makes more sense.
>> Ok.
>>>
>>> The actual value appears to not matter? It is always
>>>
>>>> +     if (reg_op == OA_TC6_CTRL_REG_WRITE)
>>>
>>> So i would drop the numbering, and leave it to the compiler. The
>>> patches will then look less odd.
>> "drop the numbering", do you refer to this patch alone or previous patch
>> also? If it is for this patch alone then it makes sense as they are
>> going to be 0 and 1 anyway. But if we drop the numbering in the previous
>> patch it will become 0 which will create an issue in the below line as
>> it needs 1,
>>
>> FIELD_PREP(OA_TC6_CTRL_HEADER_WRITE, reg_op)
> 
> That is why i asked:
> 
>> The actual value appears to not matter? It is always
>>
>> +     if (reg_op == OA_TC6_CTRL_REG_WRITE)
> 
> So the actual value does matter, so keep it in the previous patch.
> Does the value of OA_TC6_CTRL_REG_READ matter? Is it also used in
> FIELD_PREP etc? If not, taking away the = 0 will emphasise that
> OA_TC6_CTRL_REG_WRITE has to be 1.
Sorry, I have done a mistake here that's confusing. The define name 
OA_TC6_CTRL_HEADER_WRITE in the FIELD_PREP is supposed to be 
OA_TC6_CTRL_HEADER_WRITE_NOT_READ. This bit field in the control command 
header differentiates the type of operation. If it is 0, then register 
read command and if it is 1, then register write command. So regop in 
the FIELD_PREP actually sets the type of operation.

The values of both OA_TC6_CTRL_REG_READ and OA_TC6_CTRL_REG_WRITE are 
matters here. So let's keep the numbering for both as it is now. But I 
will change the bit field define name as 
OA_TC6_CTRL_HEADER_WRITE_NOT_READ in the next version. Hope you are fine 
with it?

Best regards,
Parthiban V
> 
>          Andrew
>
diff mbox series

Patch

diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
index 82131f865fe7..35e377577ba4 100644
--- a/drivers/net/ethernet/oa_tc6.c
+++ b/drivers/net/ethernet/oa_tc6.c
@@ -38,6 +38,7 @@  enum oa_tc6_header_type {
 };
 
 enum oa_tc6_register_op {
+	OA_TC6_CTRL_REG_READ = 0,
 	OA_TC6_CTRL_REG_WRITE = 1,
 };
 
@@ -113,7 +114,8 @@  static void oa_tc6_prepare_ctrl_spi_buf(struct oa_tc6 *tc6, u32 address,
 
 	*tx_buf = oa_tc6_prepare_ctrl_header(address, length, reg_op);
 
-	oa_tc6_update_ctrl_write_data(tc6, value, length);
+	if (reg_op == OA_TC6_CTRL_REG_WRITE)
+		oa_tc6_update_ctrl_write_data(tc6, value, length);
 }
 
 static int oa_tc6_check_ctrl_write_reply(struct oa_tc6 *tc6, u8 size)
@@ -132,6 +134,30 @@  static int oa_tc6_check_ctrl_write_reply(struct oa_tc6 *tc6, u8 size)
 	return 0;
 }
 
+static int oa_tc6_check_ctrl_read_reply(struct oa_tc6 *tc6, u8 size)
+{
+	u32 *tx_buf = tc6->spi_ctrl_tx_buf;
+	u32 *rx_buf = tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE;
+
+	/* The echoed control read header must match with the one that was
+	 * transmitted.
+	 */
+	if (*tx_buf != *rx_buf)
+		return -ENODEV;
+
+	return 0;
+}
+
+static void oa_tc6_copy_ctrl_read_data(struct oa_tc6 *tc6, u32 value[],
+				       u8 length)
+{
+	__be32 *rx_buf = tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE +
+			 OA_TC6_CTRL_HEADER_SIZE;
+
+	for (int i = 0; i < length; i++)
+		value[i] = be32_to_cpu(*rx_buf++);
+}
+
 static int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 address, u32 value[],
 			       u8 length, enum oa_tc6_register_op reg_op)
 {
@@ -152,8 +178,62 @@  static int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 address, u32 value[],
 	}
 
 	/* Check echoed/received control write command reply for errors */
-	return oa_tc6_check_ctrl_write_reply(tc6, size);
+	if (reg_op == OA_TC6_CTRL_REG_WRITE)
+		return oa_tc6_check_ctrl_write_reply(tc6, size);
+
+	/* Check echoed/received control read command reply for errors */
+	ret = oa_tc6_check_ctrl_read_reply(tc6, size);
+	if (ret)
+		return ret;
+
+	oa_tc6_copy_ctrl_read_data(tc6, value, length);
+
+	return 0;
+}
+
+/**
+ * oa_tc6_read_registers - function for reading multiple consecutive registers.
+ * @tc6: oa_tc6 struct.
+ * @address: address of the first register to be read in the MAC-PHY.
+ * @value: values to be read from the starting register address @address.
+ * @length: number of consecutive registers to be read from @address.
+ *
+ * Maximum of 128 consecutive registers can be read starting at @address.
+ *
+ * Returns 0 on success otherwise failed.
+ */
+int oa_tc6_read_registers(struct oa_tc6 *tc6, u32 address, u32 value[],
+			  u8 length)
+{
+	int ret;
+
+	if (!length || length > OA_TC6_CTRL_MAX_REGISTERS) {
+		dev_err(&tc6->spi->dev, "Invalid register length parameter\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&tc6->spi_ctrl_lock);
+	ret = oa_tc6_perform_ctrl(tc6, address, value, length,
+				  OA_TC6_CTRL_REG_READ);
+	mutex_unlock(&tc6->spi_ctrl_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(oa_tc6_read_registers);
+
+/**
+ * oa_tc6_read_register - function for reading a MAC-PHY register.
+ * @tc6: oa_tc6 struct.
+ * @address: register address of the MAC-PHY to be read.
+ * @value: value read from the @address register address of the MAC-PHY.
+ *
+ * Returns 0 on success otherwise failed.
+ */
+int oa_tc6_read_register(struct oa_tc6 *tc6, u32 address, u32 *value)
+{
+	return oa_tc6_read_registers(tc6, address, value, 1);
 }
+EXPORT_SYMBOL_GPL(oa_tc6_read_register);
 
 /**
  * oa_tc6_write_registers - function for writing multiple consecutive registers.
diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h
index 99c490f1c8a8..85aeecf87306 100644
--- a/include/linux/oa_tc6.h
+++ b/include/linux/oa_tc6.h
@@ -15,3 +15,6 @@  struct oa_tc6 *oa_tc6_init(struct spi_device *spi);
 int oa_tc6_write_register(struct oa_tc6 *tc6, u32 address, u32 value);
 int oa_tc6_write_registers(struct oa_tc6 *tc6, u32 address, u32 value[],
 			   u8 length);
+int oa_tc6_read_register(struct oa_tc6 *tc6, u32 address, u32 *value);
+int oa_tc6_read_registers(struct oa_tc6 *tc6, u32 address, u32 value[],
+			  u8 length);