* Re: [PATCH v2 2/2] arm64: dts: qcom: kaanapali: fix traceNoC probe issue
From: Jie Gan @ 2026-06-25 1:01 UTC (permalink / raw)
To: Leo Yan, Suzuki K Poulose
Cc: Konrad Dybcio, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Tingwei Zhang, Jingyi Wang,
Abel Vesa, Mike Leach, James Clark, Yuanfang Zhang, linux-arm-msm,
devicetree, linux-kernel, coresight, linux-arm-kernel
In-Reply-To: <20260624151610.GC575984@e132581.arm.com>
On 6/24/2026 11:16 PM, Leo Yan wrote:
> On Wed, Jun 24, 2026 at 11:08:32PM +0800, Jie Gan wrote:
>
> [...]
>
>>> Why does it fail ? power management ? hw broken ? Is it really AMBA or
>>> do you pretend that to be an AMBA device by faking the CID/PID?
>>
>> The CID reads as 0 from the register, which I suspect is a hardware design
>> issue. I have not yet confirmed this with the hardware team. As a
>> workaround, I provided a fake periphid via a DT property to bypass
>> amba_read_periphid.
>>
>>
>> Leo commented in other thread:
>>>> tnoc.c registers both an AMBA driver and a platform driver. Shouldn't >>it
>>>> be registered as a platform device instead?
>>
>> The platform driver is intended for the interconnect TraceNoC device and is
>> not designed to allocate an ATID. The issue is that the TPDM device borrows
>> the ATID from the TraceNoC device, resulting in the ATID always being 0 when
>> associated with an interconnect NoC device.
>>
>> However, I believe it is acceptable to allocate an ATID for the itNoC device
>> and the issue can be fixed with this way.
>
> I think so.
Hi Suzuki/Leo
Which solution do you prefer to address the issue?
The interconnect traceNoC platform driver is intended for the itnoc
device, implying that no TPDM devices are connected to it. So, if I
modify it to allocate an ATID, I think it would be better to rename the
“itnoc” node accordingly? Or it's ok to leave it as-is?
BTW, the traceNoC device definitely is an AMBA device with CID/PID
registers.
Thanks,
Jie
^ permalink raw reply
* Re: [PATCH v6 1/2] dt-bindings: bridge: Add Lontium LT9611C(EX/UXD) MIPI DSI to HDMI driver
From: Sunyun Yang @ 2026-06-25 0:52 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: robh, krzk+dt, conor+dt, andrzej.hajda, neil.armstrong,
dmitry.baryshkov, maarten.lankhorst, rfoss, mripard,
Laurent.pinchart, tzimmermann, jonas, jernej.skrabec, devicetree,
dri-devel, linux-kernel, xmzhu, xmzhu, rlyu, xbpeng
In-Reply-To: <495f0dc3-b5ee-429e-bc60-78b13bcb42c3@kernel.org>
Krzysztof Kozlowski <krzk@kernel.org> 于2026年6月24日周三 22:05写道:
>
> On 11/05/2026 05:28, Sunyun Yang wrote:
> > <syyang@lontium.com> 于2026年5月8日周五 22:25写道:
> >>
> >> From: Sunyun Yang <syyang@lontium.com>
> >>
> >> LT9611C(EX/UXD) is an I2C-controlled chip that Receiver signal/dual port
> >> mipi dsi and output hdmi, differences in hardware features:
> >> - LT9611C: supports 1-port mipi dsi to hdmi 1.4
> >> - LT9611EX: supports 2-port mipi dsi to hdmi 1.4
> >> - LT9611UXD: supports 2-port mipi dsi to hdmi 1.4/2.0
> >>
> >> Signed-off-by: Sunyun Yang <syyang@lontium.com>
> >> ---
> >> .../bindings/display/bridge/lontium,lt9611.yaml | 8 ++++++--
> >> 1 file changed, 6 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml
> >> index 429a06057ae8..e0821a63d9d7 100644
> >> --- a/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml
> >> +++ b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml
> >> @@ -4,19 +4,23 @@
> >> $id: http://devicetree.org/schemas/display/bridge/lontium,lt9611.yaml#
> >> $schema: http://devicetree.org/meta-schemas/core.yaml#
> >>
> >> -title: Lontium LT9611(UXC) 2 Port MIPI to HDMI Bridge
> >> +title: Lontium LT9611(UXC/C/EX/UXD) 2 Port MIPI DSI to HDMI Bridge
> >>
> >> maintainers:
> >> - Vinod Koul <vkoul@kernel.org>
> >>
> >> description: |
> >> - The LT9611 and LT9611UXC are bridge devices which convert DSI to HDMI
> >> + The LT9611、LT9611UXC、LT9611C、LT9611EX and LT9611UXD
> >> + are bridge devices which convert DSI to HDMI
> >>
> >> properties:
> >> compatible:
> >> enum:
> >> - lontium,lt9611
> >> + - lontium,lt9611c
> >> + - lontium,lt9611ex
> >> - lontium,lt9611uxc
> >> + - lontium,lt9611uxd
> >>
> >> reg:
> >> maxItems: 1
> >> --
> >
> > Gentle ping.
> > Thanks.
>
> Except mess with threading, your patchset does not build, when applied
> on next-20260618.
>
> What is the base of this?
>
Thanks for testing my patchset on next-20260618.
The base of this series is v7.0.
> Best regards,
> Krzysztof
^ permalink raw reply
* RE: [PATCH 2/3] dt-bindings: hwmon: pmbus: Support for onsemi's FD5121
From: Selvamani Rajagopal @ 2026-06-25 0:35 UTC (permalink / raw)
To: Guenter Roeck, Conor Dooley
Cc: Jonathan Corbet, Shuah Khan, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-hwmon@vger.kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
devicetree@vger.kernel.org
In-Reply-To: <eed3e19b-8cc7-4aef-b058-b2242c94c940@roeck-us.net>
> -----Original Message-----
> From: Guenter Roeck <groeck7@gmail.com> On Behalf Of Guenter Roeck
> Subject: Re: [PATCH 2/3] dt-bindings: hwmon: pmbus: Support for onsemi's FD5121
>
>
> One of the problems here is that the chip datasheet is not public,
Agree on both points. No datasheets on our website. And chips not available through distributors. Little
early in the process. I am working with our product team to see how to move forward. So, there will be some
delay in giving next patch. Thanks for your feedback. I have all the information to send a cleaner, hopefully
acceptable patch,
> so we can not verify what this actually is. The only available
> public document appears to be the "onsemi FD512x Ax Digital Controller
> User Manual" which describes the chip as follows.
>
> "The FD512x Digital Controller is a programmable device designed
> for machine vendors to configure their equipment at the factory."
>
> That really does not explain anything at all, and actually looks like
> an AI generated summary with the AI not understanding what it is talking
> about. According to the onsemi web page, the chip does not exist,
> and it appears that it is not available to buy from any distributors
> either.
>
> Guenter
>
^ permalink raw reply
* Re: [PATCH 2/3] dt-bindings: hwmon: pmbus: Support for onsemi's FD5121
From: Guenter Roeck @ 2026-06-24 23:05 UTC (permalink / raw)
To: Selvamani Rajagopal, Conor Dooley
Cc: Jonathan Corbet, Shuah Khan, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-hwmon@vger.kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
devicetree@vger.kernel.org
In-Reply-To: <CYYPR02MB9828EECB3F6AFDD2A7BD3E9B83ED2@CYYPR02MB9828.namprd02.prod.outlook.com>
On 6/24/26 15:36, Selvamani Rajagopal wrote:
>> -----Original Message-----
>> From: Conor Dooley <conor@kernel.org>
>> Subject: Re: [PATCH 2/3] dt-bindings: hwmon: pmbus: Support for onsemi's FD5121
>>
>>
>> My point is that what's actually being controlled is missing. Maybe it
>> is obvious to you, but it is not to me. Your nodename in your example is
>
>
> You are right. This chip may not be a "controller" in the traditional sense as it doesn't control anything.
> We can change node naming to sensor or regulator so that it aligns with the convention.
>
One of the problems here is that the chip datasheet is not public,
so we can not verify what this actually is. The only available
public document appears to be the "onsemi FD512x Ax Digital Controller
User Manual" which describes the chip as follows.
"The FD512x Digital Controller is a programmable device designed
for machine vendors to configure their equipment at the factory."
That really does not explain anything at all, and actually looks like
an AI generated summary with the AI not understanding what it is talking
about. According to the onsemi web page, the chip does not exist,
and it appears that it is not available to buy from any distributors
either.
Guenter
>
>>> + fd5121@50 {
>> which doesn't comply with node naming requirements and I wanted to come
>> up with a suggestion for what it should be.
>> I am assuming that its power or voltage that you're controlling so
>> either it should be hwmon@ or regulator@.
>>
>
^ permalink raw reply
* Re: [PATCH v4 03/11] HID: spi-hid: add transport driver skeleton for HID over SPI bus
From: Jingyuan Liang @ 2026-06-24 22:41 UTC (permalink / raw)
To: sashiko-reviews; +Cc: robh, conor+dt, devicetree, dmitry.torokhov, linux-input
In-Reply-To: <20260609045604.44FE71F00893@smtp.kernel.org>
On Mon, Jun 8, 2026 at 9:56 PM <sashiko-bot@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] Embedded arrays `read_approval_header` and `read_approval_body` are used for SPI DMA transfers without cacheline alignment, risking memory corruption.
> - [Medium] Unchecked return values of reset operations in `spi_hid_dev_init` and `spi_hid_resume`
> --
>
> commit ea35a3a23739acaca367a8d250ef25c96d22df36
> Author: Angela Czubak <acz@semihalf.com>
>
> HID: spi-hid: add transport driver skeleton for HID over SPI bus
>
> Create spi-hid folder and add Kconfig and Makefile for spi-hid driver.
> Add basic device structure, definitions, and probe/remove functions.
>
> > diff --git a/drivers/hid/spi-hid/spi-hid-core.c b/drivers/hid/spi-hid/spi-hid-core.c
> > new file mode 100644
> > index 0000000000000..02a7608c4b882
> > --- /dev/null
> > +++ b/drivers/hid/spi-hid/spi-hid-core.c
> > @@ -0,0 +1,213 @@
>
> [ ... ]
>
> > +/* Driver context */
> > +struct spi_hid {
> > + struct spi_device *spi; /* spi device. */
> > + struct hid_device *hid; /* pointer to corresponding HID dev. */
> > +
> > + struct spihid_ops *ops;
> > + struct spi_hid_conf *conf;
> > +
> > + enum hidspi_power_state power_state;
> > +
> > + u32 regulator_error_count;
> > + int regulator_last_error;
> > + u32 bus_error_count;
> > + int bus_last_error;
> > + u32 dir_count; /* device initiated reset count. */
> > +};
>
> [Severity: High]
> Does embedding the read_approval_header and read_approval_body arrays directly
> in this struct for SPI DMA transfers risk memory corruption?
>
> When these buffers are passed as tx_buf to spi_sync() (e.g. in
> spi_hid_input_sync()), they lack the ____cacheline_aligned directive. On
> architectures with non-coherent DMA, cache maintenance operations could
> encompass adjacent struct members.
>
> Concurrent CPU writes to those adjacent members during the DMA mapping window
> will be destroyed, leading to memory corruption.
>
> Should these buffers be cacheline aligned, or dynamically allocated?
read_approval_header and read_approval_body arrays are not in this patch.
>
> [ ... ]
>
> > +int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops,
> > + struct spi_hid_conf *conf)
> > +{
>
> [ ... ]
>
> > + /*
> > + * At the end of probe we initialize the device:
> > + * 0) assert reset, bias the interrupt line
> > + * 1) sleep minimal reset delay
> > + * 2) request IRQ
> > + * 3) power up the device
> > + * 4) deassert reset (high)
> > + * After this we expect an IRQ with a reset response.
> > + */
> > +
> > + shid->ops->assert_reset(shid->ops);
> > +
> > + shid->ops->sleep_minimal_reset_delay(shid->ops);
>
> [ ... ]
>
> > + error = shid->ops->power_up(shid->ops);
> > + if (error) {
> > + dev_err(dev, "%s: could not power up\n", __func__);
> > + return error;
> > + }
> > +
> > + shid->ops->deassert_reset(shid->ops);
>
> [Severity: Medium]
> Can hardware reset failures be masked here?
>
> The assert_reset and deassert_reset callbacks return integer error codes.
> However, their return values are ignored in spi_hid_core_probe() (as well as
> resume paths).
>
> If deassert_reset() fails, the device may remain in reset, causing the driver
> to hang waiting for a reset response IRQ that will never arrive.
>
> Should these return values be checked and handled?
>
> > +
> > + dev_dbg(dev, "%s: d3 -> %s\n", __func__,
> > + spi_hid_power_mode_string(shid->power_state));
> > +
> > + return 0;
> > +}
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260609-send-upstream-v4-0-b843d5e6ced3@chromium.org?part=3
^ permalink raw reply
* RE: [PATCH 2/3] dt-bindings: hwmon: pmbus: Support for onsemi's FD5121
From: Selvamani Rajagopal @ 2026-06-24 22:36 UTC (permalink / raw)
To: Conor Dooley
Cc: Guenter Roeck, Jonathan Corbet, Shuah Khan, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-hwmon@vger.kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
devicetree@vger.kernel.org
In-Reply-To: <20260623-scared-judgingly-7efc1c188670@spud>
> -----Original Message-----
> From: Conor Dooley <conor@kernel.org>
> Subject: Re: [PATCH 2/3] dt-bindings: hwmon: pmbus: Support for onsemi's FD5121
>
>
> My point is that what's actually being controlled is missing. Maybe it
> is obvious to you, but it is not to me. Your nodename in your example is
You are right. This chip may not be a "controller" in the traditional sense as it doesn't control anything.
We can change node naming to sensor or regulator so that it aligns with the convention.
> > + fd5121@50 {
> which doesn't comply with node naming requirements and I wanted to come
> up with a suggestion for what it should be.
> I am assuming that its power or voltage that you're controlling so
> either it should be hwmon@ or regulator@.
>
^ permalink raw reply
* Re: [PATCH v3 0/2] regulator: qcom-rpmh: Add off-on-delay support
From: Kamal Wadhwa @ 2026-06-24 22:16 UTC (permalink / raw)
To: Konrad Dybcio
Cc: Saikiran, broonie, monish.chunara, jishnu.prakash, nitin.rawat,
Bjorn Andersson, lgirdwood, andersson, konrad.dybcio,
linux-arm-msm, linux-kernel, robh, krzk+dt, devicetree
In-Reply-To: <06a264d0-6a14-4b71-b783-82b771f04411@oss.qualcomm.com>
On Tue, Jun 16, 2026 at 01:48:50PM +0200, Konrad Dybcio wrote:
> On 5/15/26 1:16 PM, Kamal Wadhwa wrote:
> > On Wed, Jan 28, 2026 at 12:32:09AM +0530, Saikiran wrote:
> >> This series adds support for the standard `regulator-off-on-delay-us`
> >> property to the Qualcomm RPMh regulator driver and updates the
> >> corresponding Device Tree bindings.
> >>
> >> Motivation:
> >> On the Lenovo Yoga Slim 7x (Snapdragon X Elite), the camera regulators
> >> (LDO1, LDO3, LDO7) have large bulk capacitors and rely on passive discharge.
> >> When these regulators are disabled, the voltage decays very slowly. If
> >> re-enabled too quickly, the sensor experiences a brownout and fails to
> >> initialize.
> >>
> >> Verification:
> >> I verified that the core `drivers/regulator/of_regulator.c` does not
> >> currently parse `regulator-off-on-delay-us` in `of_get_regulation_constraints()`.
> >> Therefore, the driver must parse this property explicitly and populate
> >> `rdesc->off_on_delay` so the regulator core can enforce the constraint.
> >>
> >> Changes in v3:
> >> - Added Patch 1/2: Update DT bindings to allow `regulator-off-on-delay-us`
> >> for `qcom,rpmh-regulator` (Requested by Mark Brown).
> >> - Updated Patch 2/2: Refined commit message to explicitly mention the
> >> passive discharge and bulk capacitor mechanism on the Yoga Slim 7x
> >> (Requested by Mark Brown).
> >>
> >> Changes in v2:
> >> - Moved the motivation/context from the cover letter into the commit
> >> message of the driver patch.
> >>
> >> Saikiran (2):
> >> dt-bindings: regulator: qcom,rpmh: Allow regulator-off-on-delay-us
> >> regulator: qcom-rpmh: Add support for regulator-off-on-delay-us
> >
> > Hi Mark, Bjorn, Konrad and all,
> >
> > We have another UFS issue on QCS8300 RB4 EVK, where it seems this patch is
> > helping.
> >
> > Issue is seen 2/10 reboots and it happens in the UFS probe defer path:
> >
> > 1. UFS probe takes regulator handle for VCC(vreg_l8a) of UFS host controller.
> > 2. UFS probe enables the regulator
> > 3. UFS probe defers (due to some other dependency un-related to regulator)
> > 4. UFS regulator disabled on probe exit
> > 5. UFS re-attempts probe and re-enables the regulator
> > 6. UFS init sequence runs -> UFS NOP OUT command failed (no shell)
> >
> > Issue Log:
> >
> > [ 6.583836] ufshcd-qcom 1d84000.ufs: ufshcd_verify_dev_init: NOP OUT failed -11
> > [ 6.592780] ufshcd-qcom 1d84000.ufs: ufshcd_async_scan failed: -11
> >
> > NOTE
> > - Issue is not seen in first probe attempt, because UFS regulators are left ON
> > from bootloader, which gives enough time between rail turn ON and UFS init
> > sequence start. However in issue case, it seems re-probe is happening too
> > fast, which causes init sequence to fail and UFS brownouts (similar to camera
> > sensor case)
> >
> > - Also, we compared this board with other RBxx EVK boards for UFS rail, it
> > seems that this board has more caps on the VCC regulator, as the board is
> > designed to have both EMMC and UFS, and we have DT option to pick one of them.
> >
> > So for EMMC those extra caps were added and they are impacting rampup on VCC.
> >
> > Since this is not entirely a UFS part issue, but a board design constraint, it
> > seems better if we handle this in the regulator side itself, as adding it in the
> > UFS driver may not be acceptable from UFS reviewers.
> >
> > Please share your opinion, if this seems to be good reason to accept this patch?
>
> Is that board in production already, or is that something that can be fixed?
yes, it cannot be fixed in HW, as the board is already in production.
>
> Konrad
^ permalink raw reply
* Re: [PATCH v3 2/2] remoteproc: add AMD BRAM-based remote processor driver
From: Ben Levinsky @ 2026-06-24 22:01 UTC (permalink / raw)
To: Mathieu Poirier
Cc: Ben Levinsky, linux-remoteproc, devicetree, robh, krzk+dt,
conor+dt, andersson, linux-kernel, michal.simek, tanmay.shah
In-Reply-To: <CANLsYkwxErFjaOJ0q1wT_59C1WGp_24d0nOksFpk-LaGq6eDGg@mail.gmail.com>
Hi Mathieu
Picking this back up now. Please see my replies inline below.
On 5/11/26 10:41 AM, Mathieu Poirier wrote:
> On Fri, 8 May 2026 at 10:59, Ben Levinsky <blevinsk@amd.com> wrote:
>>
>> Hi Mathieu,
>>
>>
>> On 5/8/26 8:47 AM, Mathieu Poirier wrote:
>>> Good morning,
>>>
>>> On Tue, Apr 28, 2026 at 07:26:33AM -0700, Ben Levinsky wrote:
>>>> Add a remoteproc driver for AMD soft-core processor subsystems
>>>> instantiated in programmable logic and using dual-port BRAM for
>>>> firmware storage and execution.
>>>>
>>>> The driver parses the firmware memory window from the remoteproc device
>>>> node's reg property, interprets that address and size in the
>>>> processor-local address space, and then uses standard devicetree
>>>> address translation through the parent bus ranges property to obtain
>>>> the corresponding Linux-visible system physical address.
>>>>
>>>> The resulting translated region is registered as the executable
>>>> remoteproc carveout and coredump segment.
>>>>
>>>> The processor is controlled through an active-low reset GPIO and a
>>>> subsystem clock. The clock is enabled before reset is released, and the
>>>> processor is kept in reset until firmware loading completes.
>>>>
>>>> The firmware-name property is optional, allowing firmware to be
>>>> assigned later through the remoteproc framework. Firmware images
>>>> without a resource table are also accepted.
>>>>
>>>> Signed-off-by: Ben Levinsky <ben.levinsky@amd.com>
>>>> ---
>>>> MAINTAINERS | 7 +
>>>> drivers/remoteproc/Kconfig | 14 ++
>>>> drivers/remoteproc/Makefile | 1 +
>>>> drivers/remoteproc/amd_bram_rproc.c | 243 ++++++++++++++++++++++++++++
>>>> 4 files changed, 265 insertions(+)
>>>> create mode 100644 drivers/remoteproc/amd_bram_rproc.c
>>>>
>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>> index c871acf2179c..172539971950 100644
>>>> --- a/MAINTAINERS
>>>> +++ b/MAINTAINERS
>>>> @@ -1037,6 +1037,13 @@ S: Maintained
>>>> F: Documentation/devicetree/bindings/w1/amd,axi-1wire-host.yaml
>>>> F: drivers/w1/masters/amd_axi_w1.c
>>>>
>>>> +AMD BRAM REMOTEPROC DRIVER
>>>> +M: Ben Levinsky <ben.levinsky@amd.com>
>>>> +L: linux-remoteproc@vger.kernel.org
>>>> +S: Maintained
>>>> +F: Documentation/devicetree/bindings/remoteproc/amd,bram-rproc.yaml
>>>> +F: drivers/remoteproc/amd_bram_rproc.c
>>>> +
>>>
>>> There is no real advantage in adding this entry, checkpatch.pl should be
>>> sufficient.
>>>
>>>> AMD CDX BUS DRIVER
>>>> M: Nipun Gupta <nipun.gupta@amd.com>
>>>> M: Nikhil Agarwal <nikhil.agarwal@amd.com>
>>>> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
>>>> index ee54436fea5a..9a2a887ede8a 100644
>>>> --- a/drivers/remoteproc/Kconfig
>>>> +++ b/drivers/remoteproc/Kconfig
>>>> @@ -23,6 +23,20 @@ config REMOTEPROC_CDEV
>>>>
>>>> It's safe to say N if you don't want to use this interface.
>>>>
>>>> +config AMD_BRAM_REMOTEPROC
>>>> + tristate "AMD BRAM-based remoteproc support"
>>>> + depends on OF && COMMON_CLK && (GPIOLIB || COMPILE_TEST)
>>>> + help
>>>> + Say y or m here to support a BRAM-based remote processor managed
>>>> + through the remoteproc framework.
>>>> +
>>>> + This driver matches designs where executable firmware memory is
>>>> + described in the BRAM-local address space and translated to
>>>> + the system physical address space with standard devicetree address
>>>> + translation.
>>>
>>> Not sure how this paragraph helps decide whether the driver should be enabled or
>>> not. Please remove.
>>>
>>>> +
>>>> + If unsure, say N.
>>>> +
>>>> config IMX_REMOTEPROC
>>>> tristate "i.MX remoteproc support"
>>>> depends on ARCH_MXC
>>>> diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
>>>> index 1c7598b8475d..5c39664b50c3 100644
>>>> --- a/drivers/remoteproc/Makefile
>>>> +++ b/drivers/remoteproc/Makefile
>>>> @@ -11,6 +11,7 @@ remoteproc-y += remoteproc_sysfs.o
>>>> remoteproc-y += remoteproc_virtio.o
>>>> remoteproc-y += remoteproc_elf_loader.o
>>>> obj-$(CONFIG_REMOTEPROC_CDEV) += remoteproc_cdev.o
>>>> +obj-$(CONFIG_AMD_BRAM_REMOTEPROC) += amd_bram_rproc.o
>>>> obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o
>>>> obj-$(CONFIG_IMX_DSP_REMOTEPROC) += imx_dsp_rproc.o
>>>> obj-$(CONFIG_INGENIC_VPU_RPROC) += ingenic_rproc.o
>>>> diff --git a/drivers/remoteproc/amd_bram_rproc.c b/drivers/remoteproc/amd_bram_rproc.c
>>>> new file mode 100644
>>>> index 000000000000..9383964b6046
>>>> --- /dev/null
>>>> +++ b/drivers/remoteproc/amd_bram_rproc.c
>>>> @@ -0,0 +1,243 @@
>>>> +// SPDX-License-Identifier: GPL-2.0
>>>> +/*
>>>> + * AMD BRAM-based Remote Processor driver
>>>> + *
>>>> + * Copyright (C) 2026 Advanced Micro Devices, Inc.
>>>> + *
>>>> + * This driver supports soft-core processors (MicroBlaze, MicroBlaze-V, or
>>>> + * similar) instantiated in AMD programmable logic, using dual-port BRAM
>>>> + * for firmware storage and execution.
>>>> + *
>>>> + * The firmware memory (BRAM) is described in the processor-local address
>>>> + * space and translated to the Linux-visible system physical address with
>>>> + * standard devicetree address translation.
>>>> + *
>>>> + * Reset is controlled via GPIO connected to Processor System Reset IP.
>>>> + */
>>>> +
>>>> +#include <linux/clk.h>
>>>> +#include <linux/dma-mapping.h>
>>>> +#include <linux/gpio/consumer.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_address.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/remoteproc.h>
>>>> +
>>>> +#include "remoteproc_internal.h"
>>>> +
>>>> +/**
>>>> + * struct amd_bram_rproc - AMD BRAM-based remoteproc private data
>>>> + * @dev: device pointer
>>>> + * @reset: GPIO descriptor for reset control (active-low)
>>>> + * @clk: processor clock
>>>> + */
>>>> +struct amd_bram_rproc {
>>>> + struct device *dev;
>>>> + struct gpio_desc *reset;
>>>> + struct clk *clk;
>>>> +};
>>>> +
>>>> +static int amd_bram_rproc_mem_map(struct rproc *rproc,
>>>> + struct rproc_mem_entry *mem)
>>>> +{
>>>> + void __iomem *va;
>>>> +
>>>> + va = ioremap_wc(mem->dma, mem->len);
>>>> + if (!va)
>>>> + return -ENOMEM;
>>>> +
>>>> + mem->va = (__force void *)va;
>>>> + mem->is_iomem = true;
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int amd_bram_rproc_mem_unmap(struct rproc *rproc,
>>>> + struct rproc_mem_entry *mem)
>>>> +{
>>>> + iounmap((void __iomem *)mem->va);
>>>> +
>>>> + return 0;
>>>> +}
>>>
>>> The above 2 are identical to what is found in xlnx_r5_remoteproc.c. Please
>>> coordinate with Tanmay to split that into common code that can be reused by both
>>> drivers.
>>>
>>>> +
>>>> +static int amd_bram_rproc_prepare(struct rproc *rproc)
>>>> +{
>>>> + struct amd_bram_rproc *priv = rproc->priv;
>>>> + struct rproc_mem_entry *mem;
>>>> + struct resource res;
>>>> + u64 da, size;
>>>> + int ret;
>>>> +
>>>> + ret = of_property_read_reg(priv->dev->of_node, 0, &da, &size);
>>>> + if (ret) {
>>>> + dev_err(priv->dev, "failed to parse executable memory reg\n");
>>>> + return ret;
>>>> + }
>>>> +
>>>> + if (!size || size > U32_MAX) {
>>>> + dev_err(priv->dev, "invalid executable memory size\n");
>>>> + return -EINVAL;
>>>> + }
>>>> +
>>>> + if (da > U32_MAX) {
>>>> + dev_err(priv->dev, "invalid executable memory address\n");
>>>> + return -EINVAL;
>>>> + }
>>>> +
>>>> + ret = of_address_to_resource(priv->dev->of_node, 0, &res);
>>>> + if (ret) {
>>>> + dev_err(priv->dev, "failed to translate executable memory reg\n");
>>>> + return ret;
>>>> + }
>>>> +
>>>> + mem = rproc_mem_entry_init(priv->dev, NULL, (dma_addr_t)res.start,
>>>> + (size_t)size, da,
>>>> + amd_bram_rproc_mem_map,
>>>> + amd_bram_rproc_mem_unmap,
>>>> + dev_name(priv->dev));
>>>> + if (!mem)
>>>> + return -ENOMEM;
>>>> +
>>>> + rproc_add_carveout(rproc, mem);
>>>> + rproc_coredump_add_segment(rproc, da, (size_t)size);
>>>
>>> I'm pretty sure you want @res.start instead of @da, and resource_size(&res)
>>> instead of @size.
>>>
For the coredump segment, I agree with using resource_size(&res) for
the size, but I think the address should remain @da rather than
@res.start.
The binding describes the reg property in the processor-local address
space and uses the parent bus ranges property only to translate that
window to the Linux-visible system physical address. That means @da and
@res.start are not necessarily in the same address space. For example,
the BRAM can appear at 0x0 to the soft-core processor while Linux sees
the same memory at a translated system physical address such as
0xa0000000.
rproc_coredump_add_segment() stores the address as a device address, and
the coredump path later resolves it through rproc_da_to_va() against the
registered carveout's device address. Since this driver registers the
carveout with @da as the device address and @res.start as the host-side
physical address used for ioremap_wc(), passing @res.start to
rproc_coredump_add_segment() could fail to match the carveout when those
addresses differ.
So in the respin I plan to use:
rproc_coredump_add_segment(rproc, da, resource_size(&res));
Does that match your expectation for this address model?
Thank you
Ben
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int amd_bram_rproc_start(struct rproc *rproc)
>>>> +{
>>>> + struct amd_bram_rproc *priv = rproc->priv;
>>>> + int ret;
>>>> +
>>>> + /* Enable clock before releasing reset */
>>>> + ret = clk_prepare_enable(priv->clk);
>>>> + if (ret) {
>>>> + dev_err(priv->dev, "failed to enable clock: %d\n", ret);
>>>> + return ret;
>>>> + }
>>>> +
>>>> + /* Deassert reset and let the processor run. */
>>>> + ret = gpiod_set_value_cansleep(priv->reset, 0);
>>>> + if (ret) {
>>>> + dev_err(priv->dev, "failed to deassert reset: %d\n", ret);
>>>> + clk_disable_unprepare(priv->clk);
>>>> + return ret;
>>>> + }
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int amd_bram_rproc_stop(struct rproc *rproc)
>>>> +{
>>>> + struct amd_bram_rproc *priv = rproc->priv;
>>>> + int ret;
>>>> +
>>>> + /* Assert reset before disabling the processor clock. */
>>>> + ret = gpiod_set_value_cansleep(priv->reset, 1);
>>>> + if (ret) {
>>>> + dev_err(priv->dev, "failed to assert reset: %d\n", ret);
>>>> + return ret;
>>>> + }
>>>> +
>>>> + /* Disable clock after asserting reset */
>>>> + clk_disable_unprepare(priv->clk);
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int amd_bram_rproc_parse_fw(struct rproc *rproc,
>>>> + const struct firmware *fw)
>>>> +{
>>>> + int ret;
>>>> +
>>>> + ret = rproc_elf_load_rsc_table(rproc, fw);
>>>> + if (ret == -EINVAL) {
>>>> + dev_dbg(&rproc->dev, "no resource table found\n");
>>>> + return 0;
>>>> + }
>>>> +
>>>> + return ret;
>>>> +}
>>>
>>> This too should go in common code or simply replaced by
>>> rproc_elf_load_rsc_table() in @amd_bram_rproc_ops - the choice is yours.
>>>
>>> Thanks,
>>> Mathieu
>>
>> Thanks for the review.
>>
>> I went through the remoteproc drivers to scope the cleanup points you
>> called out.
>>
>> For the plain carveout map/unmap callbacks, the same ioremap_wc()/iounmap()
>> pattern exists not only in amd_bram_rproc and xlnx_r5_remoteproc, but also
>> in rcar_rproc, st_remoteproc, stm32_rproc, imx_rproc, and imx_dsp_rproc.
>>
>> The xlnx_r5 TCM path is close as well, but that one still needs a wrapper
>> since it clears the memory after ioremap_wc().
>>
>> For the optional resource-table parsing, amd_bram_rproc and xlnx_r5_remoteproc
>> share the same pattern of treating only -EINVAL from rproc_elf_load_rsc_table()
>> as non-fatal. PRU is similar, but has additional firmware parsing after that.
>> Other drivers such as rcar/imx/imx_dsp/stm32 also tolerate missing resource
>> tables, but their current behavior is not identical since they flatten all
>> errors to success and only log.
>>
>> For the next revision, would you prefer the following approach?
>>
>> 1. Add a small common helper for the plain carveout ioremap_wc()/iounmap()
>> case and use it in amd_bram_rproc and xlnx_r5_remoteproc.
>>
>> 2. For the optional resource-table handling, either:
>> - add a small common helper for the "missing table is OK" case
>> (i.e. return 0 on -EINVAL and propagate other errors), and use that
>> in amd_bram_rproc and xlnx_r5_remoteproc, or
>
> I would prefer to go with the common helper that returns 0 on -EINVAL
> and propagates other errors, and apply it to other architectures such
> as stm32, rcar, imx and imx_dsp.
>
>> - drop the custom AMD parse_fw() path and use rproc_elf_load_rsc_table()
>> directly, which would make the resource table mandatory there.
>>
>> Also, for the plain map/unmap helper, should I keep the cleanup scoped to
>> the drivers directly involved here, or would you prefer that I fold the
>> other exact-match users (rcar, st, stm32, imx, imx_dsp) into the same
>> cleanup patch as well?
>>
>
> Proceed with the other exact-match as well.
>
>> I want to make sure I take the direction you prefer before respinning.
>
> I think the best approach is to send out a cleanup patchset with the
> above changes, followed by another respin of this set once the cleanup
> is merged.
>
> Thanks for being proactive.
>
>>
>> Thanks,
>> Ben
>>>
>>>> +
>>>> +static const struct rproc_ops amd_bram_rproc_ops = {
>>>> + .prepare = amd_bram_rproc_prepare,
>>>> + .start = amd_bram_rproc_start,
>>>> + .stop = amd_bram_rproc_stop,
>>>> + .load = rproc_elf_load_segments,
>>>> + .sanity_check = rproc_elf_sanity_check,
>>>> + .get_boot_addr = rproc_elf_get_boot_addr,
>>>> + .parse_fw = amd_bram_rproc_parse_fw,
>>>> +};
>>>> +
>>>> +static int amd_bram_rproc_probe(struct platform_device *pdev)
>>>> +{
>>>> + struct device *dev = &pdev->dev;
>>>> + struct amd_bram_rproc *priv;
>>>> + const char *fw_name = NULL;
>>>> + struct rproc *rproc;
>>>> + int ret;
>>>> +
>>>> + ret = rproc_of_parse_firmware(dev, 0, &fw_name);
>>>> + if (ret < 0 && ret != -EINVAL)
>>>> + return dev_err_probe(dev, ret,
>>>> + "failed to parse firmware-name property\n");
>>>> +
>>>> + rproc = devm_rproc_alloc(dev, dev_name(dev), &amd_bram_rproc_ops,
>>>> + fw_name, sizeof(*priv));
>>>> + if (!rproc)
>>>> + return -ENOMEM;
>>>> +
>>>> + priv = rproc->priv;
>>>> + priv->dev = dev;
>>>> +
>>>> + /* Get the processor clock */
>>>> + priv->clk = devm_clk_get(dev, NULL);
>>>> + if (IS_ERR(priv->clk))
>>>> + return dev_err_probe(dev, PTR_ERR(priv->clk),
>>>> + "failed to get clock\n");
>>>> +
>>>> + /*
>>>> + * Keep the processor in reset until remoteproc has finished loading
>>>> + * firmware into the executable memory window described by reg and
>>>> + * translated through the parent bus ranges property.
>>>> + */
>>>> + priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
>>>> + if (IS_ERR(priv->reset))
>>>> + return dev_err_probe(dev, PTR_ERR(priv->reset),
>>>> + "failed to get reset gpio\n");
>>>> +
>>>> + rproc->auto_boot = false;
>>>> +
>>>> + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
>>>> + if (ret)
>>>> + return dev_err_probe(dev, ret, "failed to set DMA mask\n");
>>>> +
>>>> + platform_set_drvdata(pdev, rproc);
>>>> +
>>>> + ret = devm_rproc_add(dev, rproc);
>>>> + if (ret)
>>>> + return dev_err_probe(dev, ret, "failed to register rproc\n");
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static const struct of_device_id amd_bram_rproc_of_match[] = {
>>>> + { .compatible = "xlnx,zynqmp-bram-rproc" },
>>>> + { /* sentinel */ },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, amd_bram_rproc_of_match);
>>>> +
>>>> +static struct platform_driver amd_bram_rproc_driver = {
>>>> + .probe = amd_bram_rproc_probe,
>>>> + .driver = {
>>>> + .name = "amd-bram-rproc",
>>>> + .of_match_table = amd_bram_rproc_of_match,
>>>> + },
>>>> +};
>>>> +module_platform_driver(amd_bram_rproc_driver);
>>>> +
>>>> +MODULE_DESCRIPTION("AMD BRAM-based Remote Processor driver");
>>>> +MODULE_AUTHOR("Ben Levinsky <ben.levinsky@amd.com>");
>>>> +MODULE_LICENSE("GPL");
>>>> --
>>>> 2.34.1
>>>>
>>>
>>
^ permalink raw reply
* Re: [PATCH v2] ASoC: dt-bindings: Convert cirrus,cs35l36 to DT schema
From: Bjorn Helgaas @ 2026-06-24 21:43 UTC (permalink / raw)
To: Rob Herring
Cc: david, David Rhodes, Richard Fitzgerald, Liam Girdwood,
Mark Brown, Krzysztof Kozlowski, Conor Dooley, patches,
Bjorn Helgaas, linux-sound, devicetree, linux-kernel, phone-devel
In-Reply-To: <CAL_JsqLE8Z-LbeF9r=sqRqAoGUcs7R-T4cN+hF3QzjGydHctgQ@mail.gmail.com>
On Wed, Jun 24, 2026 at 01:17:58PM -0500, Rob Herring wrote:
> On Wed, Jun 24, 2026 at 11:02 AM David Heidelberg via B4 Relay
> ...
> <devnull+david.ixit.cz@kernel.org> wrote:
> > +title: Cirrus Logic CS35L36 Speaker Amplifier
> > +
> > +maintainers:
> > + - patches@opensource.cirrus.com
> > + - Bjorn Helgaas <bhelgaas@google.com>
>
> Bjorn is not correct. Generally we want a person, not a company list.
Haha, thanks for noticing that. I definitely do not want to be listed
here; I have nothing to do with this.
^ permalink raw reply
* Re: (subset) [PATCH v2 0/3] rtc: ds1307: Add support for Epson RX8901CE
From: Alexandre Belloni @ 2026-06-24 21:42 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Nobuhiro Iwamatsu,
Fredrik M Olsson
Cc: linux-rtc, devicetree, linux-kernel, kernel, Krzysztof Kozlowski,
Nobuhiro Iwamatsu
In-Reply-To: <20260520-ds1307-rx8901-add-v2-0-e069ea32e1db@axis.com>
On Wed, 20 May 2026 16:48:52 +0200, Fredrik M Olsson wrote:
> Add basic support for the Epson RX8901CE RTC.
> Datasheet: https://download.epsondevice.com/td/pdf/app/RX8901CE_en.pdf
>
> Also includes a bug fix for an issue with reading the weekday from the
> RTC which affects both the existing rx8130 and this rx8901 driver.
>
>
> [...]
Applied, thanks!
[1/3] dt-bindings: rtc: ds1307: Add epson,rx8901
https://git.kernel.org/abelloni/c/cc387941c0a1
[2/3] rtc: ds1307: Fix off-by-one issue with wday for rx8130
https://git.kernel.org/abelloni/c/6882aab3c661
Best regards,
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH v3] rtc: bq32000: add configurable delay between RTC reads
From: Alexandre Belloni @ 2026-06-24 21:42 UTC (permalink / raw)
To: Adriana Stancu
Cc: linux-rtc, devicetree, linux-kernel, robh, krzk+dt, conor+dt
In-Reply-To: <20260416142151.3385827-1-adriana@arista.com>
On Thu, 16 Apr 2026 07:21:51 -0700, Adriana Stancu wrote:
> When the RTC is used on systems without a interrupt line, userspace
> tools like `hwclock` fall back to a frequent polling loop to synchronize
> with the edge of the next second.
>
> On the BQ32000, this aggressive polling can temporarly lock the register
> refresh cycle, because the continuous transfers prevent the hardware from
> updating the buffer. This results in stale data reads or select() timeouts
> in userspace.
>
> [...]
Applied, thanks!
[1/1] rtc: bq32000: add configurable delay between RTC reads
https://git.kernel.org/abelloni/c/d4992b7050a1
Best regards,
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH v3 3/4] firmware: xilinx: Add support for Xilsem scan operations
From: sashiko-bot @ 2026-06-24 21:39 UTC (permalink / raw)
To: Rama devi Veggalam; +Cc: robh, conor+dt, devicetree
In-Reply-To: <20260624212545.2850787-4-rama.devi.veggalam@amd.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] Uninitialized memory use and potential information leak via uninitialized stack buffer.
- [Medium] Potential address truncation and misleading parameter type for DMA addresses.
- [Low] API contract mismatch and typo in Kernel-Doc.
Pre-existing issues:
- [High] Lockless concurrent modification of global hashtable and arrays causing data races and UAF.
--
commit e939c99be4b47a8ba5e7ed4d9aaf024781ae5543
Author: Rama devi Veggalam <rama.devi.veggalam@amd.com>
firmware: xilinx: Add support for Xilsem scan operations
Add the ATF EEMI call support for Xilsem scan operations.
Initialize, start, stop scan, error inject, read configuration,
status and register for software error events.
Add macros for XilSem correctable and uncorrectable error events.
> diff --git a/drivers/firmware/xilinx/zynqmp-sem.c b/drivers/firmware/xilinx/zynqmp-sem.c
> new file mode 100644
> index 0000000000000..5cd399b165f55
> --- /dev/null
> +++ b/drivers/firmware/xilinx/zynqmp-sem.c
> @@ -0,0 +1,176 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Firmware layer for XilSEM APIs.
> + *
> + * Copyright (C), 2026 Advanced Micro Devices, Inc.
> + */
[ ... ]
> +/**
> + * zynqmp_pm_xilsem_cntrl_ops - PM call to perform XilSEM operations
> + * @cmd: Command for XilSEM scan control operations
> + * @slrid: SLR id on which scan operation to be done
> + * @response: Output response (command header, error code or status, slr id)
[Severity: Low]
Does the documentation accurately reflect the response size? The documentation
specifies 3 elements, but the function below writes 6 elements to the array.
Could this lead future callers to allocate undersized stack arrays?
> + *
> + * Return: Returns 0 on success or error value on failure.
> + */
> +int zynqmp_pm_xilsem_cntrl_ops(u32 cmd, u32 slrid, u32 *const response)
> +{
> + u32 ret_buf[PAYLOAD_ARG_CNT];
> + int ret;
> +
> + ret = zynqmp_pm_invoke_fn(PM_XSEM_HEADER | cmd, ret_buf, 1, slrid);
[Severity: High]
This is a pre-existing issue, but can multiple concurrent drivers calling into
zynqmp_pm_invoke_fn() cause race conditions or use-after-free?
Looking at zynqmp_pm_invoke_fn(), it calls zynqmp_pm_feature() which leads
to lockless hash table insertions into pm_api_features_map:
zynqmp_pm_invoke_fn()
zynqmp_pm_feature()
do_feature_check_call()
hash_add(pm_api_features_map, &feature_data->hentry, api_id);
Since hlist_add_head() is not thread-safe, could concurrent insertions
corrupt the hash bucket's linked list?
Additionally, zynqmp_firmware_remove() frees these hashtable entries
locklessly, which could expose concurrent callers to use-after-free.
> + response[0] = ret_buf[1];
[Severity: High]
Does this code copy uninitialized memory to response if zynqmp_pm_invoke_fn()
returns an error?
If zynqmp_pm_invoke_fn() fails early (for example, if zynqmp_pm_feature()
returns -EOPNOTSUPP), it returns without writing to ret_buf. The values
from ret_buf are then unconditionally copied into the response array.
Could this lead to reading uninitialized kernel stack memory?
> + response[1] = ret_buf[2];
> + response[2] = ret_buf[3];
> + response[3] = ret_buf[4];
> + response[4] = ret_buf[5];
> + response[5] = ret_buf[6];
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(zynqmp_pm_xilsem_cntrl_ops);
[ ... ]
> +/**
> + * zynqmp_pm_xilsem_read_ssit_status - PM call to perform Xilsem SSIT status
> + * @slrid: SLR id for which ECC read to be done
> + * @bufaddr: Buffer address to get the status information
> + * @response: Output response (status read header, slr id)
> + *
> + * Return: Returns 0 on success or error value on failure.
> + */
> +int zynqmp_pm_xilsem_read_ssit_status(u32 slrid, u32 bufaddr, u32 *const response)
^^^^^^^
[Severity: Medium]
Can this parameter cause address truncation? The EDAC driver may allocate a
coherent DMA buffer typed as dma_addr_t and pass it to bufaddr. Since
bufaddr is typed as u32, this could truncate a 64-bit DMA address to 32
bits, causing the firmware to write to an incorrect physical address.
> +{
> + u32 ret_buf[PAYLOAD_ARG_CNT];
> + int ret;
> +
> + ret = zynqmp_pm_invoke_fn(PM_XSEM_SSIT_RD_STS, ret_buf, 2, slrid, bufaddr);
> + response[0] = ret_buf[1];
> + response[1] = ret_buf[2];
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(zynqmp_pm_xilsem_read_ssit_status);
[ ... ]
> +/**
> + * zynqmp_pm_xilsem_cram_getcrc - PM call to perform CRAM Row CRC read
> + * @slrid: SLR id for which CRC read to be done
> + * @rowindex: CFRAME row number to be used for reading CRC
> + * @response: Output response (Get CRC header, CRC values, status)
> + *
> + * Return: Returns 0 on success or error value on failure.
> + */
> +int zynqmp_pm_xilsem_cram_getcrc(u32 slrid, u32 rowindex, u32 *const response)
> +{
> + u32 ret_buf[PAYLOAD_ARG_CNT];
> + int ret;
> +
> + ret = zynqmp_pm_invoke_fn(PM_XSEM_SSIT_GET_CRC, ret_buf, 2, slrid, rowindex);
> + response[0] = ret_buf[1];
[Severity: High]
Does this code also copy uninitialized memory to response if
zynqmp_pm_invoke_fn() returns an error? If it fails early, ret_buf is
not written to, resulting in uninitialized kernel stack memory being
read and copied unconditionally.
> + response[1] = ret_buf[2];
> + response[2] = ret_buf[3];
> + response[3] = ret_buf[4];
> + response[4] = ret_buf[5];
> + response[5] = ret_buf[6];
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(zynqmp_pm_xilsem_cram_getcrc);
> +
> +/**
> + * zynqmp_pm_xilsem_cram_ssit_totframes - PM call to perform total frames read
> + * @slrid: SLR id for which total frames read to be done
> + * @row: CFRAME row number to be used for reading ECC
> + * @framecnt: Buffer address to get toral frames data
[Severity: Low]
Is there a typo in the documentation here? Should toral be total?
> + * @response: Output response (Total frames header, slr id, row, status)
> + *
> + * Return: Returns 0 on success or error value on failure.
> + */
> +int zynqmp_pm_xilsem_cram_ssit_totframes(u32 slrid, u32 row, u32 framecnt, u32 *const response)
^^^^^^^^^^^^
[Severity: Medium]
Does framecnt suffer from address truncation similar to bufaddr? The
parameter name framecnt is somewhat misleading since it receives a DMA
buffer address rather than a count. Since it is typed as u32, passing
a 64-bit dma_addr_t could cause truncation.
> +{
> + u32 ret_buf[PAYLOAD_ARG_CNT];
> + int ret;
> +
> + ret = zynqmp_pm_invoke_fn(PM_XSEM_SSIT_GET_FRAMES, ret_buf, 3, slrid, row, framecnt);
> + response[0] = ret_buf[1];
> + response[1] = ret_buf[2];
> + response[2] = ret_buf[3];
> + response[3] = ret_buf[4];
> +
> + return ret;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624212545.2850787-1-rama.devi.veggalam@amd.com?part=3
^ permalink raw reply
* Re: [PATCH v2 3/3] rtc: ds1307: Add driver for Epson RX8901CE
From: Alexandre Belloni @ 2026-06-24 21:38 UTC (permalink / raw)
To: Fredrik M Olsson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Nobuhiro Iwamatsu,
linux-rtc, devicetree, linux-kernel, kernel
In-Reply-To: <20260520-ds1307-rx8901-add-v2-3-e069ea32e1db@axis.com>
On 20/05/2026 16:48:55+0200, Fredrik M Olsson wrote:
> +static int do_trickle_setup_rx8901(struct ds1307 *ds1307, u32 ohms __always_unused, bool diode)
> +{
> + int ret;
> + unsigned int setup;
> +
> + ret = regmap_read(ds1307->regmap, RX8901_REG_PWSW_CFG, &setup);
> + if (ret) {
> + dev_err(ds1307->dev, "Failed to read PWSW_CFG register\n");
> + return ret;
> + }
> +
> + /* Enable low battery voltage detection */
> + setup |= RX8901_REG_PWSW_CFG_VBATLDETEN;
> +
> + if (diode)
> + setup |= RX8901_REG_PWSW_CFG_CHGEN;
When diode is false, you need to explicitly clear
RX8901_REG_PWSW_CFG_CHGEN so it is possible to actually disable trickle
charging once it has been enabled has the register is battery backed.
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH v3 4/4] edac: xilinx: Add EDAC support for Versal XilSem
From: sashiko-bot @ 2026-06-24 21:37 UTC (permalink / raw)
To: Rama devi Veggalam; +Cc: devicetree, conor+dt, robh
In-Reply-To: <20260624212545.2850787-5-rama.devi.veggalam@amd.com>
Thank you for your contribution! Sashiko AI review found 13 potential issue(s) to consider:
- [Critical] Passing a 64-bit `dma_addr_t` to a 32-bit firmware API parameter truncates the physical address, causing memory corruption.
- [High] Missing 'semrtca' resource breaks driver probe for older Device Trees.
- [High] The sysfs `store` functions use the virtual EDAC device for DMA allocations instead of the platform device.
- [High] Error paths introduced in `mc_probe` fail to unregister the `VERSAL_EVENT_ERROR_PMC_ERR1` PM notifier, causing a Use-After-Free.
- [High] The error event handler uses an `if - else if` chain for bitmask evaluation, silently dropping uncorrectable errors.
- [Medium] Hexadecimal prefixes mistakenly used for decimal bit-shift macros cause undefined behavior and break CRAM frame decoding.
- [Medium] The `xsem_total_cframes_ssit_show` function mutates the driver's cached CRAM frames state in-place, corrupting data on subsequent reads.
- [Medium] Sysfs `store` functions unconditionally truncate the last character of user input if it is not newline-terminated.
- [Medium] XilSEM fabric and interconnect errors are incorrectly attributed to DDR memory DIMM 0.
- [Medium] Failure to handle an unrecognized `family_code` causes the driver to register an event with uninitialized parameters.
- [Medium] Lack of synchronization in sysfs callbacks causes data races on shared buffers.
- [Medium] The `xsem_err_callback` event handler performs unprotected read-modify-write operations on shared error counters.
- [Low] Copy-paste error in `xsem_scan_control_show` format string causes incorrect output.
--
commit 3ba94d35140e37f0feb1403bd80442cef2ad8ed1
Author: Rama devi Veggalam <rama.devi.veggalam@amd.com>
Subject: edac: xilinx: Add EDAC support for Versal XilSem
This patch adds support for Xilinx Versal Soft Error Mitigation (XilSEM)
to handle and optionally correct soft errors in Configuration Memory.
It also introduces sysfs interfaces for XilSEM scan operations, error
injection, and configuration reads.
> diff --git a/drivers/edac/versal_edac.c b/drivers/edac/versal_edac.c
> index 5a43b5d43ca28..024ddd90f6996 100644
> --- a/drivers/edac/versal_edac.c
> +++ b/drivers/edac/versal_edac.c
[ ... ]
> @@ -11,12 +11,88 @@
> #include <linux/of_address.h>
> #include <linux/of_device.h>
> #include <linux/platform_device.h>
> +#include <linux/dma-mapping.h>
> #include <linux/sizes.h>
> +#include <linux/io.h>
> #include <linux/firmware/xlnx-zynqmp.h>
> +#include <linux/firmware/xlnx-versal-error-events.h>
> #include <linux/firmware/xlnx-event-manager.h>
>
> #include "edac_module.h"
>
> +/* XilSem CE Error log count */
> +#define XILSEM_MAX_CE_LOG_CNT 7
> +
> +/** Maximum CRAM error register count */
> +#define MAX_CRAMERR_REG_CNT 14
> +/** Maximum NPI slave skip count */
> +#define MAX_NPI_SLV_SKIP_CNT 8
> +/** Maximum NPI Error info count */
> +#define MAX_NPI_ERR_INFO_CNT 2
> +
> +/* Maximum SLR count */
> +#define MAX_SLR_ID 3
> +
> +/** Maximum number of cframe types */
> +#define CFRAME_MAX_TYPE 7
> +
> +/** Mask for getting Type_0, Type_4 frames */
> +#define CFRAME_TYPE_0_4_MASK GENMASK(19, 0)
> +
> +/** Low mask, High mask for getting Type_1, Type_5 frames */
> +#define CFRAME_TYPE_1_5_MASK_L GENMASK(39, 20)
> +#define CFRAME_TYPE_1_5_MASK_H GENMASK(7, 0)
> +
> +/** Shift for getting Type_1, Type_5 frames */
> +#define CFRAME_TYPE_1_5_SHIFT_R 0x20
> +#define CFRAME_TYPE_1_5_SHIFT_L 0x12
> +
> +/** Mask for getting Type_2, Type_6 frames */
> +#define CFRAME_TYPE_2_6_MASK GENMASK(27, 8)
> +
> +/** Shift for getting Type_2, Type_6 frames */
> +#define CFRAME_TYPE_2_6_SHIFT_R 0x8
> +
> +/** Low mask, high mask for getting Type_3 frames */
> +#define CFRAME_TYPE_3_MASK_L GENMASK(31, 28)
> +#define CFRAME_TYPE_3_MASK_H GENMASK(15, 0)
> +
> +/** Shift for getting Type_3 */
> +#define CFRAME_TYPE_3_SHIFT_R 0x28
[Severity: Medium]
Are these macro definitions incorrectly using a hex prefix for decimal shift
values? Shifting a 32-bit value by 0x20 (32) or 0x28 (40) bits will invoke
undefined behavior.
> +#define CFRAME_TYPE_3_SHIFT_L 0x4
[ ... ]
> +static ssize_t xsem_scan_control_show(struct device *dev,
> + struct device_attribute *mattr,
> + char *data)
> +{
> + struct mem_ctl_info *mci = to_mci(dev);
> + struct edac_priv *priv = mci->pvt_info;
> +
> + if (!priv->xsem_rtca)
> + return -EINVAL;
> +
> + return sprintf(data, "[0x%x][0x%x][0x%x][0x%x][0x%x][0x%x][0x%x]\n\r",
> + priv->xsem_rtca->scan_ctrl_status[0],
> + priv->xsem_rtca->scan_ctrl_status[0],
[Severity: Low]
Is there a typo here where scan_ctrl_status[0] is printed twice, causing the
output to miss the last element of the array?
> + priv->xsem_rtca->scan_ctrl_status[1],
> + priv->xsem_rtca->scan_ctrl_status[2],
> + priv->xsem_rtca->scan_ctrl_status[3],
> + priv->xsem_rtca->scan_ctrl_status[4],
> + priv->xsem_rtca->scan_ctrl_status[5]);
> +}
> +
> +/**
> + * xsem_scan_control_store - Set scan control operation
[ ... ]
> +static ssize_t xsem_scan_control_store(struct device *dev,
> + struct device_attribute *mattr,
> + const char *data, size_t count)
> +{
> + struct mem_ctl_info *mci = to_mci(dev);
> + struct edac_priv *priv = mci->pvt_info;
> + char *kern_buff, *inbuf, *tok;
> + u32 cmd;
> + u32 slrid;
> + int ret;
> +
> + if (!priv->xsem_rtca)
> + return -EINVAL;
> +
> + kern_buff = kzalloc(count, GFP_KERNEL);
> + if (!kern_buff)
> + return -ENOMEM;
> + strscpy(kern_buff, data, count);
[Severity: Medium]
Does this silently truncate the last character of the user input if it is not
newline-terminated? When count matches the string length exactly, strscpy()
copies at most count - 1 bytes and inserts a null terminator.
> +
> + inbuf = kern_buff;
[ ... ]
> +static ssize_t xsem_total_cframes_ssit_show(struct device *dev,
> + struct device_attribute *mattr,
> + char *data)
> +{
> + struct mem_ctl_info *mci = to_mci(dev);
> + struct edac_priv *priv = mci->pvt_info;
> + u32 temp_buf[CFRAME_MAX_TYPE] = {0};
> + u32 id;
> + int offset = 0;
> +
> + if (!priv->xsem_rtca)
> + return -EINVAL;
> +
> + for (id = 0; id < CFRAME_MAX_TYPE; id++)
> + temp_buf[id] = priv->xsem_rtca->cram_total_frames[id];
> +
> + priv->xsem_rtca->cram_total_frames[0] = (temp_buf[0] & CFRAME_TYPE_0_4_MASK);
> + priv->xsem_rtca->cram_total_frames[1] = (temp_buf[0] &
> + CFRAME_TYPE_1_5_MASK_L) >> CFRAME_TYPE_1_5_SHIFT_R;
[Severity: Medium]
Does this modify the shared cram_total_frames array in-place during a read
operation? Subsequent reads might apply the bitwise shifts to already-shifted
data, returning garbled output.
> + priv->xsem_rtca->cram_total_frames[1] |= (temp_buf[1] &
[ ... ]
> +static ssize_t xsem_total_cframes_ssit_store(struct device *dev,
> + struct device_attribute *mattr,
> + const char *data, size_t count)
> +{
> + struct mem_ctl_info *mci = to_mci(dev);
> + struct edac_priv *priv = mci->pvt_info;
> + char *kern_buff, *inbuf, *tok, *kbuf1;
> + dma_addr_t dma_addr = 0;
> + u32 row, slrid, dma_size;
> + int ret;
[ ... ]
> + dma_size = sizeof(priv->xsem_rtca->cram_total_frames);
> + kbuf1 = dma_alloc_coherent(dev, dma_size, &dma_addr, GFP_KERNEL);
[Severity: High]
Are we passing the virtual EDAC device pointer instead of the platform device
here? Sysfs store callbacks for this attribute receive &mci->dev, which lacks
DMA configuration and could cause allocation failures.
> + if (!kbuf1) {
> + ret = -ENOMEM;
> + goto err;
> + }
> +
> + ret = zynqmp_pm_xilsem_cram_ssit_totframes(slrid, row, dma_addr,
> + priv->xsem_rtca->cram_get_frames_status);
[Severity: Critical]
Can this truncate the physical address and cause memory corruption? On ARM64,
dma_addr_t is 64-bit, but the firmware API parameters are 32-bit.
> + if (ret) {
> + edac_printk(KERN_ERR, EDAC_MC, "ERROR: XilSEM Status PM API failed\n");
> + dma_free_coherent(dev, dma_size, kbuf1, dma_addr);
> + goto err;
> + }
> +
> + memcpy(priv->xsem_rtca->cram_total_frames, kbuf1, dma_size);
[Severity: Medium]
Can concurrent sysfs store operations corrupt this shared buffer due to a lack
of locking?
> + dma_free_coherent(dev, dma_size, kbuf1, dma_addr);
[ ... ]
> +static ssize_t xsem_read_ssit_status_store(struct device *dev,
> + struct device_attribute *mattr,
> + const char *data, size_t count)
> +{
> + struct mem_ctl_info *mci = to_mci(dev);
> + struct edac_priv *priv = mci->pvt_info;
> + char *kern_buff, *inbuf, *tok, *kbuf1;
> + size_t dma_size;
> + dma_addr_t dma_addr = 0;
> + u32 slrid;
> + int ret;
[ ... ]
> + dma_size = sizeof(struct xsem_ssit_status);
> +
> + kbuf1 = dma_alloc_coherent(dev, dma_size, &dma_addr, GFP_KERNEL);
[Severity: High]
Does passing the virtual EDAC device pointer (which lacks DMA configuration)
instead of the platform device cause DMA allocation failures?
> + if (!kbuf1) {
> + ret = -ENOMEM;
> + goto err;
> + }
> +
> + ret = zynqmp_pm_xilsem_read_ssit_status(slrid, dma_addr,
> + priv->xsem_rtca->xilsem_ssit_status);
[Severity: Critical]
Could passing the 64-bit dma_addr to this 32-bit firmware API parameter result
in physical address truncation and subsequent memory corruption?
> + if (ret) {
> + edac_printk(KERN_ERR, EDAC_MC, "ERROR: XilSEM Status PM API failed\n");
> + dma_free_coherent(dev, dma_size, kbuf1, dma_addr);
> + goto err;
> + }
> +
> + memcpy(priv->xsem_rtca->slr_info, kbuf1, dma_size);
[Severity: Medium]
Can concurrent executions of this sysfs store operation result in data races on
this shared slr_info buffer?
> +
> + dma_free_coherent(dev, dma_size, kbuf1, dma_addr);
[ ... ]
> +static void xsem_geterror_info(struct mem_ctl_info *mci, struct xsem_error_status *p,
> + int mask)
> +{
> + struct edac_priv *priv = mci->pvt_info;
> + u32 error_word_0, error_word_1, ce_count;
> + u8 index;
> +
> + if (!priv->xsem_rtca || !priv->sem_baseaddr)
> + return;
> +
> + if (mask & priv->xsem_rtca->cram_ce_mask) {
> + p->ce_cnt++;
[ ... ]
> + /* Read CRAM status */
> + p->ceinfo.status = readl(priv->sem_baseaddr + CRAM_STS_INFO_OFFSET);
> + } else if (mask & priv->xsem_rtca->cram_ue_mask) {
[Severity: High]
Does this if-else chain cause uncorrectable errors to be silently ignored if
the payload mask contains both a correctable and uncorrectable error?
> + p->ue_cnt++;
> + p->ueinfo.data0 = 0;
> + p->ueinfo.data1 = 0;
> + p->ueinfo.status = readl(priv->sem_baseaddr + CRAM_STS_INFO_OFFSET);
> + } else if (mask & priv->xsem_rtca->npi_ue_mask) {
> + p->ue_cnt++;
> + p->ueinfo.data0 = readl(priv->sem_baseaddr + NPI_ERR0_INFO_OFFSET);
> + p->ueinfo.data1 = readl(priv->sem_baseaddr + NPI_ERR1_INFO_OFFSET);
> + p->ueinfo.status = readl(priv->sem_baseaddr);
> + } else {
> + edac_printk(KERN_ERR, EDAC_MC, "Invalid Event received %d\n", mask);
> + }
> +}
> +
> +/**
> + * xsem_handle_error - Handle XilSem error types CE and UE
> + * @mci: Pointer to the memory controller instance
> + * @p: Pointer to the xilsem error status structure
> + *
> + * Handles the correctable and uncorrectable error.
> + */
> +static void xsem_handle_error(struct mem_ctl_info *mci, struct xsem_error_status *p)
> +{
> + struct xsem_ecc_error_info *pinf;
> + char message[XDDR_EDAC_MSG_SIZE];
> +
> + if (p->ce_cnt) {
> + pinf = &p->ceinfo;
> + snprintf(message, XDDR_EDAC_MSG_SIZE,
> + "\n\rXILSEM CRAM error type :%s\n\r"
> + "\nFrame_Addr: [0x%X]\t Row_num: [0x%X]\t Bit_loc: [0x%X]\t Qword: [0x%X]\n\r",
> + "CE", pinf->frame_addr, pinf->row_id,
> + pinf->bit_loc, pinf->qword);
> +
> + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
> + p->ce_cnt, 0, 0, 0, 0, 0, -1,
> + message, "");
[Severity: Medium]
Are these fabric and interconnect errors being incorrectly attributed to the
first DDR memory module? Passing top_layer=0 and mid_layer=0 explicitly maps
them to csrow 0, channel 0.
> + }
> +
> + if (p->ue_cnt) {
> + pinf = &p->ueinfo;
> + snprintf(message, XDDR_EDAC_MSG_SIZE,
> + "\n\rXILSEM error type :%s\n\r"
> + "status: [0x%X]\n\rError_Info0: [0x%X]\n\r"
> + "Error_Info1: [0x%X]",
> + "UE", pinf->status, pinf->data0, pinf->data1);
> +
> + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
> + p->ue_cnt, 0, 0, 0, 0, 0, -1,
> + message, "");
[Severity: Medium]
Does mapping uncorrectable XilSEM errors to top_layer=0 incorrectly attribute
them to the first DDR memory DIMM?
> + }
> +}
> +
> +/**
> + * xsem_err_callback - Handle Correctable and Uncorrectable errors.
> + * @payload: payload data.
> + * @data: controller data.
> + *
> + * Handles ECC correctable and uncorrectable errors.
> + */
> +static void xsem_err_callback(const u32 *payload, void *data)
> +{
> + struct xsem_error_status stat;
> + struct edac_priv *priv;
> + struct mem_ctl_info *mci = (struct mem_ctl_info *)data;
> + int event;
> +
> + priv = mci->pvt_info;
> + if (!priv->xsem_rtca)
> + return;
> +
> + memset(&stat, 0, sizeof(stat));
> + /* Read payload to get the event type */
> + event = payload[2];
> + edac_printk(KERN_INFO, EDAC_MC, "Event received %x\n", event);
> + xsem_geterror_info(mci, &stat, event);
> +
> + priv->xsem_rtca->cram_ce_cnt += stat.ce_cnt;
> + priv->xsem_rtca->cram_ue_cnt += stat.ue_cnt;
[Severity: Medium]
Could these read-modify-write operations on shared counters lose increments if
the hardware event callback is executed concurrently on multiple CPUs?
> + xsem_handle_error(mci, &stat);
> +}
[ ... ]
> @@ -1094,6 +2365,10 @@ static int mc_probe(struct platform_device *pdev)
> if (!get_ecc_state(ddrmc_baseaddr))
> return -ENXIO;
>
> + sem_baseaddr = devm_platform_ioremap_resource_byname(pdev, "semrtca");
> + if (IS_ERR(sem_baseaddr))
> + return PTR_ERR(sem_baseaddr);
[Severity: High]
Does this make the "semrtca" resource mandatory, breaking the driver probe for
older device trees that do not define it?
> +
> /* Allocate ID number for the EMIF controller */
> edac_mc_id = emif_get_id(pdev->dev.of_node);
>
[ ... ]
> + rc = zynqmp_pm_get_family_info(&family_code);
> + if (rc) {
> + if (rc == -ENODEV)
> + rc = -EPROBE_DEFER;
> +
> + goto del_mc;
> + }
> + if (family_code == PM_VERSAL_FAMILY_CODE) {
> + priv->xsem_rtca->sw_event_node_id = VERSAL_EVENT_ERROR_SW_ERR;
> + priv->xsem_rtca->cram_ce_mask = XPM_VERSAL_EVENT_ERROR_MASK_XSEM_CRAM_CE_5;
> + priv->xsem_rtca->cram_ue_mask = XPM_VERSAL_EVENT_ERROR_MASK_XSEM_CRAM_UE_6;
> + priv->xsem_rtca->npi_ue_mask = XPM_VERSAL_EVENT_ERROR_MASK_XSEM_NPI_UE_7;
> + } else {
> + edac_printk(KERN_ERR, EDAC_MC, "Invalid Device family code %d\n", family_code);
> + }
> +
> + rc = xlnx_register_event(PM_NOTIFY_CB, priv->xsem_rtca->sw_event_node_id,
[Severity: Medium]
Does this execution path fall through when the family code is unrecognized,
causing the driver to register an event using uninitialized parameters (zeros)?
> + priv->xsem_rtca->cram_ce_mask | priv->xsem_rtca->cram_ue_mask |
> + priv->xsem_rtca->npi_ue_mask,
> + false, xsem_err_callback, mci);
> + if (rc)
> + goto del_mc;
> +
> #ifdef CONFIG_EDAC_DEBUG
> create_debugfs_attributes(mci);
> setup_address_map(priv);
> @@ -1154,6 +2484,8 @@ static int mc_probe(struct platform_device *pdev)
> enable_intr(priv);
> return rc;
>
> +remove_sysfs:
> + xsem_edac_remove_sysfs_attributes(mci);
> del_mc:
> edac_mc_del_mc(&pdev->dev);
> free_edac_mc:
> @@ -1173,9 +2505,21 @@ static void mc_remove(struct platform_device *pdev)
[Severity: High]
Does this error path fail to unregister the VERSAL_EVENT_ERROR_PMC_ERR1 event
that was registered earlier in the function? If the event triggers after mci is
freed, could it cause a use-after-free in the callback?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624212545.2850787-1-rama.devi.veggalam@amd.com?part=4
^ permalink raw reply
* Re: [PATCH v3 1/4] dt-bindings: edac: Add bindings for Xilinx Versal XilSEM
From: sashiko-bot @ 2026-06-24 21:33 UTC (permalink / raw)
To: Rama devi Veggalam; +Cc: conor+dt, robh, devicetree
In-Reply-To: <20260624212545.2850787-2-rama.devi.veggalam@amd.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] Adding a third mandatory item to `reg` and `reg-names` breaks backward compatibility for existing device trees, causing schema validation and driver probe failures.
- [Medium] Unrelated XilSEM hardware registers are incorrectly merged into the DDR Memory Controller (`xlnx,versal-ddrmc`) device tree node, violating DT design principles.
--
commit 4759b2e3e1d7757d4a16075824d7a25fd86d0c73
Author: Rama devi Veggalam <rama.devi.veggalam@amd.com>
dt-bindings: edac: Add bindings for Xilinx Versal XilSEM
Update versal edac device tree bindings for Versal Soft Error Mitigation
(XilSEM).
> diff --git a/Documentation/devicetree/bindings/memory-controllers/xlnx,versal-ddrmc-edac.yaml b/Documentation/devicetree/bindings/memory-controllers/xlnx,versal-ddrmc-edac.yaml
> index 12f8e9f350bcf..568d2af7de81a 100644
> --- a/Documentation/devicetree/bindings/memory-controllers/xlnx,versal-ddrmc-edac.yaml
> +++ b/Documentation/devicetree/bindings/memory-controllers/xlnx,versal-ddrmc-edac.yaml
[ ... ]
> @@ -23,11 +37,13 @@ properties:
> items:
> - description: DDR Memory Controller registers
> - description: NOC registers corresponding to DDR Memory Controller
> + - description: SEM RTCA Controller registers
[Severity: Medium]
Is it correct to merge unrelated XilSEM hardware registers into the DDR Memory
Controller device tree node?
The device tree describes an inaccurate hardware topology by grouping physically
separate register bases under a single compatible string simply because a single
EDAC driver handles both. Should XilSEM be represented by its own distinct
device tree node?
[Severity: Critical]
Does adding this new required register break backward compatibility with older
device trees?
Because this adds a third mandatory item to the list without specifying
minItems: 2, older device trees lacking the "semrtca" register will fail
schema validation.
Additionally, does the driver unconditionally require this new register in
mc_probe(), causing probes to fail on existing systems? If the driver code
looks for the new register:
drivers/edac/versal_edac.c:mc_probe() {
...
sem_baseaddr = devm_platform_ioremap_resource_byname(pdev, "semrtca");
if (IS_ERR(sem_baseaddr))
return PTR_ERR(sem_baseaddr);
...
}
This will return an error when the DT node lacks the semrtca register, leading
to immediate probe failure on existing setups.
>
> reg-names:
> items:
> - const: base
> - const: noc
> + - const: semrtca
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624212545.2850787-1-rama.devi.veggalam@amd.com?part=1
^ permalink raw reply
* Re: [PATCH v3 2/4] Documentation: ABI: Add ABI doc for versal edac sysfs
From: sashiko-bot @ 2026-06-24 21:32 UTC (permalink / raw)
To: Rama devi Veggalam; +Cc: robh, conor+dt, devicetree
In-Reply-To: <20260624212545.2850787-3-rama.devi.veggalam@amd.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Medium] The sysfs entries implement a stateful RPC command-response interface, causing data races.
- [Medium] Multiple sysfs attributes output complex, multiline blocks instead of single values.
- [Low] Malformed ABI Documentation Syntax.
- [Low] Duplicate and conflicting entries in ABI Documentation.
--
commit 9760cee2db24f4eb5850706de75cd24db0ae078c
Author: Rama devi Veggalam <rama.devi.veggalam@amd.com>
Documentation: ABI: Add ABI doc for versal edac sysfs
Add documentation for the sysfs entries created for
versal edac (XilSEM).
> diff --git a/Documentation/ABI/testing/sysfs-driver-versal-edac b/Documentation/ABI/testing/sysfs-driver-versal-edac
> new file mode 100644
> index 0000000000000..c35d864fcbe2c
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-driver-versal-edac
> @@ -0,0 +1,303 @@
> +What: /sys/devices/system/edac/versal_xilsem/xsem_scan_control
> +Date: What: /sys/devices/system/edac/mc/mc0/xsem_scan_control
> +Date: June 2026
[Severity: Low]
Is there malformed syntax in this documentation block? The second line has a
duplicate "What:" definition inside the "Date:" field.
> +Contact: rama.devi.veggalam@amd.com
> +Description:
> + It is a read/write file.
> + Writing to this file causes the software to initiate a
> + request to the firmware for doing requested scan operation in
> + Configuration RAM (CRAM) or NPI of Versal mono/SSIT devices.
> + User needs to provide scan operation id (init, start, stop) and
> + SLR id (Versal SSIT device) details. For Versal mono devices,
> + the SLR id should be 0.
> + The scan operation id values are as given below:
> + 1 - Initialize the scan
> + 2 - Start CRAM scan
> + 3 - Stop CRAM scan
> + 5 - Start NPI scan
> + 6 - Stop NPI scan
> + 7 - Inject NPI error in first descriptor
> +
> + When read, it shows the current scan status with error code.
[Severity: Medium]
Could this stateful command-response interface introduce data races?
In drivers/edac/versal_edac.c, xsem_scan_control_store() writes the command
result directly to the shared, lockless array:
ret = zynqmp_pm_xilsem_cntrl_ops(cmd, slrid, priv->xsem_rtca->scan_ctrl_status);
Then xsem_scan_control_show() reads from it:
return sprintf(data, "[0x%x][0x%x][0x%x][0x%x][0x%x][0x%x][0x%x]\n\r",
priv->xsem_rtca->scan_ctrl_status[0],
Will concurrent writes to xsem_scan_control clobber the shared buffers
in priv->xsem_rtca->scan_ctrl_status before either process reads the
attribute, leading to incorrect results?
[ ... ]
> +What: /sys/devices/system/edac/mc/mc0/xsem_read_ssit_status
> +Date: June 2026
> +Contact: rama.devi.veggalam@amd.com
> +Description:
> + It is a read/write file.
> + Writing to this file causes the software to initiate a
> + request to read CRAM and NPI scan status information in a given SLR.
> + User needs to provide SLR id in Versal SSIT device for which
> + XilSEM status to be read. When read, it shows
> + the XilSEM status of the requested SLR.
> + The format is: <Header> <SLR id> <NPI status info> <CRAM status info>
> + Example: Read SLR Status Cmd:[0x1030d]
> + SLR ID:[0x3]
> + NPI status:[0xa01]
[Severity: Medium]
Will this sysfs attribute violate the single-value-per-file guideline?
Looking at xsem_read_ssit_status_show() in drivers/edac/versal_edac.c, it
generates a multiline block instead of a single value:
offset += sprintf(data + offset, "Read SLR Status Cmd:[0x%x]\n\r",
priv->xsem_rtca->xilsem_ssit_status[0]);
offset += sprintf(data + offset, "SLR ID:[0x%x]\n\r",
priv->xsem_rtca->xilsem_ssit_status[1]);
offset += sprintf(data + offset, "NPI status:[0x%x]\n\r",
Does this complex multiline output break standard userspace tools that
parse sysfs?
[ ... ]
> +What: /sys/devices/system/edac/versal_xilsem/xsem_cram_injecterr
> +Date: July 2025
> +Contact: rama.devi.veggalam@amd.com
[Severity: Low]
Are there duplicate and conflicting entries in the documentation?
The path /sys/devices/system/edac/versal_xilsem/xsem_cram_injecterr
listed here appears to conflict with the /sys/devices/system/edac/mc/mc0/
path documented earlier for the same attribute.
> +Description:
> + It is a read/write file.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624212545.2850787-1-rama.devi.veggalam@amd.com?part=2
^ permalink raw reply
* [PATCH v3 4/4] edac: xilinx: Add EDAC support for Versal XilSem
From: Rama devi Veggalam @ 2026-06-24 21:25 UTC (permalink / raw)
To: bp, tony.luck, michal.simek, robh, krzk+dt, conor+dt
Cc: linux-kernel, linux-edac, devicetree, james.morse, mchehab, rric,
git, Rama devi Veggalam
In-Reply-To: <20260624212545.2850787-1-rama.devi.veggalam@amd.com>
Xilinx Versal Soft Error Mitigation (XilSEM) is responsible for reporting
and optionally correcting soft errors in Configuration Memory of Versal.
The Configuration Memory includes Configuration RAM and
Network on Chip (NoC) peripheral interconnect (NPI) Registers.
The Configuration RAM (CRAM) memory is used for storing configuration
data for the programmable logic (PL) fabric. The NPI registers are used
for configuring the memory controllers, miscellaneous integrated hardware,
NoC interface units in the Veral device.
Add support to handle correctable and uncorrectable error events
from XilSEM.
Add sysfs interface for XilSEM scan operations
initialize, start, stop scan, error inject, read ECC, scan status and
configuration values.
Signed-off-by: Rama devi Veggalam <rama.devi.veggalam@amd.com>
---
Changes in v3:
- Merged Versal XilSem edac with Versal edac
Changes in v2:
- Patch created on top of dependent patch series
"enhance zynqmp_pm_get_family_info()"
- Fixed maximum length warning in patch description
- Added details for eprobe_defer conditions
- Updated copyright information
- Removed ARCH_ZYNQMP in dependent list of XilSEM Kconfig
- Added error code for invalid versal device type
- Removed redundant sysfs details in function headers
- Included MAINTAINERS to this patch
- Added more description in commit message
- Removed print for probe success
- Removed function comments for xsem_edac_remove()
---
MAINTAINERS | 1 +
drivers/edac/Kconfig | 4 +-
drivers/edac/versal_edac.c | 1348 +++++++++++++++++++++++++++++++++++-
3 files changed, 1349 insertions(+), 4 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 9b787bc2855f..3109d05c324a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -29585,6 +29585,7 @@ F: include/uapi/linux/xilinx-v4l2-controls.h
XILINX VERSAL EDAC DRIVER
M: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
M: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>
+M: Rama Devi Veggalam <rama.devi.veggalam@amd.com>
S: Maintained
F: Documentation/devicetree/bindings/memory-controllers/xlnx,versal-ddrmc-edac.yaml
F: drivers/edac/versal_edac.c
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index a44b85c440ca..1549dbff3666 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -546,11 +546,11 @@ config EDAC_NPCM
device used to store data is used for ECC storage).
config EDAC_VERSAL
- tristate "Xilinx Versal DDR Memory Controller"
+ tristate "Xilinx Versal DDR Memory Controller and XilSEM"
depends on ARCH_ZYNQMP || COMPILE_TEST
help
Support for error detection and correction on the Xilinx Versal DDR
- memory controller.
+ memory controller and configuration memory of the programmable logic (PL) fabric. Support detection of errors in Network on Chip (NoC) peripheral interconnect (NPI) Registers.
Report both single bit errors (CE) and double bit errors (UE).
Support injecting both correctable and uncorrectable errors
diff --git a/drivers/edac/versal_edac.c b/drivers/edac/versal_edac.c
index 5a43b5d43ca2..024ddd90f699 100644
--- a/drivers/edac/versal_edac.c
+++ b/drivers/edac/versal_edac.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Xilinx Versal memory controller driver
- * Copyright (C) 2023 Advanced Micro Devices, Inc.
+ * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc.
*/
#include <linux/bitfield.h>
#include <linux/edac.h>
@@ -11,12 +11,88 @@
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
#include <linux/sizes.h>
+#include <linux/io.h>
#include <linux/firmware/xlnx-zynqmp.h>
+#include <linux/firmware/xlnx-versal-error-events.h>
#include <linux/firmware/xlnx-event-manager.h>
#include "edac_module.h"
+/* XilSem CE Error log count */
+#define XILSEM_MAX_CE_LOG_CNT 7
+
+/** Maximum CRAM error register count */
+#define MAX_CRAMERR_REG_CNT 14
+/** Maximum NPI slave skip count */
+#define MAX_NPI_SLV_SKIP_CNT 8
+/** Maximum NPI Error info count */
+#define MAX_NPI_ERR_INFO_CNT 2
+
+/* Maximum SLR count */
+#define MAX_SLR_ID 3
+
+/** Maximum number of cframe types */
+#define CFRAME_MAX_TYPE 7
+
+/** Mask for getting Type_0, Type_4 frames */
+#define CFRAME_TYPE_0_4_MASK GENMASK(19, 0)
+
+/** Low mask, High mask for getting Type_1, Type_5 frames */
+#define CFRAME_TYPE_1_5_MASK_L GENMASK(39, 20)
+#define CFRAME_TYPE_1_5_MASK_H GENMASK(7, 0)
+
+/** Shift for getting Type_1, Type_5 frames */
+#define CFRAME_TYPE_1_5_SHIFT_R 0x20
+#define CFRAME_TYPE_1_5_SHIFT_L 0x12
+
+/** Mask for getting Type_2, Type_6 frames */
+#define CFRAME_TYPE_2_6_MASK GENMASK(27, 8)
+
+/** Shift for getting Type_2, Type_6 frames */
+#define CFRAME_TYPE_2_6_SHIFT_R 0x8
+
+/** Low mask, high mask for getting Type_3 frames */
+#define CFRAME_TYPE_3_MASK_L GENMASK(31, 28)
+#define CFRAME_TYPE_3_MASK_H GENMASK(15, 0)
+
+/** Shift for getting Type_3 */
+#define CFRAME_TYPE_3_SHIFT_R 0x28
+#define CFRAME_TYPE_3_SHIFT_L 0x4
+
+/* XilSem_CRAM scan error info registers */
+#define CRAM_STS_INFO_OFFSET 0x34
+#define CRAM_CE_ADDRL0_OFFSET 0x38
+#define CRAM_CE_ADDRH0_OFFSET 0x3C
+#define CRAM_CE_COUNT_OFFSET 0x70
+
+/* XilSem_NPI_Scan uncorrectable error info registers */
+#define NPI_SCAN_COUNT 0x24
+#define NPI_SCAN_HB_COUNT 0x28
+#define NPI_ERR0_INFO_OFFSET 0x2C
+#define NPI_ERR1_INFO_OFFSET 0x30
+
+/* XilSem bit masks for extracting error details */
+#define CRAM_ERR_ROW_MASK GENMASK(26, 23)
+#define CRAM_ERR_BIT_MASK GENMASK(22, 16)
+#define CRAM_ERR_QWRD_MASK GENMASK(27, 23)
+#define CRAM_ERR_FRAME_MASK GENMASK(22, 0)
+
+enum xsem_cmd_id {
+ CRAM_INIT_SCAN = 1, /* To initialize CRAM scan */
+ CRAM_START_SCAN = 2, /* To start CRAM scan */
+ CRAM_STOP_SCAN = 3, /* To stop CRAM scan */
+ CRAM_ERR_INJECT = 4, /* To inject CRAM error */
+ NPI_START_SCAN = 5, /* To start NPI scan */
+ NPI_STOP_SCAN = 6, /* To stop NPI scan */
+ NPI_ERR_INJECT = 7, /* To inject NPI error */
+};
+
+/* XilSem Module IDs */
+#define CRAM_MOD_ID 0x1
+#define NPI_MOD_ID 0x2
+
/* Granularity of reported error in bytes */
#define XDDR_EDAC_ERR_GRAIN 1
@@ -205,6 +281,105 @@ struct ecc_status {
u8 error_type;
};
+/* XILSEM structures */
+/**
+ * struct xsem_ecc_error_info - ECC error log information
+ * @status: CRAM/NPI scan error status
+ * @data0: Checksum of the error descriptor
+ * @data1: Index of the error descriptor
+ * @frame_addr: Frame location at which error occurred
+ * @block_type: Block type
+ * @row_id: Row number
+ * @bit_loc: Bit position in the Qword
+ * @qword: Qword location in the frame
+ */
+struct xsem_ecc_error_info {
+ u32 status;
+ u32 data0;
+ u32 data1;
+ u32 frame_addr;
+ u8 block_type;
+ u8 row_id;
+ u8 bit_loc;
+ u8 qword;
+};
+
+/**
+ * struct xsem_error_status - ECC status information to report
+ * @ce_cnt: Correctable error count
+ * @ue_cnt: Uncorrectable error count
+ * @ceinfo: Correctable error log information
+ * @ueinfo: Uncorrectable error log information
+ */
+struct xsem_error_status {
+ u32 ce_cnt;
+ u32 ue_cnt;
+ struct xsem_ecc_error_info ceinfo;
+ struct xsem_ecc_error_info ueinfo;
+};
+
+/**
+ * struct xsem_ssit_status - SSIT status information
+ * @npi_status: NPI Status
+ * @slvskpcnt: NPI Slave skip count
+ * @scancnt: NPI Scan count
+ * @hbcnt: NPI Heartbeat count
+ * @err_info: NPI Error Information
+ * @cram_status: Cram Status
+ * @err_addr: Address of corrected error location
+ * @errcnt: Corrected Error count.
+ */
+struct xsem_ssit_status {
+ u32 npi_status;
+ u32 slvskpcnt[MAX_NPI_SLV_SKIP_CNT];
+ u32 scancnt;
+ u32 hbcnt;
+ u32 err_info[MAX_NPI_ERR_INFO_CNT];
+ u32 cram_status;
+ u32 err_addr[MAX_CRAMERR_REG_CNT];
+ u32 errcnt;
+};
+
+/**
+ * struct xsem_rtca_priv - Xilsem private instance data
+ * @baseaddr: Base address of the XilSem PLM RTCA module
+ * @cram_get_frames_status: Buffer for get total frames command
+ * @cram_get_crc_status: Buffer for CRC read command
+ * @xilsem_ssit_status: Buffer for SLR status command
+ * @cram_errinj_status: Buffer for CRAM error injection
+ * @cram_total_frames: Buffer for total cframes data
+ * @scan_ctrl_status: Buffer for scan ctrl commands
+ * @cram_frame_ecc: Buffer for CRAM frame ECC
+ * @xilsem_status: Buffer for CRAM & NPI status
+ * @xilsem_cfg: Buffer for CRAM & NPI configuration
+ * @sw_event_node_id: Error event node Id
+ * @cram_ce_mask: Event bit mask for CRAM correctable error
+ * @cram_ue_mask: Event bit mask for CRAM uncorrectable error
+ * @npi_ue_mask: Event bit mask for NPI uncorrectable error
+ * @cram_ce_cnt: Correctable Error count
+ * @cram_ue_cnt: Uncorrectable Error count
+ * @slr_info: Pointer to get SSIT status information
+ */
+struct xsem_rtca_priv {
+ void __iomem *baseaddr;
+ u32 cram_get_frames_status[4];
+ u32 cram_get_crc_status[6];
+ u32 xilsem_ssit_status[4];
+ u32 cram_errinj_status[3];
+ u32 cram_total_frames[7];
+ u32 scan_ctrl_status[7];
+ u32 cram_frame_ecc[4];
+ u32 xilsem_status[4];
+ u32 xilsem_cfg[6];
+ u32 sw_event_node_id;
+ u32 cram_ce_mask;
+ u32 cram_ue_mask;
+ u32 npi_ue_mask;
+ u32 cram_ce_cnt;
+ u32 cram_ue_cnt;
+ struct xsem_ssit_status *slr_info;
+};
+
/**
* struct edac_priv - DDR memory controller private instance data.
* @ddrmc_baseaddr: Base address of the DDR controller.
@@ -227,6 +402,8 @@ struct ecc_status {
struct edac_priv {
void __iomem *ddrmc_baseaddr;
void __iomem *ddrmc_noc_baseaddr;
+ void __iomem *sem_baseaddr;
+ struct xsem_rtca_priv *xsem_rtca;
char message[XDDR_EDAC_MSG_SIZE];
u32 mc_id;
u32 ce_cnt;
@@ -1073,14 +1250,1108 @@ static u32 emif_get_id(struct device_node *node)
return my_id;
}
+/**
+ * xsem_scan_control_show - Shows scan control operation status
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ *
+ * Shows the scan control operations status
+ * Return: Number of bytes copied.
+ */
+static ssize_t xsem_scan_control_show(struct device *dev,
+ struct device_attribute *mattr,
+ char *data)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ return sprintf(data, "[0x%x][0x%x][0x%x][0x%x][0x%x][0x%x][0x%x]\n\r",
+ priv->xsem_rtca->scan_ctrl_status[0],
+ priv->xsem_rtca->scan_ctrl_status[0],
+ priv->xsem_rtca->scan_ctrl_status[1],
+ priv->xsem_rtca->scan_ctrl_status[2],
+ priv->xsem_rtca->scan_ctrl_status[3],
+ priv->xsem_rtca->scan_ctrl_status[4],
+ priv->xsem_rtca->scan_ctrl_status[5]);
+}
+
+/**
+ * xsem_scan_control_store - Set scan control operation
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ * @count: read the size bytes from buffer
+ *
+ * User-space interface for doing Xilsem scan operations
+ * (initialization, start, stop)
+ * Return: count argument if request succeeds, else error code
+ */
+static ssize_t xsem_scan_control_store(struct device *dev,
+ struct device_attribute *mattr,
+ const char *data, size_t count)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+ char *kern_buff, *inbuf, *tok;
+ u32 cmd;
+ u32 slrid;
+ int ret;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ kern_buff = kzalloc(count, GFP_KERNEL);
+ if (!kern_buff)
+ return -ENOMEM;
+ strscpy(kern_buff, data, count);
+
+ inbuf = kern_buff;
+
+ if (!data) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ /* Read Scan command */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &cmd);
+ if (ret) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Read SLR number */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &slrid);
+ if (ret) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (cmd < CRAM_INIT_SCAN || cmd > NPI_ERR_INJECT || cmd == CRAM_ERR_INJECT) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (slrid > MAX_SLR_ID) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = zynqmp_pm_xilsem_cntrl_ops(cmd, slrid, priv->xsem_rtca->scan_ctrl_status);
+err:
+ kfree(kern_buff);
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+/**
+ * xsem_cram_injecterr_show - Shows CRAM error injection status
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ *
+ * Shows CRAM error injection status
+ * Return: Number of bytes copied.
+ */
+static ssize_t xsem_cram_injecterr_show(struct device *dev,
+ struct device_attribute *mattr,
+ char *data)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ return sprintf(data, "[0x%x][0x%x][0x%x]]\n\r",
+ priv->xsem_rtca->cram_errinj_status[0],
+ priv->xsem_rtca->cram_errinj_status[1],
+ priv->xsem_rtca->cram_errinj_status[2]);
+}
+
+/**
+ * xsem_cram_injecterr_store - Start error injection
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ * @count: read the size bytes from buffer
+ *
+ * User-space interface for doing CRAM error injection
+ * Return: count argument if request succeeds, else error code
+ */
+static ssize_t xsem_cram_injecterr_store(struct device *dev,
+ struct device_attribute *mattr,
+ const char *data, size_t count)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+ char *kern_buff, *inbuf, *tok;
+ u32 row, frame, qword, bitloc, slrid;
+ int ret;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ kern_buff = kzalloc(count, GFP_KERNEL);
+ if (!kern_buff)
+ return -ENOMEM;
+
+ strscpy(kern_buff, data, count);
+
+ inbuf = kern_buff;
+
+ /* Read Frame number */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &frame);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ /* Read Qword number */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &qword);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ /* Read Bit location */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &bitloc);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ /* Read Row number */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &row);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ /* Read slr id */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &slrid);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ if (slrid > MAX_SLR_ID) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = zynqmp_pm_xilsem_cram_errinj(slrid, frame, qword, bitloc, row,
+ priv->xsem_rtca->cram_errinj_status);
+err:
+ kfree(kern_buff);
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+/**
+ * xsem_cram_framecc_read_show - Shows CRAM Frame ECC
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ *
+ * Shows CRAM Frame ECC value
+ * Return: Number of bytes copied.
+ */
+static ssize_t xsem_cram_framecc_read_show(struct device *dev,
+ struct device_attribute *mattr,
+ char *data)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+ int offset = 0;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ offset += sprintf(data + offset, "Read Frame ECC Cmd: [0x%x]\n\r",
+ priv->xsem_rtca->cram_frame_ecc[0]);
+ offset += sprintf(data + offset, "Frame ECC Word_0: [0x%x]\n\r",
+ priv->xsem_rtca->cram_frame_ecc[1]);
+ offset += sprintf(data + offset, "Frame ECC Word_1: [0x%x]\n\r",
+ priv->xsem_rtca->cram_frame_ecc[2]);
+ offset += sprintf(data + offset, "Cmd Status: [0x%x]\n\r",
+ priv->xsem_rtca->cram_frame_ecc[3]);
+
+ return offset;
+}
+
+/**
+ * xsem_cram_framecc_read_store - Read CRAM Frame ECC
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ * @count: read the size bytes from buffer
+ *
+ * User-space interface for reading CRAM frame ECC
+ * Return: count argument if request succeeds, else error code
+ */
+static ssize_t xsem_cram_framecc_read_store(struct device *dev,
+ struct device_attribute *mattr,
+ const char *data, size_t count)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+ char *kern_buff, *inbuf, *tok;
+ u32 frameaddr, row, slrid;
+ int ret;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ kern_buff = kzalloc(count, GFP_KERNEL);
+ if (!kern_buff)
+ return -ENOMEM;
+
+ strscpy(kern_buff, data, count);
+
+ inbuf = kern_buff;
+
+ /* Read Frame address */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &frameaddr);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ /* Read Row number */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &row);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ /* Read slr id */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &slrid);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ if (slrid > MAX_SLR_ID) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = zynqmp_pm_xilsem_cram_readecc(slrid, frameaddr, row,
+ priv->xsem_rtca->cram_frame_ecc);
+err:
+ kfree(kern_buff);
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+/**
+ * xsem_cram_ssit_getcrc_show - Shows CRAM Row CRC
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ *
+ * Shows CRAM Row CRC value
+ * Return: Number of bytes copied.
+ */
+static ssize_t xsem_cram_ssit_getcrc_show(struct device *dev,
+ struct device_attribute *mattr,
+ char *data)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+ int offset = 0;
+ u32 id;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ offset += sprintf(data + offset, "Read CRC Cmd:[0x%x]\n\r",
+ priv->xsem_rtca->cram_get_crc_status[0]);
+ for (id = 0; id < 4; id++)
+ offset += sprintf(data + offset, "CRC_Word %d:[0x%x]\n\r", id,
+ priv->xsem_rtca->cram_get_crc_status[id + 1]);
+ offset += sprintf(data + offset, "Cmd status: [0x%x]\n\r",
+ priv->xsem_rtca->cram_get_crc_status[5]);
+
+ return offset;
+}
+
+/**
+ * xsem_cram_ssit_getcrc_store - Read CRAM row CRC
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ * @count: read the size bytes from buffer
+ *
+ * User-space interface for reading CRAM row CRC
+ * Return: count argument if request succeeds, else error code
+ */
+static ssize_t xsem_cram_ssit_getcrc_store(struct device *dev,
+ struct device_attribute *mattr,
+ const char *data, size_t count)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+ char *kern_buff, *inbuf, *tok;
+ u32 rowindex, slrid;
+ int ret;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ kern_buff = kzalloc(count, GFP_KERNEL);
+ if (!kern_buff)
+ return -ENOMEM;
+
+ strscpy(kern_buff, data, count);
+
+ inbuf = kern_buff;
+
+ /* Read Row number */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &rowindex);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ /* Read SLR Id */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &slrid);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ if (slrid > MAX_SLR_ID) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = zynqmp_pm_xilsem_cram_getcrc(slrid, rowindex,
+ priv->xsem_rtca->cram_get_crc_status);
+err:
+ kfree(kern_buff);
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+/**
+ * xsem_total_cframes_ssit_show - Shows total cframes
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ *
+ * Shows CRAM total cframes
+ * Return: Number of bytes copied.
+ */
+static ssize_t xsem_total_cframes_ssit_show(struct device *dev,
+ struct device_attribute *mattr,
+ char *data)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+ u32 temp_buf[CFRAME_MAX_TYPE] = {0};
+ u32 id;
+ int offset = 0;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ for (id = 0; id < CFRAME_MAX_TYPE; id++)
+ temp_buf[id] = priv->xsem_rtca->cram_total_frames[id];
+
+ priv->xsem_rtca->cram_total_frames[0] = (temp_buf[0] & CFRAME_TYPE_0_4_MASK);
+ priv->xsem_rtca->cram_total_frames[1] = (temp_buf[0] &
+ CFRAME_TYPE_1_5_MASK_L) >> CFRAME_TYPE_1_5_SHIFT_R;
+ priv->xsem_rtca->cram_total_frames[1] |= (temp_buf[1] &
+ CFRAME_TYPE_1_5_MASK_H) << CFRAME_TYPE_1_5_SHIFT_L;
+ priv->xsem_rtca->cram_total_frames[2] = (temp_buf[1] &
+ CFRAME_TYPE_2_6_MASK) >> CFRAME_TYPE_2_6_SHIFT_R;
+ priv->xsem_rtca->cram_total_frames[3] = (temp_buf[1] &
+ CFRAME_TYPE_3_MASK_L) >> CFRAME_TYPE_3_SHIFT_R;
+ priv->xsem_rtca->cram_total_frames[3] |= (temp_buf[2] &
+ CFRAME_TYPE_3_MASK_H) << CFRAME_TYPE_3_SHIFT_L;
+ priv->xsem_rtca->cram_total_frames[4] = (temp_buf[4] & CFRAME_TYPE_0_4_MASK);
+ priv->xsem_rtca->cram_total_frames[5] = (temp_buf[4] &
+ CFRAME_TYPE_1_5_MASK_L) >> CFRAME_TYPE_1_5_SHIFT_R;
+ priv->xsem_rtca->cram_total_frames[5] |= (temp_buf[5] &
+ CFRAME_TYPE_1_5_MASK_H) << CFRAME_TYPE_1_5_SHIFT_L;
+ priv->xsem_rtca->cram_total_frames[6] = (temp_buf[5] &
+ CFRAME_TYPE_2_6_MASK) >> CFRAME_TYPE_2_6_SHIFT_R;
+
+ offset += sprintf(data + offset, "Read Total Frames Cmd : [0x%x]\n\r",
+ priv->xsem_rtca->cram_get_frames_status[0]);
+ offset += sprintf(data + offset, "SLR ID : [0x%x]\n\r",
+ priv->xsem_rtca->cram_get_frames_status[1]);
+ offset += sprintf(data + offset, "Row Index: [0x%x]\n\r",
+ priv->xsem_rtca->cram_get_frames_status[2]);
+ for (id = 0; id < CFRAME_MAX_TYPE; id++)
+ offset += sprintf(data + offset, "Type[%d] frame count: [%d]\n\r", id,
+ priv->xsem_rtca->cram_total_frames[id]);
+
+ offset += sprintf(data + offset, "Cmd Status: [0x%x]\n\r",
+ priv->xsem_rtca->cram_get_frames_status[3]);
+ return offset;
+}
+
+/**
+ * xsem_total_cframes_ssit_store - Read total cframes in CRAM
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ * @count: read the size bytes from buffer
+ *
+ * User-space interface for reading CRAM total frames in ssit device
+ * Return: count argument if request succeeds, else error code
+ */
+static ssize_t xsem_total_cframes_ssit_store(struct device *dev,
+ struct device_attribute *mattr,
+ const char *data, size_t count)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+ char *kern_buff, *inbuf, *tok, *kbuf1;
+ dma_addr_t dma_addr = 0;
+ u32 row, slrid, dma_size;
+ int ret;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ kern_buff = kzalloc(count, GFP_KERNEL);
+ if (!kern_buff)
+ return -ENOMEM;
+
+ strscpy(kern_buff, data, count);
+
+ inbuf = kern_buff;
+
+ /* Read Row number */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &row);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ /* Read slr id */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &slrid);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ if (slrid > MAX_SLR_ID || row > 4) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ dma_size = sizeof(priv->xsem_rtca->cram_total_frames);
+ kbuf1 = dma_alloc_coherent(dev, dma_size, &dma_addr, GFP_KERNEL);
+ if (!kbuf1) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = zynqmp_pm_xilsem_cram_ssit_totframes(slrid, row, dma_addr,
+ priv->xsem_rtca->cram_get_frames_status);
+ if (ret) {
+ edac_printk(KERN_ERR, EDAC_MC, "ERROR: XilSEM Status PM API failed\n");
+ dma_free_coherent(dev, dma_size, kbuf1, dma_addr);
+ goto err;
+ }
+
+ memcpy(priv->xsem_rtca->cram_total_frames, kbuf1, dma_size);
+ dma_free_coherent(dev, dma_size, kbuf1, dma_addr);
+
+err:
+ kfree(kern_buff);
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+/**
+ * xsem_read_status_show - Shows CRAM & NPI scan status
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ *
+ * Shows CRAM & NPI scan status
+ * Return: Number of bytes copied.
+ */
+static ssize_t xsem_read_status_show(struct device *dev,
+ struct device_attribute *mattr,
+ char *data)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ return sprintf(data, "[0x%x][0x%x][0x%x]\n\r",
+ priv->xsem_rtca->xilsem_status[0],
+ priv->xsem_rtca->xilsem_status[1],
+ priv->xsem_rtca->xilsem_status[2]);
+}
+
+/**
+ * xsem_read_status_store - Read CRAM & NPI scan status
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ * @count: read the size bytes from buffer
+ *
+ * User-space interface for reading Xilsem status
+ * Return: count argument if read succeeds, else error code
+ */
+static ssize_t xsem_read_status_store(struct device *dev,
+ struct device_attribute *mattr,
+ const char *data, size_t count)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+ u32 module;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ if (!data)
+ return -EFAULT;
+
+ if (kstrtouint(data, 0, &module))
+ return -EINVAL;
+
+ if (module == CRAM_MOD_ID) {
+ if (priv->sem_baseaddr) {
+ priv->xsem_rtca->xilsem_status[0] = readl(priv->sem_baseaddr +
+ CRAM_STS_INFO_OFFSET);
+ priv->xsem_rtca->xilsem_status[1] = readl(priv->sem_baseaddr +
+ CRAM_CE_COUNT_OFFSET);
+ priv->xsem_rtca->xilsem_status[2] = 0;
+ }
+ } else if (module == NPI_MOD_ID) {
+ if (priv->sem_baseaddr) {
+ priv->xsem_rtca->xilsem_status[0] = readl(priv->sem_baseaddr);
+ priv->xsem_rtca->xilsem_status[1] = readl(priv->sem_baseaddr +
+ NPI_SCAN_COUNT);
+ priv->xsem_rtca->xilsem_status[2] = readl(priv->sem_baseaddr +
+ NPI_SCAN_HB_COUNT);
+ }
+ } else {
+ edac_printk(KERN_ERR, EDAC_MC, "Invalid module %d\n", module);
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+/**
+ * xsem_read_ssit_status_show - Shows CRAM & NPI scan for SSIT device
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ *
+ * Shows CRAM & NPI scan status for given SLR
+ * Return: Number of bytes copied.
+ */
+static ssize_t xsem_read_ssit_status_show(struct device *dev,
+ struct device_attribute *mattr,
+ char *data)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+ int offset = 0;
+ int id;
+
+ if (!priv->xsem_rtca || !priv->xsem_rtca->slr_info)
+ return -EINVAL;
+
+ offset += sprintf(data + offset, "Read SLR Status Cmd:[0x%x]\n\r",
+ priv->xsem_rtca->xilsem_ssit_status[0]);
+ offset += sprintf(data + offset, "SLR ID:[0x%x]\n\r",
+ priv->xsem_rtca->xilsem_ssit_status[1]);
+ offset += sprintf(data + offset, "NPI status:[0x%x]\n\r",
+ priv->xsem_rtca->slr_info->npi_status);
+ offset += sprintf(data + offset, "NPI scan count:[0x%x]\n\r",
+ priv->xsem_rtca->slr_info->scancnt);
+ offset += sprintf(data + offset, "NPI Heartbeat count:[0x%x]\n\r",
+ priv->xsem_rtca->slr_info->hbcnt);
+ for (id = 0; id < MAX_NPI_SLV_SKIP_CNT; id++)
+ offset += sprintf(data + offset, "NPI scan skip count %x :[0x%x]\n\r", id,
+ priv->xsem_rtca->slr_info->slvskpcnt[id]);
+
+ for (id = 0; id < MAX_NPI_ERR_INFO_CNT; id++)
+ offset += sprintf(data + offset, "NPI error info %x :[0x%x]\n\r", id,
+ priv->xsem_rtca->slr_info->err_info[id]);
+
+ offset += sprintf(data + offset, "CRAM status:[0x%x]\n\r",
+ priv->xsem_rtca->slr_info->cram_status);
+
+ for (id = 0U; id < 7; id++) {
+ offset += sprintf(data + offset, "Error Location High %x: [0x%x]\n\r", id,
+ priv->xsem_rtca->slr_info->err_addr[(id * 2) + 1]);
+ offset += sprintf(data + offset, "Error Location Low %x: [0x%x]\n\r", id,
+ priv->xsem_rtca->slr_info->err_addr[id * 2]);
+ }
+ offset += sprintf(data + offset, "CRAM scan CE count:[0x%x]\n\r",
+ priv->xsem_rtca->slr_info->errcnt);
+
+ return offset;
+}
+
+/**
+ * xsem_read_ssit_status_store - Read CRAM & NPI scan SSIT status
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ * @count: read the size bytes from buffer
+ *
+ * User-space interface for reading Xilsem status for SSIT device
+ * Return: count argument if read succeeds, else error code
+ */
+static ssize_t xsem_read_ssit_status_store(struct device *dev,
+ struct device_attribute *mattr,
+ const char *data, size_t count)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+ char *kern_buff, *inbuf, *tok, *kbuf1;
+ size_t dma_size;
+ dma_addr_t dma_addr = 0;
+ u32 slrid;
+ int ret;
+
+ if (!priv->xsem_rtca || !priv->xsem_rtca->slr_info)
+ return -EINVAL;
+
+ kern_buff = kzalloc(count, GFP_KERNEL);
+ if (!kern_buff)
+ return -ENOMEM;
+
+ strscpy(kern_buff, data, count);
+
+ inbuf = kern_buff;
+
+ /* Read SLR ID */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &slrid);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ if (slrid > MAX_SLR_ID) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ dma_size = sizeof(struct xsem_ssit_status);
+
+ kbuf1 = dma_alloc_coherent(dev, dma_size, &dma_addr, GFP_KERNEL);
+ if (!kbuf1) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = zynqmp_pm_xilsem_read_ssit_status(slrid, dma_addr,
+ priv->xsem_rtca->xilsem_ssit_status);
+ if (ret) {
+ edac_printk(KERN_ERR, EDAC_MC, "ERROR: XilSEM Status PM API failed\n");
+ dma_free_coherent(dev, dma_size, kbuf1, dma_addr);
+ goto err;
+ }
+
+ memcpy(priv->xsem_rtca->slr_info, kbuf1, dma_size);
+
+ dma_free_coherent(dev, dma_size, kbuf1, dma_addr);
+err:
+ kfree(kern_buff);
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+/**
+ * xsem_read_config_show - Shows CRAM & NPI configuration
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ *
+ * Shows CRAM & NPI configuration
+ * Return: Number of bytes copied.
+ */
+static ssize_t xsem_read_config_show(struct device *dev,
+ struct device_attribute *mattr,
+ char *data)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+ int offset = 0;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ offset += sprintf(data + offset, "Read Config Cmd: [0x%x]\n\r",
+ priv->xsem_rtca->xilsem_cfg[0]);
+ offset += sprintf(data + offset, "CRAM Scan Config: [0x%x]\n\r",
+ priv->xsem_rtca->xilsem_cfg[1]);
+ offset += sprintf(data + offset, "NPI Scan Config: [0x%x]\n\r",
+ priv->xsem_rtca->xilsem_cfg[2]);
+ offset += sprintf(data + offset, "Cmd Status: [0x%x]\n\r",
+ priv->xsem_rtca->xilsem_cfg[3]);
+
+ return offset;
+}
+
+/**
+ * xsem_read_config_store - Read CRAM & NPI configuration
+ * @dev: Pointer to the device struct
+ * @mattr: Pointer to device attribute
+ * @data: Pointer to user data
+ * @count: read the size bytes from buffer
+ *
+ * User-space interface for reading Xilsem configuration
+ * Return: count argument if request succeeds, else error code
+ */
+static ssize_t xsem_read_config_store(struct device *dev,
+ struct device_attribute *mattr,
+ const char *data, size_t count)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct edac_priv *priv = mci->pvt_info;
+ char *kern_buff, *inbuf, *tok;
+ u32 slrid;
+ int ret;
+
+ if (!priv->xsem_rtca)
+ return -EINVAL;
+
+ kern_buff = kzalloc(count, GFP_KERNEL);
+ if (!kern_buff)
+ return -ENOMEM;
+
+ strscpy(kern_buff, data, count);
+
+ inbuf = kern_buff;
+
+ /* Read SLR id */
+ tok = strsep(&inbuf, " ");
+ if (!tok) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = kstrtouint(tok, 0, &slrid);
+ if (ret) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ if (slrid > MAX_SLR_ID) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = zynqmp_pm_xilsem_read_cfg(slrid, priv->xsem_rtca->xilsem_cfg);
+
+err:
+ kfree(kern_buff);
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+/**
+ * xsem_geterror_info - Get the current ecc error info
+ * @mci: Pointer to the memory controller instance
+ * @p: Pointer to the Xilsem error status structure
+ * @mask: mask indicates the error type
+ *
+ * Determines there is any ecc error or not
+ */
+static void xsem_geterror_info(struct mem_ctl_info *mci, struct xsem_error_status *p,
+ int mask)
+{
+ struct edac_priv *priv = mci->pvt_info;
+ u32 error_word_0, error_word_1, ce_count;
+ u8 index;
+
+ if (!priv->xsem_rtca || !priv->sem_baseaddr)
+ return;
+
+ if (mask & priv->xsem_rtca->cram_ce_mask) {
+ p->ce_cnt++;
+
+ /* Read CRAM total correctable error count */
+ ce_count = readl(priv->sem_baseaddr + CRAM_CE_COUNT_OFFSET);
+ /* Calculate index for error log */
+ index = (ce_count % XILSEM_MAX_CE_LOG_CNT);
+ /*
+ * Check if addr index is not 0
+ * if yes, then decrement index, else set index as last entry
+ */
+ if (index != 0U) {
+ /* Decrement Index */
+ --index;
+ } else {
+ /* Set log index to 6 (Max-1) */
+ index = (XILSEM_MAX_CE_LOG_CNT - 1);
+ }
+ error_word_0 = readl(priv->sem_baseaddr + CRAM_CE_ADDRL0_OFFSET + (index * 8U));
+ error_word_1 = readl(priv->sem_baseaddr + CRAM_CE_ADDRH0_OFFSET + (index * 8U));
+
+ /* Frame is at 22:0 bits of SEM_CRAMERR_ADDRH0 reg */
+ p->ceinfo.frame_addr = FIELD_GET(CRAM_ERR_FRAME_MASK, error_word_1);
+
+ /* row is at 26:23 bits of SEM_CRAMERR_ADDRH0 reg */
+ p->ceinfo.row_id = FIELD_GET(CRAM_ERR_ROW_MASK, error_word_1);
+
+ /* bit is at 22:16 bits of SEM_CRAMERR_ADDRL0 reg */
+ p->ceinfo.bit_loc = FIELD_GET(CRAM_ERR_BIT_MASK, error_word_0);
+
+ /* Qword is at 27:23 bits of SEM_CRAMERR_ADDRL0 reg */
+ p->ceinfo.qword = FIELD_GET(CRAM_ERR_QWRD_MASK, error_word_0);
+
+ /* Read CRAM status */
+ p->ceinfo.status = readl(priv->sem_baseaddr + CRAM_STS_INFO_OFFSET);
+ } else if (mask & priv->xsem_rtca->cram_ue_mask) {
+ p->ue_cnt++;
+ p->ueinfo.data0 = 0;
+ p->ueinfo.data1 = 0;
+ p->ueinfo.status = readl(priv->sem_baseaddr + CRAM_STS_INFO_OFFSET);
+ } else if (mask & priv->xsem_rtca->npi_ue_mask) {
+ p->ue_cnt++;
+ p->ueinfo.data0 = readl(priv->sem_baseaddr + NPI_ERR0_INFO_OFFSET);
+ p->ueinfo.data1 = readl(priv->sem_baseaddr + NPI_ERR1_INFO_OFFSET);
+ p->ueinfo.status = readl(priv->sem_baseaddr);
+ } else {
+ edac_printk(KERN_ERR, EDAC_MC, "Invalid Event received %d\n", mask);
+ }
+}
+
+/**
+ * xsem_handle_error - Handle XilSem error types CE and UE
+ * @mci: Pointer to the memory controller instance
+ * @p: Pointer to the xilsem error status structure
+ *
+ * Handles the correctable and uncorrectable error.
+ */
+static void xsem_handle_error(struct mem_ctl_info *mci, struct xsem_error_status *p)
+{
+ struct xsem_ecc_error_info *pinf;
+ char message[XDDR_EDAC_MSG_SIZE];
+
+ if (p->ce_cnt) {
+ pinf = &p->ceinfo;
+ snprintf(message, XDDR_EDAC_MSG_SIZE,
+ "\n\rXILSEM CRAM error type :%s\n\r"
+ "\nFrame_Addr: [0x%X]\t Row_num: [0x%X]\t Bit_loc: [0x%X]\t Qword: [0x%X]\n\r",
+ "CE", pinf->frame_addr, pinf->row_id,
+ pinf->bit_loc, pinf->qword);
+
+ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+ p->ce_cnt, 0, 0, 0, 0, 0, -1,
+ message, "");
+ }
+
+ if (p->ue_cnt) {
+ pinf = &p->ueinfo;
+ snprintf(message, XDDR_EDAC_MSG_SIZE,
+ "\n\rXILSEM error type :%s\n\r"
+ "status: [0x%X]\n\rError_Info0: [0x%X]\n\r"
+ "Error_Info1: [0x%X]",
+ "UE", pinf->status, pinf->data0, pinf->data1);
+
+ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+ p->ue_cnt, 0, 0, 0, 0, 0, -1,
+ message, "");
+ }
+}
+
+/**
+ * xsem_err_callback - Handle Correctable and Uncorrectable errors.
+ * @payload: payload data.
+ * @data: controller data.
+ *
+ * Handles ECC correctable and uncorrectable errors.
+ */
+static void xsem_err_callback(const u32 *payload, void *data)
+{
+ struct xsem_error_status stat;
+ struct edac_priv *priv;
+ struct mem_ctl_info *mci = (struct mem_ctl_info *)data;
+ int event;
+
+ priv = mci->pvt_info;
+ if (!priv->xsem_rtca)
+ return;
+
+ memset(&stat, 0, sizeof(stat));
+ /* Read payload to get the event type */
+ event = payload[2];
+ edac_printk(KERN_INFO, EDAC_MC, "Event received %x\n", event);
+ xsem_geterror_info(mci, &stat, event);
+
+ priv->xsem_rtca->cram_ce_cnt += stat.ce_cnt;
+ priv->xsem_rtca->cram_ue_cnt += stat.ue_cnt;
+ xsem_handle_error(mci, &stat);
+}
+
+static DEVICE_ATTR_RW(xsem_scan_control);
+static DEVICE_ATTR_RW(xsem_cram_injecterr);
+static DEVICE_ATTR_RW(xsem_cram_framecc_read);
+static DEVICE_ATTR_RW(xsem_cram_ssit_getcrc);
+static DEVICE_ATTR_RW(xsem_read_status);
+static DEVICE_ATTR_RW(xsem_read_ssit_status);
+static DEVICE_ATTR_RW(xsem_total_cframes_ssit);
+static DEVICE_ATTR_RW(xsem_read_config);
+
+static struct attribute *xsem_edac_sysfs_attrs[] = {
+ &dev_attr_xsem_scan_control.attr,
+ &dev_attr_xsem_cram_injecterr.attr,
+ &dev_attr_xsem_cram_framecc_read.attr,
+ &dev_attr_xsem_cram_ssit_getcrc.attr,
+ &dev_attr_xsem_read_status.attr,
+ &dev_attr_xsem_read_ssit_status.attr,
+ &dev_attr_xsem_total_cframes_ssit.attr,
+ &dev_attr_xsem_read_config.attr,
+ NULL,
+};
+
+static const struct attribute_group xsem_edac_sysfs_attr_group = {
+ .attrs = xsem_edac_sysfs_attrs,
+};
+
+static int xsem_edac_create_sysfs_attributes(struct mem_ctl_info *mci)
+{
+ return sysfs_create_group(&mci->dev.kobj, &xsem_edac_sysfs_attr_group);
+}
+
+static void xsem_edac_remove_sysfs_attributes(struct mem_ctl_info *mci)
+{
+ sysfs_remove_group(&mci->dev.kobj, &xsem_edac_sysfs_attr_group);
+}
+
static int mc_probe(struct platform_device *pdev)
{
- void __iomem *ddrmc_baseaddr, *ddrmc_noc_baseaddr;
+ void __iomem *ddrmc_baseaddr, *ddrmc_noc_baseaddr, *sem_baseaddr;
struct edac_mc_layer layers[2];
struct mem_ctl_info *mci;
u8 num_chans, num_csrows;
struct edac_priv *priv;
u32 edac_mc_id, regval;
+ u32 family_code;
int rc;
ddrmc_baseaddr = devm_platform_ioremap_resource_byname(pdev, "base");
@@ -1094,6 +2365,10 @@ static int mc_probe(struct platform_device *pdev)
if (!get_ecc_state(ddrmc_baseaddr))
return -ENXIO;
+ sem_baseaddr = devm_platform_ioremap_resource_byname(pdev, "semrtca");
+ if (IS_ERR(sem_baseaddr))
+ return PTR_ERR(sem_baseaddr);
+
/* Allocate ID number for the EMIF controller */
edac_mc_id = emif_get_id(pdev->dev.of_node);
@@ -1124,9 +2399,29 @@ static int mc_probe(struct platform_device *pdev)
priv = mci->pvt_info;
priv->ddrmc_baseaddr = ddrmc_baseaddr;
priv->ddrmc_noc_baseaddr = ddrmc_noc_baseaddr;
+ priv->sem_baseaddr = sem_baseaddr;
priv->ce_cnt = 0;
priv->ue_cnt = 0;
priv->mc_id = edac_mc_id;
+ priv->xsem_rtca = NULL;
+
+ /* Allocate and initialize XilSem RTCA structure */
+ priv->xsem_rtca = devm_kzalloc(&pdev->dev,
+ sizeof(struct xsem_rtca_priv),
+ GFP_KERNEL);
+ if (!priv->xsem_rtca) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Failed to allocate xsem_rtca\n");
+ rc = -ENOMEM;
+ goto free_edac_mc;
+ }
+
+ priv->xsem_rtca->slr_info = devm_kzalloc(&pdev->dev, sizeof(struct xsem_ssit_status),
+ GFP_KERNEL);
+ if (!priv->xsem_rtca->slr_info) {
+ rc = -ENOMEM;
+ goto free_edac_mc;
+ }
mc_init(mci, pdev);
@@ -1147,6 +2442,41 @@ static int mc_probe(struct platform_device *pdev)
goto del_mc;
}
+ /* Create XilSem sysfs attributes only if XilSem is available */
+ rc = xsem_edac_create_sysfs_attributes(mci);
+ if (rc) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Failed to create sysfs entries\n");
+ goto remove_sysfs;
+ }
+
+ /*
+ * Firmware driver returns -ENODEV if it is not probed. In this case
+ * defer XilSEM error event registration.
+ */
+ rc = zynqmp_pm_get_family_info(&family_code);
+ if (rc) {
+ if (rc == -ENODEV)
+ rc = -EPROBE_DEFER;
+
+ goto del_mc;
+ }
+ if (family_code == PM_VERSAL_FAMILY_CODE) {
+ priv->xsem_rtca->sw_event_node_id = VERSAL_EVENT_ERROR_SW_ERR;
+ priv->xsem_rtca->cram_ce_mask = XPM_VERSAL_EVENT_ERROR_MASK_XSEM_CRAM_CE_5;
+ priv->xsem_rtca->cram_ue_mask = XPM_VERSAL_EVENT_ERROR_MASK_XSEM_CRAM_UE_6;
+ priv->xsem_rtca->npi_ue_mask = XPM_VERSAL_EVENT_ERROR_MASK_XSEM_NPI_UE_7;
+ } else {
+ edac_printk(KERN_ERR, EDAC_MC, "Invalid Device family code %d\n", family_code);
+ }
+
+ rc = xlnx_register_event(PM_NOTIFY_CB, priv->xsem_rtca->sw_event_node_id,
+ priv->xsem_rtca->cram_ce_mask | priv->xsem_rtca->cram_ue_mask |
+ priv->xsem_rtca->npi_ue_mask,
+ false, xsem_err_callback, mci);
+ if (rc)
+ goto del_mc;
+
#ifdef CONFIG_EDAC_DEBUG
create_debugfs_attributes(mci);
setup_address_map(priv);
@@ -1154,6 +2484,8 @@ static int mc_probe(struct platform_device *pdev)
enable_intr(priv);
return rc;
+remove_sysfs:
+ xsem_edac_remove_sysfs_attributes(mci);
del_mc:
edac_mc_del_mc(&pdev->dev);
free_edac_mc:
@@ -1173,9 +2505,21 @@ static void mc_remove(struct platform_device *pdev)
debugfs_remove_recursive(priv->debugfs);
#endif
+ /* Unregister XilSem events if they were registered */
+ if (priv->xsem_rtca) {
+ xlnx_unregister_event(PM_NOTIFY_CB, priv->xsem_rtca->sw_event_node_id,
+ priv->xsem_rtca->cram_ce_mask |
+ priv->xsem_rtca->cram_ue_mask |
+ priv->xsem_rtca->npi_ue_mask,
+ xsem_err_callback, mci);
+ }
xlnx_unregister_event(PM_NOTIFY_CB, VERSAL_EVENT_ERROR_PMC_ERR1,
XPM_EVENT_ERROR_MASK_DDRMC_CR |
XPM_EVENT_ERROR_MASK_DDRMC_NCR, err_callback, mci);
+ /* Remove XilSem sysfs attributes if they were created */
+ if (priv->xsem_rtca)
+ xsem_edac_remove_sysfs_attributes(mci);
+
edac_mc_del_mc(&pdev->dev);
edac_mc_free(mci);
}
--
2.23.0
^ permalink raw reply related
* [PATCH v3 3/4] firmware: xilinx: Add support for Xilsem scan operations
From: Rama devi Veggalam @ 2026-06-24 21:25 UTC (permalink / raw)
To: bp, tony.luck, michal.simek, robh, krzk+dt, conor+dt
Cc: linux-kernel, linux-edac, devicetree, james.morse, mchehab, rric,
git, Rama devi Veggalam
In-Reply-To: <20260624212545.2850787-1-rama.devi.veggalam@amd.com>
Add the ATF EEMI call support for Xilsem scan operations.
Initialize, start, stop scan, error inject, read configuration,
status and register for software error events.
Add macros for XilSem correctable and uncorrectable error events.
Signed-off-by: Rama devi Veggalam <rama.devi.veggalam@amd.com>
---
Changes in v3:
- created separate file for Xilsem ATF EEMI calls.
Changes in v2:
- Patch created on top of dependent patch series
"enhance zynqmp_pm_get_family_info()"
- Removed non-relevant SOB names in error event header files
- Updated copyright information
- Merged Versal and Versal NET error event definitions to firmware
patch
---
drivers/firmware/xilinx/Makefile | 2 +-
drivers/firmware/xilinx/zynqmp-sem.c | 176 ++++++++++++++++++
drivers/soc/xilinx/xlnx_event_manager.c | 6 +-
.../linux/firmware/xlnx-versal-error-events.h | 43 +++++
include/linux/firmware/xlnx-zynqmp-sem.h | 69 +++++++
include/linux/firmware/xlnx-zynqmp.h | 1 +
6 files changed, 294 insertions(+), 3 deletions(-)
create mode 100644 drivers/firmware/xilinx/zynqmp-sem.c
create mode 100644 include/linux/firmware/xlnx-versal-error-events.h
create mode 100644 include/linux/firmware/xlnx-zynqmp-sem.h
diff --git a/drivers/firmware/xilinx/Makefile b/drivers/firmware/xilinx/Makefile
index 8db0e66b6b7e..f9380c8931ae 100644
--- a/drivers/firmware/xilinx/Makefile
+++ b/drivers/firmware/xilinx/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for Xilinx firmwares
-obj-$(CONFIG_ZYNQMP_FIRMWARE) += zynqmp.o zynqmp-ufs.o zynqmp-crypto.o
+obj-$(CONFIG_ZYNQMP_FIRMWARE) += zynqmp.o zynqmp-sem.o zynqmp-ufs.o zynqmp-crypto.o
obj-$(CONFIG_ZYNQMP_FIRMWARE_DEBUG) += zynqmp-debug.o
diff --git a/drivers/firmware/xilinx/zynqmp-sem.c b/drivers/firmware/xilinx/zynqmp-sem.c
new file mode 100644
index 000000000000..5cd399b165f5
--- /dev/null
+++ b/drivers/firmware/xilinx/zynqmp-sem.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Firmware layer for XilSEM APIs.
+ *
+ * Copyright (C), 2026 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/export.h>
+#include <linux/firmware/xlnx-zynqmp.h>
+
+/**
+ * zynqmp_pm_xilsem_cntrl_ops - PM call to perform XilSEM operations
+ * @cmd: Command for XilSEM scan control operations
+ * @slrid: SLR id on which scan operation to be done
+ * @response: Output response (command header, error code or status, slr id)
+ *
+ * Return: Returns 0 on success or error value on failure.
+ */
+int zynqmp_pm_xilsem_cntrl_ops(u32 cmd, u32 slrid, u32 *const response)
+{
+ u32 ret_buf[PAYLOAD_ARG_CNT];
+ int ret;
+
+ ret = zynqmp_pm_invoke_fn(PM_XSEM_HEADER | cmd, ret_buf, 1, slrid);
+ response[0] = ret_buf[1];
+ response[1] = ret_buf[2];
+ response[2] = ret_buf[3];
+ response[3] = ret_buf[4];
+ response[4] = ret_buf[5];
+ response[5] = ret_buf[6];
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_xilsem_cntrl_ops);
+
+/**
+ * zynqmp_pm_xilsem_cram_errinj - PM call to perform CRAM error injection
+ * @slrid: SLR id to inject error in CRAM
+ * @frame: Frame number to be used for error injection
+ * @qword: Word number to be used for error injection
+ * @bit: Bit location to be used for error injection
+ * @row: CFRAME row number to be used for error injection
+ * @response: Output response (command header, error code or status, slr id)
+ *
+ * Return: Returns 0 on success or error value on failure.
+ */
+int zynqmp_pm_xilsem_cram_errinj(u32 slrid, u32 frame, u32 qword, u32 bit, u32 row,
+ u32 *const response)
+{
+ u32 ret_buf[PAYLOAD_ARG_CNT];
+ int ret;
+
+ ret = zynqmp_pm_invoke_fn(PM_XSEM_CRAM_ERRINJ, ret_buf, 5, slrid, frame, qword, bit, row);
+ response[0] = ret_buf[1];
+ response[1] = ret_buf[2];
+ response[2] = ret_buf[3];
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_xilsem_cram_errinj);
+
+/**
+ * zynqmp_pm_xilsem_cram_readecc - PM call to perform CFRAME ECC read
+ * @slrid: SLR id on which Frame ECC read to be done
+ * @frame: Frame number to be used for reading ECC
+ * @row: CFRAME row number to be used for reading ECC
+ * @response: Output response (Frame ecc header, ECC values, status)
+ *
+ * Return: Returns 0 on success or error value on failure.
+ */
+int zynqmp_pm_xilsem_cram_readecc(u32 slrid, u32 frame, u32 row, u32 *const response)
+{
+ u32 ret_buf[PAYLOAD_ARG_CNT];
+ int ret;
+
+ ret = zynqmp_pm_invoke_fn(PM_XSEM_CRAM_RD_ECC, ret_buf, 3, slrid, frame, row);
+ response[0] = ret_buf[1];
+ response[1] = ret_buf[2];
+ response[2] = ret_buf[3];
+ response[3] = ret_buf[4];
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_xilsem_cram_readecc);
+
+/**
+ * zynqmp_pm_xilsem_read_cfg - PM call to perform Xilsem configuration read
+ * @slrid: SLR id for which configuration to be read
+ * @response: Output response (config header, Xilsem config, status)
+ *
+ * Return: Returns 0 on success or error value on failure.
+ */
+int zynqmp_pm_xilsem_read_cfg(u32 slrid, u32 *const response)
+{
+ u32 ret_buf[PAYLOAD_ARG_CNT];
+ int ret;
+
+ ret = zynqmp_pm_invoke_fn(PM_XSEM_RD_CONFIG, ret_buf, 1, slrid);
+ response[0] = ret_buf[1];
+ response[1] = ret_buf[2];
+ response[2] = ret_buf[3];
+ response[3] = ret_buf[4];
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_xilsem_read_cfg);
+
+/**
+ * zynqmp_pm_xilsem_read_ssit_status - PM call to perform Xilsem SSIT status
+ * @slrid: SLR id for which ECC read to be done
+ * @bufaddr: Buffer address to get the status information
+ * @response: Output response (status read header, slr id)
+ *
+ * Return: Returns 0 on success or error value on failure.
+ */
+int zynqmp_pm_xilsem_read_ssit_status(u32 slrid, u32 bufaddr, u32 *const response)
+{
+ u32 ret_buf[PAYLOAD_ARG_CNT];
+ int ret;
+
+ ret = zynqmp_pm_invoke_fn(PM_XSEM_SSIT_RD_STS, ret_buf, 2, slrid, bufaddr);
+ response[0] = ret_buf[1];
+ response[1] = ret_buf[2];
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_xilsem_read_ssit_status);
+
+/**
+ * zynqmp_pm_xilsem_cram_getcrc - PM call to perform CRAM Row CRC read
+ * @slrid: SLR id for which CRC read to be done
+ * @rowindex: CFRAME row number to be used for reading CRC
+ * @response: Output response (Get CRC header, CRC values, status)
+ *
+ * Return: Returns 0 on success or error value on failure.
+ */
+int zynqmp_pm_xilsem_cram_getcrc(u32 slrid, u32 rowindex, u32 *const response)
+{
+ u32 ret_buf[PAYLOAD_ARG_CNT];
+ int ret;
+
+ ret = zynqmp_pm_invoke_fn(PM_XSEM_SSIT_GET_CRC, ret_buf, 2, slrid, rowindex);
+ response[0] = ret_buf[1];
+ response[1] = ret_buf[2];
+ response[2] = ret_buf[3];
+ response[3] = ret_buf[4];
+ response[4] = ret_buf[5];
+ response[5] = ret_buf[6];
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_xilsem_cram_getcrc);
+
+/**
+ * zynqmp_pm_xilsem_cram_ssit_totframes - PM call to perform total frames read
+ * @slrid: SLR id for which total frames read to be done
+ * @row: CFRAME row number to be used for reading ECC
+ * @framecnt: Buffer address to get toral frames data
+ * @response: Output response (Total frames header, slr id, row, status)
+ *
+ * Return: Returns 0 on success or error value on failure.
+ */
+int zynqmp_pm_xilsem_cram_ssit_totframes(u32 slrid, u32 row, u32 framecnt, u32 *const response)
+{
+ u32 ret_buf[PAYLOAD_ARG_CNT];
+ int ret;
+
+ ret = zynqmp_pm_invoke_fn(PM_XSEM_SSIT_GET_FRAMES, ret_buf, 3, slrid, row, framecnt);
+ response[0] = ret_buf[1];
+ response[1] = ret_buf[2];
+ response[2] = ret_buf[3];
+ response[3] = ret_buf[4];
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_xilsem_cram_ssit_totframes);
diff --git a/drivers/soc/xilinx/xlnx_event_manager.c b/drivers/soc/xilinx/xlnx_event_manager.c
index f733dc42b3b1..fb820fb15173 100644
--- a/drivers/soc/xilinx/xlnx_event_manager.c
+++ b/drivers/soc/xilinx/xlnx_event_manager.c
@@ -3,12 +3,13 @@
* Xilinx Event Management Driver
*
* Copyright (C) 2021 Xilinx, Inc.
- * Copyright (C) 2024 Advanced Micro Devices, Inc.
+ * Copyright (C) 2024-2026 Advanced Micro Devices, Inc.
*
* Abhyuday Godhasara <abhyuday.godhasara@xilinx.com>
*/
#include <linux/cpuhotplug.h>
+#include <linux/firmware/xlnx-versal-error-events.h>
#include <linux/firmware/xlnx-event-manager.h>
#include <linux/firmware/xlnx-zynqmp.h>
#include <linux/hashtable.h>
@@ -85,7 +86,8 @@ static bool xlnx_is_error_event(const u32 node_id)
if (node_id == VERSAL_EVENT_ERROR_PMC_ERR1 ||
node_id == VERSAL_EVENT_ERROR_PMC_ERR2 ||
node_id == VERSAL_EVENT_ERROR_PSM_ERR1 ||
- node_id == VERSAL_EVENT_ERROR_PSM_ERR2)
+ node_id == VERSAL_EVENT_ERROR_PSM_ERR2 ||
+ node_id == VERSAL_EVENT_ERROR_SW_ERR)
return true;
} else if (pm_family_code == PM_VERSAL_NET_FAMILY_CODE) {
if (node_id == VERSAL_NET_EVENT_ERROR_PMC_ERR1 ||
diff --git a/include/linux/firmware/xlnx-versal-error-events.h b/include/linux/firmware/xlnx-versal-error-events.h
new file mode 100644
index 000000000000..4767a23c9e4d
--- /dev/null
+++ b/include/linux/firmware/xlnx-versal-error-events.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Xilinx Versal Error Event Node IDs and Error Event Mask.
+ * Use with Xilinx Event Management Driver
+ *
+ * Copyright (C) 2021-2022 Xilinx
+ * Copyright (C) 2023-2026 Advanced Micro Devices, Inc.
+ *
+ */
+
+#ifndef _FIRMWARE_XLNX_VERSAL_ERROR_EVENTS_H_
+#define _FIRMWARE_XLNX_VERSAL_ERROR_EVENTS_H_
+
+/*
+ * Error Event Node Ids
+ */
+#define VERSAL_EVENT_ERROR_PMC_ERR1 (0x28100000U)
+#define VERSAL_EVENT_ERROR_PMC_ERR2 (0x28104000U)
+#define VERSAL_EVENT_ERROR_PSM_ERR1 (0x28108000U)
+#define VERSAL_EVENT_ERROR_PSM_ERR2 (0x2810C000U)
+#define VERSAL_EVENT_ERROR_SW_ERR (0x28110000U)
+
+/*
+ * XPM_VERSAL_EVENT_ERROR_MASK_XSEM_CRAM_CE_5: Error event mask for handling
+ * correctable error in Versal Configuration RAM which is reported by
+ * Soft Error Mitigation (XilSEM).
+ */
+#define XPM_VERSAL_EVENT_ERROR_MASK_XSEM_CRAM_CE_5 BIT(5)
+
+/**
+ * XPM_VERSAL_EVENT_ERROR_MASK_XSEM_CRAM_UE_6: Error event mask for handling
+ * uncorrectable error in Versal Configuration RAM which is reported by
+ * Soft Error Mitigation (XilSEM).
+ */
+#define XPM_VERSAL_EVENT_ERROR_MASK_XSEM_CRAM_UE_6 BIT(6)
+
+/**
+ * XPM_VERSAL_EVENT_ERROR_MASK_XSEM_NPI_UE_7: Error event mask for handling
+ * uncorrectable error in Versal NoC programming interface (NPI)
+ * register which is reported by Soft Error Mitigation (XilSEM).
+ */
+#define XPM_VERSAL_EVENT_ERROR_MASK_XSEM_NPI_UE_7 BIT(7)
+#endif /* _FIRMWARE_XLNX_VERSAL_ERROR_EVENTS_H_ */
diff --git a/include/linux/firmware/xlnx-zynqmp-sem.h b/include/linux/firmware/xlnx-zynqmp-sem.h
new file mode 100644
index 000000000000..722849cc6403
--- /dev/null
+++ b/include/linux/firmware/xlnx-zynqmp-sem.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Firmware layer for XilSEM APIs.
+ *
+ * Copyright (C), 2026 Advanced Micro Devices, Inc.
+ */
+
+#ifndef __FIRMWARE_ZYNQMP_SEM_H__
+#define __FIRMWARE_ZYNQMP_SEM_H__
+
+/* XilSEM commands */
+#define PM_XSEM_HEADER 0x300
+#define PM_XSEM_CRAM_ERRINJ 0x304
+#define PM_XSEM_RD_CONFIG 0x309
+#define PM_XSEM_CRAM_RD_ECC 0x30B
+#define PM_XSEM_SSIT_GET_CRC 0x30C
+#define PM_XSEM_SSIT_RD_STS 0x30D
+#define PM_XSEM_SSIT_GET_FRAMES 0x30E
+
+#if IS_REACHABLE(CONFIG_ZYNQMP_FIRMWARE)
+int zynqmp_pm_xilsem_cntrl_ops(u32 cmd, u32 slrid, u32 *const response);
+int zynqmp_pm_xilsem_cram_errinj(u32 slrid, u32 frame, u32 qword, u32 bit, u32 row,
+ u32 *const response);
+int zynqmp_pm_xilsem_cram_readecc(u32 slrid, u32 frame, u32 row, u32 *const response);
+int zynqmp_pm_xilsem_read_cfg(u32 slrid, u32 *const response);
+int zynqmp_pm_xilsem_read_ssit_status(u32 slrid, u32 bufaddr, u32 *const response);
+int zynqmp_pm_xilsem_cram_getcrc(u32 slrid, u32 rowindex, u32 *const response);
+int zynqmp_pm_xilsem_cram_ssit_totframes(u32 slrid, u32 row, u32 framecnt,
+ u32 *const response);
+#else
+static inline int zynqmp_pm_xilsem_cntrl_ops(u32 cmd, u32 slrid, u32 *const response)
+{
+ return -ENODEV;
+}
+
+static inline int zynqmp_pm_xilsem_cram_errinj(u32 slrid, u32 frame, u32 qword, u32 bit, u32 row,
+ u32 *const response)
+{
+ return -ENODEV;
+}
+
+static inline int zynqmp_pm_xilsem_cram_readecc(u32 slrid, u32 frame, u32 row, u32 *const response)
+{
+ return -ENODEV;
+}
+
+static inline int zynqmp_pm_xilsem_read_cfg(u32 slrid, u32 *const response)
+{
+ return -ENODEV;
+}
+
+static inline int zynqmp_pm_xilsem_read_ssit_status(u32 slrid, u32 bufaddr, u32 *const response)
+{
+ return -ENODEV;
+}
+
+static inline int zynqmp_pm_xilsem_cram_getcrc(u32 slrid, u32 rowindex, u32 *const response)
+{
+ return -ENODEV;
+}
+
+static inline int zynqmp_pm_xilsem_cram_ssit_totframes(u32 slrid, u32 row, u32 framecnt,
+ u32 *const response)
+{
+ return -ENODEV;
+}
+#endif
+
+#endif /* __FIRMWARE_ZYNQMP_SEM_H__ */
diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
index 7e27b0f7bf7e..f5808f39c7a6 100644
--- a/include/linux/firmware/xlnx-zynqmp.h
+++ b/include/linux/firmware/xlnx-zynqmp.h
@@ -18,6 +18,7 @@
#include <linux/err.h>
#include <linux/firmware/xlnx-zynqmp-ufs.h>
#include <linux/firmware/xlnx-zynqmp-crypto.h>
+#include <linux/firmware/xlnx-zynqmp-sem.h>
#define ZYNQMP_PM_VERSION_MAJOR 1
#define ZYNQMP_PM_VERSION_MINOR 0
--
2.23.0
^ permalink raw reply related
* [PATCH v3 2/4] Documentation: ABI: Add ABI doc for versal edac sysfs
From: Rama devi Veggalam @ 2026-06-24 21:25 UTC (permalink / raw)
To: bp, tony.luck, michal.simek, robh, krzk+dt, conor+dt
Cc: linux-kernel, linux-edac, devicetree, james.morse, mchehab, rric,
git, Rama devi Veggalam
In-Reply-To: <20260624212545.2850787-1-rama.devi.veggalam@amd.com>
Add documentation for the sysfs entries created for
versal edac (XilSEM).
Signed-off-by: Rama devi Veggalam <rama.devi.veggalam@amd.com>
---
Changes in v3:
- Renamed file name from xilsem edac to versal edac
Changes in v2:
- Updated Date field in sysfs file
---
.../ABI/testing/sysfs-driver-versal-edac | 303 ++++++++++++++++++
1 file changed, 303 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-driver-versal-edac
diff --git a/Documentation/ABI/testing/sysfs-driver-versal-edac b/Documentation/ABI/testing/sysfs-driver-versal-edac
new file mode 100644
index 000000000000..c35d864fcbe2
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-versal-edac
@@ -0,0 +1,303 @@
+What: /sys/devices/system/edac/versal_xilsem/xsem_scan_control
+Date: What: /sys/devices/system/edac/mc/mc0/xsem_scan_control
+Date: June 2026
+Contact: rama.devi.veggalam@amd.com
+Description:
+ It is a read/write file.
+ Writing to this file causes the software to initiate a
+ request to the firmware for doing requested scan operation in
+ Configuration RAM (CRAM) or NPI of Versal mono/SSIT devices.
+ User needs to provide scan operation id (init, start, stop) and
+ SLR id (Versal SSIT device) details. For Versal mono devices,
+ the SLR id should be 0.
+ The scan operation id values are as given below:
+ 1 - Initialize the scan
+ 2 - Start CRAM scan
+ 3 - Stop CRAM scan
+ 5 - Start NPI scan
+ 6 - Stop NPI scan
+ 7 - Inject NPI error in first descriptor
+
+ When read, it shows the current scan status with error code.
+ The format is <0x1030 | operation Id> <error code> <Slr ID>
+ The different error codes are as given below:
+ ========== =====
+ Error Code Cause
+ ========== =====
+ 0x0 Scan operation success
+ 0x1 Failure in NPI scan
+ 0x80 Calibration timeout
+ 0x2000 Internal error
+ 0x500000 CRAM initialization not yet done
+ 0x600000 Start scan failed
+ 0x700000 Stop scan failed
+ 0xF00000 Active CRC/UE error
+ 0x1000000 ECC/CRC error detected during calibration
+ ========== =====
+
+What: /sys/devices/system/edac/mc/mc0/xsem_cram_injecterr
+Date: June 2026
+Contact: rama.devi.veggalam@amd.com
+Description:
+ It is a read/write file.
+ Writing to this file causes the software to initiate a
+ request to the firmware for doing error injection in
+ Configuration RAM (CRAM) of Versal mono/SSIT devices.
+ User needs to provide the location details of CRAM
+ (frame, qword, bit number, row number) and
+ SLR id (Versal SSIT device) details to inject the error.
+ For Versal mono devices, the SLR id should be 0..
+ When read, it shows the current error injection status. The
+ format is <header> <error code> <Slr ID>
+ Example: 0x10304 0
+ The different error codes are as given below:
+ ========== =====
+ Error Code Cause
+ ========== =====
+ 0x0 Error injection success
+ 0x2000 Internal NULL pointer error
+ 0x500000 CRAM initialization not yet done
+ 0x800000 Invalid row
+ 0x900000 Invalid qword
+ 0xA00000 Invalid bit
+ 0xB00000 Invalid frame address
+ 0xC00000 Unexpected bits flipped
+ 0xD00000 Masked bit
+ 0xE00000 Invalid block type
+ 0xF00000 Active CRC/UE error in CRAM
+ ========== =====
+
+What: /sys/devices/system/edac/mc/mc0/xsem_cram_framecc_read
+Date: June 2026
+Contact: rama.devi.veggalam@amd.com
+Description:
+ It is a read/write file.
+ Writing to this file causes the software to initiate a
+ request to the firmware for reading frame ECC values in
+ Configuration RAM (CRAM) of Versal devices. User needs
+ to provide the location details of CRAM
+ (frame, row number, SLR id in SSIT device) to read the ECC values.
+ For Versal mono devices, SLR id should be 0.
+ When read, it shows the ECC values for the requested frame.
+ The format is <header> <ECC_0> <ECC_1> <status>
+ Example:
+ Read Frame ECC Cmd: [0x3030a]
+ Frame ECC Word_0: [0x52f245]
+ Frame ECC Word_1: [0x7c5a6b]
+ Cmd Status: [0x0]
+
+What: /sys/devices/system/edac/mc/mc0/xsem_read_config
+Date: June 2026
+Contact: rama.devi.veggalam@amd.com
+Description:
+ It is a read/write file.
+ Writing to this file causes the software to initiate a
+ request to the firmware for reading Xilsem configuration.
+ When read, it shows the CRAM and NPI scan configuration.
+ The format is <status> <header> <CRAM config> <NPI config>
+ Example: Read Config Cmd: [0x30309]
+ CRAM Scan Config: [0x2e]
+ NPI Scan Config: [0x5016]
+ Cmd Status: [0x0]
+
+What: /sys/devices/system/edac/mc/mc0/xsem_read_status
+Date: June 2026
+Contact: rama.devi.veggalam@amd.com
+Description:
+ It is a read/write file.
+ Writing to this file causes the software to initiate a
+ request read the Xilsem status. User needs to provide
+ the module id for status. The module id values are as given below:
+ 1 - CRAM scan
+ 2 - NPI scan
+ When read, it shows the status of the requested module.
+ For CRAM: <status> <CE count>
+ Example: 0x10005 0
+ For NPI: <status> <scan count> <heartbeat count>
+ Example: 0xA01 0x10 0x1
+
+What: /sys/devices/system/edac/mc/mc0/xsem_cram_ssit_getcrc
+Date: June 2026
+Contact: rama.devi.veggalam@amd.com
+Description:
+ It is a read/write file.
+ Writing to this file causes the software to initiate a
+ request to read CRC of a row in CRAM. User needs to provide
+ the row number and SLR id (Versal SSIT device) for which CRC
+ to be read. For Versal mono devices, SLR id should be 0.
+ When read, it shows the CRC of the requested row.
+ The format is: <Header> <CRC Word 0 to 3> <status>
+ Example: Read CRC Cmd:[0x1030c]
+ CRC_Word 0:[0x0]
+ CRC_Word 1:[0x1f72d881]
+ CRC_Word 2:[0x0]
+ CRC_Word 3:[0x0]
+ Cmd status: [0x0]
+
+What: /sys/devices/system/edac/mc/mc0/xsem_read_ssit_status
+Date: June 2026
+Contact: rama.devi.veggalam@amd.com
+Description:
+ It is a read/write file.
+ Writing to this file causes the software to initiate a
+ request to read CRAM and NPI scan status information in a given SLR.
+ User needs to provide SLR id in Versal SSIT device for which
+ XilSEM status to be read. When read, it shows
+ the XilSEM status of the requested SLR.
+ The format is: <Header> <SLR id> <NPI status info> <CRAM status info>
+ Example: Read SLR Status Cmd:[0x1030d]
+ SLR ID:[0x3]
+ NPI status:[0xa01]
+ NPI scan count:[0x413]
+ NPI Heartbeat count:[0x1150c]
+ NPI scan skip count 0 :[0x0]
+ NPI scan skip count 1 :[0x0]
+ NPI scan skip count 2 :[0x0]
+ NPI scan skip count 3 :[0x0]
+ NPI scan skip count 4 :[0x0]
+ NPI scan skip count 5 :[0x0]
+ NPI scan skip count 6 :[0x0]
+ NPI scan skip count 7 :[0x0]
+ NPI error info 0 :[0x0]
+ NPI error info 1 :[0x0]
+ CRAM status:[0x10005]
+ Error Location High 0: [0x0]
+ Error Location Low 0: [0x0]
+ Error Location High 1: [0x0]
+ Error Location Low 1: [0x0]
+ Error Location High 2: [0x0]
+ Error Location Low 2: [0x0]
+ Error Location High 3: [0x0]
+ Error Location Low 3: [0x0]
+ Error Location High 4: [0x0]
+ Error Location Low 4: [0x0]
+ Error Location High 5: [0x0]
+ Error Location Low 5: [0x0]
+ Error Location High 6: [0x0]
+ Error Location Low 6: [0x0]
+ CRAM scan CE count:[0x0]
+
+What: /sys/devices/system/edac/mc/mc0/xsem_total_cframes_ssit
+Date: June 2026
+Contact: rama.devi.veggalam@amd.com
+Description:
+ It is a read/write file.
+ Writing to this file causes the software to initiate a
+ request to read total cframes in a row in CRAM.
+ User needs to provide row number and SLR id in
+ Versal SSIT device for which total frames to be read.
+ When read, it shows total number of Cframes for the requested SLR.
+ The format is: <Header> <SLR id> <row> <total frames> <Cmd status>
+ Example: Read Total Frames Cmd : [0x4030e]
+ SLR ID : [0x3]
+ Row Index: [0x0]
+ Type[0] frame count: [38752]
+ Type[1] frame count: [262144]
+ Type[2] frame count: [20480]
+ Type[3] frame count: [16]
+ Type[4] frame count: [8]
+ Type[5] frame count: [0]
+ Type[6] frame count: [83]
+ Cmd Status: [0x0]
+Contact: rama.devi.veggalam@amd.com
+Description:
+ It is a read/write file.
+ Writing to this file causes the software to initiate a
+ request to the firmware for doing requested scan operation in
+ Configuration RAM (CRAM) or NPI of Versal devices. User needs
+ to provide scan operation id (init, start, stop) details.
+ The scan operation id values are as given below:
+ 1 - Initialize the scan
+ 2 - Start CRAM scan
+ 3 - Stop CRAM scan
+ 5 - Start NPI scan
+ 6 - Stop NPI scan
+ 7 - Inject NPI error in first descriptor
+
+ When read, it shows the current scan status with error code.
+ The format is <0x1030 | operation Id> <error code>.
+ The different error codes are as given below:
+ ========== =====
+ Error Code Cause
+ ========== =====
+ 0x0 Scan operation success
+ 0x1 Failure in NPI scan
+ 0x80 Calibration timeout
+ 0x2000 Internal error
+ 0x500000 CRAM initialization not yet done
+ 0x600000 Start scan failed
+ 0x700000 Stop scan failed
+ 0xF00000 Active CRC/UE error
+ 0x1000000 ECC/CRC error detected during calibration
+ ========== =====
+
+What: /sys/devices/system/edac/versal_xilsem/xsem_cram_injecterr
+Date: July 2025
+Contact: rama.devi.veggalam@amd.com
+Description:
+ It is a read/write file.
+ Writing to this file causes the software to initiate a
+ request to the firmware for doing error injection in
+ Configuration RAM (CRAM) of Versal devices. User needs
+ to provide the location details of CRAM
+ (frame, qword, bit number, row number) to inject the error.
+ When read, it shows the current error injection status. The
+ format is <header> <error code>.
+ Example: 0x10304 0
+ The different error codes are as given below:
+ ========== =====
+ Error Code Cause
+ ========== =====
+ 0x0 Error injection success
+ 0x2000 Internal NULL pointer error
+ 0x500000 CRAM initialization not yet done
+ 0x800000 Invalid row
+ 0x900000 Invalid qword
+ 0xA00000 Invalid bit
+ 0xB00000 Invalid frame address
+ 0xC00000 Unexpected bits flipped
+ 0xD00000 Masked bit
+ 0xE00000 Invalid block type
+ 0xF00000 Active CRC/UE error in CRAM
+ ========== =====
+
+What: /sys/devices/system/edac/versal_xilsem/xsem_cram_framecc_read
+Date: July 2025
+Contact: rama.devi.veggalam@amd.com
+Description:
+ It is a read/write file.
+ Writing to this file causes the software to initiate a
+ request to the firmware for reading frame ECC values in
+ Configuration RAM (CRAM) of Versal devices. User needs
+ to provide the location details of CRAM
+ (frame, row number) to read the ECC values.
+ When read, it shows the ECC values for the requested frame.
+ The format is <status> <header> <ECC_0> <ECC_1>
+ Example: 0 0x1030A 0x363B1A 0x8A0200
+
+What: /sys/devices/system/edac/versal_xilsem/xsem_read_config
+Date: July 2025
+Contact: rama.devi.veggalam@amd.com
+Description:
+ It is a read/write file.
+ Writing to this file causes the software to initiate a
+ request to the firmware for reading Xilsem configuration.
+ When read, it shows the CRAM and NPI scan configuration.
+ The format is <status> <header> <CRAM config> <NPI config>
+ Example: 0 0x1030A 0x26 0x5016
+
+What: /sys/devices/system/edac/versal_xilsem/xsem_read_status
+Date: July 2025
+Contact: rama.devi.veggalam@amd.com
+Description:
+ It is a read/write file.
+ Writing to this file causes the software to initiate a
+ request read the Xilsem status. User needs to provide
+ the module id for status. The module id values are as given below:
+ 1 - CRAM scan
+ 2 - NPI scan
+ When read, it shows the status of the requested module.
+ For CRAM: <status> <CE count>
+ Example: 0x10005 0
+ For NPI: <status> <scan count> <heartbeat count>
+ Example: 0xA01 0x10 0x1
--
2.23.0
^ permalink raw reply related
* [PATCH v3 1/4] dt-bindings: edac: Add bindings for Xilinx Versal XilSEM
From: Rama devi Veggalam @ 2026-06-24 21:25 UTC (permalink / raw)
To: bp, tony.luck, michal.simek, robh, krzk+dt, conor+dt
Cc: linux-kernel, linux-edac, devicetree, james.morse, mchehab, rric,
git, Rama devi Veggalam
In-Reply-To: <20260624212545.2850787-1-rama.devi.veggalam@amd.com>
Update versal edac device tree bindings for
Versal Soft Error Mitigation (XilSEM).
Signed-off-by: Rama devi Veggalam <rama.devi.veggalam@amd.com>
---
Changes in v3:
- Merged XilSEM edac with Versal Edac
Changes in v2:
- Changed "xlnx,versal-xilsem-edac" to constant
- Removed "compatible: in required section
- Removed "|" in description
- Removed "items" in compatible
- Fixed indentation in examples
- Updated title and description
---
.../xlnx,versal-ddrmc-edac.yaml | 22 ++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/memory-controllers/xlnx,versal-ddrmc-edac.yaml b/Documentation/devicetree/bindings/memory-controllers/xlnx,versal-ddrmc-edac.yaml
index 12f8e9f350bc..568d2af7de81 100644
--- a/Documentation/devicetree/bindings/memory-controllers/xlnx,versal-ddrmc-edac.yaml
+++ b/Documentation/devicetree/bindings/memory-controllers/xlnx,versal-ddrmc-edac.yaml
@@ -4,17 +4,31 @@
$id: http://devicetree.org/schemas/memory-controllers/xlnx,versal-ddrmc-edac.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Xilinx Versal DDRMC (Integrated DDR Memory Controller)
+title: Xilinx Versal DDRMC (Integrated DDR Memory Controller) and Soft Error Mitigation (XilSEM)
maintainers:
- Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
- Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>
+ - Rama Devi Veggalam <rama.devi.veggalam@amd.com>
description:
The integrated DDR Memory Controllers (DDRMCs) support both DDR4 and LPDDR4/
4X memory interfaces. Versal DDR memory controller has an optional ECC support
which correct single bit ECC errors and detect double bit ECC errors.
+ Xilinx Versal Soft Error Mitigation (XilSEM) is part of the
+ Platform Loader and Manager (PLM) which runs on the
+ Platform Management Controller (PMC). XilSEM is responsible for reporting
+ and optionally correcting soft errors in Configuration Memory of Versal.
+ The Configuration Memory includes Configuration RAM and
+ Network on Chip (NoC) peripheral interconnect (NPI) Registers.
+
+ The memory is scanned by a hardware controller in the Versal Programmable
+ Logic (PL). During the scan, if the controller detects any error, be it
+ correctable or uncorrectable, it reports the error to PLM.
+ The XilSEM on PLM performs the error validation and notifies the errors to user application.
+
+
properties:
compatible:
const: xlnx,versal-ddrmc
@@ -23,11 +37,13 @@ properties:
items:
- description: DDR Memory Controller registers
- description: NOC registers corresponding to DDR Memory Controller
+ - description: SEM RTCA Controller registers
reg-names:
items:
- const: base
- const: noc
+ - const: semrtca
interrupts:
maxItems: 1
@@ -49,8 +65,8 @@ examples:
#size-cells = <2>;
memory-controller@f6150000 {
compatible = "xlnx,versal-ddrmc";
- reg = <0x0 0xf6150000 0x0 0x2000>, <0x0 0xf6070000 0x0 0x20000>;
- reg-names = "base", "noc";
+ reg = <0x0 0xf6150000 0x0 0x2000>, <0x0 0xf6070000 0x0 0x20000>, < 0x00 0xf2014050 0x00 0xc4>;
+ reg-names = "base", "noc" , "semrtca";
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
};
--
2.23.0
^ permalink raw reply related
* [PATCH v3 0/4] Add support for Versal Xilsem edac
From: Rama devi Veggalam @ 2026-06-24 21:25 UTC (permalink / raw)
To: bp, tony.luck, michal.simek, robh, krzk+dt, conor+dt
Cc: linux-kernel, linux-edac, devicetree, james.morse, mchehab, rric,
git, Rama devi Veggalam
Add sysfs interface for Xilsem scan operations initialize, start,
stop scan, error inject, read ECC, status and configuration values.
Handle correctable and uncorrectable xilsem error events.
Changes in V3:
- Merged XilSEM edac with Versal Edac driver to address
the review feedback.
Rama devi Veggalam (4):
dt-bindings: edac: Add bindings for Xilinx Versal XilSEM
Documentation: ABI: Add ABI doc for versal edac sysfs
firmware: xilinx: Add support for Xilsem scan operations
edac: xilinx: Add EDAC support for Versal XilSem
.../ABI/testing/sysfs-driver-versal-edac | 303 ++++
.../xlnx,versal-ddrmc-edac.yaml | 22 +-
MAINTAINERS | 1 +
drivers/edac/Kconfig | 4 +-
drivers/edac/versal_edac.c | 1348 ++++++++++++++++-
drivers/firmware/xilinx/Makefile | 2 +-
drivers/firmware/xilinx/zynqmp-sem.c | 176 +++
drivers/soc/xilinx/xlnx_event_manager.c | 6 +-
.../linux/firmware/xlnx-versal-error-events.h | 43 +
include/linux/firmware/xlnx-zynqmp-sem.h | 69 +
include/linux/firmware/xlnx-zynqmp.h | 1 +
11 files changed, 1965 insertions(+), 10 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-driver-versal-edac
create mode 100644 drivers/firmware/xilinx/zynqmp-sem.c
create mode 100644 include/linux/firmware/xlnx-versal-error-events.h
create mode 100644 include/linux/firmware/xlnx-zynqmp-sem.h
--
2.23.0
^ permalink raw reply
* Re: [PATCH v3] ASoC: dt-bindings: Convert cirrus,cs35l36 to DT schema
From: sashiko-bot @ 2026-06-24 21:24 UTC (permalink / raw)
To: David Heidelberg via B4 Relay; +Cc: conor+dt, devicetree, robh
In-Reply-To: <20260624-dt-cirrus-cs35l36-v3-1-ec451d5a2908@ixit.cz>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The `cirrus,boost-ind-nanohenry` property was incorrectly omitted from the `required` list in the YAML schema.
--
commit 778c838f7518ecfc3c565efa00f1019533b91e2d
Author: David Heidelberg <david@ixit.cz>
ASoC: dt-bindings: Convert cirrus,cs35l36 to DT schema
Convert the CS35L36 Speaker Amplifier binding from text to YAML format,
updating the maintainer list and aligning the properties with the datasheet.
> diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
> new file mode 100644
> index 0000000000000..2a142b32acf50
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
[ ... ]
> +required:
> + - compatible
> + - reg
> + - interrupts
> + - VA-supply
> + - cirrus,boost-ctl-millivolt
> + - cirrus,boost-peak-milliamp
[Severity: Medium]
Should cirrus,boost-ind-nanohenry be included in this required list?
A device tree missing this property will pass schema validation, but the
driver will fail to probe. Looking at cs35l36_handle_of_data() in
sound/soc/codecs/cs35l36.c, the driver hard-fails if it's absent:
sound/soc/codecs/cs35l36.c:cs35l36_handle_of_data() {
...
if (of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val) >= 0) {
pdata->boost_ind = val;
} else {
dev_err(&i2c_client->dev, "Inductor not specified.\n");
return -EINVAL;
}
...
}
> +
> +unevaluatedProperties: false
> +
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624-dt-cirrus-cs35l36-v3-1-ec451d5a2908@ixit.cz?part=1
^ permalink raw reply
* Re: [PATCH v1 1/3] drivers/platform: lenovo-t14s-ec: Add hwmon support for temperatures and fan speed
From: sashiko-bot @ 2026-06-24 21:22 UTC (permalink / raw)
To: Daniel Lezcano; +Cc: robh, conor+dt, devicetree, linux-hwmon
In-Reply-To: <20260624210825.264454-2-daniel.lezcano@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] Direct calls to `t14s_ec_read` bypass the `regmap` mutex, violating the mandatory 10ms hardware recovery delay between EC commands.
- [Medium] Reading the fan RPM requires two separate I2C transfers for the LSB and MSB, allowing the hardware value to update in between and cause torn reads.
- [Low] Passing `int *` arguments to a function expecting `unsigned int *` for I2C register reads.
Pre-existing issues:
- [High] The `t14s_ec_read` function passes buffers allocated on the kernel stack to `__i2c_transfer()`, which violates DMA mapping rules and can cause panics.
--
commit d0870f0c919ef26da98287c26fc38bc327dcd76b
Author: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
drivers/platform: lenovo-t14s-ec: Add hwmon support for temperatures and fan speed
Expose the Lenovo ThinkPad T14s EC environmental sensors through
the hwmon subsystem.
> diff --git a/drivers/platform/arm64/lenovo-thinkpad-t14s.c b/drivers/platform/arm64/lenovo-thinkpad-t14s.c
> index 5590302a5694f..142464623f0e8 100644
> --- a/drivers/platform/arm64/lenovo-thinkpad-t14s.c
> +++ b/drivers/platform/arm64/lenovo-thinkpad-t14s.c
[ ... ]
> @@ -555,6 +576,128 @@ static irqreturn_t t14s_ec_irq_handler(int irq, void *data)
> return IRQ_HANDLED;
> }
>
> +static umode_t t14s_ec_hwmon_is_visible(const void *drvdata,
[ ... ]
> +static int t14s_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
> + u32 attr, int channel, long *val)
> +{
> + struct t14s_ec *ec = dev_get_drvdata(dev);
> + unsigned int value;
> + int ret;
> +
> + switch (type) {
> + case hwmon_temp:
> + if (attr == hwmon_temp_input) {
> + ret = t14s_ec_read(ec, ec->ec_hwmon.sys_thermx[channel].reg, &value);
[Severity: High]
Does calling t14s_ec_read() directly here bypass the regmap mutex?
Because the embedded controller requires a 10ms hardware recovery delay between
commands, regmap serializes accesses and includes the sleep while holding the
lock. Calling t14s_ec_read() directly appears to bypass this locking, potentially
allowing concurrent sysfs reads to interleave with other subsystem I2C
transfers and violate the hardware constraint.
[Severity: High]
This isn't a bug introduced by this patch, but because this exposes new sysfs
attributes that userspace can trigger, does t14s_ec_read() pass stack-allocated
buffers to __i2c_transfer()?
Looking at t14s_ec_read():
static int t14s_ec_read(void *context, unsigned int reg,
unsigned int *val)
{
...
u8 buf[4] = {T14S_EC_CMD_ECRD, reg, 0x00, 0x01};
struct i2c_msg request, response;
u8 result;
...
request.buf = buf;
...
response.buf = &result;
...
ret = __i2c_transfer(client->adapter, &request, 1);
On ARM64 architectures with CONFIG_VMAP_STACK, passing stack memory to I2C
drivers using DMA (like Qualcomm GENI) can trigger a BUG() panic or corrupt
adjacent physical memory. Is it possible to use heap-allocated buffers here
instead?
> + if (ret)
> + return ret;
> + *val = value * 1000;
> +
> + return 0;
> + }
> + break;
> +
> + case hwmon_fan:
> + if (attr == hwmon_fan_input) {
> + int lsb, msb;
> + ret = t14s_ec_read(ec, T14S_EC_FAN_RPM_LSB, &lsb);
[Severity: Low]
Does this pass pointers of type int * to t14s_ec_read() which expects
unsigned int *?
Newer compilers like GCC 14 treat -Wincompatible-pointer-types as an
error by default, which might break the build here.
[Severity: Medium]
Is there a risk of torn reads when reading the lsb and msb sequentially?
Because t14s_ec_read() enforces a 10ms sleep after each I2C transfer, there is
a large race window between reading T14S_EC_FAN_RPM_LSB and
T14S_EC_FAN_RPM_MSB. If the fan RPM rolls over (e.g., from 0x01ff to 0x0200)
during that window, could we combine an old lsb with a new msb and report
a wildly incorrect fan speed?
> + if (ret)
> + return ret;
> +
> + ret = t14s_ec_read(ec, T14S_EC_FAN_RPM_MSB, &msb);
> + if (ret)
> + return ret;
> +
> + *val = 0;
> + *val = lsb + (msb << 8);
> +
> + return 0;
> + }
> + break;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624210825.264454-1-daniel.lezcano@oss.qualcomm.com?part=1
^ permalink raw reply
* Re: [PATCH v1 2/3] platform: arm64: thinkpad-t14s-ec: Wire EC thermal events to hwmon
From: sashiko-bot @ 2026-06-24 21:21 UTC (permalink / raw)
To: Daniel Lezcano; +Cc: linux-hwmon, robh, conor+dt, devicetree
In-Reply-To: <20260624210825.264454-3-daniel.lezcano@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Missing HWMON_T_ALARM capability prevents sysfs notification from working.
--
commit 1242d377b6327e98b089989a953188982e0ca595
Author: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
platform: arm64: thinkpad-t14s-ec: Wire EC thermal events to hwmon
This patch wires up EC thermal zone status change notifications to the hwmon
notification framework. It associates hwmon temperature channels with EC
thermal events and emits hwmon_temp_alarm notifications to userspace.
> diff --git a/drivers/platform/arm64/lenovo-thinkpad-t14s.c b/drivers/platform/arm64/lenovo-thinkpad-t14s.c
> index 142464623f0e8..276bb51da33a3 100644
> --- a/drivers/platform/arm64/lenovo-thinkpad-t14s.c
> +++ b/drivers/platform/arm64/lenovo-thinkpad-t14s.c
[ ... ]
> @@ -493,6 +496,20 @@ static int t14s_input_probe(struct t14s_ec *ec)
> return input_register_device(ec->inputdev);
> }
>
> +static void t14s_ec_hwmon_notify_event(struct t14s_ec *ec, u8 event)
> +{
> + for (int i = 0; i < ec->ec_hwmon.num_sys_thermx; i++) {
> + if (ec->ec_hwmon.sys_thermx[i].event != event)
> + continue;
> +
> + hwmon_notify_event(ec->ec_hwmon.dev, hwmon_temp,
> + hwmon_temp_alarm, i);
> +
> + dev_dbg(ec->dev, "Thermal Zone (%s) Status Change Event\n",
> + ec->ec_hwmon.sys_thermx[i].label);
> + }
> +}
> +
[ ... ]
> @@ -658,6 +671,7 @@ static const struct hwmon_ops t14s_ec_hwmon_ops = {
> };
>
> static const struct hwmon_channel_info *t14s_ec_hwmon_info[] = {
> + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
> HWMON_CHANNEL_INFO(temp,
> HWMON_T_INPUT | HWMON_T_LABEL,
> HWMON_T_INPUT | HWMON_T_LABEL,
> HWMON_T_INPUT | HWMON_T_LABEL,
> HWMON_T_INPUT | HWMON_T_LABEL,
> HWMON_T_INPUT | HWMON_T_LABEL,
> HWMON_T_INPUT | HWMON_T_LABEL),
[Severity: Medium]
Will the hwmon_temp_alarm notifications successfully reach userspace?
The channel configuration array does not include the HWMON_T_ALARM capability
for any of the temperature channels. Without this, the hwmon core will not
create the corresponding tempX_alarm sysfs attributes.
When t14s_ec_hwmon_notify_event() calls hwmon_notify_event() for
hwmon_temp_alarm, it appears the sysfs notification will fail silently because
the attribute does not exist. The thermal subsystem still receives the event
via hwmon_thermal_notify(), but userspace monitoring tools will not be able to
read or poll the sysfs attributes.
Does HWMON_T_ALARM need to be added to the channel configurations here to make
the sysfs event notification work as described in the commit message?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624210825.264454-1-daniel.lezcano@oss.qualcomm.com?part=2
^ permalink raw reply
* Re: [PATCH v1 3/3] arm64: dts: qcom: x1e78100-t14s: Add thermal zones for keyboard skin and charging sensors
From: sashiko-bot @ 2026-06-24 21:18 UTC (permalink / raw)
To: Daniel Lezcano; +Cc: linux-hwmon, robh, conor+dt, devicetree
In-Reply-To: <20260624210825.264454-4-daniel.lezcano@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The commit message claims the charging thermal zone uses 'multiple passive trip points' to 'progressively throttle the different CPU clusters', but the implementation provides only a single passive trip point that throttles all CPUs simultaneously.
--
commit 165036bedb34a29493f4bd0a7af23dab152aff0c
Author: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
arm64: dts: qcom: x1e78100-t14s: Add thermal zones for keyboard skin and charging sensors
Add thermal zone descriptions for the keyboard skin temperature and battery
charging circuitry sensors exposed by the embedded controller.
> - a charging circuitry temperature zone with multiple passive trip
> points and CPU frequency mitigation levels.
>
> The charging thermal zone progressively throttles the different CPU
> clusters as the charging circuitry temperature rises and triggers a hot
> condition at the highest trip point.
[Severity: Medium]
Does the implementation match this commit message description?
The commit message claims there are multiple passive trip points and
progressive throttling across different CPU clusters. Is a chunk of the patch
missing, or should the commit message be updated to reflect the final design
shown below?
> diff --git a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
> --- a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
> +++ b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
[ ... ]
> + ec-charging-thermal {
> + polling-delay = <5000>;
> + polling-delay-passive = <2000>;
> +
> + thermal-sensors = <&ec 3>;
> +
> + trips {
> + psv0: trip-point0 {
> + temperature = <55000>;
> + hysteresis = <0>;
> + type = "passive";
> + };
> +
> + alert0: trip-point1 {
> + temperature = <63000>;
> + hysteresis = <0>;
> + type = "hot";
> + };
> + };
[Severity: Medium]
Only a single passive trip point is defined here in ec-charging-thermal,
which doesn't match the "multiple passive trip points" mentioned in the
commit message.
> +
> + cooling-maps {
> + map0 {
> + trip = <&psv0>;
> + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
> + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
> + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
> + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
> + <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
> + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
> + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
> + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
> + <&cpu8 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
> + <&cpu9 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
> + <&cpu10 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
> + <&cpu11 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
> +
> + };
> + };
[Severity: Medium]
Additionally, all 12 CPUs are tied uniformly to this single trip point.
Should this define progressive throttling across different CPU clusters as
described in the commit message?
> +
> + };
> +};
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624210825.264454-1-daniel.lezcano@oss.qualcomm.com?part=3
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox