* Re: [PATCH 00/12] misc/syncobj: add /dev/syncobj device
From: Xaver Hugl @ 2026-05-19 17:08 UTC (permalink / raw)
To: Christian König
Cc: Julian Orth, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Sumit Semwal, Jonathan Corbet,
Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman, dri-devel,
linux-kernel, linux-media, linaro-mm-sig, linux-doc,
wayland-devel, Michel Dänzer
In-Reply-To: <dff60378-4e47-4753-8878-feec6e1c2690@amd.com>
> > The part where we get this independent of attached hardware is quite
> > important for us though, since we can't just ignore explicit sync once
> > the device we previously imported the syncobj into is disconnected.
>
> Can you elaborate more on this?
In Wayland, the client is allowed to attach dmabuf and syncobj
independently, they don't have to be from the same device (and the
compositor wouldn't be able to verify the opposite anyways). The
compositor will usually import both into the same drm device, but
especially with compositors that render on multiple devices, that's
not necessarily the case either.
If for example we had a system with one internal GPU and one external
GPU, the client renders on the internal GPU and the compositor uses
the external one. Now when the user yanks the USB C cable, afaiu
- the buffers from the client stay valid
- the syncobj stays valid on the client side
- the syncobj becomes invalid on the compositor side
"invalid" there means either
- the acquire point of the client is marked as signaled, before
rendering on the client side is completed
- the acquire point of the client is never signaled. Since the
compositor waits for the acquire point, the Wayland surface is stuck
forever
Afaik the latter is currently the case. The former wouldn't be much
better though, not when it's preventable.
This is admittedly an edge case, but GPU hotunplug is something we try
to support as well as possible in Plasma, and all the edge cases cause
a lot of problems in combination and are a lot of headaches to handle
(or really work around) in the compositor.
Another edge case is when the client asks the compositor to import the
syncobj, which can fail when a hotunplug is in process, and ends up
disconnecting the client for no fault of either client or compositor.
> >>> 3. It removes the need to translate between syncobjs fds and handles.
> >>
> >> That's a pretty big no-go as well. The differentiation between FDs and handles is completely intentional.
> > Could you expand on why it's needed? For compositors, the handle is
> > just an intermediary thing when translating between file descriptors.
>
> Well what we could do is to add an IOCTL to directly attach an syncobj file descriptor to an eventfd.
That would be nice.
- Xaver
^ permalink raw reply
* Re: [PATCH 4/8] drm/panthor: Add support for protected memory allocation in panthor
From: Chia-I Wu @ 2026-05-19 17:07 UTC (permalink / raw)
To: Ketil Johnsen
Cc: Boris Brezillon, Liviu Dudau, Marcin Ślusarz, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Jonathan Corbet, Shuah Khan, Sumit Semwal,
Benjamin Gaignard, Brian Starkey, John Stultz, T.J. Mercier,
Christian König, Steven Price, Daniel Almeida, Alice Ryhl,
Matthias Brugger, AngeloGioacchino Del Regno, dri-devel,
linux-doc, linux-kernel, linux-media, linaro-mm-sig,
linux-arm-kernel, linux-mediatek, Florent Tomasin, nd
In-Reply-To: <8f0b1750-a853-4895-9672-73a75f6dbd84@arm.com>
On Tue, May 19, 2026 at 1:49 AM Ketil Johnsen <ketil.johnsen@arm.com> wrote:
>
> On 19/05/2026 09:39, Boris Brezillon wrote:
> > On Mon, 18 May 2026 17:36:40 -0700
> > Chia-I Wu <olvaffe@gmail.com> wrote:
> >
> >> On Mon, May 18, 2026 at 12:16 AM Boris Brezillon
> >> <boris.brezillon@collabora.com> wrote:
> >>>
> >>> On Wed, 13 May 2026 12:31:32 -0700
> >>> Chia-I Wu <olvaffe@gmail.com> wrote:
> >>>
> >>>> On Tue, May 12, 2026 at 8:39 AM Liviu Dudau <liviu.dudau@arm.com> wrote:
> >>>>>
> >>>>> On Tue, May 12, 2026 at 04:11:11PM +0200, Boris Brezillon wrote:
> >>>>>> On Tue, 12 May 2026 14:47:27 +0100
> >>>>>> Liviu Dudau <liviu.dudau@arm.com> wrote:
> >>>>>>
> >>>>>>> On Thu, May 07, 2026 at 01:53:56PM +0200, Boris Brezillon wrote:
> >>>>>>>> On Thu, 7 May 2026 11:02:26 +0200
> >>>>>>>> Marcin Ślusarz <marcin.slusarz@arm.com> wrote:
> >>>>>>>>
> >>>>>>>>> On Tue, May 05, 2026 at 06:15:23PM +0200, Boris Brezillon wrote:
> >>>>>>>>>>> @@ -277,9 +286,21 @@ int panthor_device_init(struct panthor_device *ptdev)
> >>>>>>>>>>> return ret;
> >>>>>>>>>>> }
> >>>>>>>>>>>
> >>>>>>>>>>> + /* If a protected heap name is specified but not found, defer the probe until created */
> >>>>>>>>>>> + if (protected_heap_name && strlen(protected_heap_name)) {
> >>>>>>>>>>
> >>>>>>>>>> Do we really need this strlen() > 0? Won't dma_heap_find() fail is the
> >>>>>>>>>> name is "" already?
> >>>>>>>>>
> >>>>>>>>> If dma_heap_find() will fail, then the whole probe with fail too.
> >>>>>>>>> This check prevents that.
> >>>>>>>>
> >>>>>>>> Yeah, that's also a questionable design choice. I mean, we can
> >>>>>>>> currently probe and boot the FW even though we never setup the
> >>>>>>>> protected FW sections, so why should we defer the probe here? Can't we
> >>>>>>>> just retry the next time a group with the protected bit is created and
> >>>>>>>> fail if we can find a protected heap?
> >>>>>>>
> >>>>>>> The problem we have with the current firmware is that it does a number of setup steps at "boot"
> >>>>>>> time only. One of the steps is preparing its internal structures for when it enters protected
> >>>>>>> mode and it stores them in the buffer passed in at firmware loading. We cannot later run the
> >>>>>>> process when we have a group with protected mode set.
> >>>>>>
> >>>>>> No, but we can force a full/slow reset and have that thing
> >>>>>> re-initialized, can't we? I mean, that's basically what we do when a
> >>>>>> fast reset fails: we re-initialize all the sections and reset again, at
> >>>>>> which point the FW should start from a fresh state, and be able to
> >>>>>> properly initialize the protected-related stuff if protected sections
> >>>>>> are populated. Am I missing something?
> >>>>>
> >>>>> Right, we can do that. For some reason I keep associating the reset with the
> >>>>> error handling and not with "normal" operations.
> >>>> I kind of hope we end up with either
> >>>>
> >>>> - panthor knows the exact heap to use and fails with EPROBE_DEFER if
> >>>> the heap is missing, or
> >>>> - panthor gets a dma-buf from userspace and does the full reset
> >>>> - userspace also needs to provide a dma-buf for each protected
> >>>> group for the suspend buffer
> >>>>
> >>>> than something in-between. The latter is more ad-hoc and basically
> >>>> kicks the issue to the userspace.
> >>>
> >>> Indeed, the second option is more ad-hoc, but when you think about it,
> >>> userspace has to have this knowledge, because it needs to know the
> >>> dma-heap to use for buffer allocation that cross a device boundary
> >>> anyway. Think about frames produced by a video decoder, and composited
> >>> by the GPU into a protected scanout buffer that's passed to the KMS
> >>> device. Why would the GPU driver be source of truth when it comes to
> >>> choosing the heap to use to allocate protected buffers for the video
> >>> decoder or those used for the display?
> >> I don't think the GPU driver is ever the source of truth. If the
> >> system integrator wants to specify the source of truth (SoT) from
> >> kernel space, they should use the device tree (or module params /
> >> config options). If they want to specify the SoT in userspace, then we
> >> don't really care how it is done other than providing an ioctl.
> >> Panthor is always on the receiving end.
> >
> > Okay, we're on the same page then.
> >
> >>
> >> If we don't want to delay this functionality, but it takes time to
> >> converge on SoT, maybe a solution that is not a long-term promise can
> >> work? Of the options on the table (dt, module params, kconfig options,
> >> ioctls), a kconfig option, potentially marked as experimental, seems
> >> like a good candidate.
> >
> > If Panthor is only a consumer, I actually think it'd be easier to just
> > let userspace pass the protected FW section as an imported buffer
> > through an ioctl for now. It means we don't need any of the
> > modifications to the dma_heap API in this series, and userspace is free
> > to choose its SoT (efuse, DT, ...) and pass the info back to mesa/GBM
> > somehow (envvar, driconf, ...). The only thing we need to ensure is if
> > lazy protected FW section allocation is going to work, but given the
> > current code purely and simply ignores those sections, and the FW is
> > still able to boot and act properly (at least on v10-v13), I'm pretty
> > confident this is okay, unless there's some trick the MCU can do to
> > detect that the protected section isn't mapped (which I doubt, because
> > the MCU doesn't know it lives behind an MMU).
I set up MMU to map non-protected memory to the protected section the
other day. The FW still booted fine. I didn't get access violation
until the FW executed PROT_REGION and panthor requested
GLB_PROTM_ENTER in response.
This was on v13, but I also doubt it will become an issue. Can ARM help clarify?
> >
> > Of course, once we have a consensus on how to describe this in the DT,
> > we can switch Panthor over to "protected dma_heap selection through DT",
> > and reflect that through the ioctl that exposes whether protected
> > support is ready or not (would be a DEV_QUERY), such that userspace can
> > skip this "PROTM initialization" step.
> >
> > We're talking about an extra ioctl to set those buffers, and a
> > DEV_QUERY to query the state (ready or not), the size of the global
> > protected buffer (protected FW section) and the size of the protected
> > suspend buffer. The protected suspend buffer would be allocated and
> > passed at group creation time (extra arg passed to the existing
> > GROUP_CREATE ioctl). So, overall, I don't consider it a huge liability
> > in term of maintenance cost.
>
> If we can avoid the dma-heap changes, then that would surely help!
> I can try to implement this in the next version unless someone finds a
> reason why it is a bad idea.
Yeah, that sounds good to me too.
Will the extra ioctl require root? On a system with true protected
memory, the FW cannot write to non-protected memory. It seems ok to
allow any client to make the ioctl call. But on systems without true
protected memory, it can be problematic.
>
> >>>> For the former, expressing the relation in DT seems to be the best,
> >>>> but only if possible :-). Otherwise, a kconfig option (instead of
> >>>> module param) should be easier to work with.
> >>>>
> >>>> Looking at the userspace implementation, can we also have an panthor
> >>>> ioctl to return the heap to userspace?
> >>>
> >>> Yes, it's something we can add, but again, I'm questioning the
> >>> usefulness of this: how can we ensure the heap used by panthor to
> >>> allocate its protected FW buffers is suitable for scanout buffers
> >>> (buffers that can be used by display drivers). There needs to be a glue
> >>> leaving in usersland and taking the decision, and I'm not too sure
> >>> trusting any of the component in the chain (vdec, gpu, display) is the
> >>> right thing to do.
> >> The heap returned by panthor is only for panfrost/panvk. It says
> >> nothing about compatibility with other components on the system.
> >
> > Okay, if it's used only for internal buffers, I guess that's fine.
>
> --
> Ketil
^ permalink raw reply
* Re: [PATCH v1 1/1] kernel-doc: Issue warnings that were silently discarded
From: Randy Dunlap @ 2026-05-19 16:55 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Jonathan Corbet, Mauro Carvalho Chehab, linux-doc, linux-kernel
In-Reply-To: <aRC5NjhOmuGIpdPA@smile.fi.intel.com>
Hi,
I'm still seeing duplicated warning (logging) messages coming from
kernel-doc. Is there any progress on this?
I thought that there were some patches for this...
Thanks.
On 11/9/25 7:54 AM, Andy Shevchenko wrote:
> On Sat, Nov 08, 2025 at 04:03:15PM -0800, Randy Dunlap wrote:
>> On 11/5/25 10:12 AM, Jonathan Corbet wrote:
>>> [Heads up to Stephen: this change will add a bunch of warnings that had
>>> been dropped before.]
>>> Andy Shevchenko <andriy.shevchenko@linux.intel.com> writes:
>>>
>>>> When kernel-doc parses the sections for the documentation some errors
>>>> may occur. In many cases the warning is simply stored to the current
>>>> "entry" object. However, in the most of such cases this object gets
>>>> discarded and there is no way for the output engine to even know about
>>>> that. To avoid that, check if the "entry" is going to be discarded and
>>>> if there warnings have been collected, issue them to the current logger
>>>> as is and then flush the "entry". This fixes the problem that original
>>>> Perl implementation doesn't have.
>>>
>>> I would really like to redo how some of that logging is done, but that
>>> is an exercise for another day. For now, I have applied this one,
>>> thanks.
>>
>> I think that this patch is causing a (large) problem.
>>
>> With this patch:
>> $ make mandocs &>mandocs.out
>>
>> Without this patch:
>> $ make mandocs &>mandocsnoas.out
>>
>> $ wc mandocs.out mandocsnoas.out
>> 29544 267393 3229456 mandocs.out
>> 10052 95948 1208101 mandocsnoas.out
>>
>> so it appears that this patch causes lots of extra output.
>> Some of that may be what the patch was trying to do, but
>> with this patch, "mandocs.out" above has lots of duplicated
>> Warning: lines.
>>
>> $ sort mandocs.out | uniq > mandocsuq.out
>> $ wc mandocsuq.out
>> 18012 167689 1994145 mandocsuq.out
>>
>> $ grep -c "^Warning:" mandocs.out mandocsnoas.out mandocsuq.out
>> mandocs.out:25273
>> mandocsnoas.out:10022
>> mandocsuq.out:15252
>
> Yes, that's what Mauro explained, that we may have the dups.
>
>> In mandocs.out above (29544 lines), this line:
>> Warning: ../sound/soc/sprd/sprd-mcdt.h:48 struct member 'dma_chan' not described in 'sprd_mcdt_chan'
>>
>> is found at lines 7 and 29122.
>>
>> So maybe the logging output needs to be repaired sooner
>> than later.
>
> Right! But I'm not familiar with this, so I can help only with testing,
> and not with real fix development.
>
--
~Randy
^ permalink raw reply
* [PATCH] docs: pt_BR: Translate process/kernel-docs.rst into Portuguese
From: Daniel Pereira @ 2026-05-19 16:34 UTC (permalink / raw)
To: linux-doc; +Cc: corbet, Daniel Pereira
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 17550 bytes --]
Translate Documentation/process/kernel-docs.rst into Portuguese (pt_BR)
and update the main index.
The content was adapted following the RST formatting rules and the
appropriate technical terminology for Brazilian Portuguese.
Signed-off-by: Daniel Pereira <danielmaraboo@gmail.com>
---
Documentation/translations/pt_BR/index.rst | 1 +
.../pt_BR/process/kernel-docs.rst | 373 ++++++++++++++++++
2 files changed, 374 insertions(+)
create mode 100644 Documentation/translations/pt_BR/process/kernel-docs.rst
diff --git a/Documentation/translations/pt_BR/index.rst b/Documentation/translations/pt_BR/index.rst
index 77c1a1cdc..76936710b 100644
--- a/Documentation/translations/pt_BR/index.rst
+++ b/Documentation/translations/pt_BR/index.rst
@@ -67,6 +67,7 @@ kernel e sobre como ver seu trabalho integrado.
:maxdepth: 1
Introdução <process/1.Intro>
+ Index de documentos do Kernel <process/kernel-docs>
Regras de licenciamento <process/license-rules>
Como começar <process/howto>
Requisitos mínimos <process/changes>
diff --git a/Documentation/translations/pt_BR/process/kernel-docs.rst b/Documentation/translations/pt_BR/process/kernel-docs.rst
new file mode 100644
index 000000000..3c8d80ffa
--- /dev/null
+++ b/Documentation/translations/pt_BR/process/kernel-docs.rst
@@ -0,0 +1,373 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Índice de Documentação Adicional do Kernel
+==========================================
+
+A necessidade de um documento como este tornou-se evidente na lista de discussão
+linux-kernel, uma vez que as mesmas perguntas, solicitando referências de
+informações, apareciam repetidamente.
+
+Felizmente, à medida que cada vez mais pessoas chegam ao GNU/Linux, mais pessoas
+se interessam pelo Kernel. No entanto, ler o código-fonte nem sempre é o
+suficiente. É fácil entender o código, mas perder os conceitos, a filosofia
+e as decisões de design por trás dele.
+
+Infelizmente, não há muitos documentos disponíveis para iniciantes começarem.
+E, mesmo quando existem, não havia um local "bem conhecido" que os centralizasse.
+Estas linhas tentam suprir essa falta.
+
+POR FAVOR, se você conhece algum artigo não listado aqui ou se escrever um novo
+documento, inclua uma referência a ele aqui, seguindo o processo de envio de
+patches do kernel. Quaisquer correções, ideias ou comentários também são
+bem-vindos.
+
+Todos os documentos estão catalogados com os seguintes campos: o "Título" do
+documento, o(s) "Autor(es)", a "URL" onde podem ser encontrados, algumas
+"Palavras-chave" úteis para pesquisar tópicos específicos e uma breve
+"Descrição" do documento.
+
+.. note::
+
+ Os documentos em cada seção deste documento estão ordenados por sua data de
+ publicação, do mais recente para o mais antigo. O(s) mantenedor(es) deve(m)
+ remover periodicamente recursos à medida que se tornem obsoletos ou
+ desatualizados; com exceção de livros fundamentais.
+
+Documentação na árvore do Kernel
+--------------------------------
+
+Os manuais Sphinx devem ser compilados com ``make {htmldocs | pdfdocs | epubdocs}``.
+
+ * Nome: **linux/Documentation**
+
+ :Autor: Muitos.
+ :Localização: Documentation/
+ :Palavras-chave: arquivos de texto, Sphinx.
+ :Descrição: Documentação que acompanha o código-fonte do kernel,
+ dentro do diretório Documentation. Algumas páginas deste documento
+ (incluindo este próprio documento) foram movidas para lá e podem
+ estar mais atualizadas do que a versão web.
+
+Documentação on-line
+--------------------
+
+ * Título: **Linux Kernel Mailing List Glossary**
+
+ :Autor: diversos
+ :URL: https://kernelnewbies.org/KernelGlossary
+ :Data: versão contínua (rolling)
+ :Palavras-chave: glossário, termos, linux-kernel.
+ :Descrição: Da introdução: "Este glossário destina-se a ser uma breve
+ descrição de algumas das siglas e termos que você poderá ouvir durante
+ as discussões sobre o kernel Linux".
+
+ * Título: **The Linux Kernel Module Programming Guide**
+
+ :Autor: Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram,
+ Jim Huang.
+ :URL: https://sysprog21.github.io/lkmpg/
+ :Data: 2021
+ :Palavras-chave: módulos, livro GPL, /proc, ioctls, chamadas de sistema,
+ manipuladores de interrupção.
+ :Descrição: Um excelente livro sob licença GPL sobre o tópico de
+ programação de módulos. Repleto de exemplos. Atualmente, a nova versão
+ está sendo mantida ativamente em https://github.com/sysprog21/lkmpg.
+
+Livros Publicados
+-----------------
+
+ * Title: **The Linux Memory Manager**
+
+ :Autor: Lorenzo Stoakes
+ :Editora: No Starch Press
+ :Data: Fevereiro 2025
+ :Páginas: 1300
+ :ISBN: 978-1718504462
+ :Notas: Gerenciamento de memória. Rascunho completo disponível como acesso
+ antecipado para ré-venda, lançamento completo agendado para o
+ outono de 2025. Veja https://nostarch.com/linux-memory-manager
+ para mais informações.
+
+ * Title: **Practical Linux System Administration: A Guide to Installation, Configuration, and Management, 1st Edition**
+
+ :Autor: Kenneth Hess
+ :Editora: O'Reilly Media
+ :Data: Maio, 2023
+ :Páginas: 246
+ :ISBN: 978-1098109035
+ :Notas: Administração de sistemas
+
+ * Title: **Linux Kernel Debugging: Leverage proven tools and advanced techniques to effectively debug Linux kernels and kernel modules**
+
+ :Autor: Kaiwan N Billimoria
+ :Editora: Packt Publishing Ltd
+ :Data: Agosto, 2022
+ :Páginas: 638
+ :ISBN: 978-1801075039
+ :Notas: Livro sobre depuração (debugging)
+
+ * Title: **Linux Kernel Programming: A Comprehensive Guide to Kernel Internals, Writing Kernel Modules, and Kernel Synchronization**
+
+ :Autor: Kaiwan N Billimoria
+ :Editora: Packt Publishing Ltd
+ :Data: Março, 2021 (Segunda edição publicada em 2024)
+ :Páginas: 754
+ :ISBN: 978-1789953435 (O ISBN da segunda edição é 978-1803232225)
+
+ * Title: **Linux Kernel Programming Part 2 - Char Device Drivers and Kernel Synchronization: Create user-kernel interfaces, work with peripheral I/O, and handle hardware interrupts**
+
+ :Autor: Kaiwan N Billimoria
+ :Editora: Packt Publishing Ltd
+ :Data: Março, 2021
+ :Páginas: 452
+ :ISBN: 978-1801079518
+
+ * Title: **Linux System Programming: Talking Directly to the Kernel and C Library**
+
+ :Autor: Robert Love
+ :Editora: O'Reilly Media
+ :Data: Junho, 2013
+ :Páginas: 456
+ :ISBN: 978-1449339531
+ :Notas: Livro fundamental
+
+ * Título: **Linux Kernel Development, 3rd Edition**
+
+ :Autor: Robert Love
+ :Editora: Addison-Wesley
+ :Data: Julho de 2010
+ :Páginas: 440
+ :ISBN: 978-0672329463
+ :Notas: Livro fundamental
+
+ * Título: **Linux Device Drivers, 3rd Edition**
+
+ :Autores: Jonathan Corbet, Alessandro Rubini e Greg Kroah-Hartman
+ :Editora: O'Reilly & Associates
+ :Data: 2005
+ :Páginas: 636
+ :ISBN: 0-596-00590-3
+ :Notas: Livro fundamental. Mais informações em
+ http://www.oreilly.com/catalog/linuxdrive3/
+ Formato PDF, URL: https://lwn.net/Kernel/LDD3/
+
+ * Título: **The Design of the UNIX Operating System**
+
+ :Autor: Maurice J. Bach
+ :Editora: Prentice Hall
+ :Data: 1986
+ :Páginas: 471
+ :ISBN: 0-13-201757-1
+ :Notas: Livro fundamental
+
+Diversos
+--------
+
+ * Nome: **Cross-Referencing Linux**
+
+ :URL: https://elixir.bootlin.com/
+ :Palavras-chave: Navegação em código-fonte.
+ :Descrição: Outro navegador web para o código-fonte do kernel Linux.
+ Possui muitas referências cruzadas para variáveis e funções. Você pode
+ ver onde elas são definidas e onde são utilizadas.
+
+ * Nome: **Linux Weekly News**
+
+ :URL: https://lwn.net
+ :Palavras-chave: últimas notícias do kernel.
+ :Descrição: O título diz tudo. Há uma seção fixa sobre o kernel que
+ resume o trabalho dos desenvolvedores, correções de bugs, novos recursos
+ e versões produzidas durante a semana.
+
+ * Nome: **The home page of Linux-MM**
+
+ :Autor: A equipe Linux-MM.
+ :URL: https://linux-mm.org/
+ :Palavras-chave: gerenciamento de memória, Linux-MM, mm patches, TODO,
+ docs, mailing list.
+ :Descrição: Site dedicado ao desenvolvimento do Gerenciamento de Memória
+ do Linux. Patches relacionados à memória, HOWTOs, links, desenvolvedores
+ mm... Não perca se você estiver interessado no desenvolvimento do
+ gerenciamento de memória!
+
+ * Nome: **Kernel Newbies IRC Channel and Website**
+
+ :URL: https://www.kernelnewbies.org
+ :Palavras-chave: IRC, novatos, canal, tirar dúvidas.
+ :Descrição: #kernelnewbies em irc.oftc.net.
+ O canal #kernelnewbies é uma rede de IRC dedicada ao hacker de kernel
+ "novato" (newbie). O público consiste principalmente de pessoas que estão
+ aprendendo sobre o kernel, trabalhando em projetos do kernel ou hackers
+ profissionais que desejam ajudar pessoas menos experientes.
+ O #kernelnewbies está na rede de IRC OFTC.
+ Tente acessar irc.oftc.net como seu servidor e então digite /join #kernelnewbies.
+ O site kernelnewbies também hospeda artigos, documentos, FAQs...
+
+ * Nome: **linux-kernel mailing list archives and search engines**
+
+ :URL: https://subspace.kernel.org
+ :URL: https://lore.kernel.org
+ :Palavras-chave: linux-kernel, arquivos, busca.
+ :Descrição: Alguns dos arquivadores da lista de discussão linux-kernel.
+ Se você conhece algum outro (ou um melhor), por favor, me avise.
+
+ * Nome: **The Linux Foundation YouTube channel**
+
+ :URL: https://www.youtube.com/user/thelinuxfoundation
+ :Palavras-chave: linux, vídeos, linux-foundation, youtube.
+ :Descrição: A Linux Foundation faz o upload de gravações de vídeo de seus
+ eventos colaborativos, conferências de Linux (incluindo a LinuxCon) e
+ outras pesquisas originais e conteúdos relacionados ao Linux e ao
+ desenvolvimento de software.
+
+Rust
+----
+
+ * Título: **Rust for Linux**
+
+ :Autor: diversos
+ :URL: https://rust-for-linux.com/
+ :Data: versão contínua (rolling)
+ :Palavras-chave: glossário, termos, linux-kernel, rust.
+ :Descrição Do site: "Rust for Linux é o projeto que adiciona suporte à
+ linguagem Rust ao kernel Linux. Este site pretende ser um hub de links,
+ documentação e recursos relacionados ao projeto".
+
+ * Título: **Learn Rust the Dangerous Way**
+
+ :Autor: Cliff L. Biffle
+ :URL: https://cliffle.com/p/dangerust/
+ :Data: Acessado em 11 de setembro de 2024
+ :Palavras-chave: rust, blog.
+ :Descrição: Do site: "LRtDW é uma série de artigos que coloca os recursos
+ do Rust em contexto para programadores C de baixo nível que talvez não
+ tenham uma formação formal em Ciência da Computação, o tipo de pessoa
+ que trabalha com firmware, engines de jogos, kernels de SO e afins.
+ Basicamente, pessoas como eu.". O site ilustra conversões de linha por
+ linha de C para Rust.
+
+ * Título: **The Rust Book**
+
+ :Autor: Steve Klabnik e Carol Nichols, com contribuições da comunidade Rust
+ :URL: https://doc.rust-lang.org/book/
+ :Data: Acessado em 11 de setembro de 2024
+ :Palavras-chave: rust, livro.
+ :Descrição: Do site: "Este livro abraça totalmente o potencial do Rust para
+ capacitar seus usuários. É um texto amigável e acessível destinado a
+ ajudá-lo a elevar não apenas seu conhecimento de Rust, mas também seu
+ alcance e confiança como programador em geral. Então mergulhe de cabeça,
+ prepare-se para aprender e bem-vindo à comunidade Rust!".
+
+ * Título: **Rust for the Polyglot Programmer**
+
+ :Autor: Ian Jackson
+ :URL: https://www.chiark.greenend.org.uk/~ianmdlvl/rust-polyglot/index.html
+ :Data: Dezembro de 2022
+ :Palavras-chave: rust, blog, tooling.
+ :Descrição: Do site: "Existem muitos guias e introduções ao Rust. Este é
+ algo diferente: destina-se ao programador experiente que já conhece
+ muitas outras linguagens de programação. Tento ser abrangente o suficiente
+ para servir de ponto de partida para qualquer área do Rust, mas evito
+ entrar em detalhes excessivos, exceto onde as coisas não são como você
+ poderia esperar. Além disso, este guia não é inteiramente isento de
+ opiniões, incluindo recomendações de bibliotecas (crates), ferramentas, etc.".
+
+ * Título: **Fasterthanli.me**
+
+ :Autor: Amos Wenger
+ :URL: https://fasterthanli.me/
+ :Data: Acessado em 11 de setembro de 2024
+ :Palavras-chave: rust, blog, notícias.
+ :Descrição: Do site: "Eu crio artigos e vídeos sobre como os computadores
+ funcionam. Meu conteúdo é de formato longo, didático e exploratório
+ e frequentemente uma desculpa para ensinar Rust!".
+
+ * Título: **Comprehensive Rust**
+
+ :Autor: Equipe Android do Google
+ :URL: https://google.github.io/comprehensive-rust/
+ :Data: Acessado em 13 de setembro de 2024
+ :Palavras-chave: rust, blog.
+ :Descrição: Do site: "O curso cobre todo o espectro do Rust, desde a
+ sintaxe básica até tópicos avançados como genéricos e tratamento de erros".
+
+ * Título: **The Embedded Rust Book**
+
+ :Autor: Múltiplos colaboradores, principalmente Jorge Aparicio
+ :URL: https://docs.rust-embedded.org/book/
+ :Data: Acessado em 13 de setembro de 2024
+ :Palavras-chave: rust, blog.
+ :Descrição: Do site: "Um livro introdutório sobre o uso da linguagem de
+ programação Rust em sistemas embarcados 'Bare Metal', como microcontroladores".
+
+ * Título: **Experiment: Improving the Rust Book**
+
+ :Autor: Cognitive Engineering Lab na Brown University
+ :URL: https://rust-book.cs.brown.edu/
+ :Data: Acessado em 22 de setembro de 2024
+ :Palavras-chave: rust, blog.
+ :Descrição: Do site: "O objetivo deste experimento é avaliar e melhorar o
+ conteúdo do Rust Book para ajudar as pessoas a aprenderem Rust de forma
+ mais eficaz".
+
+ * Título: **New Rustacean** (podcast)
+
+ :Autor: Chris Krycho
+ :URL: https://newrustacean.com/
+ :Data: Acessado em 22 de setembro de 2024
+ :Palavras-chave: rust, podcast.
+ :Descrição: Do site: "Este é um podcast sobre aprender a linguagem de
+ programação Rust do zero! Além desta página inicial elegante, todo o
+ conteúdo do site é construído com as próprias ferramentas de documentação
+ do Rust".
+
+ * Título: **Opsem-team** (repositório)
+
+ :Autor: Equipe de semântica operacional (Operational semantics team)
+ :URL: https://github.com/rust-lang/opsem-team/tree/main
+ :Data: Acessado em 22 de setembro de 2024
+ :Palavras-chave: rust, repositório.
+ :Descrição: Do README: "A equipe opsem é a sucessora do grupo de trabalho
+ unsafe-code-guidelines e é responsável por responder a muitas das perguntas
+ difíceis sobre a semântica do Rust inseguro (unsafe Rust)".
+
+ * Título: **You Can't Spell Trust Without Rust**
+
+ :Autor: Alexis Beingessner
+ :URL: https://repository.library.carleton.ca/downloads/1j92g820w?locale=en
+ :Data: 2015
+ :Palavras-chave: rust, mestrado, tese.
+ :Descrição: Esta tese foca no sistema de propriedade (ownership) do Rust,
+ que garante a segurança de memória ao controlar a manipulação de dados e
+ o tempo de vida, enquanto também destaca suas limitações e o compara a
+ sistemas semelhantes no Cyclone e C++.
+
+ * Nome: **Apresentações de Rust no Linux Plumbers (LPC) 2024**
+
+ :Título: Rust microconference
+ :URL: https://lpc.events/event/18/sessions/186/#20240918
+ :Título: Rust for Linux
+ :URL: https://lpc.events/event/18/contributions/1912/
+ :Título: Journey of a C kernel engineer starting a Rust driver project
+ :URL: https://lpc.events/event/18/contributions/1911/
+ :Título: Crafting a Linux kernel scheduler that runs in user-space using Rust
+ :URL: https://lpc.events/event/18/contributions/1723/
+ :Título: openHCL: A Linux and Rust based paravisor
+ :URL: https://lpc.events/event/18/contributions/1956/
+ :Palavras-chave: rust, lpc, apresentações.
+ :Descrição: Uma série de palestras do LPC relacionadas ao Rust.
+
+ * Nome: **The Rustacean Station Podcast**
+
+ :URL: https://rustacean-station.org/
+ :Palavras-chave: rust, podcasts.
+ :Descrição: Um projeto comunitário para a criação de conteúdo em podcast
+ sobre a linguagem de programação Rust.
+
+-------
+
+Este documento foi originalmente baseado em:
+
+https://www.dit.upm.es/~jmseyas/linux/kernel/hackers-docs.html
+
+e escrito por Juan-Mariano de Goyeneche.
--
2.47.3
^ permalink raw reply related
* Re: [Linaro-mm-sig] Re: [PATCH RFC 2/5] dma-heap: charge dma-buf memory via explicit memcg
From: Maxime Ripard @ 2026-05-19 16:32 UTC (permalink / raw)
To: Christian König
Cc: Albert Esteve, Barry Song, T.J. Mercier, Tejun Heo,
Johannes Weiner, Michal Koutný, Jonathan Corbet, Shuah Khan,
Sumit Semwal, Michal Hocko, Roman Gushchin, Shakeel Butt,
Muchun Song, Andrew Morton, Benjamin Gaignard, Brian Starkey,
John Stultz, Christian Brauner, Paul Moore, James Morris,
Serge E. Hallyn, Stephen Smalley, Ondrej Mosnacek, Shuah Khan,
cgroups, linux-doc, linux-kernel, linux-media, dri-,
linaro-mm-sig, linux-mm, linux-security-module, selinux,
linux-kselftest, echanude
In-Reply-To: <9cc79977-9a42-40eb-bfa7-460881c1e10f@amd.com>
[-- Attachment #1: Type: text/plain, Size: 6159 bytes --]
Hi Chritian,
On Tue, May 19, 2026 at 09:53:19AM +0200, Christian König wrote:
> On 5/18/26 14:06, Albert Esteve wrote:
> >>>>> udmabufs are already
> >>>>> memcg-charged, so adding a separate MEMCG_DMABUF would double count.
> >>>>> Are there any other exporters you had in mind that would benefit from
> >>>>> this approach?
> >>
> >> Well apart from DMA-buf memfd_create() is one of the things which as broken our neck in the past a couple of times.
> >>
> >> But thinking more about it what if instead of making this DMA-buf heaps specific what if we have a general cgroups function which allows to change accounting of a buffer referenced by a file descriptor to a different process?
> >>
> >> That would cover not only the DMA-buf heaps use case, but also all other DMA-buf with dmem and whatever we come up in the future as well.
> >
> > I removed a draft adding an ioctl for charge transfer from the series
> > before sending because I wanted to focus on the charge_pid_fd approach
> > and keep things simple, deferring the recharge path to a follow-up
> > depending on feedback.
> >
> > The main difference between my removed draft and what you're
> > describing, iiuc, is scope and layer: my draft was an explicit ioctl
> > on the dma-buf fd that the consumer calls to claim the charge (see
> > below), while you seem to be suggesting a more general kernel-internal
> > function that could work across buffer types and cgroup controllers,
> > so not necessarily userspace-initiated? A kernel-internal function
> > will need a way to identify the target process, which sounds similar
> > to the binder-backed approach from TJ [1]. For everything else, the
> > receiver still needs to declare itself, which the ioctl accomplishes.
> >
> > ```
> > # When an app imports a daemon-allocated buffer, it can transfer the
> > charge to itself:
> > int buf_fd = receive_dmabuf_from_daemon();
> > ioctl(buf_fd, DMA_BUF_IOCTL_XFER_CHARGE); /* charge now attributed to
> > apps's cgroup */
>
> Well that thinking goes into the right direction, but the requirements are still not completely
> covered as far as I can see.
>
> Let me explain below a bit more.
>
> >
> > [1] https://lore.kernel.org/cgroups/20230109213809.418135-1-tjmercier@google.com/
> >
> >>
> >> The only drawback I can see is that DMA-buf heap allocations would be temporarily accounted to the memory allocation daemon, but I don't think that this would be a problem.
> >
> > The main reasons we moved away from TJ's transfer-based approach
> > toward `charge_pid_fd` are: avoid the transient charge window on the
> > daemon's cgroup; and to decouple from Binder, allowing any allocator
> > to use it.
>
> Yeah those concerns are completely correct.
>
> The application should not volunteering says 'Charge that buffer to
> me.', but rather that the daemon says force charge that buffer to this
> application and tell me when the application is over its limit.
I would agree, but with a caveat: how do we want to deal with malicious
applications here? The application should have expressed that it's okay
for it to be charged by a different process, otherwise it becomes
trivial for a malicious app to create arbitrary charges against another
application in the system and DoS it.
But then, that means that an application could arbitrarily charge the
daemon as well if it doesn't opt-in but asks for allocations.
So maybe we should have an opt-in for the caller, and a way for the
daemon to check if the caller has indeed opted in before performing the
allocation (and the charge transfer)?
> > Technically, both approaches could coexist, though. Of the three
> > scenarios TJ described:
> > - Scenario 2 is directly addressed by charge_pid_fd approach without
> > any transient charge on the daemon at the cost of one extra field in
> > the heap ioctl uAPI struct.
>
> Yeah extending the uAPI to pass in the pid on allocation time is not
> much of a problem, but you also need to modify the whole stack above
> it and that is a bit more trickier.
>
> > - Scenario 3 can be handled by the charge transfer function without
> > changes to SurfaceFlinger. The app or dequeueBuffer claims the charge
> > for itself or the app, respectively (depending on whether we include a
> > pid_fd field in the transfer ioctl). It also covers non-heap
> > exporters. The con in both variants is the transient charge window on
> > the daemon.
>
> It should be trivial for the deamon to charge the buffer to an
> application before handing it out.
>
> > Both approaches shift the responsibility for correct charging
> > attribution to userspace: first, 'charge_pid_fd` on the allocator's
> > side, and the transfer charge on the consumer's side.
>
> Yeah that's why I said it would be better if we do that without any
> uAPI change, but with all the uAPI we have to transfer file
> descriptors (dup(), fork(), passing FDs over sockets etc...) it could
> be really tricky to implement that.
>
> > Deciding on one, the other or both depends on how much we value
> > avoiding transient attribution, and how much we need a non-heap
> > generic solution. With the XFER_CHARGE we can cover both. Thus, the
> > `charge_pid_fd` approach in this RFC can be seen as a
> > performance/strictness optimisation, eliminating transient charges to
> > the daemon at the cost of a permanent uAPI addition to the heap ioctl
> > struct, but not strictly required for correctness.
>
> Well all we need is a uAPI which says charge this buffer (file
> descriptor) to that cgroup (pidfd).
>
> With this at hand we should be able to handle all use cases at the
> same time.
>
> > On the other hand, if we agree on the end goal of migrating other
> > exporters to use dma-buf heaps
>
> That won't work. DMA-buf heaps is actually only a rather small and
> Anroid specific use case.
I don't think that's true anymore. heaps are used in lots of different
use cases now in the embedded space, including in regular, generic,
components not specifically used for embedded systems.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply
* Re: [PATCH v2 1/2] arm64/cpufeature: Define hwcaps for 2025 dpISA features
From: Mark Brown @ 2026-05-19 16:03 UTC (permalink / raw)
To: Will Deacon
Cc: Catalin Marinas, Jonathan Corbet, Shuah Khan, linux-arm-kernel,
linux-kernel, linux-doc, linux-kselftest
In-Reply-To: <agyAs0UXGulhFXga@willie-the-truck>
[-- Attachment #1: Type: text/plain, Size: 1049 bytes --]
On Tue, May 19, 2026 at 04:24:35PM +0100, Will Deacon wrote:
> On Mon, May 18, 2026 at 04:07:29PM +0100, Mark Brown wrote:
> > +HWCAP3_F16F32MM
> > + Functionality implied by ID_AA64ISAR0_EL1.FHM == 0b0011
> > +HWCAP3_SVE_LUT6
> > + Functionality implied by ID_AA64ISAR2_EL1.LUT == 0b0010 and
> > + ID_AA64PFR0_EL1.SVE == 0b0001.
> I've queued this, but I'm curious why you've called out the
> 'ID_AA64PFR0_EL1.SVE == 0b0001' part here and not for any of the other
> SVE caps you're adding?
It was mostly due to the possibility of ID_AA64ISAR2_EL1.LUT getting a
new non-SVE value, now you mention it I should go back and add the same
restriction for the others due to the use of ID_AA64ZFR0_EL1 for SME
only systems. It's the implemented behaviour.
> It's also formatted inconsistently from
> pre-existing entries (such as HWCAP2_SVE_B16B16) which put the
> ID_AA64PFR0_EL1.SVE part of the antecedent first.
No real reason for that, there just weren't other examples on screen at
the time I was editing this.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH v2 1/2] mm/memcontrol: add dmem charge/uncharge functions
From: Eric Chanudet @ 2026-05-19 15:59 UTC (permalink / raw)
To: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
Muchun Song, Andrew Morton, Maarten Lankhorst, Maxime Ripard,
Natalie Vock, Tejun Heo, Michal Koutný, Jonathan Corbet,
Shuah Khan
Cc: cgroups, linux-mm, linux-kernel, dri-devel, T.J. Mercier,
Christian König, Maxime Ripard, Albert Esteve, Dave Airlie,
linux-doc, Eric Chanudet
In-Reply-To: <20260519-cgroup-dmem-memcg-double-charge-v2-0-db4d1407062b@redhat.com>
Add mem_cgroup_dmem_charge() and mem_cgroup_dmem_uncharge() to allow
dmem pool allocations to optionally be double-charged against the memory
controller. Take the struct cgroup from the dmem pool's css as there is
no convenient object exported to represent these allocations. These will
resolve the effective memory css from that cgroup and perform the
charge.
Introduce a MEMCG_DMEM stat counter to memory.stat to make the cgroup's
dmem charge visible.
Signed-off-by: Eric Chanudet <echanude@redhat.com>
---
include/linux/memcontrol.h | 16 ++++++++++++
mm/memcontrol.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 81 insertions(+)
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index dc3fa687759b45748b2acee6d7f43da325eb50c1..8e1d49b87fb64e6114f3eb920293e14920290fe7 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -39,6 +39,7 @@ enum memcg_stat_item {
MEMCG_ZSWAP_B,
MEMCG_ZSWAPPED,
MEMCG_ZSWAP_INCOMP,
+ MEMCG_DMEM,
MEMCG_NR_STAT,
};
@@ -1872,6 +1873,21 @@ static inline bool mem_cgroup_zswap_writeback_enabled(struct mem_cgroup *memcg)
}
#endif
+#if defined(CONFIG_MEMCG) && defined(CONFIG_CGROUP_DMEM)
+bool mem_cgroup_dmem_charge(struct cgroup *cgrp, unsigned int nr_pages,
+ gfp_t gfp_mask);
+void mem_cgroup_dmem_uncharge(struct cgroup *cgrp, unsigned int nr_pages);
+#else
+static inline bool mem_cgroup_dmem_charge(struct cgroup *cgrp,
+ unsigned int nr_pages, gfp_t gfp_mask)
+{
+ return true;
+}
+static inline void mem_cgroup_dmem_uncharge(struct cgroup *cgrp,
+ unsigned int nr_pages)
+{
+}
+#endif
/* Cgroup v1-related declarations */
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index c03d4787d466803db49cdaa90e6d6ba426b7afe2..91a7ac16b6eac2d6c3700b6885a068bf8b640706 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -433,6 +433,7 @@ static const unsigned int memcg_stat_items[] = {
MEMCG_ZSWAP_B,
MEMCG_ZSWAPPED,
MEMCG_ZSWAP_INCOMP,
+ MEMCG_DMEM,
};
#define NR_MEMCG_NODE_STAT_ITEMS ARRAY_SIZE(memcg_node_stat_items)
@@ -1606,6 +1607,9 @@ static const struct memory_stat memory_stats[] = {
#ifdef CONFIG_NUMA_BALANCING
{ "pgpromote_success", PGPROMOTE_SUCCESS },
#endif
+#ifdef CONFIG_CGROUP_DMEM
+ { "dmem", MEMCG_DMEM },
+#endif
};
/* The actual unit of the state item, not the same as the output unit */
@@ -5909,6 +5913,67 @@ static struct cftype zswap_files[] = {
};
#endif /* CONFIG_ZSWAP */
+#ifdef CONFIG_CGROUP_DMEM
+/**
+ * mem_cgroup_dmem_charge - charge memcg for a dmem pool allocation
+ * @cgrp: cgroup of the dmem pool
+ * @nr_pages: number of pages to charge
+ * @gfp_mask: reclaim mode
+ *
+ * Charges @nr_pages to @memcg. Returns %true if the charge fit within
+ * @memcg's configured limit, %false if it doesn't.
+ */
+bool mem_cgroup_dmem_charge(struct cgroup *cgrp, unsigned int nr_pages,
+ gfp_t gfp_mask)
+{
+ struct cgroup_subsys_state *mem_css;
+ struct mem_cgroup *memcg;
+
+ /* CGROUP_DMEM and MEMCG guarantees this cannot be NULL. */
+ mem_css = cgroup_get_e_css(cgrp, &memory_cgrp_subsys);
+
+ /* Use the memcg, if any, of the dmem cgroup. */
+ memcg = mem_cgroup_from_css(mem_css);
+ if (!memcg || mem_cgroup_is_root(memcg)) {
+ css_put(mem_css);
+ return false;
+ }
+
+ if (try_charge_memcg(memcg, gfp_mask, nr_pages)) {
+ css_put(mem_css);
+ return false;
+ }
+
+ mod_memcg_state(memcg, MEMCG_DMEM, nr_pages);
+ css_put(mem_css);
+ return true;
+}
+
+/**
+ * mem_cgroup_dmem_uncharge - uncharge memcg from a dmem pool allocation
+ * @cgrp: cgroup of the dmem pool
+ * @nr_pages: number of pages to uncharge
+ */
+void mem_cgroup_dmem_uncharge(struct cgroup *cgrp, unsigned int nr_pages)
+{
+ struct cgroup_subsys_state *mem_css;
+ struct mem_cgroup *memcg;
+
+ /* CGROUP_DMEM and MEMCG guarantees this cannot be NULL. */
+ mem_css = cgroup_get_e_css(cgrp, &memory_cgrp_subsys);
+
+ memcg = mem_cgroup_from_css(mem_css);
+ if (!memcg || mem_cgroup_is_root(memcg)) {
+ css_put(mem_css);
+ return;
+ }
+
+ mod_memcg_state(memcg, MEMCG_DMEM, -nr_pages);
+ refill_stock(memcg, nr_pages);
+ css_put(mem_css);
+}
+#endif /* CONFIG_CGROUP_DMEM */
+
static int __init mem_cgroup_swap_init(void)
{
if (mem_cgroup_disabled())
--
2.52.0
^ permalink raw reply related
* [PATCH v2 0/2] cgroup/dmem: allow double-charging dmem allocations to memcg
From: Eric Chanudet @ 2026-05-19 15:59 UTC (permalink / raw)
To: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
Muchun Song, Andrew Morton, Maarten Lankhorst, Maxime Ripard,
Natalie Vock, Tejun Heo, Michal Koutný, Jonathan Corbet,
Shuah Khan
Cc: cgroups, linux-mm, linux-kernel, dri-devel, T.J. Mercier,
Christian König, Maxime Ripard, Albert Esteve, Dave Airlie,
linux-doc, Eric Chanudet
Following suggestion[1], offer a cgroupfs entry to allow an
administrator to request that a dmem controlled region also charges to
the memory controller.
Add mem_cgroup_dmem_charge/uncharge helpers to resolve the effective
cgroup from a dmem pool's cgroup, perform the charge and update a
MEMCG_DMEM stat counter.
Add a "dmem.memcg" control file at the root level to configure memcg
charging per region. The setting is disabled by default and locked on
first charge attempt.
[1] https://lore.kernel.org/all/a446b598-5041-450b-aaa9-3c39a09ff6a0@amd.com/
Signed-off-by: Eric Chanudet <echanude@redhat.com>
---
Changes in v2:
- Use mem_cgroup_dmem_{,un}charge to account for memcg pages instead of
exposing raw nr_pages functions. Use it to centralize where to find
the effective cgroup from the pool's cgroup (Johannes)
- Set depends_on for cgrp_memory if CONFIG_MEMCG by having a memory
controller in children cgroup (Michal)
- Move dmem.memcg to the root level as it applies by region for all
cgroups
- Add a dmem memory.stats entry for reporting memcg charges for dmem
allocations.
- Wrap the memcg enable/disable/lock configuration under a single state
to avoid toctou races and simplify transitions.
- Link to v1: https://lore.kernel.org/r/20260403-cgroup-dmem-memcg-double-charge-v1-0-c371d155de2a@redhat.com
---
Eric Chanudet (2):
mm/memcontrol: add dmem charge/uncharge functions
cgroup/dmem: add dmem.memcg control file for double-charging to memcg
Documentation/admin-guide/cgroup-v2.rst | 23 +++++
include/linux/memcontrol.h | 16 ++++
kernel/cgroup/dmem.c | 158 +++++++++++++++++++++++++++++++-
mm/memcontrol.c | 65 +++++++++++++
4 files changed, 259 insertions(+), 3 deletions(-)
---
base-commit: d989f135f71699294bb2ffd4726b526456e2db68
change-id: 20260327-cgroup-dmem-memcg-double-charge-0f100a9ffbf2
Best regards,
--
Eric Chanudet <echanude@redhat.com>
^ permalink raw reply
* Re: [PATCH 00/12] misc/syncobj: add /dev/syncobj device
From: Christian König @ 2026-05-19 16:00 UTC (permalink / raw)
To: Xaver Hugl
Cc: Julian Orth, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Sumit Semwal, Jonathan Corbet,
Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman, dri-devel,
linux-kernel, linux-media, linaro-mm-sig, linux-doc,
wayland-devel, Michel Dänzer
In-Reply-To: <CAFZQkGwmeipZnvmBkcE7KhvUSMkSE=fzLBZtiMyhv3mM04Vudg@mail.gmail.com>
On 5/19/26 17:31, Xaver Hugl wrote:
> Am Di., 19. Mai 2026 um 15:29 Uhr schrieb Christian König
> <christian.koenig@amd.com>:
>>> 1. This series makes the ability to manipulate syncobjs available
>>> independently of attached hardware.
>>> 2. It makes it available under a consistent path /dev/syncobj.
>>
>> Exactly that is a big no-go. This has to be under /dev/dri.
> FWIW udmabuf is also under /dev directly, but I don't think any
> compositor developer would complain about a different path.
> What are the rules for that? Could this simply be put in /dev/dri/syncobj?
The syncobj are actually the DRM specific way of doing things. The general kernel wide way is to use sync files (see drivers/dma-buf/sync_file.c).
But there has already been tons of problems with those sync files. E.g. they doesn't support your use case at all since they don't have wait before submit behavior.
So there are already ways to do this, but the Linux kernel so far told everybody that this is forbidden. The DRM syncobj wait before signal functionality is much better, but then basically the second try to do this.
> The part where we get this independent of attached hardware is quite
> important for us though, since we can't just ignore explicit sync once
> the device we previously imported the syncobj into is disconnected.
Can you elaborate more on this?
> Buffers can be from any device or allocated in system memory and
> access should be synchronized properly in all cases.
>
> How exactly it's made available isn't all that critical.
>
>>> 3. It removes the need to translate between syncobjs fds and handles.
>>
>> That's a pretty big no-go as well. The differentiation between FDs and handles is completely intentional.
> Could you expand on why it's needed? For compositors, the handle is
> just an intermediary thing when translating between file descriptors.
Well what we could do is to add an IOCTL to directly attach an syncobj file descriptor to an eventfd.
> FTR for me at least, this part would be merely nice to have, since it
> slightly reduces the amount of ioctls a compositor needs to call, but
> it's not important.
>
>>>> What about using VGEM for this?
>>>
>>> If the vgem render node were made available unconditionally under,
>>
>> Software rendering is a complete corner case, I don't think that this will be enabled by default.
> That simply makes vgem unsuitable for solving the problems we face in
> compositors.
Thinking more about it vgem also has the same issues as sync file mentioned above. So that is really also not doable.
Maybe Simona or David have another idea.
Regards,
Christian.
>
> - Xaver
^ permalink raw reply
* [PATCH v2 2/2] cgroup/dmem: add dmem.memcg control file for double-charging to memcg
From: Eric Chanudet @ 2026-05-19 15:59 UTC (permalink / raw)
To: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
Muchun Song, Andrew Morton, Maarten Lankhorst, Maxime Ripard,
Natalie Vock, Tejun Heo, Michal Koutný, Jonathan Corbet,
Shuah Khan
Cc: cgroups, linux-mm, linux-kernel, dri-devel, T.J. Mercier,
Christian König, Maxime Ripard, Albert Esteve, Dave Airlie,
linux-doc, Eric Chanudet
In-Reply-To: <20260519-cgroup-dmem-memcg-double-charge-v2-0-db4d1407062b@redhat.com>
Add a root-only cgroupfs file "dmem.memcg" that lets an administrator
configure whether allocations in a dmem region should also be charged to
the memory controller.
To handle inheritance, dmem adds a depends_on the memory controller,
unless MEMCG isn't configured in.
Double-charging is disabled by default. Once a charge is attempted, the
setting is locked to prevent inconsistent accounting by a small 4-state
machine (off, on, locked off, locked on).
The memcg to charge is derived from the pool's cgroup, since the pool
holds a reference to the dmem cgroup state that keeps the cgroup alive
until it gets uncharged.
Signed-off-by: Eric Chanudet <echanude@redhat.com>
---
Documentation/admin-guide/cgroup-v2.rst | 23 +++++
kernel/cgroup/dmem.c | 158 +++++++++++++++++++++++++++++++-
2 files changed, 178 insertions(+), 3 deletions(-)
diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
index 6efd0095ed995b1550317662bc1b56c7a7f3db23..1d2fa55ddf0faa17baa916a8914d3033e8e42359 100644
--- a/Documentation/admin-guide/cgroup-v2.rst
+++ b/Documentation/admin-guide/cgroup-v2.rst
@@ -2828,6 +2828,29 @@ DMEM Interface Files
drm/0000:03:00.0/vram0 12550144
drm/0000:03:00.0/stolen 8650752
+ dmem.memcg
+ A readwrite nested-keyed file that exists only on the root
+ cgroup. It configures whether allocations in a dmem region
+ should also be charged to the memory controller.
+
+ Upon the first charge to a region, its setting can no longer be changed
+ and is reported as "[true|false] (locked)".
+
+ Charges to the memory controller are visible in ``memory.stat`` as the
+ ``dmem`` entry, reported in bytes.
+
+ An example read output follows::
+
+ drm/0000:03:00.0/vram0 false
+ drm/0000:03:00.0/stolen false (locked)
+
+ Writing uses the same nested-keyed format::
+
+ echo "drm/0000:03:00.0/vram0 true" > dmem.memcg
+
+ This file is only available when the kernel is built with
+ ``CONFIG_MEMCG``.
+
HugeTLB
-------
diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c
index 1ab1fb47f2711ecc60dd13e611a8a4920b48f3e9..e07b20b8025c528f190f84c76b088cb8a32a7f5e 100644
--- a/kernel/cgroup/dmem.c
+++ b/kernel/cgroup/dmem.c
@@ -17,6 +17,14 @@
#include <linux/refcount.h>
#include <linux/rculist.h>
#include <linux/slab.h>
+#include <linux/memcontrol.h>
+
+enum dmem_memcg_status {
+ DMEM_MEMCG_OFF,
+ DMEM_MEMCG_ON,
+ DMEM_MEMCG_LOCKED_OFF,
+ DMEM_MEMCG_LOCKED_ON,
+};
struct dmem_cgroup_region {
/**
@@ -51,6 +59,14 @@ struct dmem_cgroup_region {
* No new pools should be added to the region afterwards.
*/
bool unregistered;
+
+ /**
+ * @memcg_status: Whether allocation in this region should charge memcg.
+ * DMEM_MEMCG_OFF/DMEM_MEMCG_ON or
+ * DMEM_MEMCG_LOCKED_OFF/DMEM_MEMCG_LOCKED_ON, frozen after first allocation.
+ * Transitions to a locked state are one-way.
+ */
+ atomic_t memcg_status;
};
struct dmemcg_state {
@@ -609,6 +625,34 @@ get_cg_pool_unlocked(struct dmemcg_state *cg, struct dmem_cgroup_region *region)
return pool;
}
+static bool apply_memcg_charge(atomic_t *status)
+{
+ int state = atomic_read(status);
+
+ for (;;) {
+ switch (state) {
+ case DMEM_MEMCG_OFF:
+ state = atomic_cmpxchg(status, DMEM_MEMCG_OFF,
+ DMEM_MEMCG_LOCKED_OFF);
+ if (state != DMEM_MEMCG_OFF)
+ continue;
+ return false;
+ case DMEM_MEMCG_LOCKED_OFF:
+ return false;
+ case DMEM_MEMCG_ON:
+ state = atomic_cmpxchg(status, DMEM_MEMCG_ON,
+ DMEM_MEMCG_LOCKED_ON);
+ if (state != DMEM_MEMCG_ON)
+ continue;
+ return true;
+ case DMEM_MEMCG_LOCKED_ON:
+ return true;
+ }
+ WARN_ONCE(1, "Invalid memcg_status (%#x).\n", state);
+ return false;
+ }
+}
+
/**
* dmem_cgroup_uncharge() - Uncharge a pool.
* @pool: Pool to uncharge.
@@ -624,6 +668,12 @@ void dmem_cgroup_uncharge(struct dmem_cgroup_pool_state *pool, u64 size)
return;
page_counter_uncharge(&pool->cnt, size);
+
+ if (atomic_read(&pool->region->memcg_status) == DMEM_MEMCG_LOCKED_ON &&
+ !WARN_ON_ONCE(size > (u64)UINT_MAX << PAGE_SHIFT))
+ mem_cgroup_dmem_uncharge(pool->cs->css.cgroup,
+ PAGE_ALIGN(size) >> PAGE_SHIFT);
+
css_put(&pool->cs->css);
dmemcg_pool_put(pool);
}
@@ -655,6 +705,8 @@ int dmem_cgroup_try_charge(struct dmem_cgroup_region *region, u64 size,
struct dmemcg_state *cg;
struct dmem_cgroup_pool_state *pool;
struct page_counter *fail;
+ unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ bool charge_memcg;
int ret;
*ret_pool = NULL;
@@ -670,7 +722,28 @@ int dmem_cgroup_try_charge(struct dmem_cgroup_region *region, u64 size,
pool = get_cg_pool_unlocked(cg, region);
if (IS_ERR(pool)) {
ret = PTR_ERR(pool);
- goto err;
+ goto err_css_put;
+ }
+
+ charge_memcg = apply_memcg_charge(®ion->memcg_status);
+ if (charge_memcg) {
+ /* mem_cgroup_dmem_charge limitation from try_charge_memcg */
+ if (size > (u64)UINT_MAX << PAGE_SHIFT) {
+ ret = -EINVAL;
+ dmemcg_pool_put(pool);
+ goto err_css_put;
+ }
+
+ if (!mem_cgroup_dmem_charge(pool->cs->css.cgroup, nr_pages,
+ GFP_KERNEL)) {
+ /*
+ * No dmem_cgroup_state_evict_valuable() could help,
+ * there's no ret_limit_pool to return.
+ */
+ ret = -ENOMEM;
+ dmemcg_pool_put(pool);
+ goto err_css_put;
+ }
}
if (!page_counter_try_charge(&pool->cnt, size, &fail)) {
@@ -681,14 +754,17 @@ int dmem_cgroup_try_charge(struct dmem_cgroup_region *region, u64 size,
}
dmemcg_pool_put(pool);
ret = -EAGAIN;
- goto err;
+ goto err_uncharge_memcg;
}
/* On success, reference from get_current_dmemcs is transferred to *ret_pool */
*ret_pool = pool;
return 0;
-err:
+err_uncharge_memcg:
+ if (charge_memcg)
+ mem_cgroup_dmem_uncharge(pool->cs->css.cgroup, nr_pages);
+err_css_put:
css_put(&cg->css);
return ret;
}
@@ -845,6 +921,71 @@ static ssize_t dmem_cgroup_region_max_write(struct kernfs_open_file *of,
return dmemcg_limit_write(of, buf, nbytes, off, set_resource_max);
}
+#ifdef CONFIG_MEMCG
+static int dmem_cgroup_memcg_show(struct seq_file *sf, void *v)
+{
+ struct dmem_cgroup_region *region;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(region, &dmem_cgroup_regions, region_node) {
+ int state = atomic_read(®ion->memcg_status);
+
+ seq_printf(sf, "%s %s\n", region->name,
+ state == DMEM_MEMCG_ON ? "true" :
+ state == DMEM_MEMCG_OFF ? "false" :
+ state == DMEM_MEMCG_LOCKED_ON ? "true (locked)" :
+ state == DMEM_MEMCG_LOCKED_OFF ? "false (locked)" :
+ "(invalid)");
+ }
+ rcu_read_unlock();
+ return 0;
+}
+
+static ssize_t dmem_cgroup_memcg_write(struct kernfs_open_file *of, char *buf,
+ size_t nbytes, loff_t off)
+{
+ while (buf) {
+ struct dmem_cgroup_region *region;
+ char *options, *name;
+ bool flag;
+
+ options = buf;
+ buf = strchr(buf, '\n');
+ if (buf)
+ *buf++ = '\0';
+
+ options = strstrip(options);
+ if (!options[0])
+ continue;
+
+ name = strsep(&options, " \t");
+ if (!name[0])
+ continue;
+
+ if (!options || !options[0])
+ return -EINVAL;
+
+ if (kstrtobool(options, &flag))
+ return -EINVAL;
+
+ rcu_read_lock();
+ region = dmemcg_get_region_by_name(name);
+ rcu_read_unlock();
+ if (!region)
+ return -ENODEV;
+
+ atomic_cmpxchg(®ion->memcg_status,
+ flag ? DMEM_MEMCG_OFF : DMEM_MEMCG_ON,
+ flag ? DMEM_MEMCG_ON : DMEM_MEMCG_OFF);
+ /* Continue if a region is already locked. */
+
+ kref_put(®ion->ref, dmemcg_free_region);
+ }
+
+ return nbytes;
+}
+#endif
+
static struct cftype files[] = {
{
.name = "capacity",
@@ -873,6 +1014,14 @@ static struct cftype files[] = {
.seq_show = dmem_cgroup_region_max_show,
.flags = CFTYPE_NOT_ON_ROOT,
},
+#ifdef CONFIG_MEMCG
+ {
+ .name = "memcg",
+ .write = dmem_cgroup_memcg_write,
+ .seq_show = dmem_cgroup_memcg_show,
+ .flags = CFTYPE_ONLY_ON_ROOT,
+ },
+#endif
{ } /* Zero entry terminates. */
};
@@ -882,4 +1031,7 @@ struct cgroup_subsys dmem_cgrp_subsys = {
.css_offline = dmemcs_offline,
.legacy_cftypes = files,
.dfl_cftypes = files,
+#ifdef CONFIG_MEMCG
+ .depends_on = 1 << memory_cgrp_id,
+#endif
};
--
2.52.0
^ permalink raw reply related
* [PATCH v2] tpm: tpm_tis: Add optional delay after relinquish
From: Jim Broadus @ 2026-05-19 15:45 UTC (permalink / raw)
To: linux-integrity, linux-kernel, linux-doc
Cc: peterhuewe, jarkko, jgg, Jim Broadus
Some TPMs fail to grant locality when requested immediately after being
relinquished. In this case, the TPM_ACCESS_REQUEST_USE bit of the
TPM_ACCESS register is cleared immediately without setting
TPM_ACCESS_ACTIVE_LOCALITY.
This issue can be seen at boot since tpm_chip_start, called right
after locality is relinquished, fails. This causes the probe to fail:
tpm_tis MSFT0101:00: probe with driver tpm_tis failed with error -1
This occurs on some older Dell Latitudes and maybe others. To work
around this, add a "settle" boolean param to tpm_tis. When this is
enabled, a delay is added after locality is relinquished.
Signed-off-by: Jim Broadus <jbroadus@gmail.com>
---
Documentation/admin-guide/kernel-parameters.txt | 7 +++++++
drivers/char/tpm/tpm_tis.c | 7 +++++++
drivers/char/tpm/tpm_tis_core.c | 3 +++
drivers/char/tpm/tpm_tis_core.h | 1 +
4 files changed, 18 insertions(+)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 4d0f545fb3ec..5b7111033fbb 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -7651,6 +7651,13 @@ Kernel parameters
defined by Trusted Computing Group (TCG) see
https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/
+ tpm_tis.settle= [HW,TPM]
+ Format: <bool>
+ When enabled, this adds a delay after locality is
+ relinquished. Some TPMs will fail to grant locality if
+ requested immediately after being relinquished. This
+ causes the probe to fail.
+
tp_printk [FTRACE]
Have the tracepoints sent to printk as well as the
tracing ring buffer. This is useful for early boot up
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 9aa230a63616..8ac0ea78570e 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -101,6 +101,10 @@ module_param(force, bool, 0444);
MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
#endif
+static bool settle;
+module_param(settle, bool, 0444);
+MODULE_PARM_DESC(settle, "Add settle time after relinquish");
+
#if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
static int has_hid(struct acpi_device *dev, const char *hid)
{
@@ -242,6 +246,9 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info)
if (itpm || is_itpm(ACPI_COMPANION(dev)))
set_bit(TPM_TIS_ITPM_WORKAROUND, &phy->priv.flags);
+ if (settle)
+ set_bit(TPM_TIS_SETTLE_AFTER_RELINQUISH, &phy->priv.flags);
+
return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg,
ACPI_HANDLE(dev));
}
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 21d79ad3b164..fbeee085098e 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -171,6 +171,9 @@ static int __tpm_tis_relinquish_locality(struct tpm_tis_data *priv, int l)
{
tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY);
+ if (test_bit(TPM_TIS_SETTLE_AFTER_RELINQUISH, &priv->flags))
+ tpm_msleep(TPM_TIMEOUT);
+
return 0;
}
diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
index 6c3aa480396b..413cac5e0f31 100644
--- a/drivers/char/tpm/tpm_tis_core.h
+++ b/drivers/char/tpm/tpm_tis_core.h
@@ -90,6 +90,7 @@ enum tpm_tis_flags {
TPM_TIS_DEFAULT_CANCELLATION = 2,
TPM_TIS_IRQ_TESTED = 3,
TPM_TIS_STATUS_VALID_RETRY = 4,
+ TPM_TIS_SETTLE_AFTER_RELINQUISH = 5,
};
struct tpm_tis_data {
--
2.54.0
^ permalink raw reply related
* [PATCH v3 2/2] iio: dac: Add AD5529R DAC driver support
From: Janani Sunil @ 2026-05-19 15:42 UTC (permalink / raw)
To: Lars-Peter Clausen, Michael Hennerich, Jonathan Cameron,
David Lechner, Nuno Sá, Andy Shevchenko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel, Jonathan Corbet,
Shuah Khan
Cc: linux-iio, devicetree, linux-kernel, linux-doc, Janani Sunil,
Janani Sunil
In-Reply-To: <20260519-ad5529r-driver-v3-0-267c0731aa68@analog.com>
Add support for AD5529R 16-channel, 12/16 bit Digital to Analog Converter
Signed-off-by: Janani Sunil <janani.sunil@analog.com>
---
MAINTAINERS | 1 +
drivers/iio/dac/Kconfig | 17 ++
drivers/iio/dac/Makefile | 1 +
drivers/iio/dac/ad5529r.c | 527 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 546 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 320e84765ce6..143714e27d51 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1513,6 +1513,7 @@ L: linux-iio@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/dac/adi,ad5529r.yaml
+F: drivers/iio/dac/ad5529r.c
ANALOG DEVICES INC AD5706R DRIVER
M: Alexis Czezar Torreno <alexisczezar.torreno@analog.com>
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 657c68e75542..bb1d59889a2a 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -134,6 +134,23 @@ config AD5449
To compile this driver as a module, choose M here: the
module will be called ad5449.
+config AD5529R
+ tristate "Analog Devices AD5529R High Voltage DAC driver"
+ depends on SPI_MASTER
+ select REGMAP_SPI
+ help
+ Say yes here to build support for Analog Devices AD5529R
+ 16-Channel, 12-Bit/16-Bit, 40V High Voltage Precision Digital to Analog
+ Converter.
+
+ The device features multiple output voltage ranges from -20V to +20V,
+ built-in 4.096V voltage reference, and digital functions including
+ toggle, dither, and ramp modes. Supports both 12-bit and 16-bit
+ resolution variants.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad5529r.
+
config AD5592R_BASE
tristate
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 003431798498..f35e060b3643 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_AD5446) += ad5446.o
obj-$(CONFIG_AD5446_SPI) += ad5446-spi.o
obj-$(CONFIG_AD5446_I2C) += ad5446-i2c.o
obj-$(CONFIG_AD5449) += ad5449.o
+obj-$(CONFIG_AD5529R) += ad5529r.o
obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o
obj-$(CONFIG_AD5592R) += ad5592r.o
obj-$(CONFIG_AD5593R) += ad5593r.o
diff --git a/drivers/iio/dac/ad5529r.c b/drivers/iio/dac/ad5529r.c
new file mode 100644
index 000000000000..9bb63030db95
--- /dev/null
+++ b/drivers/iio/dac/ad5529r.c
@@ -0,0 +1,527 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AD5529R Digital-to-Analog Converter Driver
+ * 16-Channel, 12/16-Bit, 40V High Voltage Precision DAC
+ *
+ * Copyright 2026 Analog Devices Inc.
+ * Author: Janani Sunil <janani.sunil@analog.com>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/iio/iio.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/spi/spi.h>
+
+#define AD5529R_REG_INTERFACE_CONFIG_A 0x00
+#define AD5529R_REG_DEVICE_CONFIG 0x02
+#define AD5529R_REG_CHIP_GRADE 0x06
+#define AD5529R_REG_SCRATCH_PAD 0x0A
+#define AD5529R_REG_SPI_REVISION 0x0B
+#define AD5529R_REG_VENDOR_H 0x0D
+#define AD5529R_REG_STREAM_MODE 0x0E
+#define AD5529R_REG_INTERFACE_STATUS_A 0x11
+#define AD5529R_REG_MULTI_DAC_CH_SEL 0x14
+#define AD5529R_REG_OUT_RANGE_BASE 0x3C
+#define AD5529R_REG_OUT_RANGE(ch) (AD5529R_REG_OUT_RANGE_BASE + (ch) * 2)
+#define AD5529R_REG_DAC_INPUT_A_BASE 0x148
+#define AD5529R_REG_DAC_INPUT_A(ch) (AD5529R_REG_DAC_INPUT_A_BASE + (ch) * 2)
+#define AD5529R_REG_DAC_DATA_READBACK_BASE 0x16A
+#define AD5529R_REG_TSENS_ALERT_FLAG 0x18C
+#define AD5529R_REG_TSENS_SHTD_FLAG 0x18E
+#define AD5529R_REG_FUNC_BUSY 0x1A0
+#define AD5529R_REG_REF_SEL 0x1A2
+#define AD5529R_REG_INIT_CRC_ERR_STAT 0x1A4
+#define AD5529R_REG_MULTI_DAC_HOTPATH_SW_LDAC 0x1A8
+
+#define AD5529R_INTERFACE_CONFIG_A_SW_RESET (BIT(7) | BIT(0))
+#define AD5529R_INTERFACE_CONFIG_A_ADDR_ASCENSION BIT(5)
+#define AD5529R_INTERFACE_CONFIG_A_SDO_ENABLE BIT(4)
+#define AD5529R_REF_SEL_MASK BIT(0)
+#define AD5529R_MAX_REGISTER 0x232
+#define AD5529R_8BIT_REG_MAX 0x13
+#define AD5529R_SPI_READ_FLAG 0x80
+
+struct ad5529r_model_data {
+ const char *model_name;
+ unsigned int resolution;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+};
+
+#define AD5529R_DAC_CHANNEL(chan, bits) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .output = 1, \
+ .channel = (chan), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+ .scan_type = { \
+ .format = 'u', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ }, \
+}
+
+static const char * const ad5529r_supply_names[] = {
+ "vdd",
+ "avdd",
+ "hvdd",
+};
+
+static const struct iio_chan_spec ad5529r_channels_16bit[] = {
+ AD5529R_DAC_CHANNEL(0, 16),
+ AD5529R_DAC_CHANNEL(1, 16),
+ AD5529R_DAC_CHANNEL(2, 16),
+ AD5529R_DAC_CHANNEL(3, 16),
+ AD5529R_DAC_CHANNEL(4, 16),
+ AD5529R_DAC_CHANNEL(5, 16),
+ AD5529R_DAC_CHANNEL(6, 16),
+ AD5529R_DAC_CHANNEL(7, 16),
+ AD5529R_DAC_CHANNEL(8, 16),
+ AD5529R_DAC_CHANNEL(9, 16),
+ AD5529R_DAC_CHANNEL(10, 16),
+ AD5529R_DAC_CHANNEL(11, 16),
+ AD5529R_DAC_CHANNEL(12, 16),
+ AD5529R_DAC_CHANNEL(13, 16),
+ AD5529R_DAC_CHANNEL(14, 16),
+ AD5529R_DAC_CHANNEL(15, 16),
+};
+
+static const struct iio_chan_spec ad5529r_channels_12bit[] = {
+ AD5529R_DAC_CHANNEL(0, 12),
+ AD5529R_DAC_CHANNEL(1, 12),
+ AD5529R_DAC_CHANNEL(2, 12),
+ AD5529R_DAC_CHANNEL(3, 12),
+ AD5529R_DAC_CHANNEL(4, 12),
+ AD5529R_DAC_CHANNEL(5, 12),
+ AD5529R_DAC_CHANNEL(6, 12),
+ AD5529R_DAC_CHANNEL(7, 12),
+ AD5529R_DAC_CHANNEL(8, 12),
+ AD5529R_DAC_CHANNEL(9, 12),
+ AD5529R_DAC_CHANNEL(10, 12),
+ AD5529R_DAC_CHANNEL(11, 12),
+ AD5529R_DAC_CHANNEL(12, 12),
+ AD5529R_DAC_CHANNEL(13, 12),
+ AD5529R_DAC_CHANNEL(14, 12),
+ AD5529R_DAC_CHANNEL(15, 12),
+};
+
+static const struct ad5529r_model_data ad5529r_16bit_model_data = {
+ .model_name = "ad5529r-16",
+ .resolution = 16,
+ .channels = ad5529r_channels_16bit,
+ .num_channels = ARRAY_SIZE(ad5529r_channels_16bit),
+};
+
+static const struct ad5529r_model_data ad5529r_12bit_model_data = {
+ .model_name = "ad5529r-12",
+ .resolution = 12,
+ .channels = ad5529r_channels_12bit,
+ .num_channels = ARRAY_SIZE(ad5529r_channels_12bit),
+};
+
+enum ad5529r_output_range {
+ AD5529R_RANGE_0V_5V,
+ AD5529R_RANGE_0V_10V,
+ AD5529R_RANGE_0V_20V,
+ AD5529R_RANGE_0V_40V,
+ AD5529R_RANGE_NEG5V_5V,
+ AD5529R_RANGE_NEG10V_10V,
+ AD5529R_RANGE_NEG15V_15V,
+ AD5529R_RANGE_NEG20V_20V,
+};
+
+static const s32 ad5529r_output_ranges_mv[8][2] = {
+ [AD5529R_RANGE_0V_5V] = { 0, 5000 },
+ [AD5529R_RANGE_0V_10V] = { 0, 10000 },
+ [AD5529R_RANGE_0V_20V] = { 0, 20000 },
+ [AD5529R_RANGE_0V_40V] = { 0, 40000 },
+ [AD5529R_RANGE_NEG5V_5V] = { -5000, 5000 },
+ [AD5529R_RANGE_NEG10V_10V] = { -10000, 10000 },
+ [AD5529R_RANGE_NEG15V_15V] = { -15000, 15000 },
+ [AD5529R_RANGE_NEG20V_20V] = { -20000, 20000 },
+};
+
+struct ad5529r_state {
+ struct spi_device *spi;
+ const struct ad5529r_model_data *model_data;
+ struct regmap *regmap_8bit;
+ struct regmap *regmap_16bit;
+ struct regulator *vref_regulator;
+ enum ad5529r_output_range output_range_idx[16];
+};
+
+static const struct regmap_range ad5529r_8bit_readable_ranges[] = {
+ regmap_reg_range(AD5529R_REG_INTERFACE_CONFIG_A, AD5529R_REG_CHIP_GRADE),
+ regmap_reg_range(AD5529R_REG_SCRATCH_PAD, AD5529R_REG_VENDOR_H),
+ regmap_reg_range(AD5529R_REG_STREAM_MODE, AD5529R_REG_INTERFACE_STATUS_A),
+};
+
+static const struct regmap_range ad5529r_16bit_readable_ranges[] = {
+ regmap_reg_range(AD5529R_REG_MULTI_DAC_CH_SEL, AD5529R_REG_INIT_CRC_ERR_STAT),
+ regmap_reg_range(AD5529R_REG_MULTI_DAC_HOTPATH_SW_LDAC, AD5529R_MAX_REGISTER),
+};
+
+static const struct regmap_access_table ad5529r_8bit_readable_table = {
+ .yes_ranges = ad5529r_8bit_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ad5529r_8bit_readable_ranges),
+};
+
+static const struct regmap_access_table ad5529r_16bit_readable_table = {
+ .yes_ranges = ad5529r_16bit_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ad5529r_16bit_readable_ranges),
+};
+
+static const struct regmap_range ad5529r_8bit_read_only_ranges[] = {
+ regmap_reg_range(AD5529R_REG_DEVICE_CONFIG, AD5529R_REG_CHIP_GRADE),
+ regmap_reg_range(AD5529R_REG_SPI_REVISION, AD5529R_REG_VENDOR_H),
+};
+
+static const struct regmap_range ad5529r_16bit_read_only_ranges[] = {
+ regmap_reg_range(AD5529R_REG_DAC_DATA_READBACK_BASE,
+ (AD5529R_REG_DAC_DATA_READBACK_BASE + 15 * 2)),
+ regmap_reg_range(AD5529R_REG_TSENS_ALERT_FLAG, AD5529R_REG_TSENS_SHTD_FLAG),
+ regmap_reg_range(AD5529R_REG_FUNC_BUSY, AD5529R_REG_FUNC_BUSY),
+ regmap_reg_range(AD5529R_REG_INIT_CRC_ERR_STAT, AD5529R_REG_INIT_CRC_ERR_STAT),
+};
+
+static const struct regmap_access_table ad5529r_8bit_writeable_table = {
+ .no_ranges = ad5529r_8bit_read_only_ranges,
+ .n_no_ranges = ARRAY_SIZE(ad5529r_8bit_read_only_ranges),
+};
+
+static const struct regmap_access_table ad5529r_16bit_writeable_table = {
+ .no_ranges = ad5529r_16bit_read_only_ranges,
+ .n_no_ranges = ARRAY_SIZE(ad5529r_16bit_read_only_ranges),
+};
+
+static const struct regmap_config ad5529r_regmap_8bit_config = {
+ .name = "ad5529r-8bit",
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = AD5529R_8BIT_REG_MAX,
+ .read_flag_mask = AD5529R_SPI_READ_FLAG,
+ .rd_table = &ad5529r_8bit_readable_table,
+ .wr_table = &ad5529r_8bit_writeable_table,
+};
+
+static const struct regmap_config ad5529r_regmap_16bit_config = {
+ .name = "ad5529r-16bit",
+ .reg_bits = 16,
+ .val_bits = 16,
+ .max_register = AD5529R_MAX_REGISTER,
+ .read_flag_mask = AD5529R_SPI_READ_FLAG,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+ .rd_table = &ad5529r_16bit_readable_table,
+ .wr_table = &ad5529r_16bit_writeable_table,
+ .reg_stride = 2,
+};
+
+static struct regmap *ad5529r_get_regmap(struct ad5529r_state *st,
+ unsigned int reg)
+{
+ if (reg <= AD5529R_8BIT_REG_MAX)
+ return st->regmap_8bit;
+
+ return st->regmap_16bit;
+}
+
+static int ad5529r_reset(struct ad5529r_state *st)
+{
+ struct reset_control *rst;
+ int ret;
+
+ rst = devm_reset_control_get_optional_exclusive(&st->spi->dev, NULL);
+ if (IS_ERR(rst))
+ return PTR_ERR(rst);
+
+ if (rst) {
+ ret = reset_control_deassert(rst);
+ if (ret)
+ return ret;
+ } else {
+ ret = regmap_write(st->regmap_8bit, AD5529R_REG_INTERFACE_CONFIG_A,
+ AD5529R_INTERFACE_CONFIG_A_SW_RESET);
+ if (ret)
+ return ret;
+ }
+
+ fsleep(10000);
+
+ return regmap_write(st->regmap_8bit, AD5529R_REG_INTERFACE_CONFIG_A,
+ AD5529R_INTERFACE_CONFIG_A_SDO_ENABLE |
+ AD5529R_INTERFACE_CONFIG_A_ADDR_ASCENSION);
+}
+
+static int ad5529r_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct ad5529r_state *st = iio_priv(indio_dev);
+ unsigned int reg_addr, reg_val_h;
+ int ret, range_idx, span_mv;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ reg_addr = AD5529R_REG_DAC_INPUT_A(chan->channel);
+ ret = regmap_read(st->regmap_16bit, reg_addr, ®_val_h);
+ if (ret)
+ return ret;
+
+ *val = reg_val_h;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ range_idx = st->output_range_idx[chan->channel];
+
+ span_mv = ad5529r_output_ranges_mv[range_idx][1] -
+ ad5529r_output_ranges_mv[range_idx][0];
+ *val = span_mv;
+ *val2 = st->model_data->resolution;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_OFFSET:
+ range_idx = st->output_range_idx[chan->channel];
+
+ if (ad5529r_output_ranges_mv[range_idx][0] < 0)
+ *val = -(1 << (st->model_data->resolution - 1));
+ else
+ *val = 0;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad5529r_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ad5529r_state *st = iio_priv(indio_dev);
+ unsigned int reg_addr;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (val < 0 || val > GENMASK(st->model_data->resolution - 1, 0))
+ return -EINVAL;
+
+ reg_addr = AD5529R_REG_DAC_INPUT_A(chan->channel);
+
+ return regmap_write(st->regmap_16bit, reg_addr, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad5529r_find_output_range(const s32 *vals)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ad5529r_output_ranges_mv); i++) {
+ if (vals[0] == ad5529r_output_ranges_mv[i][0] * 1000 &&
+ vals[1] == ad5529r_output_ranges_mv[i][1] * 1000)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int ad5529r_parse_channel_ranges(struct device *dev,
+ struct ad5529r_state *st)
+{
+ int ret, ch, range_idx;
+ s32 vals[2];
+
+ device_for_each_child_node_scoped(dev, child) {
+ range_idx = AD5529R_RANGE_0V_5V;
+
+ ret = fwnode_property_read_u32(child, "reg", &ch);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Missing reg property in channel node\n");
+
+ if (ch >= 16)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid channel number: %d\n", ch);
+
+ if (!fwnode_property_read_u32_array(child,
+ "adi,output-range-microvolt",
+ vals, 2)) {
+ range_idx = ad5529r_find_output_range(vals);
+ if (range_idx < 0)
+ return dev_err_probe(dev, range_idx,
+ "Invalid range [%d %d] for ch %d\n",
+ vals[0], vals[1], ch);
+ }
+
+ st->output_range_idx[ch] = range_idx;
+ ret = regmap_write(st->regmap_16bit,
+ AD5529R_REG_OUT_RANGE(ch), range_idx);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to configure range for ch %d\n",
+ ch);
+ }
+
+ return 0;
+}
+
+static int ad5529r_debugfs_reg_read(struct ad5529r_state *st, unsigned int reg,
+ unsigned int *val)
+{
+ return regmap_read(ad5529r_get_regmap(st, reg), reg, val);
+}
+
+static int ad5529r_debugfs_reg_write(struct ad5529r_state *st, unsigned int reg,
+ unsigned int val)
+{
+ return regmap_write(ad5529r_get_regmap(st, reg), reg, val);
+}
+
+static int ad5529r_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg,
+ unsigned int writeval,
+ unsigned int *readval)
+{
+ struct ad5529r_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return ad5529r_debugfs_reg_read(st, reg, readval);
+
+ return ad5529r_debugfs_reg_write(st, reg, writeval);
+}
+
+static void ad5529r_disable_regulator(void *regulator)
+{
+ regulator_disable(regulator);
+}
+
+static const struct iio_info ad5529r_info = {
+ .read_raw = ad5529r_read_raw,
+ .write_raw = ad5529r_write_raw,
+ .debugfs_reg_access = ad5529r_reg_access,
+};
+
+static int ad5529r_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct iio_dev *indio_dev;
+ struct ad5529r_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ st->spi = spi;
+
+ st->model_data = spi_get_device_match_data(spi);
+ if (!st->model_data)
+ return dev_err_probe(dev, -EINVAL, "Failed to identify device variant\n");
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad5529r_supply_names),
+ ad5529r_supply_names);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get and enable regulators\n");
+
+ ret = devm_regulator_get_enable_optional(dev, "hvss");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get and enable hvss regulator\n");
+
+ st->vref_regulator = devm_regulator_get_optional(dev, "vref");
+ if (IS_ERR(st->vref_regulator)) {
+ if (PTR_ERR(st->vref_regulator) != -ENODEV)
+ return dev_err_probe(dev, PTR_ERR(st->vref_regulator),
+ "Failed to get vref regulator\n");
+ st->vref_regulator = NULL;
+ }
+
+ if (st->vref_regulator) {
+ ret = regulator_enable(st->vref_regulator);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable vref regulator\n");
+
+ ret = devm_add_action_or_reset(dev, ad5529r_disable_regulator,
+ st->vref_regulator);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to add vref regulator cleanup\n");
+ }
+
+ st->regmap_8bit = devm_regmap_init_spi(spi, &ad5529r_regmap_8bit_config);
+ if (IS_ERR(st->regmap_8bit))
+ return dev_err_probe(dev, PTR_ERR(st->regmap_8bit),
+ "Failed to initialize 8-bit regmap\n");
+
+ st->regmap_16bit = devm_regmap_init_spi(spi, &ad5529r_regmap_16bit_config);
+ if (IS_ERR(st->regmap_16bit))
+ return dev_err_probe(dev, PTR_ERR(st->regmap_16bit),
+ "Failed to initialize 16-bit regmap\n");
+
+ ret = ad5529r_reset(st);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to reset device\n");
+
+ ret = regmap_update_bits(st->regmap_16bit, AD5529R_REG_REF_SEL,
+ AD5529R_REF_SEL_MASK,
+ st->vref_regulator ? 0 : AD5529R_REF_SEL_MASK);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to configure reference\n");
+
+ ret = ad5529r_parse_channel_ranges(dev, st);
+ if (ret)
+ return ret;
+
+ indio_dev->name = st->model_data->model_name;
+ indio_dev->info = &ad5529r_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = st->model_data->channels;
+ indio_dev->num_channels = st->model_data->num_channels;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id ad5529r_of_match[] = {
+ { .compatible = "adi,ad5529r-16", .data = &ad5529r_16bit_model_data },
+ { .compatible = "adi,ad5529r-12", .data = &ad5529r_12bit_model_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad5529r_of_match);
+
+static const struct spi_device_id ad5529r_id[] = {
+ { "ad5529r-16", .driver_data = (kernel_ulong_t)&ad5529r_16bit_model_data },
+ { "ad5529r-12", .driver_data = (kernel_ulong_t)&ad5529r_12bit_model_data },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad5529r_id);
+
+static struct spi_driver ad5529r_driver = {
+ .driver = {
+ .name = "ad5529r",
+ .of_match_table = ad5529r_of_match,
+ },
+ .probe = ad5529r_probe,
+ .id_table = ad5529r_id,
+};
+module_spi_driver(ad5529r_driver);
+
+MODULE_AUTHOR("Janani Sunil <janani.sunil@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD5529R 12/16-bit DAC driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related
* [PATCH v3 1/2] dt-bindings: iio: dac: Add AD5529R
From: Janani Sunil @ 2026-05-19 15:42 UTC (permalink / raw)
To: Lars-Peter Clausen, Michael Hennerich, Jonathan Cameron,
David Lechner, Nuno Sá, Andy Shevchenko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel, Jonathan Corbet,
Shuah Khan
Cc: linux-iio, devicetree, linux-kernel, linux-doc, Janani Sunil,
Janani Sunil
In-Reply-To: <20260519-ad5529r-driver-v3-0-267c0731aa68@analog.com>
Devicetree bindings for AD5529R 16 channel 12/16 bit high voltage,
buffered voltage output digital-to-analog converter (DAC) with an
integrated precision reference.
Signed-off-by: Janani Sunil <janani.sunil@analog.com>
---
.../devicetree/bindings/iio/dac/adi,ad5529r.yaml | 217 +++++++++++++++++++++
MAINTAINERS | 7 +
2 files changed, 224 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5529r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5529r.yaml
new file mode 100644
index 000000000000..eb66f6ca063d
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5529r.yaml
@@ -0,0 +1,217 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5529r.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5529R 16-Channel 12/16-bit High Voltage DAC
+
+maintainers:
+ - Janani Sunil <janani.sunil@analog.com>
+
+description: |
+ The AD5529R is a 16-channel, 12-bit or 16-bit, high voltage, buffered voltage output
+ digital-to-analog converter (DAC) with an integrated precision reference.
+ The device operates from unipolar and bipolar supplies. It is guaranteed
+ monotonic and has built-in rail-to-rail output buffers that can source or
+ sink up to 25mA.
+
+ Specifications:
+ * 16 independent 12-bit or 16-bit DAC channels
+ * Independently programmable output ranges: 0V to 5V, 0V to 10V, 0V to 20V,
+ 0V to 40V, ±5V, ±10V, ±15V, and ±20V
+ * The device supports SPI communication with Mode 0 and Mode 3.
+ * 4.096V precision reference, 12ppm/°C maximum
+ * Built-in function generation: Toggle, Sinusoidal Dither, and Ramp waveforms
+ * Multiplexer for output voltage, load current sense and die temperature
+
+ Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ad5529r.pdf
+
+properties:
+ compatible:
+ enum:
+ - adi,ad5529r-16 # 16-bit variant
+ - adi,ad5529r-12 # 12-bit variant
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency:
+ maximum: 25000000
+ description:
+ Maximum SPI frequency. The device supports SPI Mode 0 and Mode 3.
+ Read operations are limited to 25MHz maximum.
+
+ reset-gpios:
+ maxItems: 1
+ description:
+ GPIO connected to the RESET pin. Active low. When asserted low,
+ performs a power-on reset and initializes the device to its default state.
+
+ clear-gpios:
+ maxItems: 1
+ description:
+ GPIO connected to the CLEAR pin. Active low. When asserted low,
+ clears all DAC data registers without affecting configuration settings.
+
+ interrupts:
+ maxItems: 1
+ description:
+ Interrupt connected to the ALARM pin. Active low interrupt output
+ for overtemperature conditions, SPI CRC errors, and function completion.
+
+ tg0-gpios:
+ maxItems: 1
+ description:
+ GPIO connected to the TG0 toggle pin. Pulsing this pin allows all
+ selected DACs to be updated synchronously for coordinated output changes.
+
+ tg1-gpios:
+ maxItems: 1
+ description:
+ GPIO connected to the TG1 toggle pin. Pulsing this pin allows all
+ selected DACs to be updated synchronously for coordinated output changes.
+
+ tg2-gpios:
+ maxItems: 1
+ description:
+ GPIO connected to the TG2 toggle pin. Pulsing this pin allows all
+ selected DACs to be updated synchronously for coordinated output changes.
+
+ tg3-gpios:
+ maxItems: 1
+ description:
+ GPIO connected to the TG3 toggle pin. Pulsing this pin allows all
+ selected DACs to be updated synchronously for coordinated output changes.
+
+ io-channels:
+ maxItems: 1
+ description:
+ ADC channel connected to the MUXOUT pin for monitoring output voltage,
+ load current sense, and die temperature.
+
+ io-channel-names:
+ const: muxout
+
+ vdd-supply:
+ description: Digital power supply (1.08V to 1.98V)
+
+ avdd-supply:
+ description: Analog power supply (4.75V to 5.25V)
+
+ hvdd-supply:
+ description:
+ High voltage positive supply (7V to 45V). Supply voltage should be chosen
+ based on configured output ranges (see datasheet Table 9).
+
+ hvss-supply:
+ description:
+ High voltage negative supply (-22.5V to 0V). Required only when using bipolar
+ output ranges (±5V, ±10V, ±15V, ±20V). Supply voltage should be
+ chosen based on configured output ranges (see datasheet Table 9).
+
+ vref-supply:
+ description:
+ External voltage reference supply (4.056V to 4.136V, typically 4.096V).
+ When specified, the device uses external reference mode and the VREF pin becomes an
+ input. The device uses the internal 4.096V precision reference otherwise.
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+patternProperties:
+ "^channel@([0-9]|1[0-5])$":
+ type: object
+ description: Child nodes for individual channel configuration
+
+ properties:
+ reg:
+ description: Channel number.
+ minimum: 0
+ maximum: 15
+
+ adi,output-range-microvolt:
+ description: |
+ Output voltage range for this channel as [min, max] in microvolts.
+ If not specified, defaults to 0V to 5V range.
+ oneOf:
+ - items:
+ - const: 0
+ - enum: [5000000, 10000000, 20000000, 40000000]
+ - items:
+ - const: -5000000
+ - const: 5000000
+ - items:
+ - const: -10000000
+ - const: 10000000
+ - items:
+ - const: -15000000
+ - const: 15000000
+ - items:
+ - const: -20000000
+ - const: 20000000
+
+ required:
+ - reg
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+ - avdd-supply
+ - hvdd-supply
+
+dependencies:
+ spi-cpha: [ spi-cpol ]
+ spi-cpol: [ spi-cpha ]
+
+allOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dac@0 {
+ compatible = "adi,ad5529r-16";
+ reg = <0>;
+ spi-max-frequency = <25000000>;
+
+ vdd-supply = <&vdd_regulator>;
+ avdd-supply = <&avdd_regulator>;
+ hvdd-supply = <&hvdd_regulator>;
+ hvss-supply = <&hvss_regulator>;
+
+ reset-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ channel@0 {
+ reg = <0>;
+ adi,output-range-microvolt = <0 5000000>;
+ };
+
+ channel@1 {
+ reg = <1>;
+ adi,output-range-microvolt = <(-10000000) 10000000>;
+ };
+
+ channel@2 {
+ reg = <2>;
+ adi,output-range-microvolt = <0 40000000>;
+ };
+ };
+ };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index d6c3c7d22403..320e84765ce6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1507,6 +1507,13 @@ W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/adc/adi,ad4851.yaml
F: drivers/iio/adc/ad4851.c
+ANALOG DEVICES INC AD5529R DRIVER
+M: Janani Sunil <janani.sunil@analog.com>
+L: linux-iio@vger.kernel.org
+S: Supported
+W: https://ez.analog.com/linux-software-drivers
+F: Documentation/devicetree/bindings/iio/dac/adi,ad5529r.yaml
+
ANALOG DEVICES INC AD5706R DRIVER
M: Alexis Czezar Torreno <alexisczezar.torreno@analog.com>
L: linux-iio@vger.kernel.org
--
2.43.0
^ permalink raw reply related
* [PATCH v3 0/2] iio: dac: Add support for AD5529R DAC
From: Janani Sunil @ 2026-05-19 15:42 UTC (permalink / raw)
To: Lars-Peter Clausen, Michael Hennerich, Jonathan Cameron,
David Lechner, Nuno Sá, Andy Shevchenko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel, Jonathan Corbet,
Shuah Khan
Cc: linux-iio, devicetree, linux-kernel, linux-doc, Janani Sunil,
Janani Sunil
This patch series adds support for Analog Devices AD5529R, a 16 channel
16 and 12 bit voltage Digital-to-Analog Converter (DAC) with integrated
precision reference. The AD5529R operates from both unipolar and
bipolar supplies. The device communicates via SPI interface.
**Device Overview:**
The AD5529R features 16 independent DAC channels, with 16 or 12 bit
resolution, allowing independently programmable output ranges. The
internal 4.096V precision reference sets the accuracy of the output
voltage.
**Features Implemented:**
- Automatic detection of 12/16 bit variant with product ID read.
- Reset support via GPIO.
- Dual regmap configuration to handle 8 and 16 bit registers.
**Patch Summary:**
1. **dt-bindings**: Binding documentation with channel configuration.
2. **driver**: Implement IIO DAC Driver with regmap support.
**Testing:**
The driver was compiled and tested on the EVAL-AD5529R-ARDZ using a
coraZ7 with a mainline v7.0 kernel.
**Driver Rationale:**
AD5529R introduces:
1. A unique register layout
2. Mixed 8-bit and 16-bit register accesses
3. Product ID based generic identification
4. Hardware specific features like function generators, multi-die
hotpath registers etc.
The device warrants its own drivers due to these fundamental
architectural differences, that would require substantial changes to
existing drivers without providing reusable benefits. The standalone
driver also allows future extensions for related devices in the same
family.
Signed-off-by: Janani Sunil <janani.sunil@analog.com>
---
Changes in v3:
- Split into adi,ad5529r-16 and adi,ad5529r-12 device tree compatibles
- Add DT-based output range configuration via adi,output-range-microvolt
- Expand DT binding: vref-supply, clear/tg GPIOs, interrupts, muxout
- Correct power supply voltage specifications as per datasheet
- Reduce SPI frequency limit to 25MHz as per datasheet specs
- Switch to autoincrement addressing mode, remove +1 register offsets
- Use DT match data instead of device ID detection for fallback support
- Implement dynamic scale/offset calculation per configured channel range
- Added explicit val_format_endian and reg_stride for 16-bit regmap bus
- Code cleanup: alphabetical includes, ARRAY_SIZE(), unused defines
- Minor: .sign→.format field, simplify read/write order, optional hvss-supply
- Remove redundant driver documentation ad5529r.rst
- Link to v2: https://lore.kernel.org/r/20260508-ad5529r-driver-v2-0-e315441685d7@analog.com
Changes in v2:
- Fix IIO scale to use millivolts per ABI requirement
- Fix documentation voltage calculations (2.5V not 2.048V)
- Fix bipolar ranges in documentation (±5V, ±10V, ±15V, ±20V)
- Fix alphabetical ordering in documentation index
- Add missing newline to documentation file
- Fix scale units description (millivolts not microvolts)
- Include a section for driver rationale in the cover letter
- Reword contents in cover letter 12/16 bit generic->variant
- Add dependency array for spi-cpha and spi-cpol properties
- Link to v1: https://lore.kernel.org/r/20260507-ad5529r-driver-v1-0-b4460f3cb44f@analog.com
---
Janani Sunil (2):
dt-bindings: iio: dac: Add AD5529R
iio: dac: Add AD5529R DAC driver support
.../devicetree/bindings/iio/dac/adi,ad5529r.yaml | 217 +++++++++
MAINTAINERS | 8 +
drivers/iio/dac/Kconfig | 17 +
drivers/iio/dac/Makefile | 1 +
drivers/iio/dac/ad5529r.c | 527 +++++++++++++++++++++
5 files changed, 770 insertions(+)
---
base-commit: 93df88612859e8e19dec93c69d563b4b73e9bd4b
change-id: 20260507-ad5529r-driver-866bbdd864de
Best regards,
--
Janani Sunil <janani.sunil@analog.com>
^ permalink raw reply
* Re: [PATCH 00/12] misc/syncobj: add /dev/syncobj device
From: Xaver Hugl @ 2026-05-19 15:31 UTC (permalink / raw)
To: Christian König
Cc: Julian Orth, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Sumit Semwal, Jonathan Corbet,
Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman, dri-devel,
linux-kernel, linux-media, linaro-mm-sig, linux-doc,
wayland-devel, Michel Dänzer
In-Reply-To: <5ee6d5af-ac48-41d7-a19f-e08a3c5b7d19@amd.com>
Am Di., 19. Mai 2026 um 15:29 Uhr schrieb Christian König
<christian.koenig@amd.com>:
> > 1. This series makes the ability to manipulate syncobjs available
> > independently of attached hardware.
> > 2. It makes it available under a consistent path /dev/syncobj.
>
> Exactly that is a big no-go. This has to be under /dev/dri.
FWIW udmabuf is also under /dev directly, but I don't think any
compositor developer would complain about a different path.
What are the rules for that? Could this simply be put in /dev/dri/syncobj?
The part where we get this independent of attached hardware is quite
important for us though, since we can't just ignore explicit sync once
the device we previously imported the syncobj into is disconnected.
Buffers can be from any device or allocated in system memory and
access should be synchronized properly in all cases.
How exactly it's made available isn't all that critical.
> > 3. It removes the need to translate between syncobjs fds and handles.
>
> That's a pretty big no-go as well. The differentiation between FDs and handles is completely intentional.
Could you expand on why it's needed? For compositors, the handle is
just an intermediary thing when translating between file descriptors.
FTR for me at least, this part would be merely nice to have, since it
slightly reduces the amount of ioctls a compositor needs to call, but
it's not important.
> >> What about using VGEM for this?
> >
> > If the vgem render node were made available unconditionally under,
>
> Software rendering is a complete corner case, I don't think that this will be enabled by default.
That simply makes vgem unsuitable for solving the problems we face in
compositors.
- Xaver
^ permalink raw reply
* Re: [PATCH v3 0/5] Support the FEAT_HDBSS introduced in Armv9.5
From: Leonardo Bras @ 2026-05-19 15:35 UTC (permalink / raw)
To: Will Deacon
Cc: Leonardo Bras, maz, oupton, catalin.marinas, corbet, pbonzini,
Tian Zheng, kernel-team, yuzenghui, wangzhou1, liuyonglong,
yezhenyu2, linuxarm, joey.gouly, kvmarm, kvm, linux-arm-kernel,
linux-doc, linux-kernel, skhan, suzuki.poulose, Jonathan Cameron
In-Reply-To: <177918656142.736362.17906576792384645789.b4-ty@kernel.org>
On Tue, May 19, 2026 at 04:23:12PM +0100, Will Deacon wrote:
> On Wed, 25 Feb 2026 12:04:16 +0800, Tian Zheng wrote:
> > This series of patches add support to the Hardware Dirty state tracking
> > Structure(HDBSS) feature, which is introduced by the ARM architecture
> > in the DDI0601(ID121123) version.
> >
> > The HDBSS feature is an extension to the architecture that enhances
> > tracking translation table descriptors' dirty state, identified as
> > FEAT_HDBSS. This feature utilizes hardware assistance to achieve dirty
> > page tracking, aiming to significantly reduce the overhead of scanning
> > for dirty pages.
> >
> > [...]
>
> Applied sysreg definitions to arm64 (for-next/sysregs), thanks!
>
> [1/5] arm64/sysreg: Add HDBSS related register information
> https://git.kernel.org/arm64/c/72f7be0c2e30
>
Thanks!
Leo
> Cheers,
> --
> Will
>
> https://fixes.arm64.dev
> https://next.arm64.dev
> https://will.arm64.dev
^ permalink raw reply
* Re: [PATCH v3 1/3] soc: bcm2835: raspberrypi-firmware: Add voltage domain IDs
From: Florian Fainelli @ 2026-05-19 15:29 UTC (permalink / raw)
To: Shubham Chakraborty, Guenter Roeck, Jonathan Corbet
Cc: Shuah Khan, Broadcom internal kernel review list, Ray Jui,
Scott Branden, linux-hwmon, linux-doc, linux-rpi-kernel,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260517080445.103962-2-chakrabortyshubham66@gmail.com>
On 5/17/26 01:04, Shubham Chakraborty wrote:
> Add Raspberry Pi firmware voltage domain identifiers for the mailbox
> property interface.
>
> Also add the voltage request structure used with
> RPI_FIRMWARE_GET_VOLTAGE so firmware clients can share the common API
> definition from the firmware header.
>
> Signed-off-by: Shubham Chakraborty <chakrabortyshubham66@gmail.com>
Acked-by: Florian Fainelli <florian.fainelli@broadcom.com>
--
Florian
^ permalink raw reply
* Re: [PATCH v3 2/3] hwmon: raspberrypi: Add voltage input support
From: Florian Fainelli @ 2026-05-19 15:28 UTC (permalink / raw)
To: Shubham Chakraborty, Guenter Roeck, Jonathan Corbet
Cc: Shuah Khan, Broadcom internal kernel review list, Ray Jui,
Scott Branden, linux-hwmon, linux-doc, linux-rpi-kernel,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260517080445.103962-3-chakrabortyshubham66@gmail.com>
On 5/17/26 01:04, Shubham Chakraborty wrote:
> Extend the raspberrypi-hwmon driver to expose firmware-provided
> voltage measurements through the hwmon subsystem.
>
> The driver now exports the following voltage inputs:
>
> - in0_input (core)
> - in1_input (sdram_c)
> - in2_input (sdram_i)
> - in3_input (sdram_p)
>
> Voltage values returned by firmware are converted from microvolts
> to millivolts as expected by the hwmon subsystem.
>
> Update the documentation related to it.
>
> The existing undervoltage sticky alarm handling is preserved and
> associated with the first voltage channel.
>
> Tested in -
> - Raspberry Pi 3b+ (Linux raspberrypi 6.12.75+rpt-rpi-v8 #1 SMP PREEMPT
> Debian 1:6.12.75-1+rpt1 (2026-03-11) aarch64 GNU/Linux)
>
> Signed-off-by: Shubham Chakraborty <chakrabortyshubham66@gmail.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
--
Florian
^ permalink raw reply
* Re: [PATCH v2 1/2] arm64/cpufeature: Define hwcaps for 2025 dpISA features
From: Will Deacon @ 2026-05-19 15:24 UTC (permalink / raw)
To: Mark Brown
Cc: Catalin Marinas, Jonathan Corbet, Shuah Khan, linux-arm-kernel,
linux-kernel, linux-doc, linux-kselftest
In-Reply-To: <20260518-arm64-dpisa-2025-v2-1-b3367b73bd00@kernel.org>
On Mon, May 18, 2026 at 04:07:29PM +0100, Mark Brown wrote:
> The features added by the 2025 dpISA are all straightforward instruction
> only features so there is no state to manage, we can just expose hwcaps to
> let userspace know they are available.
>
> F16MM is slightly odd in that the feature is FEAT_F16MM but it is discovered
> via ID_AA64FPFR0_EL1.F16MM2. We follow the feature name.
>
> Signed-off-by: Mark Brown <broonie@kernel.org>
> ---
> Documentation/arch/arm64/elf_hwcaps.rst | 24 ++++++++++++++++++++++++
> arch/arm64/include/uapi/asm/hwcap.h | 8 ++++++++
> arch/arm64/kernel/cpufeature.c | 11 +++++++++++
> arch/arm64/kernel/cpuinfo.c | 8 ++++++++
> 4 files changed, 51 insertions(+)
>
> diff --git a/Documentation/arch/arm64/elf_hwcaps.rst b/Documentation/arch/arm64/elf_hwcaps.rst
> index 97315ae6c0da..07ff9ea1d605 100644
> --- a/Documentation/arch/arm64/elf_hwcaps.rst
> +++ b/Documentation/arch/arm64/elf_hwcaps.rst
> @@ -451,6 +451,30 @@ HWCAP3_LS64
> of CPU. User should only use ld64b/st64b on supported target (device)
> memory location, otherwise fallback to the non-atomic alternatives.
>
> +HWCAP3_SVE_B16MM
> + Functionality implied by ID_AA64ZFR0_EL1.B16B16 == 0b0011
> +
> +HWCAP3_SVE2P3
> + Functionality implied by ID_AA64ZFR0_EL1.SVEver == 0b0100
> +
> +HWCAP3_SME_LUT6
> + Functionality implied by ID_AA64SMFR0_EL1.LUT6 == 0b1
> +
> +HWCAP3_SME2P3
> + Functionality implied by ID_AA64SMFR0_EL1.SMEver == 0b0100
> +
> +HWCAP3_F16MM
> + Functionality implied by ID_AA64FPFR0_EL1.F16MM2 == 0b1
> +
> +HWCAP3_F16F32DOT
> + Functionality implied by ID_AA64ISAR0_EL1.FHM == 0b0010
> +
> +HWCAP3_F16F32MM
> + Functionality implied by ID_AA64ISAR0_EL1.FHM == 0b0011
> +
> +HWCAP3_SVE_LUT6
> + Functionality implied by ID_AA64ISAR2_EL1.LUT == 0b0010 and
> + ID_AA64PFR0_EL1.SVE == 0b0001.
I've queued this, but I'm curious why you've called out the
'ID_AA64PFR0_EL1.SVE == 0b0001' part here and not for any of the other
SVE caps you're adding? It's also formatted inconsistently from
pre-existing entries (such as HWCAP2_SVE_B16B16) which put the
ID_AA64PFR0_EL1.SVE part of the antecedent first.
Will
^ permalink raw reply
* Re: [PATCH v3 0/5] Support the FEAT_HDBSS introduced in Armv9.5
From: Will Deacon @ 2026-05-19 15:23 UTC (permalink / raw)
To: maz, oupton, catalin.marinas, corbet, pbonzini, Tian Zheng
Cc: kernel-team, Will Deacon, yuzenghui, wangzhou1, liuyonglong,
yezhenyu2, linuxarm, joey.gouly, kvmarm, kvm, linux-arm-kernel,
linux-doc, linux-kernel, skhan, suzuki.poulose, leo.bras,
Jonathan Cameron
In-Reply-To: <20260225040421.2683931-1-zhengtian10@huawei.com>
On Wed, 25 Feb 2026 12:04:16 +0800, Tian Zheng wrote:
> This series of patches add support to the Hardware Dirty state tracking
> Structure(HDBSS) feature, which is introduced by the ARM architecture
> in the DDI0601(ID121123) version.
>
> The HDBSS feature is an extension to the architecture that enhances
> tracking translation table descriptors' dirty state, identified as
> FEAT_HDBSS. This feature utilizes hardware assistance to achieve dirty
> page tracking, aiming to significantly reduce the overhead of scanning
> for dirty pages.
>
> [...]
Applied sysreg definitions to arm64 (for-next/sysregs), thanks!
[1/5] arm64/sysreg: Add HDBSS related register information
https://git.kernel.org/arm64/c/72f7be0c2e30
Cheers,
--
Will
https://fixes.arm64.dev
https://next.arm64.dev
https://will.arm64.dev
^ permalink raw reply
* Re: [PATCH v2] arm64: errata: Reformat table for IDs
From: Will Deacon @ 2026-05-19 15:23 UTC (permalink / raw)
To: catalin.marinas, Robin Murphy
Cc: kernel-team, Will Deacon, linux-arm-kernel, linux-doc
In-Reply-To: <0d4c8f3968e5c5c0a6f3dc295c3e9f696b9006f4.1777657487.git.robin.murphy@arm.com>
On Fri, 01 May 2026 18:52:28 +0100, Robin Murphy wrote:
> We have some inconsistency where multiple errata for the same component
> share the same Kconfig workaround; some are one ID per line, some are
> smooshed together, and some are entirely separate entries. Standardise
> on the single entry, one ID per line format so that things render nice
> and consistently in the HTML docs, and it's simple and clear to add new
> IDs to existing workarounds without churning the table too much.
>
> [...]
I think I intended to send this upstream at -rc1, but it didn't happen.
However, we don't (yet) seem to have any new workarounds in linux-next
so I'll take it on its own branch for 7.2.
Applied to arm64 (for-next/errata), thanks!
[1/1] arm64: errata: Reformat table for IDs
https://git.kernel.org/arm64/c/ede94377d855
Cheers,
--
Will
https://fixes.arm64.dev
https://next.arm64.dev
https://will.arm64.dev
^ permalink raw reply
* Re: [PATCH v2 0/2] arm64: Implement support for 2025 dpISA extensions
From: Will Deacon @ 2026-05-19 15:22 UTC (permalink / raw)
To: Catalin Marinas, Jonathan Corbet, Shuah Khan, Mark Brown
Cc: kernel-team, Will Deacon, linux-arm-kernel, linux-kernel,
linux-doc, linux-kselftest
In-Reply-To: <20260518-arm64-dpisa-2025-v2-0-b3367b73bd00@kernel.org>
On Mon, 18 May 2026 16:07:28 +0100, Mark Brown wrote:
> The 2025 dpISA extensions introduce a number of architecture features
> all of which are fairly straightforward from a kernel point of view
> since they only introduce new instructions, not any architecture state.
>
>
Applied selftest update to arm64 (for-next/selftests), thanks!
[2/2] kselftest/arm64: Add 2025 dpISA coverage to hwcaps
https://git.kernel.org/arm64/c/7da70f41da81
Cheers,
--
Will
https://fixes.arm64.dev
https://next.arm64.dev
https://will.arm64.dev
^ permalink raw reply
* Re: [PATCH v2 2/6] io_uring/zcrx: notify user when out of buffers
From: Vishwanath Seshagiri @ 2026-05-19 15:21 UTC (permalink / raw)
To: Clément Léger
Cc: io-uring, Pavel Begunkov, Jens Axboe, linux-doc, linux-kernel,
linux-kselftest, netdev, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
Shuah Khan, Vishwanath Seshagiri
In-Reply-To: <20260518153532.2835502-3-cleger@meta.com>
On Mon, May 18, 2026 at 8:36 AM Clément Léger <cleger@meta.com> wrote:
>
> From: Pavel Begunkov <asml.silence@gmail.com>
>
> There are currently no easy ways for the user to know if zcrx is out of
> buffers and page pool fails to allocate. Add uapi for zcrx to communicate
> it back.
>
> It's implemented as a separate CQE, which for now is posted to the creator
> ctx. To use it, on registration the user space needs to pass an instance
> of struct zcrx_notification_desc, which tells the kernel the user_data
> for resulting CQEs and which event types are expected / allowed.
>
> When an allowed event happens, zcrx will post a CQE containing the
> specified user_data, and lower bits of cqe->res will be set to the event
> mask. Before the kernel could post another notification of the given
> type, the user needs to acknowledge that it processed the previous one
> by issuing IORING_REGISTER_ZCRX_CTRL with ZCRX_CTRL_ARM_NOTIFICATION.
>
> The only notification type the patch implements is
> ZCRX_NOTIF_NO_BUFFERS, but we'll need more of them in the future.
>
> Co-developed-by: Vishwanath Seshagiri <vishs@meta.com>
> Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Signed-off-by: Vishwanath Seshagiri <vishs@meta.com>
> ---
> include/uapi/linux/io_uring/zcrx.h | 24 ++++++++-
> io_uring/io_uring.c | 2 +-
> io_uring/io_uring.h | 1 +
> io_uring/zcrx.c | 86 +++++++++++++++++++++++++++++-
> io_uring/zcrx.h | 7 ++-
> 5 files changed, 115 insertions(+), 5 deletions(-)
>
> diff --git a/include/uapi/linux/io_uring/zcrx.h b/include/uapi/linux/io_uring/zcrx.h
> index 5ce02c7a6096..67185566ad3c 100644
> --- a/include/uapi/linux/io_uring/zcrx.h
> +++ b/include/uapi/linux/io_uring/zcrx.h
> @@ -65,6 +65,20 @@ enum zcrx_features {
> * value in struct io_uring_zcrx_ifq_reg::rx_buf_len.
> */
> ZCRX_FEATURE_RX_PAGE_SIZE = 1 << 0,
> + ZCRX_FEATURE_NOTIFICATION = 1 << 1,
> +};
> +
> +enum zcrx_notification_type {
> + ZCRX_NOTIF_NO_BUFFERS,
> +
> + __ZCRX_NOTIF_TYPE_LAST,
> +};
> +
> +struct zcrx_notification_desc {
> + __u64 user_data;
> + __u32 type_mask;
> + __u32 __resv1;
> + __u64 __resv2[10];
> };
>
> /*
> @@ -82,12 +96,14 @@ struct io_uring_zcrx_ifq_reg {
> struct io_uring_zcrx_offsets offsets;
> __u32 zcrx_id;
> __u32 rx_buf_len;
> - __u64 __resv[3];
> + __u64 notif_desc; /* see struct zcrx_notification_desc */
> + __u64 __resv[2];
> };
>
> enum zcrx_ctrl_op {
> ZCRX_CTRL_FLUSH_RQ,
> ZCRX_CTRL_EXPORT,
> + ZCRX_CTRL_ARM_NOTIFICATION,
>
> __ZCRX_CTRL_LAST,
> };
> @@ -101,6 +117,11 @@ struct zcrx_ctrl_export {
> __u32 __resv1[11];
> };
>
> +struct zcrx_ctrl_arm_notif {
> + __u32 notif_type;
> + __u32 __resv[11];
> +};
> +
> struct zcrx_ctrl {
> __u32 zcrx_id;
> __u32 op; /* see enum zcrx_ctrl_op */
> @@ -109,6 +130,7 @@ struct zcrx_ctrl {
> union {
> struct zcrx_ctrl_export zc_export;
> struct zcrx_ctrl_flush_rq zc_flush;
> + struct zcrx_ctrl_arm_notif zc_arm_notif;
> };
> };
>
> diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
> index 2ebb0ba37c4f..c5972274cce1 100644
> --- a/io_uring/io_uring.c
> +++ b/io_uring/io_uring.c
> @@ -160,7 +160,7 @@ static void io_poison_cached_req(struct io_kiocb *req)
> req->apoll = IO_URING_PTR_POISON;
> }
>
> -static void io_poison_req(struct io_kiocb *req)
> +void io_poison_req(struct io_kiocb *req)
> {
> io_poison_cached_req(req);
> req->async_data = IO_URING_PTR_POISON;
> diff --git a/io_uring/io_uring.h b/io_uring/io_uring.h
> index e612a66ee80e..de0a3bed58d1 100644
> --- a/io_uring/io_uring.h
> +++ b/io_uring/io_uring.h
> @@ -213,6 +213,7 @@ bool __io_alloc_req_refill(struct io_ring_ctx *ctx);
>
> void io_activate_pollwq(struct io_ring_ctx *ctx);
> void io_restriction_clone(struct io_restriction *dst, struct io_restriction *src);
> +void io_poison_req(struct io_kiocb *req);
>
> static inline void io_lockdep_assert_cq_locked(struct io_ring_ctx *ctx)
> {
> diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c
> index 34faf90423f4..463fbaead35b 100644
> --- a/io_uring/zcrx.c
> +++ b/io_uring/zcrx.c
> @@ -768,6 +768,8 @@ static int import_zcrx(struct io_ring_ctx *ctx,
> return -EINVAL;
> if (reg->if_rxq || reg->rq_entries || reg->area_ptr || reg->region_ptr)
> return -EINVAL;
> + if (reg->notif_desc)
> + return -EINVAL;
> if (reg->flags & ~ZCRX_REG_IMPORT)
> return -EINVAL;
>
> @@ -856,6 +858,7 @@ static int zcrx_register_netdev(struct io_zcrx_ifq *ifq,
> int io_register_zcrx(struct io_ring_ctx *ctx,
> struct io_uring_zcrx_ifq_reg __user *arg)
> {
> + struct zcrx_notification_desc notif;
> struct io_uring_zcrx_area_reg area;
> struct io_uring_zcrx_ifq_reg reg;
> struct io_uring_region_desc rd;
> @@ -899,10 +902,22 @@ int io_register_zcrx(struct io_ring_ctx *ctx,
> if (copy_from_user(&area, u64_to_user_ptr(reg.area_ptr), sizeof(area)))
> return -EFAULT;
>
> + memset(¬if, 0, sizeof(notif));
> + if (reg.notif_desc && copy_from_user(¬if, u64_to_user_ptr(reg.notif_desc),
> + sizeof(notif)))
> + return -EFAULT;
> + if (notif.type_mask & ~ZCRX_NOTIF_TYPE_MASK)
> + return -EINVAL;
> + if (notif.__resv1 || !mem_is_zero(¬if.__resv2, sizeof(notif.__resv2)))
> + return -EINVAL;
> +
> ifq = io_zcrx_ifq_alloc(ctx);
> if (!ifq)
> return -ENOMEM;
>
> + ifq->notif_data = notif.user_data;
> + ifq->allowed_notif_mask = notif.type_mask;
> +
> if (ctx->user) {
> get_uid(ctx->user);
> ifq->user = ctx->user;
> @@ -954,7 +969,8 @@ int io_register_zcrx(struct io_ring_ctx *ctx,
> goto err;
> }
>
> - zcrx_set_ring_ctx(ifq, ctx);
> + if (notif.type_mask)
> + zcrx_set_ring_ctx(ifq, ctx);
> return 0;
> err:
> scoped_guard(mutex, &ctx->mmap_lock)
> @@ -1127,6 +1143,48 @@ static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if
> return allocated;
> }
>
> +static void zcrx_notif_tw(struct io_tw_req tw_req, io_tw_token_t tw)
> +{
> + struct io_kiocb *req = tw_req.req;
> + struct io_ring_ctx *ctx = req->ctx;
> +
> + io_post_aux_cqe(ctx, req->cqe.user_data, req->cqe.res, 0);
> + percpu_ref_put(&ctx->refs);
> + io_poison_req(req);
> + kmem_cache_free(req_cachep, req);
> +}
> +
> +static void zcrx_send_notif(struct io_zcrx_ifq *ifq, unsigned type)
> +{
> + gfp_t gfp = GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO;
> + u32 type_mask = 1 << type;
> + struct io_kiocb *req;
> +
> + if (!(type_mask & ifq->allowed_notif_mask))
> + return;
> +
> + guard(spinlock_bh)(&ifq->ctx_lock);
> + if (!ifq->master_ctx)
> + return;
> + if (type_mask & ifq->fired_notifs)
> + return;
> +
> + req = kmem_cache_alloc(req_cachep, gfp);
> + if (unlikely(!req))
> + return;
> +
> + ifq->fired_notifs |= type_mask;
> +
> + req->opcode = IORING_OP_NOP;
> + req->cqe.user_data = ifq->notif_data;
> + req->cqe.res = type;
> + req->ctx = ifq->master_ctx;
> + percpu_ref_get(&req->ctx->refs);
> + req->tctx = NULL;
> + req->io_task_work.func = zcrx_notif_tw;
> + io_req_task_work_add(req);
> +}
> +
> static netmem_ref io_pp_zc_alloc_netmems(struct page_pool *pp, gfp_t gfp)
> {
> struct io_zcrx_ifq *ifq = io_pp_to_ifq(pp);
> @@ -1143,8 +1201,10 @@ static netmem_ref io_pp_zc_alloc_netmems(struct page_pool *pp, gfp_t gfp)
> goto out_return;
>
> allocated = io_zcrx_refill_slow(pp, ifq, netmems, to_alloc);
> - if (!allocated)
> + if (!allocated) {
> + zcrx_send_notif(ifq, ZCRX_NOTIF_NO_BUFFERS);
> return 0;
> + }
> out_return:
> zcrx_sync_for_device(pp, ifq, netmems, allocated);
> allocated--;
> @@ -1293,12 +1353,32 @@ static int zcrx_flush_rq(struct io_ring_ctx *ctx, struct io_zcrx_ifq *zcrx,
> return 0;
> }
>
> +static int zcrx_arm_notif(struct io_ring_ctx *ctx, struct io_zcrx_ifq *zcrx,
> + struct zcrx_ctrl *ctrl)
> +{
> + const struct zcrx_ctrl_arm_notif *an = &ctrl->zc_arm_notif;
> + unsigned type_mask;
> +
> + if (an->notif_type >= __ZCRX_NOTIF_TYPE_LAST)
> + return -EINVAL;
> + if (!mem_is_zero(&an->__resv, sizeof(an->__resv)))
> + return -EINVAL;
> +
> + guard(spinlock_bh)(&zcrx->ctx_lock);
> + type_mask = 1U << an->notif_type;
> + if (type_mask & ~zcrx->fired_notifs)
> + return -EINVAL;
> + zcrx->fired_notifs &= ~type_mask;
> + return 0;
> +}
> +
> int io_zcrx_ctrl(struct io_ring_ctx *ctx, void __user *arg, unsigned nr_args)
> {
> struct zcrx_ctrl ctrl;
> struct io_zcrx_ifq *zcrx;
>
> BUILD_BUG_ON(sizeof(ctrl.zc_export) != sizeof(ctrl.zc_flush));
> + BUILD_BUG_ON(sizeof(ctrl.zc_export) != sizeof(ctrl.zc_arm_notif));
>
> if (nr_args)
> return -EINVAL;
> @@ -1316,6 +1396,8 @@ int io_zcrx_ctrl(struct io_ring_ctx *ctx, void __user *arg, unsigned nr_args)
> return zcrx_flush_rq(ctx, zcrx, &ctrl);
> case ZCRX_CTRL_EXPORT:
> return zcrx_export(ctx, zcrx, &ctrl, arg);
> + case ZCRX_CTRL_ARM_NOTIFICATION:
> + return zcrx_arm_notif(ctx, zcrx, &ctrl);
> }
>
> return -EOPNOTSUPP;
> diff --git a/io_uring/zcrx.h b/io_uring/zcrx.h
> index 6b565d0bf6da..cca10d0d02ac 100644
> --- a/io_uring/zcrx.h
> +++ b/io_uring/zcrx.h
> @@ -9,7 +9,9 @@
> #include <net/net_trackers.h>
>
> #define ZCRX_SUPPORTED_REG_FLAGS (ZCRX_REG_IMPORT | ZCRX_REG_NODEV)
> -#define ZCRX_FEATURES (ZCRX_FEATURE_RX_PAGE_SIZE)
> +#define ZCRX_FEATURES (ZCRX_FEATURE_RX_PAGE_SIZE |\
> + ZCRX_FEATURE_NOTIFICATION)
> +#define ZCRX_NOTIF_TYPE_MASK (1U << ZCRX_NOTIF_NO_BUFFERS)
>
> struct io_zcrx_mem {
> unsigned long size;
> @@ -76,6 +78,9 @@ struct io_zcrx_ifq {
>
> spinlock_t ctx_lock;
> struct io_ring_ctx *master_ctx;
> + u32 allowed_notif_mask;
> + u32 fired_notifs;
> + u64 notif_data;
> };
>
> #if defined(CONFIG_IO_URING_ZCRX)
> --
> 2.53.0-Meta
>
^ permalink raw reply
* Re: [PATCH v2 1/6] io_uring/zcrx: add ctx pointer to zcrx
From: Vishwanath Seshagiri @ 2026-05-19 15:19 UTC (permalink / raw)
To: Clément Léger
Cc: io-uring, Pavel Begunkov, Jens Axboe, linux-doc, linux-kernel,
linux-kselftest, netdev, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
Shuah Khan
In-Reply-To: <20260518153532.2835502-2-cleger@meta.com>
On Mon, May 18, 2026 at 8:36 AM Clément Léger <cleger@meta.com> wrote:
>
> From: Pavel Begunkov <asml.silence@gmail.com>
>
> zcrx will need to have a pointer to an owning ctx to communicate
> different events. Reference the ctx while it's attached to zcrx, and
> rely on zcrx termination to drop the ctx to avoid circular ref deps.
>
> Co-developed-by: Vishwanath Seshagiri <vishs@meta.com>
> Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Signed-off-by: Vishwanath Seshagiri <vishs@meta.com>
> ---
> io_uring/zcrx.c | 39 +++++++++++++++++++++++++++++++--------
> io_uring/zcrx.h | 3 +++
> 2 files changed, 34 insertions(+), 8 deletions(-)
>
> diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c
> index 3f9632e7790a..34faf90423f4 100644
> --- a/io_uring/zcrx.c
> +++ b/io_uring/zcrx.c
> @@ -44,6 +44,17 @@ static inline struct io_zcrx_area *io_zcrx_iov_to_area(const struct net_iov *nio
> return container_of(owner, struct io_zcrx_area, nia);
> }
>
> +static bool zcrx_set_ring_ctx(struct io_zcrx_ifq *zcrx,
> + struct io_ring_ctx *ctx)
> +{
> + guard(spinlock_bh)(&zcrx->ctx_lock);
> + if (zcrx->master_ctx)
> + return false;
> + percpu_ref_get(&ctx->refs);
> + zcrx->master_ctx = ctx;
> + return true;
> +}
> +
> static inline struct page *io_zcrx_iov_page(const struct net_iov *niov)
> {
> struct io_zcrx_area *area = io_zcrx_iov_to_area(niov);
> @@ -531,6 +542,7 @@ static struct io_zcrx_ifq *io_zcrx_ifq_alloc(struct io_ring_ctx *ctx)
> return NULL;
>
> ifq->if_rxq = -1;
> + spin_lock_init(&ifq->ctx_lock);
> spin_lock_init(&ifq->rq.lock);
> mutex_init(&ifq->pp_lock);
> refcount_set(&ifq->refs, 1);
> @@ -580,6 +592,8 @@ static void io_zcrx_ifq_free(struct io_zcrx_ifq *ifq)
> return;
> if (WARN_ON_ONCE(ifq->netdev != NULL))
> return;
> + if (WARN_ON_ONCE(ifq->master_ctx))
> + return;
>
> if (ifq->area)
> io_zcrx_free_area(ifq, ifq->area);
> @@ -656,17 +670,24 @@ static void io_zcrx_scrub(struct io_zcrx_ifq *ifq)
> }
> }
>
> -static void zcrx_unregister_user(struct io_zcrx_ifq *ifq)
> +static void zcrx_unregister_user(struct io_zcrx_ifq *ifq, struct io_ring_ctx *ctx)
> {
> + scoped_guard(spinlock_bh, &ifq->ctx_lock) {
> + if (ctx && ifq->master_ctx == ctx) {
> + ifq->master_ctx = NULL;
> + percpu_ref_put(&ctx->refs);
> + }
> + }
> +
> if (refcount_dec_and_test(&ifq->user_refs)) {
> io_close_queue(ifq);
> io_zcrx_scrub(ifq);
> }
> }
>
> -static void zcrx_unregister(struct io_zcrx_ifq *ifq)
> +static void zcrx_unregister(struct io_zcrx_ifq *ifq, struct io_ring_ctx *ctx)
> {
> - zcrx_unregister_user(ifq);
> + zcrx_unregister_user(ifq, ctx);
> io_put_zcrx_ifq(ifq);
> }
>
> @@ -686,7 +707,7 @@ static int zcrx_box_release(struct inode *inode, struct file *file)
>
> if (WARN_ON_ONCE(!ifq))
> return -EFAULT;
> - zcrx_unregister(ifq);
> + zcrx_unregister(ifq, NULL);
> return 0;
> }
>
> @@ -711,7 +732,7 @@ static int zcrx_export(struct io_ring_ctx *ctx, struct io_zcrx_ifq *ifq,
> file = anon_inode_create_getfile("[zcrx]", &zcrx_box_fops,
> ifq, O_CLOEXEC, NULL);
> if (IS_ERR(file)) {
> - zcrx_unregister(ifq);
> + zcrx_unregister(ifq, NULL);
> return PTR_ERR(file);
> }
>
> @@ -787,7 +808,7 @@ static int import_zcrx(struct io_ring_ctx *ctx,
> scoped_guard(mutex, &ctx->mmap_lock)
> xa_erase(&ctx->zcrx_ctxs, id);
> err:
> - zcrx_unregister(ifq);
> + zcrx_unregister(ifq, ctx);
> return ret;
> }
>
> @@ -932,12 +953,14 @@ int io_register_zcrx(struct io_ring_ctx *ctx,
> ret = -EFAULT;
> goto err;
> }
> +
> + zcrx_set_ring_ctx(ifq, ctx);
> return 0;
> err:
> scoped_guard(mutex, &ctx->mmap_lock)
> xa_erase(&ctx->zcrx_ctxs, id);
> ifq_free:
> - zcrx_unregister(ifq);
> + zcrx_unregister(ifq, ctx);
> return ret;
> }
>
> @@ -967,7 +990,7 @@ void io_terminate_zcrx(struct io_ring_ctx *ctx)
> break;
> set_zcrx_entry_mark(ctx, id);
> id++;
> - zcrx_unregister_user(ifq);
> + zcrx_unregister_user(ifq, ctx);
> }
> }
>
> diff --git a/io_uring/zcrx.h b/io_uring/zcrx.h
> index 9e1a6a1b11e8..6b565d0bf6da 100644
> --- a/io_uring/zcrx.h
> +++ b/io_uring/zcrx.h
> @@ -73,6 +73,9 @@ struct io_zcrx_ifq {
> */
> struct mutex pp_lock;
> struct io_mapped_region rq_region;
> +
> + spinlock_t ctx_lock;
> + struct io_ring_ctx *master_ctx;
> };
>
> #if defined(CONFIG_IO_URING_ZCRX)
> --
> 2.53.0-Meta
>
^ permalink raw reply
* Re: [PATCH 2/6] mm/damon/sysfs: implement update_schemes_quota_goals command
From: SeongJae Park @ 2026-05-19 15:08 UTC (permalink / raw)
To: Maksym Shcherba
Cc: SeongJae Park, Maksym Shcherba, akpm, david, ljs, liam, vbabka,
rppt, surenb, mhocko, corbet, skhan, damon, linux-mm,
linux-kernel, linux-doc, linux-kselftest
In-Reply-To: <20260519073352.16587-1-maksym.shcherba@lnu.edu.ua>
On Tue, 19 May 2026 10:33:52 +0300 Maksym Shcherba <mshcherba2000@gmail.com> wrote:
> On Mon, 18 May 2026 17:17:02 -0700 SeongJae Park <sj@kernel.org> wrote:
>
> > On Mon, 18 May 2026 22:09:28 +0300 Maksym Shcherba <mshcherba2000@gmail.com> wrote:
> >
> > > Add the logic to copy the current_value from the internal
> > > damos_quota_goal structure to the damos_sysfs_quota_goal sysfs structure.
> > > Introduce the DAMON_SYSFS_CMD_UPDATE_SCHEMES_QUOTA_GOALS command
> > > and integrate it with the sysfs interface via the 'state' file.
> >
> > Could you please further elaborate why you think this change is needed? What
> > is the expected use case and benefit?
> >
>
> Hi SJ,
>
> The documentation (`Documentation/admin-guide/mm/damon/usage.rst`)
> states that users can read the `current_value` file. However, the
> kernel currently never updates this value in sysfs, preventing users
> from reading the actual metrics.
>
> This patch series implements the missing logic to align the code
> with the documentation.
Thank you for clarifying, Maksym.
>
> If the design intent was to intentionally keep `current_value`
> internal and not expose it via sysfs, then the documentation is
> incorrect. Let me know if that's the case, and I will send a v2
> that drops the code changes and only fixes the documentation.
Yes, the documentation is incorrect. It was written in the way due to
following history. The DAMOS quota auto-tuning feature was initially developed
with oly 'user_input' target metric type. In the case, 'current_value' is set
by users. Hence reading the file was returning the last user-input value.
That is, as the documentation is also saying, it is returning the 'parameter'
(user input) value. It is not designed for exposing the internal state.
Later we extended the feature to let DAMOS self-fetch the current value. The
fact that the ``current_value`` is for reading and writing the parameter (user
input) value, and therefore reading it doesn't return the internal set value,
should be further clarified, but I forgot doing that.
So, yes, if the current behavior is not making problem, let's update the
documentation. I'll wait for your v2 :)
>
> (Apologies for missing the cover letter where this should have
> been explained, this is my first patch submission).
No worries, we continuously mistake and learn from each other in the
DAMON/mm/linux community! Welcome to the community, and I'm looking forward to
your v2!
Thanks,
SJ
[...]
^ 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