* [PATCH net-next 1/3] i2c: xiic: allow platforms to require 32-bit register accesses
[not found] <20261111041904.48916-1-ahmadexp@gmail.com>
@ 2026-11-11 4:19 ` Ahmad Byagowi
2026-11-13 10:21 ` netdev-bot+sashiko
2026-11-11 4:19 ` [PATCH net-next 2/3] i2c: xiic: add KUnit coverage for register access modes Ahmad Byagowi
2026-11-11 4:19 ` [PATCH net-next 3/3] ptp: ocp: add WiWi Time Card production image support Ahmad Byagowi
2 siblings, 1 reply; 6+ messages in thread
From: Ahmad Byagowi @ 2026-11-11 4:19 UTC (permalink / raw)
To: netdev, vadim.fedorenko, andi.shyti
Cc: linux-i2c, Michal Simek, linux-arm-kernel, linux-kernel
The LitePCIe bridge in the WiWi Time Card production image cannot safely
service subword MMIO accesses. Bringing up its AXI IIC controller with the
existing byte accessors caused a fatal machine check. Two crash dumps
placed the faulting access in ioread8(), called by xiic_clear_rx_fifo()
during xiic_reinit(). The affected register was the IIC status register.
Add a platform-data flag to use aligned 32-bit accesses for registers
carrying byte or halfword values. Keep the detected register endianness
and use a single transaction, not read-modify-write, for FIFO accesses.
Platforms that do not request this mode retain their existing accessors.
With these accessors on a WiWi card, the controller probed and at24
registered the board and MAC EEPROMs. Repeated EEPROM reads and I2C
interrupt delivery were tested separately on an earlier Ubuntu port.
Tool-origin disclosure, as required by generated-content.rst: Codex was
used to analyze the supplied crash evidence, implement the accessors,
prepare tests and draft this changelog. The request was to support the
WiWi card while retaining the existing behavior on other platforms.
Signed-off-by: Ahmad Byagowi <ahmadexp@gmail.com>
---
drivers/i2c/busses/i2c-xiic.c | 56 +++++++++++++++++---------
include/linux/platform_data/i2c-xiic.h | 3 ++
2 files changed, 41 insertions(+), 18 deletions(-)
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index ba560462d..d13cfb012 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -66,6 +66,7 @@ enum i2c_scl_freq {
* @rx_msg: Current RX message
* @rx_pos: Position within current RX message
* @endianness: big/little-endian byte order
+ * @force_32bit_access: Bridge requires aligned 32-bit register accesses
* @clk: Pointer to AXI4-lite input clock
* @irq: Interrupt number
* @state: See STATE_
@@ -95,6 +96,7 @@ struct xiic_i2c {
struct i2c_msg *rx_msg;
int rx_pos;
enum xiic_endian endianness;
+ bool force_32bit_access;
struct clk *clk;
int irq;
enum xilinx_i2c_state state;
@@ -282,52 +284,68 @@ static int xiic_i2c_runtime_resume(struct device *dev)
* Only the least significant byte [doublet] of the register are ever
* accessed. This requires an offset of 3 [2] from the base address for
* big-endian systems.
+ * Some bridges only support aligned 32-bit accesses. For these, access the
+ * entire register in its detected byte order, without a read-modify-write:
+ * reading or writing a FIFO register must perform exactly one transaction.
*/
-static inline void xiic_setreg8(struct xiic_i2c *i2c, int reg, u8 value)
+static inline void xiic_setreg32(struct xiic_i2c *i2c, int reg, int value)
{
if (i2c->endianness == LITTLE)
- iowrite8(value, i2c->base + reg);
+ iowrite32(value, i2c->base + reg);
else
- iowrite8(value, i2c->base + reg + 3);
+ iowrite32be(value, i2c->base + reg);
}
-static inline u8 xiic_getreg8(struct xiic_i2c *i2c, int reg)
+static inline int xiic_getreg32(struct xiic_i2c *i2c, int reg)
{
- u8 ret;
+ u32 ret;
if (i2c->endianness == LITTLE)
- ret = ioread8(i2c->base + reg);
+ ret = ioread32(i2c->base + reg);
else
- ret = ioread8(i2c->base + reg + 3);
+ ret = ioread32be(i2c->base + reg);
return ret;
}
-static inline void xiic_setreg16(struct xiic_i2c *i2c, int reg, u16 value)
+static inline void xiic_setreg8(struct xiic_i2c *i2c, int reg, u8 value)
{
+ if (i2c->force_32bit_access) {
+ xiic_setreg32(i2c, reg, value);
+ return;
+ }
+
if (i2c->endianness == LITTLE)
- iowrite16(value, i2c->base + reg);
+ iowrite8(value, i2c->base + reg);
else
- iowrite16be(value, i2c->base + reg + 2);
+ iowrite8(value, i2c->base + reg + 3);
}
-static inline void xiic_setreg32(struct xiic_i2c *i2c, int reg, int value)
+static inline u8 xiic_getreg8(struct xiic_i2c *i2c, int reg)
{
+ u8 ret;
+
+ if (i2c->force_32bit_access)
+ return xiic_getreg32(i2c, reg);
+
if (i2c->endianness == LITTLE)
- iowrite32(value, i2c->base + reg);
+ ret = ioread8(i2c->base + reg);
else
- iowrite32be(value, i2c->base + reg);
+ ret = ioread8(i2c->base + reg + 3);
+ return ret;
}
-static inline int xiic_getreg32(struct xiic_i2c *i2c, int reg)
+static inline void xiic_setreg16(struct xiic_i2c *i2c, int reg, u16 value)
{
- u32 ret;
+ if (i2c->force_32bit_access) {
+ xiic_setreg32(i2c, reg, value);
+ return;
+ }
if (i2c->endianness == LITTLE)
- ret = ioread32(i2c->base + reg);
+ iowrite16(value, i2c->base + reg);
else
- ret = ioread32be(i2c->base + reg);
- return ret;
+ iowrite16be(value, i2c->base + reg + 2);
}
static inline void xiic_irq_dis(struct xiic_i2c *i2c, u32 mask)
@@ -1480,6 +1498,8 @@ static int xiic_i2c_probe(struct platform_device *pdev)
return irq;
pdata = dev_get_platdata(dev);
+ if (pdata)
+ i2c->force_32bit_access = pdata->force_32bit_access;
/* hook up driver to tree */
platform_set_drvdata(pdev, i2c);
diff --git a/include/linux/platform_data/i2c-xiic.h b/include/linux/platform_data/i2c-xiic.h
index 2e3683c23..df1aeb42c 100644
--- a/include/linux/platform_data/i2c-xiic.h
+++ b/include/linux/platform_data/i2c-xiic.h
@@ -16,6 +16,8 @@
* @num_devices: Number of devices that shall be added when the driver
* is probed.
* @devices: The actuall devices to add.
+ * @force_32bit_access: Use aligned 32-bit accesses for all registers, including
+ * byte and halfword payloads, on bridges without subword I/O.
*
* This purpose of this platform data struct is to be able to provide a number
* of devices that should be added to the I2C bus. The reason is that sometimes
@@ -26,6 +28,7 @@
struct xiic_i2c_platform_data {
u8 num_devices;
struct i2c_board_info const *devices;
+ bool force_32bit_access;
};
#endif /* _LINUX_I2C_XIIC_H */
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next 2/3] i2c: xiic: add KUnit coverage for register access modes
[not found] <20261111041904.48916-1-ahmadexp@gmail.com>
2026-11-11 4:19 ` [PATCH net-next 1/3] i2c: xiic: allow platforms to require 32-bit register accesses Ahmad Byagowi
@ 2026-11-11 4:19 ` Ahmad Byagowi
2026-11-13 10:21 ` netdev-bot+sashiko
2026-11-11 4:19 ` [PATCH net-next 3/3] ptp: ocp: add WiWi Time Card production image support Ahmad Byagowi
2 siblings, 1 reply; 6+ messages in thread
From: Ahmad Byagowi @ 2026-11-11 4:19 UTC (permalink / raw)
To: netdev, vadim.fedorenko, andi.shyti
Cc: linux-i2c, Michal Simek, linux-kernel, linux-arm-kernel
Exercise the driver's private register accessors with memory-backed
registers instead of physical hardware. Cover native byte/halfword and
forced 32-bit accesses in both register byte orders, across 22 register
offsets. Check payload truncation, high-bit values and neighboring
sentinels. These tests do not validate physical bus transaction widths
or hardware interrupt behavior.
Include the tests in the driver translation unit so no accessors need
to become exported interfaces. Require built-in KUnit to avoid a
built-in driver depending on a modular test framework. The tests follow
the driver into either its built-in image or module.
The four parameterized cases passed in an isolated x86-64 QEMU boot
with networking disabled and no physical-device passthrough.
Tool-origin disclosure, as required by generated-content.rst: Codex was
used to implement this test suite, run the KUnit build/boot and draft
this changelog, in response to a request for upstream-quality testing.
Signed-off-by: Ahmad Byagowi <ahmadexp@gmail.com>
---
MAINTAINERS | 1 +
drivers/i2c/busses/Kconfig | 14 ++++
drivers/i2c/busses/i2c-xiic.c | 4 ++
drivers/i2c/busses/tests/i2c_xiic_kunit.c | 88 +++++++++++++++++++++++
4 files changed, 107 insertions(+)
create mode 100644 drivers/i2c/busses/tests/i2c_xiic_kunit.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 76fb13c87..eb5777316 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4017,6 +4017,7 @@ F: drivers/cpuidle/cpuidle-zynq.c
F: drivers/edac/synopsys_edac.c
F: drivers/i2c/busses/i2c-cadence.c
F: drivers/i2c/busses/i2c-xiic.c
+F: drivers/i2c/busses/tests/i2c_xiic_kunit.c
F: drivers/mmc/host/sdhci-of-arasan.c
N: zynq
N: xilinx
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 275aaa7f3..014281fa2 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -1322,6 +1322,20 @@ config I2C_XILINX
This driver can also be built as a module. If so, the module
will be called xilinx_i2c.
+config I2C_XILINX_KUNIT_TEST
+ bool "KUnit tests for Xilinx I2C register accesses" if !KUNIT_ALL_TESTS
+ depends on I2C_XILINX && KUNIT=y
+ default KUNIT_ALL_TESTS
+ help
+ Test the Xilinx I2C driver's register accessors with both byte orders
+ and with native-width or forced 32-bit accesses. KUnit is a kernel
+ unit testing framework. These tests use memory-backed registers and
+ do not require an I2C controller.
+
+ The tests are compiled into the driver to exercise its private
+ accessors, and follow the driver's built-in or module configuration.
+ If unsure, say N.
+
config I2C_XLP9XX
tristate "Cavium ThunderX2 I2C support"
depends on ARCH_THUNDER2 || COMPILE_TEST
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index d13cfb012..f2a77ca8d 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -1650,3 +1650,7 @@ MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("info@mocean-labs.com");
MODULE_DESCRIPTION("Xilinx I2C bus driver");
MODULE_LICENSE("GPL v2");
+
+#if IS_ENABLED(CONFIG_I2C_XILINX_KUNIT_TEST)
+#include "tests/i2c_xiic_kunit.c"
+#endif
diff --git a/drivers/i2c/busses/tests/i2c_xiic_kunit.c b/drivers/i2c/busses/tests/i2c_xiic_kunit.c
new file mode 100644
index 000000000..f8df88ca6
--- /dev/null
+++ b/drivers/i2c/busses/tests/i2c_xiic_kunit.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Included by i2c-xiic.c to exercise the driver's private accessors. */
+#include <kunit/test.h>
+
+struct xiic_access_param {
+ const char *name;
+ enum xiic_endian endianness;
+ bool force_32bit_access;
+};
+
+static const struct xiic_access_param xiic_access_params[] = {
+ { "native_little_endian", LITTLE, false },
+ { "native_big_endian", BIG, false },
+ { "word_little_endian", LITTLE, true },
+ { "word_big_endian", BIG, true },
+};
+
+KUNIT_ARRAY_PARAM_DESC(xiic_access, xiic_access_params, name);
+
+static void xiic_register_access(struct kunit *test)
+{
+ static const int offsets[] = {
+ XIIC_DGIER_OFFSET, XIIC_IISR_OFFSET, XIIC_IIER_OFFSET,
+ XIIC_RESETR_OFFSET, XIIC_CR_REG_OFFSET, XIIC_SR_REG_OFFSET,
+ XIIC_DTR_REG_OFFSET, XIIC_DRR_REG_OFFSET, XIIC_ADR_REG_OFFSET,
+ XIIC_TFO_REG_OFFSET, XIIC_RFO_REG_OFFSET, XIIC_TBA_REG_OFFSET,
+ XIIC_RFD_REG_OFFSET, XIIC_GPO_REG_OFFSET, XIIC_TSUSTA_REG_OFFSET,
+ XIIC_TSUSTO_REG_OFFSET, XIIC_THDSTA_REG_OFFSET,
+ XIIC_TSUDAT_REG_OFFSET, XIIC_TBUF_REG_OFFSET,
+ XIIC_THIGH_REG_OFFSET, XIIC_TLOW_REG_OFFSET,
+ XIIC_THDDAT_REG_OFFSET,
+ };
+ const struct xiic_access_param *param = test->param_value;
+ struct xiic_i2c *i2c;
+ u32 expected;
+ u8 *mem;
+ size_t i;
+ int reg;
+
+ i2c = kunit_kzalloc(test, sizeof(*i2c), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, i2c);
+ mem = kunit_kmalloc(test, 0x200, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, mem);
+ /* Aligned RAM stands in for MMIO. No hardware is accessed. */
+ i2c->base = (void __force __iomem *)(mem + sizeof(u32));
+ i2c->endianness = param->endianness;
+ i2c->force_32bit_access = param->force_32bit_access;
+
+ for (i = 0; i < ARRAY_SIZE(offsets); i++) {
+ reg = offsets[i];
+ memset(mem, 0xa5, 0x200);
+
+ xiic_setreg8(i2c, reg, 0xc0);
+ expected = param->force_32bit_access ? 0xc0 : 0xa5a5a5c0;
+ KUNIT_EXPECT_EQ(test, (u32)xiic_getreg32(i2c, reg), expected);
+ KUNIT_EXPECT_EQ(test, xiic_getreg8(i2c, reg), (u8)0xc0);
+
+ xiic_setreg16(i2c, reg, 0x03ff);
+ expected = param->force_32bit_access ? 0x03ff : 0xa5a503ff;
+ KUNIT_EXPECT_EQ(test, (u32)xiic_getreg32(i2c, reg), expected);
+ KUNIT_EXPECT_EQ(test, xiic_getreg8(i2c, reg), (u8)0xff);
+
+ xiic_setreg32(i2c, reg, 0x12345678);
+ KUNIT_EXPECT_EQ(test, (u32)xiic_getreg32(i2c, reg), 0x12345678U);
+ KUNIT_EXPECT_EQ(test, xiic_getreg8(i2c, reg), (u8)0x78);
+ KUNIT_EXPECT_EQ(test, mem[reg + sizeof(u32)],
+ (u8)(param->endianness == BIG ? 0x12 : 0x78));
+ KUNIT_EXPECT_EQ(test, mem[reg + sizeof(u32) + 3],
+ (u8)(param->endianness == BIG ? 0x78 : 0x12));
+ xiic_setreg32(i2c, reg, 0x89abcdefU);
+ KUNIT_EXPECT_EQ(test, (u32)xiic_getreg32(i2c, reg), 0x89abcdefU);
+ KUNIT_EXPECT_EQ(test, xiic_getreg8(i2c, reg), (u8)0xef);
+ KUNIT_EXPECT_EQ(test, mem[reg + sizeof(u32) - 1], (u8)0xa5);
+ KUNIT_EXPECT_EQ(test, mem[reg + 2 * sizeof(u32)], (u8)0xa5);
+ }
+}
+
+static struct kunit_case xiic_access_test_cases[] = {
+ KUNIT_CASE_PARAM(xiic_register_access, xiic_access_gen_params),
+ {}
+};
+
+static struct kunit_suite xiic_access_test_suite = {
+ .name = "i2c_xiic",
+ .test_cases = xiic_access_test_cases,
+};
+
+kunit_test_suite(xiic_access_test_suite);
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next 3/3] ptp: ocp: add WiWi Time Card production image support
[not found] <20261111041904.48916-1-ahmadexp@gmail.com>
2026-11-11 4:19 ` [PATCH net-next 1/3] i2c: xiic: allow platforms to require 32-bit register accesses Ahmad Byagowi
2026-11-11 4:19 ` [PATCH net-next 2/3] i2c: xiic: add KUnit coverage for register access modes Ahmad Byagowi
@ 2026-11-11 4:19 ` Ahmad Byagowi
2026-11-13 10:22 ` netdev-bot+sashiko
2 siblings, 1 reply; 6+ messages in thread
From: Ahmad Byagowi @ 2026-11-11 4:19 UTC (permalink / raw)
To: netdev, vadim.fedorenko, andi.shyti
Cc: linux-i2c, Jiri Pirko, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
Shuah Khan, Randy Dunlap, Richard Cochran, Andrew Lunn,
linux-doc, linux-kernel
Match WiWi 2163:1008, subsystem 10ee:0007, revision 2. The Xilinx
default subsystem ID is not a firmware-layout identifier. On the
verified 0x800f production image the register interface matches the
Celestica LitePCIe production image; the VID and flash header differ.
Translate a copy of each peripheral resource by 0x02000000 and its
interrupt input by 32. Use aligned 32-bit UART and XIIC register I/O.
Do not register the second GNSS UART: it exists but has no pin routing.
Leave non-WiWi resource tables and access modes unchanged.
CoreList is available via the configuration UART, not PCIe. Check the
PCI layout and the image ID at BAR0 + 0x02020000 before accessing the
remaining core signatures or initializing any peripherals. Keep exact
matches until a compatibility convention for later images is agreed.
The LitePCIe per-input gate at BAR0 + 0x1800 must enable SPI before
child probing: SPI NOR identification can wait for an interrupt. Open
only the UART, I2C and SPI inputs first. Enable timing inputs after
registering the PHC and its consumers. Skip unwired GNSS2, HWICAP and
the separate EEPROM/RGB I2C inputs 17/18: this series does not register
consumers for them. The highest owned vector is 48, not 50. Keep child
interrupts available through removal, then mask the gate before freeing
the vectors.
Reject WiWi devlink flash updates before looking up or modifying an MTD
device. The WiWi image uses a different flash header and the vendor's
programming path requires a modified spi-xilinx. A recognized JEDEC ID
does not establish a supported update path. Leave existing boards' flash
operations intact.
Source: Thomas Schaub, NetTimeLogic, 10 November 2026, email cited with
permission. He tested the Time Card repository driver at 1d49e31 with
the WiWi ID on a production card. His separate fix opens the gate before
child probe on that driver. This implementation uses a selective mask;
his test was not a test of this net-next series.
On a WiWi production card, the driver bound, allocated 64 MSI-X
vectors and registered the PHC, PPS device and three UARTs. The SPI
NOR and both at24 devices bound. The PHC advanced by 3.000429460 s
across three one-second sleeps, within the host monotonic brackets.
The clock reported UNSYNCED at probe; neither PPS lock nor UTC
accuracy was established.
Tool-origin disclosure: Codex helped analyze supplied hardware evidence,
implement and test the adaptation, and draft the changelog and docs.
The revision reconciles Thomas's findings with the tested layout and
does not treat a proposed image-ID convention as a vendor guarantee.
Signed-off-by: Ahmad Byagowi <ahmadexp@gmail.com>
---
Documentation/networking/devlink/ptp_ocp.rst | 35 +++-
drivers/ptp/ptp_ocp.c | 198 ++++++++++++++++++-
2 files changed, 226 insertions(+), 7 deletions(-)
diff --git a/Documentation/networking/devlink/ptp_ocp.rst b/Documentation/networking/devlink/ptp_ocp.rst
index f94b759d9..a81dc1136 100644
--- a/Documentation/networking/devlink/ptp_ocp.rst
+++ b/Documentation/networking/devlink/ptp_ocp.rst
@@ -54,7 +54,8 @@ selected with the component name.
- Description
* - (none)
- The card's own flash, written through the SPI controller the driver
- exposes. The card runs the new image after its next reset.
+ exposes. Not supported on WiWi. The card runs the new image after
+ its next reset.
* - ``fw.cpld``
- The configuration flash of the TAP CPLD on ADVA TimeCard X1 boards,
programmed over I2C with the MachXO3 in-system programming commands
@@ -73,3 +74,35 @@ with the standard devlink status notifications.
Example::
$ devlink dev flash pci/0000:02:00.0 file adva-cpld.bin component fw.cpld
+
+WiWi production firmware
+========================
+
+WiWi Time Cards with PCI ID ``2163:1008`` and subsystem ID ``10ee:0007``
+use the Celestica register layout behind a LitePCIe bridge. The driver
+currently supports revision 2 with production image ID ``0x0000800f``
+(reported as firmware version ``1.15``). It verifies the PCI layout and
+the image/core versions before initializing the card. Other firmware
+layouts are rejected, even if they use the same PCI ID.
+
+CoreList is readable over the configuration UART, not over PCIe. The
+driver reads the image ID at BAR0 offset ``0x02020000`` before reading the
+known core version registers. Neither a higher image ID nor the Xilinx
+default subsystem ID guarantees a compatible layout.
+
+The image uses the Celestica LitePCIe production map: add ``0x02000000``
+to the peripheral offsets and use aligned 32-bit MMIO. Interrupt input
+``n`` uses MSI-X vector ``n + 32``. The per-input enable mask is at BAR0
+offset ``0x1800``. The driver enables the SPI interrupt before probing
+the flash and defers timing interrupts until the PHC is ready. GNSS2 is
+instantiated but not wired to pins, so no second GNSS port is registered.
+The separate EEPROM and RGB I2C inputs (17 and 18) have no handlers in
+this driver and stay masked; these are distinct from its I2C input 7.
+
+WiWi firmware updates through ``devlink dev flash`` are not supported.
+The WiWi image has a different flash header from the Celestica image.
+The golden image at flash offset zero boots the update image via MultiBoot
+with watchdog fallback. The vendor's programming path requires a modified
+``spi-xilinx`` driver. Recognizing the SPI NOR does not validate that path
+or the image header. Successful clock registration does not establish
+GNSS synchronization or valid UTC.
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 625a85b2d..ee2242389 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -34,6 +34,23 @@
#define PCI_VENDOR_ID_CELESTICA 0x18d4
#define PCI_DEVICE_ID_CELESTICA_TIMECARD 0x1008
+#define PCI_VENDOR_ID_WIWI 0x2163
+#define PCI_DEVICE_ID_WIWI_TIMECARD 0x1008
+
+/* WiWi production firmware uses the Celestica map behind LitePCIe. */
+#define OCP_WIWI_MMIO_OFFSET 0x02000000
+#define OCP_WIWI_IRQ_OFFSET 32
+#define OCP_WIWI_MSI_ENABLE 0x1800
+/* Upper 32 bits: UARTs, I2C and SPI can interrupt during probe. */
+#define OCP_WIWI_PERIPHERAL_IRQS (BIT(3) | BIT(5) | BIT(7) | \
+ BIT(9) | BIT(10))
+/* PPS/TS0/TS1, TS2, GEN1-4 and TS3/TS4. */
+#define OCP_WIWI_TIMING_IRQS (GENMASK(2, 0) | BIT(6) | \
+ GENMASK(16, 11))
+/* Leave unwired GNSS2 (4), HWICAP (8) and EEPROM/RGB I2C (17/18) masked. */
+#define OCP_WIWI_IRQS (OCP_WIWI_PERIPHERAL_IRQS | \
+ OCP_WIWI_TIMING_IRQS)
+
#define PCI_VENDOR_ID_OROLIA 0x1ad7
#define PCI_DEVICE_ID_OROLIA_ARTCARD 0xa000
@@ -404,6 +421,8 @@ struct ptp_ocp {
struct delayed_work sync_work;
int id;
int n_irqs;
+ bool wiwi;
+ void __iomem *wiwi_msi;
struct ptp_ocp_serial_port port[__PORT_COUNT];
bool fw_loader;
u8 fw_tag;
@@ -1321,6 +1340,13 @@ static struct ocp_resource ocp_adva_x1_resource[] = {
static const struct pci_device_id ptp_ocp_pcidev_id[] = {
{ PCI_DEVICE_DATA(META, TIMECARD, &ocp_fb_resource) },
{ PCI_DEVICE_DATA(CELESTICA, TIMECARD, &ocp_fb_resource) },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_WIWI, PCI_DEVICE_ID_WIWI_TIMECARD,
+ PCI_VENDOR_ID_XILINX, 0x0007),
+ .class = PCI_CLASS_MEMORY_OTHER << 8,
+ .class_mask = 0xffffff,
+ .driver_data = (kernel_ulong_t)ocp_fb_resource,
+ },
{ PCI_DEVICE_DATA(OROLIA, ARTCARD, &ocp_art_resource) },
{ PCI_DEVICE_DATA(ADVA, TIMECARD, &ocp_adva_resource) },
{ PCI_DEVICE_DATA(ADVA, TIMECARD_X1, &ocp_adva_x1_resource) },
@@ -2173,6 +2199,11 @@ ptp_ocp_devlink_flash_update(struct devlink *devlink,
const char *msg;
int err;
+ if (bp->wiwi) {
+ NL_SET_ERR_MSG_MOD(extack, "WiWi flash updates are not supported");
+ return -EOPNOTSUPP;
+ }
+
if (params->component) {
if (!bp->has_cpld ||
strcmp(params->component, ADVA_CPLD_COMPONENT)) {
@@ -2331,20 +2362,29 @@ ptp_ocp_register_spi(struct ptp_ocp *bp, struct ocp_resource *r)
}
static struct platform_device *
-ptp_ocp_i2c_bus(struct pci_dev *pdev, struct ocp_resource *r, int id)
+ptp_ocp_i2c_bus(struct ptp_ocp *bp, struct ocp_resource *r, int id)
{
+ struct xiic_i2c_platform_data wiwi_data;
+ struct pci_dev *pdev = bp->pdev;
struct ptp_ocp_i2c_info *info;
struct resource res[2];
resource_size_t start;
+ const void *data;
info = r->extra;
+ data = info->data;
+ if (bp->wiwi) {
+ wiwi_data = *(struct xiic_i2c_platform_data *)info->data;
+ wiwi_data.force_32bit_access = true;
+ data = &wiwi_data;
+ }
start = pci_resource_start(pdev, 0) + r->offset;
res[0] = DEFINE_RES_MEM(start, r->size);
res[1] = DEFINE_RES_IRQ(pci_irq_vector(pdev, r->irq_vec));
return platform_device_register_resndata(&pdev->dev, info->name,
id, res, ARRAY_SIZE(res),
- info->data, info->data_size);
+ data, info->data_size);
}
static int
@@ -2369,7 +2409,7 @@ ptp_ocp_register_i2c(struct ptp_ocp *bp, struct ocp_resource *r)
sprintf(buf, "%s.%d", info->name, id);
devm_clk_hw_register_clkdev(&pdev->dev, clk, NULL, buf);
- p = ptp_ocp_i2c_bus(bp->pdev, r, id);
+ p = ptp_ocp_i2c_bus(bp, r, id);
if (IS_ERR(p))
return PTR_ERR(p);
@@ -2640,7 +2680,7 @@ ptp_ocp_serial_line(struct ptp_ocp *bp, struct ocp_resource *r)
*/
memset(&uart, 0, sizeof(uart));
uart.port.dev = &pdev->dev;
- uart.port.iotype = UPIO_MEM;
+ uart.port.iotype = bp->wiwi ? UPIO_MEM32 : UPIO_MEM;
uart.port.regshift = 2;
uart.port.mapbase = pci_resource_start(pdev, 0) + r->offset;
uart.port.irq = pci_irq_vector(pdev, r->irq_vec);
@@ -3109,7 +3149,26 @@ ptp_ocp_register_resources(struct ptp_ocp *bp, kernel_ulong_t driver_data)
int err = 0;
table = (struct ocp_resource *)driver_data;
- for (r = table; r->setup; r++) {
+ for (; table->setup; table++) {
+ struct ocp_resource translated = *table;
+
+ r = table;
+ if (bp->wiwi) {
+ /* GNSS2 is instantiated but not routed to FPGA pins. */
+ if (r->setup == ptp_ocp_register_serial &&
+ r->bp_offset == offsetof(struct ptp_ocp,
+ port[PORT_GNSS2]))
+ continue;
+ /* Never modify the resource table shared with other cards. */
+ if (translated.offset)
+ translated.offset += OCP_WIWI_MMIO_OFFSET;
+ if (r->setup == ptp_ocp_register_ext ||
+ r->setup == ptp_ocp_register_serial ||
+ r->setup == ptp_ocp_register_i2c ||
+ r->setup == ptp_ocp_register_spi)
+ translated.irq_vec += OCP_WIWI_IRQ_OFFSET;
+ r = &translated;
+ }
if (!ptp_ocp_allow_irq(bp, r))
continue;
err = r->setup(bp, r);
@@ -5786,6 +5845,12 @@ ptp_ocp_detach(struct ptp_ocp *bp)
platform_device_unregister(bp->i2c_ctrl);
if (bp->i2c_clk)
clk_hw_unregister_fixed_rate(bp->i2c_clk);
+ /* Child removal can need interrupts, notably SPI NOR reset. */
+ if (bp->wiwi_msi) {
+ iowrite32(0, bp->wiwi_msi);
+ iowrite32(0, bp->wiwi_msi + 4);
+ ioread32(bp->wiwi_msi);
+ }
if (bp->n_irqs)
pci_free_irq_vectors(bp->pdev);
mutex_destroy(&bp->cpld_lock);
@@ -5951,6 +6016,99 @@ ptp_ocp_sync_work(struct work_struct *work)
queue_delayed_work(system_power_efficient_wq, &bp->sync_work, HZ);
}
+/*
+ * CoreList is accessible via the configuration UART, not via PCIe.
+ * Check the image ID first: an unknown image need not provide any of
+ * the subsequent registers. Only the verified fixed layout is supported.
+ */
+static int ptp_ocp_wiwi_validate(struct pci_dev *pdev)
+{
+ static const struct {
+ u32 offset;
+ u32 version;
+ } versions[] = {
+ { 0x02020000, 0x0000800f }, /* image */
+ { 0x0300000c, 0x01040000 }, /* clock */
+ { 0x0301000c, 0x01030001 }, /* timestamp 0 */
+ { 0x0302000c, 0x01030001 }, /* timestamp 1 */
+ { 0x0306000c, 0x01030001 }, /* timestamp 2 */
+ { 0x0311000c, 0x01030001 }, /* timestamp 3 */
+ { 0x0312000c, 0x01030001 }, /* timestamp 4 */
+ { 0x030c000c, 0x01030001 }, /* PPS timestamp */
+ { 0x030d000c, 0x01030001 }, /* signal 1 */
+ { 0x030e000c, 0x01030001 }, /* signal 2 */
+ { 0x030f000c, 0x01030001 }, /* signal 3 */
+ { 0x0310000c, 0x01030001 }, /* signal 4 */
+ { 0x0303000c, 0x01030001 }, /* PPS generator */
+ { 0x0304000c, 0x01030002 }, /* PPS input */
+ { 0x0305000c, 0x02030002 }, /* ToD */
+ { 0x0307000c, 0x02000002 }, /* IRIG input */
+ { 0x0308000c, 0x02000001 }, /* IRIG output */
+ { 0x0309000c, 0x00010002 }, /* DCF input */
+ { 0x030a000c, 0x00010000 }, /* DCF output */
+ { 0x030b000c, 0x02000002 }, /* NMEA output */
+ };
+ u32 table, pba, value;
+ void __iomem *base;
+ unsigned int i;
+ int cap, err;
+
+ cap = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+ if (pdev->revision != 2 ||
+ !(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
+ pci_resource_len(pdev, 0) != 0x04000000 || !cap ||
+ pci_msix_vec_count(pdev) != 64 ||
+ pci_read_config_dword(pdev, cap + PCI_MSIX_TABLE, &table) ||
+ pci_read_config_dword(pdev, cap + PCI_MSIX_PBA, &pba) ||
+ table != 0x2000 || pba != 0x1808)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "Unsupported WiWi PCI layout\n");
+
+ err = pci_request_region(pdev, 0, KBUILD_MODNAME);
+ if (err)
+ return err;
+
+ base = pci_iomap(pdev, 0, 0);
+ if (!base) {
+ err = -ENOMEM;
+ goto out_release;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(versions); i++) {
+ value = ioread32(base + versions[i].offset);
+ if (value != versions[i].version) {
+ dev_err(&pdev->dev,
+ "Unsupported WiWi register version %#x at %#x\n",
+ value, versions[i].offset);
+ err = -ENODEV;
+ break;
+ }
+ }
+ pci_iounmap(pdev, base);
+out_release:
+ pci_release_region(pdev, 0);
+ return err;
+}
+
+static int ptp_ocp_wiwi_irq_init(struct ptp_ocp *bp)
+{
+ void __iomem *msi;
+
+ msi = __ptp_ocp_get_mem(bp, pci_resource_start(bp->pdev, 0) +
+ OCP_WIWI_MSI_ENABLE, 8);
+ if (IS_ERR(msi))
+ return PTR_ERR(msi);
+ bp->wiwi_msi = msi;
+
+ /* LiteX stores bits 63:32 before bits 31:0, as little-endian words. */
+ iowrite32(0, msi);
+ iowrite32(0, msi + 4);
+ if (ioread32(msi) || ioread32(msi + 4))
+ return -EIO;
+
+ return 0;
+}
+
static int
ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
@@ -5972,6 +6130,14 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
bp = devlink_priv(devlink);
+ bp->wiwi = pdev->vendor == PCI_VENDOR_ID_WIWI &&
+ pdev->device == PCI_DEVICE_ID_WIWI_TIMECARD;
+ if (bp->wiwi) {
+ /* No IRQ allocation, bus mastering or FPGA writes before this. */
+ err = ptp_ocp_wiwi_validate(pdev);
+ if (err)
+ goto out_disable;
+ }
err = ptp_ocp_device_init(bp, pdev);
if (err)
goto out_disable;
@@ -5987,18 +6153,33 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_DELAYED_WORK(&bp->sync_work, ptp_ocp_sync_work);
+ if (bp->wiwi) {
+ err = ptp_ocp_wiwi_irq_init(bp);
+ if (err)
+ goto out;
+ }
+
/* compat mode.
* Older FPGA firmware only returns 2 irq's.
* allow this - if not all of the IRQ's are returned, skip the
* extra devices and just register the clock.
*/
- err = pci_alloc_irq_vectors(pdev, 1, 17, PCI_IRQ_MSI | PCI_IRQ_MSIX);
+ if (bp->wiwi)
+ err = pci_alloc_irq_vectors(pdev, 49, 64, PCI_IRQ_MSIX);
+ else
+ err = pci_alloc_irq_vectors(pdev, 1, 17,
+ PCI_IRQ_MSI | PCI_IRQ_MSIX);
if (err < 0) {
dev_err(&pdev->dev, "alloc_irq_vectors err: %d\n", err);
goto out;
}
bp->n_irqs = err;
pci_set_master(pdev);
+ /* SPI NOR probe needs interrupts, but timestamp consumers are not ready. */
+ if (bp->wiwi_msi) {
+ iowrite32(OCP_WIWI_PERIPHERAL_IRQS, bp->wiwi_msi);
+ ioread32(bp->wiwi_msi);
+ }
err = ptp_ocp_register_resources(bp, id->driver_data);
if (err)
@@ -6047,6 +6228,11 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_dpll;
}
}
+ /* All handlers and the PHC are ready for timestamp interrupts. */
+ if (bp->wiwi_msi) {
+ iowrite32(OCP_WIWI_IRQS, bp->wiwi_msi);
+ ioread32(bp->wiwi_msi);
+ }
queue_delayed_work(system_power_efficient_wq, &bp->sync_work, HZ);
return 0;
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next 1/3] i2c: xiic: allow platforms to require 32-bit register accesses
2026-11-11 4:19 ` [PATCH net-next 1/3] i2c: xiic: allow platforms to require 32-bit register accesses Ahmad Byagowi
@ 2026-11-13 10:21 ` netdev-bot+sashiko
0 siblings, 0 replies; 6+ messages in thread
From: netdev-bot+sashiko @ 2026-11-13 10:21 UTC (permalink / raw)
To: ahmadexp
Cc: netdev, vadim.fedorenko, andi.shyti, linux-i2c, jiri, davem,
edumazet, kuba, pabeni, horms, corbet, skhan, rdunlap,
richardcochran, andrew+netdev, linux-doc, linux-kernel
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] Commit "i2c: xiic: allow platforms to require 32-bit register
accesses" adds xiic_i2c_platform_data::force_32bit_access and the…
--
i2c: xiic: allow platforms to require 32-bit register accesses
This commit adds a force_32bit_access flag to xiic_i2c_platform_data.
When the flag is set, xiic_setreg8(), xiic_getreg8() and xiic_setreg16()
perform aligned 32-bit accesses in the detected endianness. The target is
the LitePCIe bridge on the WiWi Time Card, which cannot handle subword
MMIO accesses.
> diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
> index ba560462d4513..d13cfb0127a20 100644
> --- a/drivers/i2c/busses/i2c-xiic.c
> +++ b/drivers/i2c/busses/i2c-xiic.c
[ ... ]
> @@ -1480,6 +1498,8 @@ static int xiic_i2c_probe(struct platform_device *pdev)
> return irq;
>
> pdata = dev_get_platdata(dev);
> + if (pdata)
> + i2c->force_32bit_access = pdata->force_32bit_access;
[Severity: Low]
This isn't a bug, but nothing in the tree sets force_32bit_access at this
commit. The ptp_ocp xiic tables and timberdale both leave it false, so the
new paths in xiic_setreg8(), xiic_getreg8() and xiic_setreg16() can't be
reached yet.
The later patch in this series, "ptp: ocp: add WiWi Time Card production
image support", adds the user in ptp_ocp_i2c_bus():
if (bp->wiwi) {
wiwi_data = *(struct xiic_i2c_platform_data *)info->data;
wiwi_data.force_32bit_access = true;
data = &wiwi_data;
}
That copy is then passed to platform_device_register_resndata(), so the
flag has an in-tree user once the series is applied.
Could the commit message say that the user of this flag comes in that
follow-up patch?
>
> /* hook up driver to tree */
> platform_set_drvdata(pdev, i2c);
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261111041904.48916-1-ahmadexp%40gmail.com
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next 2/3] i2c: xiic: add KUnit coverage for register access modes
2026-11-11 4:19 ` [PATCH net-next 2/3] i2c: xiic: add KUnit coverage for register access modes Ahmad Byagowi
@ 2026-11-13 10:21 ` netdev-bot+sashiko
0 siblings, 0 replies; 6+ messages in thread
From: netdev-bot+sashiko @ 2026-11-13 10:21 UTC (permalink / raw)
To: ahmadexp
Cc: netdev, vadim.fedorenko, andi.shyti, linux-i2c, jiri, davem,
edumazet, kuba, pabeni, horms, corbet, skhan, rdunlap,
richardcochran, andrew+netdev, linux-doc, linux-kernel
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 0 · Medium: 1 · Low: 0
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [Medium] The new KUnit test xiic_register_access() in
drivers/i2c/busses/tests/i2c_xiic_kunit.c takes a kunit_kmalloc() RAM…
--
i2c: xiic: add KUnit coverage for register access modes
This adds a KUnit suite that is included in the i2c-xiic.c translation
unit. It drives the private xiic_setreg*() and xiic_getreg*() accessors
against a kmalloc'd buffer that stands in for MMIO. It covers native and
forced 32-bit accesses in both byte orders across 22 register offsets. The
new I2C_XILINX_KUNIT_TEST symbol enables it and defaults to
KUNIT_ALL_TESTS.
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index 275aaa7f35833..014281fa2be5c 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -1322,6 +1322,20 @@ config I2C_XILINX
> This driver can also be built as a module. If so, the module
> will be called xilinx_i2c.
>
> +config I2C_XILINX_KUNIT_TEST
> + bool "KUnit tests for Xilinx I2C register accesses" if !KUNIT_ALL_TESTS
> + depends on I2C_XILINX && KUNIT=y
> + default KUNIT_ALL_TESTS
> + help
> + Test the Xilinx I2C driver's register accessors with both byte orders
> + and with native-width or forced 32-bit accesses. KUnit is a kernel
> + unit testing framework. These tests use memory-backed registers and
> + do not require an I2C controller.
[ ... ]
> diff --git a/drivers/i2c/busses/tests/i2c_xiic_kunit.c b/drivers/i2c/busses/tests/i2c_xiic_kunit.c
> new file mode 100644
> index 0000000000000..f8df88ca65124
> --- /dev/null
> +++ b/drivers/i2c/busses/tests/i2c_xiic_kunit.c
> @@ -0,0 +1,88 @@
[ ... ]
> + i2c = kunit_kzalloc(test, sizeof(*i2c), GFP_KERNEL);
> + KUNIT_ASSERT_NOT_NULL(test, i2c);
> + mem = kunit_kmalloc(test, 0x200, GFP_KERNEL);
> + KUNIT_ASSERT_NOT_NULL(test, mem);
> + /* Aligned RAM stands in for MMIO. No hardware is accessed. */
> + i2c->base = (void __force __iomem *)(mem + sizeof(u32));
[Severity: Medium]
Is it safe to pass a kmalloc'd buffer to ioread*() and iowrite*() on every
architecture that can build this test?
This works where the MMIO accessors are plain loads and stores to the
virtual address, as on the x86-64 setup the changelog says was tested.
However, I2C_XILINX_KUNIT_TEST only has "depends on I2C_XILINX && KUNIT=y"
with "default KUNIT_ALL_TESTS". I2C_XILINX only needs HAS_IOMEM. That means
the suite is built and run automatically on architectures where those
accessors don't touch RAM.
On sparc64, arch/sparc/include/asm/io_64.h implements readb()/readl()/
writeb()/writel(), and __raw_readl()/__raw_writel() for the be variants,
with lduba/lduwa/stba/stwa and ASI_PHYS_BYPASS_EC_E_L:
__asm__ __volatile__("lduwa\t[%1] %2, %0\t/* pci_readl */" ...
That uses the slab virtual address as a physical address. Could this trap?
Could it instead write 0xc0, 0x03ff, 0x12345678 and 0x89abcdef to an
unrelated physical location?
On s390 with CONFIG_PCI, __raw_readl() and friends map to zpci_read_u32()
and the other zpci helpers. On the non-MIO path, zpci_load_fh() and
zpci_store_fh() do:
struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)];
using bits from the fake address. They then issue a real PCI load or store
with whatever function handle and BAR they find there. On the MIO path,
PCI load/store instructions are issued against a RAM address.
On UML with INDIRECT_IOMEM, the chain is KUNIT_UML_PCI -> UML_PCI ->
UML_IOMEM_EMULATION -> INDIRECT_IOMEM. The default
tools/testing/kunit/configs/arch_uml.config sets CONFIG_KUNIT_UML_PCI=y.
For a slab address, get_area() in lib/logic_iomem.c hits:
if (WARN_ON((a & IOREMAP_MASK) != IOREMAP_BIAS))
return NULL;
Nothing selects INDIRECT_IOMEM_FALLBACK. So the fallback path WARNs again,
reads return ~0 and writes are dropped.
Wouldn't that give two WARN splats per access, across all 4 parameters and
22 offsets? It would also fail every expectation, and panic if
panic_on_warn is set.
These three statements don't hold on those architectures:
- the Kconfig help: "These tests use memory-backed registers and do not
require an I2C controller"
- the comment above: "No hardware is accessed."
- the changelog: "memory-backed registers instead of physical hardware"
Should I2C_XILINX_KUNIT_TEST get an architecture restriction, for example
excluding SPARC64, S390 and INDIRECT_IOMEM, or using an allow-list? Or
could the test go through an indirection it can mock, rather than passing
RAM to the MMIO accessors?
> + i2c->endianness = param->endianness;
> + i2c->force_32bit_access = param->force_32bit_access;
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261111041904.48916-1-ahmadexp%40gmail.com
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next 3/3] ptp: ocp: add WiWi Time Card production image support
2026-11-11 4:19 ` [PATCH net-next 3/3] ptp: ocp: add WiWi Time Card production image support Ahmad Byagowi
@ 2026-11-13 10:22 ` netdev-bot+sashiko
0 siblings, 0 replies; 6+ messages in thread
From: netdev-bot+sashiko @ 2026-11-13 10:22 UTC (permalink / raw)
To: ahmadexp
Cc: netdev, vadim.fedorenko, andi.shyti, linux-i2c, jiri, davem,
edumazet, kuba, pabeni, horms, corbet, skhan, rdunlap,
richardcochran, andrew+netdev, linux-doc, linux-kernel
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] The commit message says the WiWi register interface 'matches the
Celestica LitePCIe production image; the VID and flash header differ'.
- [Low] On WiWi, ptp_ocp_probe() makes the PHC visible to userspace at
ptp_clock_register() (drivers/ptp/ptp_ocp.c:6188).
--
ptp: ocp: add WiWi Time Card production image support
This adds a PCI ID match for the WiWi 2163:1008 Time Card. Before the
card is initialized, the driver checks its PCI layout and core versions.
The ocp_fb_resource entries are translated by 0x02000000 and their
interrupt inputs by 32. UART and XIIC use 32-bit accesses, and a LitePCIe
per-input interrupt gate at BAR0 + 0x1800 is managed during probe and
removal. devlink flash updates are rejected on WiWi cards.
> diff --git a/Documentation/networking/devlink/ptp_ocp.rst b/Documentation/networking/devlink/ptp_ocp.rst
> index f94b759d9cd65..a81dc113688b6 100644
> --- a/Documentation/networking/devlink/ptp_ocp.rst
> +++ b/Documentation/networking/devlink/ptp_ocp.rst
[ ... ]
> @@ -73,3 +74,35 @@ with the standard devlink status notifications.
> Example::
>
> $ devlink dev flash pci/0000:02:00.0 file adva-cpld.bin component fw.cpld
> +
> +WiWi production firmware
> +========================
> +
> +WiWi Time Cards with PCI ID ``2163:1008`` and subsystem ID ``10ee:0007``
> +use the Celestica register layout behind a LitePCIe bridge. The driver
[ ... ]
> +The image uses the Celestica LitePCIe production map: add ``0x02000000``
> +to the peripheral offsets and use aligned 32-bit MMIO. Interrupt input
> +``n`` uses MSI-X vector ``n + 32``. The per-input enable mask is at BAR0
> +offset ``0x1800``. The driver enables the SPI interrupt before probing
[Severity: Low]
How does this fit with the existing Celestica entry in ptp_ocp_pcidev_id?
The commit message says "the register interface matches the Celestica
LitePCIe production image; the VID and flash header differ". This section
calls the layout "the Celestica LitePCIe production map".
The Celestica entry binds the same table but gets none of this handling:
{ PCI_DEVICE_DATA(CELESTICA, TIMECARD, &ocp_fb_resource) },
For 18d4:1008, bp->wiwi is false, so:
- ptp_ocp_register_resources() applies neither the 0x02000000 offset nor
the +32 vector translation.
- ptp_ocp_serial_line() keeps UPIO_MEM.
- probe allocates 1..17 MSI/MSI-X vectors.
- the 0x1800 gate is never opened.
The earlier xiic patch in this series says the LitePCIe bridge raises a
fatal machine check on subword MMIO.
If a card with the Celestica PCI ID can run the LitePCIe production
image, would it need the same handling?
If it can't, could the changelog and this section say that the existing
Celestica entry targets a different image? That would stop the "Celestica
LitePCIe" wording from suggesting otherwise. The line "Leave non-WiWi
resource tables and access modes unchanged" only says that code is
untouched.
> diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
> index 625a85b2dc7e5..ee22423890230 100644
> --- a/drivers/ptp/ptp_ocp.c
> +++ b/drivers/ptp/ptp_ocp.c
[ ... ]
> @@ -6047,6 +6228,11 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> goto out_dpll;
> }
> }
> + /* All handlers and the PHC are ready for timestamp interrupts. */
> + if (bp->wiwi_msi) {
> + iowrite32(OCP_WIWI_IRQS, bp->wiwi_msi);
> + ioread32(bp->wiwi_msi);
> + }
> queue_delayed_work(system_power_efficient_wq, &bp->sync_work, HZ);
[Severity: Low]
Can a timestamper stop delivering interrupts if it is armed before this
gate write?
Earlier in ptp_ocp_probe(), this call makes the PHC visible to userspace:
bp->ptp = ptp_clock_register(&bp->ptp_info, &pdev->dev);
The timing inputs (0-2, 6, 11-16) are only opened here. That happens
after ptp_ocp_complete(), devlink_register() and the DPLL device and pin
registration.
During that window, userspace can arm a timing core:
- PTP_EXTTS_REQUEST or PTP_ENABLE_PPS on /dev/ptpN
- enabling a signal generator through sysfs
Each of these goes through ptp_ocp_ts_enable(). If an event arrives
while the gate is still closed, it sets the core's sticky interrupt
status. Only the ack in ptp_ocp_ts_irq() clears it:
iowrite32(1, ®->intr); /* write 1 to ack */
Whether that event gets delivered once the gate opens depends on how the
LitePCIe enable mask handles inputs that are already asserted. The patch
doesn't document that behaviour.
If the gate only detects edges, would that channel deliver no more
MSI-X interrupts until userspace disables and re-enables it?
Would acknowledging the ts/signal intr status after opening the timing
gate make the probe sequence independent of how the gate behaves?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261111041904.48916-1-ahmadexp%40gmail.com
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-11-13 10:22 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <20261111041904.48916-1-ahmadexp@gmail.com>
2026-11-11 4:19 ` [PATCH net-next 1/3] i2c: xiic: allow platforms to require 32-bit register accesses Ahmad Byagowi
2026-11-13 10:21 ` netdev-bot+sashiko
2026-11-11 4:19 ` [PATCH net-next 2/3] i2c: xiic: add KUnit coverage for register access modes Ahmad Byagowi
2026-11-13 10:21 ` netdev-bot+sashiko
2026-11-11 4:19 ` [PATCH net-next 3/3] ptp: ocp: add WiWi Time Card production image support Ahmad Byagowi
2026-11-13 10:22 ` netdev-bot+sashiko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®