2020-05-27 15:51:06

by Serge Semin

[permalink] [raw]
Subject: [PATCH] check: Add 10bit/slave i2c reg flags support

Recently the I2C-controllers slave interface support was added to the
kernel I2C subsystem. In this case Linux can be used as, for example,
a I2C EEPROM machine. See [1] for details. Other than instantiating
the EEPROM-slave device from user-space there is a way to declare the
device in dts. In this case firstly the I2C bus controller must support
the slave interface. Secondly I2C-slave sub-node of that controller
must have "reg"-property with flag I2C_OWN_SLAVE_ADDRESS set (flag is
declared in [2]). That flag is declared as (1 << 30), which when set
makes dtc unhappy about too big address set for a I2C-slave:

Warning (i2c_bus_reg): /example-2/i2c@1120000/eeprom@64: I2C bus unit address format error, expected "40000064"
Warning (i2c_bus_reg): /example-2/i2c@1120000/eeprom@64:reg: I2C address must be less than 10-bits, got "0x40000064"

Similar problem would have happened if we had set the 10-bit address
flag I2C_TEN_BIT_ADDRESS in the "reg"-property.

In order to fix the problem we suggest to alter the I2C-bus reg-check
algorithm, so one would be aware of the upper bits set. Normally if no
flag specified, the 7-bit address is expected in the "reg"-property.
If I2C_TEN_BIT_ADDRESS is set, then the 10-bit address check will be
performed. The I2C_OWN_SLAVE_ADDRESS flag will be just ignored.

[1] kernel/Documentation/i2c/slave-interface.rst
[2] kernel/include/dt-bindings/i2c/i2c.h

Signed-off-by: Serge Semin <[email protected]>
Cc: Alexey Malahov <[email protected]>
Cc: Thomas Bogendoerfer <[email protected]>
Cc: Wolfram Sang <[email protected]>
Cc: Jarkko Nikula <[email protected]>
Cc: Andy Shevchenko <[email protected]>
Cc: Frank Rowand <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
checks.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/checks.c b/checks.c
index 4b3c486f1399..6321fc5b7404 100644
--- a/checks.c
+++ b/checks.c
@@ -1028,6 +1028,7 @@ static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node
const char *unitname = get_unitname(node);
char unit_addr[17];
uint32_t reg = 0;
+ uint32_t addr;
int len;
cell_t *cells = NULL;

@@ -1044,17 +1045,21 @@ static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node
}

reg = fdt32_to_cpu(*cells);
- snprintf(unit_addr, sizeof(unit_addr), "%x", reg);
+ addr = reg & 0x3FFFFFFFU;
+ snprintf(unit_addr, sizeof(unit_addr), "%x", addr);
if (!streq(unitname, unit_addr))
FAIL(c, dti, node, "I2C bus unit address format error, expected \"%s\"",
unit_addr);

for (len = prop->val.len; len > 0; len -= 4) {
reg = fdt32_to_cpu(*(cells++));
- if (reg > 0x3ff)
+ addr = reg & 0x3FFFFFFFU;
+ if ((reg & (1 << 31)) && addr > 0x3ff)
FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"",
- reg);
-
+ addr);
+ else if (!(reg & (1 << 31)) && addr > 0x7f)
+ FAIL_PROP(c, dti, node, prop, "I2C address must be less than 7-bits, got \"0x%x\"",
+ addr);
}
}
WARNING(i2c_bus_reg, check_i2c_bus_reg, NULL, &reg_format, &i2c_bus_bridge);
--
2.26.2


2020-05-27 15:56:21

by Serge Semin

[permalink] [raw]
Subject: Re: [PATCH] check: Add 10bit/slave i2c reg flags support

On Wed, May 27, 2020 at 04:36:56PM +0300, Andy Shevchenko wrote:
> On Wed, May 27, 2020 at 03:25:25PM +0300, Serge Semin wrote:
> > Recently the I2C-controllers slave interface support was added to the
> > kernel I2C subsystem. In this case Linux can be used as, for example,
> > a I2C EEPROM machine. See [1] for details. Other than instantiating
> > the EEPROM-slave device from user-space there is a way to declare the
> > device in dts. In this case firstly the I2C bus controller must support
> > the slave interface. Secondly I2C-slave sub-node of that controller
> > must have "reg"-property with flag I2C_OWN_SLAVE_ADDRESS set (flag is
> > declared in [2]). That flag is declared as (1 << 30), which when set
> > makes dtc unhappy about too big address set for a I2C-slave:
> >
> > Warning (i2c_bus_reg): /example-2/i2c@1120000/eeprom@64: I2C bus unit address format error, expected "40000064"
> > Warning (i2c_bus_reg): /example-2/i2c@1120000/eeprom@64:reg: I2C address must be less than 10-bits, got "0x40000064"
> >
> > Similar problem would have happened if we had set the 10-bit address
> > flag I2C_TEN_BIT_ADDRESS in the "reg"-property.
> >
> > In order to fix the problem we suggest to alter the I2C-bus reg-check
> > algorithm, so one would be aware of the upper bits set. Normally if no
> > flag specified, the 7-bit address is expected in the "reg"-property.
> > If I2C_TEN_BIT_ADDRESS is set, then the 10-bit address check will be
> > performed. The I2C_OWN_SLAVE_ADDRESS flag will be just ignored.
> >
> > [1] kernel/Documentation/i2c/slave-interface.rst
> > [2] kernel/include/dt-bindings/i2c/i2c.h
>
> ...
>

> > + addr = reg & 0x3FFFFFFFU;
> > + if ((reg & (1 << 31)) && addr > 0x3ff)
> > FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"",
> > - reg);
> > -
> > + addr);
> > + else if (!(reg & (1 << 31)) && addr > 0x7f)
> > + FAIL_PROP(c, dti, node, prop, "I2C address must be less than 7-bits, got \"0x%x\"",
> > + addr);
>
> 1 << 31 is UB.

Good point. Thanks.

-Sergey

>
> --
> With Best Regards,
> Andy Shevchenko
>
>

2020-05-27 17:53:06

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH] check: Add 10bit/slave i2c reg flags support

On Wed, May 27, 2020 at 03:25:25PM +0300, Serge Semin wrote:
> Recently the I2C-controllers slave interface support was added to the
> kernel I2C subsystem. In this case Linux can be used as, for example,
> a I2C EEPROM machine. See [1] for details. Other than instantiating
> the EEPROM-slave device from user-space there is a way to declare the
> device in dts. In this case firstly the I2C bus controller must support
> the slave interface. Secondly I2C-slave sub-node of that controller
> must have "reg"-property with flag I2C_OWN_SLAVE_ADDRESS set (flag is
> declared in [2]). That flag is declared as (1 << 30), which when set
> makes dtc unhappy about too big address set for a I2C-slave:
>
> Warning (i2c_bus_reg): /example-2/i2c@1120000/eeprom@64: I2C bus unit address format error, expected "40000064"
> Warning (i2c_bus_reg): /example-2/i2c@1120000/eeprom@64:reg: I2C address must be less than 10-bits, got "0x40000064"
>
> Similar problem would have happened if we had set the 10-bit address
> flag I2C_TEN_BIT_ADDRESS in the "reg"-property.
>
> In order to fix the problem we suggest to alter the I2C-bus reg-check
> algorithm, so one would be aware of the upper bits set. Normally if no
> flag specified, the 7-bit address is expected in the "reg"-property.
> If I2C_TEN_BIT_ADDRESS is set, then the 10-bit address check will be
> performed. The I2C_OWN_SLAVE_ADDRESS flag will be just ignored.
>
> [1] kernel/Documentation/i2c/slave-interface.rst
> [2] kernel/include/dt-bindings/i2c/i2c.h

...

> + addr = reg & 0x3FFFFFFFU;
> + if ((reg & (1 << 31)) && addr > 0x3ff)
> FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"",
> - reg);
> -
> + addr);
> + else if (!(reg & (1 << 31)) && addr > 0x7f)
> + FAIL_PROP(c, dti, node, prop, "I2C address must be less than 7-bits, got \"0x%x\"",
> + addr);

1 << 31 is UB.

--
With Best Regards,
Andy Shevchenko


2020-05-27 18:04:05

by Serge Semin

[permalink] [raw]
Subject: [PATCH v2] check: Add 10bit/slave i2c reg flags support

Recently the I2C-controllers slave interface support was added to the
kernel I2C subsystem. In this case Linux can be used as, for example,
a I2C EEPROM machine. See [1] for details. Other than instantiating
the EEPROM-slave device from user-space there is a way to declare the
device in dts. In this case firstly the I2C bus controller must support
the slave interface. Secondly I2C-slave sub-node of that controller
must have "reg"-property with flag I2C_OWN_SLAVE_ADDRESS set (flag is
declared in [2]). That flag is declared as (1 << 30), which when set
makes dtc unhappy about too big address set for a I2C-slave:

Warning (i2c_bus_reg): /example-2/i2c@1120000/eeprom@64: I2C bus unit address format error, expected "40000064"
Warning (i2c_bus_reg): /example-2/i2c@1120000/eeprom@64:reg: I2C address must be less than 10-bits, got "0x40000064"

Similar problem would have happened if we had set the 10-bit address
flag I2C_TEN_BIT_ADDRESS in the "reg"-property.

In order to fix the problem we suggest to alter the I2C-bus reg-check
algorithm, so one would be aware of the upper bits set. Normally if no
flag specified, the 7-bit address is expected in the "reg"-property.
If I2C_TEN_BIT_ADDRESS is set, then the 10-bit address check will be
performed. The I2C_OWN_SLAVE_ADDRESS flag will be just ignored.

[1] kernel/Documentation/i2c/slave-interface.rst
[2] kernel/include/dt-bindings/i2c/i2c.h

Signed-off-by: Serge Semin <[email protected]>
Cc: Alexey Malahov <[email protected]>
Cc: Thomas Bogendoerfer <[email protected]>
Cc: Wolfram Sang <[email protected]>
Cc: Jarkko Nikula <[email protected]>
Cc: Andy Shevchenko <[email protected]>
Cc: Frank Rowand <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]

---

Changelog v2:
- Use unsigned numeric literal in the left-shit operation to avoid UB.
---
checks.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/checks.c b/checks.c
index 4b3c486f1399..7091d1bc38d2 100644
--- a/checks.c
+++ b/checks.c
@@ -1028,6 +1028,7 @@ static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node
const char *unitname = get_unitname(node);
char unit_addr[17];
uint32_t reg = 0;
+ uint32_t addr;
int len;
cell_t *cells = NULL;

@@ -1044,17 +1045,21 @@ static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node
}

reg = fdt32_to_cpu(*cells);
- snprintf(unit_addr, sizeof(unit_addr), "%x", reg);
+ addr = reg & 0x3FFFFFFFU;
+ snprintf(unit_addr, sizeof(unit_addr), "%x", addr);
if (!streq(unitname, unit_addr))
FAIL(c, dti, node, "I2C bus unit address format error, expected \"%s\"",
unit_addr);

for (len = prop->val.len; len > 0; len -= 4) {
reg = fdt32_to_cpu(*(cells++));
- if (reg > 0x3ff)
+ addr = reg & 0x3FFFFFFFU;
+ if ((reg & (1U << 31)) && addr > 0x3ff)
FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"",
- reg);
-
+ addr);
+ else if (!(reg & (1U << 31)) && addr > 0x7f)
+ FAIL_PROP(c, dti, node, prop, "I2C address must be less than 7-bits, got \"0x%x\"",
+ addr);
}
}
WARNING(i2c_bus_reg, check_i2c_bus_reg, NULL, &reg_format, &i2c_bus_bridge);
--
2.26.2

2020-05-30 09:34:13

by Wolfram Sang

[permalink] [raw]
Subject: Re: [PATCH v2] check: Add 10bit/slave i2c reg flags support


> + addr = reg & 0x3FFFFFFFU;
> + snprintf(unit_addr, sizeof(unit_addr), "%x", addr);

Hmm, this hardcoded value will not work if we ever need to add another
bit. I hope this will never happen, though.

> + if ((reg & (1U << 31)) && addr > 0x3ff)

Same here with bit 31. I haven't checked DTC but can't we import the
header with the defines into the project? Or is this then a circular
dependency?


Attachments:
(No filename) (414.00 B)
signature.asc (849.00 B)
Download all attachments

2020-05-31 19:12:20

by Serge Semin

[permalink] [raw]
Subject: Re: [PATCH v2] check: Add 10bit/slave i2c reg flags support

On Sat, May 30, 2020 at 11:31:52AM +0200, Wolfram Sang wrote:
>
> > + addr = reg & 0x3FFFFFFFU;
> > + snprintf(unit_addr, sizeof(unit_addr), "%x", addr);
>
> Hmm, this hardcoded value will not work if we ever need to add another
> bit. I hope this will never happen, though.
>
> > + if ((reg & (1U << 31)) && addr > 0x3ff)
>
> Same here with bit 31.

I'd be glad to use a macro or some helper here, but alas there is no
ready-to-use i2c-related one in the dtc code. See, there are hard-coded
literals in the PCI nodes checkers (check_pci_device_reg(),
check_pci_device_bus_num()) and the hard-coded literals've been in the
i2c-nodes checkers even before this patch.

> I haven't checked DTC but can't we import the
> header with the defines into the project? Or is this then a circular
> dependency?
>

I guess importing header would be much better than the hard-coded values
currently used. What do the code maintainers say about that? Any idea how it
is supposed to be implemented?

-Sergey

2020-06-01 17:40:24

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH v2] check: Add 10bit/slave i2c reg flags support

On Sat, May 30, 2020 at 3:32 AM Wolfram Sang <[email protected]> wrote:
>
>
> > + addr = reg & 0x3FFFFFFFU;
> > + snprintf(unit_addr, sizeof(unit_addr), "%x", addr);
>
> Hmm, this hardcoded value will not work if we ever need to add another
> bit. I hope this will never happen, though.

I had this concern and requested the first time this was submitted
(and abandoned) to just mask out the top byte. However, Joel's version
of this fix[1] does some actual checks on 10-bit addressing, so I've
dropped that request.

> > + if ((reg & (1U << 31)) && addr > 0x3ff)
>
> Same here with bit 31. I haven't checked DTC but can't we import the
> header with the defines into the project? Or is this then a circular
> dependency?

Easier to just duplicate the define here which Joel's patches do.

Rob

[1] https://www.spinics.net/lists/devicetree-compiler/msg03196.html

2020-06-02 07:49:03

by Wolfram Sang

[permalink] [raw]
Subject: Re: [PATCH v2] check: Add 10bit/slave i2c reg flags support


> Easier to just duplicate the define here which Joel's patches do.

Well, seems this case is closed then. Thanks everyone!


Attachments:
(No filename) (131.00 B)
signature.asc (849.00 B)
Download all attachments