* [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks
@ 2026-07-15 8:53 Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 01/16] device property: Add fwnode_graph_get_port_by_id() Chen-Yu Tsai
` (15 more replies)
0 siblings, 16 replies; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern
Hi everyone,
This is v5 of my attempt at integrating the power sequencing API into
the USB core to support the USB connection on M.2 E-key slots. M.2
E-key was enabled in v7.1-rc1 with just PCIe and UART supported [1].
Changes since v4:
- Added flags parameter to fwnode_graph_get_port_by_id() so users can
specify whether incomplete ports are returned or not (Sashiko)
- Made pwrseq_power_is_on() return 1 if descriptor is NULL, i.e. if
the descriptor is optional, matching the other pwrseq consumer APIs
- Added patch to swap out conditional set_bit()/clear_bit() with
assign_bit() (split out from "usb: hub: Power on connected M.2 E-key
connectors with power sequencing API") (Andy)
- Call fwnode_graph_get_port_by_id() with FWNODE_GRAPH_DEVICE_DISABLED
so that even incomplete ports can be connected (Sashiko)
- Dropped unused |hdev| variable from usb_hub_remove_port_device()
(Greg / Sashiko)
- Dropped 'extern' from usb_port_is_power_on() header declaration (Andy)
- Patch 10 (usb hub pwrseq integration)
- Rewrote usb_port_is_power_on() to better express intent and
restrictions of pwrseq API (Andy)
- Switched to dev_fwnode() in port_pwrseq_is_supported() (Andy)
- Added blank line separating normal variable declarations and __free()
type declarations (Andy)
- Split out assign_bit() rewrite (Andy)
- Moved pwrseq_put() to release function to avoid UAF (Sashiko)
- Added back pwrseq_power_off() call in usb_hub_remove_port_device();
otherwise power off could be delayed to object release
- Don't clear hub->ports[port1 - 1] in main error path;
by that time the port device is registered and sysfs attributes are
available to userspace (Sashiko)
- Dropped blank line between __free() variable declaration and
subsequent use of the variable in conditional (Andy)
- Added patch to split Bluetooth pwrseq units (Wei)
- Link to v4:
https://lore.kernel.org/all/20260709095726.704448-1-wenst@chromium.org/
Changes since v3:
- Added missing stub function for !POWER_SEQUENCING (patch 3) (Sashiko)
- Added missing fwnode_handle_put() (patch 5) (Sashiko)
- Added new patch to move |struct usb_port| related declarations to
separate header (patch 6) (Andy)
- Patch 9 (usb hub pwrseq integration)
- Adapted to move of usb_port_is_power_on() to port.c and port.h
- Simplified usb_hub_set_port_pwrseq() (Andy)
- Renamed usb_hub_set_port_pwrseq()'s "set" parameter to "on"
- Dropped usb_hub_restore_port_pwrseq() (use usb_hub_set_port_pwrseq()
with inverted argument)
- Fixed off-by-one access in hub_is_port_power_switchable() (Sashiko)
- Assign retval from dev_err_probe() instead of the other way around (Andy)
- Clear hub->ports[port1 - 1] in USB port error and remove paths to
avoid other threads from accidental UAF while the USB hub device is
being unwound (Sashiko)
- Short-circuit out of helpers if !IS_ENABLED(CONFIG_POWER_SEQUENCING)
to avoid errors from stub functions (Sashiko)
- Drop redundant device node validity check; device_match_of_node()
does it internally (patch 11) (Andy)
- Link to v3:
https://lore.kernel.org/all/20260703110317.1283411-1-wenst@chromium.org/
Major changes since v2:
- Removed changes for MT8192 Asurada family: one of the device is
shipped with RTL8822CE-VR, which is PCIe + UART and needs more work.
- Removed changes for USB A ports: VBUS one the type A ports on
Chromebooks are not directly controllable from the OS and VBUS is
modeled as always on. As such the changes I made don't actually
change how the system works.
- Added new pwrseq_power_is_on() function
- Make new pwrseq integration effectively OF only by not assigning the
port fwnode if the hub's fwnode is an ACPI node
- Added patch to convert remaining instances of directly setting/clearing
USB_PORT_FEAT_POWER to usb_hub_set_port_power()
- Power sequencing state removed again in favor of state tracking by
pwrseq subsystem
- Power sequencing descriptor again separately requested for HS and SS
ports
- Dropped pwrseq_power_off() call before pwrseq_put(); the latter calls
the former implicitly if the power state was left on
- Squashed DT binding revert and addition into one patch
- Link to v2:
https://lore.kernel.org/all/20260610084053.2059858-1-wenst@chromium.org/
Major changes since v1:
- No longer adding the "index" parameter the power sequencing API
- Switched from OF graph to fwnode graph APIs
- Tie "port@" node to usb_port device, and use this device as consumer
to acquire power sequencing descriptor
- Power sequencing descriptor now only tied to USB 2.0 port to avoid
double reference
- Power sequencing state tracking added
- Link to v1
https://lore.kernel.org/all/20260515090149.3169406-1-wenst@chromium.org/
The series is based on next-20260713.
Patch 1 and 2 add new fwnode graph helpers. These are used by the patch
5 and 8, respectively.
Patch 3 adds a new pwrseq_power_is_on() for a power sequencer consumer
to query the current request state. Note that this is not the _actual_
state.
Patch 4 swaps out the existing conditional set_bit()/clear_bit() with
assign_bit(), which does the same thing.
Patch 5 reworks the USB hub driver to return the actual error code from
hub_configure() in hub_probe(). This is needed in the next patch to
correctly return -EPROBE_DEFER returned by pwrseq_get() in patch 9.
Patch 6 makes the USB port device associated with a "port@" fwnode if
available. This depends on patch 1.
Patch 7 moves some |struct usb_port| related stuff from hub.c and hub.h
to port.c and port.h. No actual code or functionality is changed.
Patch 8 changes usb_port_is_power_on() so that |struct usb_port*| is
passed in instead of |struct usb_hub*|. This patch does not change any
functionality.
Patch 9 changes some USB hub port power control code that directly
toggles USB_PORT_FEAT_POWER to use usb_hub_set_port_power().
Patch 10 lets the USB hub driver look for power sequencers for each port.
Currently this only works for M.2 E-key connections, but it could be
extended to cover other cases. It should also make port reset via turning
off the port VBUS work, even when VBUS is not directly controlled by the
hub. This depends on patch 2 and 3 for the new helpers.
Patch 11 reverts an incorrectly modeled OF graph connection for the
MediaTek XHCI controller and adds a proper representation.
Patch 12 adds matching pwrseq consumer by "port@" node to the M.2 slot
driver. This is only used for the USB target, but there is no attempt
to differentiate the connection type. The driver simply tries matching
the "port@" node first, then falling back to the port parent or device's
node.
Patch 13 reworks the power sequencing targets for the E-key connector in
the pcie-m2 driver to add targets for USB and SDIO. The former is used
later on in this series.
Patch 14 splits the Bluetooth power sequencing unit so that the USB and
serdev consumers can separately toggle the actual state of W_DISABLE#2.
This patch is purposefully not squashed into the previous one to provide
a clear target for discussions.
Patches 15 and 16 enable the M.2 E-key slots (or slot-like integration)
found on MT8195 and MT8188 MediaTek-based Chromebooks.
This series unfortunately spans multiple trees. The way I see it:
- Patches 1 and 2 go through the driver core, and an immutable tag is
provided to be merged together with the USB patches.
- Patch 3 has an ack from Bartosz, and goes through the USB tree. But
Bartosz also wants an immutable branch/tag to have a copy in the
pwrseq tree.
- Patches 4 through 10 (all the USB related ones) go through the USB
tree, along with the dependencies above.
- Patches 11 and 12 go through the power sequencing tree.
- Patches 13 and 14 (device tree only) go through the soc tree via the
mediatek tree.
Some of us discussed v1 at Embedded Recipes, and I believe Bartosz, Mani
and I agree on this approach. The debate is likely going to be on
whether this should be integrated into the USB core or not. I believe it
should, so that the power sequencing timing is tied to the USB port
being brought up. I do have a fallback option of just enabling the USB
power sequencing target inside the M.2 slot driver if a valid OF graph
connection is seen. But this is less desired for the reason given above.
Please have a look and share your thoughts.
Thanks
ChenYu
[1] https://lore.kernel.org/all/20260326-pci-m2-e-v7-0-43324a7866e6@oss.qualcomm.com/
Chen-Yu Tsai (16):
device property: Add fwnode_graph_get_port_by_id()
device property: Add fwnode_graph_get_next_port_endpoint()
power: sequencing: Add pwrseq_power_is_on()
usb: hub: Use assign_bit() in usb_hub_set_port_power()
usb: hub: Return actual error from hub_configure() in hub_probe()
usb: hub: Associate port@ fwnode with USB port device
usb: core: Move struct usb_port and related APIs to port.h
usb: hub: Pass |struct usb_port*| to usb_port_is_power_on()
usb: hub: Use usb_hub_set_port_power() to control port power
everywhere
usb: hub: Power on connected M.2 E-key connectors with power
sequencing API
dt-bindings: usb: mediatek,mtk-xhci: Switch to ports for USB
connections
power: sequencing: pcie-m2: support matching on remote "port" node
power: sequencing: pcie-m2: Add usb and sdio targets for E-key
connector
power: sequencing: pcie-m2: Split Bluetooth unit based on interface
arm64: dts: mediatek: mt8195-cherry: Add M.2 E-key slot
arm64: dts: mediatek: mt8188-geralt: Add WiFi/BT as M.2 E-key slot
.../bindings/usb/mediatek,mtk-xhci.yaml | 17 +++-
.../boot/dts/mediatek/mt8188-geralt.dtsi | 92 ++++++++++++++++++-
.../boot/dts/mediatek/mt8195-cherry.dtsi | 73 ++++++++++++++-
drivers/base/property.c | 54 +++++++++++
drivers/power/sequencing/core.c | 19 ++++
drivers/power/sequencing/pwrseq-pcie-m2.c | 64 ++++++++++---
drivers/usb/Kconfig | 1 +
drivers/usb/core/hub.c | 72 +++++++--------
drivers/usb/core/hub.h | 56 ++---------
drivers/usb/core/port.c | 88 +++++++++++++++++-
drivers/usb/core/port.h | 68 ++++++++++++++
include/linux/property.h | 4 +
include/linux/pwrseq/consumer.h | 6 ++
13 files changed, 502 insertions(+), 112 deletions(-)
create mode 100644 drivers/usb/core/port.h
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v5 01/16] device property: Add fwnode_graph_get_port_by_id()
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 9:03 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 02/16] device property: Add fwnode_graph_get_next_port_endpoint() Chen-Yu Tsai
` (14 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern,
Bartosz Golaszewski
In some cases the driver needs a reference to the port firmware node.
Once such case is the upcoming USB power sequencing integration. The
USB hub port is tied to the corresponding port firmware node if it
exists.
Provide a helper for this.
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v4:
- Added flags parameter so users can specify whether incomplete ports
are returned or not (Sashiko)
Changes since v2:
- Moved "Return:" kernel-doc section to the end. (Andy)
Changes since v1:
- New patch
---
drivers/base/property.c | 29 +++++++++++++++++++++++++++++
include/linux/property.h | 3 +++
2 files changed, 32 insertions(+)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 9387bb83eb54..950defc0c55a 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -1346,6 +1346,35 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
}
EXPORT_SYMBOL(fwnode_graph_parse_endpoint);
+/**
+ * fwnode_graph_get_port_by_id - get the port matching a given id
+ * @fwnode: parent fwnode_handle containing the graph
+ * @id: id of the port
+ * @flags: fwnode lookup flags
+ *
+ * The caller is responsible for calling fwnode_handle_put() on the returned
+ * fwnode pointer.
+ *
+ * Does not return ports that belong to disabled devices or endpoints that
+ * are unconnected, unless FWNODE_GRAPH_DEVICE_DISABLED is passed in @flags.
+ *
+ * Return: A 'port' firmware node pointer with refcount incremented.
+ */
+struct fwnode_handle *fwnode_graph_get_port_by_id(struct fwnode_handle *fwnode,
+ u32 id,
+ unsigned long flags)
+{
+ struct fwnode_handle *ep;
+
+ ep = fwnode_graph_get_endpoint_by_id(fwnode, id, 0,
+ flags | FWNODE_GRAPH_ENDPOINT_NEXT);
+ if (!ep)
+ return NULL;
+
+ return fwnode_get_next_parent(ep);
+}
+EXPORT_SYMBOL_GPL(fwnode_graph_get_port_by_id);
+
const void *device_get_match_data(const struct device *dev)
{
return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, dev);
diff --git a/include/linux/property.h b/include/linux/property.h
index 14c304db4664..480ba8646bcc 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -505,6 +505,9 @@ int fwnode_get_phy_mode(const struct fwnode_handle *fwnode);
void __iomem *fwnode_iomap(struct fwnode_handle *fwnode, int index);
+struct fwnode_handle *fwnode_graph_get_port_by_id(struct fwnode_handle *fwnode, u32 id);
+struct fwnode_handle *fwnode_graph_get_port_by_id(struct fwnode_handle *fwnode, u32 id,
+ unsigned long flags);
struct fwnode_handle *fwnode_graph_get_next_endpoint(
const struct fwnode_handle *fwnode, struct fwnode_handle *prev);
struct fwnode_handle *
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 02/16] device property: Add fwnode_graph_get_next_port_endpoint()
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 01/16] device property: Add fwnode_graph_get_port_by_id() Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 9:09 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 03/16] power: sequencing: Add pwrseq_power_is_on() Chen-Yu Tsai
` (13 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern,
Bartosz Golaszewski
Due to design constraints of the power sequencing API, the consumer
must first be sure that the other side is actually a provider, or it
will continually get -EPROBE_DEFER when requesting the power
sequencing descriptor.
In the upcoming USB power sequencing integration, the USB hub driver
first needs to check whether a graph connection exists, and whether
the other side of the connection is a supported connector type. The
USB port is tied to a "port" firmware node, and this new helper will
be used to get the endpoint under the known "port" firmware node.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v2:
- Dropped unused |ep| variable
- Rewrote as do {} while()
- Dropped WARN() use
---
drivers/base/property.c | 25 +++++++++++++++++++++++++
include/linux/property.h | 3 ++-
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 950defc0c55a..5d3993bd8fc4 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -1099,6 +1099,31 @@ int fwnode_irq_get_byname(const struct fwnode_handle *fwnode, const char *name)
}
EXPORT_SYMBOL(fwnode_irq_get_byname);
+/**
+ * fwnode_graph_get_next_port_endpoint - Get next endpoint firmware node in port
+ * @port: Pointer to the target port firmware node
+ * @prev: Previous endpoint node or %NULL to get the first
+ *
+ * The caller is responsible for calling fwnode_handle_put() on the returned
+ * fwnode pointer. Note that this function also puts a reference to @prev
+ * unconditionally.
+ *
+ * Return: an endpoint firmware node pointer or %NULL if no more endpoints
+ * are available.
+ */
+struct fwnode_handle *fwnode_graph_get_next_port_endpoint(const struct fwnode_handle *port,
+ struct fwnode_handle *prev)
+{
+ do {
+ prev = fwnode_get_next_child_node(port, prev);
+ if (fwnode_name_eq(prev, "endpoint"))
+ break;
+ } while (prev);
+
+ return prev;
+}
+EXPORT_SYMBOL_GPL(fwnode_graph_get_next_port_endpoint);
+
/**
* fwnode_graph_get_next_endpoint - Get next endpoint firmware node
* @fwnode: Pointer to the parent firmware node
diff --git a/include/linux/property.h b/include/linux/property.h
index 480ba8646bcc..9a784a856773 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -505,9 +505,10 @@ int fwnode_get_phy_mode(const struct fwnode_handle *fwnode);
void __iomem *fwnode_iomap(struct fwnode_handle *fwnode, int index);
-struct fwnode_handle *fwnode_graph_get_port_by_id(struct fwnode_handle *fwnode, u32 id);
struct fwnode_handle *fwnode_graph_get_port_by_id(struct fwnode_handle *fwnode, u32 id,
unsigned long flags);
+struct fwnode_handle *fwnode_graph_get_next_port_endpoint(
+ const struct fwnode_handle *port, struct fwnode_handle *prev);
struct fwnode_handle *fwnode_graph_get_next_endpoint(
const struct fwnode_handle *fwnode, struct fwnode_handle *prev);
struct fwnode_handle *
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 03/16] power: sequencing: Add pwrseq_power_is_on()
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 01/16] device property: Add fwnode_graph_get_port_by_id() Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 02/16] device property: Add fwnode_graph_get_next_port_endpoint() Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 9:08 ` sashiko-bot
2026-07-15 9:29 ` Andy Shevchenko
2026-07-15 8:53 ` [PATCH v5 04/16] usb: hub: Use assign_bit() in usb_hub_set_port_power() Chen-Yu Tsai
` (12 subsequent siblings)
15 siblings, 2 replies; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern,
Bartosz Golaszewski
The power sequencing consumer API already does power on state tracking
internally. Expose the state to consumers through pwrseq_power_is_on()
so that they don't have to reimplement it locally.
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v4:
- Make pwrseq_power_is_on() return 1 if descriptor is NULL, i.e. if
the descriptor is optional, matching the other pwrseq consumer APIs
Changes since v3:
- Added missing stub function for !POWER_SEQUENCING
Changes since v2:
- New patch
Needs to go in with "usb: hub: Power on connected M.2 E-key connectors"
as it is a build time dependency. Bartosz wants the change on an
immutable branch to pull into the pwrseq tree.
---
drivers/power/sequencing/core.c | 19 +++++++++++++++++++
include/linux/pwrseq/consumer.h | 6 ++++++
2 files changed, 25 insertions(+)
diff --git a/drivers/power/sequencing/core.c b/drivers/power/sequencing/core.c
index 02f42da91598..db8c91be10c9 100644
--- a/drivers/power/sequencing/core.c
+++ b/drivers/power/sequencing/core.c
@@ -968,6 +968,25 @@ int pwrseq_power_off(struct pwrseq_desc *desc)
}
EXPORT_SYMBOL_GPL(pwrseq_power_off);
+/**
+ * pwrseq_power_is_on() - Queries the last requested state of the power sequencer.
+ * @desc: Descriptor referencing the power sequencer.
+ *
+ * This returns the last requested state of the power sequencer.
+ *
+ * Returns:
+ * On success, 1 for on or desc is NULL (optional) and 0 for off;
+ * negative error number on failure.
+ */
+int pwrseq_power_is_on(struct pwrseq_desc *desc)
+{
+ if (!desc)
+ return 1;
+
+ return desc->powered_on;
+}
+EXPORT_SYMBOL_GPL(pwrseq_power_is_on);
+
/**
* pwrseq_to_device() - Get the pwrseq device pointer from a descriptor.
* @desc: Descriptor referencing the power sequencer.
diff --git a/include/linux/pwrseq/consumer.h b/include/linux/pwrseq/consumer.h
index 3c907c9e1885..3c6122bd0205 100644
--- a/include/linux/pwrseq/consumer.h
+++ b/include/linux/pwrseq/consumer.h
@@ -22,6 +22,7 @@ devm_pwrseq_get(struct device *dev, const char *target);
int pwrseq_power_on(struct pwrseq_desc *desc);
int pwrseq_power_off(struct pwrseq_desc *desc);
+int pwrseq_power_is_on(struct pwrseq_desc *desc);
struct device *pwrseq_to_device(struct pwrseq_desc *desc);
@@ -53,6 +54,11 @@ static inline int pwrseq_power_off(struct pwrseq_desc *desc)
return -ENOSYS;
}
+static inline int pwrseq_power_is_on(struct pwrseq_desc *desc)
+{
+ return -ENOSYS;
+}
+
static inline struct device *pwrseq_to_device(struct pwrseq_desc *desc)
{
return NULL;
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 04/16] usb: hub: Use assign_bit() in usb_hub_set_port_power()
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
` (2 preceding siblings ...)
2026-07-15 8:53 ` [PATCH v5 03/16] power: sequencing: Add pwrseq_power_is_on() Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 9:11 ` Andy Shevchenko
2026-07-15 8:53 ` [PATCH v5 05/16] usb: hub: Return actual error from hub_configure() in hub_probe() Chen-Yu Tsai
` (11 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern
usb_hub_set_port_power() open-codes assign_bit(). Just use the
assign_bit() macro instead. This makes subsequent additions to
usb_hub_set_port_power() easier to read.
This change does not introduce any functional changes.
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Attributing suggestion to Andy, since the change was originally
requested as part of a review.
Changes since v4:
- New patch (split out from "usb: hub: Power on connected M.2 E-key
connectors with power sequencing API") (Andy)
---
drivers/usb/core/hub.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 9b2bf608f9cc..36342c5718bb 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -10,6 +10,7 @@
* Released under the GPLv2 only.
*/
+#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -896,10 +897,7 @@ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
if (ret)
return ret;
- if (set)
- set_bit(port1, hub->power_bits);
- else
- clear_bit(port1, hub->power_bits);
+ assign_bit(port1, hub->power_bits, set);
return 0;
}
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 05/16] usb: hub: Return actual error from hub_configure() in hub_probe()
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
` (3 preceding siblings ...)
2026-07-15 8:53 ` [PATCH v5 04/16] usb: hub: Use assign_bit() in usb_hub_set_port_power() Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 06/16] usb: hub: Associate port@ fwnode with USB port device Chen-Yu Tsai
` (10 subsequent siblings)
15 siblings, 0 replies; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern,
Bartosz Golaszewski
The addition of power sequencing descriptor handling in the USB hub code
requires dealing with deferred probing from pwrseq_get(). The power
sequencing provider may not yet be available when the USB hub probes.
Return the actual error code from hub_configure() when it fails, so that
the driver core can notice the deferred probe request.
Also rewrite this section into the standard error handling pattern:
if (error) {
# handle error
return error;
}
# do more work
return 0;
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v2:
- Rewrite into standard error handling pattern
Changes since v1:
- Moved "int ret" declaration in hub_configure() over here from the next
patch
---
drivers/usb/core/hub.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 36342c5718bb..a260148091c5 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1872,6 +1872,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct usb_host_interface *desc;
struct usb_device *hdev;
struct usb_hub *hub;
+ int ret;
desc = intf->cur_altsetting;
hdev = interface_to_usbdev(intf);
@@ -2003,14 +2004,15 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
usb_set_interface(hdev, 0, 0);
}
- if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) {
- onboard_dev_create_pdevs(hdev, &hub->onboard_devs);
-
- return 0;
+ ret = hub_configure(hub, &desc->endpoint[0].desc);
+ if (ret < 0) {
+ hub_disconnect(intf);
+ return ret;
}
- hub_disconnect(intf);
- return -ENODEV;
+ onboard_dev_create_pdevs(hdev, &hub->onboard_devs);
+
+ return 0;
}
static int
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 06/16] usb: hub: Associate port@ fwnode with USB port device
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
` (4 preceding siblings ...)
2026-07-15 8:53 ` [PATCH v5 05/16] usb: hub: Return actual error from hub_configure() in hub_probe() Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 9:20 ` Andy Shevchenko
2026-07-15 8:53 ` [PATCH v5 07/16] usb: core: Move struct usb_port and related APIs to port.h Chen-Yu Tsai
` (9 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern,
Bartosz Golaszewski
When a USB hub port is connected to a connector in a firmware node
graph, the port itself has a node in the graph.
Associate the port's firmware node with the USB port's device,
usb_port::dev. This is used in later changes for the M.2 slot power
sequencing provider to match against the requesting port.
To avoid potential conflicts with ACPI firmware nodes and then causing
power management issues, only assign the firmware node if the hub's
firmware node is not an ACPI firmware node.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v4:
- Dropped unused |hdev| variable
- Added flags for fwnode_graph_get_port_by_id() with
FWNODE_GRAPH_DEVICE_DISABLED so that even incomplete
ports can be connected
Changes since v3:
- Added missing fwnode_handle_put()
Changes since v2:
- Skip assignment if hub firmware node is ACPI node
---
drivers/usb/core/port.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index b1364f0c384c..4fd0a4745741 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -7,6 +7,7 @@
* Author: Lan Tianyu <tianyu.lan@intel.com>
*/
+#include <linux/acpi.h>
#include <linux/kstrtox.h>
#include <linux/slab.h>
#include <linux/string_choices.h>
@@ -358,6 +359,11 @@ static void usb_port_device_release(struct device *dev)
{
struct usb_port *port_dev = to_usb_port(dev);
+ /*
+ * At this point ACPI nodes and swnodes have been removed by
+ * device_platform_notify_remove() in device_del().
+ */
+ fwnode_handle_put(dev_fwnode(dev));
kfree(port_dev->req);
kfree(port_dev);
}
@@ -780,6 +786,14 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
port_dev->dev.driver = &usb_port_driver;
dev_set_name(&port_dev->dev, "%s-port%d", dev_name(&hub->hdev->dev),
port1);
+ /*
+ * ACPI FW nodes are associated later when device_register() happens.
+ * Skip assigning one here to avoid potential conflicts.
+ */
+ if (!is_acpi_node(dev_fwnode(&hdev->dev)))
+ device_set_node(&port_dev->dev,
+ fwnode_graph_get_port_by_id(dev_fwnode(&hdev->dev), port1,
+ FWNODE_GRAPH_DEVICE_DISABLED));
mutex_init(&port_dev->status_lock);
retval = device_register(&port_dev->dev);
if (retval) {
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 07/16] usb: core: Move struct usb_port and related APIs to port.h
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
` (5 preceding siblings ...)
2026-07-15 8:53 ` [PATCH v5 06/16] usb: hub: Associate port@ fwnode with USB port device Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 9:31 ` Andy Shevchenko
2026-07-15 8:53 ` [PATCH v5 08/16] usb: hub: Pass |struct usb_port*| to usb_port_is_power_on() Chen-Yu Tsai
` (8 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern,
Bartosz Golaszewski
|struct usb_port| and its matching container_of() macro should live in
its own port.h, matching the split we have for .c files.
Move them as described. Also move usb_port_is_power_on(), since in the
next change its |struct usb_hub *| parameter will be changed to
|struct usb_port *|, and becomes a non-static function that only
references |struct usb_port|.
port.h is only included from hub.h, as a subsequent patch will directly
use fields from |struct usb_port| in a static inline helper in hub.h.
The USB internal headers don't have header guards to help with this.
Also drop 'extern' from the header declaration of usb_port_is_power_on().
This is not needed in modern C.
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v4:
- Dropped 'extern' (Andy)
Changes since v3:
- New patch (Andy)
---
drivers/usb/core/hub.c | 16 ----------
drivers/usb/core/hub.h | 48 ++---------------------------
drivers/usb/core/port.c | 16 ++++++++++
drivers/usb/core/port.h | 68 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 86 insertions(+), 62 deletions(-)
create mode 100644 drivers/usb/core/port.h
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index a260148091c5..e5a726dbebd0 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3237,22 +3237,6 @@ static bool hub_port_stop_enumerate(struct usb_hub *hub, int port1, int retries)
return port_dev->ignore_event;
}
-/* Check if a port is power on */
-int usb_port_is_power_on(struct usb_hub *hub, unsigned int portstatus)
-{
- int ret = 0;
-
- if (hub_is_superspeed(hub->hdev)) {
- if (portstatus & USB_SS_PORT_STAT_POWER)
- ret = 1;
- } else {
- if (portstatus & USB_PORT_STAT_POWER)
- ret = 1;
- }
-
- return ret;
-}
-
static void usb_lock_port(struct usb_port *port_dev)
__acquires(&port_dev->status_lock)
{
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index 9ebc5ef54a32..de524c6da9fc 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -15,7 +15,9 @@
#include <linux/usb/ch11.h>
#include <linux/usb/hcd.h>
#include <linux/usb/typec.h>
+
#include "usb.h"
+#include "port.h"
struct usb_hub {
struct device *intfdev; /* the "interface" device */
@@ -78,51 +80,6 @@ struct usb_hub {
struct list_head onboard_devs;
};
-/**
- * struct usb port - kernel's representation of a usb port
- * @child: usb device attached to the port
- * @dev: generic device interface
- * @port_owner: port's owner
- * @peer: related usb2 and usb3 ports (share the same connector)
- * @connector: USB Type-C connector
- * @req: default pm qos request for hubs without port power control
- * @connect_type: port's connect type
- * @state: device state of the usb device attached to the port
- * @state_kn: kernfs_node of the sysfs attribute that accesses @state
- * @location: opaque representation of platform connector location
- * @status_lock: synchronize port_event() vs usb_port_{suspend|resume}
- * @portnum: port index num based one
- * @is_superspeed cache super-speed status
- * @usb3_lpm_u1_permit: whether USB3 U1 LPM is permitted.
- * @usb3_lpm_u2_permit: whether USB3 U2 LPM is permitted.
- * @early_stop: whether port initialization will be stopped earlier.
- * @ignore_event: whether events of the port are ignored.
- */
-struct usb_port {
- struct usb_device *child;
- struct device dev;
- struct usb_dev_state *port_owner;
- struct usb_port *peer;
- struct typec_connector *connector;
- struct dev_pm_qos_request *req;
- enum usb_port_connect_type connect_type;
- enum usb_device_state state;
- struct kernfs_node *state_kn;
- usb_port_location_t location;
- struct mutex status_lock;
- u32 over_current_count;
- u8 portnum;
- u32 quirks;
- unsigned int early_stop:1;
- unsigned int ignore_event:1;
- unsigned int is_superspeed:1;
- unsigned int usb3_lpm_u1_permit:1;
- unsigned int usb3_lpm_u2_permit:1;
-};
-
-#define to_usb_port(_dev) \
- container_of(_dev, struct usb_port, dev)
-
extern int usb_hub_create_port_device(struct usb_hub *hub,
int port1);
extern void usb_hub_remove_port_device(struct usb_hub *hub,
@@ -138,7 +95,6 @@ extern int usb_clear_port_feature(struct usb_device *hdev,
int port1, int feature);
extern int usb_hub_port_status(struct usb_hub *hub, int port1,
u16 *status, u16 *change);
-extern int usb_port_is_power_on(struct usb_hub *hub, unsigned int portstatus);
static inline bool hub_is_port_power_switchable(struct usb_hub *hub)
{
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 4fd0a4745741..8f99bce074fc 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -22,6 +22,22 @@ static int usb_port_block_power_off;
static const struct attribute_group *port_dev_group[];
+/* Check if a port is power on */
+int usb_port_is_power_on(struct usb_hub *hub, unsigned int portstatus)
+{
+ int ret = 0;
+
+ if (hub_is_superspeed(hub->hdev)) {
+ if (portstatus & USB_SS_PORT_STAT_POWER)
+ ret = 1;
+ } else {
+ if (portstatus & USB_PORT_STAT_POWER)
+ ret = 1;
+ }
+
+ return ret;
+}
+
static bool usb_port_allow_power_off(struct usb_device *hdev,
struct usb_hub *hub,
struct usb_port *port_dev)
diff --git a/drivers/usb/core/port.h b/drivers/usb/core/port.h
new file mode 100644
index 000000000000..00f7500af336
--- /dev/null
+++ b/drivers/usb/core/port.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * usb hub driver head file
+ *
+ * Copyright (C) 1999 Linus Torvalds
+ * Copyright (C) 1999 Johannes Erdfelt
+ * Copyright (C) 1999 Gregory P. Smith
+ * Copyright (C) 2001 Brad Hards (bhards@bigpond.net.au)
+ * Copyright (C) 2012 Intel Corp (tianyu.lan@intel.com)
+ *
+ * move struct usb_port to this file.
+ */
+
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/mutex_types.h>
+#include <linux/usb.h>
+
+#include <uapi/linux/usb/ch9.h>
+
+/**
+ * struct usb port - kernel's representation of a usb port
+ * @child: usb device attached to the port
+ * @dev: generic device interface
+ * @port_owner: port's owner
+ * @peer: related usb2 and usb3 ports (share the same connector)
+ * @connector: USB Type-C connector
+ * @req: default pm qos request for hubs without port power control
+ * @connect_type: port's connect type
+ * @state: device state of the usb device attached to the port
+ * @state_kn: kernfs_node of the sysfs attribute that accesses @state
+ * @location: opaque representation of platform connector location
+ * @status_lock: synchronize port_event() vs usb_port_{suspend|resume}
+ * @portnum: port index num based one
+ * @is_superspeed cache super-speed status
+ * @usb3_lpm_u1_permit: whether USB3 U1 LPM is permitted.
+ * @usb3_lpm_u2_permit: whether USB3 U2 LPM is permitted.
+ * @early_stop: whether port initialization will be stopped earlier.
+ * @ignore_event: whether events of the port are ignored.
+ */
+struct usb_port {
+ struct usb_device *child;
+ struct device dev;
+ struct usb_dev_state *port_owner;
+ struct usb_port *peer;
+ struct typec_connector *connector;
+ struct dev_pm_qos_request *req;
+ enum usb_port_connect_type connect_type;
+ enum usb_device_state state;
+ struct kernfs_node *state_kn;
+ usb_port_location_t location;
+ struct mutex status_lock;
+ u32 over_current_count;
+ u8 portnum;
+ u32 quirks;
+ unsigned int early_stop:1;
+ unsigned int ignore_event:1;
+ unsigned int is_superspeed:1;
+ unsigned int usb3_lpm_u1_permit:1;
+ unsigned int usb3_lpm_u2_permit:1;
+};
+
+#define to_usb_port(_dev) \
+ container_of(_dev, struct usb_port, dev)
+
+struct usb_hub;
+
+int usb_port_is_power_on(struct usb_hub *hub, unsigned int portstatus);
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 08/16] usb: hub: Pass |struct usb_port*| to usb_port_is_power_on()
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
` (6 preceding siblings ...)
2026-07-15 8:53 ` [PATCH v5 07/16] usb: core: Move struct usb_port and related APIs to port.h Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 09/16] usb: hub: Use usb_hub_set_port_power() to control port power everywhere Chen-Yu Tsai
` (7 subsequent siblings)
15 siblings, 0 replies; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern,
Bartosz Golaszewski
usb_port_is_power_on() currently takes |struct usb_hub*|, but only needs
it to tell if the hub/port is SuperSpeed or not.
In a subsequent change, usb_port_is_power_on() needs access to a pwrseq
state tracking field in |struct usb_port|. Either structure can be used
to identify whether a port/hub is SuperSpeed or not, as the field in
|struct usb_port| is inherited from the hub:
port->is_superspeed = hub_is_superspeed(hub)
Replace usb_port_is_power_on()'s |struct usb_hub*| parameter with
|struct usb_port*| so a subsequent change can use it.
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v3:
- Adapted to move of usb_port_is_power_on() to port.c and port.h
---
drivers/usb/core/hub.c | 7 ++++---
drivers/usb/core/port.c | 6 +++---
drivers/usb/core/port.h | 4 +---
3 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index e5a726dbebd0..40cdb63b5333 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3288,7 +3288,7 @@ static int check_port_resume_type(struct usb_device *udev,
}
/* Is the device still present? */
else if (status || port_is_suspended(hub, portstatus) ||
- !usb_port_is_power_on(hub, portstatus)) {
+ !usb_port_is_power_on(port_dev, portstatus)) {
if (status >= 0)
status = -ENODEV;
} else if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
@@ -3730,12 +3730,13 @@ static int wait_for_connected(struct usb_device *udev,
struct usb_hub *hub, int port1,
u16 *portchange, u16 *portstatus)
{
+ struct usb_port *port_dev = hub->ports[port1 - 1];
int status = 0, delay_ms = 0;
while (delay_ms < 2000) {
if (status || *portstatus & USB_PORT_STAT_CONNECTION)
break;
- if (!usb_port_is_power_on(hub, *portstatus)) {
+ if (!usb_port_is_power_on(port_dev, *portstatus)) {
status = -ENODEV;
break;
}
@@ -5431,7 +5432,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
* but only if the port isn't owned by someone else.
*/
if (hub_is_port_power_switchable(hub)
- && !usb_port_is_power_on(hub, portstatus)
+ && !usb_port_is_power_on(port_dev, portstatus)
&& !port_dev->port_owner)
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 8f99bce074fc..19913ad3598b 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -23,11 +23,11 @@ static int usb_port_block_power_off;
static const struct attribute_group *port_dev_group[];
/* Check if a port is power on */
-int usb_port_is_power_on(struct usb_hub *hub, unsigned int portstatus)
+int usb_port_is_power_on(struct usb_port *port, unsigned int portstatus)
{
int ret = 0;
- if (hub_is_superspeed(hub->hdev)) {
+ if (port->is_superspeed) {
if (portstatus & USB_SS_PORT_STAT_POWER)
ret = 1;
} else {
@@ -114,7 +114,7 @@ static ssize_t disable_show(struct device *dev,
}
usb_hub_port_status(hub, port1, &portstatus, &unused);
- disabled = !usb_port_is_power_on(hub, portstatus);
+ disabled = !usb_port_is_power_on(port_dev, portstatus);
out_hdev_lock:
usb_unlock_device(hdev);
diff --git a/drivers/usb/core/port.h b/drivers/usb/core/port.h
index 00f7500af336..2f4349b3ce6b 100644
--- a/drivers/usb/core/port.h
+++ b/drivers/usb/core/port.h
@@ -63,6 +63,4 @@ struct usb_port {
#define to_usb_port(_dev) \
container_of(_dev, struct usb_port, dev)
-struct usb_hub;
-
-int usb_port_is_power_on(struct usb_hub *hub, unsigned int portstatus);
+int usb_port_is_power_on(struct usb_port *port, unsigned int portstatus);
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 09/16] usb: hub: Use usb_hub_set_port_power() to control port power everywhere
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
` (7 preceding siblings ...)
2026-07-15 8:53 ` [PATCH v5 08/16] usb: hub: Pass |struct usb_port*| to usb_port_is_power_on() Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 10/16] usb: hub: Power on connected M.2 E-key connectors with power sequencing API Chen-Yu Tsai
` (6 subsequent siblings)
15 siblings, 0 replies; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern,
Bartosz Golaszewski
There are still some instances in the USB hub driver where port power is
directly controlled by toggling the USB_PORT_FEAT_POWER feature flag.
Switch these instances over to usb_hub_set_port_power() so that only one
unified function to do this exists. This makes adding external power
control with the power sequencing API easier and consistently applied.
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v2:
- New patch
---
drivers/usb/core/hub.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 40cdb63b5333..47010090d3b6 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -973,11 +973,8 @@ static void hub_power_on(struct usb_hub *hub, bool do_delay)
dev_dbg(hub->intfdev, "trying to enable port power on "
"non-switchable hub\n");
for (port1 = 1; port1 <= hub->hdev->maxchild; port1++)
- if (test_bit(port1, hub->power_bits))
- set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
- else
- usb_clear_port_feature(hub->hdev, port1,
- USB_PORT_FEAT_POWER);
+ usb_hub_set_port_power(hub->hdev, hub, port1,
+ test_bit(port1, hub->power_bits));
if (do_delay)
msleep(hub_power_on_good_delay(hub));
}
@@ -5434,7 +5431,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
if (hub_is_port_power_switchable(hub)
&& !usb_port_is_power_on(port_dev, portstatus)
&& !port_dev->port_owner)
- set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
+ usb_hub_set_port_power(hdev, hub, port1, true);
if (portstatus & USB_PORT_STAT_ENABLE)
goto done;
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 10/16] usb: hub: Power on connected M.2 E-key connectors with power sequencing API
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
` (8 preceding siblings ...)
2026-07-15 8:53 ` [PATCH v5 09/16] usb: hub: Use usb_hub_set_port_power() to control port power everywhere Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 9:28 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 11/16] dt-bindings: usb: mediatek,mtk-xhci: Switch to ports for USB connections Chen-Yu Tsai
` (5 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern,
Bartosz Golaszewski
The new M.2 E-key connector can have a USB connection. For the USB device
on this connector to work, its power must be enabled and the W_DISABLE2#
signal deasserted. The connector driver handles this and provides a
toggle over the power sequencing API.
This feature currently only supports a directly connected (no mux in
between) M.2 E-key connector. Existing USB connector types are not
covered. The USB A connector was recently added to the onboard devices
driver. USB B connectors have historically been managed by the USB
gadget or dual-role device controller drivers. USB C connectors are
handled by TCPM drivers.
The power sequencing API does not know whether a power sequence provider
is not needed or not available yet, so we only request it for connectors
that we know need it, which at this time is just the E-key connector.
On the USB side, the port firmware node (if present) is tied to the
usb_port device. This device is used to acquire the power sequencing
descriptor. This allows the provider to tell the different ports on one
hub apart.
This feature is not implemented in the onboard USB devices driver. The
power sequencing API expects the consumer device to make the request,
but there is no device node to instantiate a platform device to tie
the driver to. The connector is not a child node of the USB host or
hub, and the graph connection is from a USB port to the connector.
And the connector itself already has a driver.
Power sequencing is not directly enabled in the connector driver as
that would completely decouple the timing of it from the USB subsystem.
It would not be possible for the USB subsystem to toggle the power
for a power cycle or to disable the port.
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v4:
- Rewrote usb_port_is_power_on() to better express intent and
restrictions of pwrseq API (Andy)
- Switched to dev_fwnode() in port_pwrseq_is_supported() (Andy)
- Added blank line separating normal variable declarations and __free()
type declarations (Andy)
- Split out assign_bit() rewrite
- Moved pwrseq_put() to release function to avoid UAF (Sashiko)
- Added back pwrseq_power_off() call in usb_hub_remove_port_device();
otherwise power off could be delayed to object release
- Don't clear hub->ports[port1 - 1] in main error path;
by that time the port device is registered and sysfs attributes are
available to userspace (Sashiko)
Changes since v3:
- Adapted to move of usb_port_is_power_on() to port.c and port.h
- Simplified usb_hub_set_port_pwrseq() (Andy)
- Renamed usb_hub_set_port_pwrseq()'s "set" parameter to "on"
- Dropped usb_hub_restore_port_pwrseq() (use usb_hub_set_port_pwrseq()
with inverted argument)
- Fixed off-by-one access in hub_is_port_power_switchable() (Sashiko)
- Assign retval from dev_err_probe() instead of the other way around (Andy)
- Clear hub->ports[port1 - 1] in USB port error and remove paths to
avoid other threads from accidental UAF while the USB hub device is
being unwound (Sashiko)
- Short-circuit out of helpers if !IS_ENABLED(CONFIG_POWER_SEQUENCING)
to avoid errors from stub functions (Sashiko)
Changes since v2:
- Expanded subject to mention power sequencing API
- Dropped commit message bit about power sequencing Kconfig symbol change
to bool
- Added optional dependency on POWER_SEQUENCING to USB
- Split out pwrseq_power_*() calls into separate helpers
- Rewrote set_bit() and clear_bit() branches with assign_bit()
- Dropped the pwrseq_power_off() before pwrseq_put(): pwrseq_put() does it
automatically.
- Removed pwrseq_power_on() from usb_hub_create_port_device(); it will
get called through usb_hub_set_port_power() in hub_activate().
- Added checks for port->pwrseq in hub_is_port_power_switchable()
- Use separate pwrseq descriptors for HighSpeed and SuperSpeed ports.
This makes things simpler. On the other hand to power cycle a port
userspace needs to toggle it on both the HS and SS ports together.
- Dropped pwrseq state tracking again
The power sequencing consumer API already tracks the state internally;
doing it again in |struct usb_port| is not necessary especially now
that the descriptors aren't shared.
It's unclear to me how actual hubs reconcile USB_PORT_FEAT_POWER settings
from the HS side and SS side. One hub chip vendor said that VBUS_EN for
a port is on if the flag is set on either side; however actually testing
on one of their hubs showed that VBUS was cut as soon as the flag is
cleared on the HS port. Maybe it could be different if a SS device was
connected? That scenario was not tested. Testing on another retail
bought hub seemed to work exactly as described though: USB_PORT_FEAT_POWER
needed to be clear on both HS and SS ports to turn off VBUS.
Under this scheme, I'm not sure how the power cycle in hub_port_connect()
would work correctly.
- Link to v2:
https://lore.kernel.org/all/20260610084053.2059858-1-wenst@chromium.org/
Changes since v1:
- Switch to fwnode instead of OF
- Tie port@ fwnode to usb_port device
- Move remote node compatible checking to separate helper
- Use usb_port device to request power sequencing descriptor
- Drop "index" parameter from pwrseq_get()
- Do not get pwrseq descriptor for SuperSpeed port; share one for one
physical port
- Add pwrseq state tracking
- Link to v1:
https://lore.kernel.org/all/20260515090149.3169406-1-wenst@chromium.org/
---
drivers/usb/Kconfig | 1 +
drivers/usb/core/hub.c | 20 ++++++++++++++-
drivers/usb/core/hub.h | 8 +++++-
drivers/usb/core/port.c | 56 +++++++++++++++++++++++++++++++++++++++++
drivers/usb/core/port.h | 2 ++
5 files changed, 85 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index abf8c6cdea9e..ef1959363fb1 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -44,6 +44,7 @@ config USB_ARCH_HAS_HCD
config USB
tristate "Support for Host-side USB"
depends on USB_ARCH_HAS_HCD
+ depends on POWER_SEQUENCING if POWER_SEQUENCING
select GENERIC_ALLOCATOR
select USB_COMMON
select NLS # for UTF-8 strings
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 47010090d3b6..d31c4f807391 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -33,6 +33,7 @@
#include <linux/mutex.h>
#include <linux/random.h>
#include <linux/pm_qos.h>
+#include <linux/pwrseq/consumer.h>
#include <linux/kobject.h>
#include <linux/bitfield.h>
@@ -872,6 +873,16 @@ static void hub_tt_work(struct work_struct *work)
spin_unlock_irqrestore(&hub->tt.lock, flags);
}
+static int usb_hub_set_port_pwrseq(struct usb_port *port, bool on)
+{
+ if (!IS_ENABLED(CONFIG_POWER_SEQUENCING))
+ return 0;
+
+ if (on)
+ return pwrseq_power_on(port->pwrseq);
+ return pwrseq_power_off(port->pwrseq);
+}
+
/**
* usb_hub_set_port_power - control hub port's power state
* @hdev: USB device belonging to the usb hub
@@ -887,15 +898,22 @@ static void hub_tt_work(struct work_struct *work)
int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
int port1, bool set)
{
+ struct usb_port *pwrseq_port = hub->ports[port1 - 1];
int ret;
+ ret = usb_hub_set_port_pwrseq(pwrseq_port, set);
+ if (ret)
+ return ret;
+
if (set)
ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
else
ret = usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
- if (ret)
+ if (ret) {
+ usb_hub_set_port_pwrseq(pwrseq_port, !set);
return ret;
+ }
assign_bit(port1, hub->power_bits, set);
return 0;
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index de524c6da9fc..7277c38c9e62 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -103,7 +103,13 @@ static inline bool hub_is_port_power_switchable(struct usb_hub *hub)
if (!hub)
return false;
hcs = hub->descriptor->wHubCharacteristics;
- return (le16_to_cpu(hcs) & HUB_CHAR_LPSM) < HUB_CHAR_NO_LPSM;
+ if ((le16_to_cpu(hcs) & HUB_CHAR_LPSM) < HUB_CHAR_NO_LPSM)
+ return true;
+ /* check for controllable external power sequencers */
+ for (unsigned int i = 0; i < hub->hdev->maxchild; i++)
+ if (hub->ports[i] && hub->ports[i]->pwrseq)
+ return true;
+ return false;
}
static inline int hub_is_superspeed(struct usb_device *hdev)
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 19913ad3598b..430fc9023250 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -8,11 +8,14 @@
*/
#include <linux/acpi.h>
+#include <linux/cleanup.h>
#include <linux/kstrtox.h>
#include <linux/slab.h>
#include <linux/string_choices.h>
#include <linux/sysfs.h>
#include <linux/pm_qos.h>
+#include <linux/property.h>
+#include <linux/pwrseq/consumer.h>
#include <linux/component.h>
#include <linux/usb/of.h>
@@ -35,6 +38,10 @@ int usb_port_is_power_on(struct usb_port *port, unsigned int portstatus)
ret = 1;
}
+ /* stub functions return error */
+ if (IS_ENABLED(CONFIG_POWER_SEQUENCING))
+ return ret && pwrseq_power_is_on(port->pwrseq);
+
return ret;
}
@@ -45,6 +52,9 @@ static bool usb_port_allow_power_off(struct usb_device *hdev,
if (hub_is_port_power_switchable(hub))
return true;
+ if (port_dev->pwrseq)
+ return true;
+
if (!IS_ENABLED(CONFIG_ACPI))
return false;
@@ -380,6 +390,9 @@ static void usb_port_device_release(struct device *dev)
* device_platform_notify_remove() in device_del().
*/
fwnode_handle_put(dev_fwnode(dev));
+ /* usb_hub_create_port_device() could leave an error value */
+ if (!IS_ERR(port_dev->pwrseq))
+ pwrseq_put(port_dev->pwrseq);
kfree(port_dev->req);
kfree(port_dev);
}
@@ -770,6 +783,40 @@ static const struct component_ops connector_ops = {
.unbind = connector_unbind,
};
+static bool port_pwrseq_is_supported(struct usb_port *port_dev)
+{
+ struct device *dev = &port_dev->dev;
+ struct fwnode_handle *port = dev_fwnode(dev);
+
+ struct fwnode_handle *ep __free(fwnode_handle) =
+ fwnode_graph_get_next_port_endpoint(port, NULL);
+ if (!ep)
+ return false;
+
+ struct fwnode_handle *remote __free(fwnode_handle) =
+ fwnode_graph_get_remote_port_parent(ep);
+ if (!remote)
+ return false;
+
+ if (!fwnode_device_is_compatible(remote, "pcie-m2-e-connector")) {
+ dev_dbg(dev, "remote endpoint %pfw is not a supported connector", remote);
+ return false;
+ }
+
+ return true;
+}
+
+static struct pwrseq_desc *usb_hub_port_pwrseq_get(struct usb_port *port_dev)
+{
+ if (!IS_ENABLED(CONFIG_POWER_SEQUENCING))
+ return NULL;
+
+ if (!port_pwrseq_is_supported(port_dev))
+ return NULL;
+
+ return pwrseq_get(&port_dev->dev, "usb");
+}
+
int usb_hub_create_port_device(struct usb_hub *hub, int port1)
{
struct usb_port *port_dev;
@@ -814,6 +861,7 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
retval = device_register(&port_dev->dev);
if (retval) {
put_device(&port_dev->dev);
+ hub->ports[port1 - 1] = NULL;
return retval;
}
@@ -831,6 +879,13 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
goto err_put_kn;
}
+ port_dev->pwrseq = usb_hub_port_pwrseq_get(port_dev);
+ if (IS_ERR(port_dev->pwrseq)) {
+ retval = dev_err_probe(&port_dev->dev, PTR_ERR(port_dev->pwrseq),
+ "failed to get power sequencing descriptor\n");
+ goto err_put_kn;
+ }
+
retval = component_add(&port_dev->dev, &connector_ops);
if (retval) {
dev_warn(&port_dev->dev, "failed to add component\n");
@@ -888,6 +943,7 @@ void usb_hub_remove_port_device(struct usb_hub *hub, int port1)
peer = port_dev->peer;
if (peer)
unlink_peers(port_dev, peer);
+ pwrseq_power_off(port_dev->pwrseq);
component_del(&port_dev->dev, &connector_ops);
sysfs_put(port_dev->state_kn);
device_unregister(&port_dev->dev);
diff --git a/drivers/usb/core/port.h b/drivers/usb/core/port.h
index 2f4349b3ce6b..088a182332d4 100644
--- a/drivers/usb/core/port.h
+++ b/drivers/usb/core/port.h
@@ -25,6 +25,7 @@
* @port_owner: port's owner
* @peer: related usb2 and usb3 ports (share the same connector)
* @connector: USB Type-C connector
+ * @pwrseq: power sequencing descriptor for the port
* @req: default pm qos request for hubs without port power control
* @connect_type: port's connect type
* @state: device state of the usb device attached to the port
@@ -44,6 +45,7 @@ struct usb_port {
struct usb_dev_state *port_owner;
struct usb_port *peer;
struct typec_connector *connector;
+ struct pwrseq_desc *pwrseq;
struct dev_pm_qos_request *req;
enum usb_port_connect_type connect_type;
enum usb_device_state state;
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 11/16] dt-bindings: usb: mediatek,mtk-xhci: Switch to ports for USB connections
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
` (9 preceding siblings ...)
2026-07-15 8:53 ` [PATCH v5 10/16] usb: hub: Power on connected M.2 E-key connectors with power sequencing API Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 12/16] power: sequencing: pcie-m2: support matching on remote "port" node Chen-Yu Tsai
` (4 subsequent siblings)
15 siblings, 0 replies; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern,
Krzysztof Kozlowski, Bartosz Golaszewski
This reverts commit 454a1e3cd36c113341d7b71e8e691c6e47ab4a8a.
MediaTek's XHCI implementation supports both USB 2.0 High Speed (HS)
and USB 3.x Super Speed (SS). The block can also be synthesized with
either HS-only capability or HS+SS capability. The SSUSB controller
handles the device or gadget mode. Saying that SSUSB handles the HS
portion is wrong.
For example, on the MT8195, the first two instances support both HS and
SS, while the latter two instances support only HS.
Switch to a "ports" sub-node for describing USB connections. Port 1 is
Super Speed if the controller is SS-capable, otherwise it is High Speed.
Port 2 is High Speed if SS-capable. This port mapping scheme directly
matches what the hardware returns in its capability registers.
Fixes: 454a1e3cd36c ("dt-bindings: usb: mediatek,mtk-xhci: Add port for SuperSpeed EP")
Cc: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v1:
- Squashed DT binding revert and addition together
- Dropped reviewed-by from Bartosz
---
.../bindings/usb/mediatek,mtk-xhci.yaml | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml
index 231e6f35a986..d6c75bd20b78 100644
--- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml
+++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml
@@ -107,10 +107,6 @@ properties:
- description: USB3/SS(P) PHY
- description: USB2/HS PHY
- port:
- $ref: /schemas/graph.yaml#/properties/port
- description: Super Speed (SS) Output endpoint to a Type-C connector
-
vusb33-supply:
description: Regulator of USB AVDD3.3v
@@ -188,6 +184,19 @@ properties:
"#size-cells":
const: 0
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Super Speed (SS) data bus if SS-capable;
+ otherwise High Speed (HS) data bus.
+
+ port@2:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: High Speed (HS) data bus if controller is SS-capable.
+
patternProperties:
"@[0-9a-f]{1}$":
type: object
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 12/16] power: sequencing: pcie-m2: support matching on remote "port" node
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
` (10 preceding siblings ...)
2026-07-15 8:53 ` [PATCH v5 11/16] dt-bindings: usb: mediatek,mtk-xhci: Switch to ports for USB connections Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 9:29 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 13/16] power: sequencing: pcie-m2: Add usb and sdio targets for E-key connector Chen-Yu Tsai
` (3 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern
A USB hub can have multiple ports, and this driver needs to
differentiate which port is being matched to. The USB hub driver now
associates the "port" node with the usb_port device, so here we can
use the remote "port" node to check for a match. Then fall back to
the remote device node for the other connection types.
Also rewrite the existing "remote == dev_of_node(dev)" with
device_match_of_node() for consistency.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v4:
- Dropped blank line between __free() variable declaration and
subsequent use of the variable in conditional (Andy)
Changes since v3:
- Drop redundant device node validity check; device_match_of_node()
does it internally
Changes since v2:
- Use device_match_of_node()
---
drivers/power/sequencing/pwrseq-pcie-m2.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index 83fe6a1396bc..691cad0a6dd0 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -175,9 +175,16 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
* parent matches the OF node of 'dev'.
*/
for_each_endpoint_of_node(ctx->of_node, endpoint) {
+ /* USB port devices are tied to the port nodes. */
+ struct device_node *remote_port __free(device_node) =
+ of_graph_get_remote_port(endpoint);
+ if (device_match_of_node(dev, remote_port))
+ return PWRSEQ_MATCH_OK;
+
+ /* Try the remote port parent for other types. */
struct device_node *remote __free(device_node) =
of_graph_get_remote_port_parent(endpoint);
- if (remote && (remote == dev_of_node(dev)))
+ if (device_match_of_node(dev, remote))
return PWRSEQ_MATCH_OK;
}
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 13/16] power: sequencing: pcie-m2: Add usb and sdio targets for E-key connector
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
` (11 preceding siblings ...)
2026-07-15 8:53 ` [PATCH v5 12/16] power: sequencing: pcie-m2: support matching on remote "port" node Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 9:34 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 14/16] power: sequencing: pcie-m2: Split Bluetooth unit based on interface Chen-Yu Tsai
` (2 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern
The M.2 E-key connector allows either PCIe or SDIO for WiFi and USB or
UART for BT. Currently the driver only supports PCIe and UART.
Add power sequencing targets for SDIO and USB. To avoid adding a
complicated dependency tree, rename the existing power sequencing units
"pcie" and "uart" to "wifi" and "bt". The existing target names are left
untouched. The new "sdio" and "usb" targets just point to the renamed
"wifi" and "bt" units.
The "unit" names are internal to the power sequencing framework, and
should be confined to a single provider. The names are only
informational. Dependencies are tracked with pointers to other units.
The "target" names are the strings that the consumer uses to acquire a
descriptor with. As these remain the same, existing users will continue
to work.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v2:
- Expand commit message
---
drivers/power/sequencing/pwrseq-pcie-m2.c | 41 +++++++++++++++--------
1 file changed, 27 insertions(+), 14 deletions(-)
diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index 691cad0a6dd0..693b0d33f8cf 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -69,46 +69,46 @@ static const struct pwrseq_unit_data *pwrseq_pcie_m2_unit_deps[] = {
NULL
};
-static int pwrseq_pci_m2_e_uart_enable(struct pwrseq_device *pwrseq)
+static int pwrseq_pci_m2_e_bt_enable(struct pwrseq_device *pwrseq)
{
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
return gpiod_set_value_cansleep(ctx->w_disable2_gpio, 0);
}
-static int pwrseq_pci_m2_e_uart_disable(struct pwrseq_device *pwrseq)
+static int pwrseq_pci_m2_e_bt_disable(struct pwrseq_device *pwrseq)
{
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
return gpiod_set_value_cansleep(ctx->w_disable2_gpio, 1);
}
-static const struct pwrseq_unit_data pwrseq_pcie_m2_e_uart_unit_data = {
- .name = "uart-enable",
+static const struct pwrseq_unit_data pwrseq_pcie_m2_e_bt_unit_data = {
+ .name = "bt-enable",
.deps = pwrseq_pcie_m2_unit_deps,
- .enable = pwrseq_pci_m2_e_uart_enable,
- .disable = pwrseq_pci_m2_e_uart_disable,
+ .enable = pwrseq_pci_m2_e_bt_enable,
+ .disable = pwrseq_pci_m2_e_bt_disable,
};
-static int pwrseq_pci_m2_e_pcie_enable(struct pwrseq_device *pwrseq)
+static int pwrseq_pci_m2_e_wifi_enable(struct pwrseq_device *pwrseq)
{
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
return gpiod_set_value_cansleep(ctx->w_disable1_gpio, 0);
}
-static int pwrseq_pci_m2_e_pcie_disable(struct pwrseq_device *pwrseq)
+static int pwrseq_pci_m2_e_wifi_disable(struct pwrseq_device *pwrseq)
{
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
return gpiod_set_value_cansleep(ctx->w_disable1_gpio, 1);
}
-static const struct pwrseq_unit_data pwrseq_pcie_m2_e_pcie_unit_data = {
- .name = "pcie-enable",
+static const struct pwrseq_unit_data pwrseq_pcie_m2_e_wifi_unit_data = {
+ .name = "wifi-enable",
.deps = pwrseq_pcie_m2_unit_deps,
- .enable = pwrseq_pci_m2_e_pcie_enable,
- .disable = pwrseq_pci_m2_e_pcie_disable,
+ .enable = pwrseq_pci_m2_e_wifi_enable,
+ .disable = pwrseq_pci_m2_e_wifi_disable,
};
static const struct pwrseq_unit_data pwrseq_pcie_m2_m_pcie_unit_data = {
@@ -130,13 +130,24 @@ static int pwrseq_pcie_m2_e_pwup_delay(struct pwrseq_device *pwrseq)
static const struct pwrseq_target_data pwrseq_pcie_m2_e_uart_target_data = {
.name = "uart",
- .unit = &pwrseq_pcie_m2_e_uart_unit_data,
+ .unit = &pwrseq_pcie_m2_e_bt_unit_data,
.post_enable = pwrseq_pcie_m2_e_pwup_delay,
};
+static const struct pwrseq_target_data pwrseq_pcie_m2_e_usb_target_data = {
+ .name = "usb",
+ .unit = &pwrseq_pcie_m2_e_bt_unit_data,
+};
+
static const struct pwrseq_target_data pwrseq_pcie_m2_e_pcie_target_data = {
.name = "pcie",
- .unit = &pwrseq_pcie_m2_e_pcie_unit_data,
+ .unit = &pwrseq_pcie_m2_e_wifi_unit_data,
+ .post_enable = pwrseq_pcie_m2_e_pwup_delay,
+};
+
+static const struct pwrseq_target_data pwrseq_pcie_m2_e_sdio_target_data = {
+ .name = "sdio",
+ .unit = &pwrseq_pcie_m2_e_wifi_unit_data,
.post_enable = pwrseq_pcie_m2_e_pwup_delay,
};
@@ -147,7 +158,9 @@ static const struct pwrseq_target_data pwrseq_pcie_m2_m_pcie_target_data = {
static const struct pwrseq_target_data *pwrseq_pcie_m2_e_targets[] = {
&pwrseq_pcie_m2_e_pcie_target_data,
+ &pwrseq_pcie_m2_e_sdio_target_data,
&pwrseq_pcie_m2_e_uart_target_data,
+ &pwrseq_pcie_m2_e_usb_target_data,
NULL
};
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 14/16] power: sequencing: pcie-m2: Split Bluetooth unit based on interface
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
` (12 preceding siblings ...)
2026-07-15 8:53 ` [PATCH v5 13/16] power: sequencing: pcie-m2: Add usb and sdio targets for E-key connector Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 9:34 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 15/16] arm64: dts: mediatek: mt8195-cherry: Add M.2 E-key slot Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 16/16] arm64: dts: mediatek: mt8188-geralt: Add WiFi/BT as " Chen-Yu Tsai
15 siblings, 1 reply; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern
Some UART / serdev based Bluetooth drivers need to be able to reset the
hardware during initialization or recovery. This is not possible with
the current power sequencing API if a unit is shared between USB and
UART interfaces.
For now, split the Bluetooth unit into two, one for each interface.
This allows either interface to independently toggle the power, with
the last action prevailing, thereby unbreaking the Qualcomm Bluetooth
serdev driver. This is also needed for the Realtek Bluetooth serdev
driver (hci_h5).
Having independent control from either interface unfortunately means
that userspace is able to shut down the controller from sysfs using
the USB port's "disable" setting without the serdev driver knowing
about it. On the USB side, independent control is also desired, as it
allows the USB core to power cycle the port/device during faults, and
for userspace to initiate reset and recovery using the aforementioned
"disable" setting. However when USB is used, a serdev device is not
created, and there is no conflicting usage, which allows the power
sequencing to work even without the split unit.
Suggested-by: Wei Deng <wei.deng@oss.qualcomm.com>
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v4:
- New patch
This patch is _not_ squashed into the previous to provide clear context
on the change, and the less than perfect nature of it.
I think what we need in this case is some sort of lockout. The serdev
consumer would want "exclusive" access, locking out the USB consumer,
which can tolerate "shared" access.
Something similar would be needed for the WiFi if we ever add support
for SDIO for toggling the state of W_DISABLE#1. At least the SDIO and
PCIe reset signals are separate.
---
drivers/power/sequencing/pwrseq-pcie-m2.c | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index 693b0d33f8cf..56e4f40e0480 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -83,8 +83,22 @@ static int pwrseq_pci_m2_e_bt_disable(struct pwrseq_device *pwrseq)
return gpiod_set_value_cansleep(ctx->w_disable2_gpio, 1);
}
-static const struct pwrseq_unit_data pwrseq_pcie_m2_e_bt_unit_data = {
- .name = "bt-enable",
+/*
+ * XXX There are two Bluetooth units to allow either one to be able to power
+ * off and thus reset the controller. In practice only one of the interfaces
+ * is used, so there is no conflict. However userspace could power off the
+ * USB unit by disabling the associated USB port, without the UART unit or
+ * its consumer ever knowing.
+ */
+static const struct pwrseq_unit_data pwrseq_pcie_m2_e_bt_uart_unit_data = {
+ .name = "bt-uart-enable",
+ .deps = pwrseq_pcie_m2_unit_deps,
+ .enable = pwrseq_pci_m2_e_bt_enable,
+ .disable = pwrseq_pci_m2_e_bt_disable,
+};
+
+static const struct pwrseq_unit_data pwrseq_pcie_m2_e_bt_usb_unit_data = {
+ .name = "bt-usb-enable",
.deps = pwrseq_pcie_m2_unit_deps,
.enable = pwrseq_pci_m2_e_bt_enable,
.disable = pwrseq_pci_m2_e_bt_disable,
@@ -130,13 +144,13 @@ static int pwrseq_pcie_m2_e_pwup_delay(struct pwrseq_device *pwrseq)
static const struct pwrseq_target_data pwrseq_pcie_m2_e_uart_target_data = {
.name = "uart",
- .unit = &pwrseq_pcie_m2_e_bt_unit_data,
+ .unit = &pwrseq_pcie_m2_e_bt_uart_unit_data,
.post_enable = pwrseq_pcie_m2_e_pwup_delay,
};
static const struct pwrseq_target_data pwrseq_pcie_m2_e_usb_target_data = {
.name = "usb",
- .unit = &pwrseq_pcie_m2_e_bt_unit_data,
+ .unit = &pwrseq_pcie_m2_e_bt_usb_unit_data,
};
static const struct pwrseq_target_data pwrseq_pcie_m2_e_pcie_target_data = {
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 15/16] arm64: dts: mediatek: mt8195-cherry: Add M.2 E-key slot
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
` (13 preceding siblings ...)
2026-07-15 8:53 ` [PATCH v5 14/16] power: sequencing: pcie-m2: Split Bluetooth unit based on interface Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
2026-07-15 9:45 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 16/16] arm64: dts: mediatek: mt8188-geralt: Add WiFi/BT as " Chen-Yu Tsai
15 siblings, 1 reply; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern
The Mt8195 Cherry design features an M.2 E-key slot for WiFi/BT combo
cards. Only PCIe and USB are wired from the SoC to the slot, along with
some auxiliary signals.
Add the proper representation for it, replacing the PCIe wifi node and
vpcie3v3-supply property under the PCIe controller, and the vbus-supply
property under the xhci3 node.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v2:
- Drop default GPIO output state from kill pins pinconfig
---
.../boot/dts/mediatek/mt8195-cherry.dtsi | 73 +++++++++++++++++--
1 file changed, 68 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
index ef7afc436aef..8d4cc30d91e4 100644
--- a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
@@ -266,6 +266,47 @@ tboard_thermistor2: thermal-sensor-t2 {
120000 51
125000 44>;
};
+
+ wifi-bt-connector {
+ compatible = "pcie-m2-e-connector";
+ pinctrl-names = "default";
+ pinctrl-0 = <&m2_e_key_kill_pins>;
+ vpcie3v3-supply = <&pp3300_wlan>;
+ w-disable1-gpios = <&pio 61 GPIO_ACTIVE_LOW>;
+ w-disable2-gpios = <&pio 59 GPIO_ACTIVE_LOW>;
+ /* PCIe auxiliary signals wired to controller. */
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* PCIe for WiFi */
+ port@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ wifi_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&pcie1_ep>;
+ };
+ };
+
+ /* USB for Bluetooth */
+ port@2 {
+ reg = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ bt_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&usb3_ep>;
+ };
+ };
+
+ /* SDIO, UART and I2S not implemented */
+ };
+ };
};
&adsp {
@@ -791,14 +832,14 @@ pcie@0 {
reg = <0 0 0 0 0>;
device_type = "pci";
num-lanes = <1>;
- vpcie3v3-supply = <&pp3300_wlan>;
#address-cells = <3>;
#size-cells = <2>;
ranges;
- wifi@0 {
- reg = <0 0 0 0 0>;
- wakeup-source;
+ port {
+ pcie1_ep: endpoint {
+ remote-endpoint = <&wifi_ep>;
+ };
};
};
};
@@ -1085,6 +1126,13 @@ pins-bus {
};
};
+ m2_e_key_kill_pins: m2-e-key-kill-pins {
+ pins-kill {
+ pinmux = <PINMUX_GPIO61__FUNC_GPIO61>,
+ <PINMUX_GPIO59__FUNC_GPIO59>;
+ };
+ };
+
mmc0_pins_default: mmc0-default-pins {
pins-cmd-dat {
pinmux = <PINMUX_GPIO126__FUNC_MSDC0_DAT0>,
@@ -1637,9 +1685,24 @@ &xhci2 {
&xhci3 {
/* MT7921's USB Bluetooth has issues with USB2 LPM */
usb2-lpm-disable;
- vbus-supply = <&pp3300_wlan>;
vusb33-supply = <&mt6359_vusb_ldo_reg>;
status = "okay";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ usb3_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&bt_ep>;
+ };
+ };
+ };
};
#include <arm/cros-ec-keyboard.dtsi>
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v5 16/16] arm64: dts: mediatek: mt8188-geralt: Add WiFi/BT as M.2 E-key slot
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
` (14 preceding siblings ...)
2026-07-15 8:53 ` [PATCH v5 15/16] arm64: dts: mediatek: mt8195-cherry: Add M.2 E-key slot Chen-Yu Tsai
@ 2026-07-15 8:53 ` Chen-Yu Tsai
15 siblings, 0 replies; 29+ messages in thread
From: Chen-Yu Tsai @ 2026-07-15 8:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: Wei Deng, Chen-Yu Tsai, linux-acpi, driver-core, linux-pm,
linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Alan Stern
The MT8188 Geralt design features a chip-on-board WiFi/BT solution. This
is a M.2 E-key WiFi/BT board layout directly inserted into the mainboard
design. The connections to the rest of the board are almost the same as
if it were a separate M.2 card. The only addition is the PMU_EN pin on
the chip; on M.2 cards this would be tied to the primary power source.
Model the chip-on-board WiFi/BT solution as a M.2 E-key slot with PCIe,
USB and auxiliary signals. The PMU_EN pin, which enables the internal
power controls and regulators, is modeled as a regulator fed by the
pp3300_wlan regulator. Since power sequencing is now correctly modeled
using the M.2 E-key slot, drop the "regulator-always-on" property one
pp3300_wlan regulator. Also drop the comment in xhci2 saying "MT7921's
power is controlled by PCIe".
Also drop the voltage range on the pp3300_wlan regulator. This
"regulator" is just a load switch and does not provide any regulation.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v2:
- Drop default GPIO output state from kill pins pinconfig
---
.../boot/dts/mediatek/mt8188-geralt.dtsi | 92 ++++++++++++++++++-
1 file changed, 88 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt.dtsi b/arch/arm64/boot/dts/mediatek/mt8188-geralt.dtsi
index dee946309121..73b5c0fdeae6 100644
--- a/arch/arm64/boot/dts/mediatek/mt8188-geralt.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt.dtsi
@@ -88,13 +88,11 @@ pp3300_z1: regulator-pp3300-z1 {
pp3300_wlan: regulator-pp3300-wlan {
compatible = "regulator-fixed";
regulator-name = "pp3300_wlan";
- regulator-always-on;
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
enable-active-high;
gpio = <&pio 12 GPIO_ACTIVE_HIGH>;
pinctrl-0 = <&wlan_en>;
pinctrl-names = "default";
+ /* load switch */
vin-supply = <&pp3300_z1>;
};
@@ -161,6 +159,17 @@ ppvar_mipi_disp_avee: regulator-ppvar-mipi-disp-avee {
vin-supply = <&pp5000_z1>;
};
+ /* PMU_EN pin controls internal regulators and power sequence */
+ wlan_pmu: regulator-wlan-pmu {
+ compatible = "regulator-fixed";
+ regulator-name = "wlan-pmu";
+ enable-active-high;
+ gpio = <&pio 145 GPIO_ACTIVE_HIGH>;
+ pinctrl-0 = <&wlan_pmu_en>;
+ pinctrl-names = "default";
+ vin-supply = <&pp3300_wlan>;
+ };
+
reserved_memory: reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
@@ -195,6 +204,39 @@ adsp_dma_mem: memory@61000000 {
no-map;
};
};
+
+ wifi-bt-connector {
+ compatible = "pcie-m2-e-connector";
+ pinctrl-names = "default";
+ pinctrl-0 = <&m2_e_key_kill_pins>;
+ vpcie1v8-supply = <&mt6359_vcn18_ldo_reg>;
+ vpcie3v3-supply = <&wlan_pmu>;
+ w-disable1-gpios = <&pio 13 GPIO_ACTIVE_LOW>;
+ w-disable2-gpios = <&pio 14 GPIO_ACTIVE_LOW>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* PCIe for WiFi */
+ port@0 {
+ reg = <0>;
+
+ wifi_ep: endpoint {
+ remote-endpoint = <&pcie_ep>;
+ };
+ };
+
+ /* USB for Bluetooth */
+ port@2 {
+ reg = <2>;
+
+ bt_ep: endpoint {
+ remote-endpoint = <&usb2_ep>;
+ };
+ };
+ };
+ };
};
&adsp {
@@ -659,6 +701,22 @@ &pcie {
pinctrl-names = "default";
pinctrl-0 = <&pcie_pins>;
status = "okay";
+
+ pcie@0 {
+ compatible = "pciclass,0604";
+ reg = <0 0 0 0 0>;
+ device_type = "pci";
+ num-lanes = <1>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+
+ port {
+ pcie_ep: endpoint {
+ remote-endpoint = <&wifi_ep>;
+ };
+ };
+ };
};
&pciephy {
@@ -1002,6 +1060,13 @@ pins-bus {
};
};
+ m2_e_key_kill_pins: m2-e-key-kill-pins {
+ pins-kill {
+ pinmux = <PINMUX_GPIO13__FUNC_B_GPIO13>,
+ <PINMUX_GPIO14__FUNC_B_GPIO14>;
+ };
+ };
+
mipi_disp_avdd_en: mipi-disp-avdd-en-pins {
pins-en-ppvar-mipi-disp {
pinmux = <PINMUX_GPIO3__FUNC_B_GPIO3>;
@@ -1174,6 +1239,13 @@ pins-bus {
};
};
+ wlan_pmu_en: wlan-pmu-en-pins {
+ pins-wlan-pmu-en {
+ pinmux = <PINMUX_GPIO145__FUNC_B_GPIO145>;
+ output-low;
+ };
+ };
+
wlan_en: wlan-en-pins {
pins-en-pp3300-wlan {
pinmux = <PINMUX_GPIO12__FUNC_B_GPIO12>;
@@ -1417,10 +1489,22 @@ vdosys1_ep_ext: endpoint@1 {
};
&xhci2 {
- /* no power supply since MT7921's power is controlled by PCIe */
/* MT7921's USB BT has issues with USB2 LPM */
usb2-lpm-disable;
status = "okay";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ reg = <1>;
+
+ usb2_ep: endpoint {
+ remote-endpoint = <&bt_ep>;
+ };
+ };
+ };
};
#include <arm/cros-ec-keyboard.dtsi>
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH v5 01/16] device property: Add fwnode_graph_get_port_by_id()
2026-07-15 8:53 ` [PATCH v5 01/16] device property: Add fwnode_graph_get_port_by_id() Chen-Yu Tsai
@ 2026-07-15 9:03 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-15 9:03 UTC (permalink / raw)
To: Chen-Yu Tsai; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The patch adds two conflicting declarations for `fwnode_graph_get_port_by_id` in `include/linux/property.h`, which will break the build.
--
--- Patch [1]: [PATCH v5 01/16] device property: Add fwnode_graph_get_port_by_id() ---
commit 88979df4c2fc6de15d7726e00adc783bff896bbd
Author: Chen-Yu Tsai <wenst@chromium.org>
device property: Add fwnode_graph_get_port_by_id()
This commit introduces a helper function to retrieve a reference to a port
firmware node by its ID. It includes a flags parameter to allow callers to
specify whether incomplete ports should be returned.
[ ... ]
> diff --git a/include/linux/property.h b/include/linux/property.h
> index 14c304db46648..480ba8646bcc8 100644
> --- a/include/linux/property.h
> +++ b/include/linux/property.h
> @@ -505,6 +505,9 @@ int fwnode_get_phy_mode(const struct fwnode_handle *fwnode);
>
> void __iomem *fwnode_iomap(struct fwnode_handle *fwnode, int index);
>
> +struct fwnode_handle *fwnode_graph_get_port_by_id(struct fwnode_handle *fwnode, u32 id);
> +struct fwnode_handle *fwnode_graph_get_port_by_id(struct fwnode_handle *fwnode, u32 id,
> + unsigned long flags);
[Severity: Low]
Does this cause a build failure? It looks like there are two conflicting
declarations for fwnode_graph_get_port_by_id() with different signatures.
Since C doesn't support function overloading, will this result in a
'conflicting types' compilation error when the header is included?
> struct fwnode_handle *fwnode_graph_get_next_endpoint(
> const struct fwnode_handle *fwnode, struct fwnode_handle *prev);
> struct fwnode_handle *
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260715085348.3457359-1-wenst@chromium.org?part=1
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v5 03/16] power: sequencing: Add pwrseq_power_is_on()
2026-07-15 8:53 ` [PATCH v5 03/16] power: sequencing: Add pwrseq_power_is_on() Chen-Yu Tsai
@ 2026-07-15 9:08 ` sashiko-bot
2026-07-15 9:29 ` Andy Shevchenko
1 sibling, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-15 9:08 UTC (permalink / raw)
To: Chen-Yu Tsai; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [Medium] The !CONFIG_POWER_SEQUENCING stub for pwrseq_power_is_on() unconditionally returns -ENOSYS, breaking support for optional descriptors.
- [Medium] Unprotected lockless read of `desc->powered_on` in `pwrseq_power_is_on()` constitutes a data race.
Pre-existing issues:
- [High] The stubs for pwrseq_power_on() and pwrseq_power_off() unconditionally return -ENOSYS, breaking optional descriptors when CONFIG_POWER_SEQUENCING is disabled.
- [High] Lockless TOCTOU race on `desc->powered_on` in `pwrseq_power_on()` and `pwrseq_power_off()` allows concurrent calls to leak `enable_count` references.
--
--- Patch [3]: [PATCH v5 03/16] power: sequencing: Add pwrseq_power_is_on() ---
commit 32144de8b3a9da0a0745b35617cfc4d0359911df
Author: Chen-Yu Tsai <wenst@chromium.org>
power: sequencing: Add pwrseq_power_is_on()
This commit introduces pwrseq_power_is_on() to expose the internal power-on
state tracking to consumers, eliminating the need for local tracking. The API
handles optional descriptors by returning 1 if the descriptor is NULL.
> diff --git a/drivers/power/sequencing/core.c b/drivers/power/sequencing/core.c
> index 02f42da915985..db8c91be10c95 100644
> --- a/drivers/power/sequencing/core.c
> +++ b/drivers/power/sequencing/core.c
> @@ -968,6 +968,25 @@ int pwrseq_power_off(struct pwrseq_desc *desc)
> }
> EXPORT_SYMBOL_GPL(pwrseq_power_off);
[Severity: High]
This is a pre-existing issue, but could the lockless check of
desc->powered_on in pwrseq_power_on() and pwrseq_power_off() cause a race
condition that leaks enable_count references?
If two threads concurrently invoke pwrseq_power_on() with the same descriptor,
both could bypass the early check locklessly:
if (!desc || desc->powered_on)
return 0;
They then sequentially acquire pwrseq->state_lock, but neither re-validates
the flag inside the critical section. Both execute pwrseq_unit_enable(),
incrementing enable_count twice.
When pwrseq_power_off() is called later, the first invocation decrements the
count and clears desc->powered_on. The second invocation sees
desc->powered_on == false locklessly and returns early, leaving enable_count
permanently elevated.
> +/**
> + * pwrseq_power_is_on() - Queries the last requested state of the power sequencer.
> + * @desc: Descriptor referencing the power sequencer.
> + *
> + * This returns the last requested state of the power sequencer.
> + *
> + * Returns:
> + * On success, 1 for on or desc is NULL (optional) and 0 for off;
> + * negative error number on failure.
> + */
> +int pwrseq_power_is_on(struct pwrseq_desc *desc)
> +{
> + if (!desc)
> + return 1;
> +
> + return desc->powered_on;
[Severity: Medium]
Does this lockless read of desc->powered_on need READ_ONCE() to prevent data
races?
Since desc->powered_on can be concurrently modified by pwrseq_power_on()
and pwrseq_power_off(), reading it without protection might lead to unsafe
compiler optimizations.
> +}
> +EXPORT_SYMBOL_GPL(pwrseq_power_is_on);
[ ... ]
> diff --git a/include/linux/pwrseq/consumer.h b/include/linux/pwrseq/consumer.h
> index 3c907c9e1885d..3c6122bd02057 100644
> --- a/include/linux/pwrseq/consumer.h
> +++ b/include/linux/pwrseq/consumer.h
[ ... ]
> @@ -53,6 +54,11 @@ static inline int pwrseq_power_off(struct pwrseq_desc *desc)
> return -ENOSYS;
> }
[Severity: High]
This is a pre-existing issue, but do the stubs for pwrseq_power_on() and
pwrseq_power_off() also break optional descriptors?
If a driver invokes pwrseq_power_on(NULL) on a kernel without power
sequencing enabled, returning -ENOSYS instead of 0 defeats the purpose of
an optional descriptor, as consumers checking for errors will abort their
operations.
> +static inline int pwrseq_power_is_on(struct pwrseq_desc *desc)
> +{
> + return -ENOSYS;
> +}
[Severity: Medium]
When CONFIG_POWER_SEQUENCING is disabled, does this stub break the contract
for optional descriptors?
The commit message mentions returning 1 if the descriptor is NULL (optional),
but this stub unconditionally returns -ENOSYS. This will cause consumers
checking the power state of an optional descriptor to receive a negative
error code instead of the expected 1.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260715085348.3457359-1-wenst@chromium.org?part=3
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v5 02/16] device property: Add fwnode_graph_get_next_port_endpoint()
2026-07-15 8:53 ` [PATCH v5 02/16] device property: Add fwnode_graph_get_next_port_endpoint() Chen-Yu Tsai
@ 2026-07-15 9:09 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-15 9:09 UTC (permalink / raw)
To: Chen-Yu Tsai; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] The new `fwnode_graph_get_next_port_endpoint()` helper breaks the `fwnode` graph abstraction by hardcoding OF-specific naming conventions, which will silently ignore valid ACPI and software node endpoints.
- [Medium] `fwnode_graph_get_next_port_endpoint()` fails to unconditionally put the `prev` fwnode reference if an invalid `port` is provided, violating its documented API contract.
Pre-existing issues:
- [High] This problem wasn't introduced by this patch, but iterating over endpoints using `fwnode_get_next_child_node()` causes an infinite loop and Use-After-Free when a device has secondary fwnodes attached.
--
--- Patch [2]: [PATCH v5 02/16] device property: Add fwnode_graph_get_next_port_endpoint() ---
commit 8a16a51eeb8e99439d5b85ce61789ff1153e9060
Author: Chen-Yu Tsai <wenst@chromium.org>
device property: Add fwnode_graph_get_next_port_endpoint()
Adds a helper function to iterate through the endpoint firmware nodes
under a given port. This is intended to be used in USB power sequencing
integration to verify graph connections and supported connector types.
> diff --git a/drivers/base/property.c b/drivers/base/property.c
> index 0bd45f8b01c14..62c6221d65d05 100644
> --- a/drivers/base/property.c
> +++ b/drivers/base/property.c
[ ... ]
> @@ -1099,6 +1099,31 @@ int fwnode_irq_get_byname(const struct fwnode_handle *fwnode, const char *name)
> }
> EXPORT_SYMBOL(fwnode_irq_get_byname);
>
> +/**
> + * fwnode_graph_get_next_port_endpoint - Get next endpoint firmware node in port
> + * @port: Pointer to the target port firmware node
> + * @prev: Previous endpoint node or %NULL to get the first
> + *
> + * The caller is responsible for calling fwnode_handle_put() on the returned
> + * fwnode pointer. Note that this function also puts a reference to @prev
> + * unconditionally.
> + *
> + * Return: an endpoint firmware node pointer or %NULL if no more endpoints
> + * are available.
> + */
> +struct fwnode_handle *fwnode_graph_get_next_port_endpoint(const struct fwnode_handle *port,
> + struct fwnode_handle *prev)
> +{
> + do {
> + prev = fwnode_get_next_child_node(port, prev);
[Severity: High]
This is a pre-existing issue, but iterating over endpoints using
fwnode_get_next_child_node() can cause an infinite loop and a use-after-free
if a device has secondary fwnodes attached.
If a device port has both primary children and a secondary fwnode, the primary
ops finish and drop the reference to the last primary child, returning NULL.
Then, fwnode_get_next_child_node() incorrectly passes this same dropped child
pointer to the secondary ops:
drivers/base/property.c:fwnode_get_next_child_node() {
/* Try to find a child in primary fwnode */
next = fwnode_call_ptr_op(fwnode, get_next_child_node, child);
if (next)
return next;
/* When no more children in primary, continue with secondary */
return fwnode_call_ptr_op(fwnode->secondary, get_next_child_node, child);
}
This can result in a double-put. Furthermore, when traversing secondary
children, the primary ops don't recognize the software node, treat it as NULL,
and return the first primary child again, creating an infinite loop.
[Severity: Medium]
Does this fail to unconditionally put the prev reference if the provided port
is invalid?
If a caller passes a valid prev node but port is NULL or an error pointer,
fwnode_get_next_child_node() returns early without dropping prev:
drivers/base/property.c:fwnode_get_next_child_node() {
struct fwnode_handle *next;
if (IS_ERR_OR_NULL(fwnode))
return NULL;
...
}
Could this lead to a reference count leak, violating the documented API
contract that prev is unconditionally put?
> + if (fwnode_name_eq(prev, "endpoint"))
[Severity: High]
Does hardcoding this string match break the fwnode graph abstraction for
non-DeviceTree platforms?
By strictly matching the "endpoint" prefix, this bypasses the provider-specific
fwnode_operations, which could silently ignore valid ACPI and software node
endpoints that don't follow this exact naming scheme. Shouldn't this rely on
the backend-specific graph_get_next_endpoint operations instead?
> + break;
> + } while (prev);
> +
> + return prev;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_graph_get_next_port_endpoint);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260715085348.3457359-1-wenst@chromium.org?part=2
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v5 04/16] usb: hub: Use assign_bit() in usb_hub_set_port_power()
2026-07-15 8:53 ` [PATCH v5 04/16] usb: hub: Use assign_bit() in usb_hub_set_port_power() Chen-Yu Tsai
@ 2026-07-15 9:11 ` Andy Shevchenko
0 siblings, 0 replies; 29+ messages in thread
From: Andy Shevchenko @ 2026-07-15 9:11 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Daniel Scally,
Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Wei Deng,
linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
linux-mediatek, linux-arm-kernel, linux-kernel,
Manivannan Sadhasivam, Alan Stern
On Wed, Jul 15, 2026 at 04:53:34PM +0800, Chen-Yu Tsai wrote:
> usb_hub_set_port_power() open-codes assign_bit(). Just use the
> assign_bit() macro instead. This makes subsequent additions to
> usb_hub_set_port_power() easier to read.
>
> This change does not introduce any functional changes.
Yes, it's a pure cleanup.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v5 06/16] usb: hub: Associate port@ fwnode with USB port device
2026-07-15 8:53 ` [PATCH v5 06/16] usb: hub: Associate port@ fwnode with USB port device Chen-Yu Tsai
@ 2026-07-15 9:20 ` Andy Shevchenko
0 siblings, 0 replies; 29+ messages in thread
From: Andy Shevchenko @ 2026-07-15 9:20 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Daniel Scally,
Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Wei Deng,
linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
linux-mediatek, linux-arm-kernel, linux-kernel,
Manivannan Sadhasivam, Alan Stern, Bartosz Golaszewski
On Wed, Jul 15, 2026 at 04:53:36PM +0800, Chen-Yu Tsai wrote:
> When a USB hub port is connected to a connector in a firmware node
> graph, the port itself has a node in the graph.
>
> Associate the port's firmware node with the USB port's device,
> usb_port::dev. This is used in later changes for the M.2 slot power
> sequencing provider to match against the requesting port.
>
> To avoid potential conflicts with ACPI firmware nodes and then causing
> power management issues, only assign the firmware node if the hub's
> firmware node is not an ACPI firmware node.
...
> int usb_hub_create_port_device(struct usb_hub *hub, int port1)
What about adding
struct fwnode_handle *fwnode = dev_fwnode(&hdev->dev);
to the top of the function, and...
> port_dev->dev.driver = &usb_port_driver;
> dev_set_name(&port_dev->dev, "%s-port%d", dev_name(&hub->hdev->dev),
> port1);
> + /*
> + * ACPI FW nodes are associated later when device_register() happens.
> + * Skip assigning one here to avoid potential conflicts.
> + */
> + if (!is_acpi_node(dev_fwnode(&hdev->dev)))
> + device_set_node(&port_dev->dev,
> + fwnode_graph_get_port_by_id(dev_fwnode(&hdev->dev), port1,
> + FWNODE_GRAPH_DEVICE_DISABLED));
...shorten this a bit to
if (!is_acpi_node(fwnode)) {
struct fwnode_handle *ep;
ep = fwnode_graph_get_port_by_id(fwnode, port1, FWNODE_GRAPH_DEVICE_DISABLED);
// Is NULL or error pointer is fine here to be set as fwnode in port device?
// Perhaps add a comment?
device_set_node(&port_dev->dev, ep);
}
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v5 10/16] usb: hub: Power on connected M.2 E-key connectors with power sequencing API
2026-07-15 8:53 ` [PATCH v5 10/16] usb: hub: Power on connected M.2 E-key connectors with power sequencing API Chen-Yu Tsai
@ 2026-07-15 9:28 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-15 9:28 UTC (permalink / raw)
To: Chen-Yu Tsai; +Cc: robh, devicetree, conor+dt
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Concurrent sysfs `disable` read or write can dereference an `ERR_PTR` if `usb_hub_port_pwrseq_get()` fails.
- [High] usb_hub_set_port_power() accesses the dynamically allocated hub->ports array, which can be freed concurrently by hub_disconnect().
--
--- Patch [10]: [PATCH v5 10/16] usb: hub: Power on connected M.2 E-key connectors with power sequencing API ---
commit e0346a1be7fb5d1254f3498bb6d857dd5db5a9d7
Author: Chen-Yu Tsai <wenst@chromium.org>
Subject: usb: hub: Power on connected M.2 E-key connectors with power sequencing API
This patch integrates the power sequencing API with USB ports to support M.2
E-key connectors. It manages power sequencing during port creation, removal,
and power state changes.
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index 10f15b40fcc55..298fb68c6afc7 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
[ ... ]
> @@ -887,15 +898,22 @@ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
> int port1, bool set)
> {
> + struct usb_port *pwrseq_port = hub->ports[port1 - 1];
[Severity: High]
Can this code trigger a use-after-free on the hub->ports array?
The sysfs disable_store callback uses sysfs_break_active_protection()
to avoid deadlocks, meaning it prevents device_unregister() from waiting
for the callback to finish.
If hub_probe() fails and triggers hub_disconnect() concurrently,
hub_disconnect() will call device_unregister() which returns immediately.
Then hub_disconnect() unconditionally frees the hub->ports array:
hub_disconnect() {
...
kfree(hub->ports);
}
Meanwhile, disable_store() can continue and call usb_hub_set_port_power(),
which now accesses the freed hub->ports array. Prior to this change,
usb_hub_set_port_power() only accessed inline fields of the refcounted
hub struct.
Is there a way to safely access the port here without racing against the array
being freed?
> + int ret;
>
> + ret = usb_hub_set_port_pwrseq(pwrseq_port, set);
> + if (ret)
> + return ret;
[ ... ]
> diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
> index 19913ad3598b3..430fc90232502 100644
> --- a/drivers/usb/core/port.c
> +++ b/drivers/usb/core/port.c
[ ... ]
> @@ -831,6 +879,13 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
> goto err_put_kn;
> }
>
> + port_dev->pwrseq = usb_hub_port_pwrseq_get(port_dev);
> + if (IS_ERR(port_dev->pwrseq)) {
> + retval = dev_err_probe(&port_dev->dev, PTR_ERR(port_dev->pwrseq),
> + "failed to get power sequencing descriptor\n");
> + goto err_put_kn;
> + }
[Severity: High]
Could this temporarily expose an ERR_PTR to concurrent sysfs operations?
The port device is registered earlier in this function via device_register(),
exposing its sysfs attributes (like disable) before usb_hub_port_pwrseq_get()
is called.
If acquiring the power sequencer fails and returns an ERR_PTR,
port_dev->pwrseq will hold this ERR_PTR. Because sysfs unregistration waits
for active callbacks on the error path, a concurrent read or write to the
disable attribute could access port_dev->pwrseq while it holds an error value.
This ERR_PTR would then be passed to usb_port_is_power_on() or
usb_hub_set_port_pwrseq(), which call the power sequencer APIs:
static int usb_hub_set_port_pwrseq(struct usb_port *port, bool on)
{
if (!IS_ENABLED(CONFIG_POWER_SEQUENCING))
return 0;
if (on)
return pwrseq_power_on(port->pwrseq);
return pwrseq_power_off(port->pwrseq);
}
Since the pwrseq_power_* APIs do not check for ERR_PTR, would this cause
a panic when dereferencing the pointer?
> +
> retval = component_add(&port_dev->dev, &connector_ops);
> if (retval) {
> dev_warn(&port_dev->dev, "failed to add component\n");
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260715085348.3457359-1-wenst@chromium.org?part=10
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v5 03/16] power: sequencing: Add pwrseq_power_is_on()
2026-07-15 8:53 ` [PATCH v5 03/16] power: sequencing: Add pwrseq_power_is_on() Chen-Yu Tsai
2026-07-15 9:08 ` sashiko-bot
@ 2026-07-15 9:29 ` Andy Shevchenko
1 sibling, 0 replies; 29+ messages in thread
From: Andy Shevchenko @ 2026-07-15 9:29 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Daniel Scally,
Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Wei Deng,
linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
linux-mediatek, linux-arm-kernel, linux-kernel,
Manivannan Sadhasivam, Alan Stern, Bartosz Golaszewski
On Wed, Jul 15, 2026 at 04:53:33PM +0800, Chen-Yu Tsai wrote:
> The power sequencing consumer API already does power on state tracking
> internally. Expose the state to consumers through pwrseq_power_is_on()
> so that they don't have to reimplement it locally.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
...
> +/**
> + * pwrseq_power_is_on() - Queries the last requested state of the power sequencer.
> + * @desc: Descriptor referencing the power sequencer.
> + *
> + * This returns the last requested state of the power sequencer.
> + *
> + * Returns:
> + * On success, 1 for on or desc is NULL (optional) and 0 for off;
> + * negative error number on failure.
I would rephrase it a bit.
* On success, 1 for on and 0 for off; negative error number on failure.
* If desc is NULL (means optional) return 1.
And this rises a question: why 1? Shouldn't it be some "unknown" state?
(But since Bart Acked this, this doesn't prevent the patch to go, you
got my tag above.)
> + */
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v5 12/16] power: sequencing: pcie-m2: support matching on remote "port" node
2026-07-15 8:53 ` [PATCH v5 12/16] power: sequencing: pcie-m2: support matching on remote "port" node Chen-Yu Tsai
@ 2026-07-15 9:29 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-15 9:29 UTC (permalink / raw)
To: Chen-Yu Tsai; +Cc: devicetree, conor+dt, robh
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing `serdev_controller_put()` in `pwrseq_pcie_m2_create_serdev_one()` returns path.
- [High] Unchecked `pdev->dev.parent` in `pwrseq_pcie_m2_notify()` leads to NULL pointer dereference.
- [High] Mixing `devm` registration with manual resource cleanup causes Use-After-Free of regulator consumers.
--
--- Patch [12]: [PATCH v5 12/16] power: sequencing: pcie-m2: support matching on remote "port" node ---
commit 8eb380a4e579162e00e556321400077f29d6c07e
Author: Chen-Yu Tsai <wenst@chromium.org>
power: sequencing: pcie-m2: support matching on remote "port" node
This commit updates the pcie-m2 power sequencing driver to support matching
against remote "port" nodes for USB hubs. It uses of_graph_get_remote_port()
and falls back to the remote port parent for other connection types. It
also updates the existing matching logic to use device_match_of_node().
> diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
> index ddfe6ca824945..01f9f6a717464 100644
> --- a/drivers/power/sequencing/pwrseq-pcie-m2.c
> +++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
> @@ -175,9 +175,16 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
> * parent matches the OF node of 'dev'.
> */
> for_each_endpoint_of_node(ctx->of_node, endpoint) {
> + /* USB port devices are tied to the port nodes. */
> + struct device_node *remote_port __free(device_node) =
> + of_graph_get_remote_port(endpoint);
> + if (device_match_of_node(dev, remote_port))
> + return PWRSEQ_MATCH_OK;
> +
> + /* Try the remote port parent for other types. */
> struct device_node *remote __free(device_node) =
> of_graph_get_remote_port_parent(endpoint);
> - if (remote && (remote == dev_of_node(dev)))
> + if (device_match_of_node(dev, remote))
> return PWRSEQ_MATCH_OK;
> }
>
[Severity: High]
This isn't a bug introduced by this patch, but does
pwrseq_pcie_m2_create_serdev_one() leak the serdev_ctrl reference on the
early return path?
If the serdev device was already created for the PCI device, the list
iteration returns 0 directly:
drivers/power/sequencing/pwrseq-pcie-m2.c:pwrseq_pcie_m2_create_serdev_one() {
...
scoped_guard(mutex, &ctx->list_lock) {
list_for_each_entry(pci_dev, &ctx->pci_devices, list) {
if (pci_dev->pdev == pdev)
return 0;
}
}
...
}
This appears to bypass the serdev_controller_put(serdev_ctrl) cleanup. Could
this accumulate leaked references during PCI bus probing or device
notification callbacks?
[Severity: High]
This is a pre-existing issue, but could pwrseq_pcie_m2_notify() trigger a
NULL pointer dereference on systems with a root PCI bus?
Some bus scanning flows use pci_create_root_bus(NULL, ...), where devices
have no parent. The BUS_NOTIFY_ADD_DEVICE notifier is registered globally
and evaluates this without checking if pdev->dev.parent is NULL:
drivers/power/sequencing/pwrseq-pcie-m2.c:pwrseq_pcie_m2_notify() {
...
if (!pci_parent || (pci_parent != pdev->dev.parent->of_node))
return NOTIFY_DONE;
...
}
Could this cause a kernel panic during PCI bus probing on affected systems
when the driver is active?
[Severity: High]
This isn't a bug introduced by this patch, but does mixing devm registration
with manual regulator cleanup cause a use-after-free?
In the probe error path and remove function, the regulators are manually
freed:
drivers/power/sequencing/pwrseq-pcie-m2.c:pwrseq_pcie_m2_probe() {
...
err_free_regulators:
regulator_bulk_free(ctx->num_vregs, ctx->regs);
...
}
drivers/power/sequencing/pwrseq-pcie-m2.c:pwrseq_pcie_m2_remove() {
...
regulator_bulk_free(ctx->num_vregs, ctx->regs);
...
}
Since the power sequencer device is registered via
devm_pwrseq_device_register(), it remains active until the devres teardown
runs after the function returns. If a consumer calls a power sequencing
operation during this window, or if the driver is unbound via sysfs, will
it access the freed regulator consumer objects?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260715085348.3457359-1-wenst@chromium.org?part=12
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v5 07/16] usb: core: Move struct usb_port and related APIs to port.h
2026-07-15 8:53 ` [PATCH v5 07/16] usb: core: Move struct usb_port and related APIs to port.h Chen-Yu Tsai
@ 2026-07-15 9:31 ` Andy Shevchenko
0 siblings, 0 replies; 29+ messages in thread
From: Andy Shevchenko @ 2026-07-15 9:31 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Daniel Scally,
Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Wei Deng,
linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
linux-mediatek, linux-arm-kernel, linux-kernel,
Manivannan Sadhasivam, Alan Stern, Bartosz Golaszewski
On Wed, Jul 15, 2026 at 04:53:37PM +0800, Chen-Yu Tsai wrote:
> |struct usb_port| and its matching container_of() macro should live in
> its own port.h, matching the split we have for .c files.
>
> Move them as described. Also move usb_port_is_power_on(), since in the
> next change its |struct usb_hub *| parameter will be changed to
> |struct usb_port *|, and becomes a non-static function that only
> references |struct usb_port|.
>
> port.h is only included from hub.h, as a subsequent patch will directly
> use fields from |struct usb_port| in a static inline helper in hub.h.
> The USB internal headers don't have header guards to help with this.
>
> Also drop 'extern' from the header declaration of usb_port_is_power_on().
> This is not needed in modern C.
...
> +struct usb_port {
> + struct usb_device *child;
> + struct device dev;
> + struct usb_dev_state *port_owner;
> + struct usb_port *peer;
> + struct typec_connector *connector;
> + struct dev_pm_qos_request *req;
> + enum usb_port_connect_type connect_type;
> + enum usb_device_state state;
> + struct kernfs_node *state_kn;
> + usb_port_location_t location;
> + struct mutex status_lock;
> + u32 over_current_count;
> + u8 portnum;
> + u32 quirks;
> + unsigned int early_stop:1;
> + unsigned int ignore_event:1;
> + unsigned int is_superspeed:1;
> + unsigned int usb3_lpm_u1_permit:1;
> + unsigned int usb3_lpm_u2_permit:1;
> +};
A side note for the future development (no need to change anything here
right now). It might be that the layout is suboptimal and `pahole` might
propose a better one.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v5 13/16] power: sequencing: pcie-m2: Add usb and sdio targets for E-key connector
2026-07-15 8:53 ` [PATCH v5 13/16] power: sequencing: pcie-m2: Add usb and sdio targets for E-key connector Chen-Yu Tsai
@ 2026-07-15 9:34 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-15 9:34 UTC (permalink / raw)
To: Chen-Yu Tsai; +Cc: conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing initialization of `list_head` causes a NULL pointer dereference on the `pwrseq_unit_setup()` error path.
--
--- Patch [13]: [PATCH v5 13/16] power: sequencing: pcie-m2: Add usb and sdio targets for E-key connector ---
commit a4efebd06d30c32580111345a5d6a16748b52be2
Author: Chen-Yu Tsai <wenst@chromium.org>
power: sequencing: pcie-m2: Add usb and sdio targets for E-key connector
The M.2 E-key connector allows either PCIe or SDIO for WiFi and USB or
UART for BT. This commit adds power sequencing targets for SDIO and USB
by renaming existing units to wifi and bt.
> diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
> index 01f9f6a717464..8ae55e87db74c 100644
> --- a/drivers/power/sequencing/pwrseq-pcie-m2.c
> +++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
> @@ -69,46 +69,46 @@ static const struct pwrseq_unit_data *pwrseq_pcie_m2_unit_deps[] = {
[ ... ]
> -static const struct pwrseq_unit_data pwrseq_pcie_m2_e_uart_unit_data = {
> - .name = "uart-enable",
> +static const struct pwrseq_unit_data pwrseq_pcie_m2_e_bt_unit_data = {
> + .name = "bt-enable",
> .deps = pwrseq_pcie_m2_unit_deps,
> - .enable = pwrseq_pci_m2_e_uart_enable,
> - .disable = pwrseq_pci_m2_e_uart_disable,
> + .enable = pwrseq_pci_m2_e_bt_enable,
> + .disable = pwrseq_pci_m2_e_bt_disable,
> };
[Severity: High]
This is a pre-existing issue, but while reviewing the new power sequencing
units being added here, I noticed a potential NULL pointer dereference in
the core power sequencing error path.
Does the error path in pwrseq_unit_setup() crash when freeing an uninitialized
list?
When a unit is allocated in drivers/power/sequencing/core.c:pwrseq_unit_new(),
the unit->list field is not initialized:
drivers/power/sequencing/core.c:pwrseq_unit_new() {
...
kref_init(&unit->ref);
INIT_LIST_HEAD(&unit->deps);
unit->enable = data->enable;
...
}
If pwrseq_unit_setup() fails before adding the unit to the list (for example,
due to an out-of-memory error), the cleanup path calls pwrseq_unit_put(unit).
This triggers pwrseq_unit_release():
drivers/power/sequencing/core.c:pwrseq_unit_release() {
...
pwrseq_unit_free_deps(&unit->deps);
list_del(&unit->list);
kfree_const(unit->name);
...
}
Since INIT_LIST_HEAD(&unit->list) was never called, the list pointers are
still NULL. Calling list_del(&unit->list) will attempt to modify next->prev,
resulting in an immediate kernel panic.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260715085348.3457359-1-wenst@chromium.org?part=13
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v5 14/16] power: sequencing: pcie-m2: Split Bluetooth unit based on interface
2026-07-15 8:53 ` [PATCH v5 14/16] power: sequencing: pcie-m2: Split Bluetooth unit based on interface Chen-Yu Tsai
@ 2026-07-15 9:34 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-15 9:34 UTC (permalink / raw)
To: Chen-Yu Tsai; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Splitting a single shared physical reset GPIO into two logical power sequencing units bypasses the core's refcounting, causing the USB subsystem's runtime PM to inadvertently power off the Bluetooth controller while it is actively in use by the UART driver.
--
--- Patch [14]: [PATCH v5 14/16] power: sequencing: pcie-m2: Split Bluetooth unit based on interface ---
commit 87ef77e2c86fea3f38f875c67c427d48fa406c76
Author: Chen-Yu Tsai <wenst@chromium.org>
power: sequencing: pcie-m2: Split Bluetooth unit based on interface
This commit splits the Bluetooth power sequencing unit into two distinct
units (UART and USB) to allow independent control. It aims to fix
initialization and recovery for serdev drivers by letting either interface
toggle the power.
> diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
> --- a/drivers/power/sequencing/pwrseq-pcie-m2.c
> +++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
> @@ -83,8 +83,22 @@ static int pwrseq_pci_m2_e_bt_disable(struct pwrseq_device *pwrseq)
[ ... ]
> -static const struct pwrseq_unit_data pwrseq_pcie_m2_e_bt_unit_data = {
> - .name = "bt-enable",
> +/*
> + * XXX There are two Bluetooth units to allow either one to be able to power
> + * off and thus reset the controller. In practice only one of the interfaces
> + * is used, so there is no conflict. However userspace could power off the
> + * USB unit by disabling the associated USB port, without the UART unit or
> + * its consumer ever knowing.
> + */
> +static const struct pwrseq_unit_data pwrseq_pcie_m2_e_bt_uart_unit_data = {
> + .name = "bt-uart-enable",
> + .deps = pwrseq_pcie_m2_unit_deps,
> + .enable = pwrseq_pci_m2_e_bt_enable,
> + .disable = pwrseq_pci_m2_e_bt_disable,
> +};
> +
> +static const struct pwrseq_unit_data pwrseq_pcie_m2_e_bt_usb_unit_data = {
> + .name = "bt-usb-enable",
[Severity: High]
Does splitting a single physical reset GPIO into two logical units bypass the
power sequencing core's refcounting?
The commit message notes there is no conflict in practice, but won't the USB
subsystem's runtime PM automatically turn off the Bluetooth controller while
the UART driver is actively using it?
Because a power sequencing target exists, the USB core removes the PM QoS
constraint for the port:
drivers/usb/core/port.c:usb_hub_create_port_device() {
...
/* Userspace owns the policy, drop the kernel 'no_poweroff' request. */
retval = dev_pm_qos_remove_request(port_dev->req);
...
}
If the USB port on the M.2 connector is physically empty (since Bluetooth is
using UART), runtime PM automatically suspends the empty port and powers it
off:
drivers/usb/core/port.c:usb_port_runtime_suspend() {
...
retval = usb_hub_set_port_power(hdev, hub, port1, false);
...
}
This calls into the power sequence disable callback for the USB target. Since
both logical units control the exact same physical w_disable2_gpio, won't
this disable action blindly assert the reset GPIO and yank the power state
from underneath the active UART driver without any user interaction?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260715085348.3457359-1-wenst@chromium.org?part=14
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v5 15/16] arm64: dts: mediatek: mt8195-cherry: Add M.2 E-key slot
2026-07-15 8:53 ` [PATCH v5 15/16] arm64: dts: mediatek: mt8195-cherry: Add M.2 E-key slot Chen-Yu Tsai
@ 2026-07-15 9:45 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-15 9:45 UTC (permalink / raw)
To: Chen-Yu Tsai; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Removing the `wifi@0` node drops the `wakeup-source` property, breaking default Wake-on-WLAN (WoWLAN) configuration.
--
--- Patch [15]: [PATCH v5 15/16] arm64: dts: mediatek: mt8195-cherry: Add M.2 E-key slot ---
commit a818c27444e50b0200c6065b8b79412ac5712494
Author: Chen-Yu Tsai <wenst@chromium.org>
arm64: dts: mediatek: mt8195-cherry: Add M.2 E-key slot
This patch adds an M.2 E-key slot for WiFi/BT combo cards on the
Mt8195 Cherry design. It replaces the PCIe wifi node and its vpcie3v3-supply
property with the new pcie-m2-e-connector representation.
> diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
> index ef7afc436aefc..8d4cc30d91e44 100644
> --- a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
> +++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
[ ... ]
> @@ -791,14 +832,14 @@ pcie@0 {
> reg = <0 0 0 0 0>;
> device_type = "pci";
> num-lanes = <1>;
> - vpcie3v3-supply = <&pp3300_wlan>;
> #address-cells = <3>;
> #size-cells = <2>;
> ranges;
>
> - wifi@0 {
> - reg = <0 0 0 0 0>;
> - wakeup-source;
> + port {
> + pcie1_ep: endpoint {
> + remote-endpoint = <&wifi_ep>;
> + };
> };
> };
> };
[Severity: Medium]
Does removing the wifi@0 node and its wakeup-source property break default
Wake-on-WLAN configuration?
The mt7921 PCIe Wi-Fi driver explicitly checks for this property during probe:
drivers/net/wireless/mediatek/mt76/mt7921/pci.c:
if (of_property_read_bool(dev->mt76.dev->of_node, "wakeup-source"))
device_init_wakeup(..., true);
By completely replacing the wifi@0 child node with an OF graph port under
the PCIe root port, the PCI endpoint device loses its of_node instantiation
and the driver cannot find the wakeup-source property.
Should the port node be placed inside the wifi@0 node so the PCI device
retains its Device Tree bindings?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260715085348.3457359-1-wenst@chromium.org?part=15
^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2026-07-15 9:45 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-15 8:53 [PATCH v5 00/16] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 01/16] device property: Add fwnode_graph_get_port_by_id() Chen-Yu Tsai
2026-07-15 9:03 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 02/16] device property: Add fwnode_graph_get_next_port_endpoint() Chen-Yu Tsai
2026-07-15 9:09 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 03/16] power: sequencing: Add pwrseq_power_is_on() Chen-Yu Tsai
2026-07-15 9:08 ` sashiko-bot
2026-07-15 9:29 ` Andy Shevchenko
2026-07-15 8:53 ` [PATCH v5 04/16] usb: hub: Use assign_bit() in usb_hub_set_port_power() Chen-Yu Tsai
2026-07-15 9:11 ` Andy Shevchenko
2026-07-15 8:53 ` [PATCH v5 05/16] usb: hub: Return actual error from hub_configure() in hub_probe() Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 06/16] usb: hub: Associate port@ fwnode with USB port device Chen-Yu Tsai
2026-07-15 9:20 ` Andy Shevchenko
2026-07-15 8:53 ` [PATCH v5 07/16] usb: core: Move struct usb_port and related APIs to port.h Chen-Yu Tsai
2026-07-15 9:31 ` Andy Shevchenko
2026-07-15 8:53 ` [PATCH v5 08/16] usb: hub: Pass |struct usb_port*| to usb_port_is_power_on() Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 09/16] usb: hub: Use usb_hub_set_port_power() to control port power everywhere Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 10/16] usb: hub: Power on connected M.2 E-key connectors with power sequencing API Chen-Yu Tsai
2026-07-15 9:28 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 11/16] dt-bindings: usb: mediatek,mtk-xhci: Switch to ports for USB connections Chen-Yu Tsai
2026-07-15 8:53 ` [PATCH v5 12/16] power: sequencing: pcie-m2: support matching on remote "port" node Chen-Yu Tsai
2026-07-15 9:29 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 13/16] power: sequencing: pcie-m2: Add usb and sdio targets for E-key connector Chen-Yu Tsai
2026-07-15 9:34 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 14/16] power: sequencing: pcie-m2: Split Bluetooth unit based on interface Chen-Yu Tsai
2026-07-15 9:34 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 15/16] arm64: dts: mediatek: mt8195-cherry: Add M.2 E-key slot Chen-Yu Tsai
2026-07-15 9:45 ` sashiko-bot
2026-07-15 8:53 ` [PATCH v5 16/16] arm64: dts: mediatek: mt8188-geralt: Add WiFi/BT as " Chen-Yu Tsai
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox