Module Name:    src
Committed By:   msaitoh
Date:           Thu Dec 26 17:51:08 UTC 2019

Modified Files:
        src/sys/dev/pci: if_cas.c if_casreg.h if_casvar.h

Log Message:
 Fix a bug that the driver sometimes incorrectly attach gentbi(4) instead of
gphyter(4) on non-fiber device.

Tested with Sun Quad GigaSwift Ethernet UTP (QGE) (part no. 501-6522) on
amd64. On this environment, the problem frequently had occurred. I also
tested with other 4 cas(4) variants.


To generate a diff of this commit:
cvs rdiff -u -r1.36 -r1.37 src/sys/dev/pci/if_cas.c
cvs rdiff -u -r1.1 -r1.2 src/sys/dev/pci/if_casreg.h
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/pci/if_casvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/if_cas.c
diff -u src/sys/dev/pci/if_cas.c:1.36 src/sys/dev/pci/if_cas.c:1.37
--- src/sys/dev/pci/if_cas.c:1.36	Thu Nov 21 09:12:30 2019
+++ src/sys/dev/pci/if_cas.c	Thu Dec 26 17:51:08 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_cas.c,v 1.36 2019/11/21 09:12:30 msaitoh Exp $	*/
+/*	$NetBSD: if_cas.c,v 1.37 2019/12/26 17:51:08 msaitoh Exp $	*/
 /*	$OpenBSD: if_cas.c,v 1.29 2009/11/29 16:19:38 kettenis Exp $	*/
 
 /*
@@ -44,7 +44,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_cas.c,v 1.36 2019/11/21 09:12:30 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_cas.c,v 1.37 2019/12/26 17:51:08 msaitoh Exp $");
 
 #ifndef _MODULE
 #include "opt_inet.h"
@@ -114,7 +114,7 @@ CFATTACH_DECL3_NEW(cas, sizeof(struct ca
     cas_match, cas_attach, cas_detach, NULL, NULL, NULL,
     DVF_DETACH_SHUTDOWN);
 
-int	cas_pci_enaddr(struct cas_softc *, struct pci_attach_args *, uint8_t *);
+int	cas_pci_readvpd(struct cas_softc *, struct pci_attach_args *, uint8_t *);
 
 void		cas_config(struct cas_softc *, const uint8_t *);
 void		cas_start(struct ifnet *);
@@ -163,18 +163,32 @@ int		cas_intr(void *);
 #define	DPRINTF(sc, x)	/* nothing */
 #endif
 
+static const struct cas_pci_dev {
+	uint16_t cpd_vendor;
+	uint16_t cpd_device;
+	int cpd_variant;
+} cas_pci_devlist[] = {
+	{ PCI_VENDOR_SUN, PCI_PRODUCT_SUN_CASSINI, CAS_CAS },
+	{ PCI_VENDOR_NS, PCI_PRODUCT_NS_SATURN, CAS_SATURN },
+	{ 0, 0, 0 }
+};
+
+#define	CAS_LOCAL_MAC_ADDRESS	"local-mac-address"
+#define	CAS_PHY_INTERFACE	"phy-interface"
+#define	CAS_PHY_TYPE		"phy-type"
+#define	CAS_PHY_TYPE_PCS	"pcs"
+
 int
 cas_match(device_t parent, cfdata_t cf, void *aux)
 {
 	struct pci_attach_args *pa = aux;
+	int i;
 
-	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN &&
-	    (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_CASSINI))
-		return 1;
-
-	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NS &&
-	    (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NS_SATURN))
-		return 1;
+	for (i = 0; cas_pci_devlist[i].cpd_vendor != 0; i++) {
+		if ((PCI_VENDOR(pa->pa_id) == cas_pci_devlist[i].cpd_vendor) &&
+		    (PCI_PRODUCT(pa->pa_id) == cas_pci_devlist[i].cpd_device))
+			return 1;
+	}
 
 	return 0;
 }
@@ -205,7 +219,7 @@ static const uint8_t cas_promdat2[] = {
 
 #define CAS_LMA_MAXNUM	4
 int
-cas_pci_enaddr(struct cas_softc *sc, struct pci_attach_args *pa,
+cas_pci_readvpd(struct cas_softc *sc, struct pci_attach_args *pa,
     uint8_t *enaddr)
 {
 	struct pci_vpd_largeres *res;
@@ -214,9 +228,10 @@ cas_pci_enaddr(struct cas_softc *sc, str
 	bus_space_tag_t romt;
 	bus_size_t romsize = 0;
 	uint8_t enaddrs[CAS_LMA_MAXNUM][ETHER_ADDR_LEN];
+	bool pcs[4] = {false, false, false, false};
 	uint8_t buf[32], *desc;
 	pcireg_t address;
-	int dataoff, vpdoff, len, lma = 0;
+	int dataoff, vpdoff, len, lma = 0, phy = 0;
 	int i, rv = -1;
 
 	if (pci_mapreg_map(pa, PCI_MAPREG_ROM, PCI_MAPREG_TYPE_MEM, 0,
@@ -261,6 +276,20 @@ next:
 		goto next;
 
 	case PCI_VPDRES_TYPE_VPD:
+#ifdef CAS_DEBUG
+	printf("\n");
+	for (i = 0; i < len; i++) {
+		uint8_t byte;
+		if (i % 16 == 0)
+			printf("%04x :", i);
+		byte = bus_space_read_1(romt, romh, vpdoff + i);
+		printf(" %02x", byte);
+		if (i % 16 == 15)
+			printf("\n");
+	}
+	printf("\n");
+#endif
+
 		while (len > 0) {
 			bus_space_read_region_1(romt, romh, vpdoff,
 			     buf, sizeof(buf));
@@ -284,26 +313,57 @@ next:
 				continue;
 			desc += 3;
 
-			/*
-			 * ...that's a byte array with the proper
-			 * length for a MAC address...
-			 */
-			if (desc[0] != 'B' || desc[1] != ETHER_ADDR_LEN)
-				continue;
-			desc += 2;
+			if (desc[0] == 'B' || desc[1] == ETHER_ADDR_LEN) {
+				/*
+				 * ...that's a byte array with the proper
+				 * length for a MAC address...
+				 */
+				desc += 2;
 
-			/*
-			 * ...named "local-mac-address".
-			 */
-			if (strcmp(desc, "local-mac-address") != 0)
+				/*
+				 * ...named "local-mac-address".
+				 */
+				if (strcmp(desc, CAS_LOCAL_MAC_ADDRESS) != 0)
+					continue;
+				desc += sizeof(CAS_LOCAL_MAC_ADDRESS);
+
+				if (lma == CAS_LMA_MAXNUM)
+					continue;
+
+				memcpy(enaddrs[lma], desc, ETHER_ADDR_LEN);
+				lma++;
+				rv = 0;
 				continue;
-			desc += strlen("local-mac-address") + 1;
+			} else if (desc[0] == 'S') {
+				size_t k;
 
-			memcpy(enaddrs[lma], desc, ETHER_ADDR_LEN);
-			lma++;
-			rv = 0;
-			if (lma == CAS_LMA_MAXNUM)
-				break;
+				/* String */
+				desc += 2;
+#ifdef CAS_DEBUG
+				/* ...named "pcs". */
+				printf("STR: \"%s\"\n", desc);
+				if (strcmp(desc, CAS_PHY_TYPE_PCS) != 0)
+					continue;
+				desc += sizeof(CAS_PHY_TYPE_PCS);
+				printf("STR: \"%s\"\n", desc);
+#endif
+				/* ...named "phy-interface" or "phy-type". */
+				if (strcmp(desc, CAS_PHY_INTERFACE) == 0)
+					k = sizeof(CAS_PHY_INTERFACE);
+				else if (strcmp(desc, CAS_PHY_TYPE) == 0)
+					k = sizeof(CAS_PHY_TYPE);
+				else
+					continue;
+
+				desc += k;
+#ifdef CAS_DEBUG
+				printf("STR: \"%s\"\n", desc);
+#endif
+				if (strcmp(desc, CAS_PHY_TYPE_PCS) == 0)
+					pcs[phy] = true;
+				phy++;
+				continue;
+			}
 		}
 		break;
 
@@ -311,7 +371,6 @@ next:
 		goto fail;
 	}
 
-	i = 0;
 	/*
 	 * Multi port card has bridge chip. The device number is fixed:
 	 * e.g.
@@ -320,10 +379,15 @@ next:
 	 * p2: 006:02:0
 	 * p3: 006:03:0
 	 */
-	if ((lma > 1) && (pa->pa_device < CAS_LMA_MAXNUM)
-	    && (pa->pa_device < lma))
-		i = pa->pa_device;
-	memcpy(enaddr, enaddrs[i], ETHER_ADDR_LEN);
+	if (enaddr != 0) {
+		i = 0;
+		if ((lma > 1) && (pa->pa_device < CAS_LMA_MAXNUM)
+		    && (pa->pa_device < lma))
+			i = pa->pa_device;
+		memcpy(enaddr, enaddrs[i], ETHER_ADDR_LEN);
+	}
+	if (pcs[pa->pa_device])
+		sc->sc_flags |= CAS_SERDES;
  fail:
 	if (romsize != 0)
 		bus_space_unmap(romt, romh, romsize);
@@ -340,6 +404,7 @@ cas_attach(device_t parent, device_t sel
 {
 	struct pci_attach_args *pa = aux;
 	struct cas_softc *sc = device_private(self);
+	int i;
 	prop_data_t data;
 	uint8_t enaddr[ETHER_ADDR_LEN];
 
@@ -348,6 +413,20 @@ cas_attach(device_t parent, device_t sel
 	sc->sc_rev = PCI_REVISION(pa->pa_class);
 	sc->sc_dmatag = pa->pa_dmat;
 
+	sc->sc_variant = CAS_UNKNOWN;
+	for (i = 0; cas_pci_devlist[i].cpd_vendor != 0; i++) {
+		if ((PCI_VENDOR(pa->pa_id) == cas_pci_devlist[i].cpd_vendor) &&
+		    (PCI_PRODUCT(pa->pa_id) == cas_pci_devlist[i].cpd_device)) {
+			sc->sc_variant = cas_pci_devlist[i].cpd_variant;
+			break;
+		}
+	}
+	aprint_debug_dev(sc->sc_dev, "variant = %d\n", sc->sc_variant);
+	if (sc->sc_variant == CAS_UNKNOWN) {
+		aprint_error_dev(sc->sc_dev, "unknown adaptor\n");
+		return;
+	}
+
 #define PCI_CAS_BASEADDR	0x10
 	if (pci_mapreg_map(pa, PCI_CAS_BASEADDR, PCI_MAPREG_TYPE_MEM, 0,
 	    &sc->sc_memt, &sc->sc_memh, NULL, &sc->sc_size) != 0) {
@@ -359,7 +438,7 @@ cas_attach(device_t parent, device_t sel
 	if ((data = prop_dictionary_get(device_properties(sc->sc_dev),
 	    "mac-address")) != NULL)
 		memcpy(enaddr, prop_data_data_nocopy(data), ETHER_ADDR_LEN);
-	else if (cas_pci_enaddr(sc, pa, enaddr) != 0) {
+	if (cas_pci_readvpd(sc, pa, (data == NULL) ? enaddr : 0) != 0) {
 		aprint_error_dev(sc->sc_dev, "no Ethernet address found\n");
 		memset(enaddr, 0, sizeof(enaddr));
 	}
@@ -409,6 +488,7 @@ cas_config(struct cas_softc *sc, const u
 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
 	struct mii_data *mii = &sc->sc_mii;
 	struct mii_softc *child;
+	uint32_t reg;
 	int i, error;
 
 	/* Make sure the chip is stopped. */
@@ -555,10 +635,25 @@ cas_config(struct cas_softc *sc, const u
 
 	cas_mifinit(sc);
 
-	if (sc->sc_mif_config & CAS_MIF_CONFIG_MDI1) {
-		sc->sc_mif_config |= CAS_MIF_CONFIG_PHY_SEL;
-		bus_space_write_4(sc->sc_memt, sc->sc_memh,
-		    CAS_MIF_CONFIG, sc->sc_mif_config);
+	if (sc->sc_mif_config & (CAS_MIF_CONFIG_MDI1 | CAS_MIF_CONFIG_MDI0)) {
+		if (sc->sc_mif_config & CAS_MIF_CONFIG_MDI1) {
+			sc->sc_mif_config |= CAS_MIF_CONFIG_PHY_SEL;
+			bus_space_write_4(sc->sc_memt, sc->sc_memh,
+			    CAS_MIF_CONFIG, sc->sc_mif_config);
+		}
+		/* Enable/unfreeze the GMII pins of Saturn. */
+		if (sc->sc_variant == CAS_SATURN) {
+			reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
+			    CAS_SATURN_PCFG) & ~CAS_SATURN_PCFG_FSI;
+			if ((sc->sc_mif_config & CAS_MIF_CONFIG_MDI0) != 0)
+				reg |= CAS_SATURN_PCFG_FSI;
+			bus_space_write_4(sc->sc_memt, sc->sc_memh,
+			    CAS_SATURN_PCFG, reg);
+			/* Read to flush */
+			bus_space_read_4(sc->sc_memt, sc->sc_memh,
+			    CAS_SATURN_PCFG);
+			DELAY(10000);
+		}
 	}
 
 	mii_attach(sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY,

Index: src/sys/dev/pci/if_casreg.h
diff -u src/sys/dev/pci/if_casreg.h:1.1 src/sys/dev/pci/if_casreg.h:1.2
--- src/sys/dev/pci/if_casreg.h:1.1	Thu Jan  7 09:19:55 2010
+++ src/sys/dev/pci/if_casreg.h	Thu Dec 26 17:51:08 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_casreg.h,v 1.1 2010/01/07 09:19:55 jdc Exp $ */
+/*	$NetBSD: if_casreg.h,v 1.2 2019/12/26 17:51:08 msaitoh Exp $ */
 /*	$OpenBSD: if_casreg.h,v 1.10 2008/05/31 22:49:03 kettenis Exp $	*/
 
 /*
@@ -55,6 +55,7 @@
 #define	CAS_BIF_CONFIG		0x0008  /* BIF config reg */
 #define	CAS_BIF_DIAG		0x000c
 #define	CAS_RESET		0x1010  /* Software reset register */
+#define	CAS_SATURN_PCFG		0x106c	/* internal MACPHY pin configuration */
 
 /* Bits in CAS_SEB register */
 #define	CAS_SEB_ARB		0x000000002	/* Arbitration status */
@@ -114,6 +115,18 @@
 #define	CAS_RESET_RSTOUT	0x000000004	/* Force PCI RSTOUT# */
 #define	CAS_RESET_BLOCK_PCS	0x00000008	/* Block PCS reset */
 
+/* CAS_SATURN_PCFG register bits */
+#define	CAS_SATURN_PCFG_TLA	0x00000001	/* PHY activity LED */
+#define	CAS_SATURN_PCFG_FLA	0x00000002	/* PHY 10MBit/sec LED */
+#define	CAS_SATURN_PCFG_CLA	0x00000004	/* PHY 100MBit/sec LED */
+#define	CAS_SATURN_PCFG_LLA	0x00000008	/* PHY 1000MBit/sec LED */
+#define	CAS_SATURN_PCFG_RLA	0x00000010	/* PHY full-duplex LED */
+#define	CAS_SATURN_PCFG_PDS	0x00000020	/* PHY debug mode */
+#define	CAS_SATURN_PCFG_MTP	0x00000080	/* test point select */
+#define	CAS_SATURN_PCFG_GMO	0x00000100	/* GMII observe */
+#define	CAS_SATURN_PCFG_FSI	0x00000200	/* freeze GMII/SERDES */
+#define	CAS_SATURN_PCFG_LAD	0x00000800	/* MAC LED control active low */
+
 /* TX DMA registers */
 #define	CAS_TX_CONFIG		0x2004
 

Index: src/sys/dev/pci/if_casvar.h
diff -u src/sys/dev/pci/if_casvar.h:1.6 src/sys/dev/pci/if_casvar.h:1.7
--- src/sys/dev/pci/if_casvar.h:1.6	Tue Mar  5 08:25:02 2019
+++ src/sys/dev/pci/if_casvar.h	Thu Dec 26 17:51:08 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_casvar.h,v 1.6 2019/03/05 08:25:02 msaitoh Exp $ */
+/*	$NetBSD: if_casvar.h,v 1.7 2019/12/26 17:51:08 msaitoh Exp $ */
 /*	$OpenBSD: if_casvar.h,v 1.6 2009/06/13 12:18:58 kettenis Exp $	*/
 
 /*
@@ -158,6 +158,17 @@ struct cas_softc {
 	int		sc_burst;	/* DVMA burst size in effect */
 	int		sc_phys[2];	/* MII instance -> PHY map */
 
+	u_int		sc_variant;
+#define	CAS_UNKNOWN	0		/* don't know */
+#define	CAS_CAS		1		/* Sun Cassini */
+#if 0 /* notyet */
+#define	CAS_CASPLUS	2		/* Sun Cassini+ */
+#endif
+#define	CAS_SATURN	3		/* National Semiconductor Saturn */
+
+	u_int		sc_flags;
+#define	CAS_SERDES	(1 << 4)	/* use the SERDES */
+
 	int		sc_mif_config;	/* Selected MII reg setting */
 
 	/*

Reply via email to