Index | Thread | Search

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

Download raw body.

Thread
  • gwes@oat.com:

    NetMos NMC9912 PCI I/O

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<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE> ecx=47f8ebbf<SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,SDBG,CX16,xTPR,PDCM,SSE4.1,SSE4.2,x2APIC,MOVBE,POPCNT,DEADLINE,AES,XSAVE,RDRAND>
cpu0: cpuid 6 eax=57<SENSOR,ARAT> ecx=1<EFFFREQ>
cpu0: cpuid 7.0 ebx=2294e287<FSGSBASE,TSC_ADJUST,SGX,SMEP,ERMS,MPX,RDSEED,SMAP,CLFLUSHOPT,PT,SHA> ecx=40400004<UMIP> edx=ac000400<MD_CLEAR,IBRS,IBPB,STIBP,SSBD>
cpu0: cpuid a vers=4, gp=4, gpwidth=48, ff=3, ffwidth=48
cpu0: cpuid d.1 eax=f<XSAVEOPT,XSAVEC,XGETBV1,XSAVES>
cpu0: cpuid 80000001 edx=2c100800<NXE,PAGE1GB,RDTSCP,LONG> ecx=101<LAHF,3DNOWP>
cpu0: cpuid 80000007 edx=100<ITSC>
cpu0: msr 10a=14000c6a<IBRS_ALL,SKIP_L1DFL,MDS_NO,IF_PSCHANGE,MISC_PKG_CT,ENERGY_FILT,GDS_NO,RFDS_CLEAR>
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: <ATA, PNY CS1211 240GB, CS12> 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)