* Re: [PATCH v13 3/6] iommu: Add verisilicon IOMMU driver
From: Benjamin Gaignard @ 2026-03-24 16:28 UTC (permalink / raw)
To: Will Deacon
Cc: joro, robin.murphy, robh, krzk+dt, conor+dt, heiko,
nicolas.dufresne, p.zabel, mchehab, iommu, devicetree,
linux-kernel, linux-arm-kernel, linux-rockchip, linux-media
In-Reply-To: <acKxzGk1Z541yoZ4@willie-the-truck>
Le 24/03/2026 à 16:46, Will Deacon a écrit :
> On Mon, Feb 16, 2026 at 10:51:35AM +0100, Benjamin Gaignard wrote:
>> The Verisilicon IOMMU hardware block can be found in combination
>> with Verisilicon hardware video codecs (encoders or decoders) on
>> different SoCs.
>> Enable it will allow us to use non contiguous memory allocators
>> for Verisilicon video codecs.
>> If both decoder and this iommu driver are compiled has modules
>> there is undefined symboles issues so this iommu driver could
>> only be compiled has built-in.
>>
>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
>> ---
>> MAINTAINERS | 8 +
>> drivers/iommu/Kconfig | 11 +
>> drivers/iommu/Makefile | 1 +
>> drivers/iommu/vsi-iommu.c | 794 ++++++++++++++++++++++++++++++++++++++
>> include/linux/vsi-iommu.h | 21 +
>> 5 files changed, 835 insertions(+)
>> create mode 100644 drivers/iommu/vsi-iommu.c
>> create mode 100644 include/linux/vsi-iommu.h
> [...]
>
>> +static size_t vsi_iommu_unmap(struct iommu_domain *domain, unsigned long _iova,
>> + size_t size, size_t count, struct iommu_iotlb_gather *gather)
>> +{
>> + struct vsi_iommu_domain *vsi_domain = to_vsi_domain(domain);
>> + dma_addr_t pte_dma, iova = (dma_addr_t)_iova;
>> + unsigned long flags;
>> + phys_addr_t pt_phys;
>> + u32 dte;
>> + u32 *pte_addr;
>> + size_t unmap_size = 0;
>> +
>> + spin_lock_irqsave(&vsi_domain->lock, flags);
>> +
>> + dte = vsi_domain->dt[vsi_iova_dte_index(iova)];
>> + /* Just return 0 if iova is unmapped */
>> + if (!vsi_dte_is_pt_valid(dte))
>> + goto unlock;
>> +
>> + pt_phys = vsi_dte_pt_address(dte);
>> + pte_addr = (u32 *)phys_to_virt(pt_phys) + vsi_iova_pte_index(iova);
>> + pte_dma = pt_phys + vsi_iova_pte_index(iova) * sizeof(u32);
>> + unmap_size = vsi_iommu_unmap_iova(vsi_domain, pte_addr, pte_dma, size);
>> +
>> +unlock:
>> + spin_unlock_irqrestore(&vsi_domain->lock, flags);
>> +
>> + return unmap_size;
>> +}
> I still think you need TLB invalidation here.
>
> I looked at the downstream code that you linked to and it litters the
> invalidation in the callers via mpp_iommu_flush_tlb(), which tend to
> invalidate _before_ starting an operation. That's very likely buggy and
> certainly not something we want upstream.
>
> The unmap routine should do the invalidation so that, when it returns,
> the pages really are unmapped from the device (assuming strict mode).
>
> I know you said that you tried to add invalidation here and it "didn't
> work", but that's not something I can really help you with.
I know you expect the hardware to work like that but that isn't not the case.
I spend quite long to try to found hidden bit(s) or an other way to do like
you want but I can't find any solution.
As you mention the downstream code suggest that the iommu can't invalidate
TLB in unmap routine so I don't see how to progress.
Maybe we should just admit that is how the hardware work.
This v13 has fixed the documentation so I don't plan to spend more time on this driver.
Benjamin
>
> Will
^ permalink raw reply
* Re: [GIT PULL] KVM/arm64 fixes for 7.0, take #4
From: Paolo Bonzini @ 2026-03-24 16:32 UTC (permalink / raw)
To: Marc Zyngier
Cc: Joey Gouly, Suzuki K Poulose, Zenghui Yu, Oliver Upton,
Zenghui Yu, linux-arm-kernel, kvmarm, kvm
In-Reply-To: <20260320094151.2541661-1-maz@kernel.org>
On Fri, Mar 20, 2026 at 10:42 AM Marc Zyngier <maz@kernel.org> wrote:
>
> Paolo,
>
> Another week, another set of fixes. This time, another two fixes,
> mostly observable with nested virt. The first one results in a vcpu
> coming out of reset potentially skipping the first instruction at its
> initial PC. The second one is a classic example of pointer arithmetic
> going wrong in our address translation emulation, setting the access
> bit in semi-random places. Both are stable candidates.
Pulled, thanks.
Paolo
^ permalink raw reply
* Re: [PATCH v4 05/21] mm: switch the rmap lock held option off in compat layer
From: Lorenzo Stoakes (Oracle) @ 2026-03-24 16:35 UTC (permalink / raw)
To: Vlastimil Babka (SUSE)
Cc: Andrew Morton, Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
Jan Kara, David Hildenbrand, Liam R . Howlett, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Jann Horn, Pedro Falcato,
linux-kernel, linux-doc, linux-hyperv, linux-stm32,
linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <d5b66671-697f-4a4d-8039-d9c9ac5ad4d7@kernel.org>
On Tue, Mar 24, 2026 at 03:26:28PM +0100, Vlastimil Babka (SUSE) wrote:
> On 3/20/26 23:39, Lorenzo Stoakes (Oracle) wrote:
> > In the mmap_prepare compatibility layer, we don't need to hold the rmap
> > lock, as we are being called from an .mmap handler.
> >
> > The .mmap_prepare hook, when invoked in the VMA logic, is called prior to
> > the VMA being instantiated, but the completion hook is called after the VMA
> > is linked into the maple tree, meaning rmap walkers can reach it.
> >
> > The mmap hook does not link the VMA into the tree, so this cannot happen.
> >
> > Therefore it's safe to simply disable this in the mmap_prepare
> > compatibility layer.
> >
> > Also update VMA tests code to reflect current compatibility layer state.
> >
> > Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
>
> Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
>
> a typo fix below, Andrew can fix locally?
>
> > ---
> > mm/util.c | 6 ++++-
> > tools/testing/vma/include/dup.h | 42 +++++++++++++++++----------------
> > 2 files changed, 27 insertions(+), 21 deletions(-)
> >
> > diff --git a/mm/util.c b/mm/util.c
> > index a2cfa0d77c35..182f0f5cc400 100644
> > --- a/mm/util.c
> > +++ b/mm/util.c
> > @@ -1204,6 +1204,7 @@ int compat_vma_mmap(struct file *file, struct vm_area_struct *vma)
> >
> > .action.type = MMAP_NOTHING, /* Default */
> > };
> > + struct mmap_action *action = &desc.action;
> > int err;
> >
> > err = vfs_mmap_prepare(file, &desc);
> > @@ -1214,8 +1215,11 @@ int compat_vma_mmap(struct file *file, struct vm_area_struct *vma)
> > if (err)
> > return err;
> >
> > + /* being invoked from .mmmap means we don't have to enforce this. */
>
> .mmap
mmmmm map! ;)
Andrew - could you fixup in place? Thanks.
>
> > + action->hide_from_rmap_until_complete = false;
> > +
> > set_vma_from_desc(vma, &desc);
> > - err = mmap_action_complete(vma, &desc.action);
> > + err = mmap_action_complete(vma, action);
> > if (err) {
> > const size_t len = vma_pages(vma) << PAGE_SHIFT;
> >
^ permalink raw reply
* Re: [PATCH v3 16/27] media: rockchip: rga: check scaling factor
From: Sven Püschel @ 2026-03-24 16:38 UTC (permalink / raw)
To: Nicolas Dufresne, Jacob Chen, Ezequiel Garcia,
Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel
In-Reply-To: <90da83de861e8268745255720554ad23341e6839.camel@ndufresne.ca>
Hi Nicolas,
On 3/20/26 6:57 PM, Nicolas Dufresne wrote:
> Le mardi 27 janvier 2026 à 15:39 +0100, Sven Püschel a écrit :
>> Check the scaling factor to avoid potential problems. This is relevant
>> for the upcoming RGA3 support, as it can hang when the scaling factor
>> is exceeded.
>>
>> There are two relevant scenarios that have to be considered to protect
>> against invalid scaling values:
>>
>> When the output or capture is already streaming, setting the format on
>> the other side should consider the max scaling factor and clamp it
>> accordingly. This is only done in the streaming case, as it otherwise
>> may unintentionally clamp the value when the application sets the first
>> format (due to a default format on the other side).
>>
>> When the format is set on both sides first, then the format won't be
>> corrected by above means. Therefore the second streamon call has to
>> check the scaling factor and fail otherwise.
>>
>> As try functions should only be state aware if specified, the scaling
>> limitation is only done in s_fmt.
>>
>> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
>> ---
>> drivers/media/platform/rockchip/rga/rga-hw.c | 1 +
>> drivers/media/platform/rockchip/rga/rga-hw.h | 1 +
>> drivers/media/platform/rockchip/rga/rga.c | 47 ++++++++++++++++++++++++++++
>> drivers/media/platform/rockchip/rga/rga.h | 1 +
>> 4 files changed, 50 insertions(+)
>>
>> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
>> index dcd540ed3fd5b..7a4070665fed7 100644
>> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
>> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
>> @@ -584,6 +584,7 @@ const struct rga_hw rga2_hw = {
>> .max_width = MAX_WIDTH,
>> .min_height = MIN_HEIGHT,
>> .max_height = MAX_HEIGHT,
>> + .max_scaling_factor = MAX_SCALING_FACTOR,
>> .stride_alignment = 4,
>>
>> .setup_cmdbuf = rga_hw_setup_cmdbuf,
>> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
>> index f4752aa823051..fffcab0131225 100644
>> --- a/drivers/media/platform/rockchip/rga/rga-hw.h
>> +++ b/drivers/media/platform/rockchip/rga/rga-hw.h
>> @@ -14,6 +14,7 @@
>>
>> #define MIN_WIDTH 34
>> #define MIN_HEIGHT 34
>> +#define MAX_SCALING_FACTOR 16
>>
>> #define RGA_TIMEOUT 500
>>
>> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
>> index 6947c472a8b01..fad921ddd8348 100644
>> --- a/drivers/media/platform/rockchip/rga/rga.c
>> +++ b/drivers/media/platform/rockchip/rga/rga.c
>> @@ -405,10 +405,36 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
>> struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
>> struct rga_ctx *ctx = file_to_rga_ctx(file);
>> struct rockchip_rga *rga = ctx->rga;
>> + const struct rga_hw *hw = rga->hw;
>> struct vb2_queue *vq;
>> struct rga_frame *frm;
>> int ret = 0;
>> int i;
>> + struct rga_frame *limit_frm = NULL;
>> +
>> + /* Limit before try_fmt to avoid recalculating the stride */
>> + if (V4L2_TYPE_IS_OUTPUT(f->type) &&
>> + v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming)
>> + limit_frm = &ctx->out;
>> + if (V4L2_TYPE_IS_CAPTURE(f->type) &&
>> + v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)->streaming)
>> + limit_frm = &ctx->in;
>> + if (limit_frm) {
>> + const struct v4l2_frmsize_stepwise frmsize = {
>> + .min_width = DIV_ROUND_UP(limit_frm->pix.width,
>> + hw->max_scaling_factor),
>> + .max_width =
>> + limit_frm->pix.width * hw->max_scaling_factor,
>> + .min_height = DIV_ROUND_UP(limit_frm->pix.height,
>> + hw->max_scaling_factor),
>> + .max_height =
>> + limit_frm->pix.height * hw->max_scaling_factor,
>> + .step_width = 1,
>> + .step_height = 1,
> Is there a risk to re-introduce odd sizes ? Should this be the hdiv / vdiv
> values ?
I'm still calling try_fmt afterwards, which does all of the further
clamping (min/max size supported by the core and the yuv step size).
Therefore I don't see the risk of re-introducing invalid sizes. It's
just an additional clamping only done in s_fmt to avoid the try_fmt
getting stateful.
Sincerely
Sven
>
>> + };
>> + v4l2_apply_frmsize_constraints(&pix_fmt->width,
>> + &pix_fmt->height, &frmsize);
>> + }
>>
>> /* Adjust all values accordingly to the hardware capabilities
>> * and chosen format.
>> @@ -568,12 +594,33 @@ static int vidioc_s_selection(struct file *file, void *priv,
>> return ret;
>> }
>>
>> +static bool check_scaling(const struct rga_hw *hw, u32 src_size, u32 dst_size)
>> +{
>> + if (src_size < dst_size)
>> + return src_size * hw->max_scaling_factor >= dst_size;
>> + else
>> + return dst_size * hw->max_scaling_factor >= src_size;
>> +}
>> +
>> static int vidioc_streamon(struct file *file, void *priv,
>> enum v4l2_buf_type type)
>> {
>> struct rga_ctx *ctx = file_to_rga_ctx(file);
>> const struct rga_hw *hw = ctx->rga->hw;
>>
>> + if ((V4L2_TYPE_IS_OUTPUT(type) &&
>> + v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) ||
>> + (V4L2_TYPE_IS_CAPTURE(type) &&
>> + v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)->streaming)) {
>> + /*
>> + * As the other side is already streaming,
>> + * check that the max scaling factor isn't exceeded.
>> + */
>> + if (!check_scaling(hw, ctx->in.pix.width, ctx->out.pix.width) ||
>> + !check_scaling(hw, ctx->in.pix.height, ctx->out.pix.height))
>> + return -EINVAL;
>> + }
>> +
>> hw->setup_cmdbuf(ctx);
>>
>> return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type);
>> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
>> index c741213710b32..454af283b1694 100644
>> --- a/drivers/media/platform/rockchip/rga/rga.h
>> +++ b/drivers/media/platform/rockchip/rga/rga.h
>> @@ -150,6 +150,7 @@ struct rga_hw {
>> size_t cmdbuf_size;
>> u32 min_width, min_height;
>> u32 max_width, max_height;
>> + u8 max_scaling_factor;
>> u8 stride_alignment;
>>
>> void (*setup_cmdbuf)(struct rga_ctx *ctx);
^ permalink raw reply
* Re: [PATCH v2 net-next 13/14] net: dsa: netc: initialize buffer bool table and implement flow-control
From: Simon Horman @ 2026-03-24 16:42 UTC (permalink / raw)
To: wei.fang
Cc: Simon Horman, xiaoning.wang, netdev, linux, krzk+dt, kuba,
andrew+netdev, chleroy, andrew, conor+dt, edumazet,
linux-arm-kernel, frank.li, robh, devicetree, claudiu.manoil,
f.fainelli, vladimir.oltean, linuxppc-dev, pabeni, davem,
linux-kernel, imx
In-Reply-To: <20260323060752.1157031-14-wei.fang@nxp.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
For local reproduction steps see https://netdev-ai.bots.linux.dev/ai-local.html
---
net: dsa: netc: initialize buffer bool table and implement flow-control
The buffer pool is a quantity of memory available for buffering a group
of flows (e.g. frames having the same priority, frames received from the
same port), while waiting to be transmitted on a port. The buffer pool
tracks internal memory consumption with upper bound limits and optionally
a non-shared portion when associated with a shared buffer pool. Currently
the shared buffer pool is not supported, it will be added in the future.
For i.MX94, the switch has 4 ports and 8 buffer pools, so each port is
allocated two buffer pools. For frames with priorities of 0 to 3, they
will be mapped to the first buffer pool; For frames with priorities of
4 to 7, they will be mapped to the second buffer pool. Each buffer pool
has a flow control on threshold and a flow control off threshold. By
setting these threshold, add the flow control support to each port.
> diff --git a/drivers/net/dsa/netc/netc_main.c b/drivers/net/dsa/netc/netc_main.c
> index 4b331971dd8c..2a7ad39f8bed 100644
> --- a/drivers/net/dsa/netc/netc_main.c
> +++ b/drivers/net/dsa/netc/netc_main.c
[ ... ]
> @@ -617,6 +628,80 @@ static int netc_add_standalone_fdb_bcast_entry(struct netc_switch *priv)
> bcast, NETC_STANDALONE_PVID);
> }
>
> +static u32 netc_get_buffer_pool_num(struct netc_switch *priv)
> +{
> + return netc_base_rd(&priv->regs, NETC_BPCAPR) & BPCAPR_NUM_BP;
> +}
> +
> +static void netc_port_set_pbpmcr(struct netc_port *np, u64 mapping)
> +{
> + u32 pbpmcr0 = lower_32_bits(mapping);
> + u32 pbpmcr1 = upper_32_bits(mapping);
> +
> + netc_port_wr(np, NETC_PBPMCR0, pbpmcr0);
> + netc_port_wr(np, NETC_PBPMCR1, pbpmcr1);
> +}
> +
> +static void netc_ipv_to_buffer_pool_mapping(struct netc_switch *priv)
> +{
> + int num_port_bp = priv->num_bp / priv->info->num_ports;
> + int q = NETC_IPV_NUM / num_port_bp;
> ^^^^
Can this cause a division by zero? If netc_get_buffer_pool_num() reads
the hardware register NETC_BPCAPR and returns 0, then num_port_bp would be
0 and this division would crash the kernel.
The call chain is:
netc_setup()
netc_switch_bpt_default_config()
priv->num_bp = netc_get_buffer_pool_num()
netc_ipv_to_buffer_pool_mapping()
num_port_bp = priv->num_bp / priv->info->num_ports;
q = NETC_IPV_NUM / num_port_bp; <- division by zero
Should netc_switch_bpt_default_config() validate that priv->num_bp is
non-zero before proceeding?
> + int r = NETC_IPV_NUM % num_port_bp;
> + int num = q + r;
> +
> + /* IPV-to–buffer-pool mapping per port:
[ ... ]
> +static int netc_switch_bpt_default_config(struct netc_switch *priv)
> +{
> + priv->num_bp = netc_get_buffer_pool_num(priv);
> + priv->bpt_list = devm_kcalloc(priv->dev, priv->num_bp,
> + sizeof(struct bpt_cfge_data),
> + GFP_KERNEL);
> + if (!priv->bpt_list)
> + return -ENOMEM;
> +
> + /* Initialize the maximum threshold of each buffer pool entry */
> + for (int i = 0; i < priv->num_bp; i++) {
> + struct bpt_cfge_data *cfge = &priv->bpt_list[i];
> + int err;
> +
> + cfge->max_thresh = cpu_to_le16(NETC_BP_THRESH);
> + err = ntmp_bpt_update_entry(&priv->ntmp, i, cfge);
> + if (err)
> + return err;
> + }
> +
> + netc_ipv_to_buffer_pool_mapping(priv);
> +
> + return 0;
> +}
> +
[ ... ]
> @@ -1224,6 +1313,40 @@ static void netc_port_set_hd_flow_control(struct netc_port *np, bool en)
> en ? PM_CMD_CFG_HD_FCEN : 0);
> }
>
> +static void netc_port_set_tx_pause(struct netc_port *np, bool tx_pause)
> +{
> + struct netc_switch *priv = np->switch_priv;
> + int port = np->dp->index;
> + int i, j, num_bp;
> +
> + num_bp = priv->num_bp / priv->info->num_ports;
> + for (i = 0, j = port * num_bp; i < num_bp; i++, j++) {
> + struct bpt_cfge_data *cfge;
> +
> + cfge = &priv->bpt_list[j];
> + if (tx_pause) {
> + cfge->fc_on_thresh = cpu_to_le16(NETC_FC_THRESH_ON);
> + cfge->fc_off_thresh = cpu_to_le16(NETC_FC_THRESH_OFF);
> + cfge->fccfg_sbpen = FIELD_PREP(BPT_FC_CFG,
> + BPT_FC_CFG_EN_BPFC);
> + cfge->fc_ports = cpu_to_le32(BIT(port));
> + } else {
> + cfge->fc_on_thresh = cpu_to_le16(0);
> + cfge->fc_off_thresh = cpu_to_le16(0);
> + cfge->fccfg_sbpen = 0;
> + cfge->fc_ports = cpu_to_le32(0);
> + }
> +
> + ntmp_bpt_update_entry(&priv->ntmp, j, cfge);
> ^^^^
Should the return value of ntmp_bpt_update_entry() be checked here?
Simon Horman noted in v1 review that other NTMP table operations in the
driver propagate errors from the update functions. While this was fixed
in netc_switch_bpt_default_config() in v2, the same issue remains here.
If the hardware update fails (for example, DMA allocation failure or
hardware timeout), the driver's bpt_list will have flow control values that
do not match the actual hardware state, potentially causing incorrect flow
control behavior.
https://lore.kernel.org/netdev/20260318145452.1898637-2-horms@kernel.org/
> + }
> +}
> +
[ ... ]
^ permalink raw reply
* [PATCH 1/7] dt-bindings: sram: Document Allwinner H616 VE SRAM
From: Chen-Yu Tsai @ 2026-03-24 16:43 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland
Cc: devicetree, linux-sunxi, linux-arm-kernel, linux-kernel
In-Reply-To: <20260324164357.1607247-1-wens@kernel.org>
The Allwinner H616 has two switchable peripheral SRAM regions:
- The VE SRAM is a 2 MB dedicated SRAM for the Video Engine. CPU access
to this region is enabled by default. CPU access can be disabled,
after which reads will show the same stale value for all addresses,
while writes are ignored.
The mux value for this region is different from previous generations,
and thus needs a completely new compatible.
- The SRAM C region is an alias of the first 128 KB of VE SRAM, plus 64
KB of DE SRAM. The latter is otherwise unaccessible from the CPU. When
CPU access is disabled, the whole region reads as zero, while writes
are ignored.
The mux value for this region is the same as on the A64 and H6. The
existing compatible for the A64 already covers this.
Add the compatible for the VE SRAM to the list of covered compatibles in
the generic SRAM region binding.
Signed-off-by: Chen-Yu Tsai <wens@kernel.org>
---
Documentation/devicetree/bindings/sram/sram.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/sram/sram.yaml b/Documentation/devicetree/bindings/sram/sram.yaml
index c451140962c8..ddaab84f7ba0 100644
--- a/Documentation/devicetree/bindings/sram/sram.yaml
+++ b/Documentation/devicetree/bindings/sram/sram.yaml
@@ -81,6 +81,7 @@ patternProperties:
- allwinner,sun4i-a10-sram-d
- allwinner,sun9i-a80-smp-sram
- allwinner,sun50i-a64-sram-c
+ - allwinner,sun50i-h616-ve-sram
- amlogic,meson8-ao-arc-sram
- amlogic,meson8b-ao-arc-sram
- amlogic,meson8-smp-sram
--
2.47.3
^ permalink raw reply related
* [PATCH 3/7] soc: sunxi: sram: Const-ify sunxi_sram_func data and references
From: Chen-Yu Tsai @ 2026-03-24 16:43 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland
Cc: devicetree, linux-sunxi, linux-arm-kernel, linux-kernel
In-Reply-To: <20260324164357.1607247-1-wens@kernel.org>
sunxi_sram_func contains value mapping that do not change at runtime.
Const-ify them.
Signed-off-by: Chen-Yu Tsai <wens@kernel.org>
---
drivers/soc/sunxi/sunxi_sram.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
index 446b9fc1f175..5e8c80ae3509 100644
--- a/drivers/soc/sunxi/sunxi_sram.c
+++ b/drivers/soc/sunxi/sunxi_sram.c
@@ -29,11 +29,11 @@ struct sunxi_sram_func {
};
struct sunxi_sram_data {
- char *name;
- u8 reg;
- u8 offset;
- u8 width;
- struct sunxi_sram_func *func;
+ char *name;
+ u8 reg;
+ u8 offset;
+ u8 width;
+ const struct sunxi_sram_func *func;
};
struct sunxi_sram_desc {
@@ -54,7 +54,7 @@ struct sunxi_sram_desc {
.reg = _reg, \
.offset = _off, \
.width = _width, \
- .func = (struct sunxi_sram_func[]){ \
+ .func = (const struct sunxi_sram_func[]){ \
__VA_ARGS__, { } }, \
}
@@ -111,7 +111,7 @@ static int sunxi_sram_show(struct seq_file *s, void *data)
struct device_node *sram_node, *section_node;
const struct sunxi_sram_data *sram_data;
const struct of_device_id *match;
- struct sunxi_sram_func *func;
+ const struct sunxi_sram_func *func;
const __be32 *sram_addr_p, *section_addr_p;
u32 val;
@@ -169,7 +169,7 @@ static const struct sunxi_sram_data *sunxi_sram_of_parse(struct device_node *nod
{
const struct of_device_id *match;
const struct sunxi_sram_data *data;
- struct sunxi_sram_func *func;
+ const struct sunxi_sram_func *func;
struct of_phandle_args args;
u8 val;
int ret;
--
2.47.3
^ permalink raw reply related
* [PATCH 2/7] dt-bindings: sram: sunxi-sram: Add H616 SRAM regions
From: Chen-Yu Tsai @ 2026-03-24 16:43 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland
Cc: devicetree, linux-sunxi, linux-arm-kernel, linux-kernel
In-Reply-To: <20260324164357.1607247-1-wens@kernel.org>
The Allwinner H616 has two switchable peripheral SRAM regions:
- The VE SRAM is a 2 MB dedicated SRAM for the Video Engine. CPU access
to this region is enabled by default. CPU access can be disabled,
after which reads will show the same stale value for all addresses,
while writes are ignored.
The mux value for this region is different from previous generations.
- The SRAM C region is an alias of the first 128 KB of VE SRAM, plus 64
KB of DE SRAM. The latter is otherwise unaccessible from the CPU. When
CPU access is disabled, the whole region reads as zero, while writes
are ignored.
The mux value for this region is the same as on the A64 and H6.
Add compatible strings for both of them.
Signed-off-by: Chen-Yu Tsai <wens@kernel.org>
---
.../bindings/sram/allwinner,sun4i-a10-system-control.yaml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml b/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml
index e7f7cf72719e..6e6ab2168a2a 100644
--- a/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml
+++ b/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml
@@ -80,6 +80,7 @@ patternProperties:
- const: allwinner,sun4i-a10-sram-c1
- const: allwinner,sun4i-a10-sram-d
- const: allwinner,sun50i-a64-sram-c
+ - const: allwinner,sun50i-h616-ve-sram
- items:
- enum:
- allwinner,sun5i-a13-sram-a3-a4
@@ -103,7 +104,9 @@ patternProperties:
- allwinner,sun7i-a20-sram-d
- const: allwinner,sun4i-a10-sram-d
- items:
- - const: allwinner,sun50i-h6-sram-c
+ - enum:
+ - allwinner,sun50i-h6-sram-c
+ - allwinner,sun50i-h616-sram-c
- const: allwinner,sun50i-a64-sram-c
required:
--
2.47.3
^ permalink raw reply related
* [PATCH 7/7] arm64: dts: allwinner: sun50i-h616: Add SRAM nodes
From: Chen-Yu Tsai @ 2026-03-24 16:43 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland
Cc: Jernej Skrabec, devicetree, linux-sunxi, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260324164357.1607247-1-wens@kernel.org>
From: Jernej Skrabec <jernej.skrabec@gmail.com>
The H616 SoC has a video engine, and two SRAM regions needed by it.
Add the SRAM regions to the dtsi file. The video engine will be added
in a separate change.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
[wens@kernel.org: Add VE SRAM region, commit message, and split into two]
Signed-off-by: Chen-Yu Tsai <wens@kernel.org>
---
.../arm64/boot/dts/allwinner/sun50i-h616.dtsi | 28 ++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
index 8d1110c14bad..0c50a73def65 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
@@ -182,12 +182,38 @@ syscon: syscon@3000000 {
#size-cells = <1>;
ranges;
- sram_c: sram@28000 {
+ /* SRAM C */
+ sram@28000 {
compatible = "mmio-sram";
reg = <0x00028000 0x30000>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x00028000 0x30000>;
+
+ /*
+ * 0x0 ~ 0x20000 is partial alias of VE SRAM below.
+ * 0x20000 ~ 0x2ffff is (partial?) alias of DE SRAM.
+ * However the whole region is toggled together.
+ */
+ sram_c: sram-section@0 {
+ compatible = "allwinner,sun50i-h616-sram-c",
+ "allwinner,sun50i-a64-sram-c";
+ reg = <0x00000 0x30000>;
+ };
+ };
+
+ /* VE SRAM */
+ sram@1a00000 {
+ compatible = "mmio-sram";
+ reg = <0x01a00000 0x200000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x01a00000 0x200000>;
+
+ ve_sram: sram-section@0 {
+ compatible = "allwinner,sun50i-h616-ve-sram";
+ reg = <0x000000 0x200000>;
+ };
};
};
--
2.47.3
^ permalink raw reply related
* [PATCH 0/7] soc: sunxi: sram: Add H616 SRAM support
From: Chen-Yu Tsai @ 2026-03-24 16:43 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland
Cc: devicetree, linux-sunxi, linux-arm-kernel, linux-kernel
Hi,
The Allwinner H616 has two switchable peripheral SRAM regions:
- The VE SRAM is a 2 MB dedicated SRAM for the Video Engine. CPU access
to this region is enabled by default. CPU access can be disabled,
after which reads will show the same stale value for all addresses,
while writes are ignored.
The mux value for this region is different from previous generations.
- The SRAM C region is an alias of the first 128 KB of VE SRAM, plus 64
KB of DE SRAM. The latter is otherwise unaccessible from the CPU. When
CPU access is disabled, the whole region reads as zero, while writes
are ignored.
The mux value for this region is the same as on the A64 and H6.
The driver needs to allow both the Video Engine and Display Engine to
claim the SRAM C region at the same time.
At the same time, since the Video Engine needs to claim both SRAM
regions, the Allwinner SRAM consumer interface needs to support claiming
multiple regions for one consumer.
Patch 1 adds a compatible for the new H616 VE SRAM to the common SRAM
binding.
Patch 2 adds a compatible for the new H616 VE SRAM to the Allwinner SRAM
binding.
Patch 3 is a minor cleanup that const-ifies the SRAM related hardware
description data in the driver.
Patch 4 implements support for multiple hardware block drivers to claim
the same SRAM region.
Patch 5 implements support for one consumer to claim multiple SRAM
regions.
Patch 6 adds support for the H616 VE SRAM region to the SRAM driver.
Patch 7 adds the SRAM regions to the H616 dtsi file. This was picked
from Jernej's tree and split into one patch for SRAM and one patch for
the video engine.
I think all the changes can go through the sunxi tree, unless the device
tree maintainers want to take the first patch separately?
The new users of this, support for the H616 video engine, will be sent
separately.
Thanks
ChenYu
Chen-Yu Tsai (6):
dt-bindings: sram: Document Allwinner H616 VE SRAM
dt-bindings: sram: sunxi-sram: Add H616 SRAM regions
soc: sunxi: sram: Const-ify sunxi_sram_func data and references
soc: sunxi: sram: Allow SRAM to be claimed multiple times
soc: sunxi: sram: Support claiming multiple regions per device
soc: sunxi: sram: Add H616 SRAM regions
Jernej Skrabec (1):
arm64: dts: allwinner: sun50i-h616: Add SRAM nodes
.../allwinner,sun4i-a10-system-control.yaml | 5 +-
.../devicetree/bindings/sram/sram.yaml | 1 +
.../arm64/boot/dts/allwinner/sun50i-h616.dtsi | 28 ++-
drivers/soc/sunxi/sunxi_sram.c | 196 +++++++++++-------
4 files changed, 151 insertions(+), 79 deletions(-)
--
2.47.3
^ permalink raw reply
* [PATCH 6/7] soc: sunxi: sram: Add H616 SRAM regions
From: Chen-Yu Tsai @ 2026-03-24 16:43 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland
Cc: devicetree, linux-sunxi, linux-arm-kernel, linux-kernel
In-Reply-To: <20260324164357.1607247-1-wens@kernel.org>
The Allwinner H616 has two switchable peripheral SRAM regions:
- The VE SRAM is a 2 MB dedicated SRAM for the Video Engine. CPU access
to this region is enabled by default. CPU access can be disabled,
after which reads will show the same stale value for all addresses,
while writes are ignored.
The mux value for this region is different from previous generations.
- The SRAM C region is an alias of the first 128 KB of VE SRAM, plus 64
KB of DE SRAM. The latter is otherwise unaccessible from the CPU. When
CPU access is disabled, the whole region reads as zero, while writes
are ignored.
The mux value for this region is the same as on the A64 and H6.
Add data for the VE SRAM. The register values were taken from the BSP
vendor kernel.
Signed-off-by: Chen-Yu Tsai <wens@kernel.org>
---
drivers/soc/sunxi/sunxi_sram.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
index 4d81897179e7..2ccaeacf8c70 100644
--- a/drivers/soc/sunxi/sunxi_sram.c
+++ b/drivers/soc/sunxi/sunxi_sram.c
@@ -83,6 +83,12 @@ static struct sunxi_sram_desc sun50i_a64_sram_c = {
SUNXI_SRAM_MAP(0, 1, "de2")),
};
+static struct sunxi_sram_desc sun50i_h616_ve_sram = {
+ .data = SUNXI_SRAM_DATA("VE", 0x0, 0, 1,
+ SUNXI_SRAM_MAP(1, 0, "cpu"),
+ SUNXI_SRAM_MAP(0, 1, "ve")),
+};
+
static const struct of_device_id sunxi_sram_dt_ids[] = {
{
.compatible = "allwinner,sun4i-a10-sram-a3-a4",
@@ -100,6 +106,10 @@ static const struct of_device_id sunxi_sram_dt_ids[] = {
.compatible = "allwinner,sun50i-a64-sram-c",
.data = &sun50i_a64_sram_c.data,
},
+ {
+ .compatible = "allwinner,sun50i-h616-ve-sram",
+ .data = &sun50i_h616_ve_sram.data,
+ },
{}
};
--
2.47.3
^ permalink raw reply related
* [PATCH 5/7] soc: sunxi: sram: Support claiming multiple regions per device
From: Chen-Yu Tsai @ 2026-03-24 16:43 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland
Cc: devicetree, linux-sunxi, linux-arm-kernel, linux-kernel
In-Reply-To: <20260324164357.1607247-1-wens@kernel.org>
On the H616, the video engine needs to claim two SRAM regions.
Support claiming multiple regions per device.
Signed-off-by: Chen-Yu Tsai <wens@kernel.org>
---
drivers/soc/sunxi/sunxi_sram.c | 164 +++++++++++++++++++--------------
1 file changed, 96 insertions(+), 68 deletions(-)
diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
index aba155379ccc..4d81897179e7 100644
--- a/drivers/soc/sunxi/sunxi_sram.c
+++ b/drivers/soc/sunxi/sunxi_sram.c
@@ -165,79 +165,48 @@ static inline struct sunxi_sram_desc *to_sram_desc(const struct sunxi_sram_data
return container_of(data, struct sunxi_sram_desc, data);
}
-static const struct sunxi_sram_data *sunxi_sram_of_parse(struct device_node *node,
- unsigned int *reg_value)
+static const struct sunxi_sram_data *sunxi_sram_get_match(struct device_node *np, u8 val,
+ unsigned int *reg_value)
{
const struct of_device_id *match;
const struct sunxi_sram_data *data;
const struct sunxi_sram_func *func;
- struct of_phandle_args args;
- u8 val;
- int ret;
-
- ret = of_parse_phandle_with_fixed_args(node, "allwinner,sram", 1, 0,
- &args);
- if (ret)
- return ERR_PTR(ret);
- if (!of_device_is_available(args.np)) {
- ret = -EBUSY;
- goto err;
- }
+ if (!of_device_is_available(np))
+ return ERR_PTR(-ENODEV);
- val = args.args[0];
-
- match = of_match_node(sunxi_sram_dt_ids, args.np);
- if (!match) {
- ret = -EINVAL;
- goto err;
- }
+ match = of_match_node(sunxi_sram_dt_ids, np);
+ if (!match)
+ return ERR_PTR(-ENODEV);
data = match->data;
- if (!data) {
- ret = -EINVAL;
- goto err;
- }
-
- for (func = data->func; func->func; func++) {
- if (val == func->val) {
- if (reg_value)
- *reg_value = func->reg_val;
+ if (!data)
+ return ERR_PTR(-EINVAL);
+ for (func = data->func; func->func; func++)
+ if (val == func->val)
break;
- }
- }
- if (!func->func) {
- ret = -EINVAL;
- goto err;
- }
+ if (!func->func)
+ return ERR_PTR(-EINVAL);
- of_node_put(args.np);
- return match->data;
+ if (reg_value)
+ *reg_value = func->reg_val;
-err:
- of_node_put(args.np);
- return ERR_PTR(ret);
+ return data;
}
-int sunxi_sram_claim(struct device *dev)
+#define SUNXI_SRAM_PROP "allwinner,sram"
+#define SUNXI_SRAM_CELLS 1
+
+static int sunxi_sram_claim_one(struct device_node *np, u8 arg)
{
const struct sunxi_sram_data *sram_data;
struct sunxi_sram_desc *sram_desc;
unsigned int device;
u32 val, mask;
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- if (!base)
- return -EPROBE_DEFER;
-
- if (!dev || !dev->of_node)
- return -EINVAL;
-
- sram_data = sunxi_sram_of_parse(dev->of_node, &device);
+ sram_data = sunxi_sram_get_match(np, arg, &device);
if (IS_ERR(sram_data))
return PTR_ERR(sram_data);
@@ -248,33 +217,28 @@ int sunxi_sram_claim(struct device *dev)
if (sram_desc->claim_cnt) {
if (!WARN_ON(sram_desc->claim_cnt == U8_MAX))
sram_desc->claim_cnt++;
- spin_unlock(&sram_lock);
- return 0;
+ } else {
+ mask = GENMASK(sram_data->offset + sram_data->width - 1,
+ sram_data->offset);
+ val = readl(base + sram_data->reg);
+ val &= ~mask;
+ writel(val | ((device << sram_data->offset) & mask),
+ base + sram_data->reg);
+
+ sram_desc->claim_cnt++;
}
- mask = GENMASK(sram_data->offset + sram_data->width - 1,
- sram_data->offset);
- val = readl(base + sram_data->reg);
- val &= ~mask;
- writel(val | ((device << sram_data->offset) & mask),
- base + sram_data->reg);
-
- sram_desc->claim_cnt++;
spin_unlock(&sram_lock);
return 0;
}
-EXPORT_SYMBOL(sunxi_sram_claim);
-void sunxi_sram_release(struct device *dev)
+static void sunxi_sram_release_one(struct device_node *np, u8 arg)
{
const struct sunxi_sram_data *sram_data;
struct sunxi_sram_desc *sram_desc;
- if (!dev || !dev->of_node)
- return;
-
- sram_data = sunxi_sram_of_parse(dev->of_node, NULL);
+ sram_data = sunxi_sram_get_match(np, arg, NULL);
if (IS_ERR(sram_data))
return;
@@ -285,6 +249,70 @@ void sunxi_sram_release(struct device *dev)
sram_desc->claim_cnt--;
spin_unlock(&sram_lock);
}
+
+int sunxi_sram_claim(struct device *dev)
+{
+ struct of_phandle_iterator it;
+ int err;
+ int count = 0;
+
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ if (!base)
+ return -EPROBE_DEFER;
+
+ if (!dev || !dev->of_node)
+ return -EINVAL;
+
+ of_for_each_phandle(&it, err, dev->of_node, SUNXI_SRAM_PROP,
+ NULL, SUNXI_SRAM_CELLS) {
+ u32 args[SUNXI_SRAM_CELLS];
+
+ of_phandle_iterator_args(&it, args, SUNXI_SRAM_CELLS);
+
+ err = sunxi_sram_claim_one(it.node, args[0]);
+ if (err)
+ goto err;
+
+ count++;
+ }
+
+ if (count == 0)
+ return -ENOENT;
+
+ return 0;
+
+err:
+ while (count--) {
+ struct of_phandle_args args;
+
+ of_parse_phandle_with_fixed_args(dev->of_node, SUNXI_SRAM_PROP,
+ SUNXI_SRAM_CELLS, count, &args);
+ sunxi_sram_release_one(args.np, args.args[0]);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(sunxi_sram_claim);
+
+void sunxi_sram_release(struct device *dev)
+{
+ struct of_phandle_iterator it;
+ int err;
+
+ if (!dev || !dev->of_node)
+ return;
+
+ of_for_each_phandle(&it, err, dev->of_node, SUNXI_SRAM_PROP,
+ NULL, SUNXI_SRAM_CELLS) {
+ u32 args[SUNXI_SRAM_CELLS];
+
+ of_phandle_iterator_args(&it, args, SUNXI_SRAM_CELLS);
+
+ sunxi_sram_release_one(it.node, args[0]);
+ }
+}
EXPORT_SYMBOL(sunxi_sram_release);
struct sunxi_sramc_variant {
--
2.47.3
^ permalink raw reply related
* [PATCH 4/7] soc: sunxi: sram: Allow SRAM to be claimed multiple times
From: Chen-Yu Tsai @ 2026-03-24 16:43 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland
Cc: devicetree, linux-sunxi, linux-arm-kernel, linux-kernel
In-Reply-To: <20260324164357.1607247-1-wens@kernel.org>
On the H616, the SRAM C region is an alias mapping to part of the VE
SRAM (accessible in whole at a different address) and part of the DE
SRAM (otherwise unaccessible). As such both the VE and DE need to claim
this SRAM region to prevent access from the CPU.
The SRAM claim API is designed so that a "claim" routes the SRAM to the
peripheral device, disabling access from the CPU. So long as the written
register value is the same for all the claimants involved, allowing
multiple or repeated claims is trivial. This is indeed the case for all
supported SRAM regions. The only known SRAM region to have multiple
different settings is the SRAM C2 region; this can be claimed by the AE,
CE, or ACE (assumed to be AE + CE). This region is not supported, and
likely will never be needed nor supported, as there is no documentation
for the peripherals involved.
Change the SRAM region "claimed" field from a boolean to a reference
count. A claim will increment the count, while a release decreases it.
The first claim will trigger the register value write. The driver
otherwise behaves as before.
Signed-off-by: Chen-Yu Tsai <wens@kernel.org>
---
drivers/soc/sunxi/sunxi_sram.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
index 5e8c80ae3509..aba155379ccc 100644
--- a/drivers/soc/sunxi/sunxi_sram.c
+++ b/drivers/soc/sunxi/sunxi_sram.c
@@ -12,6 +12,7 @@
#include <linux/debugfs.h>
#include <linux/io.h>
+#include <linux/limits.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -38,7 +39,7 @@ struct sunxi_sram_data {
struct sunxi_sram_desc {
struct sunxi_sram_data data;
- bool claimed;
+ u8 claim_cnt;
};
#define SUNXI_SRAM_MAP(_reg_val, _val, _func) \
@@ -244,9 +245,11 @@ int sunxi_sram_claim(struct device *dev)
spin_lock(&sram_lock);
- if (sram_desc->claimed) {
+ if (sram_desc->claim_cnt) {
+ if (!WARN_ON(sram_desc->claim_cnt == U8_MAX))
+ sram_desc->claim_cnt++;
spin_unlock(&sram_lock);
- return -EBUSY;
+ return 0;
}
mask = GENMASK(sram_data->offset + sram_data->width - 1,
@@ -256,7 +259,7 @@ int sunxi_sram_claim(struct device *dev)
writel(val | ((device << sram_data->offset) & mask),
base + sram_data->reg);
- sram_desc->claimed = true;
+ sram_desc->claim_cnt++;
spin_unlock(&sram_lock);
return 0;
@@ -278,7 +281,8 @@ void sunxi_sram_release(struct device *dev)
sram_desc = to_sram_desc(sram_data);
spin_lock(&sram_lock);
- sram_desc->claimed = false;
+ if (!WARN_ON(sram_desc->claim_cnt == 0))
+ sram_desc->claim_cnt--;
spin_unlock(&sram_lock);
}
EXPORT_SYMBOL(sunxi_sram_release);
--
2.47.3
^ permalink raw reply related
* Re: [PATCH] ARM: dts: rockchip: Pass linux,code to the power key on rk3288-veyron-pinky
From: Heiko Stuebner @ 2026-03-24 16:45 UTC (permalink / raw)
To: Fabio Estevam
Cc: Heiko Stuebner, robh, krzk+dt, conor+dt, devicetree,
linux-arm-kernel, linux-rockchip, linux-kernel
In-Reply-To: <20260323125721.692139-1-festevam@gmail.com>
On Mon, 23 Mar 2026 09:57:21 -0300, Fabio Estevam wrote:
> According to gpio-keys.yaml, linux,code is a required property.
>
> Pass it to fix the following dt-schema warning:
>
> lid-switch (gpio-keys): key-power: 'linux,code' is a required property
>
>
> [...]
Applied, thanks!
[1/1] ARM: dts: rockchip: Pass linux,code to the power key on rk3288-veyron-pinky
commit: 94c8dc1fa8e1ad4037084204152bca1e799d7d1c
Best regards,
--
Heiko Stuebner <heiko@sntech.de>
^ permalink raw reply
* Re: [PATCH v7 1/4] dt-bindings: soc: rockchip: grf: Add RV1103B compatibles
From: Heiko Stuebner @ 2026-03-24 16:45 UTC (permalink / raw)
To: Fabio Estevam
Cc: Heiko Stuebner, robh, krzk+dt, conor+dt, devicetree,
linux-arm-kernel, linux-rockchip, linux-kernel, shawn.lin,
Fabio Estevam, Krzysztof Kozlowski
In-Reply-To: <20260313131058.708361-1-festevam@gmail.com>
On Fri, 13 Mar 2026 10:10:55 -0300, Fabio Estevam wrote:
> Add the PMU GRF and IOC compatible strings for the RV1103B SoC.
>
>
Applied, thanks!
[1/4] dt-bindings: soc: rockchip: grf: Add RV1103B compatibles
commit: 25c2721f18ff97226a6561aedc9f8f76a51fe2e8
[2/4] ARM: dts: rockchip: Add support for RV1103B
commit: b4dc241c68f5a2a6e312259bf23885d693f91960
[3/4] dt-bindings: arm: rockchip: Add Omega4 Evaluation board
commit: 2ea01fbb1d29d2349aa489eb884938898f10a84d
[4/4] ARM: dts: rockchip: Add Onion Omega4 Evaluation Board
commit: 683192d7d5b47e89d920867f7c6997d2c0d1a0ad
Now that the adapted mmc binding went in, this is also ready.
I've reordered some properties according to documented preference
= largely { compatible, reg, [alphabetical], status }
And dropped the watchdog node for now.
Please resubmit that one, once the watchdog compatible went
into the watchdog tree (and drop the status=disabled from
the wdt node, as the watchdog is not dependent on supplies
from the board dts)
Best regards,
--
Heiko Stuebner <heiko@sntech.de>
^ permalink raw reply
* Re: [PATCH v5 4/5] KVM: selftests: arm64: Skip all 32 bit IDs when set_id_regs is aarch64 only
From: Marc Zyngier @ 2026-03-24 16:47 UTC (permalink / raw)
To: Mark Brown
Cc: Joey Gouly, Suzuki K Poulose, Paolo Bonzini, Shuah Khan,
Oliver Upton, Ben Horgan, linux-arm-kernel, kvmarm, kvm,
linux-kselftest, linux-kernel
In-Reply-To: <20260317-kvm-arm64-set-id-regs-aarch64-v5-4-a60f2b956e22@kernel.org>
On Tue, 17 Mar 2026 20:10:37 +0000,
Mark Brown <broonie@kernel.org> wrote:
>
> On an aarch64 only system the 32 bit ID registers have UNDEFINED values.
> As a result set_id_regs skips tests for setting fields in these registers
> when testing an aarch64 only guest. This has the side effect of meaning
> that we don't record an expected value for these registers, meaning that
> when the subsequent tests for values being visible in guests and preserved
> over reset check the value they can spuriously fail. This can be seen by
> running on an emulated system with both NV and 32 bit enabled, NV will
> result in the guests created by the test program being 64 bit only but
> the 32 bit ID registers will have values.
I don't think papering over this problem is the right thing to do.
If the issue is that you have HW that has both NV and AArch32, then
KVM needs to be fixed to make the 32bit IDregs RAZ when NV is present
because that's not a configuration we support.
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* Re: [PATCH v2 net-next 09/14] net: dsa: add NETC switch tag support
From: Simon Horman @ 2026-03-24 16:54 UTC (permalink / raw)
To: wei.fang
Cc: Simon Horman, devicetree, robh, andrew, vladimir.oltean, frank.li,
pabeni, conor+dt, xiaoning.wang, davem, krzk+dt, linux-arm-kernel,
imx, kuba, edumazet, linux-kernel, linux, andrew+netdev,
f.fainelli, claudiu.manoil, netdev, chleroy, linuxppc-dev
In-Reply-To: <20260323060752.1157031-10-wei.fang@nxp.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
For local reproduction steps see https://netdev-ai.bots.linux.dev/ai-local.html
---
net: dsa: add NETC switch tag support
This commit introduces support for the NXP NETC switch tag protocol,
a proprietary header used by NETC switches. The tag supports three
types (Forward, To_Port, and To_Host) with variable length (6-14 bytes).
> diff --git a/include/linux/dsa/tag_netc.h b/include/linux/dsa/tag_netc.h
> new file mode 100644
> index 000000000000..fe964722e5b0
> --- /dev/null
> +++ b/include/linux/dsa/tag_netc.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + *
> + * Copyright 2025-2026 NXP
> + */
> +
> +#ifndef __NET_DSA_TAG_NETC_H
> +#define __NET_DSA_TAG_NETC_H
> +
> +#include <linux/skbuff.h>
> +#include <net/dsa.h>
> +
> +#define NETC_TAG_MAX_LEN 14
> +
> +#endif
[ ... ]
> diff --git a/net/dsa/tag_netc.c b/net/dsa/tag_netc.c
> new file mode 100644
> index 000000000000..15b0dd5c5408
> --- /dev/null
> +++ b/net/dsa/tag_netc.c
[ ... ]
> @@ -0,0 +1,180 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2025-2026 NXP
> + */
> +
> +#include <linux/dsa/tag_netc.h>
> +
> +#include "tag.h"
> +
> +#define NETC_NAME "nxp_netc"
> +
> +/* Forward NXP switch tag */
> +#define NETC_TAG_FORWARD 0
> +
> +/* To_Port NXP switch tag */
> +#define NETC_TAG_TO_PORT 1
> +/* SubType0: No request to perform timestamping */
> +#define NETC_TAG_TP_SUBTYPE0 0
> +
> +/* To_Host NXP switch tag */
> +#define NETC_TAG_TO_HOST 2
> +/* SubType0: frames redirected or copied to CPU port */
> +#define NETC_TAG_TH_SUBTYPE0 0
> +/* SubType1: frames redirected or copied to CPU port with timestamp */
> +#define NETC_TAG_TH_SUBTYPE1 1
> +/* SubType2: Transmit timestamp response (two-step timestamping) */
> +#define NETC_TAG_TH_SUBTYPE2 2
> +
> +/* NETC switch tag lengths */
> +#define NETC_TAG_FORWARD_LEN 6
> +#define NETC_TAG_TP_SUBTYPE0_LEN 6
> +#define NETC_TAG_TH_SUBTYPE0_LEN 6
> +#define NETC_TAG_TH_SUBTYPE1_LEN 14
> +#define NETC_TAG_TH_SUBTYPE2_LEN 14
> +#define NETC_TAG_CMN_LEN 5
> +
> +#define NETC_TAG_SUBTYPE GENMASK(3, 0)
> +#define NETC_TAG_TYPE GENMASK(7, 4)
> +#define NETC_TAG_QV BIT(0)
> +#define NETC_TAG_IPV GENMASK(4, 2)
> +#define NETC_TAG_SWITCH GENMASK(2, 0)
> +#define NETC_TAG_PORT GENMASK(7, 3)
> +
> +struct netc_tag_cmn {
> + __be16 tpid;
> + u8 type;
> + u8 qos;
> + u8 switch_port;
> +} __packed;
[ ... ]
> +static int netc_get_rx_tag_len(int rx_type)
> +{
> + int type = FIELD_GET(NETC_TAG_TYPE, rx_type);
> +
> + if (type == NETC_TAG_TO_HOST) {
> + u8 subtype = rx_type & NETC_TAG_SUBTYPE;
> +
> + if (subtype == NETC_TAG_TH_SUBTYPE1)
> + return NETC_TAG_TH_SUBTYPE1_LEN;
> + else if (subtype == NETC_TAG_TH_SUBTYPE2)
> + return NETC_TAG_TH_SUBTYPE2_LEN;
> + else
> + return NETC_TAG_TH_SUBTYPE0_LEN;
> + }
> +
> + return NETC_TAG_FORWARD_LEN;
> +}
> +
> +static struct sk_buff *netc_rcv(struct sk_buff *skb,
> + struct net_device *ndev)
> +{
> + struct netc_tag_cmn *tag_cmn = dsa_etype_header_pos_rx(skb);
> + int tag_len = netc_get_rx_tag_len(tag_cmn->type);
^^^^^^^^^^^^
Is the tag header guaranteed to be in the linear region of the skb?
Looking at other EtherType-based DSA tag drivers (tag_ar9331, tag_lan9303,
tag_dsa, tag_edsa, tag_a5psw, tag_brcm_legacy, tag_mxl-gsw1xx,
tag_gswip, and tag_mtk), they all call pskb_may_pull() before accessing
tag data to ensure the header is linearized.
For example, tag_ar9331.c:
static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
struct net_device *ndev)
{
if (unlikely(!pskb_may_pull(skb, AR9331_HDR_LEN)))
return NULL;
...
}
Similarly, tag_lan9303.c:
static struct sk_buff *lan9303_rcv(struct sk_buff *skb,
struct net_device *ndev)
{
if (unlikely(!pskb_may_pull(skb, LAN9303_TAG_LEN)))
return NULL;
...
}
Without this check, netc_rcv() accesses tag_cmn->type, tag_cmn->tpid,
tag_cmn->qos, and tag_cmn->switch_port before verifying these bytes are
linearized. The struct netc_tag_cmn is 5 bytes, with 3 bytes at
skb->data through skb->data+2 that may not be guaranteed to be in the
linear region.
Additionally, netc_get_rx_tag_len() can return up to 14 bytes
(NETC_TAG_TH_SUBTYPE1_LEN or NETC_TAG_TH_SUBTYPE2_LEN), and this value
is passed directly to skb_pull_rcsum():
> + int tag_len = netc_get_rx_tag_len(tag_cmn->type);
> + int sw_id, port;
> +
> + if (ntohs(tag_cmn->tpid) != ETH_P_NXP_NETC) {
> + dev_warn_ratelimited(&ndev->dev, "Unknown TPID 0x%04x\n",
> + ntohs(tag_cmn->tpid));
> +
> + return NULL;
> + }
> +
> + if (tag_cmn->qos & NETC_TAG_QV)
> + skb->priority = FIELD_GET(NETC_TAG_IPV, tag_cmn->qos);
> +
> + sw_id = NETC_TAG_SWITCH & tag_cmn->switch_port;
> + /* ENETC VEPA switch ID (0) is not supported yet */
> + if (!sw_id) {
> + dev_warn_ratelimited(&ndev->dev,
> + "VEPA switch ID is not supported yet\n");
> +
> + return NULL;
> + }
> +
> + port = FIELD_GET(NETC_TAG_PORT, tag_cmn->switch_port);
> + skb->dev = dsa_conduit_find_user(ndev, sw_id, port);
> + if (!skb->dev)
> + return NULL;
> +
> + if (tag_cmn->type == NETC_TAG_FORWARD)
> + dsa_default_offload_fwd_mark(skb);
> +
> + /* Remove Switch tag from the frame */
> + skb_pull_rcsum(skb, tag_len);
^^^^^^^^^^^^^^^^^^
The skb_pull_rcsum() function contains BUG_ON(len > skb->len). If a
truncated or malformed packet arrives with fewer than tag_len bytes
remaining, the kernel will panic rather than gracefully handling the
error.
Should a check like this be added at the beginning of netc_rcv():
if (unlikely(!pskb_may_pull(skb, NETC_TAG_MAX_LEN - 2)))
return NULL;
The -2 would account for the EtherType bytes already consumed by
eth_type_trans().
> + dsa_strip_etype_header(skb, tag_len);
> +
> + return skb;
> +}
[ ... ]
^ permalink raw reply
* [PATCH net-next] net: airoha: Grab flow_offload_mutex running airoha_register_gdm_devices()
From: Lorenzo Bianconi @ 2026-03-24 16:54 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: linux-arm-kernel, linux-mediatek, netdev, Lorenzo Bianconi
Netfilter flowtable can theoretically try offload flower rules as soon
as a net-device is registered while not all the other ones are
registered/initialized, triggering a possible NULL pointer dereferencing
of qdma pointer in airoha_ppe_set_cpu_port routine. In order to avoid any
possible race, grab the flow_offload_mutex running
airoha_register_gdm_devices().
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 15 +++++++++++----
drivers/net/ethernet/airoha/airoha_eth.h | 2 ++
drivers/net/ethernet/airoha/airoha_ppe.c | 2 +-
3 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 82e53c60f561f6314fbf201ba8bc8711e40edc68..c1476032f78cbac95c9813bbeae6bec2c9c0a685 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2943,21 +2943,28 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth,
static int airoha_register_gdm_devices(struct airoha_eth *eth)
{
- int i;
+ int i, err = 0;
+
+ /* Netfilter flowtable can try offload flower rules while not all
+ * the net-devices are registered/initialized. Grab flow_offload_mutex
+ * to avoid any possible race.
+ */
+ mutex_lock(&flow_offload_mutex);
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
- int err;
if (!port)
continue;
err = register_netdev(port->dev);
if (err)
- return err;
+ break;
}
- return 0;
+ mutex_unlock(&flow_offload_mutex);
+
+ return err;
}
static int airoha_probe(struct platform_device *pdev)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
index 7df4dbcd8861856c54c2a38bc89c69180ac2f6dc..9d97a54dbfdf9107a10bdb09cf144e5cf1ac9bdb 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -548,6 +548,8 @@ struct airoha_gdm_port {
struct metadata_dst *dsa_meta[AIROHA_MAX_DSA_PORTS];
};
+extern struct mutex flow_offload_mutex;
+
#define AIROHA_RXD4_PPE_CPU_REASON GENMASK(20, 16)
#define AIROHA_RXD4_FOE_ENTRY GENMASK(15, 0)
diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index 7666b1d2f4f6ea758683181ab90d6fffb7bcd19d..96d092f7214ee3e80843a14528df66cabf79bc58 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -15,7 +15,7 @@
#include "airoha_regs.h"
#include "airoha_eth.h"
-static DEFINE_MUTEX(flow_offload_mutex);
+DEFINE_MUTEX(flow_offload_mutex);
static DEFINE_SPINLOCK(ppe_lock);
static const struct rhashtable_params airoha_flow_table_params = {
---
base-commit: b1c803d5c8167026791abfaed96fd3e6a1fcd750
change-id: 20260321-airoha-regiser-race-fix-fe854f61d760
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply related
* Re: [PATCH v10 0/4] arm64: dts: add description for solidrun imx8mp hummingboard-iiot
From: Frank Li @ 2026-03-24 16:55 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Josua Mayer
Cc: Frank Li, Mikhail Anikin, Yazan Shhady, devicetree, linux-kernel,
imx, linux-arm-kernel
In-Reply-To: <20260313-imx8mp-hb-iiot-v10-0-52b3084f2426@solid-run.com>
On Fri, 13 Mar 2026 14:30:56 +0200, Josua Mayer wrote:
> This patchset mainly adds description for 3 SolidRun boards:
> - i.MX8MP Hummingboard IIoT
> - SolidSense N8 Compact
> - i.MX8MM Hummingboard Ripple
>
> This includes dt bindings and a range of bug-fixes:
>
> [...]
Applied, thanks!
[1/4] arm64: dts: add description for SolidRun i.MX8MP HummingBoard IIoT
(no commit info)
Change "description" to "support". Add freesacle tag in subject
[2/4] arm64: dts: imx8mp-hummingboard-iiot: add dt overlays for muxable ports
commit: a26dd6546e2a05c3504072c96129a0932f9aa532
[3/4] arm64: dts: add description for solidrun solidsense-n8 board
(no commit info)
Change "description" to "support". Add freesacle tag in subject
[4/4] arm64: dts: add description for solidrun i.mx8mm som and evb
(no commit info)
Change "description" to "support". Add imx tag in subject
Best regards,
--
Frank Li <Frank.Li@nxp.com>
^ permalink raw reply
* [PATCH 00/10] PCI: Improve head free space usage
From: Ilpo Järvinen @ 2026-03-24 16:56 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Guenter Roeck, linux-alpha,
linux-arm-kernel, linux-m68k, linux-mips, linux-parisc,
linuxppc-dev, linux-s390, linux-sh, Russell King,
Geert Uytterhoeven, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, H. Peter Anvin, Chris Zankel,
Max Filippov, Madhavan Srinivasan, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz
Cc: linux-kernel, Ilpo Järvinen
Hi all,
This series attempts to take advantage of free head space (the free
space before the aligned start address) in order to generally produce a
tighter packing of the resources/bridge windows.
The recent changes to the resource fitting algorithm caused resource
allocation failures in some cases where a bridge window that is sized
to be gapless could no longer be assigned. The previous algorithm left
a huge gaps which allowed it to place the remainder (non-aligning part
of the size) before the start address of used for the gapless fit,
whereas the new gapless approach always had to place the remainder
after the aligning part of the resources. There is not always space
for the remainder triggering those failures (e.g., when the aligning
part must be placed at the top of the window).
This series attempts to allow placing the remainder once again before
the aligning part, but now without leaving huge gaps to retain the
benefits of the gapless bridge windows. The approach is somewhat hacky
but should work thanks to PCI resources fundamentally consisting only
power-of-two atoms.
There maybe cases where architecture would not want to do such
relocation. This series adds the relocation to arch
pcibios_align_resource() functions to allow all of them taking
advantage of the better resource packing but if somebody objects doing
this relocation for a particular arch, I can remove it, please just let
me know (this relocation doesn't seem critical unless there are
regressions).
Ilpo Järvinen (10):
resource: Add __resource_contains_unbound() for internal contains
checks
resource: Pass full extent of empty space to resource_alignf CB
resource: Rename 'tmp' variable to 'full_avail'
ARM/PCI: Remove unnecessary second application of align
am68k/PCI: Remove unnecessary second application of align
MIPS: PCI: Remove unnecessary second application of align
parisc/PCI: Cleanup align handling
PCI: Rename window_alignment() to pci_min_window_alignment()
PCI: Align head space better
PCI: Fix alignment calculation for resource size larger than align
arch/alpha/kernel/pci.c | 1 +
arch/arm/kernel/bios32.c | 9 ++++---
arch/m68k/kernel/pcibios.c | 8 +++++--
arch/mips/pci/pci-generic.c | 8 ++++---
arch/mips/pci/pci-legacy.c | 3 +++
arch/parisc/kernel/pci.c | 17 ++++++++------
arch/powerpc/kernel/pci-common.c | 6 ++++-
arch/s390/pci/pci.c | 1 +
arch/sh/drivers/pci/pci.c | 6 ++++-
arch/x86/pci/i386.c | 5 +++-
arch/xtensa/kernel/pci.c | 3 +++
drivers/pci/pci.h | 3 +++
drivers/pci/setup-bus.c | 15 ++++++++----
drivers/pci/setup-res.c | 40 +++++++++++++++++++++++++++++++-
drivers/pcmcia/rsrc_nonstatic.c | 3 ++-
include/linux/ioport.h | 22 +++++++++++++++---
include/linux/pci.h | 12 +++++++---
kernel/resource.c | 33 +++++++++++++-------------
18 files changed, 149 insertions(+), 46 deletions(-)
base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
--
2.39.5
^ permalink raw reply
* Re: [PATCH v2 net-next 08/14] net: enetc: add multiple command BD rings support
From: Simon Horman @ 2026-03-24 16:58 UTC (permalink / raw)
To: wei.fang
Cc: Simon Horman, frank.li, devicetree, andrew+netdev, conor+dt,
vladimir.oltean, linux-arm-kernel, kuba, claudiu.manoil, andrew,
krzk+dt, linux, edumazet, linux-kernel, pabeni, f.fainelli, imx,
chleroy, netdev, robh, linuxppc-dev, xiaoning.wang, davem
In-Reply-To: <20260323060752.1157031-9-wei.fang@nxp.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
For local reproduction steps see https://netdev-ai.bots.linux.dev/ai-local.html
---
net: enetc: add multiple command BD rings support
This patch adds support for multiple command BD rings to the NTMP driver.
The switch has two command BD rings, and netc_select_cbdr() is added to
select an appropriate ring when the current one is busy.
> diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c b/drivers/net/ethernet/freescale/enetc/ntmp.c
> --- a/drivers/net/ethernet/freescale/enetc/ntmp.c
> +++ b/drivers/net/ethernet/freescale/enetc/ntmp.c
> @@ -117,6 +117,25 @@ static void ntmp_clean_cbdr(struct netc_cbdr *cbdr)
> cbdr->next_to_clean = i;
> }
>
> +static struct netc_cbdr *netc_select_cbdr(struct ntmp_user *user)
> +{
> + int cpu, i;
> +
> + for (i = 0; i < user->cbdr_num; i++) {
> + if (spin_is_locked(&user->ring[i].ring_lock))
> + continue;
> +
> + return &user->ring[i];
> + }
Frank Li raised a concern about the use of spin_is_locked() here. Is this
lockless check reliable across all architectures? spin_is_locked() behavior
varies across configurations - it can return false negatives on UP builds and
may not provide the ordering guarantees needed for lockless checks.
Would spin_trylock() be more appropriate here? Or if this racy check is
intentional and acceptable, should it be documented why the potential race is
safe in this context?
> +
> + /* If all the command BDRs are busy now, we select
> + * one of them, but need to wait for a while to use.
> + */
> + cpu = raw_smp_processor_id();
> +
> + return &user->ring[cpu % user->cbdr_num];
> +}
> +
> static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
> {
> union netc_cbd *cur_cbd;
> @@ -125,10 +144,10 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
> u16 status;
> u32 val;
>
> - /* Currently only i.MX95 ENETC is supported, and it only has one
> - * command BD ring
> - */
> - cbdr = &user->ring[0];
> + if (user->cbdr_num == 1)
> + cbdr = &user->ring[0];
> + else
> + cbdr = netc_select_cbdr(user);
This isn't a bug, but Frank Li suggested that the special case for
cbdr_num == 1 might be redundant. Since netc_select_cbdr() would handle the
single ring case correctly (the loop would find the only ring on the first
iteration), would it be simpler to just unconditionally call:
cbdr = netc_select_cbdr(user);
>
> spin_lock_bh(&cbdr->ring_lock);
>
^ permalink raw reply
* [PATCH 01/10] resource: Add __resource_contains_unbound() for internal contains checks
From: Ilpo Järvinen @ 2026-03-24 16:56 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Guenter Roeck, linux-alpha,
linux-arm-kernel, linux-m68k, linux-mips, linux-parisc,
linuxppc-dev, linux-s390, linux-sh, Russell King,
Geert Uytterhoeven, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, H. Peter Anvin, Chris Zankel,
Max Filippov, Madhavan Srinivasan, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, linux-kernel
Cc: Ilpo Järvinen
In-Reply-To: <20260324165633.4583-1-ilpo.jarvinen@linux.intel.com>
__find_resource_space() currently uses resource_contains() but for
tentative resources that are not yet crafted into the resource tree. As
resource_contains() checks that IORESOURCE_UNSET is not set for either
of the resources, the caller has to hack around this problem by
clearing the IORESOURCE_UNSET flag (essentially lying to
resource_contains()).
Instead of the hack, introduce __resource_contains_unbound() for cases
like this.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
include/linux/ioport.h | 20 +++++++++++++++++---
kernel/resource.c | 4 ++--
2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 5533a5debf3f..19d5e04564d9 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -304,14 +304,28 @@ static inline unsigned long resource_ext_type(const struct resource *res)
{
return res->flags & IORESOURCE_EXT_TYPE_BITS;
}
-/* True iff r1 completely contains r2 */
-static inline bool resource_contains(const struct resource *r1, const struct resource *r2)
+
+/*
+ * For checking if @r1 completely contains @r2 for resources that have real
+ * addresses but are not yet crafted into the resource tree. Normally
+ * resource_contains() should be used instead of this function as it checks
+ * also IORESOURCE_UNSET flag.
+ */
+static inline bool __resource_contains_unbound(const struct resource *r1,
+ const struct resource *r2)
{
if (resource_type(r1) != resource_type(r2))
return false;
+
+ return r1->start <= r2->start && r1->end >= r2->end;
+}
+/* True iff r1 completely contains r2 */
+static inline bool resource_contains(const struct resource *r1, const struct resource *r2)
+{
if (r1->flags & IORESOURCE_UNSET || r2->flags & IORESOURCE_UNSET)
return false;
- return r1->start <= r2->start && r1->end >= r2->end;
+
+ return __resource_contains_unbound(r1, r2);
}
/* True if any part of r1 overlaps r2 */
diff --git a/kernel/resource.c b/kernel/resource.c
index bb966699da31..1e2f1dfc0edd 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -754,7 +754,7 @@ static int __find_resource_space(struct resource *root, struct resource *old,
/* Check for overflow after ALIGN() */
avail.start = ALIGN(tmp.start, constraint->align);
avail.end = tmp.end;
- avail.flags = new->flags & ~IORESOURCE_UNSET;
+ avail.flags = new->flags;
if (avail.start >= tmp.start) {
alloc.flags = avail.flags;
if (alignf) {
@@ -765,7 +765,7 @@ static int __find_resource_space(struct resource *root, struct resource *old,
}
alloc.end = alloc.start + size - 1;
if (alloc.start <= alloc.end &&
- resource_contains(&avail, &alloc)) {
+ __resource_contains_unbound(&avail, &alloc)) {
new->start = alloc.start;
new->end = alloc.end;
return 0;
--
2.39.5
^ permalink raw reply related
* [PATCH 02/10] resource: Pass full extent of empty space to resource_alignf CB
From: Ilpo Järvinen @ 2026-03-24 16:56 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Guenter Roeck, linux-alpha,
linux-arm-kernel, linux-m68k, linux-mips, linux-parisc,
linuxppc-dev, linux-s390, linux-sh, Russell King,
Geert Uytterhoeven, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, H. Peter Anvin, Chris Zankel,
Max Filippov, Madhavan Srinivasan, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, Richard Henderson, Matt Turner,
Magnus Lindholm, Nicholas Piggin, Christophe Leroy (CS GROUP),
Niklas Schnelle, Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Christian Borntraeger, Sven Schnelle, x86,
Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
In-Reply-To: <20260324165633.4583-1-ilpo.jarvinen@linux.intel.com>
__find_resource_space() calculates the full extent of empty space but
only passes the aligned space to resource_alignf callback. In some
situations, the callback may choose take advantage of the free space
before the requested alignment.
Pass the full extent of the calculated empty space to resource_alignf
callback as an additional parameter.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
arch/alpha/kernel/pci.c | 1 +
arch/arm/kernel/bios32.c | 4 +++-
arch/m68k/kernel/pcibios.c | 4 +++-
arch/mips/pci/pci-generic.c | 3 ++-
arch/mips/pci/pci-legacy.c | 1 +
arch/parisc/kernel/pci.c | 4 +++-
arch/powerpc/kernel/pci-common.c | 4 +++-
arch/s390/pci/pci.c | 1 +
arch/sh/drivers/pci/pci.c | 4 +++-
arch/x86/pci/i386.c | 3 ++-
arch/xtensa/kernel/pci.c | 1 +
drivers/pci/setup-res.c | 3 ++-
drivers/pcmcia/rsrc_nonstatic.c | 3 ++-
include/linux/ioport.h | 2 ++
include/linux/pci.h | 7 ++++---
kernel/resource.c | 3 ++-
16 files changed, 35 insertions(+), 13 deletions(-)
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 51a8a4c4572a..11df411b1d18 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -125,6 +125,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_final);
resource_size_t
pcibios_align_resource(void *data, const struct resource *res,
+ const struct resource *empty_res,
resource_size_t size, resource_size_t align)
{
struct pci_dev *dev = data;
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index b5793e8fbdc1..5b9b4fcd0e54 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -560,7 +560,9 @@ char * __init pcibios_setup(char *str)
* which might be mirrored at 0x0100-0x03ff..
*/
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
+ const struct resource *empty_res,
+ resource_size_t size,
+ resource_size_t align)
{
struct pci_dev *dev = data;
resource_size_t start = res->start;
diff --git a/arch/m68k/kernel/pcibios.c b/arch/m68k/kernel/pcibios.c
index e6ab3f9ff5d8..1415f6e4e5ce 100644
--- a/arch/m68k/kernel/pcibios.c
+++ b/arch/m68k/kernel/pcibios.c
@@ -27,7 +27,9 @@
* which might be mirrored at 0x0100-0x03ff..
*/
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
+ const struct resource *empty_res,
+ resource_size_t size,
+ resource_size_t align)
{
resource_size_t start = res->start;
diff --git a/arch/mips/pci/pci-generic.c b/arch/mips/pci/pci-generic.c
index d2d68bac3d25..f4957c26efc7 100644
--- a/arch/mips/pci/pci-generic.c
+++ b/arch/mips/pci/pci-generic.c
@@ -22,7 +22,8 @@
* which might have be mirrored at 0x0100-0x03ff..
*/
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
+ const struct resource *empty_res,
+ resource_size_t size, resource_size_t align)
{
struct pci_dev *dev = data;
resource_size_t start = res->start;
diff --git a/arch/mips/pci/pci-legacy.c b/arch/mips/pci/pci-legacy.c
index d04b7c1294b6..817e97402afe 100644
--- a/arch/mips/pci/pci-legacy.c
+++ b/arch/mips/pci/pci-legacy.c
@@ -52,6 +52,7 @@ unsigned long pci_address_to_pio(phys_addr_t address)
*/
resource_size_t
pcibios_align_resource(void *data, const struct resource *res,
+ const struct resource *empty_res,
resource_size_t size, resource_size_t align)
{
struct pci_dev *dev = data;
diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
index cf285b17a5ae..f99b20795d5a 100644
--- a/arch/parisc/kernel/pci.c
+++ b/arch/parisc/kernel/pci.c
@@ -196,7 +196,9 @@ void __ref pcibios_init_bridge(struct pci_dev *dev)
* than res->start.
*/
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t alignment)
+ const struct resource *empty_res,
+ resource_size_t size,
+ resource_size_t alignment)
{
resource_size_t mask, align, start = res->start;
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index a7a2fb605971..e7bfa15da043 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1132,7 +1132,9 @@ static int skip_isa_ioresource_align(struct pci_dev *dev)
* which might have be mirrored at 0x0100-0x03ff..
*/
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
+ const struct resource *empty_res,
+ resource_size_t size,
+ resource_size_t align)
{
struct pci_dev *dev = data;
resource_size_t start = res->start;
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 2a430722cbe4..39bd2adfc240 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -266,6 +266,7 @@ static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len)
}
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+ const struct resource *empty_res,
resource_size_t size,
resource_size_t align)
{
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index a3903304f33f..7a0522316ee3 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -168,7 +168,9 @@ subsys_initcall(pcibios_init);
* modulo 0x400.
*/
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
+ const struct resource *empty_res,
+ resource_size_t size,
+ resource_size_t align)
{
struct pci_dev *dev = data;
struct pci_channel *hose = dev->sysdata;
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index c4ec39ad276b..6fbd4b34c3f7 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -153,7 +153,8 @@ skip_isa_ioresource_align(struct pci_dev *dev) {
*/
resource_size_t
pcibios_align_resource(void *data, const struct resource *res,
- resource_size_t size, resource_size_t align)
+ const struct resource *empty_res,
+ resource_size_t size, resource_size_t align)
{
struct pci_dev *dev = data;
resource_size_t start = res->start;
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 62c900e400d6..64ccb7e0d92f 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -39,6 +39,7 @@
*/
resource_size_t
pcibios_align_resource(void *data, const struct resource *res,
+ const struct resource *empty_res,
resource_size_t size, resource_size_t align)
{
struct pci_dev *dev = data;
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index bb2aef373d6f..c375e255c509 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -251,10 +251,11 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
*/
resource_size_t __weak pcibios_align_resource(void *data,
const struct resource *res,
+ const struct resource *empty_res,
resource_size_t size,
resource_size_t align)
{
- return res->start;
+ return res->start;
}
static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 0679dd434719..949e69921fe9 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -602,7 +602,8 @@ static resource_size_t pcmcia_common_align(struct pcmcia_align_data *align_data,
static resource_size_t
pcmcia_align(void *align_data, const struct resource *res,
- resource_size_t size, resource_size_t align)
+ const struct resource *empty_res,
+ resource_size_t size, resource_size_t align)
{
struct pcmcia_align_data *data = align_data;
struct resource_map *m;
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 19d5e04564d9..3c73c9c0d4f7 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -202,6 +202,7 @@ enum {
* typedef resource_alignf - Resource alignment callback
* @data: Private data used by the callback
* @res: Resource candidate range (an empty resource space)
+ * @empty_res: Empty resource range without alignment applied
* @size: The minimum size of the empty space
* @align: Alignment from the constraints
*
@@ -212,6 +213,7 @@ enum {
*/
typedef resource_size_t (*resource_alignf)(void *data,
const struct resource *res,
+ const struct resource *empty_res,
resource_size_t size,
resource_size_t align);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1c270f1d5123..ac332ff9da9f 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1206,9 +1206,10 @@ int __must_check pcibios_enable_device(struct pci_dev *, int mask);
char *pcibios_setup(char *str);
/* Used only when drivers/pci/setup.c is used */
-resource_size_t pcibios_align_resource(void *, const struct resource *,
- resource_size_t,
- resource_size_t);
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+ const struct resource *empty_res,
+ resource_size_t size,
+ resource_size_t align);
/* Generic PCI functions used internally */
diff --git a/kernel/resource.c b/kernel/resource.c
index 1e2f1dfc0edd..1b8d3101bdc6 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -759,7 +759,8 @@ static int __find_resource_space(struct resource *root, struct resource *old,
alloc.flags = avail.flags;
if (alignf) {
alloc.start = alignf(constraint->alignf_data,
- &avail, size, constraint->align);
+ &avail, &tmp,
+ size, constraint->align);
} else {
alloc.start = avail.start;
}
--
2.39.5
^ permalink raw reply related
* [PATCH 03/10] resource: Rename 'tmp' variable to 'full_avail'
From: Ilpo Järvinen @ 2026-03-24 16:56 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Guenter Roeck, linux-alpha,
linux-arm-kernel, linux-m68k, linux-mips, linux-parisc,
linuxppc-dev, linux-s390, linux-sh, Russell King,
Geert Uytterhoeven, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, H. Peter Anvin, Chris Zankel,
Max Filippov, Madhavan Srinivasan, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, linux-kernel
Cc: Ilpo Järvinen
In-Reply-To: <20260324165633.4583-1-ilpo.jarvinen@linux.intel.com>
__find_resource_space() has variable called 'tmp'. Rename it to
'full_avail' to better indicate its purpose.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
kernel/resource.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/kernel/resource.c b/kernel/resource.c
index 1b8d3101bdc6..8c5fcb30fc33 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -727,39 +727,39 @@ static int __find_resource_space(struct resource *root, struct resource *old,
struct resource_constraint *constraint)
{
struct resource *this = root->child;
- struct resource tmp = *new, avail, alloc;
+ struct resource full_avail = *new, avail, alloc;
resource_alignf alignf = constraint->alignf;
- tmp.start = root->start;
+ full_avail.start = root->start;
/*
* Skip past an allocated resource that starts at 0, since the assignment
- * of this->start - 1 to tmp->end below would cause an underflow.
+ * of this->start - 1 to full_avail->end below would cause an underflow.
*/
if (this && this->start == root->start) {
- tmp.start = (this == old) ? old->start : this->end + 1;
+ full_avail.start = (this == old) ? old->start : this->end + 1;
this = this->sibling;
}
for(;;) {
if (this)
- tmp.end = (this == old) ? this->end : this->start - 1;
+ full_avail.end = (this == old) ? this->end : this->start - 1;
else
- tmp.end = root->end;
+ full_avail.end = root->end;
- if (tmp.end < tmp.start)
+ if (full_avail.end < full_avail.start)
goto next;
- resource_clip(&tmp, constraint->min, constraint->max);
- arch_remove_reservations(&tmp);
+ resource_clip(&full_avail, constraint->min, constraint->max);
+ arch_remove_reservations(&full_avail);
/* Check for overflow after ALIGN() */
- avail.start = ALIGN(tmp.start, constraint->align);
- avail.end = tmp.end;
+ avail.start = ALIGN(full_avail.start, constraint->align);
+ avail.end = full_avail.end;
avail.flags = new->flags;
- if (avail.start >= tmp.start) {
+ if (avail.start >= full_avail.start) {
alloc.flags = avail.flags;
if (alignf) {
alloc.start = alignf(constraint->alignf_data,
- &avail, &tmp,
+ &avail, &full_avail,
size, constraint->align);
} else {
alloc.start = avail.start;
@@ -777,7 +777,7 @@ next: if (!this || this->end == root->end)
break;
if (this != old)
- tmp.start = this->end + 1;
+ full_avail.start = this->end + 1;
this = this->sibling;
}
return -EBUSY;
--
2.39.5
^ permalink raw reply related
* [PATCH 04/10] ARM/PCI: Remove unnecessary second application of align
From: Ilpo Järvinen @ 2026-03-24 16:56 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Guenter Roeck, linux-alpha,
linux-arm-kernel, linux-m68k, linux-mips, linux-parisc,
linuxppc-dev, linux-s390, linux-sh, Russell King,
Geert Uytterhoeven, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, H. Peter Anvin, Chris Zankel,
Max Filippov, Madhavan Srinivasan, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, linux-kernel
Cc: Ilpo Järvinen
In-Reply-To: <20260324165633.4583-1-ilpo.jarvinen@linux.intel.com>
Aligning res->start by align inside pcibios_align_resource() is
unnecessary because caller of pcibios_align_resource() is
__find_resource_space() that aligns res->start with align before
calling pcibios_align_resource().
Aligning by align in case of IORESOURCE_IO && start & 0x300 cannot ever
result in changing start either because 0x300 bits would have not
survived the earlier alignment if align was large enough to have an
impact.
Thus, remove the duplicated aligning from pcibios_align_resource().
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
arch/arm/kernel/bios32.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 5b9b4fcd0e54..cedb83a85dd9 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -571,8 +571,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
if (res->flags & IORESOURCE_IO && start & 0x300)
start = (start + 0x3ff) & ~0x3ff;
- start = (start + align - 1) & ~(align - 1);
-
host_bridge = pci_find_host_bridge(dev->bus);
if (host_bridge->align_resource)
--
2.39.5
^ permalink raw reply related
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