]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
i3c: mipi-i3c-hci: Fix number of DAT/DCT entries for HCI versions < 1.1
authorJarkko Nikula <jarkko.nikula@linux.intel.com>
Fri, 14 Jun 2024 14:02:08 +0000 (17:02 +0300)
committerAlexandre Belloni <alexandre.belloni@bootlin.com>
Fri, 26 Jul 2024 12:21:29 +0000 (14:21 +0200)
I was wrong about the TABLE_SIZE field description in the
commit 0676bfebf576 ("i3c: mipi-i3c-hci: Fix DAT/DCT entry sizes").

For the MIPI I3C HCI versions 1.0 and earlier the TABLE_SIZE field in
the registers DAT_SECTION_OFFSET and DCT_SECTION_OFFSET is indeed defined
in DWORDs and not number of entries like it is defined in later versions.

Where above fix allowed driver initialization to continue the wrongly
interpreted TABLE_SIZE field leads variables DAT_entries being twice and
DCT_entries four times as big as they really are.

That in turn leads clearing the DAT table over the boundary in the
dat_v1.c: hci_dat_v1_init().

So interprete the TABLE_SIZE field in DWORDs for HCI versions < 1.1 and
fix number of DAT/DCT entries accordingly.

Fixes: 0676bfebf576 ("i3c: mipi-i3c-hci: Fix DAT/DCT entry sizes")
Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
drivers/i3c/master/mipi-i3c-hci/core.c

index d7e966a255833730c40728725e5f6c3817083cd9..4e7d6a43ee9b3b5b74f68934c93b7689c3f3d752 100644 (file)
@@ -631,6 +631,7 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id)
 static int i3c_hci_init(struct i3c_hci *hci)
 {
        u32 regval, offset;
+       bool size_in_dwords;
        int ret;
 
        /* Validate HCI hardware version */
@@ -654,11 +655,16 @@ static int i3c_hci_init(struct i3c_hci *hci)
        hci->caps = reg_read(HC_CAPABILITIES);
        DBG("caps = %#x", hci->caps);
 
+       size_in_dwords = hci->version_major < 1 ||
+                        (hci->version_major == 1 && hci->version_minor < 1);
+
        regval = reg_read(DAT_SECTION);
        offset = FIELD_GET(DAT_TABLE_OFFSET, regval);
        hci->DAT_regs = offset ? hci->base_regs + offset : NULL;
        hci->DAT_entries = FIELD_GET(DAT_TABLE_SIZE, regval);
        hci->DAT_entry_size = FIELD_GET(DAT_ENTRY_SIZE, regval) ? 0 : 8;
+       if (size_in_dwords)
+               hci->DAT_entries = 4 * hci->DAT_entries / hci->DAT_entry_size;
        dev_info(&hci->master.dev, "DAT: %u %u-bytes entries at offset %#x\n",
                 hci->DAT_entries, hci->DAT_entry_size, offset);
 
@@ -667,6 +673,8 @@ static int i3c_hci_init(struct i3c_hci *hci)
        hci->DCT_regs = offset ? hci->base_regs + offset : NULL;
        hci->DCT_entries = FIELD_GET(DCT_TABLE_SIZE, regval);
        hci->DCT_entry_size = FIELD_GET(DCT_ENTRY_SIZE, regval) ? 0 : 16;
+       if (size_in_dwords)
+               hci->DCT_entries = 4 * hci->DCT_entries / hci->DCT_entry_size;
        dev_info(&hci->master.dev, "DCT: %u %u-bytes entries at offset %#x\n",
                 hci->DCT_entries, hci->DCT_entry_size, offset);