* [PATCH v11 0/2] Add support for Microchip EMC1812
From: Marius Cristea @ 2026-06-10 15:19 UTC (permalink / raw)
To: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Jonathan Corbet
Cc: linux-hwmon, devicetree, linux-kernel, linux-doc, Marius Cristea
This is the hwmon driver for EMC1812/13/14/15/33 multichannel Low-Voltage
Remote Diode Sensor Family. The chips in the family have one internal
and different numbers of external channels, ranging from 1 (EMC1812) to
4 channels (EMC1815).
Reading diodes in anti-parallel connection is supported by EMC1814, EMC1815
and EMC1833.
Signed-off-by: Marius Cristea <marius.cristea@microchip.com>
---
Changes in v11:
- remove unnecessary check for channels which are not physically available
- fix pointer signedness mismatch warning
- fix off-by-one misalignment when setting IDEALITY_FACTOR
- update the max temperature and critical temperature limit to match the
extended temperature range
- Link to v10: https://lore.kernel.org/r/20260429-hw_mon-emc1812-v10-0-a8ca1d779502@microchip.com
Changes in v10:
- made comments more clear into the devicetree binding
- allow channel 0 (internal channel) into devicetree binding
- allow the default name for Channel 0 to be overridden by the Device Tree property
- translate temperature limits to support the hardware's extended temperature range
- update channel count validation to properly account for the internal channel
- return -EOPNOTSUPP if channel is greater than or equal to phys_channels
- Link to v9: https://lore.kernel.org/r/20260403-hw_mon-emc1812-v9-0-1a798f31cf2e@microchip.com
Changes in v9:
- improve the wording in the Documentation/hwmon/emc1812.rst file
- add const to variables in the driver
- initialize the EXT2_BETA_CONFIG only for the pats that support it
- update the writeble regmap table to exclude read-only registers
- Link to v8: https://lore.kernel.org/r/20260310-hw_mon-emc1812-v8-0-bc155727e0d2@microchip.com
Changes in v8:
- remove "address scan" from emc1812.rst documentation
- change the second dimension of emc1812_limit_regs_low[][] to 2
- clamp input value before doing math on it to avoid overflow
- use rounding instead of truncation for 8 bits limit registers
- fix misleading comment when HW ID is not recognized
- Link to v7: https://lore.kernel.org/r/20260223-hw_mon-emc1812-v7-0-51e2676f4e20@microchip.com
Changes in v7:
- driver
- fix an overflow emc1812_set_hyst
- remove unused parameter in emc1812_set_temp
- devicetree binding:
- remove unneeded restrictions not to bloating the binding
- Link to v6: https://lore.kernel.org/r/20260212-hw_mon-emc1812-v6-0-e37e9b38d898@microchip.com
Changes in v6:
- driver
- fix an overflow when writing more then 191875 to limits stored on 8
bits register
- remove "i2c_set_clientdata" from probe
- fix discrepancy where writing 16ms and reading it back returns 15ms
at update interval
- skip setting the ideality factor for channels that are not available
on the device
- devicetree binding:
- change the way interrupts are described/used
- add "microchip,enable-anti-parallel"
- rewrite "allOf" section to be more clear
- Link to v5: https://lore.kernel.org/r/20260205-hw_mon-emc1812-v5-0-232835aefe8f@microchip.com
Changes in v5:
- fix calculation in emc1812_get_limit_temp
- use i2c_get_match_data cover the case when the driver is instantiated
via I2C ID table.
- replace dev_info with dev_warn
- remove some unnecessary truncation on 8 bits
- remove clamping when reading the temerature with hyst
- not change the conversion rate at probe time
- use a generic define to remove duplicate channel_info entries
- Link to v4: https://lore.kernel.org/r/20260127-hw_mon-emc1812-v4-0-6bf636b54847@microchip.com
Changes in v4:
- fix file permissions for read only properties
- fix calculation when the limits are written
- remove the temp_min_hyst because the part doesn't support it
- Link to v3: https://lore.kernel.org/r/20251218-hw_mon-emc1812-v3-0-a123ada7b859@microchip.com
Changes in v3:
- remove mesages that are not helpfull
- fix an issue related to NULL labels
- fix sign/unsign calculation
- replace E2BIG with EINVAL
- use BIT() to create mask
- Link to v2: https://lore.kernel.org/r/20251121-hw_mon-emc1812-v2-0-5b2070f8b778@microchip.com
Changes in v2:
- update the interrupt section from yaml file
- update index.rst
- remove fault condition from internal sensor
- remove unused members from structures
- update the driver to work on systems without device tree or
firmware nodes
- add missing include files
- make NULL labels to be not visible
- corect sign/unsign calculations
- corect possible underflow for limits
- Link to v1: https://lore.kernel.org/r/20251029-hw_mon-emc1812-v1-0-be4fd8af016a@microchip.com
---
Marius Cristea (2):
dt-bindings: hwmon: temperature: add support for EMC1812
hwmon: temperature: add support for EMC1812
.../bindings/hwmon/microchip,emc1812.yaml | 193 +++++
Documentation/hwmon/emc1812.rst | 67 ++
Documentation/hwmon/index.rst | 1 +
MAINTAINERS | 8 +
drivers/hwmon/Kconfig | 11 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/emc1812.c | 965 +++++++++++++++++++++
7 files changed, 1246 insertions(+)
---
base-commit: d2b2fea3503e5e12b2e28784152937e48bcca6ff
change-id: 20251002-hw_mon-emc1812-f1b806487d10
Best regards,
--
Marius Cristea <marius.cristea@microchip.com>
^ permalink raw reply
* Re: [PATCH v5 07/21] nfsd: add callback encoding and decoding linkages for CB_NOTIFY
From: Jeff Layton @ 2026-06-10 15:19 UTC (permalink / raw)
To: Chuck Lever, Chuck Lever, NeilBrown, Olga Kornievskaia, Dai Ngo,
Tom Talpey, Trond Myklebust, Anna Schumaker, Jonathan Corbet,
Shuah Khan
Cc: Steven Rostedt, Alexander Aring, Amir Goldstein, Jan Kara,
Alexander Viro, Christian Brauner, Calum Mackay, linux-kernel,
linux-doc, linux-nfs
In-Reply-To: <35918046-66e3-4361-adc3-bce328ce9821@app.fastmail.com>
On Mon, 2026-06-08 at 12:52 -0400, Chuck Lever wrote:
>
> On Fri, May 22, 2026, at 3:42 PM, Jeff Layton wrote:
> > Add routines for encoding and decoding CB_NOTIFY messages. These call
> > into the code generated by xdrgen to do the actual encoding and
> > decoding.
>
> The commit message needs to explain that the encoder is not yet functional.
> Something like: "The encoder is a stub; payload encoding (stateid, fh, and
> cna_changes) is deferred."
>
Ok.
>
> > diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
> > index 25bbf5b8814d..ea3e7deb06fa 100644
> > --- a/fs/nfsd/nfs4callback.c
> > +++ b/fs/nfsd/nfs4callback.c
> > @@ -865,6 +865,51 @@ static void encode_stateowner(struct xdr_stream
> > *xdr, struct nfs4_stateowner *so
> > xdr_encode_opaque(p, so->so_owner.data, so->so_owner.len);
> > }
> >
> > +static void nfs4_xdr_enc_cb_notify(struct rpc_rqst *req,
> > + struct xdr_stream *xdr,
> > + const void *data)
> > +{
> > + const struct nfsd4_callback *cb = data;
> > + struct nfs4_cb_compound_hdr hdr = {
> > + .ident = 0,
> > + .minorversion = cb->cb_clp->cl_minorversion,
> > + };
> > + struct CB_NOTIFY4args args = { };
> > +
> > + WARN_ON_ONCE(hdr.minorversion == 0);
> > +
> > + encode_cb_compound4args(xdr, &hdr);
> > + encode_cb_sequence4args(xdr, cb, &hdr);
> > +
> > + /*
> > + * FIXME: get stateid and fh from delegation. Inline the cna_changes
> > + * buffer, and zero it.
> > + */
> > + WARN_ON_ONCE(!xdrgen_encode_CB_NOTIFY4args(xdr, &args));
> > +
> > + hdr.nops++;
> > + encode_cb_nops(&hdr);
> > +}
>
> There are a number of problems with this, but since there are no
> callers yet, we can let some of those issues stand.
>
> What is problematic in the longer-term is that this is a client-side
> encoder (since this is the server's NFSv4 callback client).
>
> xdrgen_encode_CB_NOTIFY4args() is an argument encoder, which is
> client-side functionality, but it resides in fs/nfsd/nfs4xdr_gen.c,
> which is server-side. Let's not mix these purposes.
>
> I replaced the comment and WARN_ON with this:
>
> + xdr_stream_encode_u32(xdr, OP_CB_NOTIFY);
> +
> + /* FIXME: encode stateid, fh, and cna_changes from delegation */
>
> You can use xdrgen functions for individual data items, but for
> full argument and response structures, only server-side is supported
> at the moment. In the later patch that completes this code, I'll cover
> the other fields, which can be a mix of open code and xdrgen.
>
The full argument encoder and decoder works just fine. When you say
"supported" what do you mean, specifically?
I'd really rather not go back to open-coding the encoders and decoders,
particularly since CB_NOTIFY has one of the most complex argument
structures in the protocol.
>
> > diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> > index e1c40f8b5d01..790282781243 100644
> > --- a/fs/nfsd/state.h
> > +++ b/fs/nfsd/state.h
> > @@ -190,6 +190,13 @@ struct nfs4_cb_fattr {
> > u64 ncf_cur_fsize;
> > };
> >
> > +/*
> > + * FIXME: the current backchannel encoder can't handle a send buffer longer
> > + * than a single page (see bc_alloc/bc_free).
> > + */
>
> Nit: The allocator function name is bc_malloc
>
Will fix.
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply
* [PATCH v3 net-next 1/1] dt-bindings: net: dsa: Convert lan9303.txt to yaml format
From: Frank.Li @ 2026-06-10 15:05 UTC (permalink / raw)
To: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Simon Horman, Jonathan Corbet, Shuah Khan, Frank Li,
open list:NETWORKING DRIVERS,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
open list, open list:DOCUMENTATION
Cc: imx
From: Frank Li <Frank.Li@nxp.com>
Convert lan9303.txt to yaml format to fix below CHECK_DTBS warnings:
arch/arm/boot/dts/nxp/imx/imx53-kp-hsc.dtb: /soc/bus@50000000/i2c@53fec000/switch@a: failed to match any schema with compatible: ['smsc,lan9303-i2c']
Additional changes:
- rename switch-phy to switch in example.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v3
- rebase to net-next
change in v2:
- fix typo Additional in commit message
- add rob's reviewed-by tags
- fix doc ref problem
---
.../devicetree/bindings/net/dsa/lan9303.txt | 100 --------------
.../bindings/net/dsa/smsc,lan9303.yaml | 123 ++++++++++++++++++
Documentation/networking/dsa/lan9303.rst | 2 +-
3 files changed, 124 insertions(+), 101 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/net/dsa/lan9303.txt
create mode 100644 Documentation/devicetree/bindings/net/dsa/smsc,lan9303.yaml
diff --git a/Documentation/devicetree/bindings/net/dsa/lan9303.txt b/Documentation/devicetree/bindings/net/dsa/lan9303.txt
deleted file mode 100644
index 0337c2ccfa9a7..0000000000000
--- a/Documentation/devicetree/bindings/net/dsa/lan9303.txt
+++ /dev/null
@@ -1,100 +0,0 @@
-SMSC/MicroChip LAN9303 three port ethernet switch
--------------------------------------------------
-
-Required properties:
-
-- compatible: should be
- - "smsc,lan9303-i2c" for I2C managed mode
- or
- - "smsc,lan9303-mdio" for mdio managed mode
-
-Optional properties:
-
-- reset-gpios: GPIO to be used to reset the whole device
-- reset-duration: reset duration in milliseconds, defaults to 200 ms
-
-Subnodes:
-
-The integrated switch subnode should be specified according to the binding
-described in dsa/dsa.yaml. The CPU port of this switch is always port 0.
-
-Note: always use 'reg = <0/1/2>;' for the three DSA ports, even if the device is
-configured to use 1/2/3 instead. This hardware configuration will be
-auto-detected and mapped accordingly.
-
-Example:
-
-I2C managed mode:
-
- master: masterdevice@X {
-
- fixed-link { /* RMII fixed link to LAN9303 */
- speed = <100>;
- full-duplex;
- };
- };
-
- switch: switch@a {
- compatible = "smsc,lan9303-i2c";
- reg = <0xa>;
- reset-gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
- reset-duration = <200>;
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 { /* RMII fixed link to master */
- reg = <0>;
- ethernet = <&master>;
- };
-
- port@1 { /* external port 1 */
- reg = <1>;
- label = "lan1";
- };
-
- port@2 { /* external port 2 */
- reg = <2>;
- label = "lan2";
- };
- };
- };
-
-MDIO managed mode:
-
- master: masterdevice@X {
- phy-handle = <&switch>;
-
- mdio {
- #address-cells = <1>;
- #size-cells = <0>;
-
- switch: switch-phy@0 {
- compatible = "smsc,lan9303-mdio";
- reg = <0>;
- reset-gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
- reset-duration = <100>;
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- ethernet = <&master>;
- };
-
- port@1 { /* external port 1 */
- reg = <1>;
- label = "lan1";
- };
-
- port@2 { /* external port 2 */
- reg = <2>;
- label = "lan2";
- };
- };
- };
- };
- };
diff --git a/Documentation/devicetree/bindings/net/dsa/smsc,lan9303.yaml b/Documentation/devicetree/bindings/net/dsa/smsc,lan9303.yaml
new file mode 100644
index 0000000000000..42f8473538a07
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/dsa/smsc,lan9303.yaml
@@ -0,0 +1,123 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/dsa/smsc,lan9303.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SMSC/MicroChip LAN9303 three port ethernet switch
+
+maintainers:
+ - Frank Li <Frank.Li@nxp.com>
+
+description:
+ The LAN9303 is a three port ethernet switch with integrated PHYs for the
+ two external ports. The third port is an RMII/MII interface to a host
+ processor. The device can be managed via I2C or MDIO.
+
+ Note - always use 'reg = <0/1/2>;' for the three DSA ports, even if the
+ device is configured to use 1/2/3 instead. This hardware configuration
+ will be auto-detected and mapped accordingly.
+
+properties:
+ compatible:
+ enum:
+ - smsc,lan9303-i2c
+ - smsc,lan9303-mdio
+
+ reg:
+ maxItems: 1
+
+ reset-gpios:
+ description:
+ GPIO to be used to reset the whole device
+ maxItems: 1
+
+ reset-duration:
+ description:
+ Reset duration in milliseconds
+ default: 200
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+allOf:
+ - $ref: dsa.yaml#
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ /* I2C managed mode */
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ switch@a {
+ compatible = "smsc,lan9303-i2c";
+ reg = <0xa>;
+ reset-gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
+ reset-duration = <200>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ label = "cpu";
+ ethernet = <&master>;
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "lan1";
+ };
+
+ port@2 {
+ reg = <2>;
+ label = "lan2";
+ };
+ };
+ };
+ };
+
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ /* MDIO managed mode */
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ switch@0 {
+ compatible = "smsc,lan9303-mdio";
+ reg = <0>;
+ reset-gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
+ reset-duration = <100>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ label = "cpu";
+ ethernet = <&master>;
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "lan1";
+ };
+
+ port@2 {
+ reg = <2>;
+ label = "lan2";
+ };
+ };
+ };
+ };
diff --git a/Documentation/networking/dsa/lan9303.rst b/Documentation/networking/dsa/lan9303.rst
index ab81b4e0139e3..776572be265e1 100644
--- a/Documentation/networking/dsa/lan9303.rst
+++ b/Documentation/networking/dsa/lan9303.rst
@@ -12,7 +12,7 @@ Driver details
The driver is implemented as a DSA driver, see ``Documentation/networking/dsa/dsa.rst``.
-See ``Documentation/devicetree/bindings/net/dsa/lan9303.txt`` for device tree
+See ``Documentation/devicetree/bindings/net/dsa/smsc,lan9303.yaml`` for device tree
binding.
The LAN9303 can be managed both via MDIO and I2C, both supported by this driver.
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v5] Docs/{admin-guide,mm}/damon: fix DAMON documentation details
From: Doehyun Baek @ 2026-06-10 14:41 UTC (permalink / raw)
To: SeongJae Park, Dongliang Mu
Cc: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Jonathan Corbet, Shuah Khan,
damon, linux-mm, linux-doc, linux-kernel
In-Reply-To: <20260610140217.65110-1-sj@kernel.org>
> Let me know if you think this is really urgent or I'm missing something, though.
Thanks for reviewing and applying it to damon/next.
It is not urgent from my side. I needed the English documentation fix as
a base for the Chinese translation patches.
Dongliang, would it be okay for me to send the Chinese translation
patches based on damon/next, or should I wait until the English fix is
picked up by mm.git or mainline?
Thanks,
Doehyun
^ permalink raw reply
* Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
From: Pranjal Shrivastava @ 2026-06-10 14:37 UTC (permalink / raw)
To: Jason Gunthorpe
Cc: David Matlack, kexec, linux-doc, linux-kernel, linux-mm,
linux-pci, Adithya Jayachandran, Alexander Graf, Alex Williamson,
Bjorn Helgaas, Chris Li, David Rientjes, Jacob Pan,
Jonathan Corbet, Josh Hilke, Leon Romanovsky, Lukas Wunner,
Mike Rapoport, Parav Pandit, Pasha Tatashin, Pratyush Yadav,
Saeed Mahameed, Samiullah Khawaja, Shuah Khan, Vipin Sharma,
William Tu, Yi Liu
In-Reply-To: <20260610000704.GR1962447@nvidia.com>
On Tue, Jun 09, 2026 at 09:07:04PM -0300, Jason Gunthorpe wrote:
> On Tue, Jun 09, 2026 at 05:20:14PM +0000, Pranjal Shrivastava wrote:
>
> > Now, the attacker has an opportunity with Liveupdate, since the devices
> > are already assigned, if *somehow* it flips a bit like ACS_RR, the
>
> If this is possible then your environment is already security broken,
> no need to involve live update.
Ack. Alright.
Thanks,
Praan
^ permalink raw reply
* Re: [PATCH v5] Docs/{admin-guide,mm}/damon: fix DAMON documentation details
From: SeongJae Park @ 2026-06-10 14:02 UTC (permalink / raw)
To: Doehyun Baek
Cc: SeongJae Park, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Jonathan Corbet, Shuah Khan,
damon, linux-mm, linux-doc, linux-kernel
In-Reply-To: <20260610053951.553739-1-doehyunbaek@gmail.com>
On Wed, 10 Jun 2026 05:39:50 +0000 Doehyun Baek <doehyunbaek@gmail.com> wrote:
> Fix minor DAMON documentation issues. Correct the sysfs scheme file name
> apply_interval_us, the DAMON_STAT module count, a malformed reference, a
> misplaced label indentation, and a few typos.
Nice catches, thank you for fixing those!
>
> Signed-off-by: Doehyun Baek <doehyunbaek@gmail.com>
Reviewed-by: SeongJae Park <sj@kernel.org>
I applied this patch to damon/next [1] tree. We are now quite close to next
merge window. We (mm community) want to focus on making mm.git more stabilized
and therefore ready for the next merge window, rather than adding more changes
that are not really urgent. I understand this patch is not really urgent.
Hence, Andrew might not add this patch to mm.git until next -rc1 release. In
the case, I will request that after next -rc1 release. So, no action from your
side is needed for now. Let me know if you think this is really urgent or I'm
missing something, though.
[1] https://origin.kernel.org/doc/html/latest/mm/damon/maintainer-profile.html#scm-trees
Thanks,
SJ
[...]
^ permalink raw reply
* Re: [PATCH v5 05/21] nfsd: update the fsnotify mark when setting or removing a dir delegation
From: Chuck Lever @ 2026-06-10 13:55 UTC (permalink / raw)
To: Jeff Layton, Chuck Lever, NeilBrown, Olga Kornievskaia, Dai Ngo,
Tom Talpey, Trond Myklebust, Anna Schumaker, Jonathan Corbet,
Shuah Khan
Cc: Steven Rostedt, Alexander Aring, Amir Goldstein, Jan Kara,
Alexander Viro, Christian Brauner, Calum Mackay, linux-kernel,
linux-doc, linux-nfs
In-Reply-To: <dd5836b365946641824dbde5b6edc5395271617d.camel@kernel.org>
On Wed, Jun 10, 2026, at 9:49 AM, Jeff Layton wrote:
> On Mon, 2026-06-08 at 12:38 -0400, Chuck Lever wrote:
>> > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>> > index 2a34ba457b74..efbc99f0a965 100644
>> > --- a/fs/nfsd/nfs4state.c
>> > +++ b/fs/nfsd/nfs4state.c
>> > @@ -1246,6 +1246,38 @@ static void
>> > nfsd4_finalize_deleg_timestamps(struct nfs4_delegation *dp, struct f
>> > nfsd_update_cmtime_attr(f, ATTR_ATIME);
>> > }
>> >
>> > +static void nfsd_fsnotify_recalc_mask(struct nfsd_file *nf)
>>
>> Since nfsd_fsnotify_recalc_mask() takes a single struct nfsd_file
>> as an argument, should this function reside in fs/nfsd/filecache.c
>> instead? The question might reflect my misunderstanding of the
>> new function's purpose.
>>
>
> The only caller is in this file, so by keeping it here we can make it
> static. I can change that if you'd prefer it be in filecache.c.
My thought was that the new function is accessing and modifying
the internals of an nfsd_file -- it contains local knowledge about
how the filecache manages fs notifications.
>> > +{
>> > + struct inode *inode = file_inode(nf->nf_file);
>> > + u32 lease_mask, set = 0, clear = 0;
>> > + struct fsnotify_mark *mark;
>> > +
>> > + /* This is only needed when adding or removing dir delegs */
>> > + if (!S_ISDIR(inode->i_mode) || !nf->nf_mark)
>> > + return;
>> > +
>> > + /* Set up notifications for any ignored delegation events */
>> > + lease_mask = inode_lease_ignore_mask(inode);
>> > + mark = &nf->nf_mark->nfm_mark;
>> > +
>> > + if (lease_mask & FL_IGN_DIR_CREATE)
>> > + set |= FS_CREATE | FS_MOVED_TO;
>> > + else
>> > + clear |= FS_CREATE | FS_MOVED_TO;
>> > +
>> > + if (lease_mask & FL_IGN_DIR_DELETE)
>> > + set |= FS_DELETE | FS_MOVED_FROM;
>> > + else
>> > + clear |= FS_DELETE | FS_MOVED_FROM;
>> > +
>> > + if (lease_mask & FL_IGN_DIR_RENAME)
>> > + set |= FS_RENAME;
>> > + else
>> > + clear |= FS_RENAME;
>> > +
>> > + fsnotify_modify_mark_mask(mark, set, clear);
>> > +}
>> > +
>> > static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp)
>> > {
>> > struct nfs4_file *fp = dp->dl_stid.sc_file;
--
Chuck Lever
^ permalink raw reply
* Re: [PATCH v5 05/21] nfsd: update the fsnotify mark when setting or removing a dir delegation
From: Jeff Layton @ 2026-06-10 13:49 UTC (permalink / raw)
To: Chuck Lever, Chuck Lever, NeilBrown, Olga Kornievskaia, Dai Ngo,
Tom Talpey, Trond Myklebust, Anna Schumaker, Jonathan Corbet,
Shuah Khan
Cc: Steven Rostedt, Alexander Aring, Amir Goldstein, Jan Kara,
Alexander Viro, Christian Brauner, Calum Mackay, linux-kernel,
linux-doc, linux-nfs
In-Reply-To: <e0e995e9-8272-44f6-b2e0-9e61ed0eef3b@app.fastmail.com>
On Mon, 2026-06-08 at 12:38 -0400, Chuck Lever wrote:
>
> On Fri, May 22, 2026, at 3:42 PM, Jeff Layton wrote:
> > Add a new helper function that will update the mask on the nfsd_file's
> > fsnotify_mark to be a union of all current directory delegations on an
> > inode. Call that when directory delegations are added or removed.
>
> This commit message repeats what the diff below says. Can it instead
> explain why this change is necessary?
>
The idea is that as new delegations are added or removed, the mask of
events that nfsd requires from the VFS layer can change, since clients
can request notifications of different events. I'll add that to the
changelog.
>
> > Reviewed-by: Jan Kara <jack@suse.cz>
> > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > ---
> > fs/nfsd/nfs4state.c | 34 ++++++++++++++++++++++++++++++++++
> > 1 file changed, 34 insertions(+)
> >
> > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> > index 2a34ba457b74..efbc99f0a965 100644
> > --- a/fs/nfsd/nfs4state.c
> > +++ b/fs/nfsd/nfs4state.c
> > @@ -1246,6 +1246,38 @@ static void
> > nfsd4_finalize_deleg_timestamps(struct nfs4_delegation *dp, struct f
> > nfsd_update_cmtime_attr(f, ATTR_ATIME);
> > }
> >
> > +static void nfsd_fsnotify_recalc_mask(struct nfsd_file *nf)
>
> Since nfsd_fsnotify_recalc_mask() takes a single struct nfsd_file
> as an argument, should this function reside in fs/nfsd/filecache.c
> instead? The question might reflect my misunderstanding of the
> new function's purpose.
>
The only caller is in this file, so by keeping it here we can make it
static. I can change that if you'd prefer it be in filecache.c.
>
> > +{
> > + struct inode *inode = file_inode(nf->nf_file);
> > + u32 lease_mask, set = 0, clear = 0;
> > + struct fsnotify_mark *mark;
> > +
> > + /* This is only needed when adding or removing dir delegs */
> > + if (!S_ISDIR(inode->i_mode) || !nf->nf_mark)
> > + return;
> > +
> > + /* Set up notifications for any ignored delegation events */
> > + lease_mask = inode_lease_ignore_mask(inode);
> > + mark = &nf->nf_mark->nfm_mark;
> > +
> > + if (lease_mask & FL_IGN_DIR_CREATE)
> > + set |= FS_CREATE | FS_MOVED_TO;
> > + else
> > + clear |= FS_CREATE | FS_MOVED_TO;
> > +
> > + if (lease_mask & FL_IGN_DIR_DELETE)
> > + set |= FS_DELETE | FS_MOVED_FROM;
> > + else
> > + clear |= FS_DELETE | FS_MOVED_FROM;
> > +
> > + if (lease_mask & FL_IGN_DIR_RENAME)
> > + set |= FS_RENAME;
> > + else
> > + clear |= FS_RENAME;
> > +
> > + fsnotify_modify_mark_mask(mark, set, clear);
> > +}
> > +
> > static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp)
> > {
> > struct nfs4_file *fp = dp->dl_stid.sc_file;
> > @@ -1255,6 +1287,7 @@ static void nfs4_unlock_deleg_lease(struct
> > nfs4_delegation *dp)
> >
> > nfsd4_finalize_deleg_timestamps(dp, nf->nf_file);
> > kernel_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp);
> > + nfsd_fsnotify_recalc_mask(nf);
> > put_deleg_file(fp);
> > }
> >
>
> I added the following edit to this patch>
>
> @@ -9597,8 +9629,7 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry,
> * @nf: nfsd_file opened on the directory
> *
> * Given a GET_DIR_DELEGATION request @gdd, attempt to acquire a delegation
> - * on the directory to which @nf refers. Note that this does not set up any
> - * sort of async notifications for the delegation.
> + * on the directory to which @nf refers.
> */
> struct nfs4_delegation *
> nfsd_get_dir_deleg
>
> The patch makes the above kerneldoc note ("does not set up any sort of async
> notifications") logically obsolete.
>
Thanks. I folded that change into this patch.
>
> > @@ -9682,6 +9715,7 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *cstate,
> >
> > if (!status) {
> > put_nfs4_file(fp);
> > + nfsd_fsnotify_recalc_mask(nf);
> > return dp;
> > }
> >
> >
> > --
> > 2.54.0
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply
* Re: [PATCH v2] arm64: errata: Workaround NVIDIA Olympus device store/load ordering erratum
From: Shanker Donthineni @ 2026-06-10 13:20 UTC (permalink / raw)
To: Will Deacon
Cc: Catalin Marinas, linux-arm-kernel, Vladimir Murzin, Mark Rutland,
linux-kernel, linux-doc, Vikram Sethi, Jason Sequeira, jgg
In-Reply-To: <ailKYTOX23EMnJsK@willie-the-truck>
Hi Will,
On 6/10/2026 6:28 AM, Will Deacon wrote:
> External email: Use caution opening links or attachments
>
>
> [+Jason G]
>
> On Fri, Jun 05, 2026 at 09:45:51AM -0500, Shanker Donthineni wrote:
>> On systems with NVIDIA Olympus cores, a Device-nGnR* load can be
>> observed by a peripheral before an older, non-overlapping Device-nGnR*
>> store to the same peripheral. This breaks the program-order guarantee
>> that software expects for Device-nGnR* accesses and can leave a
>> peripheral in an incorrect state, as a load is observed before an
>> earlier store takes effect.
>>
>> The erratum can occur only when all of the following apply:
>>
>> - A PE executes a Device-nGnR* store followed by a younger
>> Device-nGnR* load.
>> - The store is not a store-release.
>> - The accesses target the same peripheral and do not overlap in bytes.
>> - There is at most one intervening Device-nGnR* store in program
>> order, and there are no intervening Device-nGnR* loads.
>> - There is no DSB, and no DMB that orders loads, between the store and
>> the load.
>> - Specific micro-architectural and timing conditions occur.
>>
>> Two ways to restore ordering: insert a barrier (any DSB, or a DMB that
>> orders loads) between the store and the load, or make the store a
>> store-release. A load-acquire on the load side would not help, because
>> acquire semantics do not prevent a load from being observed ahead of an
>> older store; only the store side (release or a barrier) closes the
>> window.
> I think you can drop the paragraph above. A store-release isn't enough
> to order against a later load in the architecture either, so we're
> clearly in micro-architecture territory and I don't think you need to
> describe mechanisms that don't work here.
>
>> Promote the raw MMIO store helpers (__raw_writeb/w/l/q) from plain str*
>> to stlr* (Store-Release), which removes the "store is not a
>> store-release" condition for every device write the kernel issues.
>> Because writel() and writel_relaxed() are both built on __raw_writel()
>> in asm-generic/io.h, patching the raw variants covers both the
>> non-relaxed and relaxed APIs without touching the higher layers. Note
>> that writel()'s own barrier sits before the store, so it does not order
>> the store against a subsequent readl(); the store-release promotion is
>> what provides that ordering.
Based on the existing code comments and after reviewing this path again,
__const_memcpy_toio_aligned32() and __const_memcpy_toio_aligned64()
appear to be intended for WC regions. Since the erratum is scoped to
Device-nGnR* accesses, and WC mappings are Normal-NC on arm64, I don’t
think the STLR workaround should apply to these helpers by default.
Applying it there would also break the contiguous STR grouping that
this path relies on for write combining.
-Shanker
^ permalink raw reply
* Re: [PATCH] hwmon: (pmbus/max34440): add support adpm12250
From: Guenter Roeck @ 2026-06-10 13:12 UTC (permalink / raw)
To: Alexis Czezar Torreno
Cc: Jonathan Corbet, Shuah Khan, linux-hwmon, linux-doc, linux-kernel
In-Reply-To: <20260610-dev-adpm12250-v1-1-422760bb80da@analog.com>
On Wed, Jun 10, 2026 at 09:12:10AM +0800, Alexis Czezar Torreno wrote:
> ADPM12250 is a quarter brick DC/DC Power Module. It is a high power
> non-isolated converter capable of delivering regulated 12V with
> continuous power level of 2500W. Uses PMBus.
>
> Signed-off-by: Alexis Czezar Torreno <alexisczezar.torreno@analog.com>
> Reviewed-by: Nuno Sá <nuno.sa@analog.com>
Applied.
Thanks,
Guenter
^ permalink raw reply
* Re: configurable block error injection v4
From: Christoph Hellwig @ 2026-06-10 13:11 UTC (permalink / raw)
To: Jens Axboe
Cc: Jonathan Corbet, Damien Le Moal, Hannes Reinecke, Keith Busch,
linux-block, linux-doc
In-Reply-To: <20260610051015.1906799-1-hch@lst.de>
Sashiko had two comments on this:
- the one about the race of removal vs. addition is spot on, and
trivially fixed by actually removing the code (unlock/lock cycle).
- the other about zero-sized commands is valid, but more of an
enhancement. And one that if implemented right now actually
make things worse, as flushed actually show up as empty writes
with the preflush bit and not as REQ_OP_FLUSH. So if we'd special
case zero-sized bios, we'd make a flush hit all write rules,
which would defeat the point. We really need to do flushes as
REQ_OP_FLUSH at the bio level :(
Below is what I plan to fold in, and I'm thinking of the empty bio
issue above can be caught in a comment or the documentation nicely.
diff --git a/block/error-injection.c b/block/error-injection.c
index 7f7f0d3327bc..3bc91f199dc7 100644
--- a/block/error-injection.c
+++ b/block/error-injection.c
@@ -119,11 +119,7 @@ static void error_inject_removeall(struct gendisk *disk)
while ((inj = list_first_entry_or_null(&disk->error_injection_list,
struct blk_error_inject, entry))) {
list_del_rcu(&inj->entry);
- mutex_unlock(&disk->error_injection_lock);
-
kfree_rcu_mightsleep(inj);
-
- mutex_lock(&disk->error_injection_lock);
}
static_branch_dec(&blk_error_injection_enabled);
mutex_unlock(&disk->error_injection_lock);
^ permalink raw reply related
* Re: [PATCH v2] arm64: errata: Workaround NVIDIA Olympus device store/load ordering erratum
From: Shanker Donthineni @ 2026-06-10 12:53 UTC (permalink / raw)
To: Will Deacon
Cc: Catalin Marinas, linux-arm-kernel, Vladimir Murzin, Mark Rutland,
linux-kernel, linux-doc, Vikram Sethi, Jason Sequeira, jgg
In-Reply-To: <ailKYTOX23EMnJsK@willie-the-truck>
Hi Will,
On 6/10/2026 6:28 AM, Will Deacon wrote:
> External email: Use caution opening links or attachments
>
>
> [+Jason G]
>
> On Fri, Jun 05, 2026 at 09:45:51AM -0500, Shanker Donthineni wrote:
>> On systems with NVIDIA Olympus cores, a Device-nGnR* load can be
>> observed by a peripheral before an older, non-overlapping Device-nGnR*
>> store to the same peripheral. This breaks the program-order guarantee
>> that software expects for Device-nGnR* accesses and can leave a
>> peripheral in an incorrect state, as a load is observed before an
>> earlier store takes effect.
>>
>> The erratum can occur only when all of the following apply:
>>
>> - A PE executes a Device-nGnR* store followed by a younger
>> Device-nGnR* load.
>> - The store is not a store-release.
>> - The accesses target the same peripheral and do not overlap in bytes.
>> - There is at most one intervening Device-nGnR* store in program
>> order, and there are no intervening Device-nGnR* loads.
>> - There is no DSB, and no DMB that orders loads, between the store and
>> the load.
>> - Specific micro-architectural and timing conditions occur.
>>
>> Two ways to restore ordering: insert a barrier (any DSB, or a DMB that
>> orders loads) between the store and the load, or make the store a
>> store-release. A load-acquire on the load side would not help, because
>> acquire semantics do not prevent a load from being observed ahead of an
>> older store; only the store side (release or a barrier) closes the
>> window.
> I think you can drop the paragraph above. A store-release isn't enough
> to order against a later load in the architecture either, so we're
> clearly in micro-architecture territory and I don't think you need to
> describe mechanisms that don't work here.
Thanks, Will. I’ll drop paragraph and avoid describing store-release
as an architectural ordering mechanism here.
>> Promote the raw MMIO store helpers (__raw_writeb/w/l/q) from plain str*
>> to stlr* (Store-Release), which removes the "store is not a
>> store-release" condition for every device write the kernel issues.
>> Because writel() and writel_relaxed() are both built on __raw_writel()
>> in asm-generic/io.h, patching the raw variants covers both the
>> non-relaxed and relaxed APIs without touching the higher layers. Note
>> that writel()'s own barrier sits before the store, so it does not order
>> the store against a subsequent readl(); the store-release promotion is
>> what provides that ordering.
> Sashiko points out that you're missing __const_memcpy_toio_aligned32().
I’ll also cover __const_memcpy_toio_aligned32(); it currently emits plain
STRs directly and can bypass the raw write helper workaround. I’ll audit
the aligned64 path at the same time.
>> Like ARM64_ERRATUM_832075 on the load side, the change is gated on a new
>> ARM64_WORKAROUND_DEVICE_STORE_RELEASE capability and only activated on
>> parts that match MIDR_NVIDIA_OLYMPUS, so unaffected CPUs continue to use
>> the plain str* sequence.
>>
>> Note: stlr* only supports base-register addressing, so the raw accessors
>> can no longer use the offset addressing introduced by commit d044d6ba6f02
>> ("arm64: io: permit offset addressing"). The str* and stlr* alternates
>> share a single inline-asm operand and the sequence is selected at boot,
>> so the operand form is fixed at compile time; unaffected CPUs keep using
>> str* but also revert to base-register addressing. This keeps the store
>> side as simple as the existing load-side patching (load-acquire) and
>> avoids adding complexity to the device write path; retaining offset
>> addressing only for str* would otherwise require a runtime branch on
>> every write.
> I seem to remember Jason caring about that, possibly because some CPUs
> are very picky about write-combining?
For the offset-addressing concern, I’ll rework the raw accessors so
unaffected CPUs keep the existing offset-addressed STR sequence, and
only CPUs with ARM64_WORKAROUND_DEVICE_STORE_RELEASE take the base-register
STLR path.
I’ll post a v3 using the patched branch from alternative_has_cap_unlikely(),
and include the memcpy_toio() aligned-helper coverage as shown below.
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -22,10 +22,46 @@
/*
* Generic IO read/write. These perform native-endian accesses.
*/
+static __always_inline bool arm64_needs_device_store_release(void)
+{
+ return alternative_has_cap_unlikely(
+ ARM64_WORKAROUND_DEVICE_STORE_RELEASE);
+}
+
+static __always_inline void __raw_writeb_stlr(u8 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlrb %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writew_stlr(u16 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlrh %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writel_stlr(u32 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlr %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writeq_stlr(u64 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlr %x0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
#define __raw_writeb __raw_writeb
static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
{
volatile u8 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writeb_stlr(val, addr);
+ return;
+ }
+
asm volatile("strb %w0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -33,6 +69,12 @@ static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
static __always_inline void __raw_writew(u16 val, volatile void __iomem *addr)
{
volatile u16 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writew_stlr(val, addr);
+ return;
+ }
+
asm volatile("strh %w0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -40,6 +82,12 @@ static __always_inline void __raw_writew(u16 val, volatile void __iomem *addr)
static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
{
volatile u32 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writel_stlr(val, addr);
+ return;
+ }
+
asm volatile("str %w0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -47,6 +95,12 @@ static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
static __always_inline void __raw_writeq(u64 val, volatile void __iomem *addr)
{
volatile u64 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writeq_stlr(val, addr);
+ return;
+ }
+
asm volatile("str %x0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -147,6 +201,12 @@ static __always_inline void
__const_memcpy_toio_aligned32(volatile u32 __iomem *to, const u32 *from,
size_t count)
{
+ if (arm64_needs_device_store_release()) {
+ while (count--)
+ __raw_writel_stlr(*from++, to++);
+ return;
+ }
+
switch (count) {
case 8:
asm volatile("str %w0, [%8, #4 * 0]\n"
@@ -204,6 +264,12 @@ static __always_inline void
__const_memcpy_toio_aligned64(volatile u64 __iomem *to, const u64 *from,
size_t count)
{
+ if (arm64_needs_device_store_release()) {
+ while (count--)
+ __raw_writeq_stlr(*from++, to++);
+ return;
+ }
+
switch (count) {
case 8:
asm volatile("str %x0, [%8, #8 * 0]\n"
I'll post v3 patch with jump instruction patch.
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -22,10 +22,46 @@
/*
* Generic IO read/write. These perform native-endian accesses.
*/
+static __always_inline bool arm64_needs_device_store_release(void)
+{
+ return alternative_has_cap_unlikely(
+ ARM64_WORKAROUND_DEVICE_STORE_RELEASE);
+}
+
+static __always_inline void __raw_writeb_stlr(u8 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlrb %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writew_stlr(u16 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlrh %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writel_stlr(u32 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlr %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writeq_stlr(u64 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlr %x0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
#define __raw_writeb __raw_writeb
static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
{
volatile u8 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writeb_stlr(val, addr);
+ return;
+ }
+
asm volatile("strb %w0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -33,6 +69,12 @@ static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
static __always_inline void __raw_writew(u16 val, volatile void __iomem *addr)
{
volatile u16 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writew_stlr(val, addr);
+ return;
+ }
+
asm volatile("strh %w0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -40,6 +82,12 @@ static __always_inline void __raw_writew(u16 val, volatile void __iomem *addr)
static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
{
volatile u32 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writel_stlr(val, addr);
+ return;
+ }
+
asm volatile("str %w0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -47,6 +95,12 @@ static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
static __always_inline void __raw_writeq(u64 val, volatile void __iomem *addr)
{
volatile u64 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writeq_stlr(val, addr);
+ return;
+ }
+
asm volatile("str %x0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -147,6 +201,12 @@ static __always_inline void
__const_memcpy_toio_aligned32(volatile u32 __iomem *to, const u32 *from,
size_t count)
{
+ if (arm64_needs_device_store_release()) {
+ while (count--)
+ __raw_writel_stlr(*from++, to++);
+ return;
+ }
+
switch (count) {
case 8:
asm volatile("str %w0, [%8, #4 * 0]\n"
@@ -204,6 +264,12 @@ static __always_inline void
__const_memcpy_toio_aligned64(volatile u64 __iomem *to, const u64 *from,
size_t count)
{
+ if (arm64_needs_device_store_release()) {
+ while (count--)
+ __raw_writeq_stlr(*from++, to++);
+ return;
+ }
+
switch (count) {
case 8:
asm volatile("str %x0, [%8, #8 * 0]\n"
-Shanker
^ permalink raw reply
* Re: [PATCH v2] arm64: errata: Workaround NVIDIA Olympus device store/load ordering erratum
From: Jason Gunthorpe @ 2026-06-10 12:50 UTC (permalink / raw)
To: Will Deacon
Cc: Shanker Donthineni, Catalin Marinas, linux-arm-kernel,
Vladimir Murzin, Mark Rutland, linux-kernel, linux-doc,
Vikram Sethi, Jason Sequeira
In-Reply-To: <ailKYTOX23EMnJsK@willie-the-truck>
On Wed, Jun 10, 2026 at 12:28:33PM +0100, Will Deacon wrote:
> > Note: stlr* only supports base-register addressing, so the raw accessors
> > can no longer use the offset addressing introduced by commit d044d6ba6f02
> > ("arm64: io: permit offset addressing"). The str* and stlr* alternates
> > share a single inline-asm operand and the sequence is selected at boot,
> > so the operand form is fixed at compile time; unaffected CPUs keep using
> > str* but also revert to base-register addressing. This keeps the store
> > side as simple as the existing load-side patching (load-acquire) and
> > avoids adding complexity to the device write path; retaining offset
> > addressing only for str* would otherwise require a runtime branch on
> > every write.
>
> I seem to remember Jason caring about that, possibly because some CPUs
> are very picky about write-combining?
I think it was more a fall out of the work there, after looking at the
assembly this minor edit to the constraint made a nice codegen
impact. It is certainly a shame to loose it for this bug.
If we care about write combining we can't have a branch anyhow, but
that is most important for the specific memcpy operations (which will
need a branch)
Jason
^ permalink raw reply
* Re: [PATCH v4 2/2] cpu/hotplug: Fix NULL kobject warning in cpuhp_smt_enable()
From: Catalin Marinas @ 2026-06-10 12:43 UTC (permalink / raw)
To: Jinjie Ruan
Cc: will, corbet, skhan, punit.agrawal, mrigendra.chaubey,
suzuki.poulose, chenl311, fengchengwen, maz, timothy.hayes,
lpieralisi, arnd, gshan, jic23, dietmar.eggemann, sudeep.holla,
pierre.gondois, linux-arm-kernel, linux-doc, linux-kernel
In-Reply-To: <20260610075202.3597031-3-ruanjinjie@huawei.com>
On Wed, Jun 10, 2026 at 03:52:02PM +0800, Jinjie Ruan wrote:
> diff --git a/Documentation/arch/arm64/cpu-hotplug.rst b/Documentation/arch/arm64/cpu-hotplug.rst
> index 8fb438bf7781..7c3379b704aa 100644
> --- a/Documentation/arch/arm64/cpu-hotplug.rst
> +++ b/Documentation/arch/arm64/cpu-hotplug.rst
> @@ -47,11 +47,12 @@ ever have can be described at boot. There are no power-domain considerations
> as such devices are emulated.
>
> CPU Hotplug on virtual systems is supported. It is distinct from physical
> -CPU Hotplug as all resources are described as ``present``, but CPUs may be
> -marked as disabled by firmware. Only the CPU's online/offline behaviour is
> -influenced by firmware. An example is where a virtual machine boots with a
> -single CPU, and additional CPUs are added once a cloud orchestrator deploys
> -the workload.
> +CPU Hotplug as all vCPU resources are statically described in the firmware
> +configuration tables (e.g. MADT), meaning their maximum possible count is
> +known at boot. However, vCPUs that are not enabled at boot are not marked
> +as ``present`` by the kernel until they are hotplugged. An example is where
> +a virtual machine boots with a single CPU, and additional CPUs are added
> +once a cloud orchestrator deploys the workload.
>
> For a virtual machine, the VMM (e.g. Qemu) plays the part of firmware.
>
> @@ -60,16 +61,19 @@ brought online. Firmware can enforce its policy via PSCI's return codes. e.g.
> ``DENIED``.
>
> The ACPI tables must describe all the resources of the virtual machine. CPUs
> -that firmware wishes to disable either from boot (or later) should not be
> -``enabled`` in the MADT GICC structures, but should have the ``online capable``
> -bit set, to indicate they can be enabled later. The boot CPU must be marked as
> -``enabled``. The 'always on' GICR structure must be used to describe the
> -redistributors.
> +that are hot-pluggable must have the ``online capable`` bit set and the
> +``enabled`` bit cleared in the MADT GICC structures to indicate they can be
> +enabled later. The boot CPU must be marked as ``enabled`` with its
> +``online capable`` bit cleared. The 'always on' GICR structure must be used
> +to describe the redistributors.
>
> CPUs described as ``online capable`` but not ``enabled`` can be set to enabled
> by the DSDT's Processor object's _STA method. On virtual systems the _STA method
> -must always report the CPU as ``present``. Changes to the firmware policy can
> -be notified to the OS via device-check or eject-request.
> +must always set the ``ACPI_STA_DEVICE_PRESENT`` bit, while toggling the
> +``ACPI_STA_DEVICE_ENABLED`` bit to reflect its plug status. The kernel will
> +then dynamically mark the vCPU as ``present`` within the OS when the
> +``ACPI_STA_DEVICE_ENABLED`` bit becomes set during hot-add. Changes to the
> +firmware policy can be notified to the OS via device-check or eject-request.
The doc update looks fine as well, thanks for clarifying. My reviewed-by
stands.
--
Catalin
^ permalink raw reply
* Re: [RFC PATCH v1 00/13] exec: add spawn templates for repeated executable startup
From: Li Chen @ 2026-06-10 12:29 UTC (permalink / raw)
To: John Ericson
Cc: Andy Lutomirski, Christian Brauner, Kees Cook, Al Viro,
linux-fsdevel, linux-api, LKML, linux-mm, linux-arch, linux-doc,
linux-kselftest, x86, Arnd Bergmann, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, H. Peter Anvin, Jan Kara,
Jonathan Corbet, Shuah Khan
In-Reply-To: <4e049396-377d-48a7-a34c-91318413a876@app.fastmail.com>
Hi John,
---- On Wed, 10 Jun 2026 01:27:47 +0800 John Ericson <mail@johnericson.me> wrote ---
>
>
> On Tue, Jun 9, 2026, at 10:43 AM, Li Chen wrote:
> > Hi Andy,
> >
> > ---- On Tue, 09 Jun 2026 08:01:57 +0800 Andy Lutomirski <luto@kernel.org> wrote ---
> > > [...]
> > >
> > > After contemplating this for a bit... why pidfd? Doesn't a pidfd
> > > refer to an actual process that is, or at least was, running? This
> > > new thing is a process that we are contemplating spawning. I can
> > > imagine that basically all pidfd APIs would be a bit confused by the
> > > nonexistence of the process in question.
> > >
> >
> > Yes, I think that is a real concern.
> >
> > In my current local WIP I tried to keep that distinction explicit.
> > pidfd_spawn_open() returns a pidfs-backed builder fd, not a normal pidfd
> > referring to a process. The builder fd is allocated as an anonymous pidfs
> > file with builder-specific file operations:
> >
> > file = pidfs_alloc_anon_file("[pidfd_spawn]",
> > &pidfd_spawn_builder_fops, builder,
> > O_RDWR);
> >
>
> What does your builder fd point to, explicitly? For example in my other reply I
> talked about how it was "real" process state. In my FreeBSD patch, for example,
> I found there was already a status for a process "in exec", and I figured that
> was clean to reuse for one of these "embryonic" processes that also hadn't
> started running. I would reckon that Linux probably has some similar notions.
>
> > and the normal pidfd helpers still reject it because it does not use the
> > ordinary pidfd file operations:
> >
> > struct pid *pidfd_pid(const struct file *file)
> > {
> > if (file->f_op != &pidfs_file_operations)
> > return ERR_PTR(-EBADF);
> > return file_inode(file)->i_private;
> > }
> >
> > So the current split is:
> >
> > builder_fd = pidfd_spawn_open(...); /* builder object */
> > pidfd_config(builder_fd, ...);
> > child_pidfd = pidfd_spawn_run(builder_fd, ...); /* real pidfd */
> >
> > Only the last fd is a normal pidfd for an actual child process. The builder
> > fd is only accepted by the builder operations.
> >
> > This avoids having to define what waitid(P_PIDFD), pidfd_send_signal(),
> > pidfd_getfd(), poll(), etc. mean before the process exists.
>
> I wouldn't be so sure this is necessary/good. For example, I think it could
> make sense to wait on a process that has yet to be started; one just waits for
> both the process to start and the process to exit. Obviously a blocking syscall
> in the thread that is spawning the process is not useful, but the asynchronous
> poll variation seems fine.
>
> As long as there is real process state here, it shouldn't be too hard to
> implement.
>
> > The downside is that it adds a separate open-style entry point and is less
> > uniform than the pidfd_open(0, PIDFD_EMPTY) spelling Christian sketched.
>
> I do think there is no point having two file descriptors. The file descriptor
> that previously referred to the builder/embryonic process then can refer to the
> real process, right?
>
> > If people think there is a better way to represent the pre-spawn builder
> > state, or if the preference is to integrate it directly into pidfd_open()
> > with an explicit empty/future-pidfd state, I would be happy to discuss that.
>
> Hope the above answers your question? I suppose my ideas lean more on the
> "future" than "empty" side --- there is indeed a thread in the thread group,
> with real VM/namespace/file descriptor etc. state. Moreover, state gets
> initialized before the process is started, so the actual start is a pretty
> lightweight step of just letting the scheduler know the now-ready process can
> be scheduled. The only thing that distinguishes the embryonic process from a
> real one is simply that it isn't running --- i.e. isn't (yet) available to be
> scheduled --- so the pidfds holders are free to poke at its state.
>
> Cheers,
>
> John
>
Thanks, this helped a lot. I looked at FreeBSD/OpenBSD/XNU after your
note. FreeBSD has P_INEXEC, OpenBSD has PS_INEXEC, and XNU seems even
closer with P_LINTRANSIT, described as "process in exec or in creation".
Linux does not seem to have a single equivalent today: current->in_execve
is only an LSM hint, while the real synchronization is spread across
exec_update_lock, cred_guard_mutex, and the exec path.
I am switching my local WIP from the two-fd builder model to one fd,
closer to Christian's sketch:
fd = pidfd_open(0, PIDFD_EMPTY);
pidfd_config(fd, ...);
pidfd_spawn_run(fd, ...);
In my current local version, I still use copy_process(), so the fd points
at a real task_struct/pid that is not woken until run. Following
Christian's point that existing APIs can handle this not-yet-running case
with ESRCH, I currently make ordinary pidfd operations that need a real
started process return -ESRCH before start.
I am not sure yet whether Linux should grow a general exec/creation
transition state like that, or whether a narrower future-process
lifecycle is enough for this API. I will think more about that when
working on the pristine process version.
Regards,
Li
^ permalink raw reply
* Re: [PATCH v1] arm64: errata: Mitigate TLBI errata on NVIDIA Olympus CPU
From: Will Deacon @ 2026-06-10 12:14 UTC (permalink / raw)
To: Catalin Marinas, linux-arm-kernel, Mark Rutland,
Shanker Donthineni
Cc: kernel-team, Will Deacon, linux-kernel, linux-doc, Vikram Sethi,
Jason Sequeira, Alok Mooley, Rich Wiley
In-Reply-To: <20260609234044.3945938-1-sdonthineni@nvidia.com>
On Tue, 09 Jun 2026 18:40:44 -0500, Shanker Donthineni wrote:
> NVIDIA Olympus cores are affected by the TLBI completion issue tracked as
> CVE-2025-10263. The existing ARM64_ERRATUM_4118414 handling already uses
> ARM64_WORKAROUND_REPEAT_TLBI to issue an additional broadcast TLBI;DSB
> sequence and ensure affected memory write effects are globally observed.
>
> Add MIDR_NVIDIA_OLYMPUS to the repeat-TLBI match list so the same
> mitigation is enabled on affected Olympus systems. Also document the
> NVIDIA Olympus erratum in the arm64 silicon errata table and list it in
> the Kconfig help text.
>
> [...]
Applied to arm64 (for-next/errata), thanks!
[1/1] arm64: errata: Mitigate TLBI errata on NVIDIA Olympus CPU
https://git.kernel.org/arm64/c/ec7216f92e4e
Cheers,
--
Will
https://fixes.arm64.dev
https://next.arm64.dev
https://will.arm64.dev
^ permalink raw reply
* Re: [PATCH v17 21/28] drm/tests: bridge: Add KUnit tests for bridge chain format selection
From: Jani Nikula @ 2026-06-10 11:54 UTC (permalink / raw)
To: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel
In-Reply-To: <gnicb4WkT1S4aQIC2G_naw@collabora.com>
On Wed, 10 Jun 2026, Nicolas Frattaroli <nicolas.frattaroli@collabora.com> wrote:
> If you don't want __maybe_unused, then sure, I'll move them into a new
> .c file. Though I think the two are roughly equivalent in that I don't
> think anyone is really trying to minimise the size of their KUnit
> binaries.
I think placing arrays in headers is bad practice, and we shouldn't set
that example, kunit or not.
> I'll send a patch to move them to a .c
Thanks.
BR,
Jani.
--
Jani Nikula, Intel
^ permalink raw reply
* Re: [PATCH v17 21/28] drm/tests: bridge: Add KUnit tests for bridge chain format selection
From: Nicolas Frattaroli @ 2026-06-10 11:42 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, Daniel Stone, Jani Nikula
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel
In-Reply-To: <04ff70850213ae0f75486b1a27a7edb6fb4e71c3@intel.com>
On Wednesday, 10 June 2026 12:32:29 Central European Summer Time Jani Nikula wrote:
> On Tue, 09 Jun 2026, Nicolas Frattaroli <nicolas.frattaroli@collabora.com> wrote:
> > diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c
> > index 64b665580a88..92f142ca6695 100644
> > --- a/drivers/gpu/drm/tests/drm_bridge_test.c
> > +++ b/drivers/gpu/drm/tests/drm_bridge_test.c
> > @@ -2,15 +2,23 @@
> > /*
> > * Kunit test for drm_bridge functions
> > */
> > +#include <linux/cleanup.h>
> > +#include <linux/media-bus-format.h>
> > +
> > #include <drm/drm_atomic_state_helper.h>
> > +#include <drm/drm_atomic_uapi.h>
> > #include <drm/drm_bridge.h>
> > #include <drm/drm_bridge_connector.h>
> > #include <drm/drm_bridge_helper.h>
> > +#include <drm/drm_edid.h>
> > #include <drm/drm_kunit_helpers.h>
> > +#include <drm/drm_managed.h>
> >
> > #include <kunit/device.h>
> > #include <kunit/test.h>
> >
> > +#include "drm_kunit_edid.h"
>
> So here's the problem with adding *any* arrays into headers: every
> compilation unit that includes them duplicates all the arrays. It's only
> really okay for single use.
>
> And, in this case, most of the included arrays are unused, leading to
> build failures:
>
> CC [M] drivers/gpu/drm/tests/drm_bridge_test.o
> In file included from ../drivers/gpu/drm/tests/drm_bridge_test.c:21:
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:958:28: error: ‘test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz’ defined but not used [-Werror=unused-const-variable=]
> 958 | static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:726:28: error: ‘test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz’ defined but not used [-Werror=unused-const-variable=]
> 726 | static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:612:28: error: ‘test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz’ defined but not used [-Werror=unused-const-variable=]
> 612 | static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz[] = {
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:498:28: error: ‘test_edid_hdmi_1080p_rgb_max_340mhz’ defined but not used [-Werror=unused-const-variable=]
> 498 | static const unsigned char test_edid_hdmi_1080p_rgb_max_340mhz[] = {
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:390:28: error: ‘test_edid_hdmi_1080p_rgb_max_200mhz_hdr’ defined but not used [-Werror=unused-const-variable=]
> 390 | static const unsigned char test_edid_hdmi_1080p_rgb_max_200mhz_hdr[] = {
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:271:28: error: ‘test_edid_hdmi_1080p_rgb_max_200mhz’ defined but not used [-Werror=unused-const-variable=]
> 271 | static const unsigned char test_edid_hdmi_1080p_rgb_max_200mhz[] = {
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:163:28: error: ‘test_edid_hdmi_1080p_rgb_max_100mhz’ defined but not used [-Werror=unused-const-variable=]
> 163 | static const unsigned char test_edid_hdmi_1080p_rgb_max_100mhz[] = {
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:57:28: error: ‘test_edid_dvi_1080p’ defined but not used [-Werror=unused-const-variable=]
> 57 | static const unsigned char test_edid_dvi_1080p[] = {
> | ^~~~~~~~~~~~~~~~~~~
> cc1: all warnings being treated as errors
>
> This breaks the build for me, I don't know how it didn't for any of you.
It broke the build for me in the past[1], but then I couldn't repro
it anymore when challenged on my fix[2].
>
> Reverting these two fixes it:
>
> ce1d0139adac ("drm/tests: bridge: Add test for HDMI output bus formats helper")
> 082fbc179c01 ("drm/tests: bridge: Add KUnit tests for bridge chain format selection")
>
> I think the proper fix would be to move the arrays into a .c file, and
> only have declarations in the headers. But that needs to happen real
> soon or the commits need to be reverted.
If you don't want __maybe_unused, then sure, I'll move them into a new
.c file. Though I think the two are roughly equivalent in that I don't
think anyone is really trying to minimise the size of their KUnit
binaries.
I'll send a patch to move them to a .c
[1]: https://lore.kernel.org/dri-devel/20260121-color-format-v7-20-ef790dae780c@collabora.com/
[2]: https://lore.kernel.org/dri-devel/20260210-didactic-okapi-of-modernism-ff00d9@houat/
Kind regards,
Nicolas Frattaroli
>
> BR,
> Jani.
>
>
>
^ permalink raw reply
* Re: [PATCH v4 1/2] arm64: smp: Fix hot-unplug tearing by forcing unregistration
From: Catalin Marinas @ 2026-06-10 11:38 UTC (permalink / raw)
To: Jinjie Ruan
Cc: will, corbet, skhan, punit.agrawal, mrigendra.chaubey,
suzuki.poulose, chenl311, fengchengwen, maz, timothy.hayes,
lpieralisi, arnd, gshan, jic23, dietmar.eggemann, sudeep.holla,
pierre.gondois, linux-arm-kernel, linux-doc, linux-kernel
In-Reply-To: <20260610075202.3597031-2-ruanjinjie@huawei.com>
On Wed, Jun 10, 2026 at 03:52:01PM +0800, Jinjie Ruan wrote:
> Sashiko review pointed out the following issue[1].
>
> Commit eba4675008a6 ("arm64: arch_register_cpu() variant to check if
> an ACPI handle is now available.") introduced architectural safety
> blocks inside arch_unregister_cpu(). If a hot-unplug operation is
> determined to be a physical hardware removal (where _STA evaluates to
> !ACPI_STA_DEVICE_PRESENT), or if firmware evaluation fails, it aborts
> the unregistration transaction early to protect unreadied arm64
> infrastructure.
>
> However, returning early from arch_unregister_cpu() causes a catastrophic
> state tearing because the generic ACPI layer (acpi_processor_post_eject())
> unconditionally continues its cleanup flow. This leaves the stale sysfs
> device leaked in the memory, deadlocking any subsequent hot-add attempts
> on the same CPU.
>
> Fix it by simplifying arch_unregister_cpu() to always proceed with
> the unregistration, as a pr_err_once() warning is sufficient to make
> it more visible for currently not supported physical CPU removal.
> Also remove the redundant NULL check on acpi_handle as it cannot be
> NULL when calling arch_unregister_cpu().
>
> [1]: https://sashiko.dev/#/patchset/20260520022023.126670-1-ruanjinjie@huawei.com
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Jonathan Cameron <jic23@kernel.org>
> Cc: James Morse <james.morse@arm.com>
> Cc: stable@vger.kernel.org
> Fixes: eba4675008a6e ("arm64: arch_register_cpu() variant to check if an ACPI handle is now available.")
> Suggested-by: Catalin Marinas <catalin.marinas@arm.com>
> Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
^ permalink raw reply
* Re: [PATCH v2] arm64: errata: Workaround NVIDIA Olympus device store/load ordering erratum
From: Will Deacon @ 2026-06-10 11:28 UTC (permalink / raw)
To: Shanker Donthineni
Cc: Catalin Marinas, linux-arm-kernel, Vladimir Murzin, Mark Rutland,
linux-kernel, linux-doc, Vikram Sethi, Jason Sequeira, jgg
In-Reply-To: <20260605144551.2004391-1-sdonthineni@nvidia.com>
[+Jason G]
On Fri, Jun 05, 2026 at 09:45:51AM -0500, Shanker Donthineni wrote:
> On systems with NVIDIA Olympus cores, a Device-nGnR* load can be
> observed by a peripheral before an older, non-overlapping Device-nGnR*
> store to the same peripheral. This breaks the program-order guarantee
> that software expects for Device-nGnR* accesses and can leave a
> peripheral in an incorrect state, as a load is observed before an
> earlier store takes effect.
>
> The erratum can occur only when all of the following apply:
>
> - A PE executes a Device-nGnR* store followed by a younger
> Device-nGnR* load.
> - The store is not a store-release.
> - The accesses target the same peripheral and do not overlap in bytes.
> - There is at most one intervening Device-nGnR* store in program
> order, and there are no intervening Device-nGnR* loads.
> - There is no DSB, and no DMB that orders loads, between the store and
> the load.
> - Specific micro-architectural and timing conditions occur.
>
> Two ways to restore ordering: insert a barrier (any DSB, or a DMB that
> orders loads) between the store and the load, or make the store a
> store-release. A load-acquire on the load side would not help, because
> acquire semantics do not prevent a load from being observed ahead of an
> older store; only the store side (release or a barrier) closes the
> window.
I think you can drop the paragraph above. A store-release isn't enough
to order against a later load in the architecture either, so we're
clearly in micro-architecture territory and I don't think you need to
describe mechanisms that don't work here.
> Promote the raw MMIO store helpers (__raw_writeb/w/l/q) from plain str*
> to stlr* (Store-Release), which removes the "store is not a
> store-release" condition for every device write the kernel issues.
> Because writel() and writel_relaxed() are both built on __raw_writel()
> in asm-generic/io.h, patching the raw variants covers both the
> non-relaxed and relaxed APIs without touching the higher layers. Note
> that writel()'s own barrier sits before the store, so it does not order
> the store against a subsequent readl(); the store-release promotion is
> what provides that ordering.
Sashiko points out that you're missing __const_memcpy_toio_aligned32().
> Like ARM64_ERRATUM_832075 on the load side, the change is gated on a new
> ARM64_WORKAROUND_DEVICE_STORE_RELEASE capability and only activated on
> parts that match MIDR_NVIDIA_OLYMPUS, so unaffected CPUs continue to use
> the plain str* sequence.
>
> Note: stlr* only supports base-register addressing, so the raw accessors
> can no longer use the offset addressing introduced by commit d044d6ba6f02
> ("arm64: io: permit offset addressing"). The str* and stlr* alternates
> share a single inline-asm operand and the sequence is selected at boot,
> so the operand form is fixed at compile time; unaffected CPUs keep using
> str* but also revert to base-register addressing. This keeps the store
> side as simple as the existing load-side patching (load-acquire) and
> avoids adding complexity to the device write path; retaining offset
> addressing only for str* would otherwise require a runtime branch on
> every write.
I seem to remember Jason caring about that, possibly because some CPUs
are very picky about write-combining?
Will
^ permalink raw reply
* Re: [PATCH v1] arm64: errata: Mitigate TLBI errata on NVIDIA Olympus CPU
From: Mark Rutland @ 2026-06-10 11:28 UTC (permalink / raw)
To: Shanker Donthineni
Cc: Catalin Marinas, Will Deacon, linux-arm-kernel, linux-kernel,
linux-doc, Vikram Sethi, Jason Sequeira, Alok Mooley, Rich Wiley
In-Reply-To: <aik1owW9Rz8B7rEz@J2N7QTR9R3>
On Wed, Jun 10, 2026 at 11:00:03AM +0100, Mark Rutland wrote:
> On Tue, Jun 09, 2026 at 06:40:44PM -0500, Shanker Donthineni wrote:
> I have one minor comment below, but that's more for Catalin/Will, and
> doesn't require a respin.
[...]
> As this is getting increasingly long, maybe it's worth reducing this to
> "Various" in the title, i.e.
>
> bool "Cortex-*/Neoverse: Completion of affected memory accesses might not be guaranteed by completion of a TLBI"
Sorry, I messed that up when copy-editing. That should have been:
bool "Various: Completion of affected memory accesses might not be guaranteed by completion of a TLBI"
As above, that doesn't need a respin.
Mark.
^ permalink raw reply
* Re: [PATCH v4 1/6] alloc_tag: add ioctl to /proc/allocinfo
From: Usama Arif @ 2026-06-10 11:23 UTC (permalink / raw)
To: Abhishek Bapat
Cc: Usama Arif, Suren Baghdasaryan, Andrew Morton, Kent Overstreet,
Hao Ge, Shuah Khan, Jonathan Corbet, linux-doc, linux-kernel,
linux-mm, Sourav Panda
In-Reply-To: <b58a0d01c8bb6d7c1d2350599c1b0170be161489.1781042698.git.abhishekbapat@google.com>
On Wed, 10 Jun 2026 00:12:54 +0000 Abhishek Bapat <abhishekbapat@google.com> wrote:
> From: Suren Baghdasaryan <surenb@google.com>
>
> Add the following ioctl commands for /proc/allocinfo file:
>
> ALLOCINFO_IOC_CONTENT_ID - gets content identifier which can be used
> to check whether the file content has changed specifically due to module
> load/unload. Every time a module is loaded / unloaded, the returned
> value will be different. By comparing the identifier value at the
> beginning and at the end of the content retrieval operation, users can
> validate retrieved information for consistency.
>
> ALLOCINFO_IOC_GET_AT - gets the record at the specified position. This
> is the position of a record in /proc/allocinfo.
>
> ALLOCINFO_IOC_GET_NEXT - gets the record next to the last retrieved
> one. If no records were previously retrieved, returns the first
> record.
>
> Signed-off-by: Suren Baghdasaryan <surenb@google.com>
> Signed-off-by: Abhishek Bapat <abhishekbapat@google.com>
> ---
> Documentation/mm/allocation-profiling.rst | 5 +
> .../userspace-api/ioctl/ioctl-number.rst | 2 +
> MAINTAINERS | 1 +
> include/linux/codetag.h | 2 +
> include/uapi/linux/alloc_tag.h | 60 +++++
> lib/alloc_tag.c | 232 +++++++++++++++++-
> lib/codetag.c | 18 ++
> 7 files changed, 318 insertions(+), 2 deletions(-)
> create mode 100644 include/uapi/linux/alloc_tag.h
>
> diff --git a/Documentation/mm/allocation-profiling.rst b/Documentation/mm/allocation-profiling.rst
> index 5389d241176a..c3a28467955f 100644
> --- a/Documentation/mm/allocation-profiling.rst
> +++ b/Documentation/mm/allocation-profiling.rst
> @@ -46,6 +46,11 @@ sysctl:
> Runtime info:
> /proc/allocinfo
>
> + Profiling data can be retrieved either by reading `/proc/allocinfo` directly as
> + text or programmatically via `ioctl()` calls defined in `<uapi/linux/alloc_tag.h>`.
> + The ioctl interface supports structured binary data extraction as well as filtering
> + by module name, function, file, line number, accuracy, or allocation size limits.
> +
> Example output::
>
> root@moria-kvm:~# sort -g /proc/allocinfo|tail|numfmt --to=iec
> diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
> index 331223761fff..84f6808a8578 100644
> --- a/Documentation/userspace-api/ioctl/ioctl-number.rst
> +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
> @@ -349,6 +349,8 @@ Code Seq# Include File Comments
> <mailto:luzmaximilian@gmail.com>
> 0xA5 20-2F linux/surface_aggregator/dtx.h Microsoft Surface DTX driver
> <mailto:luzmaximilian@gmail.com>
> +0xA6 00-0F uapi/linux/alloc_tag.h Memory allocation profiling
> + <mailto:surenb@google.com>
> 0xAA 00-3F linux/uapi/linux/userfaultfd.h
> 0xAB 00-1F linux/nbd.h
> 0xAC 00-1F linux/raw.h
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 65bd4328fe05..019cc4c285a3 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -16713,6 +16713,7 @@ S: Maintained
> F: Documentation/mm/allocation-profiling.rst
> F: include/linux/alloc_tag.h
> F: include/linux/pgalloc_tag.h
> +F: include/uapi/linux/alloc_tag.h
> F: lib/alloc_tag.c
>
> MEMORY CONTROLLER DRIVERS
> diff --git a/include/linux/codetag.h b/include/linux/codetag.h
> index ddae7484ca45..a25a085c2df1 100644
> --- a/include/linux/codetag.h
> +++ b/include/linux/codetag.h
> @@ -77,6 +77,8 @@ struct codetag_iterator {
> void codetag_lock_module_list(struct codetag_type *cttype);
> bool codetag_trylock_module_list(struct codetag_type *cttype);
> void codetag_unlock_module_list(struct codetag_type *cttype);
> +unsigned long codetag_get_content_id(struct codetag_type *cttype);
> +unsigned int codetag_get_count(struct codetag_type *cttype);
> struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype);
> struct codetag *codetag_next_ct(struct codetag_iterator *iter);
>
> diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h
> new file mode 100644
> index 000000000000..0928e1a48d49
> --- /dev/null
> +++ b/include/uapi/linux/alloc_tag.h
> @@ -0,0 +1,60 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +/*
> + * alloc_tag IOCTL API definition
> + *
> + * Copyright (C) 2026 Google, LLC. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef _UAPI_ALLOC_TAG_H
> +#define _UAPI_ALLOC_TAG_H
> +
> +#include <linux/types.h>
> +
> +#define ALLOCINFO_STR_SIZE 64
> +
> +struct allocinfo_content_id {
> + __u64 id;
> +};
> +
> +struct allocinfo_tag {
> + /* Longer names are trimmed */
> + char modname[ALLOCINFO_STR_SIZE];
> + char function[ALLOCINFO_STR_SIZE];
> + char filename[ALLOCINFO_STR_SIZE];
> + __u64 lineno;
> +};
> +
> +/* The alignment ensures 32-bit compatible interfaces are not broken */
> +struct allocinfo_counter {
> + __u64 bytes;
> + __u64 calls;
> + __u8 accurate;
> +} __attribute__((aligned(8)));
> +
> +struct allocinfo_tag_data {
> + struct allocinfo_tag tag;
> + struct allocinfo_counter counter;
> +};
> +
> +struct allocinfo_get_at {
> + __u64 pos; /* input */
> + struct allocinfo_tag_data data;
> +};
> +
> +#define _ALLOCINFO_IOC_CONTENT_ID 0
> +#define _ALLOCINFO_IOC_GET_AT 1
> +#define _ALLOCINFO_IOC_GET_NEXT 2
> +
> +#define ALLOCINFO_IOC_BASE 0xA6
> +#define ALLOCINFO_IOC_CONTENT_ID _IOR(ALLOCINFO_IOC_BASE, _ALLOCINFO_IOC_CONTENT_ID, \
> + struct allocinfo_content_id)
> +#define ALLOCINFO_IOC_GET_AT _IOWR(ALLOCINFO_IOC_BASE, _ALLOCINFO_IOC_GET_AT, \
> + struct allocinfo_get_at)
> +#define ALLOCINFO_IOC_GET_NEXT _IOR(ALLOCINFO_IOC_BASE, _ALLOCINFO_IOC_GET_NEXT, \
> + struct allocinfo_tag_data)
> +
> +#endif /* _UAPI_ALLOC_TAG_H */
> diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c
> index d9be1cf5187d..a0577215eb3d 100644
> --- a/lib/alloc_tag.c
> +++ b/lib/alloc_tag.c
> @@ -5,6 +5,7 @@
> #include <linux/gfp.h>
> #include <linux/kallsyms.h>
> #include <linux/module.h>
> +#include <linux/mutex.h>
> #include <linux/page_ext.h>
> #include <linux/pgalloc_tag.h>
> #include <linux/proc_fs.h>
> @@ -14,6 +15,7 @@
> #include <linux/string_choices.h>
> #include <linux/vmalloc.h>
> #include <linux/kmemleak.h>
> +#include <uapi/linux/alloc_tag.h>
>
> #define ALLOCINFO_FILE_NAME "allocinfo"
> #define MODULE_ALLOC_TAG_VMAP_SIZE (100000UL * sizeof(struct alloc_tag))
> @@ -47,6 +49,10 @@ struct allocinfo_private {
> struct codetag_iterator iter;
> struct codetag_iterator reported_iter;
> bool print_header;
> + /* ioctl uses a separate iterator not to interfere with reads */
> + struct codetag_iterator ioctl_iter;
> + bool positioned; /* seq_open_private() sets to 0 */
> + struct mutex ioctl_lock;
> };
>
> static void *allocinfo_start(struct seq_file *m, loff_t *pos)
> @@ -130,6 +136,229 @@ static const struct seq_operations allocinfo_seq_op = {
> .show = allocinfo_show,
> };
>
> +/*
> + * Initializes seq_file operations and allocates private state when opening
> + * the /proc/allocinfo procfs entry.
> + */
> +static int allocinfo_open(struct inode *inode, struct file *file)
> +{
> + int ret;
> +
> + ret = seq_open_private(file, &allocinfo_seq_op,
> + sizeof(struct allocinfo_private));
> + if (!ret) {
> + struct seq_file *m = file->private_data;
> + struct allocinfo_private *priv = m->private;
> +
> + mutex_init(&priv->ioctl_lock);
> + }
> + return ret;
> +}
> +
> +/*
> + * Cleans up the seq_file state and frees up the private state allocated in
> + * allocinfo_open() when closing the /proc/allocinfo file descriptor.
> + */
> +static int allocinfo_release(struct inode *inode, struct file *file)
> +{
Need to destory the mutex here like below?
struct seq_file *m = file->private_data;
struct allocinfo_private *priv = m->private;
mutex_destroy(&priv->ioctl_lock);
> + return seq_release_private(inode, file);
> +}
> +
> +/*
> + * Returns a pointer to the suffix of a string so that its length fits within
> + * ALLOCINFO_STR_SIZE, preserving the trailing characters.
> + */
> +static const char *allocinfo_str(const char *str)
> +{
> + size_t len = strlen(str);
> +
> + /* Keep an extra space for the trailing NULL. */
> + if (len >= ALLOCINFO_STR_SIZE)
> + str += (len - ALLOCINFO_STR_SIZE) + 1;
> + return str;
> +}
> +
> +/* Copy a string and trim from the beginning if it's too long */
> +static void allocinfo_copy_str(char *dest, const char *src)
> +{
> + strscpy_pad(dest, allocinfo_str(src), ALLOCINFO_STR_SIZE);
> +}
> +
> +/*
> + * Populates the UAPI allocinfo_tag_data structure with active runtime
> + * profiling counters extracted from the given kernel codetag.
> + */
> +static void allocinfo_to_params(struct codetag *ct,
> + struct allocinfo_tag_data *data)
> +{
> + struct alloc_tag *tag = ct_to_alloc_tag(ct);
> + struct alloc_tag_counters counter = alloc_tag_read(tag);
> +
> + if (ct->modname)
> + allocinfo_copy_str(data->tag.modname, ct->modname);
> + else
> + data->tag.modname[0] = '\0';
> + allocinfo_copy_str(data->tag.function, ct->function);
> + allocinfo_copy_str(data->tag.filename, ct->filename);
> + data->tag.lineno = ct->lineno;
> + data->counter.bytes = counter.bytes;
> + data->counter.calls = counter.calls;
> + data->counter.accurate = !alloc_tag_is_inaccurate(tag);
> +}
> +
> +/*
> + * Retrieves the unique content ID representing the current allocation tag module
> + * layout, allowing userspace to detect if modules were loaded / unloaded.
> + */
> +static int allocinfo_ioctl_get_content_id(struct seq_file *m, void __user *arg)
> +{
> + struct allocinfo_content_id params;
> +
> + codetag_lock_module_list(alloc_tag_cttype);
> + params.id = codetag_get_content_id(alloc_tag_cttype);
> + codetag_unlock_module_list(alloc_tag_cttype);
> + if (copy_to_user(arg, ¶ms, sizeof(params)))
> + return -EFAULT;
> +
> + return 0;
> +}
> +
> +/*
> + * Seeks the ioctl iterator to the specified 0-indexed tag position, reads its
> + * profiling data and returns it to userspace.
> + */
> +static int allocinfo_ioctl_get_at(struct seq_file *m, void __user *arg)
> +{
> + struct allocinfo_private *priv;
> + struct codetag *ct;
> + __u64 pos;
> + struct allocinfo_get_at params = {0};
> +
> + if (copy_from_user(¶ms, arg, sizeof(params)))
> + return -EFAULT;
> +
> + priv = m->private;
> + pos = params.pos;
> +
> + mutex_lock(&priv->ioctl_lock);
> + codetag_lock_module_list(alloc_tag_cttype);
> +
> + if (pos >= codetag_get_count(alloc_tag_cttype)) {
> + codetag_unlock_module_list(alloc_tag_cttype);
> + mutex_unlock(&priv->ioctl_lock);
> + return -ENOENT;
> + }
> +
> + /* Find the codetag */
> + priv->ioctl_iter = codetag_get_ct_iter(alloc_tag_cttype);
> + ct = codetag_next_ct(&priv->ioctl_iter);
> + while (ct && pos--)
> + ct = codetag_next_ct(&priv->ioctl_iter);
> + if (ct) {
> + allocinfo_to_params(ct, ¶ms.data);
> + priv->positioned = true;
> + }
> +
> + codetag_unlock_module_list(alloc_tag_cttype);
> + mutex_unlock(&priv->ioctl_lock);
> +
> + if (!ct)
> + return -ENOENT;
> +
> + if (copy_to_user(arg, ¶ms, sizeof(params)))
> + return -EFAULT;
> +
> + return 0;
> +}
> +
> +/*
> + * Advances the ioctl iterator to the next allocation tag in the sequence and
> + * returns its profiling data to userspace.
> + */
> +static int allocinfo_ioctl_get_next(struct seq_file *m, void __user *arg)
> +{
> + struct allocinfo_private *priv;
> + struct codetag *ct;
> + struct allocinfo_tag_data params;
> + int ret = 0;
> +
> + memset(¶ms, 0, sizeof(params));
> + priv = m->private;
> +
> + mutex_lock(&priv->ioctl_lock);
> + codetag_lock_module_list(alloc_tag_cttype);
> +
> + if (!priv->positioned) {
> + priv->ioctl_iter = codetag_get_ct_iter(alloc_tag_cttype);
> + priv->positioned = true;
> + }
> +
> + ct = codetag_next_ct(&priv->ioctl_iter);
> + if (ct)
> + allocinfo_to_params(ct, ¶ms);
> +
> + if (!ct) {
> + priv->positioned = false;
> + ret = -ENOENT;
> + }
> + codetag_unlock_module_list(alloc_tag_cttype);
> + mutex_unlock(&priv->ioctl_lock);
> +
> + if (ret == 0) {
> + if (copy_to_user(arg, ¶ms, sizeof(params)))
> + return -EFAULT;
> + }
> + return ret;
> +}
> +
> +/*
> + * Entry point ioctl function for /proc/allocinfo routing requests to fetch the
> + * layout content ID, seek to a specific tag, or read sequential tags.
> + */
> +static long allocinfo_ioctl(struct file *file, unsigned int cmd,
> + unsigned long __arg)
> +{
> + void __user *arg = (void __user *)__arg;
> + int ret;
> +
> + switch (cmd) {
> + case ALLOCINFO_IOC_CONTENT_ID:
> + ret = allocinfo_ioctl_get_content_id(file->private_data, arg);
> + break;
> + case ALLOCINFO_IOC_GET_AT:
> + ret = allocinfo_ioctl_get_at(file->private_data, arg);
> + break;
> + case ALLOCINFO_IOC_GET_NEXT:
> + ret = allocinfo_ioctl_get_next(file->private_data, arg);
> + break;
> + default:
> + ret = -ENOIOCTLCMD;
> + break;
> + }
> +
> + return ret;
> +}
> +
> +#ifdef CONFIG_COMPAT
> +static long allocinfo_compat_ioctl(struct file *file, unsigned int cmd,
> + unsigned long arg)
> +{
> + return allocinfo_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
> +}
> +#endif
> +
> +static const struct proc_ops allocinfo_proc_ops = {
> + .proc_open = allocinfo_open,
> + .proc_read_iter = seq_read_iter,
> + .proc_lseek = seq_lseek,
> + .proc_release = allocinfo_release,
> + .proc_ioctl = allocinfo_ioctl,
> +#ifdef CONFIG_COMPAT
> + .proc_compat_ioctl = allocinfo_compat_ioctl,
> +#endif
> +
> +};
> +
> size_t alloc_tag_top_users(struct codetag_bytes *tags, size_t count, bool can_sleep)
> {
> struct codetag_iterator iter;
> @@ -993,8 +1222,7 @@ static int __init alloc_tag_init(void)
> return 0;
> }
>
> - if (!proc_create_seq_private(ALLOCINFO_FILE_NAME, 0400, NULL, &allocinfo_seq_op,
> - sizeof(struct allocinfo_private), NULL)) {
> + if (!proc_create(ALLOCINFO_FILE_NAME, 0400, NULL, &allocinfo_proc_ops)) {
> pr_err("Failed to create %s file\n", ALLOCINFO_FILE_NAME);
> shutdown_mem_profiling(false);
> return -ENOMEM;
> diff --git a/lib/codetag.c b/lib/codetag.c
> index 4001a7ea6675..a9cda4c962a3 100644
> --- a/lib/codetag.c
> +++ b/lib/codetag.c
> @@ -19,6 +19,8 @@ struct codetag_type {
> struct codetag_type_desc desc;
> /* generates unique sequence number for module load */
> unsigned long next_mod_seq;
> + /* bumped on every module load and unload */
> + unsigned long content_id;
> };
>
> struct codetag_range {
> @@ -50,6 +52,20 @@ void codetag_unlock_module_list(struct codetag_type *cttype)
> up_read(&cttype->mod_lock);
> }
>
> +unsigned long codetag_get_content_id(struct codetag_type *cttype)
> +{
> + lockdep_assert_held(&cttype->mod_lock);
> +
> + return cttype->content_id;
> +}
> +
> +unsigned int codetag_get_count(struct codetag_type *cttype)
> +{
> + lockdep_assert_held(&cttype->mod_lock);
> +
> + return cttype->count;
> +}
> +
> struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype)
> {
> struct codetag_iterator iter = {
> @@ -204,6 +220,7 @@ static int codetag_module_init(struct codetag_type *cttype, struct module *mod)
>
> down_write(&cttype->mod_lock);
> cmod->mod_seq = ++cttype->next_mod_seq;
> + ++cttype->content_id;
> mod_id = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL);
> if (mod_id >= 0) {
> if (cttype->desc.module_load) {
> @@ -368,6 +385,7 @@ void codetag_unload_module(struct module *mod)
> cttype->count -= range_size(cttype, &cmod->range);
> idr_remove(&cttype->mod_idr, mod_id);
> kfree(cmod);
> + ++cttype->content_id;
> }
> up_write(&cttype->mod_lock);
> if (found && cttype->desc.free_section_mem)
> --
> 2.54.0.1099.g489fc7bff1-goog
>
>
^ permalink raw reply
* Re: [RFC V2 1/3] lib/vsprintf: Add support for pgtable entries
From: Usama Arif @ 2026-06-10 11:13 UTC (permalink / raw)
To: Anshuman Khandual
Cc: Usama Arif, linux-mm, Andy Shevchenko, Rasmus Villemoes,
Sergey Senozhatsky, Petr Mladek, Steven Rostedt, Jonathan Corbet,
Andrew Morton, David Hildenbrand, linux-kernel, linux-doc,
David Hildenbrand, Lorenzo Stoakes, Andy Whitcroft
In-Reply-To: <20260610043545.3725735-2-anshuman.khandual@arm.com>
On Wed, 10 Jun 2026 05:35:43 +0100 Anshuman Khandual <anshuman.khandual@arm.com> wrote:
> Add some print formats for pgtable entries at any pgtable level. These new
> formats are %pp[g|4|u|m|t][d|e] i.e %ppgd, %pp4d, %ppud, %ppmd, and %ppte.
> These currently support both 32 bit and 64 bit pgtable entries that can be
> extended up to 128 bit when required.
>
> Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
> ---
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: David Hildenbrand <david@kernel.org>
> Cc: Lorenzo Stoakes <ljs@kernel.org>
> Cc: Petr Mladek <pmladek@suse.com>
> Cc: Steven Rostedt <rostedt@goodmis.org>
> Cc: Jonathan Corbet <corbet@lwn.net>
> Cc: Andy Whitcroft <apw@canonical.com>
> Cc: linux-mm@kvack.org
> Cc: linux-kernel@vger.kernel.org
> Cc: linux-doc@vger.kernel.org
>
> Documentation/core-api/printk-formats.rst | 19 ++++++++
> lib/vsprintf.c | 58 +++++++++++++++++++++++
> scripts/checkpatch.pl | 2 +-
> 3 files changed, 78 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst
> index c0b1b6089307..e69f91a9dd9d 100644
> --- a/Documentation/core-api/printk-formats.rst
> +++ b/Documentation/core-api/printk-formats.rst
> @@ -696,6 +696,25 @@ Rust
> Only intended to be used from Rust code to format ``core::fmt::Arguments``.
> Do *not* use it from C.
>
> +Page Table Entry
> +----------------
> +
> +::
> +
> + %p[pgd|p4dp|pud|pmd|pte]
s/p4dp/p4d to match others
> +
> +Print page table entry at any level.
> +
> +Passed by reference.
> +
> +Examples for a 64 bit page table entry, given &(u64)0xc0ffee::
> +
> + %ppte 0x0000000000c0ffee
> + %ppmd 0x0000000000c0ffee
> + %ppud 0x0000000000c0ffee
> + %pp4d 0x0000000000c0ffee
> + %ppgd 0x0000000000c0ffee
> +
> Thanks
> ======
>
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index 9f359b31c8d1..d4ad3048a4db 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -856,6 +856,59 @@ static char *default_pointer(char *buf, char *end, const void *ptr,
> return ptr_to_id(buf, end, ptr, spec);
> }
>
> +static char *pxd_pointer(char *buf, char *end, const void *ptr,
> + struct printf_spec spec, const char *fmt)
> +{
> + if (check_pointer(&buf, end, ptr, spec))
> + return buf;
> +
> + if (fmt[1] == 't' && fmt[2] == 'e') {
> + pte_t *pte = (pte_t *)ptr;
> +
> + static_assert(sizeof(pte_t) == 4 ||
> + sizeof(pte_t) == 8,
> + "pte_t size must be 4 or 8 bytes");
> + return special_hex_number(buf, end, pte_val(ptep_get(pte)), sizeof(pte_t));
> + }
> +
> + if (fmt[1] == 'm' && fmt[2] == 'd') {
> + pmd_t *pmd = (pmd_t *)ptr;
> +
> + static_assert(sizeof(pmd_t) == 4 ||
> + sizeof(pmd_t) == 8,
> + "pmd_t size must be 4 or 8 bytes");
> + return special_hex_number(buf, end, pmd_val(pmdp_get(pmd)), sizeof(pmd_t));
> + }
> +
> + if (fmt[1] == 'u' && fmt[2] == 'd') {
> + pud_t *pud = (pud_t *)ptr;
> +
> + static_assert(sizeof(pud_t) == 4 ||
> + sizeof(pud_t) == 8,
> + "pud_t size must be 4 or 8 bytes");
> + return special_hex_number(buf, end, pud_val(pudp_get(pud)), sizeof(pud_t));
> + }
> +
> + if (fmt[1] == '4' && fmt[2] == 'd') {
> + p4d_t *p4d = (p4d_t *)ptr;
> +
> + static_assert(sizeof(p4d_t) == 4 ||
> + sizeof(p4d_t) == 8,
> + "p4d_t size must be 4 or 8 bytes");
> + return special_hex_number(buf, end, p4d_val(p4dp_get(p4d)), sizeof(p4d_t));
> + }
> +
> + if (fmt[1] == 'g' && fmt[2] == 'd') {
> + pgd_t *pgd = (pgd_t *)ptr;
> +
> + static_assert(sizeof(pgd_t) == 4 ||
> + sizeof(pgd_t) == 8,
> + "pgd_t size must be 4 or 8 bytes");
> + return special_hex_number(buf, end, pgd_val(pgdp_get(pgd)), sizeof(pgd_t));
You mentioned in the coverletter that pgdp_get() is the reason arm32 builds dont work.
Just wanted to check what the issue is?
I had a look at arch/arm/include/asm/pgtable.h and I couldnt understand why
it reads pgdp_get(pgpd) instead of pgdp_get(pgdp)?
> + }
> + return default_pointer(buf, end, ptr, spec);
> +}
> +
> int kptr_restrict __read_mostly;
>
> static noinline_for_stack
> @@ -2506,6 +2559,9 @@ early_param("no_hash_pointers", no_hash_pointers_enable);
> * Without an option prints the full name of the node
> * f full name
> * P node name, including a possible unit address
> + * - 'p[g|4|u|m|t|][d|e]' For a page table entry, this prints its
> + * contents in a hexadecimal format
> + *
> * - 'x' For printing the address unmodified. Equivalent to "%lx".
> * Please read the documentation (path below) before using!
> * - '[ku]s' For a BPF/tracing related format specifier, e.g. used out of
> @@ -2615,6 +2671,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
> default:
> return error_string(buf, end, "(einval)", spec);
> }
> + case 'p':
> + return pxd_pointer(buf, end, ptr, spec, fmt);
> default:
> return default_pointer(buf, end, ptr, spec);
> }
> diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
> index 0492d6afc9a1..f68955858e29 100755
> --- a/scripts/checkpatch.pl
> +++ b/scripts/checkpatch.pl
> @@ -6975,7 +6975,7 @@ sub process {
> my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
> $fmt =~ s/%%//g;
>
> - while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*))/g) {
> + while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*)(pte|pmd|pud|p4d|pgd))/g) {
> $specifier = $1;
> $extension = $2;
> $qualifier = $3;
> --
> 2.30.2
>
>
^ permalink raw reply
* RE: [External Mail] Re: [PATCH 00/11] net: wwan: t9xx: Add MediaTek T9XX WWAN driver
From: Wu. JackBB (GSM) @ 2026-06-10 10:56 UTC (permalink / raw)
To: Sergey Ryazanov, Jakub Kicinski, Jack Wu via B4 Relay
Cc: Loic Poulain, Johannes Berg, Andrew Lunn, David S. Miller,
Eric Dumazet, Paolo Abeni, Wen-Zhi Huang, Shi-Wei Yeh,
Minano Tseng, Matthias Brugger, AngeloGioacchino Del Regno,
Simon Horman, Jonathan Corbet, Shuah Khan,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-mediatek@lists.infradead.org, linux-doc@vger.kernel.org,
wojackbb@gmail.com
In-Reply-To: <98dcaccc34ac4083aef7d57d349c4b7a@compal.com>
> let me join the discussion and put my 2c.
>
> On 6/2/26 13:58, Wu. JackBB (GSM) wrote:
> > Hi Jakub,
> >
> > > On Fri, 29 May 2026 18:31:39 +0800 Jack Wu via B4 Relay wrote:
> > > > 43 files changed, 14761 insertions(+)
> > >
> > > Please try to cut this down to ~5kLoC for the initial submission.
> > > Whatever the absolute minimum sensible chunk of code is.
> > >
> > > Each patch must build cleanly with W=1
> >
> > We've already reduced this significantly from the original 41k LoC
> > down to ~14.7k by stripping out non-essential features such as
> > exception handling, memory logging, devlink, statistics, debug
> > tracing, and others.
> >
> > We even removed some arguably necessary features (PM, mdlog,
> > throughput optimizations) that we plan to submit as follow-up
> > series.
>
> Great work. Highly appreciate!
>
> > Note that the line count may slightly increase in v2, as we plan
> > to add missing kdoc comments based on review feedback.
> >
> > For reference, the t7xx driver (two generations older, simpler HW)
> > had an initial submission of ~11.3k LoC [1]. The t9xx hardware is
> > more complex, so we believe being in a similar range is reasonable.
>
> Let me elaborate a bit here. The size problem is not due to a git or a
> mailbox limitation. It arise due to the human limitation. The T7xx
> submission review took something about 4 months and 8 iterations. And it
> was 'only' 11.3k lines. Let's do some extrapolation assuming that
> function is linear. 14.7k is 30% bigger, thus, estimated reviewing time
> should be 5 months and 2 weeks. And this looks optimistic.
>
> Recommendation, shared by Jakub, is practical. 5k lines might be
> reviewed in a reasonable time and merged with the full confidence of the
> quality.
>
> > We'd like to keep the driver functional and reviewable in its
> > current scope. Do you have any suggestions on how we could further
> > reduce the size while maintaining a working initial submission?
>
> Off the top of my head, I would suggest joining T7xx and T9xx code
> bases. It could be done through factoring out a core functionality of
> T7xx into a library, or through making the driver layered.
>
> I am not pretending being an expert in any of these drivers, but
> generally divide-n-conqueror together with code reuse work reliable. As
> an alternative, I could spend a couple of weeks reviewing the new
> submission and will come with more specific ideas on what can be thrown
> away or reused.
>
Thank you again for the suggestions on reducing the submission size.
We went with the split approach discussed earlier — v2 covers only the
control plane (patches 1–6) plus a MAINTAINERS entry, bringing it down
to ~7.9k LoC across 7 patches. The data plane will follow as a separate
series once the control plane is accepted.
v2 also addresses all review feedback from v1, including W=1 clean
builds for each patch.
Link to v2: https://patch.msgid.link/20260610-t9xx_driver_v1-v2-0-c65addf23b3f@compal.com
We would appreciate any further feedback you may have.
Best regards,
Jack
> > [1]
> > https://patchwork.kernel.org/project/netdevbpf/cover/20220506181310.2183829-1-ricardo.martinez@linux.intel.com/
> >
> > Thanks.
> >
> >
> > ================================================================================================================================================================
> > This message may contain information which is private, privileged or
> > confidential of Compal Electronics, Inc. If you are not the intended
> > recipient of this message, please notify the sender and destroy/delete the
> > message. Any review, retransmission, dissemination or other use of, or
> > taking of any action in reliance upon this information, by persons or
> > entities other than the intended recipient is prohibited.
> > ================================================================================================================================================================
>
> And this disclaimer does not facilitate the review. Am I 'intended'
> recipient or should I destroy the message ASAP?
We apologize for any inconvenience this may cause.
Could I use my personal email address (wojackbb@gmail.com) to discuss code review?
This would avoid this issue.
Thanks.
================================================================================================================================================================
This message may contain information which is private, privileged or confidential of Compal Electronics, Inc. If you are not the intended recipient of this message, please notify the sender and destroy/delete the message. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon this information, by persons or entities other than the intended recipient is prohibited.
================================================================================================================================================================
^ permalink raw reply
* [PATCH v2 6/7] net: wwan: t9xx: Add AT & MBIM WWAN ports
From: Jack Wu via B4 Relay @ 2026-06-10 10:41 UTC (permalink / raw)
To: Loic Poulain, Sergey Ryazanov, Johannes Berg, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Jack Wu, Wen-Zhi Huang, Shi-Wei Yeh, Minano Tseng,
Matthias Brugger, AngeloGioacchino Del Regno, Simon Horman,
Jonathan Corbet, Shuah Khan
Cc: linux-kernel, netdev, linux-arm-kernel, linux-mediatek, linux-doc
In-Reply-To: <20260610-t9xx_driver_v1-v2-0-c65addf23b3f@compal.com>
From: Jack Wu <jackbb_wu@compal.com>
Add AT & MBIM ports to the port infrastructure.
The WWAN initialization method is responsible for creating the
corresponding ports using the WWAN framework infrastructure. The
implemented WWAN port operations are start, stop, tx, tx_blocking
and tx_poll.
Signed-off-by: Jack Wu <jackbb_wu@compal.com>
---
drivers/net/wwan/t9xx/mtk_port.c | 26 ++
drivers/net/wwan/t9xx/mtk_port.h | 15 ++
drivers/net/wwan/t9xx/mtk_port_io.c | 337 ++++++++++++++++++++++++-
drivers/net/wwan/t9xx/mtk_port_io.h | 5 +
drivers/net/wwan/t9xx/pcie/mtk_ctrl_cfg_m9xx.c | 8 +
5 files changed, 390 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wwan/t9xx/mtk_port.c b/drivers/net/wwan/t9xx/mtk_port.c
index c68437e58ea2..f28f046cf2c9 100644
--- a/drivers/net/wwan/t9xx/mtk_port.c
+++ b/drivers/net/wwan/t9xx/mtk_port.c
@@ -819,6 +819,29 @@ int mtk_port_ch_disable(struct mtk_port *port)
return ret;
}
+static int mtk_port_enable_by_type(struct mtk_port_mngr *port_mngr, int tbl_type)
+{
+ struct mtk_port **ports;
+ int ret, idx;
+
+ if (tbl_type < 0 || tbl_type >= PORT_TBL_MAX)
+ return -EINVAL;
+
+ ports = kcalloc(port_mngr->port_cnt, sizeof(struct mtk_port *), GFP_KERNEL);
+ if (!ports)
+ return -ENOMEM;
+
+ ret = radix_tree_gang_lookup(&port_mngr->port_tbl[tbl_type],
+ (void **)ports, 0, port_mngr->port_cnt);
+ for (idx = 0; idx < ret; idx++) {
+ if (ports[idx]->enable)
+ ports_ops[ports[idx]->info.type]->enable(ports[idx]);
+ }
+
+ kfree(ports);
+ return 0;
+}
+
static void mtk_port_disable(struct mtk_port_mngr *port_mngr)
{
struct mtk_port **ports;
@@ -852,6 +875,9 @@ void mtk_port_mngr_fsm_state_handler(struct mtk_fsm_param *fsm_param, void *arg)
case FSM_STATE_OFF:
mtk_port_disable(port_mngr);
break;
+ case FSM_STATE_READY:
+ mtk_port_enable_by_type(port_mngr, PORT_TBL_MD);
+ break;
default:
break;
}
diff --git a/drivers/net/wwan/t9xx/mtk_port.h b/drivers/net/wwan/t9xx/mtk_port.h
index a201c0007878..cf561add6318 100644
--- a/drivers/net/wwan/t9xx/mtk_port.h
+++ b/drivers/net/wwan/t9xx/mtk_port.h
@@ -56,6 +56,10 @@ enum mtk_ccci_ch {
/* to MD */
CCCI_CONTROL_RX = 0x2000,
CCCI_CONTROL_TX = 0x2001,
+ CCCI_UART2_RX = 0x200A,
+ CCCI_UART2_TX = 0x200C,
+ CCCI_MBIM_RX = 0x20D0,
+ CCCI_MBIM_TX = 0x20D1,
};
enum mtk_port_flag {
@@ -73,6 +77,7 @@ enum mtk_port_tbl {
enum mtk_port_type {
PORT_TYPE_INTERNAL,
+ PORT_TYPE_WWAN,
PORT_TYPE_MAX
};
@@ -81,6 +86,13 @@ struct mtk_internal_port {
int (*recv_cb)(void *arg, struct sk_buff *skb);
};
+struct mtk_wwan_port {
+ /* w_lock protects wwan_port when recv data and disable port at the same time */
+ struct mutex w_lock;
+ int w_type;
+ void *w_port;
+};
+
struct mtk_port_cfg {
enum mtk_ccci_ch tx_ch;
enum mtk_ccci_ch rx_ch;
@@ -108,8 +120,11 @@ struct mtk_port {
wait_queue_head_t rx_wq;
struct list_head stale_entry;
char dev_str[MTK_DEV_STR_LEN];
+ /* Serializes port write operations */
+ struct mutex write_lock;
struct mtk_port_mngr *port_mngr;
struct mtk_internal_port i_priv;
+ struct mtk_wwan_port w_priv;
};
struct mtk_port_mngr {
diff --git a/drivers/net/wwan/t9xx/mtk_port_io.c b/drivers/net/wwan/t9xx/mtk_port_io.c
index bbde0d950226..58655678d82b 100644
--- a/drivers/net/wwan/t9xx/mtk_port_io.c
+++ b/drivers/net/wwan/t9xx/mtk_port_io.c
@@ -3,6 +3,10 @@
* Copyright (c) 2022, MediaTek Inc.
*/
#include <linux/netdevice.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/wwan.h>
#include "mtk_port_io.h"
@@ -39,6 +43,146 @@ static void mtk_port_struct_init(struct mtk_port *port)
port->rx_buf_size = MTK_RX_BUF_SIZE;
init_waitqueue_head(&port->trb_wq);
init_waitqueue_head(&port->rx_wq);
+ mutex_init(&port->write_lock);
+}
+
+static int mtk_port_copy_data_from(void *to, union user_buf from, unsigned int len,
+ unsigned int offset, bool from_user_space)
+{
+ if (from_user_space) {
+ if (copy_from_user(to, from.ubuf + offset, len))
+ return -EINVAL;
+ } else {
+ memcpy(to, from.kbuf + offset, len);
+ }
+
+ return 0;
+}
+
+static int mtk_port_common_write_frag_skb(struct mtk_port *port, struct sk_buff *skb,
+ union user_buf buf, u32 packet_size,
+ u32 cur_pos, bool from_user_space)
+{
+ struct sk_buff *frag_skb, *tmp = NULL;
+ u32 frag_size;
+ int ret;
+
+ frag_size = min(packet_size, port->tx_frag_size);
+ ret = mtk_port_copy_data_from(skb_put(skb, frag_size),
+ buf, frag_size,
+ cur_pos, from_user_space);
+ if (ret) {
+ dev_err(port->port_mngr->ctrl_blk->mdev->dev,
+ "Failed to copy skb for port(%s)\n", port->info.name);
+ goto err_reset_skb;
+ }
+ cur_pos += frag_size;
+ packet_size -= frag_size;
+ if (!packet_size)
+ return cur_pos;
+
+ while (packet_size > 0) {
+ frag_skb = __dev_alloc_skb(port->tx_mtu, GFP_KERNEL);
+ if (!frag_skb) {
+ ret = -ENOMEM;
+ goto err_free_frag_list;
+ }
+
+ frag_size = min(packet_size, port->tx_frag_size);
+ ret = mtk_port_copy_data_from(skb_put(frag_skb, frag_size),
+ buf, frag_size,
+ cur_pos, from_user_space);
+ if (ret) {
+ dev_err(port->port_mngr->ctrl_blk->mdev->dev,
+ "Failed to copy frag_skb for port(%s)\n", port->info.name);
+ dev_kfree_skb_any(frag_skb);
+ goto err_free_frag_list;
+ }
+ skb->data_len += frag_size;
+ skb->len += frag_size;
+ cur_pos += frag_size;
+ packet_size -= frag_size;
+ if (!tmp)
+ skb_shinfo(skb)->frag_list = frag_skb;
+ else
+ tmp->next = frag_skb;
+ tmp = frag_skb;
+ }
+ return cur_pos;
+
+err_free_frag_list:
+ frag_skb = skb_shinfo(skb)->frag_list;
+ while (frag_skb) {
+ tmp = frag_skb->next;
+ frag_skb->next = NULL;
+ dev_kfree_skb_any(frag_skb);
+ frag_skb = tmp;
+ }
+ skb_shinfo(skb)->frag_list = NULL;
+err_reset_skb:
+ skb->data_len = 0;
+ return ret;
+}
+
+static int mtk_port_common_write(struct mtk_port *port, union user_buf buf, unsigned int len,
+ bool from_user_space)
+{
+ u32 packet_size, left_cnt = len, cur_pos;
+ struct sk_buff *skb;
+ int ret;
+
+ if (len == 0)
+ return -EINVAL;
+
+start_write:
+ ret = mtk_port_status_check(port);
+ if (ret)
+ goto end_write;
+
+ skb = __dev_alloc_skb(port->tx_mtu, GFP_KERNEL);
+ if (!skb) {
+ ret = -ENOMEM;
+ goto end_write;
+ }
+
+ skb_reserve(skb, sizeof(struct mtk_ccci_header));
+
+ packet_size = min_t(u32, left_cnt, port->tx_mtu - sizeof(struct mtk_ccci_header));
+ cur_pos = len - left_cnt;
+ /* Support scatter gather transmission */
+ if (port->tx_mtu > port->tx_frag_size) {
+ ret = mtk_port_common_write_frag_skb(port, skb, buf, packet_size,
+ cur_pos, from_user_space);
+ if (ret < 0)
+ goto err_free_skb;
+ } else {
+ ret = mtk_port_copy_data_from(skb_put(skb, packet_size),
+ buf, packet_size,
+ cur_pos, from_user_space);
+ if (ret) {
+ dev_err(port->port_mngr->ctrl_blk->mdev->dev,
+ "Failed to copy data for port(%s)\n", port->info.name);
+ goto err_free_skb;
+ }
+ }
+
+ ret = mtk_port_send_data(port, skb);
+ if (ret < 0) {
+ if (ret == -EINTR)
+ left_cnt -= packet_size;
+ goto end_write;
+ }
+
+ left_cnt -= ret;
+ if (left_cnt)
+ goto start_write;
+ else
+ goto end_write;
+
+err_free_skb:
+ dev_kfree_skb_any(skb);
+end_write:
+ return (len > left_cnt) ? (len - left_cnt) : ret;
}
static int mtk_port_internal_init(struct mtk_port *port)
@@ -101,7 +245,6 @@ static int mtk_port_internal_recv(struct mtk_port *port, struct sk_buff *skb)
return ret;
drop_data:
- dev_kfree_skb_any(skb);
return ret;
}
@@ -233,6 +376,198 @@ static const struct port_ops port_internal_ops = {
.recv = mtk_port_internal_recv,
};
+static int mtk_port_wwan_open(struct wwan_port *w_port)
+{
+ struct mtk_port *port;
+ int ret;
+
+ port = wwan_port_get_drvdata(w_port);
+ ret = mtk_port_get_locked(port);
+ if (ret)
+ return ret;
+
+ ret = mtk_port_common_open(port);
+ if (ret)
+ mtk_port_put_locked(port);
+
+ return ret;
+}
+
+static void mtk_port_wwan_close(struct wwan_port *w_port)
+{
+ struct mtk_port *port = wwan_port_get_drvdata(w_port);
+
+ mtk_port_common_close(port);
+ mtk_port_put_locked(port);
+}
+
+static int mtk_port_wwan_write(struct wwan_port *w_port, struct sk_buff *skb)
+{
+ struct mtk_port *port = wwan_port_get_drvdata(w_port);
+ union user_buf user_buf;
+ int ret;
+
+ if (unlikely(!skb->len)) {
+ consume_skb(skb);
+ return 0;
+ }
+
+ port->info.flags &= ~PORT_F_BLOCKING;
+ user_buf.kbuf = (void *)skb->data;
+ ret = mtk_port_common_write(port, user_buf, skb->len, false);
+ if (ret < 0)
+ return ret;
+
+ consume_skb(skb);
+ return 0;
+}
+
+static int mtk_port_wwan_write_blocking(struct wwan_port *w_port, struct sk_buff *skb)
+{
+ struct mtk_port *port = wwan_port_get_drvdata(w_port);
+ union user_buf user_buf;
+ int ret;
+
+ if (unlikely(!skb->len)) {
+ consume_skb(skb);
+ return 0;
+ }
+
+ port->info.flags |= PORT_F_BLOCKING;
+ user_buf.kbuf = (void *)skb->data;
+ ret = mtk_port_common_write(port, user_buf, skb->len, false);
+ if (ret < 0)
+ return ret;
+
+ consume_skb(skb);
+ return 0;
+}
+
+static __poll_t mtk_port_wwan_poll(struct wwan_port *w_port, struct file *file,
+ struct poll_table_struct *poll)
+{
+ struct mtk_port *port = wwan_port_get_drvdata(w_port);
+ union ctrl_hif_cmd_data hif_cmd;
+ struct mtk_ctrl_blk *ctrl_blk;
+ __poll_t mask = 0;
+
+ poll_wait(file, &port->trb_wq, poll);
+ if (mtk_port_status_check(port))
+ return EPOLLERR | EPOLLHUP;
+
+ ctrl_blk = port->port_mngr->ctrl_blk;
+ hif_cmd.rx_ch = port->info.rx_ch;
+ if (!ctrl_blk->ops->send_cmd(ctrl_blk->mdev, HIF_CTRL_CMD_CHECK_TX_FULL, &hif_cmd))
+ mask |= EPOLLOUT | EPOLLWRNORM;
+
+ return mask;
+}
+
+static const struct wwan_port_ops wwan_ops = {
+ .start = mtk_port_wwan_open,
+ .stop = mtk_port_wwan_close,
+ .tx = mtk_port_wwan_write,
+ .tx_blocking = mtk_port_wwan_write_blocking,
+ .tx_poll = mtk_port_wwan_poll,
+};
+
+static int mtk_port_wwan_init(struct mtk_port *port)
+{
+ mtk_port_struct_init(port);
+ port->enable = false;
+
+ mutex_init(&port->w_priv.w_lock);
+
+ switch (port->info.rx_ch) {
+ case CCCI_MBIM_RX:
+ port->w_priv.w_type = WWAN_PORT_MBIM;
+ break;
+ case CCCI_UART2_RX:
+ port->w_priv.w_type = WWAN_PORT_AT;
+ break;
+ default:
+ port->w_priv.w_type = WWAN_PORT_UNKNOWN;
+ break;
+ }
+
+ return 0;
+}
+
+static void mtk_port_wwan_exit(struct mtk_port *port)
+{
+ if (test_bit(PORT_S_ENABLE, &port->status))
+ ports_ops[port->info.type]->disable(port);
+}
+
+static void mtk_port_wwan_enable(struct mtk_port *port)
+{
+ struct mtk_port_mngr *port_mngr;
+ int ret;
+
+ port_mngr = port->port_mngr;
+
+ if (test_bit(PORT_S_ENABLE, &port->status))
+ return;
+
+ ret = mtk_port_ch_enable(port);
+ if (ret && ret != -EBUSY)
+ return;
+
+ port->w_priv.w_port = wwan_create_port(port_mngr->ctrl_blk->mdev->dev,
+ port->w_priv.w_type,
+ &wwan_ops, NULL, port);
+ if (IS_ERR(port->w_priv.w_port)) {
+ dev_warn(port_mngr->ctrl_blk->mdev->dev,
+ "Failed to create wwan port for (%s)\n", port->info.name);
+ port->w_priv.w_port = NULL;
+ mtk_port_ch_disable(port);
+ return;
+ }
+
+ set_bit(PORT_S_WR, &port->status);
+ set_bit(PORT_S_ENABLE, &port->status);
+}
+
+static void mtk_port_wwan_disable(struct mtk_port *port)
+{
+ struct wwan_port *w_port;
+
+ if (!test_and_clear_bit(PORT_S_ENABLE, &port->status))
+ return;
+
+ clear_bit(PORT_S_WR, &port->status);
+ w_port = port->w_priv.w_port;
+ mutex_lock(&port->w_priv.w_lock);
+ port->w_priv.w_port = NULL;
+ mutex_unlock(&port->w_priv.w_lock);
+
+ mtk_port_ch_disable(port);
+ wwan_remove_port(w_port);
+}
+
+static int mtk_port_wwan_recv(struct mtk_port *port, struct sk_buff *skb)
+{
+ mutex_lock(&port->w_priv.w_lock);
+ if (!port->w_priv.w_port) {
+ mutex_unlock(&port->w_priv.w_lock);
+ return -ENXIO;
+ }
+
+ wwan_port_rx(port->w_priv.w_port, skb);
+ mutex_unlock(&port->w_priv.w_lock);
+ return 0;
+}
+
+static const struct port_ops port_wwan_ops = {
+ .init = mtk_port_wwan_init,
+ .exit = mtk_port_wwan_exit,
+ .reset = mtk_port_reset,
+ .enable = mtk_port_wwan_enable,
+ .disable = mtk_port_wwan_disable,
+ .recv = mtk_port_wwan_recv,
+};
+
const struct port_ops *ports_ops[PORT_TYPE_MAX] = {
&port_internal_ops,
+ &port_wwan_ops,
};
diff --git a/drivers/net/wwan/t9xx/mtk_port_io.h b/drivers/net/wwan/t9xx/mtk_port_io.h
index 0c10e893b7e0..ea92cd22dba0 100644
--- a/drivers/net/wwan/t9xx/mtk_port_io.h
+++ b/drivers/net/wwan/t9xx/mtk_port_io.h
@@ -23,6 +23,11 @@ struct port_ops {
int (*recv)(struct mtk_port *port, struct sk_buff *skb);
};
+union user_buf {
+ void __user *ubuf;
+ void *kbuf;
+};
+
void *mtk_port_internal_open(struct mtk_md_dev *mdev, char *name, int flag);
int mtk_port_internal_close(void *i_port);
int mtk_port_internal_write(void *i_port, struct sk_buff *skb);
diff --git a/drivers/net/wwan/t9xx/pcie/mtk_ctrl_cfg_m9xx.c b/drivers/net/wwan/t9xx/pcie/mtk_ctrl_cfg_m9xx.c
index 8611561dd67c..aab09cab360c 100644
--- a/drivers/net/wwan/t9xx/pcie/mtk_ctrl_cfg_m9xx.c
+++ b/drivers/net/wwan/t9xx/pcie/mtk_ctrl_cfg_m9xx.c
@@ -16,6 +16,10 @@ static const int mtk_srv_cfg_m9xx[NR_CLDMA][HW_QUE_NUM] = {
/* the number of RX GPDs should be at last two */
static const struct queue_info mtk_queue_info_m9xx[] = {
+ {CCCI_UART2_TX, CCCI_UART2_RX, CLDMA1, TXQ(5), RXQ(5),
+ Q_MTU_3_5K, Q_MTU_3_5K, TX_GPD_NUM, RX_GPD_NUM, Q_FRAG_3_5K, Q_FRAG_3_5K, 0},
+ {CCCI_MBIM_TX, CCCI_MBIM_RX, CLDMA1, TXQ(2), RXQ(2),
+ Q_MTU_3_5K, Q_MTU_3_5K, TX_GPD_NUM, RX_GPD_NUM, Q_FRAG_3_5K, Q_FRAG_3_5K, 0},
{CCCI_CONTROL_TX, CCCI_CONTROL_RX, CLDMA1, TXQ(0), RXQ(0),
Q_MTU_3_5K, Q_MTU_3_5K, TX_GPD_NUM, RX_GPD_NUM, Q_FRAG_3_5K, Q_FRAG_3_5K, 0},
{CCCI_SAP_CONTROL_TX, CCCI_SAP_CONTROL_RX, CLDMA0, TXQ(0), RXQ(0),
@@ -23,6 +27,10 @@ static const struct queue_info mtk_queue_info_m9xx[] = {
};
static const struct mtk_port_cfg port_cfg_m9xx[] = {
+ {CCCI_UART2_TX, CCCI_UART2_RX, PORT_TYPE_WWAN, "AT",
+ PORT_F_ALLOW_DROP},
+ {CCCI_MBIM_TX, CCCI_MBIM_RX, PORT_TYPE_WWAN, "MBIM",
+ PORT_F_ALLOW_DROP},
{CCCI_CONTROL_TX, CCCI_CONTROL_RX, PORT_TYPE_INTERNAL, "MDCTRL",
PORT_F_ALLOW_DROP},
{CCCI_SAP_CONTROL_TX, CCCI_SAP_CONTROL_RX, PORT_TYPE_INTERNAL, "SAPCTRL",
--
2.34.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox