Brijesh-Thakkar opened a new pull request, #20919:
URL: https://github.com/apache/nuttx/pull/20919

   **Title:** drivers/serial/uart_pci_16550: Fix probing of multi-port cards
   
   *Refs #20870 (together with the defconfig PR for `citest_smp`/`jumbo`, which 
fixes the other cause listed in the issue).*
   
   ## Summary
   
   `pci_u16550_probe()` walks the ports of a PCI 16550 card.  Two bugs in that
   loop, both described in #20870:
   
   1. **The probe aborts at the first unconfigured port.**  When no `UARTn`
      instance is configured for the current port it did `return -ENODEV`, so a
      configuration that only uses a later port of a multi-port card (e.g. only
      `UART1` = port 1 of a QEMU `pci-serial-2x`) never reached it.  It now
      `continue`s with the next port, and returns `-ENODEV` only if no port of
      the device was registered, so a card none of whose ports is configured is
      still rejected as before.
   2. **The port address accumulates.**  `base += type->portincr * port` 
modifies
      the BAR base on every iteration, so with `portincr = 8` ports 2 and 3 got
      offsets 24 and 48 instead of 16 and 24.  Port 2 therefore talked to
      port 3's registers and port 3 to an unmapped range.  Each port address is
      now `BAR base + portincr * port`.  The issue only mentioned this one from
      reading the code; it is now tested (below), and it matters in practice
      because fix 1 makes ports 2 and 3 reachable on their own.
   
   Two commits, one per fix:
   
   ```
   drivers/serial/uart_pci_16550: Don't abort probe at the first unconfigured 
port
   drivers/serial/uart_pci_16550: Compute port address from the BAR base
   ```
   
   The other cause in the issue (the defconfigs select the single-port card but
   leave `CONFIG_16550_PCI_UART1_PORT` at 1) is a separate PR touching only the
   two defconfigs.  The two PRs are independent.
   
   ## Impact
   
   - **Users / boards:** only PCI 16550 users (`CONFIG_16550_PCI_UART`).  A
     configuration whose port 0 is configured behaves exactly as before; the
     difference is for configurations where an earlier port is *not* configured,
     and for cards with `portincr != 0` (QEMU `pci-serial-2x`/`4x`) from the
     third port on.  AX99100 (`portincr = 0`, one port per PCI function) is not
     affected by the address change.
   - **Build / docs / compatibility:** none; no Kconfig, no API change.
   - Does not conflict with #20842 (`feat/16550-stage1-hooks`): `git merge-tree`
     is clean, the merge builds, and the 4x test below passes on the merge too.
   
   ## Testing
   
   **Host:** Ubuntu 26.04, Linux 7.0.0-38, x86_64, GCC 15.2.0, QEMU 10.2.1 + 
KVM.
   Builds in a throwaway clone: nuttx `b01e7e760c` (master) + these commits, 
apps
   `e0174bf71`.  `tools/checkpatch.sh -m -g upstream/master..HEAD`: all checks
   pass.
   
   **Method.** Base config `qemu-intel64:citest_smp` plus `CONFIG_IRQCHAIN=y`
   (see "Found while testing") and the UART options in the table.  QEMU:
   `-cpu host -enable-kvm -m 2G -smp 4 -kernel nuttx -nographic -serial
   mon:stdio -device <card>`, every card port backed by a unix-socket chardev.
   For each UART: `ls /dev` at the NSH prompt; TX = `echo MARK > /dev/ttySn` and
   the marker must arrive on the expected host chardev and on no other; RX = a
   host script sends `MARK` byte by byte to the chardev and `cat /dev/ttySn`
   must print it.  For the address check, a temporary `syslog()` of the port
   address before `pci_u16550_initialize()` (not part of the commits); the BAR 0
   base was 0xc040 (4x) and 0xc050 (2x).
   
   | Card | UARTs configured | Driver | `/dev/ttyS*` | Result |
   |---|---|---|---|---|
   | `pci-serial-2x` | UART1 = `0003` port 1 | master | none | not registered |
   | | | commit 1 | `ttyS1` | TX **PASS**, RX **PASS** (chardev 2), addr = 
BAR+8 |
   | | | both commits | `ttyS1` | TX **PASS**, RX **PASS** (chardev 2), addr = 
BAR+8 |
   | `pci-serial-4x` | UART1 = `0004` port 2, UART2 = `0004` port 3 | master | 
none | not registered |
   | | | commit 1 only | `ttyS1`, `ttyS2` | `ttyS1`: TX **FAIL** (output 
appears on chardev **4**), RX FAIL; `ttyS2`: TX/RX FAIL; addrs BAR+24, BAR+48 |
   | | | both commits | `ttyS1`, `ttyS2` | `ttyS1`: TX **PASS** RX **PASS** 
(chardev 3); `ttyS2`: TX **PASS** RX **PASS** (chardev 4); no cross-talk; addrs 
BAR+16, BAR+24 |
   | `pci-serial-4x` | UART1 = `0003` (card is `0004`) | both commits | none, 
no crash | `-ENODEV` kept |
   | `pci-serial` (1x) | UART1 = `0002` port 0 | master / both commits | 
`ttyS1` | identical: TX/RX PASS, addr BAR+0 |
   | `pci-serial-4x` | UART1 = `0004` port 0 | master / both commits | `ttyS1` 
| identical: TX/RX PASS, addr BAR+0 |
   
   The "commit 1 only" rows show that the second commit is needed: fix 1 alone
   registers ports 2/3 at the wrong addresses.
   
   **Build only:** with this branch, `qemu-intel64:nxterm`, `nsh_pci`,
   `nsh_pci_smp`, `knsh_romfs_pci` build with no new warnings (`nxterm` has the
   same 8 warnings on master).  `nsh_pci*` target an AX99100 (`125b:9100`) which
   QEMU does not provide, so they cannot be booted there.  `nxterm` (PCI 
console,
   wildcard ids) I could not boot: the kernel resets early, on unmodified master
   too, with both `-kernel` and a GRUB ISO, so I have no runtime signal from it.
   Merging with #20842's branch builds `citest_smp` and passes the 4x test.
   
   **Found while testing (not changed here).**  Opening `/dev/ttyS1` on a PCI
   legacy-IRQ card asserts in `up_enable_irq()` (`g_irq_priv[irq].busy`) when
   `CONFIG_IRQCHAIN` is not set, which is the case in `citest_smp`.  It happens
   with the single-port card and the unmodified driver, so it is independent of
   this PR, and all my runtime tests above set `CONFIG_IRQCHAIN=y`.  
Registration
   (what #20870 is about) and `ls /dev` work without it.  I can open a separate
   issue for it if wanted.
   
   **Not tested:** AX99100 or any real hardware; MMIO BARs (QEMU's cards use an
   I/O BAR); `citest_smp` in CI (it has no PCI serial device).
   
   ## AI assistance
   
   This change was developed with Claude Code (`claude-sonnet-5-5`).  Both
   commits carry an `Assisted-by:` field as required by CONTRIBUTING.md.  I
   reviewed the diff and certify the DCO with my `Signed-off-by`.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to