Skip to content

[Deepin-Kernel-SIG] [linux 6.6.y] Input: i8042 - skip a KBC that has no ports behind it - #2223

Merged
opsiff merged 3 commits into
deepin-community:linux-6.6.yfrom
opsiff:linux-6.6.y-2026-10-23-phytium
Oct 23, 2026
Merged

opsiff merged 3 commits into
deepin-community:linux-6.6.yfrom
opsiff:linux-6.6.y-2026-10-23-phytium

Conversation

@opsiff

@opsiff opsiff commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Summary by Sourcery

Prevent Phytium systems with portless KBCs from probing i8042 and modernize PIO interrupt delivery for legacy devices.

New Features:

  • Skip probing the Phytium i8042 controller when firmware or board data indicates that no legacy keyboard ports are present.
  • Expose individual Phytium PIO interrupt-latch bits as Linux IRQs for child devices.

Bug Fixes:

  • Prevent i8042 initialization from hanging on boards whose advertised KBC has no accessible ports.
  • Ensure PIO interrupt sources are acknowledged and dispatched independently without repeatedly looping on stuck latch bits.

Enhancements:

  • Migrate Phytium PIO consumers, including i8042, the embedded controller, and UARTs, to per-source chained IRQ handling.
  • Improve Phytium PIO window mapping and platform-specific latch register address selection.

Chores:

  • Remove legacy shared-parent interrupt bookkeeping and source-specific latch handling from child drivers.

The latch registers live in the SoC's LPC window, and that window does not
necessarily start where the firmware places resource 0, which only describes
the legacy port aperture.  Reading the latch at the firmware base misses the
register, so the source is never acknowledged and the level irq re-fires.

Use the SoC address for the window and keep the latch offsets absolute.  The
firmware base stays the anchor for phytium_pio_is_lpc_mem(), which matches
children against the window the firmware publishes.

Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
The controller reports all legacy sources in one status register and raises a
single interrupt.  The children used to share that irq and acknowledge their
own latch bit, which only works while everyone agrees on which bit is whose
and breaks whenever a bit is pending without an owner: the handler acks a
latch nobody will drain and the level irq re-fires forever.

Own the irq here instead.  The latch is acknowledged once and the status
register is demultiplexed through an irq domain, so every bit becomes a Linux
irq of its own; the children are back to plain request_irq()/free_irq() and
never touch the register again.  A source that stays asserted after the ack
shuts the line down instead of looping.

The bit masks and the EC helper left over from the polling ack have no users
since the shared-latch rework, so drop them too.

Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
A KBCI8042 node whose _CRS describes no I/O ports means nothing decodes
0x60/0x64, and the first access in i8042_probe() hangs the machine before
anything can be reported.

Keep probing as before by default and skip only on positive evidence: a board
on the list, or a non-laptop whose ACPI node documents the controller without
its ports.

Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
@sourcery-ai

sourcery-ai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

The PR replaces Phytium's shared PIO interrupt mechanism with a chained IRQ-domain implementation that independently dispatches and acknowledges latch sources, updates all affected consumers to use per-source IRQs, and avoids i8042 hangs by skipping firmware-described KBCs that have no backing ports.

Sequence diagram for Phytium latch interrupt dispatch

sequenceDiagram
    participant Source as Interrupt source
    participant PIO as Phytium PIO
    participant Domain as IRQ domain
    participant Handler as Per-source handler

    Source->>PIO: Assert latch bit
    PIO->>PIO: phytium_pio_irq_dispatch
    PIO->>PIO: Read int_status_reg
    PIO->>PIO: Write ~pending to int_clear_reg
    PIO->>Domain: generic_handle_domain_irq(bit)
    Domain->>Handler: Dispatch mapped Linux IRQ
    PIO->>PIO: Read latch again
    alt Source remains asserted repeatedly
        PIO->>PIO: disable_irq_nosync
    end
Loading

File-Level Changes

Change Details Files
Rework Phytium PIO interrupt handling into a hierarchical per-latch-bit IRQ controller.
  • Create a linear IRQ domain with one child IRQ per latch bit.
  • Replace child-managed latch acknowledgement with chained-parent dispatch that clears pending bits before invoking child handlers.
  • Add stuck-latch detection and disable the parent IRQ after repeated failed acknowledgements.
  • Map the long latch window using SoC-specific bases and retain the firmware window separately.
  • Migrate i8042, EC, and UART consumers to per-source IRQs and remove legacy shared-parent bookkeeping and exported latch helpers.
drivers/bus/phytium_pio.c
drivers/bus/phytium_pio.h
drivers/platform/arm64/phytium/ec_it8528.c
drivers/platform/arm64/phytium/ec_it8528.h
drivers/platform/arm64/phytium/phyt_laptop.c
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_pnp.c
Prevent i8042 probing on systems where firmware exposes a KBC device without usable legacy ports.
  • Add a DMI blacklist for a board whose KBC reads do not complete.
  • Inspect ACPI KBCI8042 resources for ports covering 0x60–0x64 and skip probing on non-laptops when absent.
  • Keep probing on laptops to support internal keyboards.
  • Assign separate PIO-domain keyboard and auxiliary IRQs before normal i8042 setup.
drivers/input/serio/i8042-phytio.h
drivers/input/serio/i8042.c

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@opsiff
opsiff merged commit 3b1b204 into deepin-community:linux-6.6.y Oct 23, 2026
13 checks passed
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please ask for approval from opsiff. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 9 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="drivers/bus/phytium_pio.c" line_range="85-91" />
<code_context>
+	 * A source that is still asserted after its latch was cleared cannot
+	 * be acknowledged; shut the line down instead of looping forever.
+	 */
+	if (again & pending && ++pio->stuck_acks > PHYTIUM_PIO_STUCK_LIMIT) {
+		pr_err("phytium-pio: latch bit 0x%x stuck, disabling irq %d\n",
+		       again & pending, pio->irq);
+		disable_irq_nosync(pio->irq);
+	} else if (!(again & pending)) {
+		pio->stuck_acks = 0;
+	}
+out:
+	chained_irq_exit(chip, desc);
</code_context>
<issue_to_address>
**Normal interrupts eventually disable PIO**

When a latch bit remains asserted until its child IRQ handler services it, `again` is read before `generic_handle_domain_irq()` lets the child clear its source, so a normally serviced level-triggered interrupt increments `stuck_acks`. Since the counter resets only when that pre-dispatch read has no matching bits, ordinary interrupts accumulate until the parent IRQ is disabled, stopping all PIO children.

Check whether the source remains asserted after child dispatch, and reset the stuck counter when the child has cleared it.
</issue_to_address>

### Comment 2
<location path="drivers/input/serio/i8042-phytio.h" line_range="90-91" />
<code_context>
+{
+	bool *found = data;
+
+	if (ares->type == ACPI_RESOURCE_TYPE_IO &&
+	    ares->data.io.minimum <= 0x60 && ares->data.io.maximum >= 0x64)
+		*found = true;
+
</code_context>
<issue_to_address>
**Working KBC ports go undetected**

When the KBC `_CRS` describes its ports in separate resources, uses `FIXED_IO`, or uses an I/O descriptor whose range is described by `address_length`, `phytium_i8042_io_cb()` only recognizes one `ACPI_RESOURCE_TYPE_IO` descriptor whose minimum and maximum span both ports, so `phytium_i8042_acpi_has_ports()` returns false and `i8042_platform_init()` skips the working controller, leaving keyboard or touchpad input unavailable.

Recognize the covered ports across the supported I/O and fixed-I/O resource descriptors, using their actual lengths.

Also at `drivers/input/serio/i8042-phytio.h:108`.
</issue_to_address>

### Comment 3
<location path="drivers/bus/phytium_pio.c" line_range="75-78" />
<code_context>
-	unsigned long flags;
+	/* The latch is write-zero-to-clear. */
+	writel(~pending, pio->regbase + pio->int_clear_reg);
+	again = readl(pio->regbase + pio->int_status_reg);

-	if (!ppio || bit >= 32)
-		return;
+	bits = pending;
+	for_each_set_bit(bit, &bits, PHYTIUM_PIO_IRQ_NR)
+		generic_handle_domain_irq(pio->domain, bit);

</code_context>
<issue_to_address>
**Stuck parent interrupt keeps firing**

When a latch bit remains asserted after the stuck-ack limit is exceeded, `disable_irq_nosync()` masks the parent, but `chained_irq_exit()` unconditionally unmasks it, so the stuck interrupt storm continues.

Handle a stuck source with a mechanism that remains effective after `chained_irq_exit()` unmasks the parent.

Also at `drivers/bus/phytium_pio.c:88-93`.
</issue_to_address>

### Comment 4
<location path="drivers/bus/phytium_pio.c" line_range="85-89" />
<code_context>
+	 * A source that is still asserted after its latch was cleared cannot
+	 * be acknowledged; shut the line down instead of looping forever.
+	 */
+	if (again & pending && ++pio->stuck_acks > PHYTIUM_PIO_STUCK_LIMIT) {
+		pr_err("phytium-pio: latch bit 0x%x stuck, disabling irq %d\n",
+		       again & pending, pio->irq);
+		disable_irq_nosync(pio->irq);
+	} else if (!(again & pending)) {
+		pio->stuck_acks = 0;
+	}
</code_context>
<issue_to_address>
**One stuck source silences every device**

When any latch source remains asserted for more than `PHYTIUM_PIO_STUCK_LIMIT` acknowledgements, the handler disables `pio->irq` after a latch remains asserted, but that is the single chained parent for all latch bits; one stuck source therefore stops delivery to unrelated keyboard, UART, and EC sources too.

Quarantine the stuck source without permanently disabling delivery for the other latch bits, or provide a recovery path that reenables the parent IRQ.

Also at `drivers/bus/phytium_pio.c:339`.
</issue_to_address>

### Comment 5
<location path="drivers/tty/serial/8250/8250_pnp.c" line_range="476-478" />
<code_context>
+		if (irq >= 0) {
+			uart.port.irq = irq;
+			uart.port.flags |= UPF_SHARE_IRQ;
+		} else if (pnp_irq_valid(dev, 0)) {
+			uart.port.irq = pnp_irq(dev, 0);
+		}
 	}
 #else
</code_context>
<issue_to_address>
**UART falls back to chained parent IRQ**

When a PNP0501 UART qualifies as a PIO UART, `phytium_pio_irq_get()` fails while the firmware IRQ is the PIO parent, and the PIO driver later claims that parent, `phytium_pnp_uart_irq()` can fail to obtain the PIO child IRQ, but `serial_pnp_probe()` then assigns the firmware IRQ directly. If that IRQ is the PIO parent and the PIO driver later installs its chained handler, the UART's direct handler is bypassed and the UART stops receiving interrupts.

Do not use the firmware parent IRQ as a fallback for a UART identified as PIO-backed; defer probing or propagate the PIO IRQ lookup failure instead.
</issue_to_address>

### Comment 6
<location path="drivers/bus/phytium_pio.c" line_range="360-368" />
<code_context>
+	if (pio && pio->domain) {
+		int bit;
+
+		irq_set_chained_handler_and_data(pio->irq, NULL, NULL);
+		for (bit = 0; bit < PHYTIUM_PIO_IRQ_NR; bit++) {
+			unsigned int virq = irq_find_mapping(pio->domain, bit);
+
+			if (virq)
+				irq_dispose_mapping(virq);
+		}
+		irq_domain_remove(pio->domain);
+		pio->domain = NULL;
+	}
+
</code_context>
<issue_to_address>
**PIO removal leaves child IRQ users active**

When the PIO ACPI device is removed while a child still has a requested IRQ, or while another child is obtaining one, `phytium_pio_remove()` detaches the parent handler and disposes the domain mappings without first stopping consumers that requested those IRQs. An active i8042, EC, or UART can therefore retain a registered action for a removed mapping, while a concurrent `phytium_pio_irq_get()` can use the domain as it is being removed; child interrupts or teardown then fail.

Ensure consumers are quiesced before removing the domain, and synchronize IRQ lookup with PIO teardown.

Also at `drivers/bus/phytium_pio.c:122-124`.
</issue_to_address>

### Comment 7
<location path="drivers/bus/phytium_pio.c" line_range="360-367" />
<code_context>
+	if (pio && pio->domain) {
+		int bit;
+
+		irq_set_chained_handler_and_data(pio->irq, NULL, NULL);
+		for (bit = 0; bit < PHYTIUM_PIO_IRQ_NR; bit++) {
+			unsigned int virq = irq_find_mapping(pio->domain, bit);
+
+			if (virq)
+				irq_dispose_mapping(virq);
+		}
+		irq_domain_remove(pio->domain);
+		pio->domain = NULL;
+	}
</code_context>
<issue_to_address>
**Removal races active latch dispatch**

When the PIO device is removed while its parent interrupt is being dispatched, `phytium_pio_remove()` clears the chained handler and immediately disposes its mappings and domain without synchronizing the parent IRQ. An already-running `phytium_pio_irq_dispatch()` can still use `pio` and `pio->domain` as teardown proceeds, causing access to released state during removal.

Disable the parent IRQ and synchronize it after detaching the chained handler, before disposing mappings or releasing the PIO state.
</issue_to_address>

### Comment 8
<location path="drivers/bus/phytium_pio.c" line_range="51-56" />
<code_context>
-EXPORT_SYMBOL(phytium_pio_clear_interrupt);

-void phytium_pio_handle_interrupt_bit(unsigned int bit)
+static struct irq_chip phytium_pio_irq_chip = {
+	.name		= PHYT_PIO_DRIVER_NAME,
+	.irq_mask	= phytium_pio_irq_noop,
+	.irq_unmask	= phytium_pio_irq_noop,
+	.irq_ack	= phytium_pio_irq_noop,
+};
+
+/* One Linux irq per latch bit, acknowledged once before the dispatch. */
</code_context>
<issue_to_address>
**Keyboard IRQs cannot wake the system**

When a Phytium i8042 port is configured as a wake source for suspend, the virtual IRQ chip has no `.irq_set_wake` callback, so `enable_irq_wake()` on the new per-source i8042 IRQs fails instead of configuring wake on the PIO parent. Phytium keyboard or touchpad input therefore cannot wake the system from suspend.

Add wake handling for the child IRQs that propagates wake configuration to the PIO parent IRQ.
</issue_to_address>

### Comment 9
<location path="drivers/bus/phytium_pio.c" line_range="292-298" />
<code_context>

-	pio->regbase = devm_ioremap(dev, reg_start, reg_size);
+	/* The latch window is a SoC property, not what resource 0 describes. */
+	if (cpu_is_ft_d2000()) {
+		reg_start = PHYTIUM_PIO_D2000_BASE;
+	} else if (is_pd2408()) {
+		reg_start = PHYTIUM_PIO_D3000M_BASE;
+	} else {
+		reg_start = res->start;
+		if (resource_size(res) < PHYTIUM_PIO_LENGTH_LONG)
+			dev_warn(dev, "short window on an unknown SoC, the latch address may be wrong\n");
+	}
</code_context>
<issue_to_address>
**D3000 latch reads use firmware base**

When a D3000 is not identified by either special-case predicate and its firmware resource 0 is shorter than the LPC window, on a D3000 that is neither classified as FT D2000 nor PD2408, `phytium_pio_probe()` selects `res->start` even when resource 0 is shorter than the LPC window. The latch is then accessed at the wrong physical address, so PIO child interrupts are not acknowledged or dispatched.

Select the 0x20000000 latch base for D3000 systems as well as D2000 systems, using a reliable SoC predicate.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread drivers/bus/phytium_pio.c
Comment on lines +85 to +91
if (again & pending && ++pio->stuck_acks > PHYTIUM_PIO_STUCK_LIMIT) {
pr_err("phytium-pio: latch bit 0x%x stuck, disabling irq %d\n",
again & pending, pio->irq);
disable_irq_nosync(pio->irq);
} else if (!(again & pending)) {
pio->stuck_acks = 0;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High · Normal interrupts eventually disable PIO

When a latch bit remains asserted until its child IRQ handler services it, again is read before generic_handle_domain_irq() lets the child clear its source, so a normally serviced level-triggered interrupt increments stuck_acks. Since the counter resets only when that pre-dispatch read has no matching bits, ordinary interrupts accumulate until the parent IRQ is disabled, stopping all PIO children.

Check whether the source remains asserted after child dispatch, and reset the stuck counter when the child has cleared it.

Prompt for AI agents
In `drivers/bus/phytium_pio.c` at lines 85-91:

**Normal interrupts eventually disable PIO**

When a latch bit remains asserted until its child IRQ handler services it, `again` is read before `generic_handle_domain_irq()` lets the child clear its source, so a normally serviced level-triggered interrupt increments `stuck_acks`. Since the counter resets only when that pre-dispatch read has no matching bits, ordinary interrupts accumulate until the parent IRQ is disabled, stopping all PIO children.

Check whether the source remains asserted after child dispatch, and reset the stuck counter when the child has cleared it.

Comment on lines +90 to +91
if (ares->type == ACPI_RESOURCE_TYPE_IO &&
ares->data.io.minimum <= 0x60 && ares->data.io.maximum >= 0x64)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High · Working KBC ports go undetected

When the KBC _CRS describes its ports in separate resources, uses FIXED_IO, or uses an I/O descriptor whose range is described by address_length, phytium_i8042_io_cb() only recognizes one ACPI_RESOURCE_TYPE_IO descriptor whose minimum and maximum span both ports, so phytium_i8042_acpi_has_ports() returns false and i8042_platform_init() skips the working controller, leaving keyboard or touchpad input unavailable.

Recognize the covered ports across the supported I/O and fixed-I/O resource descriptors, using their actual lengths.

Also at drivers/input/serio/i8042-phytio.h:108.

Prompt for AI agents
In `drivers/input/serio/i8042-phytio.h` at lines 90-91:

**Working KBC ports go undetected**

When the KBC `_CRS` describes its ports in separate resources, uses `FIXED_IO`, or uses an I/O descriptor whose range is described by `address_length`, `phytium_i8042_io_cb()` only recognizes one `ACPI_RESOURCE_TYPE_IO` descriptor whose minimum and maximum span both ports, so `phytium_i8042_acpi_has_ports()` returns false and `i8042_platform_init()` skips the working controller, leaving keyboard or touchpad input unavailable.

Recognize the covered ports across the supported I/O and fixed-I/O resource descriptors, using their actual lengths.

Also at `drivers/input/serio/i8042-phytio.h:108`.

Comment thread drivers/bus/phytium_pio.c
Comment on lines +75 to +78
again = readl(pio->regbase + pio->int_status_reg);

if (!ppio || bit >= 32)
return;
bits = pending;
for_each_set_bit(bit, &bits, PHYTIUM_PIO_IRQ_NR)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High · Stuck parent interrupt keeps firing

When a latch bit remains asserted after the stuck-ack limit is exceeded, disable_irq_nosync() masks the parent, but chained_irq_exit() unconditionally unmasks it, so the stuck interrupt storm continues.

Handle a stuck source with a mechanism that remains effective after chained_irq_exit() unmasks the parent.

Also at drivers/bus/phytium_pio.c:88-93.

Prompt for AI agents
In `drivers/bus/phytium_pio.c` at lines 75-78:

**Stuck parent interrupt keeps firing**

When a latch bit remains asserted after the stuck-ack limit is exceeded, `disable_irq_nosync()` masks the parent, but `chained_irq_exit()` unconditionally unmasks it, so the stuck interrupt storm continues.

Handle a stuck source with a mechanism that remains effective after `chained_irq_exit()` unmasks the parent.

Also at `drivers/bus/phytium_pio.c:88-93`.

Comment thread drivers/bus/phytium_pio.c
Comment on lines +85 to +89
if (again & pending && ++pio->stuck_acks > PHYTIUM_PIO_STUCK_LIMIT) {
pr_err("phytium-pio: latch bit 0x%x stuck, disabling irq %d\n",
again & pending, pio->irq);
disable_irq_nosync(pio->irq);
} else if (!(again & pending)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · One stuck source silences every device

When any latch source remains asserted for more than PHYTIUM_PIO_STUCK_LIMIT acknowledgements, the handler disables pio->irq after a latch remains asserted, but that is the single chained parent for all latch bits; one stuck source therefore stops delivery to unrelated keyboard, UART, and EC sources too.

Quarantine the stuck source without permanently disabling delivery for the other latch bits, or provide a recovery path that reenables the parent IRQ.

Also at drivers/bus/phytium_pio.c:339.

Prompt for AI agents
In `drivers/bus/phytium_pio.c` at lines 85-89:

**One stuck source silences every device**

When any latch source remains asserted for more than `PHYTIUM_PIO_STUCK_LIMIT` acknowledgements, the handler disables `pio->irq` after a latch remains asserted, but that is the single chained parent for all latch bits; one stuck source therefore stops delivery to unrelated keyboard, UART, and EC sources too.

Quarantine the stuck source without permanently disabling delivery for the other latch bits, or provide a recovery path that reenables the parent IRQ.

Also at `drivers/bus/phytium_pio.c:339`.

Comment on lines +476 to +478
} else if (pnp_irq_valid(dev, 0)) {
uart.port.irq = pnp_irq(dev, 0);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High · UART falls back to chained parent IRQ

When a PNP0501 UART qualifies as a PIO UART, phytium_pio_irq_get() fails while the firmware IRQ is the PIO parent, and the PIO driver later claims that parent, phytium_pnp_uart_irq() can fail to obtain the PIO child IRQ, but serial_pnp_probe() then assigns the firmware IRQ directly. If that IRQ is the PIO parent and the PIO driver later installs its chained handler, the UART's direct handler is bypassed and the UART stops receiving interrupts.

Do not use the firmware parent IRQ as a fallback for a UART identified as PIO-backed; defer probing or propagate the PIO IRQ lookup failure instead.

Prompt for AI agents
In `drivers/tty/serial/8250/8250_pnp.c` at lines 476-478:

**UART falls back to chained parent IRQ**

When a PNP0501 UART qualifies as a PIO UART, `phytium_pio_irq_get()` fails while the firmware IRQ is the PIO parent, and the PIO driver later claims that parent, `phytium_pnp_uart_irq()` can fail to obtain the PIO child IRQ, but `serial_pnp_probe()` then assigns the firmware IRQ directly. If that IRQ is the PIO parent and the PIO driver later installs its chained handler, the UART's direct handler is bypassed and the UART stops receiving interrupts.

Do not use the firmware parent IRQ as a fallback for a UART identified as PIO-backed; defer probing or propagate the PIO IRQ lookup failure instead.

Comment thread drivers/bus/phytium_pio.c
Comment on lines +360 to +368
irq_set_chained_handler_and_data(pio->irq, NULL, NULL);
for (bit = 0; bit < PHYTIUM_PIO_IRQ_NR; bit++) {
unsigned int virq = irq_find_mapping(pio->domain, bit);

if (virq)
irq_dispose_mapping(virq);
}
irq_domain_remove(pio->domain);
pio->domain = NULL;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · PIO removal leaves child IRQ users active

When the PIO ACPI device is removed while a child still has a requested IRQ, or while another child is obtaining one, phytium_pio_remove() detaches the parent handler and disposes the domain mappings without first stopping consumers that requested those IRQs. An active i8042, EC, or UART can therefore retain a registered action for a removed mapping, while a concurrent phytium_pio_irq_get() can use the domain as it is being removed; child interrupts or teardown then fail.

Ensure consumers are quiesced before removing the domain, and synchronize IRQ lookup with PIO teardown.

Also at drivers/bus/phytium_pio.c:122-124.

Prompt for AI agents
In `drivers/bus/phytium_pio.c` at lines 360-368:

**PIO removal leaves child IRQ users active**

When the PIO ACPI device is removed while a child still has a requested IRQ, or while another child is obtaining one, `phytium_pio_remove()` detaches the parent handler and disposes the domain mappings without first stopping consumers that requested those IRQs. An active i8042, EC, or UART can therefore retain a registered action for a removed mapping, while a concurrent `phytium_pio_irq_get()` can use the domain as it is being removed; child interrupts or teardown then fail.

Ensure consumers are quiesced before removing the domain, and synchronize IRQ lookup with PIO teardown.

Also at `drivers/bus/phytium_pio.c:122-124`.

Comment thread drivers/bus/phytium_pio.c
Comment on lines +360 to +367
irq_set_chained_handler_and_data(pio->irq, NULL, NULL);
for (bit = 0; bit < PHYTIUM_PIO_IRQ_NR; bit++) {
unsigned int virq = irq_find_mapping(pio->domain, bit);

if (virq)
irq_dispose_mapping(virq);
}
irq_domain_remove(pio->domain);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Removal races active latch dispatch

When the PIO device is removed while its parent interrupt is being dispatched, phytium_pio_remove() clears the chained handler and immediately disposes its mappings and domain without synchronizing the parent IRQ. An already-running phytium_pio_irq_dispatch() can still use pio and pio->domain as teardown proceeds, causing access to released state during removal.

Disable the parent IRQ and synchronize it after detaching the chained handler, before disposing mappings or releasing the PIO state.

Prompt for AI agents
In `drivers/bus/phytium_pio.c` at lines 360-367:

**Removal races active latch dispatch**

When the PIO device is removed while its parent interrupt is being dispatched, `phytium_pio_remove()` clears the chained handler and immediately disposes its mappings and domain without synchronizing the parent IRQ. An already-running `phytium_pio_irq_dispatch()` can still use `pio` and `pio->domain` as teardown proceeds, causing access to released state during removal.

Disable the parent IRQ and synchronize it after detaching the chained handler, before disposing mappings or releasing the PIO state.

Comment thread drivers/bus/phytium_pio.c
Comment on lines +51 to +56
static struct irq_chip phytium_pio_irq_chip = {
.name = PHYT_PIO_DRIVER_NAME,
.irq_mask = phytium_pio_irq_noop,
.irq_unmask = phytium_pio_irq_noop,
.irq_ack = phytium_pio_irq_noop,
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High · Keyboard IRQs cannot wake the system

When a Phytium i8042 port is configured as a wake source for suspend, the virtual IRQ chip has no .irq_set_wake callback, so enable_irq_wake() on the new per-source i8042 IRQs fails instead of configuring wake on the PIO parent. Phytium keyboard or touchpad input therefore cannot wake the system from suspend.

Add wake handling for the child IRQs that propagates wake configuration to the PIO parent IRQ.

Prompt for AI agents
In `drivers/bus/phytium_pio.c` at lines 51-56:

**Keyboard IRQs cannot wake the system**

When a Phytium i8042 port is configured as a wake source for suspend, the virtual IRQ chip has no `.irq_set_wake` callback, so `enable_irq_wake()` on the new per-source i8042 IRQs fails instead of configuring wake on the PIO parent. Phytium keyboard or touchpad input therefore cannot wake the system from suspend.

Add wake handling for the child IRQs that propagates wake configuration to the PIO parent IRQ.

Comment thread drivers/bus/phytium_pio.c
Comment on lines +292 to +298
if (cpu_is_ft_d2000()) {
reg_start = PHYTIUM_PIO_D2000_BASE;
} else if (is_pd2408()) {
reg_start = PHYTIUM_PIO_D3000M_BASE;
} else {
reg_start = res->start;
if (resource_size(res) < PHYTIUM_PIO_LENGTH_LONG)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High · D3000 latch reads use firmware base

When a D3000 is not identified by either special-case predicate and its firmware resource 0 is shorter than the LPC window, on a D3000 that is neither classified as FT D2000 nor PD2408, phytium_pio_probe() selects res->start even when resource 0 is shorter than the LPC window. The latch is then accessed at the wrong physical address, so PIO child interrupts are not acknowledged or dispatched.

Select the 0x20000000 latch base for D3000 systems as well as D2000 systems, using a reliable SoC predicate.

Prompt for AI agents
In `drivers/bus/phytium_pio.c` at lines 292-298:

**D3000 latch reads use firmware base**

When a D3000 is not identified by either special-case predicate and its firmware resource 0 is shorter than the LPC window, on a D3000 that is neither classified as FT D2000 nor PD2408, `phytium_pio_probe()` selects `res->start` even when resource 0 is shorter than the LPC window. The latch is then accessed at the wrong physical address, so PIO child interrupts are not acknowledged or dispatched.

Select the 0x20000000 latch base for D3000 systems as well as D2000 systems, using a reliable SoC predicate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants