* [PATCH] Documentation/devicetree/bindings: update Sudeep Holla's email address
From: Laszlo Ersek @ 2026-07-20 16:02 UTC (permalink / raw)
To: laszlo.ersek
Cc: Conor Dooley, Cristian Marussi, Jassi Brar, Krzysztof Kozlowski,
Linus Walleij, Liviu Dudau, Lorenzo Pieralisi, Rob Herring,
Sudeep Holla, arm-scmi, devicetree, linux-arm-kernel,
linux-kernel
MAINTAINERS disagrees with Documentation/devicetree/bindings on Sudeep's
email address; fix the latter.
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Cristian Marussi <cristian.marussi@arm.com>
Cc: Jassi Brar <jassisinghbrar@gmail.com>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Linus Walleij <linusw@kernel.org>
Cc: Liviu Dudau <liviu.dudau@arm.com>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: Sudeep Holla <sudeep.holla@kernel.org>
Cc: arm-scmi@vger.kernel.org
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Fixes: 59e82a4237cf ("MAINTAINERS: Change Sudeep Holla's email address")
Signed-off-by: Laszlo Ersek <laszlo.ersek@arm.com>
---
Documentation/devicetree/bindings/arm/arm,juno-fpga-apb-regs.yaml | 2 +-
Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml | 2 +-
Documentation/devicetree/bindings/arm/arm,vexpress-scc.yaml | 2 +-
Documentation/devicetree/bindings/dvfs/performance-domain.yaml | 2 +-
Documentation/devicetree/bindings/firmware/arm,scmi.yaml | 2 +-
Documentation/devicetree/bindings/firmware/arm,scpi.yaml | 2 +-
Documentation/devicetree/bindings/mailbox/arm,mhuv3.yaml | 2 +-
7 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/Documentation/devicetree/bindings/arm/arm,juno-fpga-apb-regs.yaml b/Documentation/devicetree/bindings/arm/arm,juno-fpga-apb-regs.yaml
index ce5f2e1ec1ea..4ae7dc706b84 100644
--- a/Documentation/devicetree/bindings/arm/arm,juno-fpga-apb-regs.yaml
+++ b/Documentation/devicetree/bindings/arm/arm,juno-fpga-apb-regs.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: ARM Juno FPGA APB Registers
maintainers:
- - Sudeep Holla <sudeep.holla@arm.com>
+ - Sudeep Holla <sudeep.holla@kernel.org>
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml b/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml
index 95d4baa85506..30cc534a91ee 100644
--- a/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml
+++ b/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: ARM Versatile Express and Juno Boards
maintainers:
- - Sudeep Holla <sudeep.holla@arm.com>
+ - Sudeep Holla <sudeep.holla@kernel.org>
- Linus Walleij <linusw@kernel.org>
description: |+
diff --git a/Documentation/devicetree/bindings/arm/arm,vexpress-scc.yaml b/Documentation/devicetree/bindings/arm/arm,vexpress-scc.yaml
index 9b8f7e0c4ea0..060c0bc58a15 100644
--- a/Documentation/devicetree/bindings/arm/arm,vexpress-scc.yaml
+++ b/Documentation/devicetree/bindings/arm/arm,vexpress-scc.yaml
@@ -8,7 +8,7 @@ title: ARM Versatile Express Serial Configuration Controller
maintainers:
- Liviu Dudau <liviu.dudau@arm.com>
- - Sudeep Holla <sudeep.holla@arm.com>
+ - Sudeep Holla <sudeep.holla@kernel.org>
description: |
Test chips for ARM Versatile Express platform implement SCC (Serial
diff --git a/Documentation/devicetree/bindings/dvfs/performance-domain.yaml b/Documentation/devicetree/bindings/dvfs/performance-domain.yaml
index cc930660b794..09bbd2e33786 100644
--- a/Documentation/devicetree/bindings/dvfs/performance-domain.yaml
+++ b/Documentation/devicetree/bindings/dvfs/performance-domain.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Generic performance domains
maintainers:
- - Sudeep Holla <sudeep.holla@arm.com>
+ - Sudeep Holla <sudeep.holla@kernel.org>
description: |+
This binding is intended for performance management of groups of devices or
diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
index d06cca9273c4..6fc44105f1c3 100644
--- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
+++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
@@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: System Control and Management Interface (SCMI) Message Protocol
maintainers:
- - Sudeep Holla <sudeep.holla@arm.com>
+ - Sudeep Holla <sudeep.holla@kernel.org>
description: |
The SCMI is intended to allow agents such as OSPM to manage various functions
diff --git a/Documentation/devicetree/bindings/firmware/arm,scpi.yaml b/Documentation/devicetree/bindings/firmware/arm,scpi.yaml
index 241317239ffc..08c7e05c577c 100644
--- a/Documentation/devicetree/bindings/firmware/arm,scpi.yaml
+++ b/Documentation/devicetree/bindings/firmware/arm,scpi.yaml
@@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: System Control and Power Interface (SCPI) Message Protocol
maintainers:
- - Sudeep Holla <sudeep.holla@arm.com>
+ - Sudeep Holla <sudeep.holla@kernel.org>
description: |
Firmware implementing the SCPI described in ARM document number ARM DUI
diff --git a/Documentation/devicetree/bindings/mailbox/arm,mhuv3.yaml b/Documentation/devicetree/bindings/mailbox/arm,mhuv3.yaml
index 449b55afeb7d..025a5c55b284 100644
--- a/Documentation/devicetree/bindings/mailbox/arm,mhuv3.yaml
+++ b/Documentation/devicetree/bindings/mailbox/arm,mhuv3.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: ARM MHUv3 Mailbox Controller
maintainers:
- - Sudeep Holla <sudeep.holla@arm.com>
+ - Sudeep Holla <sudeep.holla@kernel.org>
- Cristian Marussi <cristian.marussi@arm.com>
description: |
^ permalink raw reply related
* Re: [PATCH 7/8] net: mv643xx: use platform_device_set_fwnode()
From: Bartosz Golaszewski @ 2026-07-20 16:01 UTC (permalink / raw)
To: Andrew Lunn
Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Andi Shyti,
Joerg Roedel (AMD), Will Deacon, Robin Murphy, Andy Shevchenko,
Doug Berger, Florian Fainelli,
Broadcom internal kernel review list, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Ulf Hansson, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Lee Jones, Sebastian Hesselbarth,
Srinivas Kandagatla, brgl, driver-core, linuxppc-dev,
linux-kernel, linux-i2c, iommu, netdev, linux-pm, imx,
linux-arm-kernel, mfd, linux-arm-msm, linux-sound
In-Reply-To: <86b2aba7-b049-47e6-bc94-6cb499b30ce4@lunn.ch>
On Mon, 20 Jul 2026 16:43:40 +0200, Andrew Lunn <andrew@lunn.ch> said:
> On Mon, Jul 20, 2026 at 11:24:54AM +0200, Bartosz Golaszewski wrote:
>> Prefer the higher-level platform_device_set_fwnode() over the
>> OF-specific platform_device_set_of_node() for dynamically allocated
>> platform devices.
>>
>> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>> ---
>> drivers/net/ethernet/marvell/mv643xx_eth.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
>> index 9caa1e47c174c9d7a161b7f2e2ee12a829b813d4..2f2d6cce8d852b9ec3ab42678a04a7915d1f00cc 100644
>> --- a/drivers/net/ethernet/marvell/mv643xx_eth.c
>> +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
>> @@ -2780,7 +2780,7 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
>> goto put_err;
>> }
>> ppdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
>> - platform_device_set_of_node(ppdev, pnp);
>> + platform_device_set_fwnode(ppdev, of_fwnode_handle(pnp));
>
> This is definitely an OF only driver. There are no other calls to
> fwnode functions in this driver, so this is the wrong thing to do.
>
> Sorry, NACK.
>
I'm not going to die on this hill but drivers are OF-only until they're not.
For example, Qualcomm is now working on a hybrid ACPI-OF approach for
laptops[1] and we may end up needing to start converting drivers to fwnode
after all.
There's no real benefit to sticking to OF-specific APIs unless you need to
iterate over all properties of a node or use some other functionality not
available in fwnode. The overhead is minimal and it's never a hot path.
Thanks,
Bartosz
[1] https://lore.kernel.org/all/20260623145225.143218-1-johannes.goede@oss.qualcomm.com/
^ permalink raw reply
* Re: [PATCH v3 02/16] arm_mpam: propagate MSC read errors for wrapper functions
From: Andre Przywara @ 2026-07-20 15:58 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla, Catalin Marinas,
Will Deacon, Rafael J . Wysocki, Len Brown, James Morse,
Ben Horgan, Reinette Chatre, Fenghua Yu, Jonathan Cameron,
Srivathsa L Rao, Ganapatrao Kulkarni, Trilok Soni,
Srinivas Ramana, Niyas Sait, linux-acpi, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260710112158.0000490d@oss.qualcomm.com>
Hi Jonathan,
On 7/10/26 20:21, Jonathan Cameron wrote:
> On Fri, 10 Jul 2026 16:45:06 +0200
> Andre Przywara <andre.przywara@arm.com> wrote:
>
>> Allow the wrapper functions for IDR and ESR accesses to return an
>> error, and propagate read errors from the lower level up.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Hi Andre,
>
> Just a few superficial code style comments.
>
> Thanks,
>
> Jonathan
>
>> ---
>> drivers/resctrl/mpam_devices.c | 53 ++++++++++++++++++++++++----------
>> 1 file changed, 38 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
>> index df14b4513382..8fd2c38c821c 100644
>> --- a/drivers/resctrl/mpam_devices.c
>> +++ b/drivers/resctrl/mpam_devices.c
>> @@ -247,27 +247,38 @@ static bool mpam_msc_check_aidr(struct mpam_msc *msc)
>> return true;
>> }
>>
>> -static u64 mpam_msc_read_idr(struct mpam_msc *msc)
>> +static int mpam_msc_read_idr(struct mpam_msc *msc, u64 *res)
>> {
>> u32 idr_high = 0, idr_low;
>> + int ret;
>>
>> lockdep_assert_held(&msc->part_sel_lock);
>>
>> - mpam_read_partsel_reg(msc, IDR, &idr_low);
>> + ret = mpam_read_partsel_reg(msc, IDR, &idr_low);
>> + if (ret)
>> + return ret;
>> +
>> if (FIELD_GET(MPAMF_IDR_EXT, idr_low))
>> - mpam_read_partsel_reg(msc, IDR + 4, &idr_high);
>> + ret = mpam_read_partsel_reg(msc, IDR + 4, &idr_high);
>> + if (ret)
>> + return ret;
>
> From a readability point of view, I'd indent the if (ret) as well
> given that will then make it visually clear the check only applies
> when the if is taken.
>
> if (FIELD_GET()) {
> ret = mpam_read_partsel_reg(msc, IDR + 4 &idr_high);
> if (ret)
> return ret;
> }
Sure, done. Was indeed not consistent with other places.
>> +
>> + *res = ((u64)idr_high << 32) | idr_low;
>>
>> - return ((u64)idr_high << 32) | idr_low;
>> + return 0;
>> }
>>
>> -static void mpam_msc_clear_esr(struct mpam_msc *msc)
>> +static int mpam_msc_clear_esr(struct mpam_msc *msc)
>> {
>> u32 esr_low;
>> + int ret;
>>
>> - __mpam_read_reg(msc, MPAMF_ESR, &esr_low);
>> + ret = __mpam_read_reg(msc, MPAMF_ESR, &esr_low);
>> + if (ret)
>> + return ret;
>>
>> if (!esr_low)
>> - return;
>> + return 0;
>>
>> /*
>> * Clearing the high/low bits of MPAMF_ESR can not be atomic.
>> @@ -277,18 +288,30 @@ static void mpam_msc_clear_esr(struct mpam_msc *msc)
>> */
>> if (msc->has_extd_esr)
>> __mpam_write_reg(msc, MPAMF_ESR + 4, 0);
>> +
>
> Might be valid, but to me that smells like an unrelated cleanup
> that shouldn't really be in a patch doing more meaningful work. Perhaps
I guess you mean the added line? That looks like a rebasing artefact,
sorry for that. Will remove it.
> makes sense when you circle back to do writes. BTW, I'm not sure
> there is real benefit in separate patches doing reads from those doing writes!
The reason was just to split them up in a) smaller, but b) still
bisectable chunks, that c) ideally group similar change patterns, to
help review. As reads require an interface change while writes do not, I
decided to split them up this way.
I didn't really think too hard to find a better grouping (I guess any
alternative would be subject to discussion as well), but instead
focussed on generating smallish patches that allow reviewing a bunch of
them without having to skip lunch ;-)
Cheers,
Andre
> Mind you I haven't read all the way through yet, so maybe I'm missing some
> subtlety.
>
>> __mpam_write_reg(msc, MPAMF_ESR, 0);
>> +
>> + return 0;
>> }
>>
>> -static u64 mpam_msc_read_esr(struct mpam_msc *msc)
>> +static int mpam_msc_read_esr(struct mpam_msc *msc, u64 *res)
>> {
>> u32 esr_high = 0, esr_low;
>> + int ret;
>>
>> - __mpam_read_reg(msc, MPAMF_ESR, &esr_low);
>> - if (msc->has_extd_esr)
>> - __mpam_read_reg(msc, MPAMF_ESR + 4, &esr_high);
>> + ret = __mpam_read_reg(msc, MPAMF_ESR, &esr_low);
>> + if (ret)
>> + return ret;
>> +
>> + if (msc->has_extd_esr) {
>> + ret = __mpam_read_reg(msc, MPAMF_ESR + 4, &esr_high);
>> + if (ret)
>> + return ret;
>
> So this is the style I suggest above. Good, but check for consistency.
> It may feel like a really small thing (and it is :) but keeping code
> very consistent helps a surprising amount when it comes to readability.
>
>> + }
>> +
>> + *res = ((u64)esr_high << 32) | esr_low;
>>
>> - return ((u64)esr_high << 32) | esr_low;
>> + return 0;
>> }
>
^ permalink raw reply
* Re: [PATCH v3 07/16] arm_mpam: __ris_msmon_read(): get rid of nrdy special handling
From: Andre Przywara @ 2026-07-20 15:58 UTC (permalink / raw)
To: Ben Horgan, Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla,
Catalin Marinas, Will Deacon, Rafael J . Wysocki, Len Brown,
James Morse, Reinette Chatre, Fenghua Yu
Cc: Jonathan Cameron, Srivathsa L Rao, Ganapatrao Kulkarni,
Trilok Soni, Srinivas Ramana, Niyas Sait, linux-acpi,
linux-arm-kernel, linux-kernel
In-Reply-To: <b5f54fad-b7a0-4949-b78a-fe684eeb4d75@arm.com>
Hi Ben,
thanks for having a look!
On 7/15/26 15:39, Ben Horgan wrote:
> Hi Andre,
>
> On 7/10/26 15:45, Andre Przywara wrote:
>> Although so far MSC accesses couldn't fail, there is one special
>> condition that would create an error: when the MBWU counter wouldn't be
>> able to read a stable value, we were setting bit 63 to mark this value
>> as unstable, and return this as an error later.
>> Now since the functions can return a proper error value, we can get rid of
>> this kludge and use the return value directly.
>>
>> Remove the "nrdy" error flag variable, and assign -EBUSY to "ret" to handle
>> this case.
>
> I don't think we want this patch. The h/w can still return (as much as it ever could) and so we
> still need to handle it even if we are no longer augmenting its meaning in software to also indicate
> an unstable 64 bit value.
Mmh, not sure I understand your concern: to me it looks like nrdy is
some kind of error flag, that we used in absence of a proper error
return value. Now we have "int ret;", so can use that directly? But to
me it looks like nothing really changes, or did I miss something?
I have no really strong opinion of this patch, it was more an pportunity
to consolidate the crude error handling in this function. I am happy to
drop it, if you like, maybe we can revisit this later.
Cheers,
Andre
>
> Thanks,
>
> Ben
>
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> drivers/resctrl/mpam_devices.c | 38 +++++++++++++++-------------------
>> 1 file changed, 17 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
>> index 84a8715464be..530ac0fe97b5 100644
>> --- a/drivers/resctrl/mpam_devices.c
>> +++ b/drivers/resctrl/mpam_devices.c
>> @@ -1306,7 +1306,6 @@ static void __ris_msmon_read(void *arg)
>> u64 now;
>> int ret;
>> u32 now32;
>> - bool nrdy = false;
>> bool config_mismatch;
>> bool overflow = false;
>> struct mon_read *m = arg;
>> @@ -1371,14 +1370,18 @@ static void __ris_msmon_read(void *arg)
>> switch (m->type) {
>> case mpam_feat_msmon_csu:
>> ret = mpam_read_monsel_reg(msc, CSU, &now32);
>> + if (!ret) {
>> + if ((now32 & MSMON___NRDY))
>> + ret = -EBUSY;
>> +
>> + if (mpam_has_quirk(IGNORE_CSU_NRDY, msc) &&
>> + m->waited_timeout)
>> + ret = 0;
>> + }
>> if (ret)
>> goto out_unlock;
>> - nrdy = now32 & MSMON___NRDY;
>> - now = FIELD_GET(MSMON___VALUE, now32);
>> -
>> - if (mpam_has_quirk(IGNORE_CSU_NRDY, msc) && m->waited_timeout)
>> - nrdy = false;
>>
>> + now = FIELD_GET(MSMON___VALUE, now32);
>> break;
>> case mpam_feat_msmon_mbwu_31counter:
>> case mpam_feat_msmon_mbwu_44counter:
>> @@ -1394,9 +1397,11 @@ static void __ris_msmon_read(void *arg)
>> now = FIELD_GET(MSMON___L_VALUE, now);
>> } else {
>> ret = mpam_read_monsel_reg(msc, MBWU, &now32);
>> + if (!ret && (now32 & MSMON___NRDY))
>> + ret = -EBUSY;
>> if (ret)
>> goto out_unlock;
>> - nrdy = now32 & MSMON___NRDY;
>> +
>> now = FIELD_GET(MSMON___VALUE, now32);
>> }
>>
>> @@ -1404,9 +1409,6 @@ static void __ris_msmon_read(void *arg)
>> m->type != mpam_feat_msmon_mbwu_63counter)
>> now *= 64;
>>
>> - if (nrdy)
>> - break;
>> -
>> mbwu_state = &ris->mbwu_state[ctx->mon];
>>
>> if (overflow)
>> @@ -1419,22 +1421,16 @@ static void __ris_msmon_read(void *arg)
>> now += mbwu_state->correction;
>> break;
>> default:
>> - m->err = -EINVAL;
>> + ret = -EINVAL;
>> }
>> - mpam_mon_sel_unlock(msc);
>> -
>> - if (nrdy)
>> - m->err = -EBUSY;
>> -
>> - if (!m->err)
>> - *m->val += now;
>> -
>> - return;
>>
>> out_unlock:
>> mpam_mon_sel_unlock(msc);
>>
>> - m->err = ret;
>> + if (ret)
>> + m->err = ret;
>> + else
>> + *m->val += now;
>> }
>>
>> static int _msmon_read(struct mpam_component *comp, struct mon_read *arg)
>
^ permalink raw reply
* Re: [PATCH v3 08/16] arm_mpam: propagate MSC read errors for state saving functions
From: Andre Przywara @ 2026-07-20 15:57 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla, Catalin Marinas,
Will Deacon, Rafael J . Wysocki, Len Brown, James Morse,
Ben Horgan, Reinette Chatre, Fenghua Yu, Jonathan Cameron,
Srivathsa L Rao, Ganapatrao Kulkarni, Trilok Soni,
Srinivas Ramana, Niyas Sait, linux-acpi, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260710120054.000035dc@oss.qualcomm.com>
Hi Jonathan,
On 7/10/26 21:00, Jonathan Cameron wrote:
> On Fri, 10 Jul 2026 16:45:12 +0200
> Andre Przywara <andre.przywara@arm.com> wrote:
>
>> Allow the mpam_save_mbwu_state() function to return an error, and
>> propagate read errors from the lower level up.
>
> I'm not following why propagating errors is related to the
> if (val != MSMON___L_NRDY)
> as nothing in this patch is changing val.
This MSMON__L_NRDY bit is some kind of software error condition, that
gets set in mpam_msc_read_mbwu_l() to indicate an unstable value
condition. In the lack of an error return value this was somewhat
shoehorned into the return value, and now we can get rid of that kludge,
since we gained a proper error return value. At least that was my hope,
but maybe I missed something.
Cheers,
Andre
>
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> drivers/resctrl/mpam_devices.c | 30 +++++++++++++++++++-----------
>> 1 file changed, 19 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
>> index 530ac0fe97b5..b2ecaba29fcc 100644
>> --- a/drivers/resctrl/mpam_devices.c
>> +++ b/drivers/resctrl/mpam_devices.c
>> @@ -1782,7 +1782,7 @@ static int mpam_save_mbwu_state(void *arg)
>> {
>> int i;
>> u64 val;
>> - int ret = 0;
>> + int ret;
>> struct mon_cfg *cfg;
>> u32 cur_flt, cur_ctl, mon_sel;
>> struct mpam_msc_ris *ris = arg;
>> @@ -1799,8 +1799,12 @@ static int mpam_save_mbwu_state(void *arg)
>> mon_sel = FIELD_PREP(MSMON_CFG_MON_SEL_MON_SEL, i) |
>> FIELD_PREP(MSMON_CFG_MON_SEL_RIS, ris->ris_idx);
>> mpam_write_monsel_reg(msc, CFG_MON_SEL, mon_sel);
>> - mpam_read_monsel_reg(msc, CFG_MBWU_FLT, &cur_flt);
>> - mpam_read_monsel_reg(msc, CFG_MBWU_CTL, &cur_ctl);
>> + ret = mpam_read_monsel_reg(msc, CFG_MBWU_FLT, &cur_flt);
>> + if (ret)
>> + goto out_unlock;
>> + ret = mpam_read_monsel_reg(msc, CFG_MBWU_CTL, &cur_ctl);
>> + if (ret)
>> + goto out_unlock;
>> mpam_write_monsel_reg(msc, CFG_MBWU_CTL, 0);
>>
>> if (mpam_ris_has_mbwu_long_counter(ris)) {
>> @@ -1811,20 +1815,24 @@ static int mpam_save_mbwu_state(void *arg)
>> } else {
>> u32 val32;
>>
>> - mpam_read_monsel_reg(msc, MBWU, &val32);
>> + ret = mpam_read_monsel_reg(msc, MBWU, &val32);
>> + if (ret)
>> + goto out_unlock;
>> +
>> val = val32;
>> mpam_write_monsel_reg(msc, MBWU, 0);
>> }
>>
>> - cfg->mon = i;
>> - cfg->pmg = FIELD_GET(MSMON_CFG_x_FLT_PMG, cur_flt);
>> - cfg->match_pmg = FIELD_GET(MSMON_CFG_x_CTL_MATCH_PMG, cur_ctl);
>> - cfg->partid = FIELD_GET(MSMON_CFG_x_FLT_PARTID, cur_flt);
>> - mbwu_state->correction += val;
>> - mbwu_state->enabled = FIELD_GET(MSMON_CFG_x_CTL_EN, cur_ctl);
>> + if (val != MSMON___L_NRDY) {
>
> with ACQUIRE() you can just do
> if (val == MS_MON__L_NRDY)
> return;
>
> and leave the rest where it was.
> However I don't actually see what this has to do wiht the main purpose of the
> patch to propagate errors. Perhaps a bit more detail in the commit message.
>
> Thanks,
>
> Jonathan
>
>
>> + cfg->mon = i;
>> + cfg->pmg = FIELD_GET(MSMON_CFG_x_FLT_PMG, cur_flt);
>> + cfg->match_pmg = FIELD_GET(MSMON_CFG_x_CTL_MATCH_PMG, cur_ctl);
>> + cfg->partid = FIELD_GET(MSMON_CFG_x_FLT_PARTID, cur_flt);
>> + mbwu_state->correction += val;
>> + mbwu_state->enabled = FIELD_GET(MSMON_CFG_x_CTL_EN, cur_ctl);
>> + }
>> mpam_mon_sel_unlock(msc);
>> }
>> -
>> return 0;
>>
>> out_unlock:
>
^ permalink raw reply
* Re: [PATCH v3 07/16] arm_mpam: __ris_msmon_read(): get rid of nrdy special handling
From: Andre Przywara @ 2026-07-20 15:57 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla, Catalin Marinas,
Will Deacon, Rafael J . Wysocki, Len Brown, James Morse,
Ben Horgan, Reinette Chatre, Fenghua Yu, Jonathan Cameron,
Srivathsa L Rao, Ganapatrao Kulkarni, Trilok Soni,
Srinivas Ramana, Niyas Sait, linux-acpi, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260710115656.00001345@oss.qualcomm.com>
Hi,
On 7/10/26 20:56, Jonathan Cameron wrote:
> On Fri, 10 Jul 2026 16:45:11 +0200
> Andre Przywara <andre.przywara@arm.com> wrote:
>
>> Although so far MSC accesses couldn't fail, there is one special
>> condition that would create an error: when the MBWU counter wouldn't be
>> able to read a stable value, we were setting bit 63 to mark this value
>> as unstable, and return this as an error later.
>> Now since the functions can return a proper error value, we can get rid of
>> this kludge and use the return value directly.
>>
>> Remove the "nrdy" error flag variable, and assign -EBUSY to "ret" to handle
>> this case.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Hi Andre
>
> I'm still fussing about code flow and style :(
>
> Obviously none of this is that important, but it does help make
> the code more maintainable in the long run.
>
> Jonathan
>
>> ---
>> drivers/resctrl/mpam_devices.c | 38 +++++++++++++++-------------------
>> 1 file changed, 17 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
>> index 84a8715464be..530ac0fe97b5 100644
>> --- a/drivers/resctrl/mpam_devices.c
>> +++ b/drivers/resctrl/mpam_devices.c
>> @@ -1306,7 +1306,6 @@ static void __ris_msmon_read(void *arg)
>> u64 now;
>> int ret;
>> u32 now32;
>> - bool nrdy = false;
>> bool config_mismatch;
>> bool overflow = false;
>> struct mon_read *m = arg;
>> @@ -1371,14 +1370,18 @@ static void __ris_msmon_read(void *arg)
>> switch (m->type) {
>> case mpam_feat_msmon_csu:
>> ret = mpam_read_monsel_reg(msc, CSU, &now32);
>> + if (!ret) {
>> + if ((now32 & MSMON___NRDY))
>> + ret = -EBUSY;
>> +
>> + if (mpam_has_quirk(IGNORE_CSU_NRDY, msc) &&
>> + m->waited_timeout)
>> + ret = 0;
> Whilst it is from existing code, this pattern of set and error then clear it
> is less than ideal. Maybe
>
> if ((now32 & MSMON___NRDY) &&
> !(mpam_has_quirk(IGNORE_CS_NRDY, MSC && m->waited_timeout))
> ret = -EBUSY;
>
> is clearer as that odd intermediate state of ret never happens.
Is it? I see where you are coming from, and I actually had it like this
before, but I found this combination of conditions harder to read. Also
this is a quirk, so an exception, and I think the extra check makes this
clearer that this is some unfortunate mishap we don't really want, but
have to deal with.
But it's of course easy to change ...
>
>> + }
>> if (ret)
>> goto out_unlock;
>> - nrdy = now32 & MSMON___NRDY;
>> - now = FIELD_GET(MSMON___VALUE, now32);
>> -
>> - if (mpam_has_quirk(IGNORE_CSU_NRDY, msc) && m->waited_timeout)
>> - nrdy = false;
>>
>> + now = FIELD_GET(MSMON___VALUE, now32);
>> break;
>> case mpam_feat_msmon_mbwu_31counter:
>> case mpam_feat_msmon_mbwu_44counter:
>> @@ -1394,9 +1397,11 @@ static void __ris_msmon_read(void *arg)
>> now = FIELD_GET(MSMON___L_VALUE, now);
>> } else {
>> ret = mpam_read_monsel_reg(msc, MBWU, &now32);
>> + if (!ret && (now32 & MSMON___NRDY))
>> + ret = -EBUSY;
>> if (ret)
>> goto out_unlock;
>> - nrdy = now32 & MSMON___NRDY;
>> +
>> now = FIELD_GET(MSMON___VALUE, now32);
>> }
>>
>> @@ -1404,9 +1409,6 @@ static void __ris_msmon_read(void *arg)
>> m->type != mpam_feat_msmon_mbwu_63counter)
>> now *= 64;
>>
>> - if (nrdy)
>> - break;
>> -
>> mbwu_state = &ris->mbwu_state[ctx->mon];
>>
>> if (overflow)
>> @@ -1419,22 +1421,16 @@ static void __ris_msmon_read(void *arg)
>> now += mbwu_state->correction;
>> break;
>> default:
>> - m->err = -EINVAL;
>> + ret = -EINVAL;
>> }
>> - mpam_mon_sel_unlock(msc);
>> -
>> - if (nrdy)
>> - m->err = -EBUSY;
>> -
>> - if (!m->err)
>> - *m->val += now;
>> -
>> - return;
>>
>> out_unlock:
>> mpam_mon_sel_unlock(msc);
>>
>> - m->err = ret;
>> + if (ret)
>> + m->err = ret;
>> + else
>> + *m->val += now;
>
> If you do the earlier suggestion of ACQUIRE() this all get simpler, but if you do keep
> this, then burn a line or two of code to make it obvious what is error and what isn't.
>
> if (ret) {
> m->err = ret;
> return;
> }
>
> *m->val += now;
>> }
>
So I started to put scoped_guard's and ACQUIRE() everywhere now, will
see how this turns out.
Cheers,
Andre
^ permalink raw reply
* Re: [PATCH 7/7] soc: xilinx: Remove redundant dev_err()
From: Pandey, Radhey Shyam @ 2026-07-20 15:50 UTC (permalink / raw)
To: Pan Chuang, Michal Simek, Prasanna Kumar T S M, Marco Crivellari,
Jay Buddhabhatti, moderated list:ARM/ZYNQ ARCHITECTURE, open list
In-Reply-To: <20260720095920.542801-8-panchuang@vivo.com>
On 7/20/2026 3:29 PM, Pan Chuang wrote:
> Since commit 55b48e23f5c4 ("genirq/devres: Add error handling in
> devm_request_*_irq()"), devm_request_threaded_irq() automatically logs
> detailed error messages on failure. Remove the now-redundant
> driver-specific dev_err() calls.
>
> Signed-off-by: Pan Chuang <panchuang@vivo.com>
> ---
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
Thanks!
> drivers/soc/xilinx/zynqmp_power.c | 5 +----
> 1 file changed, 1 insertion(+), 4 deletions(-)
>
> diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c
> index 370e61ac47d8..54c796afb89e 100644
> --- a/drivers/soc/xilinx/zynqmp_power.c
> +++ b/drivers/soc/xilinx/zynqmp_power.c
> @@ -368,11 +368,8 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
> IRQF_NO_SUSPEND | IRQF_ONESHOT,
> dev_name(&pdev->dev),
> &pdev->dev);
> - if (ret) {
> - dev_err(&pdev->dev, "devm_request_threaded_irq '%d' failed with %d\n",
> - irq, ret);
> + if (ret)
> return ret;
> - }
> } else {
> dev_err(&pdev->dev, "Required property not found in DT node\n");
> return -ENOENT;
^ permalink raw reply
* Re: [PATCH v2] KVM: arm64: Reject guest_memfd memslots when the VM has MTE
From: Marc Zyngier @ 2026-07-20 15:46 UTC (permalink / raw)
To: Alexandru Elisei
Cc: oupton, joey.gouly, seiden, suzuki.poulose, yuzenghui,
linux-arm-kernel, kvmarm, catalin.marinas, will, steven.price,
fuad.tabba
In-Reply-To: <20260720130942.135033-1-alexandru.elisei@arm.com>
On Mon, 20 Jul 2026 14:09:42 +0100,
Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>
> The user cannot use MTE on VMAs created by mapping a guest_memfd file,
> as arch_calc_vm_flag_bits() does not set VM_MTE_ALLOWED.
>
> When creating a guest_memfd backed memslot,
> kvm_arch_prepare_memory_region() rejects the memslot if MTE is enabled for
> the VM and if guest_memfd has been mapped in a VMA that intersects the
> memslot.
>
> However, the documentation for KVM_SET_USER_MEMORY_REGION2 explicitly
> states that the only condition for userspace_addr is for it to be a legal
> userspace address, but the mapping is not required to be valid nor
> populated at memslot creation.
>
> If userspace sets userspace_addr to an address that hasn't been mapped, or
> if userspace_addr belongs to a VMA that isn't backed by the guest_memfd
> file, or if the VMA doesn't intersect the memslot, memslot creation is
> successful and KVM ends up with a VM with MTE and guest_memfd-backed
> memslots.
>
> The same happens if the order is reversed: when userspace enables MTE, KVM
> does not check if memslots backed by guest_memfd are already present.
>
> Fix both issues by rejecting guest_memfd-backed memslots when MTE is
> enabled, and by reject MTE when guest_memfd-backed memslots are already
> present.
>
> Fixes: 32e200bd6e44 ("KVM: arm64: Enable support for guest_memfd backed memory")
> Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
This looks reasonable to me, but you probably want to capture some of
that in the documentation one way or another, because this will leave
the amateur VMM author puzzled for a bit...
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* [PATCH v2 2/2] drm/bridge: it6505: Don't reject audio hw_params without an encoder
From: Daniel Golle @ 2026-07-20 15:44 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Matthias Brugger, AngeloGioacchino Del Regno, Hermes Wu,
Allen Chen, dri-devel, linux-kernel, linux-arm-kernel,
linux-mediatek
In-Reply-To: <cover.1784561622.git.daniel@makrotopia.org>
it6505_audio_setup_hw_params() returns -ENODEV when the bridge is not
attached to a DRM encoder. Now that it6505 registers an hdmi-audio-codec,
this callback runs whenever a stream is configured on the I2S DAI it is
wired to, including when that DAI is shared with another codec. On
mt8186-corsola the speaker amplifier (rt1019) and it6505 share I2S3, so
when the it6505 DP output has no display attached (bridge.encoder is
NULL) the -ENODEV propagates up through dpcm_be_dai_hw_params() and tears
down the whole backend, breaking speaker playback.
The check is harmful in its own right: the rest of the function only
caches the stream parameters (channel count, rate, word length) in
software, none of which needs an encoder. Returning early leaves
it6505->audio.channel_count at 0, which would then index
audio_info_ca[-1] in it6505_enable_audio_infoframe() should a display be
hotplugged while a stream is running, and makes such a hotplug play with
stale parameters.
Drop the encoder check so the parameters are always cached; the actual
audio output is already gated by it6505->powered.
Fixes: b5c84a9edcd4 ("drm/bridge: add it6505 driver")
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v2:
* drop the encoder check entirely instead of returning 0 early, so
the stream parameters are always cached even while no display is
attached; rewrite the commit message to explain why the check is
harmful
drivers/gpu/drm/bridge/ite-it6505.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c
index d84441926e8e..e20edbbb7c13 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -2979,9 +2979,6 @@ static int it6505_audio_setup_hw_params(struct it6505 *it6505,
params->sample_rate, params->sample_width,
params->cea.channels);
- if (!it6505->bridge.encoder)
- return -ENODEV;
-
if (params->cea.channels <= 1 || params->cea.channels > 8) {
DRM_DEV_DEBUG_DRIVER(dev, "channel number: %d not support",
it6505->audio.channel_count);
--
2.55.0
^ permalink raw reply related
* [PATCH v2 1/2] drm/bridge: it6505: Add audio support
From: Daniel Golle @ 2026-07-20 15:43 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Matthias Brugger, AngeloGioacchino Del Regno, Hermes Wu,
Allen Chen, dri-devel, linux-kernel, linux-arm-kernel,
linux-mediatek
In-Reply-To: <cover.1784561622.git.daniel@makrotopia.org>
From: Jiaxin Yu <jiaxin.yu@mediatek.com>
Add audio support for it6505 by bridging to the hdmi-codec, registering
an "hdmi-audio-codec" platform device from probe. The it6505's audio
setup/shutdown helpers were merged earlier as unused code; wire them up
via hdmi_codec_ops so the DAI actually appears, which unblocks the
mt8186-mt6366 sound card that references it6505 as the I2S3 codec.
Some DP-to-HDMI dongles get into a bad state if InfoFrame is sent
without audio data, so it6505's audio is only enabled once the stream
is unmuted.
Signed-off-by: Jiaxin Yu <jiaxin.yu@mediatek.com>
Link: https://lore.kernel.org/all/20230730180803.22570-4-jiaxin.yu@mediatek.com/
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
djg: respin of Jiaxin Yu's v3, rebased onto current mainline. Changes
from v3: hdmi_codec_ops lost .trigger, so drive enable/disable from
.mute_stream; drop the now-redundant __maybe_unused; use it6505->dev
instead of &client->dev, addressing AngeloGioacchino Del Regno's v3
review. Also fix issues in v3: initialise delayed_audio before
registering the codec device; keep and unregister the platform_device
and cancel delayed_audio on remove to avoid a leak and a
use-after-free; cancel the delayed work on audio shutdown; and
actually disable audio (not just cancel the pending enable) when the
stream is muted.
Note: it6505_enable_audio()/it6505_disable_audio() can still run
concurrently from the delayed work, the .mute_stream / .audio_shutdown
callbacks and the audio-FIFO-error IRQ; as in v3 these are left
unserialised -- input welcome on whether a lock is warranted.
v2:
* store the hdmi-codec platform_device and unregister it on i2c
remove, fixing a resource leak and use-after-free on unbind
* initialise the delayed audio work before registering the codec
device instead of after
* synchronously cancel the delayed audio work on audio shutdown and
on driver remove (cancel_delayed_work_sync)
* rework the mute path to cancel pending work synchronously and
disable audio immediately when muting, removing a race with the
delayed enable work
drivers/gpu/drm/bridge/ite-it6505.c | 101 +++++++++++++++++++++++-----
1 file changed, 85 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c
index 8ecb43611dba..d84441926e8e 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -476,6 +476,7 @@ struct it6505 {
bool enable_enhanced_frame;
hdmi_codec_plugged_cb plugged_cb;
struct device *codec_dev;
+ struct platform_device *audio_pdev;
struct delayed_work delayed_audio;
struct it6505_audio_data audio;
struct dentry *debugfs;
@@ -2320,19 +2321,12 @@ static void it6505_stop_link_train(struct it6505 *it6505)
static void it6505_link_train_ok(struct it6505 *it6505)
{
- struct device *dev = it6505->dev;
-
it6505->link_state = LINK_OK;
/* disalbe mute enable avi info frame */
it6505_set_bits(it6505, REG_DATA_MUTE_CTRL, EN_VID_MUTE, 0x00);
it6505_set_bits(it6505, REG_INFOFRAME_CTRL,
EN_VID_CTRL_PKT, EN_VID_CTRL_PKT);
- if (it6505_audio_input(it6505)) {
- DRM_DEV_DEBUG_DRIVER(dev, "Enable audio!");
- it6505_enable_audio(it6505);
- }
-
if (it6505->hdcp_desired)
it6505_start_hdcp(it6505);
}
@@ -2960,7 +2954,7 @@ static void it6505_remove_notifier_module(struct it6505 *it6505)
}
}
-static void __maybe_unused it6505_delayed_audio(struct work_struct *work)
+static void it6505_delayed_audio(struct work_struct *work)
{
struct it6505 *it6505 = container_of(work, struct it6505,
delayed_audio.work);
@@ -2974,9 +2968,9 @@ static void __maybe_unused it6505_delayed_audio(struct work_struct *work)
it6505_enable_audio(it6505);
}
-static int __maybe_unused it6505_audio_setup_hw_params(struct it6505 *it6505,
- struct hdmi_codec_params
- *params)
+static int it6505_audio_setup_hw_params(struct it6505 *it6505,
+ struct hdmi_codec_params
+ *params)
{
struct device *dev = it6505->dev;
int i = 0;
@@ -3031,18 +3025,52 @@ static int __maybe_unused it6505_audio_setup_hw_params(struct it6505 *it6505,
return 0;
}
-static void __maybe_unused it6505_audio_shutdown(struct device *dev, void *data)
+static void it6505_audio_shutdown(struct device *dev, void *data)
{
struct it6505 *it6505 = dev_get_drvdata(dev);
+ cancel_delayed_work_sync(&it6505->delayed_audio);
if (it6505->powered)
it6505_disable_audio(it6505);
}
-static int __maybe_unused it6505_audio_hook_plugged_cb(struct device *dev,
- void *data,
- hdmi_codec_plugged_cb fn,
- struct device *codec_dev)
+static int it6505_audio_hw_params(struct device *dev, void *data,
+ struct hdmi_codec_daifmt *daifmt,
+ struct hdmi_codec_params *params)
+{
+ struct it6505 *it6505 = dev_get_drvdata(dev);
+
+ return it6505_audio_setup_hw_params(it6505, params);
+}
+
+static int it6505_audio_mute(struct device *dev, void *data,
+ bool enable, int direction)
+{
+ struct it6505 *it6505 = dev_get_drvdata(dev);
+
+ DRM_DEV_DEBUG_DRIVER(dev, "mute: %d", enable);
+
+ /*
+ * Some DP-to-HDMI dongles get into a bad state if the InfoFrame is
+ * sent without audio data, so only enable it6505's audio once the
+ * stream is unmuted (i.e. actually playing).
+ */
+ if (enable) {
+ cancel_delayed_work_sync(&it6505->delayed_audio);
+ if (it6505->powered)
+ it6505_disable_audio(it6505);
+ } else {
+ queue_delayed_work(system_wq, &it6505->delayed_audio,
+ msecs_to_jiffies(180));
+ }
+
+ return 0;
+}
+
+static int it6505_audio_hook_plugged_cb(struct device *dev,
+ void *data,
+ hdmi_codec_plugged_cb fn,
+ struct device *codec_dev)
{
struct it6505 *it6505 = data;
@@ -3053,6 +3081,39 @@ static int __maybe_unused it6505_audio_hook_plugged_cb(struct device *dev,
return 0;
}
+static const struct hdmi_codec_ops it6505_audio_codec_ops = {
+ .hw_params = it6505_audio_hw_params,
+ .mute_stream = it6505_audio_mute,
+ .audio_shutdown = it6505_audio_shutdown,
+ .hook_plugged_cb = it6505_audio_hook_plugged_cb,
+};
+
+static int it6505_register_audio_driver(struct device *dev)
+{
+ struct it6505 *it6505 = dev_get_drvdata(dev);
+ struct hdmi_codec_pdata codec_data = {
+ .ops = &it6505_audio_codec_ops,
+ .max_i2s_channels = 8,
+ .i2s = 1,
+ .no_capture_mute = 1,
+ .data = it6505,
+ };
+ struct platform_device *pdev;
+
+ INIT_DELAYED_WORK(&it6505->delayed_audio, it6505_delayed_audio);
+
+ pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
+ PLATFORM_DEVID_AUTO, &codec_data,
+ sizeof(codec_data));
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ it6505->audio_pdev = pdev;
+ DRM_DEV_DEBUG_DRIVER(dev, "bound to %s", HDMI_CODEC_DRV_NAME);
+
+ return 0;
+}
+
static inline struct it6505 *bridge_to_it6505(struct drm_bridge *bridge)
{
return container_of(bridge, struct it6505, bridge);
@@ -3612,6 +3673,12 @@ static int it6505_i2c_probe(struct i2c_client *client)
return err;
}
+ err = it6505_register_audio_driver(dev);
+ if (err < 0) {
+ dev_err(dev, "Failed to register audio driver: %d", err);
+ return err;
+ }
+
INIT_WORK(&it6505->link_works, it6505_link_training_work);
INIT_WORK(&it6505->hdcp_wait_ksv_list, it6505_hdcp_wait_ksv_list);
INIT_DELAYED_WORK(&it6505->hdcp_work, it6505_hdcp_work);
@@ -3644,6 +3711,8 @@ static void it6505_i2c_remove(struct i2c_client *client)
{
struct it6505 *it6505 = i2c_get_clientdata(client);
+ platform_device_unregister(it6505->audio_pdev);
+ cancel_delayed_work_sync(&it6505->delayed_audio);
drm_bridge_remove(&it6505->bridge);
drm_dp_aux_unregister(&it6505->aux);
it6505_debugfs_remove(it6505);
--
2.55.0
^ permalink raw reply related
* Re: [PATCH net-next v9 12/12] net: airoha: add phylink support
From: Christian Marangi @ 2026-07-20 15:43 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Simon Horman, Jonathan Corbet, Shuah Khan, Heiner Kallweit,
Russell King, Saravana Kannan, Philipp Zabel, netdev, devicetree,
linux-kernel, linux-doc, linux-arm-kernel, linux-mediatek,
Maxime Chevallier
In-Reply-To: <al5AVLxWRhnpGzJ1@lore-desk>
On Mon, Jul 20, 2026 at 05:35:48PM +0200, Lorenzo Bianconi wrote:
> > Add phylink support for each GDM port. For GDM1 add the internal interface
> > mode as the only supported mode. For GDM2/3/4 add the required
> > configuration of the PCS to make the external PHY or attached SFP cage
> > work.
> >
> > These needs to be defined in the GDM port node using the pcs-handle
> > property.
> >
> > Update and provide a .get/set_link_ksettings function that use phylink
> > for ethtool OPs now that we fully support phylink.
> >
> > Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
> > ---
> > drivers/net/ethernet/airoha/Kconfig | 1 +
> > drivers/net/ethernet/airoha/airoha_eth.c | 194 +++++++++++++++++++++-
> > drivers/net/ethernet/airoha/airoha_eth.h | 7 +-
> > drivers/net/ethernet/airoha/airoha_regs.h | 12 ++
> > 4 files changed, 207 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/airoha/Kconfig b/drivers/net/ethernet/airoha/Kconfig
> > index 1f6640a15fc9..789906516bf8 100644
> > --- a/drivers/net/ethernet/airoha/Kconfig
> > +++ b/drivers/net/ethernet/airoha/Kconfig
> > @@ -20,6 +20,7 @@ config NET_AIROHA
> > depends on NET_DSA || !NET_DSA
> > select NET_AIROHA_NPU
> > select PAGE_POOL
> > + select PHYLINK
> > help
> > This driver supports the gigabit ethernet MACs in the
> > Airoha SoC family.
> > diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> > index 59001fd4b6f7..ed1ac032f337 100644
> > --- a/drivers/net/ethernet/airoha/airoha_eth.c
> > +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> > @@ -8,6 +8,7 @@
> > #include <linux/of_reserved_mem.h>
> > #include <linux/platform_device.h>
> > #include <linux/tcp.h>
> > +#include <linux/pcs/pcs.h>
> > #include <linux/u64_stats_sync.h>
> > #include <net/dst_metadata.h>
> > #include <net/page_pool/helpers.h>
> > @@ -1837,7 +1838,7 @@ static void airoha_update_hw_stats(struct airoha_gdm_dev *dev)
> > struct airoha_gdm_port *port = dev->port;
> > int i;
> >
> > - spin_lock(&port->stats_lock);
> > + spin_lock(&port->lock);
>
> Hi Christian,
>
> as pointed out in a previous email, I do not like the approach of reusing this
> spin_lock for airoha_mac_link_up(). Can we use rtl_lock() (when necessary) as
> pointed out before?
>
For context, quoting from the previous series, the suggestion is to use
rtnl_is_locked() and then lock accordingly but I didn't find other usage of
that in other driver (aside from core net) and I don't like the use of
is_locked. I can already see the BOT saying that in the timeframe of
is_locked and writing the register another interface goes up causing a
race.
Guess I will add a simple mutex for this case and the other.
> >
> > for (i = 0; i < ARRAY_SIZE(port->devs); i++) {
> > if (port->devs[i])
> > @@ -1848,7 +1849,7 @@ static void airoha_update_hw_stats(struct airoha_gdm_dev *dev)
> > airoha_fe_set(dev->eth, REG_FE_GDM_MIB_CLEAR(port->id),
> > FE_GDM_MIB_RX_CLEAR_MASK | FE_GDM_MIB_TX_CLEAR_MASK);
> >
> > - spin_unlock(&port->stats_lock);
> > + spin_unlock(&port->lock);
> > }
> >
> > static void airoha_dev_set_xmit_frame_size(struct net_device *netdev)
> > @@ -1870,6 +1871,14 @@ static int airoha_dev_open(struct net_device *netdev)
> > u32 pse_port = FE_PSE_PORT_PPE1;
> > int err;
> >
> > + err = phylink_of_phy_connect(dev->phylink, netdev->dev.of_node, 0);
> > + if (err) {
> > + netdev_err(netdev, "could not attach PHY: %d\n", err);
> > + return err;
> > + }
> > +
> > + phylink_start(dev->phylink);
> > +
> > netif_tx_start_all_queues(netdev);
> > err = airoha_set_vip_for_gdm_port(dev, true);
> > if (err)
> > @@ -1909,6 +1918,10 @@ static int airoha_dev_stop(struct net_device *netdev)
> > airoha_set_gdm_port_fwd_cfg(qdma->eth,
> > REG_GDM_FWD_CFG(port->id),
> > FE_PSE_PORT_DROP);
> > +
> > + phylink_stop(dev->phylink);
> > + phylink_disconnect_phy(dev->phylink);
> > +
> > return 0;
> > }
> >
> > @@ -2389,6 +2402,24 @@ airoha_ethtool_get_rmon_stats(struct net_device *netdev,
> > } while (u64_stats_fetch_retry(&dev->stats.syncp, start));
> > }
> >
> > +static int
> > +airoha_ethtool_get_link_ksettings(struct net_device *netdev,
> > + struct ethtool_link_ksettings *cmd)
> > +{
> > + struct airoha_gdm_dev *dev = netdev_priv(netdev);
> > +
> > + return phylink_ethtool_ksettings_get(dev->phylink, cmd);
> > +}
> > +
> > +static int
> > +airoha_ethtool_set_link_ksettings(struct net_device *netdev,
> > + const struct ethtool_link_ksettings *cmd)
> > +{
> > + struct airoha_gdm_dev *dev = netdev_priv(netdev);
> > +
> > + return phylink_ethtool_ksettings_set(dev->phylink, cmd);
> > +}
> > +
> > static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev,
> > int channel, enum tx_sched_mode mode,
> > const u16 *weights, u8 n_weights)
> > @@ -3120,7 +3151,8 @@ static const struct ethtool_ops airoha_ethtool_ops = {
> > .get_drvinfo = airoha_ethtool_get_drvinfo,
> > .get_eth_mac_stats = airoha_ethtool_get_mac_stats,
> > .get_rmon_stats = airoha_ethtool_get_rmon_stats,
> > - .get_link_ksettings = phy_ethtool_get_link_ksettings,
> > + .get_link_ksettings = airoha_ethtool_get_link_ksettings,
> > + .set_link_ksettings = airoha_ethtool_set_link_ksettings,
> > .get_link = ethtool_op_get_link,
> > };
> >
> > @@ -3176,6 +3208,155 @@ bool airoha_is_valid_gdm_dev(struct airoha_eth *eth,
> > return false;
> > }
> >
> > +/* Nothing to do in MAC, everything is handled in PCS */
> > +static void airoha_mac_config(struct phylink_config *config, unsigned int mode,
> > + const struct phylink_link_state *state)
> > +{
> > +}
> > +
> > +static void airoha_mac_link_up(struct phylink_config *config, struct phy_device *phy,
> > + unsigned int mode, phy_interface_t interface,
> > + int speed, int duplex, bool tx_pause, bool rx_pause)
> > +{
> > + struct airoha_gdm_dev *dev = container_of(config, struct airoha_gdm_dev,
> > + phylink_config);
> > + struct airoha_gdm_port *port = dev->port;
> > + struct airoha_eth *eth = dev->eth;
> > + u32 frag_size_tx, frag_size_rx;
> > + u32 mask, val;
> > +
> > + /* TX/RX frag is configured only for GDM4 */
> > + if (port->id != AIROHA_GDM4_IDX)
> > + return;
> > +
> > + switch (speed) {
> > + case SPEED_10000:
> > + case SPEED_5000:
> > + frag_size_tx = 8;
> > + frag_size_rx = 8;
> > + break;
> > + case SPEED_2500:
> > + frag_size_tx = 2;
> > + frag_size_rx = 1;
> > + break;
> > + default:
> > + frag_size_tx = 1;
> > + frag_size_rx = 0;
> > + }
> > +
> > + spin_lock(&port->lock);
> > +
> > + /* Configure TX/RX frag based on speed */
> > + if (dev->nbq == 1) {
> > + mask = GDM4_SGMII1_TX_FRAG_SIZE_MASK;
> > + val = FIELD_PREP(GDM4_SGMII1_TX_FRAG_SIZE_MASK,
> > + frag_size_tx);
> > + } else {
> > + mask = GDM4_SGMII0_TX_FRAG_SIZE_MASK;
> > + val = FIELD_PREP(GDM4_SGMII0_TX_FRAG_SIZE_MASK,
> > + frag_size_tx);
> > + }
> > + airoha_fe_rmw(eth, REG_FE_GDM4_TMBI_FRAG, mask, val);
> > +
> > + if (dev->nbq == 1) {
> > + mask = GDM4_SGMII1_RX_FRAG_SIZE_MASK;
> > + val = FIELD_PREP(GDM4_SGMII1_RX_FRAG_SIZE_MASK,
> > + frag_size_rx);
> > + } else {
> > + mask = GDM4_SGMII0_RX_FRAG_SIZE_MASK;
> > + val = FIELD_PREP(GDM4_SGMII0_RX_FRAG_SIZE_MASK,
> > + frag_size_rx);
> > + }
> > + airoha_fe_rmw(eth, REG_FE_GDM4_RMBI_FRAG, mask, val);
> > +
> > + spin_unlock(&port->lock);
> > +}
> > +
> > +/* Nothing to do in MAC, everything is handled in PCS */
> > +static void airoha_mac_link_down(struct phylink_config *config, unsigned int mode,
> > + phy_interface_t interface)
> > +{
> > +}
> > +
> > +static const struct phylink_mac_ops airoha_phylink_ops = {
> > + .mac_config = airoha_mac_config,
> > + .mac_link_up = airoha_mac_link_up,
> > + .mac_link_down = airoha_mac_link_down,
> > +};
> > +
> > +static int airoha_fill_available_pcs(struct phylink_config *config,
> > + struct phylink_pcs **available_pcs,
> > + unsigned int num_possible_pcs)
> > +{
> > + struct device *dev = config->dev;
> > +
> > + return fwnode_phylink_pcs_parse(dev_fwnode(dev), available_pcs,
> > + num_possible_pcs);
> > +}
> > +
> > +static int airoha_setup_phylink(struct net_device *netdev)
> > +{
> > + struct airoha_gdm_dev *dev = netdev_priv(netdev);
> > + struct device_node *np = netdev->dev.of_node;
> > + struct airoha_gdm_port *port = dev->port;
> > + struct phylink_config *config;
> > + phy_interface_t phy_mode;
> > + struct phylink *phylink;
> > + int err;
> > +
> > + err = of_get_phy_mode(np, &phy_mode);
> > + if (err) {
> > + dev_err(&netdev->dev, "incorrect phy-mode\n");
> > + return err;
> > + }
> > +
> > + config = &dev->phylink_config;
> > + config->dev = &netdev->dev;
> > + config->type = PHYLINK_NETDEV;
> > +
> > + /*
> > + * GDM1 only supports internal for Embedded Switch
> > + * and doesn't require a PCS.
> > + */
> > + if (port->id == AIROHA_GDM1_IDX) {
> > + config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
> > + MAC_10000FD;
> > +
> > + __set_bit(PHY_INTERFACE_MODE_INTERNAL,
> > + config->supported_interfaces);
> > + } else {
> > + config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
> > + MAC_10 | MAC_100 | MAC_1000 |
> > + MAC_2500FD | MAC_5000FD | MAC_10000FD;
> > +
> > + config->num_possible_pcs = fwnode_phylink_pcs_count(dev_fwnode(config->dev));
> > + config->fill_available_pcs = airoha_fill_available_pcs;
> > +
> > + __set_bit(PHY_INTERFACE_MODE_SGMII,
> > + config->supported_interfaces);
> > + __set_bit(PHY_INTERFACE_MODE_1000BASEX,
> > + config->supported_interfaces);
> > + __set_bit(PHY_INTERFACE_MODE_2500BASEX,
> > + config->supported_interfaces);
> > + __set_bit(PHY_INTERFACE_MODE_10GBASER,
> > + config->supported_interfaces);
> > + __set_bit(PHY_INTERFACE_MODE_USXGMII,
> > + config->supported_interfaces);
> > +
> > + phy_interface_copy(config->pcs_interfaces,
> > + config->supported_interfaces);
> > + }
> > +
> > + phylink = phylink_create(config, of_fwnode_handle(np),
> > + phy_mode, &airoha_phylink_ops);
> > + if (IS_ERR(phylink))
> > + return PTR_ERR(phylink);
> > +
> > + dev->phylink = phylink;
> > +
> > + return 0;
> > +}
> > +
> > static int airoha_alloc_gdm_device(struct airoha_eth *eth,
> > struct airoha_gdm_port *port,
> > int nbq, struct device_node *np)
> > @@ -3239,7 +3420,7 @@ static int airoha_alloc_gdm_device(struct airoha_eth *eth,
> > dev->nbq = nbq;
> > port->devs[index] = dev;
> >
> > - return 0;
> > + return airoha_setup_phylink(netdev);
> > }
> >
> > static int airoha_alloc_gdm_port(struct airoha_eth *eth,
> > @@ -3274,7 +3455,7 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth,
> > return -ENOMEM;
> >
> > port->id = id;
> > - spin_lock_init(&port->stats_lock);
> > + spin_lock_init(&port->lock);
> > eth->ports[p] = port;
> >
> > err = airoha_metadata_dst_alloc(port);
> > @@ -3471,6 +3652,8 @@ static int airoha_probe(struct platform_device *pdev)
> > netdev = netdev_from_priv(dev);
> > if (netdev->reg_state == NETREG_REGISTERED)
> > unregister_netdev(netdev);
> > + if (dev->phylink)
> > + phylink_destroy(dev->phylink);
> > of_node_put(netdev->dev.of_node);
> > }
> > airoha_metadata_dst_free(port);
> > @@ -3509,6 +3692,7 @@ static void airoha_remove(struct platform_device *pdev)
> >
> > netdev = netdev_from_priv(dev);
> > unregister_netdev(netdev);
> > + phylink_destroy(dev->phylink);
> > of_node_put(netdev->dev.of_node);
> > }
> > airoha_metadata_dst_free(port);
> > diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
> > index f6d01a8e8da1..b49fc5304b3a 100644
> > --- a/drivers/net/ethernet/airoha/airoha_eth.h
> > +++ b/drivers/net/ethernet/airoha/airoha_eth.h
> > @@ -561,6 +561,9 @@ struct airoha_gdm_dev {
> > int nbq;
> >
> > struct airoha_hw_stats stats;
> > +
> > + struct phylink *phylink;
> > + struct phylink_config phylink_config;
> > };
> >
> > struct airoha_gdm_port {
> > @@ -568,8 +571,8 @@ struct airoha_gdm_port {
> > int id;
> > int users;
> >
> > - /* protect concurrent hw_stats accesses */
> > - spinlock_t stats_lock;
> > + /* protect concurrent hw_stats and frag register accesses */
> > + spinlock_t lock;
> >
> > struct metadata_dst *dsa_meta[AIROHA_MAX_DSA_PORTS];
> > };
> > diff --git a/drivers/net/ethernet/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h
> > index 6fed63d013b4..8df02f51211c 100644
> > --- a/drivers/net/ethernet/airoha/airoha_regs.h
> > +++ b/drivers/net/ethernet/airoha/airoha_regs.h
> > @@ -357,6 +357,18 @@
> > #define IP_FRAGMENT_PORT_MASK GENMASK(8, 5)
> > #define IP_FRAGMENT_NBQ_MASK GENMASK(4, 0)
> >
> > +#define REG_FE_GDM4_TMBI_FRAG 0x2028
> > +#define GDM4_SGMII1_TX_WEIGHT_MASK GENMASK(31, 26)
> > +#define GDM4_SGMII1_TX_FRAG_SIZE_MASK GENMASK(25, 16)
> > +#define GDM4_SGMII0_TX_WEIGHT_MASK GENMASK(15, 10)
> > +#define GDM4_SGMII0_TX_FRAG_SIZE_MASK GENMASK(9, 0)
> > +
> > +#define REG_FE_GDM4_RMBI_FRAG 0x202c
> > +#define GDM4_SGMII1_RX_WEIGHT_MASK GENMASK(31, 26)
> > +#define GDM4_SGMII1_RX_FRAG_SIZE_MASK GENMASK(25, 16)
> > +#define GDM4_SGMII0_RX_WEIGHT_MASK GENMASK(15, 10)
> > +#define GDM4_SGMII0_RX_FRAG_SIZE_MASK GENMASK(9, 0)
> > +
> > #define REG_MC_VLAN_EN 0x2100
> > #define MC_VLAN_EN_MASK BIT(0)
> >
> > --
> > 2.53.0
> >
--
Ansuel
^ permalink raw reply
* [PATCH v2 0/2] drm/bridge: it6505: DP audio support + shared-DAI hw_params fix
From: Daniel Golle @ 2026-07-20 15:42 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Matthias Brugger, AngeloGioacchino Del Regno, Hermes Wu,
Allen Chen, dri-devel, linux-kernel, linux-arm-kernel,
linux-mediatek
This series revives HDMI/DP audio support for the ITE IT6505 DP
bridge, originally posted by Jiaxin Yu [1], rebased onto current
-next and with the v3 review feedback addressed: the stale
&client->dev usages reported by AngeloGioacchino Del Regno [2] are
gone (the driver meanwhile gained it6505->dev), and the
"#sound-dai-cells" binding property requested by Chen-Yu Tsai [3] has
since been added by commit 325af1bef5b9 ("dt-bindings: display:
bridge: it6505: Add #sound-dai-cells").
Patch 1 wires up the previously-unused it6505 audio helpers via
hdmi_codec_ops, which unblocks the mt8186-mt6366 sound card that
references it6505 as the I2S3 codec.
Patch 2 is a follow-up fix so that audio hw_params are accepted even
when the it6505 DP output has no display (and thus no encoder)
attached. This is needed when the it6505 shares its I2S bus with
another codec, as on the MediaTek MT8186 "steelix" Chromebooks, where
the shared I2S3 must keep working for the speaker path regardless of
the it6505 link state.
Tested on a MediaTek MT8186 (google,steelix) Chromebook.
Actual HDMI/DP audio output could not be tested lacking the USB-C
adapter cable. However, making the it6505 at least probe and fixing
the obviously missing things makes the sound card on the Chromebook
come up and internal speakers and microphone as well as the headset
mini-jack work as expected (both tested).
[1] https://lore.kernel.org/all/20230730180803.22570-4-jiaxin.yu@mediatek.com/
[2] https://lore.kernel.org/all/c35ef2d8-ab40-484b-9a4c-38f2f3e7d99c@collabora.com/
[3] https://lore.kernel.org/all/CAGXv+5G2tP9i8VrUc6-xs2d72_nL9XH9iSCeixzA2AM7X5fXOQ@mail.gmail.com/
---
v2:
* it6505: store the hdmi-codec platform_device and unregister it on
i2c remove, fixing a resource leak / use-after-free
* it6505: initialise the delayed audio work before registering the
codec device
* it6505: synchronously cancel the delayed audio work on audio
shutdown and on driver remove (cancel_delayed_work_sync)
* it6505: rework the mute path to cancel pending work synchronously
and disable audio immediately when muting, removing a race
* patch 2: drop the encoder check entirely instead of returning 0
early, so the stream parameters are always cached; rewrite the
commit message accordingly
v1: https://lore.kernel.org/all/cover.1784393979.git.daniel@makrotopia.org/
Daniel Golle (1):
drm/bridge: it6505: Don't reject audio hw_params without an encoder
Jiaxin Yu (1):
drm/bridge: it6505: Add audio support
drivers/gpu/drm/bridge/ite-it6505.c | 104 +++++++++++++++++++++++-----
1 file changed, 85 insertions(+), 19 deletions(-)
base-commit: 0718283ab28bc3907e10b61a6b4be6fefa1cbb2f
--
2.55.0
^ permalink raw reply
* [PATCH 2/2] phy: zynqmp: fix runtime PM leak on probe allocation failure
From: Radhey Shyam Pandey @ 2026-07-20 15:38 UTC (permalink / raw)
To: tomi.valkeinen, vkoul, neil.armstrong, michal.simek
Cc: linux-kernel, linux-phy, linux-arm-kernel, git,
Radhey Shyam Pandey
In-Reply-To: <20260720153832.1130006-1-radhey.shyam.pandey@amd.com>
Allocate saved_regs before pm_runtime_resume_and_get() so a
devm_kmalloc() failure does not leave an unreleased runtime PM usage
counter.
Fixes: 5af9b304bc60 ("phy: xilinx: phy-zynqmp: Fix SGMII linkup failure on resume")
Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
---
drivers/phy/xilinx/phy-zynqmp.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c
index c8230f2bda62..2138f5399821 100644
--- a/drivers/phy/xilinx/phy-zynqmp.c
+++ b/drivers/phy/xilinx/phy-zynqmp.c
@@ -1044,6 +1044,12 @@ static int xpsgtr_probe(struct platform_device *pdev)
return PTR_ERR(provider);
}
+ gtr_dev->saved_regs = devm_kmalloc(gtr_dev->dev,
+ sizeof(save_reg_address),
+ GFP_KERNEL);
+ if (!gtr_dev->saved_regs)
+ return -ENOMEM;
+
pm_runtime_set_active(gtr_dev->dev);
pm_runtime_enable(gtr_dev->dev);
@@ -1053,12 +1059,6 @@ static int xpsgtr_probe(struct platform_device *pdev)
return ret;
}
- gtr_dev->saved_regs = devm_kmalloc(gtr_dev->dev,
- sizeof(save_reg_address),
- GFP_KERNEL);
- if (!gtr_dev->saved_regs)
- return -ENOMEM;
-
return 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH 1/2] phy: zynqmp: fix clock error handling in xpsgtr_phy_init()
From: Radhey Shyam Pandey @ 2026-07-20 15:38 UTC (permalink / raw)
To: tomi.valkeinen, vkoul, neil.armstrong, michal.simek
Cc: linux-kernel, linux-phy, linux-arm-kernel, git,
Radhey Shyam Pandey
In-Reply-To: <20260720153832.1130006-1-radhey.shyam.pandey@amd.com>
Propagate clk_prepare_enable() failures to the caller instead of
returning success, and disable the reference clock on initialization
error paths to avoid leaking clock references when phy_exit() is not
called.
Fixes: 25d700833513 ("phy: xilinx: phy-zynqmp: dynamic clock support for power-save")
Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
---
drivers/phy/xilinx/phy-zynqmp.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c
index fe6b4925d166..c8230f2bda62 100644
--- a/drivers/phy/xilinx/phy-zynqmp.c
+++ b/drivers/phy/xilinx/phy-zynqmp.c
@@ -658,12 +658,13 @@ static int xpsgtr_phy_init(struct phy *phy)
{
struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
- int ret = 0;
+ int ret;
mutex_lock(>r_dev->gtr_mutex);
/* Configure and enable the clock when peripheral phy_init call */
- if (clk_prepare_enable(gtr_dev->clk[gtr_phy->refclk]))
+ ret = clk_prepare_enable(gtr_dev->clk[gtr_phy->refclk]);
+ if (ret)
goto out;
/* Skip initialization if not required. */
@@ -673,7 +674,7 @@ static int xpsgtr_phy_init(struct phy *phy)
if (gtr_dev->tx_term_fix) {
ret = xpsgtr_phy_tx_term_fix(gtr_phy);
if (ret < 0)
- goto out;
+ goto out_disable_clk;
gtr_dev->tx_term_fix = false;
}
@@ -687,7 +688,7 @@ static int xpsgtr_phy_init(struct phy *phy)
*/
ret = xpsgtr_configure_pll(gtr_phy);
if (ret)
- goto out;
+ goto out_disable_clk;
xpsgtr_lane_set_protocol(gtr_phy);
@@ -705,6 +706,10 @@ static int xpsgtr_phy_init(struct phy *phy)
break;
}
+ goto out;
+
+out_disable_clk:
+ clk_disable_unprepare(gtr_dev->clk[gtr_phy->refclk]);
out:
mutex_unlock(>r_dev->gtr_mutex);
return ret;
--
2.43.0
^ permalink raw reply related
* [PATCH 0/2] phy: zynqmp: fix clock and runtime PM error paths in xpsgtr driver
From: Radhey Shyam Pandey @ 2026-07-20 15:38 UTC (permalink / raw)
To: tomi.valkeinen, vkoul, neil.armstrong, michal.simek
Cc: linux-kernel, linux-phy, linux-arm-kernel, git,
Radhey Shyam Pandey
This series fixes two pre-existing resource handling bugs in the Zynq
UltraScale+ MPSoC Gigabit Transceiver (XPSGTR) PHY driver. They were
reported during review of the SERDES scrambler series [1] and were
intentionally deferred to this follow-up series.
Patch 1:
Propagate clk_prepare_enable() failures from xpsgtr_phy_init() and
disable the reference clock on initialization error paths.
Patch 2:
Move saved_regs allocation before runtime PM resume to avoid
leaking the runtime PM usage count on probe failures.
[1]: https://lore.kernel.org/all/20260627155229.2791113-1-radhey.shyam.pandey@amd.com
Radhey Shyam Pandey (2):
phy: zynqmp: fix clock error handling in xpsgtr_phy_init()
phy: zynqmp: fix runtime PM leak on probe allocation failure
drivers/phy/xilinx/phy-zynqmp.c | 25 +++++++++++++++----------
1 file changed, 15 insertions(+), 10 deletions(-)
base-commit: 0718283ab28bc3907e10b61a6b4be6fefa1cbb2f
--
2.43.0
^ permalink raw reply
* Re: [PATCH v2 5/6] media: nxp: imx8-isi: Correct color map between V4L2 and ISI
From: Frank Li @ 2026-07-20 15:37 UTC (permalink / raw)
To: Guoniu Zhou
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Christian Hemp,
Stefan Riedmueller, Jacopo Mondi, Loic Poulain,
Bryan O'Donoghue, Dong Aisheng, Guoniu Zhou, linux-media, imx,
linux-arm-kernel, linux-kernel, stable
In-Reply-To: <20260720-isi-v2-5-45845bc5d4fa@oss.nxp.com>
On Mon, Jul 20, 2026 at 11:34:07AM +0800, Guoniu Zhou wrote:
> Fix the ISI input format for the color map V4L2_PIX_FMT_XBGR32 in
> memory-to-memory mode.
>
> Fixes: cf21f328fcaf ("media: nxp: Add i.MX8 ISI driver")
> Cc: stable@vger.kernel.org
> Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Changes in v2:
> - Reword commit description for clarity (Frank Li)
> ---
> drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
> index 5eb448f4c26f..05b51b98344b 100644
> --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
> +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
> @@ -151,7 +151,7 @@ static const struct mxc_isi_format_info mxc_isi_formats[] = {
> .fourcc = V4L2_PIX_FMT_XBGR32,
> .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT
> | MXC_ISI_VIDEO_M2M_CAP,
> - .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_XBGR8,
> + .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_XRGB8,
> .isi_out_format = CHNL_IMG_CTRL_FORMAT_XRGB888,
> .mem_planes = 1,
> .color_planes = 1,
>
> --
> 2.34.1
>
>
^ permalink raw reply
* Re: [PATCH net-next v9 12/12] net: airoha: add phylink support
From: Lorenzo Bianconi @ 2026-07-20 15:35 UTC (permalink / raw)
To: Christian Marangi
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Simon Horman, Jonathan Corbet, Shuah Khan, Heiner Kallweit,
Russell King, Saravana Kannan, Philipp Zabel, netdev, devicetree,
linux-kernel, linux-doc, linux-arm-kernel, linux-mediatek,
Maxime Chevallier
In-Reply-To: <20260717065448.1498335-13-ansuelsmth@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 12669 bytes --]
> Add phylink support for each GDM port. For GDM1 add the internal interface
> mode as the only supported mode. For GDM2/3/4 add the required
> configuration of the PCS to make the external PHY or attached SFP cage
> work.
>
> These needs to be defined in the GDM port node using the pcs-handle
> property.
>
> Update and provide a .get/set_link_ksettings function that use phylink
> for ethtool OPs now that we fully support phylink.
>
> Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
> ---
> drivers/net/ethernet/airoha/Kconfig | 1 +
> drivers/net/ethernet/airoha/airoha_eth.c | 194 +++++++++++++++++++++-
> drivers/net/ethernet/airoha/airoha_eth.h | 7 +-
> drivers/net/ethernet/airoha/airoha_regs.h | 12 ++
> 4 files changed, 207 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/net/ethernet/airoha/Kconfig b/drivers/net/ethernet/airoha/Kconfig
> index 1f6640a15fc9..789906516bf8 100644
> --- a/drivers/net/ethernet/airoha/Kconfig
> +++ b/drivers/net/ethernet/airoha/Kconfig
> @@ -20,6 +20,7 @@ config NET_AIROHA
> depends on NET_DSA || !NET_DSA
> select NET_AIROHA_NPU
> select PAGE_POOL
> + select PHYLINK
> help
> This driver supports the gigabit ethernet MACs in the
> Airoha SoC family.
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> index 59001fd4b6f7..ed1ac032f337 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.c
> +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> @@ -8,6 +8,7 @@
> #include <linux/of_reserved_mem.h>
> #include <linux/platform_device.h>
> #include <linux/tcp.h>
> +#include <linux/pcs/pcs.h>
> #include <linux/u64_stats_sync.h>
> #include <net/dst_metadata.h>
> #include <net/page_pool/helpers.h>
> @@ -1837,7 +1838,7 @@ static void airoha_update_hw_stats(struct airoha_gdm_dev *dev)
> struct airoha_gdm_port *port = dev->port;
> int i;
>
> - spin_lock(&port->stats_lock);
> + spin_lock(&port->lock);
Hi Christian,
as pointed out in a previous email, I do not like the approach of reusing this
spin_lock for airoha_mac_link_up(). Can we use rtl_lock() (when necessary) as
pointed out before?
Regards,
Lorenzo
>
> for (i = 0; i < ARRAY_SIZE(port->devs); i++) {
> if (port->devs[i])
> @@ -1848,7 +1849,7 @@ static void airoha_update_hw_stats(struct airoha_gdm_dev *dev)
> airoha_fe_set(dev->eth, REG_FE_GDM_MIB_CLEAR(port->id),
> FE_GDM_MIB_RX_CLEAR_MASK | FE_GDM_MIB_TX_CLEAR_MASK);
>
> - spin_unlock(&port->stats_lock);
> + spin_unlock(&port->lock);
> }
>
> static void airoha_dev_set_xmit_frame_size(struct net_device *netdev)
> @@ -1870,6 +1871,14 @@ static int airoha_dev_open(struct net_device *netdev)
> u32 pse_port = FE_PSE_PORT_PPE1;
> int err;
>
> + err = phylink_of_phy_connect(dev->phylink, netdev->dev.of_node, 0);
> + if (err) {
> + netdev_err(netdev, "could not attach PHY: %d\n", err);
> + return err;
> + }
> +
> + phylink_start(dev->phylink);
> +
> netif_tx_start_all_queues(netdev);
> err = airoha_set_vip_for_gdm_port(dev, true);
> if (err)
> @@ -1909,6 +1918,10 @@ static int airoha_dev_stop(struct net_device *netdev)
> airoha_set_gdm_port_fwd_cfg(qdma->eth,
> REG_GDM_FWD_CFG(port->id),
> FE_PSE_PORT_DROP);
> +
> + phylink_stop(dev->phylink);
> + phylink_disconnect_phy(dev->phylink);
> +
> return 0;
> }
>
> @@ -2389,6 +2402,24 @@ airoha_ethtool_get_rmon_stats(struct net_device *netdev,
> } while (u64_stats_fetch_retry(&dev->stats.syncp, start));
> }
>
> +static int
> +airoha_ethtool_get_link_ksettings(struct net_device *netdev,
> + struct ethtool_link_ksettings *cmd)
> +{
> + struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +
> + return phylink_ethtool_ksettings_get(dev->phylink, cmd);
> +}
> +
> +static int
> +airoha_ethtool_set_link_ksettings(struct net_device *netdev,
> + const struct ethtool_link_ksettings *cmd)
> +{
> + struct airoha_gdm_dev *dev = netdev_priv(netdev);
> +
> + return phylink_ethtool_ksettings_set(dev->phylink, cmd);
> +}
> +
> static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev,
> int channel, enum tx_sched_mode mode,
> const u16 *weights, u8 n_weights)
> @@ -3120,7 +3151,8 @@ static const struct ethtool_ops airoha_ethtool_ops = {
> .get_drvinfo = airoha_ethtool_get_drvinfo,
> .get_eth_mac_stats = airoha_ethtool_get_mac_stats,
> .get_rmon_stats = airoha_ethtool_get_rmon_stats,
> - .get_link_ksettings = phy_ethtool_get_link_ksettings,
> + .get_link_ksettings = airoha_ethtool_get_link_ksettings,
> + .set_link_ksettings = airoha_ethtool_set_link_ksettings,
> .get_link = ethtool_op_get_link,
> };
>
> @@ -3176,6 +3208,155 @@ bool airoha_is_valid_gdm_dev(struct airoha_eth *eth,
> return false;
> }
>
> +/* Nothing to do in MAC, everything is handled in PCS */
> +static void airoha_mac_config(struct phylink_config *config, unsigned int mode,
> + const struct phylink_link_state *state)
> +{
> +}
> +
> +static void airoha_mac_link_up(struct phylink_config *config, struct phy_device *phy,
> + unsigned int mode, phy_interface_t interface,
> + int speed, int duplex, bool tx_pause, bool rx_pause)
> +{
> + struct airoha_gdm_dev *dev = container_of(config, struct airoha_gdm_dev,
> + phylink_config);
> + struct airoha_gdm_port *port = dev->port;
> + struct airoha_eth *eth = dev->eth;
> + u32 frag_size_tx, frag_size_rx;
> + u32 mask, val;
> +
> + /* TX/RX frag is configured only for GDM4 */
> + if (port->id != AIROHA_GDM4_IDX)
> + return;
> +
> + switch (speed) {
> + case SPEED_10000:
> + case SPEED_5000:
> + frag_size_tx = 8;
> + frag_size_rx = 8;
> + break;
> + case SPEED_2500:
> + frag_size_tx = 2;
> + frag_size_rx = 1;
> + break;
> + default:
> + frag_size_tx = 1;
> + frag_size_rx = 0;
> + }
> +
> + spin_lock(&port->lock);
> +
> + /* Configure TX/RX frag based on speed */
> + if (dev->nbq == 1) {
> + mask = GDM4_SGMII1_TX_FRAG_SIZE_MASK;
> + val = FIELD_PREP(GDM4_SGMII1_TX_FRAG_SIZE_MASK,
> + frag_size_tx);
> + } else {
> + mask = GDM4_SGMII0_TX_FRAG_SIZE_MASK;
> + val = FIELD_PREP(GDM4_SGMII0_TX_FRAG_SIZE_MASK,
> + frag_size_tx);
> + }
> + airoha_fe_rmw(eth, REG_FE_GDM4_TMBI_FRAG, mask, val);
> +
> + if (dev->nbq == 1) {
> + mask = GDM4_SGMII1_RX_FRAG_SIZE_MASK;
> + val = FIELD_PREP(GDM4_SGMII1_RX_FRAG_SIZE_MASK,
> + frag_size_rx);
> + } else {
> + mask = GDM4_SGMII0_RX_FRAG_SIZE_MASK;
> + val = FIELD_PREP(GDM4_SGMII0_RX_FRAG_SIZE_MASK,
> + frag_size_rx);
> + }
> + airoha_fe_rmw(eth, REG_FE_GDM4_RMBI_FRAG, mask, val);
> +
> + spin_unlock(&port->lock);
> +}
> +
> +/* Nothing to do in MAC, everything is handled in PCS */
> +static void airoha_mac_link_down(struct phylink_config *config, unsigned int mode,
> + phy_interface_t interface)
> +{
> +}
> +
> +static const struct phylink_mac_ops airoha_phylink_ops = {
> + .mac_config = airoha_mac_config,
> + .mac_link_up = airoha_mac_link_up,
> + .mac_link_down = airoha_mac_link_down,
> +};
> +
> +static int airoha_fill_available_pcs(struct phylink_config *config,
> + struct phylink_pcs **available_pcs,
> + unsigned int num_possible_pcs)
> +{
> + struct device *dev = config->dev;
> +
> + return fwnode_phylink_pcs_parse(dev_fwnode(dev), available_pcs,
> + num_possible_pcs);
> +}
> +
> +static int airoha_setup_phylink(struct net_device *netdev)
> +{
> + struct airoha_gdm_dev *dev = netdev_priv(netdev);
> + struct device_node *np = netdev->dev.of_node;
> + struct airoha_gdm_port *port = dev->port;
> + struct phylink_config *config;
> + phy_interface_t phy_mode;
> + struct phylink *phylink;
> + int err;
> +
> + err = of_get_phy_mode(np, &phy_mode);
> + if (err) {
> + dev_err(&netdev->dev, "incorrect phy-mode\n");
> + return err;
> + }
> +
> + config = &dev->phylink_config;
> + config->dev = &netdev->dev;
> + config->type = PHYLINK_NETDEV;
> +
> + /*
> + * GDM1 only supports internal for Embedded Switch
> + * and doesn't require a PCS.
> + */
> + if (port->id == AIROHA_GDM1_IDX) {
> + config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
> + MAC_10000FD;
> +
> + __set_bit(PHY_INTERFACE_MODE_INTERNAL,
> + config->supported_interfaces);
> + } else {
> + config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
> + MAC_10 | MAC_100 | MAC_1000 |
> + MAC_2500FD | MAC_5000FD | MAC_10000FD;
> +
> + config->num_possible_pcs = fwnode_phylink_pcs_count(dev_fwnode(config->dev));
> + config->fill_available_pcs = airoha_fill_available_pcs;
> +
> + __set_bit(PHY_INTERFACE_MODE_SGMII,
> + config->supported_interfaces);
> + __set_bit(PHY_INTERFACE_MODE_1000BASEX,
> + config->supported_interfaces);
> + __set_bit(PHY_INTERFACE_MODE_2500BASEX,
> + config->supported_interfaces);
> + __set_bit(PHY_INTERFACE_MODE_10GBASER,
> + config->supported_interfaces);
> + __set_bit(PHY_INTERFACE_MODE_USXGMII,
> + config->supported_interfaces);
> +
> + phy_interface_copy(config->pcs_interfaces,
> + config->supported_interfaces);
> + }
> +
> + phylink = phylink_create(config, of_fwnode_handle(np),
> + phy_mode, &airoha_phylink_ops);
> + if (IS_ERR(phylink))
> + return PTR_ERR(phylink);
> +
> + dev->phylink = phylink;
> +
> + return 0;
> +}
> +
> static int airoha_alloc_gdm_device(struct airoha_eth *eth,
> struct airoha_gdm_port *port,
> int nbq, struct device_node *np)
> @@ -3239,7 +3420,7 @@ static int airoha_alloc_gdm_device(struct airoha_eth *eth,
> dev->nbq = nbq;
> port->devs[index] = dev;
>
> - return 0;
> + return airoha_setup_phylink(netdev);
> }
>
> static int airoha_alloc_gdm_port(struct airoha_eth *eth,
> @@ -3274,7 +3455,7 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth,
> return -ENOMEM;
>
> port->id = id;
> - spin_lock_init(&port->stats_lock);
> + spin_lock_init(&port->lock);
> eth->ports[p] = port;
>
> err = airoha_metadata_dst_alloc(port);
> @@ -3471,6 +3652,8 @@ static int airoha_probe(struct platform_device *pdev)
> netdev = netdev_from_priv(dev);
> if (netdev->reg_state == NETREG_REGISTERED)
> unregister_netdev(netdev);
> + if (dev->phylink)
> + phylink_destroy(dev->phylink);
> of_node_put(netdev->dev.of_node);
> }
> airoha_metadata_dst_free(port);
> @@ -3509,6 +3692,7 @@ static void airoha_remove(struct platform_device *pdev)
>
> netdev = netdev_from_priv(dev);
> unregister_netdev(netdev);
> + phylink_destroy(dev->phylink);
> of_node_put(netdev->dev.of_node);
> }
> airoha_metadata_dst_free(port);
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
> index f6d01a8e8da1..b49fc5304b3a 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.h
> +++ b/drivers/net/ethernet/airoha/airoha_eth.h
> @@ -561,6 +561,9 @@ struct airoha_gdm_dev {
> int nbq;
>
> struct airoha_hw_stats stats;
> +
> + struct phylink *phylink;
> + struct phylink_config phylink_config;
> };
>
> struct airoha_gdm_port {
> @@ -568,8 +571,8 @@ struct airoha_gdm_port {
> int id;
> int users;
>
> - /* protect concurrent hw_stats accesses */
> - spinlock_t stats_lock;
> + /* protect concurrent hw_stats and frag register accesses */
> + spinlock_t lock;
>
> struct metadata_dst *dsa_meta[AIROHA_MAX_DSA_PORTS];
> };
> diff --git a/drivers/net/ethernet/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h
> index 6fed63d013b4..8df02f51211c 100644
> --- a/drivers/net/ethernet/airoha/airoha_regs.h
> +++ b/drivers/net/ethernet/airoha/airoha_regs.h
> @@ -357,6 +357,18 @@
> #define IP_FRAGMENT_PORT_MASK GENMASK(8, 5)
> #define IP_FRAGMENT_NBQ_MASK GENMASK(4, 0)
>
> +#define REG_FE_GDM4_TMBI_FRAG 0x2028
> +#define GDM4_SGMII1_TX_WEIGHT_MASK GENMASK(31, 26)
> +#define GDM4_SGMII1_TX_FRAG_SIZE_MASK GENMASK(25, 16)
> +#define GDM4_SGMII0_TX_WEIGHT_MASK GENMASK(15, 10)
> +#define GDM4_SGMII0_TX_FRAG_SIZE_MASK GENMASK(9, 0)
> +
> +#define REG_FE_GDM4_RMBI_FRAG 0x202c
> +#define GDM4_SGMII1_RX_WEIGHT_MASK GENMASK(31, 26)
> +#define GDM4_SGMII1_RX_FRAG_SIZE_MASK GENMASK(25, 16)
> +#define GDM4_SGMII0_RX_WEIGHT_MASK GENMASK(15, 10)
> +#define GDM4_SGMII0_RX_FRAG_SIZE_MASK GENMASK(9, 0)
> +
> #define REG_MC_VLAN_EN 0x2100
> #define MC_VLAN_EN_MASK BIT(0)
>
> --
> 2.53.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH net-next] net: stmmac: Simplify ioctl handling
From: Maxime Chevallier @ 2026-07-20 15:34 UTC (permalink / raw)
To: Vadim Fedorenko, Andrew Lunn
Cc: Andrew Lunn, Jakub Kicinski, davem, Eric Dumazet, Paolo Abeni,
Simon Horman, Maxime Coquelin, Alexandre Torgue, Russell King,
thomas.petazzoni, Alexis Lothoré, netdev, linux-kernel,
linux-arm-kernel, linux-stm32
In-Reply-To: <6ac12388-60de-45aa-a8d0-62fcfaf7bea2@linux.dev>
On 7/20/26 17:17, Vadim Fedorenko wrote:
> On 19.07.2026 17:13, Andrew Lunn wrote:
>>> Looking at this, I'm wondering if we can't just get rid of SIOCSHWTSTAMP
>>> handling in phy_mii_ioctl(). Looks like we can ?
>>
>> I'm not sure about that. We need Richards input.
>>
>> The code in phy_mii_ioctl() allows the MAC to be bypassed, it goes
>> straight to a PHY based stamper. It could be the MAC has no idea the
>> PHY has this capability, so it has not implemented the .ndo?
Indeed, but even then the SIOCxHWTSTAMP aren't reaching the ndo_ioctl.
Maybe the thing to change (unrelated to the icotl though) is in
dev_set_hwtstamp :
if (!ops->ndo_hwtstamp_set)
return -EOPNOTSUPP;
if (!netif_device_present(dev))
return -ENODEV;
netdev_lock_ops(dev);
err = dev_set_hwtstamp_phylib(dev, &kernel_cfg, &extack);
netdev_unlock_ops(dev);
We don't try to configure the PHY timestamping if the MAC doesn't support the
.ndo, maybe we should allow that ?
>>
>> It might be we need to hoist the code from phy_mii_ioctl() into
>> dev_{sg}et_hwtstamp()?
>
> Hi Andrew!
>
> I think I've converted all phy drivers while removing support for
> SIOCSHWTSTAMP/SIOCGHWTSTAMP from netdev ioctl. I believe it's impossible right
> now to reach SIOCSHWTSTAMP path of phy_mii_ioctl via ioctl on net device.
That was also my understanding indeed.
> Is it possible to have ioctl on phy device directly without involving netdev?
Unless there's an obscure mechanism I don't know about, there shouldn't be a way.
SIOCSHWTSTAMP/SIOCGHWTSTAMP don't seem to reach netdev anymore with the (great !) work
you've done, so they won't reach the PHY either indeed.
The SIOC ioctls can't reach PHYs without a netdev, neither can the ethnl ones.
Even when we have multiple PHYs and we use netlink, we can only reach the ones
behind a netdevice.
There is still sysfs entries for standalone PHYs, but I don't think we can use
any of that for ioctl.
Maxime
^ permalink raw reply
* Re: [PATCH v2 3/6] media: nxp: imx8-isi: Fix per-stream reference counting for multiplexed streams
From: Frank Li @ 2026-07-20 15:34 UTC (permalink / raw)
To: Guoniu Zhou
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Christian Hemp,
Stefan Riedmueller, Jacopo Mondi, Loic Poulain,
Bryan O'Donoghue, Dong Aisheng, Guoniu Zhou, linux-media, imx,
linux-arm-kernel, linux-kernel, stable
In-Reply-To: <20260720-isi-v2-3-45845bc5d4fa@oss.nxp.com>
On Mon, Jul 20, 2026 at 11:34:05AM +0800, Guoniu Zhou wrote:
> The ISI crossbar fails to properly enable multiple streams from different
> virtual channels on the same input pad. Only the first stream gets enabled
> in hardware, subsequent streams are silently ignored.
>
> The driver uses a single enable_count per input to track the input state.
> When enable_count is non-zero, the code assumes the input is already active
> and skips calling v4l2_subdev_enable_streams() for additional streams:
>
> Call 1: enable_streams(stream 0)
> -> enable_count == 0, enable gasket and stream 0 in hardware
> -> enable_count = 1
>
> Call 2: enable_streams(stream 1)
> -> enable_count == 1, skip hardware enable (BUG!)
> -> enable_count = 2
> -> stream 1 never gets enabled
>
> Similarly on disable, when enable_count reaches zero, ALL streams are
> disabled regardless of which streams are actually still active.
>
> Fix this by tracking per-stream state using:
> - enabled_streams (u64 bitmask): tracks which streams are currently enabled
> - enabled_count[] (array): per-stream reference counter to support the same
> stream being enabled/disabled multiple times
>
> Now each stream is independently enabled/disabled in hardware based on the
> enabled_streams bitmask, while enabled_count[] provides reference counting
> for scenarios where the same stream is enabled multiple times, such as
> duplicate cases in the ISI stream.
>
> Fixes: cf21f328fcaf ("media: nxp: Add i.MX8 ISI driver")
> Cc: stable@vger.kernel.org
> Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
> ---
> Changes in v2:
> - Use fixed-size array for enabled_count instead of dynamic allocation
> - Use BIT_ULL() macro for u64 bitmask operations
> - Use MXC_ISI_MAX_STREAMS (64) as loop boundary instead of num_sources
> - Remove mxc_isi_stream_counters_alloc/free functions
> ---
> .../media/platform/nxp/imx8-isi/imx8-isi-core.h | 7 +-
> .../platform/nxp/imx8-isi/imx8-isi-crossbar.c | 76 ++++++++++++++++------
> 2 files changed, 63 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
> index 7547a6559d4c..9adbe2fe7cf8 100644
> --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
> +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
> @@ -184,8 +184,13 @@ struct mxc_isi_dma_buffer {
> dma_addr_t dma;
> };
>
> +/* V4L2 subdev max stream ID is 63, need 64 counters (0-63) */
> +#define MXC_ISI_MAX_STREAMS 64
Any existing Macro define max stream ID as 63? it'd better to use such
macro
> +
> struct mxc_isi_input {
> - unsigned int enable_count;
> + u64 enabled_streams;
> + /* Per-stream reference counter */
> + unsigned int enabled_count[MXC_ISI_MAX_STREAMS];
> };
>
...
> @@ -396,19 +417,36 @@ static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd,
>
> input = &xbar->inputs[sink_pad];
>
> - input->enable_count--;
> + /*
> + * Decrease the enable count for each stream. Only disable streams
> + * whose count reaches zero.
> + */
> + for (stream = 0; stream < MXC_ISI_MAX_STREAMS; stream++) {
> + if (!(sink_streams & BIT_ULL(stream)))
> + continue;
for_each_set_bit() ?
Frank
>
> - if (!input->enable_count) {
> - ret = v4l2_subdev_disable_streams(remote_sd, remote_pad,
> - sink_streams);
> - if (ret)
> - dev_err(xbar->isi->dev,
> - "failed to disable streams 0x%llx on '%s':%u: %d\n",
> - sink_streams, remote_sd->name, remote_pad, ret);
> + if (!(input->enabled_streams & BIT_ULL(stream)))
> + continue;
>
> - mxc_isi_crossbar_gasket_disable(xbar, sink_pad);
> + if (--input->enabled_count[stream] == 0)
> + streams_to_disable |= BIT_ULL(stream);
> }
>
> + if (!streams_to_disable)
> + return 0;
> +
> + ret = v4l2_subdev_disable_streams(remote_sd, remote_pad,
> + streams_to_disable);
> + if (ret)
> + dev_err(xbar->isi->dev,
> + "failed to disable streams 0x%llx on '%s':%u: %d\n",
> + streams_to_disable, remote_sd->name, remote_pad, ret);
> +
> + input->enabled_streams &= ~streams_to_disable;
> +
> + if (!input->enabled_streams)
> + mxc_isi_crossbar_gasket_disable(xbar, sink_pad);
> +
> return ret;
> }
>
>
> --
> 2.34.1
>
>
^ permalink raw reply
* Re: [PATCH RESEND v4 net-next 11/14] net: enetc: move enetc_set_si_vlan_promisc() to enetc_pf_common.c
From: Joe Damato @ 2026-07-20 15:28 UTC (permalink / raw)
To: wei.fang
Cc: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy,
maxime.chevallier, imx, netdev, linux-kernel, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <20260720014317.1059359-12-wei.fang@oss.nxp.com>
On Mon, Jul 20, 2026 at 09:43:13AM +0800, wei.fang@oss.nxp.com wrote:
> From: Wei Fang <wei.fang@nxp.com>
>
> The PSIPVMR in ENETC v4 has the same bit layout and functionality as the
> PSIPVMR register in ENETC v1: bit n (n <= 15) controls VLAN promiscuous
> mode for SI n. The only difference between the two hardware generations
> is the register address offset.
>
> Since the register functionality is identical, the VLAN promiscuous mode
> setting code can be shared between ENETC v1 and v4 drivers.
>
> Move enetc_set_si_vlan_promisc() from enetc_pf.c to enetc_pf_common.c
> and export it so that it can be shared between the two drivers. Add a
> revision check using is_enetc_rev1() to select the correct register
> offset (ENETC_PSIPVMR for v1 and ENETC4_PSIPVMR for v4) while keeping
> the same logic.
>
> Remove the v4-specific enetc4_pf_set_si_vlan_promisc() from enetc4_pf.c
> and replace its call site with the new common enetc_set_si_vlan_promisc()
> to eliminate code duplication.
>
> Signed-off-by: Wei Fang <wei.fang@nxp.com>
> ---
> .../net/ethernet/freescale/enetc/enetc4_pf.c | 17 ++------------
> .../net/ethernet/freescale/enetc/enetc_pf.c | 16 --------------
> .../freescale/enetc/enetc_pf_common.c | 22 +++++++++++++++++++
> .../freescale/enetc/enetc_pf_common.h | 1 +
> 4 files changed, 25 insertions(+), 31 deletions(-)
Reviewed-by: Joe Damato <joe@dama.to>
^ permalink raw reply
* [PATCH v3 1/2] dt-bindings: phy: Document MT8196 MediaTek PCI-Express Gen4 S-PHY
From: AngeloGioacchino Del Regno @ 2026-07-20 15:26 UTC (permalink / raw)
To: chunfeng.yun
Cc: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, matthias.bgg,
angelogioacchino.delregno, linux-arm-kernel, linux-mediatek,
linux-phy, devicetree, linux-kernel, kernel
In-Reply-To: <20260720152654.92216-1-angelogioacchino.delregno@collabora.com>
This adds bindings for the PCI-Express Gen4 S-PHY found in newer
MediaTek SoCs, such as MT8196 and its variants.
In the current "revision 3", depending on the specific port, this
S-PHY supports up to two lanes of PCI-Express Gen 4 and both EP
and RC modes.
It is not clear whether revisions/versions earlier than 3 have
ever been shipped in any other MediaTek SoC.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
.../phy/mediatek,mt8196-pcie-sphy.yaml | 93 +++++++++++++++++++
1 file changed, 93 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/mediatek,mt8196-pcie-sphy.yaml
diff --git a/Documentation/devicetree/bindings/phy/mediatek,mt8196-pcie-sphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,mt8196-pcie-sphy.yaml
new file mode 100644
index 000000000000..3fd1bfbc3822
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/mediatek,mt8196-pcie-sphy.yaml
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/mediatek,mt8196-pcie-sphy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek PCI-Express Gen4 S-PHY
+
+maintainers:
+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+ The MediaTek PCI-Express Gen4 S-PHY is capable of data serialization
+ and de-serialization with 8, 10, 128 or 130 bits (16GT/s) encoding
+ and decoding, has analog buffers, elastic buffers and mechanisms for
+ receiver detection.
+ This PHY supports link rates of 2.5, 5.0, 8.0 and 16.0 GT/s per-lane
+ in both Root Complex (RC) and End Point (EP) modes, depending on the
+ chosen port.
+ The Digital PHY (PHYD) part adheres to the Intel PIPE (PHY Interface
+ for the PCIe) specification.
+
+properties:
+ compatible:
+ const: mediatek,mt8196-pcie-sphy
+
+ reg:
+ items:
+ - description: System Interface (SIF) registers
+ - description: Clock Management (CKM) registers
+
+ reg-names:
+ items:
+ - const: sif
+ - const: ckm
+
+ "#phy-cells":
+ const: 0
+
+ nvmem-cells:
+ items:
+ - description: Internal resistor selection of TX Bias Current
+ - description: XTP Bias V2V voltage calibration
+ - description: S-PLL CKTX Impedance Selection (P-MOSFET side)
+ - description: S-PLL CKTX Impedance Selection (N-MOSFET side)
+ - description: S-PLL CKTX Intermediate Transition Impedance
+ - description: RX Front-End Return Loss Continuous Time Linear EQ
+ - description: RX Front-End Return Loss Variable Gain Amplifier
+ - description: RX Front-End Return Loss Decision Feedback EQ
+ - description: RX Impedance Selection
+ - description: TX Impedance Selection (P-MOSFET side)
+ - description: TX Impedance Selection (N-MOSFET side)
+ - description: TX Lane 0 Switch Resistance (RSWn)
+ - description: TX Lane 1 Switch Resistance (RSWn)
+ - description: eFuse calibration table version
+
+ nvmem-cell-names:
+ items:
+ - const: int-r
+ - const: xtp-vtrim
+ - const: cktx-pmos
+ - const: cktx-nmos
+ - const: cktx-r-mid
+ - const: rxfe-lanes-rl-ctle
+ - const: rxfe-lanes-rl-vga
+ - const: rxfe-lanes-rl-dfe
+ - const: rx-lanes-imp
+ - const: tx-lanes-pmos
+ - const: tx-lanes-nmos
+ - const: tx-ln0-rswn
+ - const: tx-ln1-rswn
+ - const: cal-version
+
+ power-domains:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ phy@16900000 {
+ compatible = "mediatek,mt8196-pcie-sphy";
+ reg = <0x16900000 0x10000>, <0x16920000 0x10000>;
+ reg-names = "sif", "ckm";
+ power-domains = <&spm 10>;
+ #phy-cells = <0>;
+ };
--
2.55.0
^ permalink raw reply related
* [PATCH v3 0/2] PHY: Add MediaTek PCI-Express Gen4 S-PHY Driver
From: AngeloGioacchino Del Regno @ 2026-07-20 15:26 UTC (permalink / raw)
To: chunfeng.yun
Cc: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, matthias.bgg,
angelogioacchino.delregno, linux-arm-kernel, linux-mediatek,
linux-phy, devicetree, linux-kernel, kernel
Changes in v3:
- Allowed value 0 in calibration fields (as it's a legal value)
- Fixed duplicated LN_TX_IMPSEL_{P,N}MOS writes
- Allowed -ENOENT for nvmem_cell_read_u{8,16}() calls, as the
calibration data is effectively optional
- Removed two development stage leftover unused definitions
- Moved num_lanes check in mtk_pcie_sphy_get_calibration_data()
to reduce indent in probe function.
Changes in v2:
- Added items/description to reg in binding
- Added missing pm_runtime.h inclusion
- Moved pm_runtime_enable call to before registering PHY
- Fixed pmos/nmos variable size for 5 bits calibration values
- Fixed calibration for single-lane PCIe, as in, the ln1 rswn
calibration nvmem value is ignored in code if it's single
lane and will not return an error; this is due to the fact
that, effectively, single-lane may have a zero calibration
in tx-ln1-rswn which is fine, as that'd be anyway unused
- Changed calibration data errors to dev_err_probe and changed
the "no calibration for ..." message to dev_info instead
This adds a driver for the PCI-Express Gen4 "S-PHY" found in the
Genio MT8894, Kompanio MT8196, Dimensity MT6991 SoCs (which are
all variants of the same chip).
This was successfully tested on MT8894 and MT8196.
AngeloGioacchino Del Regno (2):
dt-bindings: phy: Document MT8196 MediaTek PCI-Express Gen4 S-PHY
phy: mediatek: Add support for PCI-Express Gen4 S-PHY
.../phy/mediatek,mt8196-pcie-sphy.yaml | 93 +++
drivers/phy/mediatek/Kconfig | 9 +
drivers/phy/mediatek/Makefile | 1 +
drivers/phy/mediatek/phy-mtk-pcie-sphy.c | 556 ++++++++++++++++++
4 files changed, 659 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/mediatek,mt8196-pcie-sphy.yaml
create mode 100644 drivers/phy/mediatek/phy-mtk-pcie-sphy.c
--
2.55.0
^ permalink raw reply
* [PATCH v3 2/2] phy: mediatek: Add support for PCI-Express Gen4 S-PHY
From: AngeloGioacchino Del Regno @ 2026-07-20 15:26 UTC (permalink / raw)
To: chunfeng.yun
Cc: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, matthias.bgg,
angelogioacchino.delregno, linux-arm-kernel, linux-mediatek,
linux-phy, devicetree, linux-kernel, kernel
In-Reply-To: <20260720152654.92216-1-angelogioacchino.delregno@collabora.com>
Add support for the PCI-Express Gen4 S-PHY found in the latest
MediaTek SoCs, including MT8196, MT8894 and similar.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/phy/mediatek/Kconfig | 9 +
drivers/phy/mediatek/Makefile | 1 +
drivers/phy/mediatek/phy-mtk-pcie-sphy.c | 556 +++++++++++++++++++++++
3 files changed, 566 insertions(+)
create mode 100644 drivers/phy/mediatek/phy-mtk-pcie-sphy.c
diff --git a/drivers/phy/mediatek/Kconfig b/drivers/phy/mediatek/Kconfig
index ba6461350951..77236f3084c8 100644
--- a/drivers/phy/mediatek/Kconfig
+++ b/drivers/phy/mediatek/Kconfig
@@ -13,6 +13,15 @@ config PHY_MTK_PCIE
callback for PCIe GEN3 port, it supports software efuse
initialization.
+config PHY_MTK_PCIE_SPHY
+ tristate "MediaTek PCIe S-PHY Driver"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ depends on OF
+ select GENERIC_PHY
+ help
+ Say 'Y' here to add support for MediaTek PCIe S-PHY driver for
+ PCI-Express Gen4 controllers as found in MT6991, MT8196 and others.
+
config PHY_MTK_XFI_TPHY
tristate "MediaTek 10GE SerDes XFI T-PHY driver"
depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile
index ed0da708759b..7e984c7cfea3 100644
--- a/drivers/phy/mediatek/Makefile
+++ b/drivers/phy/mediatek/Makefile
@@ -5,6 +5,7 @@
obj-$(CONFIG_PHY_MTK_DP) += phy-mtk-dp.o
obj-$(CONFIG_PHY_MTK_PCIE) += phy-mtk-pcie.o
+obj-$(CONFIG_PHY_MTK_PCIE_SPHY) += phy-mtk-pcie-sphy.o
obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o
obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o
diff --git a/drivers/phy/mediatek/phy-mtk-pcie-sphy.c b/drivers/phy/mediatek/phy-mtk-pcie-sphy.c
new file mode 100644
index 000000000000..853aafa18259
--- /dev/null
+++ b/drivers/phy/mediatek/phy-mtk-pcie-sphy.c
@@ -0,0 +1,556 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+#include "phy-mtk-io.h"
+
+/* PHY System Interface (SIF) registers */
+#define PEXTP_DIG_GLB_TOP 0x20
+# define RG_XTP_BYPASS_PIPE_RST_RC BIT(17)
+#define PEXTP_DIG_GLB_CKBG0 0x30
+# define RG_XTP_CKBG_XTAL_STABLE_TIME_SEL GENMASK(25, 16)
+#define PEXTP_DIG_GLB_TPLL_CTL0 0x38
+# define RG_XTP_TPLL_SET_STABLE_TIME_SEL GENMASK(7, 2)
+# define RG_XTP_TPLL_PWE_ON_STABLE_TIME_SEL GENMASK(9, 8)
+#define PEXTP_DIG_GLB_CLKREQ_CTL 0x50
+# define RG_XTP_CKM_EN_L1S0 BIT(13)
+# define RG_XTP_CKM_EN_L1S1 BIT(14)
+#define PEXTP_DIG_GLB_TPLL_CTL2 0xf4
+# define RG_XTP_TPLL_ISO_EN_STABLE_TIME_SEL GENMASK(13, 12)
+
+/* PHY System Interface Digital registers */
+#define PEXTP_DIG_LN_TRX_PIPE_IF_17 0x30e8
+# define RG_XTP_LN_RX_LF_CTLE_CSEL_GEN4 GENMASK(14, 12)
+#define PEXTP_DIG_LN_RX_F0 0x50f0
+# define RG_XTP_LN_RX_GEN1_CTLE1_CSEL GENMASK(3, 0)
+# define RG_XTP_LN_RX_GEN2_CTLE1_CSEL GENMASK(7, 4)
+# define RG_XTP_LN_RX_GEN3_CTLE1_CSEL GENMASK(11, 8)
+# define RG_XTP_LN_RX_GEN4_CTLE1_CSEL GENMASK(15, 12)
+#define PEXTP_DIG_LN_RX2_AEQ_EDGE_0 0x6004
+# define RG_XTP_LN_RX_AEQ_EGEQ_RATIO_GEN3 GENMASK(21, 16)
+# define RG_XTP_LN_RX_AEQ_EGEQ_RATIO_GEN4 GENMASK(29, 24)
+
+/* PHY System Interface Analog registers */
+#define PEXTP_ANA_GLB_TPLL1_RSVD 0x902c
+# define RG_XTP_GLB_TPLL1_P_PATH_GAIN GENMASK(2, 0)
+#define PEXTP_ANA_GLB_BIAS_0 0x9060
+# define RG_XTP_GLB_BIAS_INTR_CTRL GENMASK(5, 0)
+#define PEXTP_ANA_GLB_BIAS_1 0x90c0
+# define RG_XTP_GLB_BIAS_V2V_VTRIM GENMASK(9, 6)
+#define PEXTP_ANA_LN_TRX_0C 0xa00c
+# define RG_XTP_LN_TX_RSWN_IMPSEL GENMASK(20, 16)
+#define PEXTP_ANA_LN_TRX_34 0xa034
+# define RG_XTP_LN_RX_FE BIT(15)
+#define PEXTP_ANA_LN_TRX_6C 0xa06c
+# define RG_XTP_LN_RX_AEQ_CTLE_ERR_TYPE GENMASK(14, 13)
+# define AEQ_CTLE_SEARCH_ERR_TYPE_H1P5 0
+# define AEQ_CTLE_SEARCH_ERR_TYPE_H1P5_H2P5 1
+# define AEQ_CTLE_SEARCH_ERR_TYPE_P1P5_H2P5_H3P5 2
+#define PEXTP_ANA_LN_TRX_A0 0xa0a0
+# define RG_XTP_LN_TX_IMPSEL_PMOS GENMASK(4, 0)
+# define RG_XTP_LN_TX_IMPSEL_NMOS GENMASK(11, 7)
+# define RG_XTP_LN_RX_IMPSEL GENMASK(15, 12)
+#define PEXTP_ANA_LN_TRX_A8 0xa0a8
+# define RG_XTP_LN_RX_LEQ_RL_CTLE_CAL GENMASK(6, 2)
+# define RG_XTP_LN_RX_LEQ_RL_VGA_CAL GENMASK(11, 7)
+# define RG_XTP_LN_RX_LEQ_RL_DFE_CAL GENMASK(23, 19)
+#define PEXTP_DIG_LN_TX_LC_TABLE_RSWN_4 0xb004
+#define PEXTP_DIG_LN_TX_LC_TABLE_RSWN_8 0xb008
+#define PEXTP_DIG_LN_TX_LC_TABLE_RSWN_C 0xb00c
+#define PEXTP_DIG_LN_TX_LC_TABLE_RSWN_10 0xb010
+#define PEXTP_DIG_LN_TX_LC_TABLE_RSWN_14 0xb014
+#define PEXTP_DIG_LN_TX_LC_TABLE_RSWN_18 0xb018
+# define RG_XTP_LN_TX_LC_PRESET_MGx_Px_CM1 GENMASK(5, 0)
+# define RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0 GENMASK(13, 8)
+# define RG_XTP_LN_TX_LC_PRESET_MGx_Px_CP1 GENMASK(21, 16)
+#define PEXTP_REG_LANE(x) ((x) * 0x100)
+
+/* PHY Clock Management (CKM) registers */
+#define XTP_CKM_FORCE_6 0x38
+# define RG_CKM_BIAS_WAIT_PRD_US GENMASK(21, 16)
+#define XTP_CKM_REG_SPLL_FBKDIV_5 0xd4
+# define RG_CKM_CKTX_IMPSEL_PMOS GENMASK(19, 16)
+# define RG_CKM_CKTX_IMPSEL_NMOS GENMASK(23, 20)
+# define RG_CKM_CKTX_IMPSEL_SW GENMASK(27, 24)
+
+/* Calibration data from eFuses */
+#define MTK_PCIE_SPHY_CALIBRATION_MAX_DATA_LANES 2
+#define MTK_PCIE_SPHY_CALIBRATION_LAST_QUIRK_VER 4
+
+/**
+ * struct mtk_pcie_sphy_imp_sel - Impedance Selection parameters
+ * @pmos: Impedance selection for P-Channel MOSFET
+ * @nmos: Impedance selection for N-Channel MOSFET
+ */
+struct mtk_pcie_sphy_imp_sel {
+ u8 pmos;
+ u8 nmos;
+};
+
+/**
+ * struct mtk_pcie_sphy_efuse - eFuse calibration data for S-PHY
+ * @int_r_ctrl: Internal resistor selection of TX Bias Current
+ * @xtp_vtrim: XTP Bias V2V voltage calibration
+ * @cktx_impsel: SPLL CKTX Impedance Selection (P and N MOSFET)
+ * @cktx_r_mid: SPLL CKTX Intermediate Transition Impedance (Rmid)
+ * @rx_leq_rl_ctle: RX Front-End Return Loss Continuous Time Linear Equalization value
+ * @rx_leq_rl_vga: RX Front-End Return Loss Variable Gain Amplifier value
+ * @rx_leq_rl_dfe: RX Front-End Return Loss Decision Feedback Equalization value
+ * @rx_impsel: RX Impedance Selection
+ * @tx_impsel: TX Impedance Selection (P and N MOSFET)
+ * @tx_rswn_impsel: TX RSWn (Switch Resistance) impedance selection
+ * @supported: eFuse calibration data is supported
+ */
+struct mtk_pcie_sphy_efuse {
+ u8 int_r_ctrl;
+ u8 xtp_vtrim;
+ struct mtk_pcie_sphy_imp_sel cktx_impsel;
+ u8 cktx_r_mid;
+ u8 rx_leq_rl_ctle;
+ u8 rx_leq_rl_vga;
+ u8 rx_leq_rl_dfe;
+ u8 rx_impsel;
+ struct mtk_pcie_sphy_imp_sel tx_impsel;
+ u8 tx_rswn_impsel[MTK_PCIE_SPHY_CALIBRATION_MAX_DATA_LANES];
+ bool supported;
+};
+
+/**
+ * struct mtk_pcie_sphy - PCI-Express S-PHY driver main structure
+ * @dev: Pointer to device structure
+ * @phy: Pointer to generic phy structure
+ * @sif_base: IO mapped register base address of system interface
+ * @ckm_base: IO mapped register base address of clock management interface
+ * @num_lanes: Number of lanes
+ * @calibration: eFuse calibration data for S-PHY
+ */
+struct mtk_pcie_sphy {
+ struct device *dev;
+ struct phy *phy;
+ void __iomem *sif_base;
+ void __iomem *ckm_base;
+ u8 num_lanes;
+ struct mtk_pcie_sphy_efuse calibration;
+};
+
+static void mtk_pcie_sphy_apply_calibration(struct mtk_pcie_sphy *pcie_sphy)
+{
+ struct mtk_pcie_sphy_efuse *cal = &pcie_sphy->calibration;
+ int i;
+
+ mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_ANA_GLB_BIAS_0,
+ RG_XTP_GLB_BIAS_INTR_CTRL, cal->int_r_ctrl);
+
+ mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_ANA_GLB_BIAS_1,
+ RG_XTP_GLB_BIAS_V2V_VTRIM, cal->xtp_vtrim);
+
+ mtk_phy_update_field(pcie_sphy->ckm_base + XTP_CKM_REG_SPLL_FBKDIV_5,
+ RG_CKM_CKTX_IMPSEL_PMOS, cal->cktx_impsel.pmos);
+
+ mtk_phy_update_field(pcie_sphy->ckm_base + XTP_CKM_REG_SPLL_FBKDIV_5,
+ RG_CKM_CKTX_IMPSEL_NMOS, cal->cktx_impsel.nmos);
+
+ mtk_phy_update_field(pcie_sphy->ckm_base + XTP_CKM_REG_SPLL_FBKDIV_5,
+ RG_CKM_CKTX_IMPSEL_SW, cal->cktx_r_mid);
+
+ for (i = 0; i < pcie_sphy->num_lanes; i++) {
+ void __iomem *sif_lane_base = pcie_sphy->sif_base + PEXTP_REG_LANE(i);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_0C,
+ RG_XTP_LN_TX_RSWN_IMPSEL, cal->tx_rswn_impsel[i]);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A8,
+ RG_XTP_LN_RX_LEQ_RL_CTLE_CAL, cal->rx_leq_rl_ctle);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A8,
+ RG_XTP_LN_RX_LEQ_RL_VGA_CAL, cal->rx_leq_rl_vga);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A8,
+ RG_XTP_LN_RX_LEQ_RL_DFE_CAL, cal->rx_leq_rl_dfe);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A0,
+ RG_XTP_LN_RX_IMPSEL, cal->rx_impsel);
+ }
+}
+
+/**
+ * mtk_pcie_sphy_init() - Initialize the PCI-Express S-PHY
+ * @phy: the phy to be initialized
+ *
+ * The hardware settings will be reset during suspend, it should be
+ * reinitialized when the consumer calls phy_init() again on resume.
+ */
+static int mtk_pcie_sphy_init(struct phy *phy)
+{
+ struct mtk_pcie_sphy *pcie_sphy = phy_get_drvdata(phy);
+ struct mtk_pcie_sphy_imp_sel tx_impsel;
+ int i;
+
+ /* Set CKM Bias wait time to 4 microseconds */
+ mtk_phy_update_field(pcie_sphy->ckm_base + XTP_CKM_FORCE_6,
+ RG_CKM_BIAS_WAIT_PRD_US, 4);
+
+ /* TPLL needs 63 ref_ck ticks to stabilize when setting frequency */
+ mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_DIG_GLB_TPLL_CTL0,
+ RG_XTP_TPLL_SET_STABLE_TIME_SEL, 63);
+
+ /* TPLL needs 3 ref_ck ticks to stabilize when powering on... */
+ mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_DIG_GLB_TPLL_CTL0,
+ RG_XTP_TPLL_PWE_ON_STABLE_TIME_SEL, 3);
+
+ /* ...and the same goes for setting isolation */
+ mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_DIG_GLB_TPLL_CTL2,
+ RG_XTP_TPLL_ISO_EN_STABLE_TIME_SEL, 3);
+
+ /* XTAL doesn't need any stabilization time */
+ mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_DIG_GLB_CKBG0,
+ RG_XTP_CKBG_XTAL_STABLE_TIME_SEL, 0);
+
+ /* Keep pextp_ckm enabled when in L1SS_L1S1 state */
+ mtk_phy_clear_bits(pcie_sphy->sif_base + PEXTP_DIG_GLB_CLKREQ_CTL, RG_XTP_CKM_EN_L1S1);
+
+ /* Set PIPE to reset TPLL */
+ mtk_phy_clear_bits(pcie_sphy->sif_base + PEXTP_DIG_GLB_TOP, RG_XTP_BYPASS_PIPE_RST_RC);
+
+ /* Set TPLL P-Path gain compensation to 1 */
+ mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_ANA_GLB_TPLL1_RSVD,
+ RG_XTP_GLB_TPLL1_P_PATH_GAIN, 1);
+
+ for (i = 0; i < pcie_sphy->num_lanes; i++) {
+ void __iomem *sif_lane_base = pcie_sphy->sif_base + PEXTP_REG_LANE(i);
+
+ /* Set RX Lane AEQ CTRL-E Search Error type to h1.5 + h2.5 */
+ mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_6C,
+ RG_XTP_LN_RX_AEQ_CTLE_ERR_TYPE,
+ AEQ_CTLE_SEARCH_ERR_TYPE_H1P5_H2P5);
+
+ mtk_phy_set_bits(sif_lane_base + PEXTP_ANA_LN_TRX_34, RG_XTP_LN_RX_FE);
+
+ /* TRX: Select CTLE1 for RX Lane AutoEQ CTRL-E Setting on Gen4 */
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TRX_PIPE_IF_17,
+ RG_XTP_LN_RX_LF_CTLE_CSEL_GEN4, 1);
+
+ /* Set RX Lane AutoEQ CTRL-E for PCI-Express Gen1 to Gen 4 */
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_RX_F0,
+ RG_XTP_LN_RX_GEN1_CTLE1_CSEL, 13);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_RX_F0,
+ RG_XTP_LN_RX_GEN2_CTLE1_CSEL, 13);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_RX_F0,
+ RG_XTP_LN_RX_GEN3_CTLE1_CSEL, 13);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_RX_F0,
+ RG_XTP_LN_RX_GEN4_CTLE1_CSEL, 0);
+
+ /* Set RX Lane AutoEQ's Edge EQ Ratio to 22 * 0.0625 = 1.375 */
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_RX2_AEQ_EDGE_0,
+ RG_XTP_LN_RX_AEQ_EGEQ_RATIO_GEN3, 22);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_RX2_AEQ_EDGE_0,
+ RG_XTP_LN_RX_AEQ_EGEQ_RATIO_GEN4, 22);
+
+ /* Setup Digital lane TX Link Characteristics Table */
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_4,
+ RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0, 10);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_4,
+ RG_XTP_LN_TX_LC_PRESET_MGx_Px_CP1, 2);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_8,
+ RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0, 11);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_8,
+ RG_XTP_LN_TX_LC_PRESET_MGx_Px_CP1, 1);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_C,
+ RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0, 12);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_10,
+ RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0, 13);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_10,
+ RG_XTP_LN_TX_LC_PRESET_MGx_Px_CM1, 1);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_14,
+ RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0, 11);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_14,
+ RG_XTP_LN_TX_LC_PRESET_MGx_Px_CM1, 1);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_18,
+ RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0, 10);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_18,
+ RG_XTP_LN_TX_LC_PRESET_MGx_Px_CM1, 2);
+ }
+
+ if (pcie_sphy->calibration.supported) {
+ mtk_pcie_sphy_apply_calibration(pcie_sphy);
+
+ tx_impsel.pmos = pcie_sphy->calibration.tx_impsel.pmos;
+ tx_impsel.nmos = pcie_sphy->calibration.tx_impsel.nmos;
+ } else {
+ /* Set P=10, N=9 to prevent EMI if no calibration present */
+ tx_impsel.pmos = 10;
+ tx_impsel.nmos = 9;
+ }
+
+ /* Select TX Impedance on N and P MOSFETs */
+ for (i = 0; i < pcie_sphy->num_lanes; i++) {
+ void __iomem *sif_lane_base = pcie_sphy->sif_base + PEXTP_REG_LANE(i);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A0,
+ RG_XTP_LN_TX_IMPSEL_PMOS, tx_impsel.pmos);
+
+ mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A0,
+ RG_XTP_LN_TX_IMPSEL_NMOS, tx_impsel.nmos);
+ }
+
+ return 0;
+}
+
+static const struct phy_ops mtk_pcie_sphy_ops = {
+ .init = mtk_pcie_sphy_init,
+ .owner = THIS_MODULE,
+};
+
+static int mtk_pcie_sphy_get_one_cal_para(struct device *dev, const char *name, u8 max_val)
+{
+ u16 buf;
+ u8 tmp;
+ int ret;
+
+ /*
+ * All of the calibrations are always max 8 bits long, but some may
+ * be split between two different 8-bits cells: handle this corner
+ * case by retrying reading as u16.
+ */
+ ret = nvmem_cell_read_u8(dev, name, &tmp);
+ if (ret == 0)
+ buf = tmp;
+ else
+ ret = nvmem_cell_read_u16(dev, name, &buf);
+
+ if (ret == -ENOENT) {
+ dev_info(dev, "No calibration for %s. Using defaults\n", name);
+ return -ENOENT;
+ } else if (ret)
+ return dev_err_probe(dev, ret,
+ "Cannot get calibration data for %s\n", name);
+
+ if (buf > max_val)
+ return dev_err_probe(dev, -ERANGE,
+ "Bad value %u retrieved for %s.\n", buf, name);
+
+ return buf;
+}
+
+static int mtk_pcie_sphy_get_calibration_data(struct mtk_pcie_sphy *pcie_sphy)
+{
+ struct mtk_pcie_sphy_efuse *cal = &pcie_sphy->calibration;
+ struct device *dev = pcie_sphy->dev;
+ u8 version;
+ int ret;
+
+ if (pcie_sphy->num_lanes > MTK_PCIE_SPHY_CALIBRATION_MAX_DATA_LANES) {
+ dev_info(dev, "Skipping PHY calibration for more than %u lanes.\n",
+ MTK_PCIE_SPHY_CALIBRATION_MAX_DATA_LANES);
+ ret = -EOPNOTSUPP;
+ goto end;
+ }
+
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "int-r",
+ FIELD_MAX(RG_XTP_GLB_BIAS_INTR_CTRL));
+ if (ret < 0)
+ goto end;
+ cal->int_r_ctrl = ret;
+
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "xtp-vtrim",
+ FIELD_MAX(RG_XTP_GLB_BIAS_V2V_VTRIM));
+ if (ret < 0)
+ goto end;
+ cal->xtp_vtrim = ret;
+
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "cktx-pmos",
+ FIELD_MAX(RG_CKM_CKTX_IMPSEL_PMOS));
+ if (ret < 0)
+ goto end;
+ cal->cktx_impsel.pmos = ret;
+
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "cktx-nmos",
+ FIELD_MAX(RG_CKM_CKTX_IMPSEL_NMOS));
+ if (ret < 0)
+ goto end;
+ cal->cktx_impsel.nmos = ret;
+
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "cktx-r-mid",
+ FIELD_MAX(RG_CKM_CKTX_IMPSEL_SW));
+ if (ret < 0)
+ goto end;
+ cal->cktx_r_mid = ret;
+
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "rxfe-lanes-rl-ctle",
+ FIELD_MAX(RG_XTP_LN_RX_LEQ_RL_CTLE_CAL));
+ if (ret < 0)
+ goto end;
+ cal->rx_leq_rl_ctle = ret;
+
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "rxfe-lanes-rl-vga",
+ FIELD_MAX(RG_XTP_LN_RX_LEQ_RL_VGA_CAL));
+ if (ret < 0)
+ goto end;
+ cal->rx_leq_rl_vga = ret;
+
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "rxfe-lanes-rl-dfe",
+ FIELD_MAX(RG_XTP_LN_RX_LEQ_RL_DFE_CAL));
+ if (ret < 0)
+ goto end;
+ cal->rx_leq_rl_dfe = ret;
+
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "rx-lanes-imp",
+ FIELD_MAX(RG_XTP_LN_RX_IMPSEL));
+ if (ret < 0)
+ goto end;
+ cal->rx_impsel = ret;
+
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "tx-lanes-pmos",
+ FIELD_MAX(RG_XTP_LN_TX_IMPSEL_PMOS));
+ if (ret < 0)
+ goto end;
+ cal->tx_impsel.pmos = ret;
+
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "tx-lanes-nmos",
+ FIELD_MAX(RG_XTP_LN_TX_IMPSEL_NMOS));
+ if (ret < 0)
+ goto end;
+ cal->tx_impsel.nmos = ret;
+
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "tx-ln0-rswn",
+ FIELD_MAX(RG_XTP_LN_TX_RSWN_IMPSEL));
+ if (ret < 0)
+ goto end;
+ cal->tx_rswn_impsel[0] = ret;
+
+ if (pcie_sphy->num_lanes == 2) {
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "tx-ln1-rswn",
+ FIELD_MAX(RG_XTP_LN_TX_RSWN_IMPSEL));
+ if (ret < 0)
+ goto end;
+ cal->tx_rswn_impsel[1] = ret;
+ }
+
+ ret = mtk_pcie_sphy_get_one_cal_para(dev, "cal-version", 15);
+ if (ret < 0)
+ goto end;
+ version = ret;
+
+ /* Quirk for eFuse calibration table versions 0 to 4 */
+ if ((version <= MTK_PCIE_SPHY_CALIBRATION_LAST_QUIRK_VER) &&
+ cal->rx_leq_rl_ctle == 10) {
+ cal->rx_leq_rl_vga = cal->rx_leq_rl_ctle;
+ cal->rx_leq_rl_dfe = cal->rx_leq_rl_ctle;
+ }
+
+end:
+ if (ret < 0) {
+ /*
+ * If any of the calibration values is missing, or if there is
+ * no calibration at all in the eFuses, this is not a problem,
+ * as the PHY doesn't require one to actually work.
+ */
+ if (ret == -ENOENT || ret == -EOPNOTSUPP) {
+ cal->supported = false;
+ return 0;
+ }
+ return ret;
+ };
+ cal->supported = true;
+
+ return 0;
+}
+
+static int mtk_pcie_sphy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct phy_provider *provider;
+ struct mtk_pcie_sphy *pcie_sphy;
+ u32 num_lanes;
+ int ret;
+
+ pcie_sphy = devm_kzalloc(dev, sizeof(*pcie_sphy), GFP_KERNEL);
+ if (!pcie_sphy)
+ return -ENOMEM;
+
+ pcie_sphy->sif_base = devm_platform_ioremap_resource_byname(pdev, "sif");
+ if (IS_ERR(pcie_sphy->sif_base))
+ return dev_err_probe(dev, PTR_ERR(pcie_sphy->sif_base),
+ "Failed to map phy-sif base\n");
+
+ pcie_sphy->ckm_base = devm_platform_ioremap_resource_byname(pdev, "ckm");
+ if (IS_ERR(pcie_sphy->ckm_base))
+ return dev_err_probe(dev, PTR_ERR(pcie_sphy->ckm_base),
+ "Failed to map phy-ckm base\n");
+
+ pcie_sphy->phy = devm_phy_create(dev, dev->of_node, &mtk_pcie_sphy_ops);
+ if (IS_ERR(pcie_sphy->phy))
+ return dev_err_probe(dev, PTR_ERR(pcie_sphy->phy),
+ "Failed to create PCIe phy\n");
+
+ ret = of_property_read_u32(dev->of_node, "num-lanes", &num_lanes);
+ if (ret)
+ num_lanes = 1;
+ else if (num_lanes > 4)
+ return dev_err_probe(dev, -EINVAL, "Invalid number of lanes.\n");
+
+ pcie_sphy->num_lanes = num_lanes;
+ pcie_sphy->dev = dev;
+
+ ret = mtk_pcie_sphy_get_calibration_data(pcie_sphy);
+ if (ret)
+ return ret;
+
+ phy_set_drvdata(pcie_sphy->phy, pcie_sphy);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(provider))
+ return dev_err_probe(dev, PTR_ERR(provider),
+ "Could not register PCI-Express S-PHY\n");
+
+ return 0;
+}
+
+static const struct of_device_id mtk_pcie_sphy_of_match[] = {
+ { .compatible = "mediatek,mt8196-pcie-sphy" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mtk_pcie_sphy_of_match);
+
+static struct platform_driver mtk_pcie_sphy_driver = {
+ .probe = mtk_pcie_sphy_probe,
+ .driver = {
+ .name = "mtk-pcie-sphy",
+ .of_match_table = mtk_pcie_sphy_of_match,
+ },
+};
+module_platform_driver(mtk_pcie_sphy_driver);
+
+MODULE_DESCRIPTION("MediaTek PCIe SPHY driver");
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_LICENSE("GPL");
--
2.55.0
^ permalink raw reply related
* Re: [PATCH RESEND v4 net-next 09/14] net: enetc: open-code enetc4_set_default_si_vlan_promisc()
From: Joe Damato @ 2026-07-20 15:26 UTC (permalink / raw)
To: wei.fang
Cc: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy,
maxime.chevallier, imx, netdev, linux-kernel, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <20260720014317.1059359-10-wei.fang@oss.nxp.com>
On Mon, Jul 20, 2026 at 09:43:11AM +0800, wei.fang@oss.nxp.com wrote:
> From: Wei Fang <wei.fang@nxp.com>
>
> The function enetc4_set_default_si_vlan_promisc() is only called once,
> from enetc4_configure_port_si(). Open-code the loop at the call site
> and remove the single-use wrapper.
>
> Signed-off-by: Wei Fang <wei.fang@nxp.com>
> ---
> drivers/net/ethernet/freescale/enetc/enetc4_pf.c | 15 +++------------
> 1 file changed, 3 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> index 859b02f5170a..505e4abf6c37 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> @@ -307,17 +307,6 @@ static void enetc4_pf_set_si_vlan_promisc(struct enetc_hw *hw, int si, bool en)
> enetc_port_wr(hw, ENETC4_PSIPVMR, val);
> }
>
> -static void enetc4_set_default_si_vlan_promisc(struct enetc_pf *pf)
> -{
> - struct enetc_hw *hw = &pf->si->hw;
> - int num_si = pf->caps.num_vsi + 1;
> - int i;
> -
> - /* enforce VLAN promiscuous mode for all SIs */
> - for (i = 0; i < num_si; i++)
> - enetc4_pf_set_si_vlan_promisc(hw, i, true);
> -}
> -
> /* Allocate the number of MSI-X vectors for per SI. */
> static void enetc4_set_si_msix_num(struct enetc_pf *pf)
> {
> @@ -361,7 +350,9 @@ static void enetc4_configure_port_si(struct enetc_pf *pf)
> /* Outer VLAN tag will be used for VLAN filtering */
> enetc_port_wr(hw, ENETC4_PSIVLANFMR, PSIVLANFMR_VS);
>
> - enetc4_set_default_si_vlan_promisc(pf);
> + /* Enforce VLAN promiscuous mode for all SIs */
> + for (int i = 0; i < pf->caps.num_vsi + 1; i++)
> + enetc4_pf_set_si_vlan_promisc(hw, i, true);
>
> /* Disable SI MAC multicast & unicast promiscuous */
> enetc_port_wr(hw, ENETC4_PSIPMMR, 0);
Reviewed-by: Joe Damato <joe@dama.to>
^ permalink raw reply
* Re: [PATCH v2] KVM: arm64: Reject guest_memfd memslots when the VM has MTE
From: Fuad Tabba @ 2026-07-20 15:20 UTC (permalink / raw)
To: Alexandru Elisei
Cc: maz, oupton, joey.gouly, seiden, suzuki.poulose, yuzenghui,
linux-arm-kernel, kvmarm, catalin.marinas, will, steven.price
In-Reply-To: <20260720130942.135033-1-alexandru.elisei@arm.com>
On Mon, 20 Jul 2026 at 14:10, Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>
> The user cannot use MTE on VMAs created by mapping a guest_memfd file,
> as arch_calc_vm_flag_bits() does not set VM_MTE_ALLOWED.
>
> When creating a guest_memfd backed memslot,
> kvm_arch_prepare_memory_region() rejects the memslot if MTE is enabled for
> the VM and if guest_memfd has been mapped in a VMA that intersects the
> memslot.
>
> However, the documentation for KVM_SET_USER_MEMORY_REGION2 explicitly
> states that the only condition for userspace_addr is for it to be a legal
> userspace address, but the mapping is not required to be valid nor
> populated at memslot creation.
>
> If userspace sets userspace_addr to an address that hasn't been mapped, or
> if userspace_addr belongs to a VMA that isn't backed by the guest_memfd
> file, or if the VMA doesn't intersect the memslot, memslot creation is
> successful and KVM ends up with a VM with MTE and guest_memfd-backed
> memslots.
>
> The same happens if the order is reversed: when userspace enables MTE, KVM
> does not check if memslots backed by guest_memfd are already present.
>
> Fix both issues by rejecting guest_memfd-backed memslots when MTE is
> enabled, and by reject MTE when guest_memfd-backed memslots are already
> present.
>
> Fixes: 32e200bd6e44 ("KVM: arm64: Enable support for guest_memfd backed memory")
> Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Reviewed-by: Fuad Tabba <fuad.tabba@linux.dev>
Tested-by: Fuad Tabba < fuad.tabba@linux.dev>
Cheers,
/fuad
> ---
>
> v1 can be found at [1].
>
> Changes in v2:
>
> * Added the Fixes tag (Fuad)
> * Split the condition in kvm_arch_prepare_memory_region() (Fuad)
> * Added the check in kvm_vm_ioctl_enable_cap() (Fuad)
>
> Tested by using Fuad's patches to add guest_memfd support for kvmtool at [2],
> with the following changes:
>
> diff --git a/arm64/kvm.c b/arm64/kvm.c
> index 36b3284e4a92..de83b5d7e517 100644
> --- a/arm64/kvm.c
> +++ b/arm64/kvm.c
> @@ -125,10 +125,12 @@ static void kvm__arch_enable_mte(struct kvm *kvm)
> return;
> }
>
> + /*
> if (kvm->cfg.arch.guest_memfd) {
> pr_debug("MTE is incompatible with guest_memfd");
> return;
> }
> + */
>
> if (kvm->cfg.arch.mte_disabled) {
> pr_debug("MTE disabled by user");
> diff --git a/kvm.c b/kvm.c
> index 96583f916442..cc8628b558ea 100644
> --- a/kvm.c
> +++ b/kvm.c
> @@ -332,8 +332,15 @@ int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size,
> .guest_memfd_offset = guest_memfd_offset,
> };
>
> + if (munmap(userspace_addr, size) < 0)
> + die_perror("munmap hack");
> +
> ret = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION2,
> &mem2);
> +
> + if (mmap(userspace_addr, size, PROT_RW, MAP_SHARED | MAP_FIXED,
> + guest_memfd, guest_memfd_offset) == MAP_FAILED)
> + die_perror("mmap hack");
> } else {
> struct kvm_userspace_memory_region mem = {
> .slot = slot,
>
> (indentation is weird on purpose so git doesn't get confused). That's to
> test that the user can create a guest_memfd memslot after MTE has been
> enabled for the VM. Without this patch, I was able to create a VM with MTE
> and guest_memfd backed ram (the guest reported MTE as enabled, but I didn't
> test that it actually worked). With this patch, creating a VM with MTE is
> rejected.
>
> To test that KVM rejects enabling MTE *after* creating a guest_memfd backed
> memslot, I modified kvmtool to enable MTE *after* creating the memslot.
> Same situation: without this patch, KVM allows that, with this patch, KVM
> rejects enabling MTE.
>
> [1] https://lore.kernel.org/kvmarm/20260714110756.116950-1-alexandru.elisei@arm.com/
> [2] https://lore.kernel.org/kvmarm/20260712142536.1391557-1-fuad.tabba@linux.dev/
>
> arch/arm64/kvm/arm.c | 25 +++++++++++++++++++------
> arch/arm64/kvm/mmu.c | 4 ++++
> 2 files changed, 23 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index 50adfff75be8..9a6c72a18672 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -149,14 +149,27 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
> set_bit(KVM_ARCH_FLAG_RETURN_NISV_IO_ABORT_TO_USER,
> &kvm->arch.flags);
> break;
> - case KVM_CAP_ARM_MTE:
> - mutex_lock(&kvm->lock);
> - if (system_supports_mte() && !kvm->created_vcpus) {
> - r = 0;
> - set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
> + case KVM_CAP_ARM_MTE: {
> + struct kvm_memory_slot *memslot;
> + int bkt;
> +
> + guard(mutex)(&kvm->lock);
> + if (!system_supports_mte() || kvm->created_vcpus)
> + break;
> +
> + r = 0;
> + guard(mutex)(&kvm->slots_lock);
> + kvm_for_each_memslot(memslot, bkt, kvm_memslots(kvm)) {
> + if (kvm_slot_has_gmem(memslot)) {
> + r = -EINVAL;
> + break;
> + }
> }
> - mutex_unlock(&kvm->lock);
> + if (r == 0)
> + set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
> break;
> +
> + }
> case KVM_CAP_ARM_SYSTEM_SUSPEND:
> r = 0;
> set_bit(KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED, &kvm->arch.flags);
> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> index 6c941aaa10c6..2d95203386ba 100644
> --- a/arch/arm64/kvm/mmu.c
> +++ b/arch/arm64/kvm/mmu.c
> @@ -2652,6 +2652,10 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
> if (kvm_slot_has_gmem(new) && !kvm_memslot_is_gmem_only(new))
> return -EINVAL;
>
> + /* guest_memfd is incompatible with MTE. */
> + if (kvm_slot_has_gmem(new) && kvm_has_mte(kvm))
> + return -EINVAL;
> +
> hva = new->userspace_addr;
> reg_end = hva + (new->npages << PAGE_SHIFT);
>
>
> base-commit: 1590cf0329716306e948a8fc29f1d3ee87d3989f
> --
> 2.55.0
>
^ 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