NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/57359: 10.0_BETA failed to detect USB 2.0 Hub on AMD SB600



The following reply was made to PR kern/57359; it has been noted by GNATS.

From: Izumi Tsutsui <tsutsui%ceres.dti.ne.jp@localhost>
To: gnats-bugs%netbsd.org@localhost
Cc: netbsd-bugs%netbsd.org@localhost, tsutsui%ceres.dti.ne.jp@localhost
Subject: Re: kern/57359: 10.0_BETA failed to detect USB 2.0 Hub on AMD SB600
Date: Mon, 5 Jan 2026 02:50:17 +0900

 I wrote:
 
 > >Number:         57359
 > >Category:       kern
 > >Synopsis:       10.0_BETA failed to detect USB 2.0 Hub on AMD SB600
 
  :
 
 > >Description:
 > On ASRock M3A UCC motherboard with AMD 480X CrossFire / AMD SB600
 >  https://www.asrock.com/mb/AMD/M3A%20UCC/index.asp
 > (no overclock, no unlock CPU Core)
 > USB 2.0 Hub connected to an on-board USB port is not detected properly
 > on NetBSD/i386 10.0_BETA GENERIC (202304150840Z):
 > >> uhub3: autoconfiguration error: device problem, disabling port 6
 > 
 > while it works on NetBSD/i386 9.3 GENERIC:
 
 After git-bisect(1) between netbsd-9-base and netbsd-10-base,
 it turns out the following commit caused this SB600 ehci problem:
 
  https://mail-index.netbsd.org/source-changes/2020/05/05/msg117061.html
 
 ---
 Module Name:    src
 Committed By:   bouyer
 Date:           Tue May  5 16:58:11 UTC 2020
 
 Modified Files:
         src/sys/dev/pci: pci_map.c
 
 Log Message:
 disable I/O or mem decode before probing BAR size.
 Bar size is probed writing 0xffffffff to the BAR and reading back; but while
 doing this the decoding address is not guaranteed to be valid and could have
 side effect.
 
 Xen PVH enforces disabling decoding before writing to a BAR.
 
 Proposed on tech-kern@, got positive comments
 
 
 To generate a diff of this commit:
 cvs rdiff -u -r1.39 -r1.40 src/sys/dev/pci/pci_map.c
 
 ```
 Index: src/sys/dev/pci/pci_map.c
 diff -u src/sys/dev/pci/pci_map.c:1.39 src/sys/dev/pci/pci_map.c:1.40
 --- src/sys/dev/pci/pci_map.c:1.39	Mon Dec  2 17:13:13 2019
 +++ src/sys/dev/pci/pci_map.c	Tue May  5 16:58:11 2020
 @@ -1,4 +1,4 @@
 -/*	$NetBSD: pci_map.c,v 1.39 2019/12/02 17:13:13 riastradh Exp $	*/
 +/*	$NetBSD: pci_map.c,v 1.40 2020/05/05 16:58:11 bouyer Exp $	*/
  
  /*-
   * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
 @@ -34,7 +34,7 @@
   */
  
  #include <sys/cdefs.h>
 -__KERNEL_RCSID(0, "$NetBSD: pci_map.c,v 1.39 2019/12/02 17:13:13 riastradh Exp $");
 +__KERNEL_RCSID(0, "$NetBSD: pci_map.c,v 1.40 2020/05/05 16:58:11 bouyer Exp $");
  
  #include <sys/param.h>
  #include <sys/systm.h>
 @@ -49,7 +49,7 @@
  pci_io_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
      bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
  {
 -	pcireg_t address, mask;
 +	pcireg_t address, mask, csr;
  	int s;
  
  	if (reg < PCI_MAPREG_START ||
 @@ -75,9 +75,18 @@
  	 */
  	s = splhigh();
  	address = pci_conf_read(pc, tag, reg);
 +	/*
 +	 * Disable decoding via the command register before writing to the
 +	 * BAR register. Changing the decoding address to all-one is
 +	 * not a valid address and could have side effects.
 +	 */
 +	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
 +	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
 +	    csr & ~PCI_COMMAND_IO_ENABLE) ;
  	pci_conf_write(pc, tag, reg, 0xffffffff);
  	mask = pci_conf_read(pc, tag, reg);
  	pci_conf_write(pc, tag, reg, address);
 +	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
  	splx(s);
  
  	if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_IO) {
 @@ -107,6 +116,7 @@
  	pcireg_t address, mask, address1 = 0, mask1 = 0xffffffff;
  	uint64_t waddress, wmask;
  	int s, is64bit, isrom;
 +	pcireg_t csr;
  
  	is64bit = (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT);
  	isrom = (reg == PCI_MAPREG_ROM);
 @@ -138,6 +148,14 @@
  	 */
  	s = splhigh();
  	address = pci_conf_read(pc, tag, reg);
 +	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
 +	/*
 +	 * Disable decoding via the command register before writing to the
 +	 * BAR register. Changing the decoding address to all-one is
 +	 * not a valid address and could have side effects.
 +	 */
 +	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
 +	    csr & ~PCI_COMMAND_MEM_ENABLE) ;
  	pci_conf_write(pc, tag, reg, 0xffffffff);
  	mask = pci_conf_read(pc, tag, reg);
  	pci_conf_write(pc, tag, reg, address);
 @@ -149,6 +167,7 @@
  			pci_conf_write(pc, tag, reg + 4, address1);
  		}
  	}
 +	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
  	splx(s);
  
  	if (!isrom) {
 @@ -240,14 +259,28 @@
  int
  pci_mapreg_probe(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *typep)
  {
 -	pcireg_t address, mask;
 +	pcireg_t address, mask, csr;
  	int s;
  
  	s = splhigh();
  	address = pci_conf_read(pc, tag, reg);
 +	/*
 +	 * Disable decoding via the command register before writing to the
 +	 * BAR register. Changing the decoding address to all-one is
 +	 * not a valid address and could have side effects.
 +	 */
 +	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
 +	if (PCI_MAPREG_TYPE(address) == PCI_MAPREG_TYPE_IO) {
 +		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
 +		    csr & ~PCI_COMMAND_IO_ENABLE);
 +	} else {
 +		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
 +		    csr & ~PCI_COMMAND_MEM_ENABLE);
 +	}
  	pci_conf_write(pc, tag, reg, 0xffffffff);
  	mask = pci_conf_read(pc, tag, reg);
  	pci_conf_write(pc, tag, reg, address);
 +	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
  	splx(s);
  
  	if (mask == 0) /* unimplemented mapping register */
 ```
 
 Actually reverting this change on netbsd-10 branch makes USB 2.0
 devices on ehci(4) work again on my M3A-UCC.
 
 However, as noted in the above log the changes in pci_map.c rev 1.40
 seem correct per the PCI specification, so the problem in this
 PR could be caused by some SB600 specific side effects around
 PCI_COMMAND_STATUS_REG accesses.
 
 After several try-and-errors, it works around to move existing
 SB600/SB700 quirk handling in ehci_pci.c (writing a MAGIC value
 to SBx00 specific EHCI_SBx00_WORKAROUND_REG) after the enabling
 devices even with pci_map.c rev 1.40, at least on my ASRock M3A-UCC.
 
 ```
 Index: sys/dev/pci/ehci_pci.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/pci/ehci_pci.c,v
 retrieving revision 1.75.2.2
 diff -u -p -d -r1.75.2.2 ehci_pci.c
 --- sys/dev/pci/ehci_pci.c	11 Sep 2024 15:56:21 -0000	1.75.2.2
 +++ sys/dev/pci/ehci_pci.c	4 Jan 2026 16:59:08 -0000
 @@ -168,6 +168,15 @@ ehci_pci_attach(device_t parent, device_
  	DPRINTF(("%s: offs=%d\n", device_xname(self), sc->sc.sc_offs));
  	EOWRITE4(&sc->sc, EHCI_USBINTR, 0);
  
 +	pcireg_t intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
 +	int pin = PCI_INTERRUPT_PIN(intr);
 +
 +	/* Enable the device. */
 +	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
 +	csr |= PCI_COMMAND_MASTER_ENABLE;
 +	csr &= ~(pin ? PCI_COMMAND_INTERRUPT_DISABLE : 0);
 +	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
 +
  	/* Handle quirks */
  	switch (quirk) {
  	case EHCI_PCI_QUIRK_AMD_SB600:
 @@ -179,15 +188,6 @@ ehci_pci_attach(device_t parent, device_
  		break;
  	}
  
 -	pcireg_t intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
 -	int pin = PCI_INTERRUPT_PIN(intr);
 -
 -	/* Enable the device. */
 -	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
 -	csr |= PCI_COMMAND_MASTER_ENABLE;
 -	csr &= ~(pin ? PCI_COMMAND_INTERRUPT_DISABLE : 0);
 -	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
 -
  	/* Map and establish the interrupt. */
  	if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0) != 0) {
  		aprint_error_dev(self, "couldn't map interrupt\n");
 ```
 
 This chane should not affect other systems than SB600 (and early
 SB700) systems, so if there is no particular objection I'll commit
 the above fix soon.
 
 Thanks,
 ---
 Izumi Tsutsui
 


Home | Main Index | Thread Index | Old Index