Subject: port-i386/15261: patches to if_sip.c for SiS 635/735 support
To: None <gnats-bugs@gnats.netbsd.org>
From: None <sdegler@degler.net>
List: netbsd-bugs
Date: 01/15/2002 22:22:04
>Number:         15261
>Category:       port-i386
>Synopsis:       patches to if_sip.c for SiS 635/735 support
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    port-i386-maintainer
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue Jan 15 19:23:00 PST 2002
>Closed-Date:
>Last-Modified:
>Originator:     Stephen Degler
>Release:        NetBSD 1.5ZA
>Organization:
Very little, at best
	
>Environment:
	
	
System: NetBSD bauhaus.degler.net 1.5ZA NetBSD 1.5ZA (BAUHAUS) #1: Tue Jan 15 21:43:19 EST 2002 sdegler@bauhaus.degler.net:/vol1/NetBSD/kernels/BAUHAUS i386
Architecture: i386
Machine: i386
>Description:
	Attached is a patch to add support for the integrated ethernet
	controller on the SiS 635 and 735 chipsets.  This solves two problems.

	"master abort" --> apparently caused by initializing the receive
	filter too early in the init function.

	"oversize packet dropped" --> The SiS chipsets seem to has some
	magical internal (not quite pci) bus that the ethernet controller
	is attached to.  It requires the DMA thresholds to not exceed 64
	bytes.

	See reports of these problems on the port-i386 mailing list circa
	December 20.

	Note that I had to refer to the Linux driver as it is the only
	source of documentation to be found for the 635/735, and it is
	maintained by SIS.  No code was borrowed, I wrote what little is
	here.

	The multicast filter was changed to support at 256 bit hash
	table for the 635/735.  Finally, changed the crc calculation
	as it seemed to be backwards.  This needs to be verified.  It
	is possible that I broke the other supported chips by doing
	this.  It definitely fixed a problem for me as I was not
	receiving NTP multicast packets without it.
	
>How-To-Repeat:
	Boot any SiS 635/735 based system and try to use the integrated
	ethernet.
>Fix:
	The following 2 patches are against -current:
--------------------------------------------------------------------------
diff -c -r1.8 if_sipreg.h
*** if_sipreg.h	2001/12/20 03:32:31	1.8
--- if_sipreg.h	2002/01/16 03:11:12
***************
*** 249,254 ****
--- 249,257 ----
  #else
  #define	CFG_EUPHCOMP	0x00000100	/* 83810 descriptor compat (83815) */
  #endif /* DP83820 */
+ #define CFG_EDBMASTEN	0x00002000	/* 635,900B ?? from linux driver */
+ #define CFG_RNDCNT	0x00000400	/* 635,900B ?? from linux driver */
+ #define CFG_FAIRBO	0x00000200	/* 635,900B ?? from linux driver */
  #define	CFG_REQALG	0x00000080	/* PCI bus request alg. */
  #define	CFG_SB		0x00000040	/* single backoff */
  #define	CFG_POW		0x00000020	/* program out of window timer */
***************
*** 471,476 ****
--- 474,480 ----
  #define	RXCFG_MXDMA_256	0x00700000	/*     256 bytes */
  #endif /* DP83820 */
  #define	RXCFG_DRTH	0x0000003e
+ /* #define	RXCFG_DRTH	14 */
  #define	RXCFG_DRTH_SHIFT 1
  
  #ifdef DP83820
***************
*** 519,524 ****
--- 523,537 ----
  #define	RFCR_RFADDR_MC5	  0x00090000	/* multicast hash word 5 */
  #define	RFCR_RFADDR_MC6	  0x000a0000	/* multicast hash word 6 */
  #define	RFCR_RFADDR_MC7	  0x000b0000	/* multicast hash word 7 */
+ /* sis900 B and 635/735 only */
+ #define	RFCR_RFADDR_MC8	  0x000c0000	/* multicast hash word 8 */
+ #define	RFCR_RFADDR_MC9	  0x000d0000	/* multicast hash word 9 */
+ #define	RFCR_RFADDR_MC10  0x000e0000	/* multicast hash word 10 */
+ #define	RFCR_RFADDR_MC11  0x000f0000	/* multicast hash word 11 */
+ #define	RFCR_RFADDR_MC12  0x00100000	/* multicast hash word 12 */
+ #define	RFCR_RFADDR_MC13  0x00110000	/* multicast hash word 13 */
+ #define	RFCR_RFADDR_MC14  0x00120000	/* multicast hash word 14 */
+ #define	RFCR_RFADDR_MC15  0x00130000	/* multicast hash word 15 */
  
  #define	RFCR_NS_RFADDR_PMATCH0	0x0000	/* perfect match octets 1-0 */
  #define	RFCR_NS_RFADDR_PMATCH2	0x0002	/* perfect match octets 3-2 */
***************
*** 694,699 ****
--- 707,714 ----
  #define	SIS_REV_630E	0x81
  #define	SIS_REV_630S	0x82
  #define	SIS_REV_630EA1	0x83
+ #define	SIS_REV_635	0x90	/* same for 735 (745?) */
+ #define	SIS_REV_900B	0x03
  
  /*
   * Serial EEPROM opcodes, including the start bit.
--------------------------------------------------------------------------
Index: if_sip.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/pci/if_sip.c,v
retrieving revision 1.44
diff -c -r1.44 if_sip.c
*** if_sip.c	2001/12/20 03:32:31	1.44
--- if_sip.c	2002/01/16 03:13:05
***************
*** 366,371 ****
--- 366,385 ----
  	SIP_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \
  } while (0)
  
+ #define SIP_CHIP_VERS(sc,vendor,product,rev) \
+ 	(sc->sc_model->sip_vendor == vendor  && \
+ 	 sc->sc_model->sip_product == product && \
+ 	 sc->sc_model->sip_revision == rev )
+ 
+ #define SIP_CHIP_MODEL(sc,vendor,product) \
+ 	(sc->sc_model->sip_vendor == vendor  && \
+ 	 sc->sc_model->sip_product == product)
+ 
+ #if !defined(DP83820)
+ #define SIP_SIS900_REV(sc,rev) \
+        (SIP_CHIP_VERS(sc,PCI_VENDOR_SIS,PCI_PRODUCT_SIS_900,rev))
+ #endif
+ 
  #define SIP_TIMEOUT 1000
  
  void	SIP_DECL(start)(struct ifnet *);
***************
*** 488,514 ****
  const struct sip_product {
  	pci_vendor_id_t		sip_vendor;
  	pci_product_id_t	sip_product;
  	const char		*sip_name;
  	const struct sip_variant *sip_variant;
  } SIP_DECL(products)[] = {
  #if defined(DP83820)
! 	{ PCI_VENDOR_NS,	PCI_PRODUCT_NS_DP83820,
  	  "NatSemi DP83820 Gigabit Ethernet",
  	  &SIP_DECL(variant_dp83820) },
  #else
! 	{ PCI_VENDOR_SIS,	PCI_PRODUCT_SIS_900,
  	  "SiS 900 10/100 Ethernet",
  	  &SIP_DECL(variant_sis900) },
! 	{ PCI_VENDOR_SIS,	PCI_PRODUCT_SIS_7016,
  	  "SiS 7016 10/100 Ethernet",
  	  &SIP_DECL(variant_sis900) },
! 
! 	{ PCI_VENDOR_NS,	PCI_PRODUCT_NS_DP83815,
  	  "NatSemi DP83815 10/100 Ethernet",
  	  &SIP_DECL(variant_dp83815) },
  #endif /* DP83820 */
! 
! 	{ 0,			0,
  	  NULL,
  	  NULL },
  };
--- 502,527 ----
  const struct sip_product {
  	pci_vendor_id_t		sip_vendor;
  	pci_product_id_t	sip_product;
+ 	pci_revision_t		sip_revision;
  	const char		*sip_name;
  	const struct sip_variant *sip_variant;
  } SIP_DECL(products)[] = {
  #if defined(DP83820)
! 	{ PCI_VENDOR_NS,	PCI_PRODUCT_NS_DP83820, 0,
  	  "NatSemi DP83820 Gigabit Ethernet",
  	  &SIP_DECL(variant_dp83820) },
  #else
! 	{ PCI_VENDOR_SIS,	PCI_PRODUCT_SIS_900, 0,
  	  "SiS 900 10/100 Ethernet",
  	  &SIP_DECL(variant_sis900) },
! 	{ PCI_VENDOR_SIS,	PCI_PRODUCT_SIS_7016, 0,
  	  "SiS 7016 10/100 Ethernet",
  	  &SIP_DECL(variant_sis900) },
! 	{ PCI_VENDOR_NS,	PCI_PRODUCT_NS_DP83815, 0,
  	  "NatSemi DP83815 10/100 Ethernet",
  	  &SIP_DECL(variant_dp83815) },
  #endif /* DP83820 */
! 	{ 0,			0,			0,
  	  NULL,
  	  NULL },
  };
***************
*** 551,557 ****
  	bus_dma_segment_t seg;
  	int ioh_valid, memh_valid;
  	int i, rseg, error;
! 	const struct sip_product *sip;
  	pcireg_t pmode;
  	u_int8_t enaddr[ETHER_ADDR_LEN];
  	int pmreg;
--- 564,571 ----
  	bus_dma_segment_t seg;
  	int ioh_valid, memh_valid;
  	int i, rseg, error;
! 	const struct sip_product *sip_template;
! 	struct sip_product *sip;
  	pcireg_t pmode;
  	u_int8_t enaddr[ETHER_ADDR_LEN];
  	int pmreg;
***************
*** 562,572 ****
  
  	callout_init(&sc->sc_tick_ch);
  
! 	sip = SIP_DECL(lookup)(pa);
! 	if (sip == NULL) {
  		printf("\n");
  		panic(SIP_STR(attach) ": impossible");
  	}
  
  	printf(": %s\n", sip->sip_name);
  
--- 576,592 ----
  
  	callout_init(&sc->sc_tick_ch);
  
! 	sip_template = SIP_DECL(lookup)(pa);
! 	if (sip_template == NULL) {
  		printf("\n");
  		panic(SIP_STR(attach) ": impossible");
  	}
+ 	else {
+ 		sip = (struct sip_product *)
+ 		    malloc(sizeof(struct sip_product), M_DEVBUF, M_NOWAIT);
+ 		memcpy(sip,sip_template,sizeof(struct sip_product));
+ 		sip->sip_revision = PCI_REVISION(pa->pa_class);
+ 	}
  
  	printf(": %s\n", sip->sip_name);
  
***************
*** 611,617 ****
  
  	/* Enable bus mastering. */
  	pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
! 	    pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
  	    PCI_COMMAND_MASTER_ENABLE);
  
  	/* Get it out of power save mode if needed. */
--- 631,637 ----
  
  	/* Enable bus mastering. */
  	pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
! 		pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
  	    PCI_COMMAND_MASTER_ENABLE);
  
  	/* Get it out of power save mode if needed. */
***************
*** 728,733 ****
--- 748,759 ----
  	 * in the softc.
  	 */
  	sc->sc_cfg = 0;
+ 
+ #if !defined(DP83820)
+ 	if ( SIP_SIS900_REV(sc,SIS_REV_635) || SIP_SIS900_REV(sc,SIS_REV_900B))
+ 		sc->sc_cfg |= (CFG_PESEL | CFG_RNDCNT);
+ #endif /* !defined(DP83820) */
+ 
  	(*sip->sip_variant->sipv_read_macaddr)(sc, pa, enaddr);
  
  	printf("%s: Ethernet address %s\n", sc->sc_dev.dv_xname,
***************
*** 910,915 ****
--- 936,942 ----
   fail_1:
  	bus_dmamem_free(sc->sc_dmat, &seg, rseg);
   fail_0:
+ 	free((void *)sc->sc_model,M_DEVBUF);
  	return;
  }
  
***************
*** 1406,1413 ****
  			PRINTERR(ISR_RMABT, "master abort");
  			PRINTERR(ISR_RTABT, "target abort");
  			PRINTERR(ISR_RXSOVR, "receive status FIFO overrun");
  			(void) SIP_DECL(init)(ifp);
- #undef PRINTERR
  		}
  	}
  
--- 1433,1440 ----
  			PRINTERR(ISR_RMABT, "master abort");
  			PRINTERR(ISR_RTABT, "target abort");
  			PRINTERR(ISR_RXSOVR, "receive status FIFO overrun");
+ #undef PRINTERR	
  			(void) SIP_DECL(init)(ifp);
  		}
  	}
  
***************
*** 1913,1918 ****
--- 1940,1948 ----
  	bus_space_handle_t sh = sc->sc_sh;
  	int i;
  
+ 	bus_space_write_4(st, sh, SIP_IER, 0);
+ 	bus_space_write_4(st, sh, SIP_IMR, 0);
+ 	bus_space_write_4(st, sh, SIP_RFCR, 0);
  	bus_space_write_4(st, sh, SIP_CR, CR_RST);
  
  	for (i = 0; i < SIP_TIMEOUT; i++) {
***************
*** 1964,1971 ****
  	SIP_DECL(reset)(sc);
  
  #if !defined(DP83820)
! 	if (sc->sc_model->sip_vendor == PCI_VENDOR_NS &&
! 	    sc->sc_model->sip_product == PCI_PRODUCT_NS_DP83815) {
  		/*
  		 * DP83815 manual, page 78:
  		 *    4.4 Recommended Registers Configuration
--- 1994,2000 ----
  	SIP_DECL(reset)(sc);
  
  #if !defined(DP83820)
! 	if (SIP_CHIP_MODEL(sc,PCI_VENDOR_NS,PCI_PRODUCT_NS_DP83815)) {
  		/*
  		 * DP83815 manual, page 78:
  		 *    4.4 Recommended Registers Configuration
***************
*** 2062,2068 ****
  		 * minimum (32 bytes), and we may be able to
  		 * improve performance by increasing it.
  		 */
! 		sc->sc_tx_fill_thresh = 1;
  	}
  	if (sc->sc_tx_drain_thresh == 0) {
  		/*
--- 2091,2097 ----
  		 * minimum (32 bytes), and we may be able to
  		 * improve performance by increasing it.
  		 */
! 		sc->sc_tx_fill_thresh = 64/32;
  	}
  	if (sc->sc_tx_drain_thresh == 0) {
  		/*
***************
*** 2075,2089 ****
  		 * may trash the first few outgoing packets if the
  		 * PCI bus is saturated.
  		 */
! 		sc->sc_tx_drain_thresh = 512 / 32;
  	}
  
  	/*
  	 * Initialize the prototype TXCFG register.
  	 */
! 	sc->sc_txcfg = TXCFG_ATP | TXCFG_MXDMA_512 |
  	    (sc->sc_tx_fill_thresh << TXCFG_FLTH_SHIFT) |
  	    sc->sc_tx_drain_thresh;
  	bus_space_write_4(st, sh, SIP_TXCFG, sc->sc_txcfg);
  
  	/*
--- 2104,2135 ----
  		 * may trash the first few outgoing packets if the
  		 * PCI bus is saturated.
  		 */
! 		 sc->sc_tx_drain_thresh = 512 / 32;
  	}
  
  	/*
  	 * Initialize the prototype TXCFG register.
  	 */
! 
! #if defined(DP83820)
! 	sc->sc_txcfg = TXCFG_MXDMA_512;
! 	sc->sc_rxcfg = RXCFG_MXDMA_512;
! #else
! 	if ((SIP_SIS900_REV(sc,SIS_REV_635) || 
! 	     SIP_SIS900_REV(sc,SIS_REV_900B)) &&
! 	    (bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_CFG) & CFG_EDBMASTEN)) {
! 		sc->sc_txcfg = TXCFG_MXDMA_64;
! 		sc->sc_rxcfg = RXCFG_MXDMA_64;
! 	} else {
! 		sc->sc_txcfg = TXCFG_MXDMA_512;
! 		sc->sc_rxcfg = RXCFG_MXDMA_512;
! 	}
! #endif /* DP83820 */
! 
! 	sc->sc_txcfg |= TXCFG_ATP | 
  	    (sc->sc_tx_fill_thresh << TXCFG_FLTH_SHIFT) |
  	    sc->sc_tx_drain_thresh;
+         
  	bus_space_write_4(st, sh, SIP_TXCFG, sc->sc_txcfg);
  
  	/*
***************
*** 2098,2116 ****
  		 * set this value lower than 2; 14 bytes are required to
  		 * filter the packet).
  		 */
! 		sc->sc_rx_drain_thresh = RXCFG_DRTH >> RXCFG_DRTH_SHIFT;
  	}
  
  	/*
  	 * Initialize the prototype RXCFG register.
  	 */
! 	sc->sc_rxcfg = RXCFG_MXDMA_512 |
! 	    (sc->sc_rx_drain_thresh << RXCFG_DRTH_SHIFT);
  	bus_space_write_4(st, sh, SIP_RXCFG, sc->sc_rxcfg);
  
- 	/* Set up the receive filter. */
- 	(*sc->sc_model->sip_variant->sipv_set_filter)(sc);
- 
  #ifdef DP83820
  	/*
  	 * Initialize the VLAN/IP receive control register.
--- 2144,2159 ----
  		 * set this value lower than 2; 14 bytes are required to
  		 * filter the packet).
  		 */
! 		 sc->sc_rx_drain_thresh = RXCFG_DRTH >> RXCFG_DRTH_SHIFT ;
! 		 /* sc->sc_rx_drain_thresh = 32/8 ; */
  	}
  
  	/*
  	 * Initialize the prototype RXCFG register.
  	 */
! 	sc->sc_rxcfg |= (sc->sc_rx_drain_thresh << RXCFG_DRTH_SHIFT);
  	bus_space_write_4(st, sh, SIP_RXCFG, sc->sc_rxcfg);
  
  #ifdef DP83820
  	/*
  	 * Initialize the VLAN/IP receive control register.
***************
*** 2160,2165 ****
--- 2203,2211 ----
  	    ISR_TXURN|ISR_TXDESC|ISR_RXORN|ISR_RXIDLE|ISR_RXDESC;
  	bus_space_write_4(st, sh, SIP_IMR, sc->sc_imr);
  
+ 	/* Set up the receive filter. */
+ 	(*sc->sc_model->sip_variant->sipv_set_filter)(sc);
+ 
  	/*
  	 * Set the current media.  Do this after initializing the prototype
  	 * IMR, since sip_mii_statchg() modifies the IMR for 802.3x flow
***************
*** 2418,2424 ****
  	struct ether_multi *enm;
  	u_int8_t *cp;
  	struct ether_multistep step;
! 	u_int32_t crc, mchash[8];
  
  	/*
  	 * Initialize the prototype RFCR.
--- 2464,2470 ----
  	struct ether_multi *enm;
  	u_int8_t *cp;
  	struct ether_multistep step;
! 	u_int32_t crc, mchash[16];
  
  	/*
  	 * Initialize the prototype RFCR.
***************
*** 2456,2465 ****
  			goto allmulti;
  		}
  
! 		crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
  
! 		/* Just want the 7 most significant bits. */
! 		crc >>= 25;
  
  		/* Set the corresponding bit in the hash table. */
  		mchash[crc >> 4] |= 1 << (crc & 0xf);
--- 2502,2516 ----
  			goto allmulti;
  		}
  
! 		/* Huh? Hash table must be big endian? */
! 		crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN);
  
! 		/* Just want the 7 or 8 most significant bits. */
! 		if ( SIP_SIS900_REV(sc,SIS_REV_635) ||
! 		     SIP_SIS900_REV(sc,SIS_REV_900B))
! 			crc >>= 24;
! 		else
! 			crc >>= 25;
  
  		/* Set the corresponding bit in the hash table. */
  		mchash[crc >> 4] |= 1 << (crc & 0xf);
***************
*** 2501,2506 ****
--- 2552,2568 ----
  		FILTER_EMIT(RFCR_RFADDR_MC5, mchash[5]);
  		FILTER_EMIT(RFCR_RFADDR_MC6, mchash[6]);
  		FILTER_EMIT(RFCR_RFADDR_MC7, mchash[7]);
+ 		if ( SIP_SIS900_REV(sc,SIS_REV_635) ||
+ 		     SIP_SIS900_REV(sc,SIS_REV_900B)) {
+ 			FILTER_EMIT(RFCR_RFADDR_MC8, mchash[8]);
+ 			FILTER_EMIT(RFCR_RFADDR_MC9, mchash[9]);
+ 			FILTER_EMIT(RFCR_RFADDR_MC10, mchash[10]);
+ 			FILTER_EMIT(RFCR_RFADDR_MC11, mchash[11]);
+ 			FILTER_EMIT(RFCR_RFADDR_MC12, mchash[12]);
+ 			FILTER_EMIT(RFCR_RFADDR_MC13, mchash[13]);
+ 			FILTER_EMIT(RFCR_RFADDR_MC14, mchash[14]);
+ 			FILTER_EMIT(RFCR_RFADDR_MC15, mchash[15]);
+ 		} 
  	}
  #undef FILTER_EMIT
  
***************
*** 2760,2768 ****
  
  	/*
  	 * The SiS 900 has only an internal PHY on the MII.  Only allow
! 	 * MII address 0.
  	 */
! 	if (sc->sc_model->sip_product == PCI_PRODUCT_SIS_900 && phy != 0)
  		return (0);
  
  	bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_ENPHY,
--- 2822,2832 ----
  
  	/*
  	 * The SiS 900 has only an internal PHY on the MII.  Only allow
! 	 * MII address 0.  However, the revisions integrated into SiS
! 	 * 635/735 do.
  	 */
! 	if (SIP_CHIP_MODEL(sc,PCI_VENDOR_SIS,PCI_PRODUCT_SIS_900) &&
! 	    sc->sc_model->sip_revision < SIS_REV_635 && phy != 0)
  		return (0);
  
  	bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_ENPHY,
***************
*** 2787,2795 ****
  
  	/*
  	 * The SiS 900 has only an internal PHY on the MII.  Only allow
! 	 * MII address 0.
  	 */
! 	if (sc->sc_model->sip_product == PCI_PRODUCT_SIS_900 && phy != 0)
  		return;
  
  	bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_ENPHY,
--- 2851,2861 ----
  
  	/*
  	 * The SiS 900 has only an internal PHY on the MII.  Only allow
! 	 * MII address 0.  However, the revisions integrated into SiS
! 	 * 635/735 do.
  	 */
! 	if (SIP_CHIP_MODEL(sc,PCI_VENDOR_SIS,PCI_PRODUCT_SIS_900) &&
! 	    sc->sc_model->sip_revision < SIS_REV_635 && phy != 0)
  		return;
  
  	bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_ENPHY,
***************
*** 2839,2846 ****
--- 2905,2915 ----
  		flowctl = 0;
  	}
  
+ 	/*  If we have not properly set these values, don't emit them */
+ 	if ( sc->sc_txcfg & TXCFG_ATP ) {
  	bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_TXCFG, sc->sc_txcfg);
  	bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_RXCFG, sc->sc_rxcfg);
+         }
  	bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_IMR, sc->sc_imr);
  	bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_FLOWCTL, flowctl);
  }
***************
*** 2992,2997 ****
--- 3061,3067 ----
  	case SIS_REV_630S:
  	case SIS_REV_630E:
  	case SIS_REV_630EA1:
+ 	case SIS_REV_635:
  		/*
  		 * The MAC address for the on-board Ethernet of
  		 * the SiS 630 chipset is in the NVRAM.  Kick
--------------------------------------------------------------------------
>Release-Note:
>Audit-Trail:
>Unformatted: