From: gwes@oat.com Subject: NetMos NMC9912 PCI I/O To: gwes@oat.com, tech@openbsd.org Date: Tue, 24 Jun 2025 18:13:40 -0400 The NetMos NMC9901 chip appears in some common, cheap PCI I/O boards. It is configured from an EPROM to be various combinations of peripherals. This patch is for the 9912 variant emulating 2 st16c650 ports and one apparently standard parallel port. It has one unfortunate bug: after power up and hard reset the RXRDY bit is on and will not clear when the FIFO is cleared. That caused the system to spin forever in the "clear the FIFO" code in open(2). The bit -does- clear eventually and the chip works. A long justification for the code changes to com.c. They terminate the attempts to drain the input section during open(2). The first loop enabling & disabling the FIFO has a comment about a possible race condition in which a character could arrive between the clear and enabling the FIFO. This loop is a workaround for some SMC chips. The original 2*100us delay is long enough for a character incoming at 115200 to arrive so I changed it to 10us. This isn't perfect but I really don't like infinite spins on hardware that's not critical. The second change terminates the next loop if the CPU can't drain the chip in a hard loop. A slow CPU and a 1Mbaud stream is unlikely but possible. A stuck RXRDY is very unlikely but possible if a surge on the comm port gets through the 1489. The patched version works on the 3 serial port variants I have. I don't -think- this will break any other of the 1001 8251/16450 clones. geoff steckel Index: sys/dev/ic/com.c =================================================================== RCS file: /cvs/src/sys/dev/ic/com.c,v retrieving revision 1.179 diff -u -p -u -r1.179 com.c --- sys/dev/ic/com.c 13 May 2024 01:15:50 -0000 1.179 +++ sys/dev/ic/com.c 24 Jun 2025 21:23:18 -0000 @@ -314,6 +314,7 @@ comopen(dev_t dev, int flag, int mode, s u_int8_t fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST; u_int8_t lcr; + /* Set the FIFO threshold based on the receive speed.*/ if (tp->t_ispeed <= 1200) fifo |= FIFO_TRIGGER_1; else if (tp->t_ispeed <= 38400) @@ -335,16 +336,17 @@ comopen(dev_t dev, int flag, int mode, s * if necessary to clear the input. Test the input * ready bit after enabling the FIFOs to handle races * between enabling and fresh input. + * Some NetMos chips after reset disabling/resetting + * FIFOs doesn't clear RXRDY so don't spin forever * - * Set the FIFO threshold based on the receive speed. */ - for (;;) { + for (int i = 0; i < 1000; i++) { com_write_reg(sc, com_fifo, 0); - delay(100); + delay(10); (void) com_read_reg(sc, com_data); com_write_reg(sc, com_fifo, fifo | FIFO_RCV_RST | FIFO_XMT_RST); - delay(100); + delay(10); if(!ISSET(com_read_reg(sc, com_lsr), LSR_RXRDY)) break; @@ -354,8 +356,13 @@ comopen(dev_t dev, int flag, int mode, s } /* Flush any pending I/O. */ - while (ISSET(com_read_reg(sc, com_lsr), LSR_RXRDY)) + for (int i = 0; i < 1000; i++) { + if ( ! (ISSET(com_read_reg(sc, com_lsr), LSR_RXRDY))) + goto ok; (void) com_read_reg(sc, com_data); + } + return EIO; /* hw is broken or overwhelming input flood */ + ok:; /* You turn me on, baby! */ sc->sc_mcr = MCR_DTR | MCR_RTS; Index: sys/dev/pci/pcidevs =================================================================== RCS file: /cvs/src/sys/dev/pci/pcidevs,v retrieving revision 1.2099 diff -u -p -u -r1.2099 pcidevs --- sys/dev/pci/pcidevs 7 Mar 2025 15:06:58 -0000 1.2099 +++ sys/dev/pci/pcidevs 24 Jun 2025 21:23:18 -0000 @@ -7820,6 +7820,7 @@ product NETMOS NM9845 0x9845 Nm9845 product NETMOS NM9865 0x9865 Nm9865 product NETMOS NM9901 0x9901 Nm9901 product NETMOS NM9922 0x9922 Nm9922 +product NETMOS NM9912 0x9912 Nm9912 /* Netoctave */ product NETOCTAVE NSP2K 0x0100 NSP2K Index: sys/dev/pci/pcidevs.h =================================================================== RCS file: /cvs/src/sys/dev/pci/pcidevs.h,v retrieving revision 1.2093 diff -u -p -u -r1.2093 pcidevs.h --- sys/dev/pci/pcidevs.h 7 Mar 2025 15:07:12 -0000 1.2093 +++ sys/dev/pci/pcidevs.h 24 Jun 2025 21:23:19 -0000 @@ -7825,6 +7825,7 @@ #define PCI_PRODUCT_NETMOS_NM9865 0x9865 /* Nm9865 */ #define PCI_PRODUCT_NETMOS_NM9901 0x9901 /* Nm9901 */ #define PCI_PRODUCT_NETMOS_NM9922 0x9922 /* Nm9922 */ +#define PCI_PRODUCT_NETMOS_NM9912 0x9912 /* Nm9912 */ /* Netoctave */ #define PCI_PRODUCT_NETOCTAVE_NSP2K 0x0100 /* NSP2K */ Index: sys/dev/pci/pcidevs_data.h =================================================================== RCS file: /cvs/src/sys/dev/pci/pcidevs_data.h,v retrieving revision 1.2088 diff -u -p -u -r1.2088 pcidevs_data.h --- sys/dev/pci/pcidevs_data.h 7 Mar 2025 15:07:13 -0000 1.2088 +++ sys/dev/pci/pcidevs_data.h 24 Jun 2025 21:23:19 -0000 @@ -28204,6 +28204,10 @@ static const struct pci_known_product pc "Nm9922", }, { + PCI_VENDOR_NETMOS, PCI_PRODUCT_NETMOS_NM9912, + "Nm9912", + }, + { PCI_VENDOR_NETOCTAVE, PCI_PRODUCT_NETOCTAVE_NSP2K, "NSP2K", }, Index: sys/dev/pci/pucdata.c =================================================================== RCS file: /cvs/src/sys/dev/pci/pucdata.c,v retrieving revision 1.121 diff -u -p -u -r1.121 pucdata.c --- sys/dev/pci/pucdata.c 9 Nov 2024 10:23:06 -0000 1.121 +++ sys/dev/pci/pucdata.c 24 Jun 2025 21:23:19 -0000 @@ -1682,6 +1682,24 @@ const struct puc_device_description puc_ }, }, + /* NetMos PCIe Peripheral Controller 2 serial 16550/650+ uarts */ + { /* "NetMos NMC9912 UART" */ + { PCI_VENDOR_NETMOS, PCI_PRODUCT_NETMOS_NM9912, 0xa000, 0x1000 }, + { 0xffff, 0xffff, 0xffff, 0xffff }, + { + { PUC_PORT_COM, 0x10, 0x0000 }, + }, + }, + + /* NetMos PCIe Peripheral Controller 1 1284+ parallel port */ + { /* "NetMos NMC9912 parallel port" */ + { PCI_VENDOR_NETMOS, PCI_PRODUCT_NETMOS_NM9912, 0xa000, 0x2000 }, + { 0xffff, 0xffff, 0xffff, 0xffff }, + { + { PUC_PORT_LPT, 0x10, 0x0000 }, + }, + }, + { /* NetMos NM9922: 2S */ { PCI_VENDOR_NETMOS, PCI_PRODUCT_NETMOS_NM9922, 0xa000, 0x1000 }, { 0xffff, 0xffff, 0xffff, 0xffff }, Index: sys/dev/pci/pucvar.h =================================================================== RCS file: /cvs/src/sys/dev/pci/pucvar.h,v retrieving revision 1.18 diff -u -p -u -r1.18 pucvar.h --- sys/dev/pci/pucvar.h 24 May 2024 04:36:26 -0000 1.18 +++ sys/dev/pci/pucvar.h 24 Jun 2025 21:23:19 -0000 @@ -61,6 +61,7 @@ struct puc_port_type { PUC_PORT_COM_MUL10, PUC_PORT_COM_MUL128, PUC_PORT_COM_XR17V35X, + PUC_PORT_COM_MAX } type; u_int32_t freq; }; @@ -76,7 +77,7 @@ static const struct puc_port_type puc_po }; #define PUC_IS_LPT(type) ((type) == PUC_PORT_LPT) -#define PUC_IS_COM(type) ((type) != PUC_PORT_LPT) +#define PUC_IS_COM(type) ((type) >= PUC_PORT_COM && (type) < PUC_PORT_COM_MAX) #define PUC_PORT_BAR_INDEX(bar) (((bar) - PCI_MAPREG_START) / 4) OpenBSD 7.7-stable (try) #3: Tue Jun 24 16:12:11 EDT 2025 gwes@eight.oat.com:/usr/src/sys/arch/amd64/compile/try real mem = 8183627776 (7804MB) avail mem = 7909265408 (7542MB) random: good seed from bootblocks mpath0 at root scsibus0 at mpath0: 256 targets mainbus0 at root bios0 at mainbus0: SMBIOS rev. 2.8 @ 0x6d946000 (19 entries) bios0: vendor American Megatrends Inc. version "P1.30" date 05/04/2018 bios0: ASRock J4105M efi0 at bios0: UEFI 2.6 efi0: American Megatrends rev 0x5000d acpi0 at bios0: ACPI 6.1 acpi0: sleep states S0 S3 S4 S5 acpi0: tables DSDT FACP FPDT FIDT MCFG DBG2 DBGP HPET LPIT APIC NPKT SSDT SSDT SSDT AAFT SSDT SSDT SSDT SSDT SSDT UEFI WDAT WSMT acpi0: wakeup devices SIO1(S3) PS2K(S4) UAR1(S4) UAR2(S4) HDAS(S3) XHC_(S4) XDCI(S4) RP01(S4) PXSX(S4) RP02(S4) PXSX(S4) RP03(S4) PXSX(S4) RP04(S4) PXSX(S4) RP05(S4) [...] acpitimer0 at acpi0: 3579545 Hz, 32 bits acpimcfg0 at acpi0 acpimcfg0: addr 0xe0000000, bus 0-255 acpihpet0 at acpi0: 19200000 Hz acpimadt0 at acpi0 addr 0xfee00000: PC-AT compat cpu0 at mainbus0: apid 0 (boot processor) cpu0: Intel(R) Celeron(R) J4105 CPU @ 1.50GHz, 1495.86 MHz, 06-7a-01, patch 00000042 cpu0: cpuid 1 edx=bfebfbff ecx=47f8ebbf cpu0: cpuid 6 eax=57 ecx=1 cpu0: cpuid 7.0 ebx=2294e287 ecx=40400004 edx=ac000400 cpu0: cpuid a vers=4, gp=4, gpwidth=48, ff=3, ffwidth=48 cpu0: cpuid d.1 eax=f cpu0: cpuid 80000001 edx=2c100800 ecx=101 cpu0: cpuid 80000007 edx=100 cpu0: msr 10a=14000c6a cpu0: MELTDOWN cpu0: 24KB 64b/line 6-way D-cache, 32KB 64b/line 8-way I-cache, 4MB 64b/line 16-way L2 cache cpu0: smt 0, core 0, package 0 mtrr: Pentium Pro MTRR support, 10 var ranges, 88 fixed ranges cpu0: apic clock running at 19MHz cpu0: mwait min=64, max=64, C-substates=0.2.0.2.4.2.1.1, IBE cpu at mainbus0: not configured cpu at mainbus0: not configured cpu at mainbus0: not configured ioapic0 at mainbus0: apid 1 pa 0xfec00000, version 20, 120 pins acpiprt0 at acpi0: bus 0 (PCI0) acpiprt1 at acpi0: bus 1 (RP03) acpiprt2 at acpi0: bus 2 (RP04) acpiprt3 at acpi0: bus 3 (RP05) acpiprt4 at acpi0: bus 4 (RP06) acpiec0 at acpi0: not present acpipci0 at acpi0 PCI0: 0x00000000 0x00000011 0x00000001 "PNP0303" at acpi0 not configured com0 at acpi0 UAR1 addr 0x3f8/0x8 irq 4: ns16550a, 16 byte fifo com1 at acpi0 UAR2 addr 0x2f8/0x8 irq 3: ns16550a, 16 byte fifo acpicmos0 at acpi0 acpibtn0 at acpi0: PWRB(wakeup) glkgpio0 at acpi0 GPO1 uid 1 addr 0xd0c40000/0xcef irq 14, 80 pins glkgpio1 at acpi0 GPO0 uid 2 addr 0xd0c50000/0xaff irq 14, 80 pins glkgpio2 at acpi0 GPO2 uid 3 addr 0xd0c90000/0x7bf irq 15, 20 pins glkgpio3 at acpi0 GPO3 uid 4 addr 0xd0c80000/0x82f irq 14, 35 pins intelpmc0 at acpi0: PEPD state 0: 0x7f:1:2:0x00:0x0000000000000060 counter: 0x7f:64:0:0x00:0x0000000000000632 frequency: 0 "INT3400" at acpi0 not configured "INT3406" at acpi0 not configured "INT3404" at acpi0 not configured "INT3403" at acpi0 not configured "INT3407" at acpi0 not configured "INT3403" at acpi0 not configured "INT3403" at acpi0 not configured "INT3403" at acpi0 not configured "INT3403" at acpi0 not configured "PNP0C0B" at acpi0 not configured acpipwrres0 at acpi0: DRST acpipwrres1 at acpi0: DRST acpipwrres2 at acpi0: DRST acpipwrres3 at acpi0: DRST acpipwrres4 at acpi0: DRST acpipwrres5 at acpi0: DRST acpipwrres6 at acpi0: WRST acpicpu0 at acpi0: C3(10@150 mwait.1@0x60), C2(10@50 mwait.1@0x21), C1(1000@1 mwait.1@0x1), PSS acpipwrres7 at acpi0: FN00, resource for FAN0 acpitz0 at acpi0 acpitz0: critical temperature is 95 degC acpivideo0 at acpi0: GFX0 acpivout0 at acpivideo0: DD1F cpu0: using VERW MDS workaround cpu0: Enhanced SpeedStep 1495 MHz: speeds: 1501, 1500, 1400, 1300, 1200, 1100, 1000, 900, 800 MHz pci0 at mainbus0 bus 0 pchb0 at pci0 dev 0 function 0 "Intel Gemini Lake Host" rev 0x03 "Intel Gemini Lake DPTF" rev 0x03 at pci0 dev 0 function 1 not configured inteldrm0 at pci0 dev 2 function 0 "Intel UHD Graphics 600" rev 0x03 drm0 at inteldrm0 inteldrm0: msi, GEMINILAKE, gen 9 azalia0 at pci0 dev 14 function 0 "Intel Gemini Lake HD Audio" rev 0x03: msi azalia0: codecs: Realtek ALC887, Intel/0x280d, using Realtek ALC887 audio0 at azalia0 "Intel Gemini Lake MEI" rev 0x03 at pci0 dev 15 function 0 not configured ahci0 at pci0 dev 18 function 0 "Intel Gemini Lake AHCI" rev 0x03: msi, AHCI 1.3.1 ahci0: PHY offline on port 0 ahci0: port 1: 6.0Gb/s scsibus1 at ahci0: 32 targets sd0 at scsibus1 targ 1 lun 0: naa.5f8db4c205161184 sd0: 228936MB, 512 bytes/sector, 468862128 sectors, thin ppb0 at pci0 dev 19 function 0 "Intel Gemini Lake PCIE" rev 0xf3: msi pci1 at ppb0 bus 1 puc0 at pci1 dev 0 function 0 "NetMos Nm9912" rev 0x00: ports: 1 com com4 at puc0 port 0 apic 1 int 22: st16650, 32 byte fifo puc1 at pci1 dev 0 function 1 "NetMos Nm9912" rev 0x00: ports: 1 com com5 at puc1 port 0 apic 1 int 23: st16650, 32 byte fifo puc2 at pci1 dev 0 function 2 "NetMos Nm9912" rev 0x00: ports: 1 lpt lpt1 at puc2 port 0 apic 1 int 20 ppb1 at pci0 dev 19 function 1 "Intel Gemini Lake PCIE" rev 0xf3: msi pci2 at ppb1 bus 2 ppb2 at pci0 dev 19 function 2 "Intel Gemini Lake PCIE" rev 0xf3: msi pci3 at ppb2 bus 3 re0 at pci3 dev 0 function 0 "Realtek 8168" rev 0x0c: RTL8168G/8111G (0x4c00), msi, address 70:85:c2:f7:d4:ee rgephy0 at re0 phy 7: RTL8251, rev. 0 ppb3 at pci0 dev 19 function 3 "Intel Gemini Lake PCIE" rev 0xf3: msi pci4 at ppb3 bus 4 xhci0 at pci0 dev 21 function 0 "Intel Gemini Lake xHCI" rev 0x03: msi, xHCI 1.0 usb0 at xhci0: USB revision 3.0 uhub0 at usb0 configuration 1 interface 0 "Intel xHCI root hub" rev 3.00/1.00 addr 1 pcib0 at pci0 dev 31 function 0 "Intel Gemini Lake LPC" rev 0x03 ichiic0 at pci0 dev 31 function 1 "Intel Gemini Lake SMBus" rev 0x03: apic 1 int 20 iic0 at ichiic0 spdmem0 at iic0 addr 0x50: 4GB DDR4 SDRAM PC4-19200 spdmem1 at iic0 addr 0x52: 4GB DDR4 SDRAM PC4-19200 isa0 at pcib0 isadma0 at isa0 pckbc0 at isa0 port 0x60/5 irq 1 irq 12 pckbd0 at pckbc0 (kbd slot) wskbd0 at pckbd0: console keyboard pcppi0 at isa0 port 0x61 spkr0 at pcppi0 lpt0 at isa0 port 0x378/4 irq 7 vmm0 at mainbus0: VMX/EPT (using slow L1TF mitigation) efifb at mainbus0 not configured uhub1 at uhub0 port 7 configuration 1 interface 0 "Genesys Logic USB2.0 Hub" rev 2.00/88.32 addr 2 vscsi0 at root scsibus2 at vscsi0: 256 targets softraid0 at root scsibus3 at softraid0: 256 targets root on sd0a (e8dbc61507ec5f9d.a) swap on sd0b dump on sd0b drm : [drm] Unclaimed read from register 0xd8150 inteldrm0: 1920x1080, 32bpp wsdisplay0 at inteldrm0 mux 1: console (std, vt100 emulation), using wskbd0 wsdisplay0: screen 1-5 added (std, vt100 emulation)