if_sk no PHY found, next iteration

Juergen Lock nox at jelal.kn-bremen.de
Wed Aug 10 23:10:58 GMT 2005


On Wed, Aug 10, 2005 at 09:19:41PM +0000, Bjoern A. Zeeb wrote:
> On Wed, 10 Aug 2005, Juergen Lock wrote:
> 
> Hi,
> 
> > Thanks for the info on your http://sources.zabbadoz.net/freebsd/if_sk.html
> > page.  Here is a dmesg snippet of another sk problem (Asus A8V deluxe,
> > 5.4-R amd64):
> >
> > skc0: <Marvell Gigabit Ethernet> port 0xa000-0xa0ff mem 0xfba00000-0xfba03fff irq 17 at device 10.0 on pci0
> > skc0: Reserved 0x4000 bytes for rid 0x10 type 3 at 0xfba00000
> > skc0: Marvell Yukon Lite Gigabit Ethernet rev. (0x9)
> > sk0: <Marvell Semiconductor, Inc. Yukon> on skc0
> > sk0: bpf attached
> > sk0: Ethernet address: 00:11:d8:a9:d5:6d
> > skc0: no PHY found!
> > device_attach: sk0 attach returned 6
> > skc0: [MPSAFE]
> >
> >  Under TODO you have `unkown rev. 0x9 for Yukon Lite', seems this is it?
> > Btw i also installed xp on the box and for that i had to fetch the
> > latest driver off the marvell.com site too (yk51x86.sys), the one
> > distributed by Asus didnt work. (nice, eh?)  Linux's sk98lin driver
> > (2.6.11 kernel) seems to have no problems tho.
> >
> >  Any patches/info welcome...
> 
> I am currently fixing another problem but in the meantime you can use
> this one which should:
> 
> * fix your problem
> * catch a bus attach error
> * improve locking
> 
> http://sources.zabbadoz.net/freebsd/patchset/EXPERIMENTAL/if_sk.c-rev1.108.diff
Thanx.  I had to MFC it, but it seems to get the nic working.
I haven't tested networking extensively yet tho. (will do that later :)

 boot -v dmesg:

skc0: <Marvell Gigabit Ethernet> port 0xa000-0xa0ff mem 0xfba00000-0xfba03fff irq 17 at device 10.0 on pci0
skc0: Reserved 0x4000 bytes for rid 0x10 type 3 at 0xfba00000
skc0: interrupt moderation is 100 us
skc0: Marvell Yukon Lite Gigabit Ethernet rev. (0x9)
skc0: PN: Yukon 88E8001
skc0: EC: Rev. 1.3
skc0: MN: Marvell
skc0: SN: AbCdEfG334454
skc0: chip ver  = 0xb1
skc0: chip rev  = 0x09
skc0: SK_EPROM0 = 0x10
skc0: SRAM size = 0x010000
sk0: <Marvell Semiconductor, Inc. Yukon> on skc0
sk0: bpf attached
sk0: Ethernet address: 00:11:d8:a9:d5:6d
miibus0: <MII bus> on sk0
e1000phy0: <Marvell 88E1000 Gigabit PHY> on miibus0
e1000phy0:  10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, 1000baseTX-FDX, auto
skc0: [MPSAFE]

 Diff against RELENG_5_4_0_RELEASE:

Index: if_sk.c
===================================================================
RCS file: /home/ncvs/src/sys/pci/if_sk.c,v
retrieving revision 1.83.2.9
diff -u -r1.83.2.9 if_sk.c
--- if_sk.c	28 Mar 2005 16:21:16 -0000	1.83.2.9
+++ if_sk.c	10 Aug 2005 22:54:19 -0000
@@ -94,12 +94,14 @@
 #include <sys/module.h>
 #include <sys/socket.h>
 #include <sys/queue.h>
+#include <sys/sysctl.h>
 
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <net/ethernet.h>
 #include <net/if_dl.h>
 #include <net/if_media.h>
+#include <net/if_types.h>
 
 #include <net/bpf.h>
 
@@ -195,8 +197,10 @@
 static int sk_encap(struct sk_if_softc *, struct mbuf *,
 					u_int32_t *);
 static void sk_start(struct ifnet *);
+static void sk_start_locked(struct ifnet *);
 static int sk_ioctl(struct ifnet *, u_long, caddr_t);
 static void sk_init(void *);
+static void sk_init_locked(struct sk_if_softc *);
 static void sk_init_xmac(struct sk_if_softc *);
 static void sk_init_yukon(struct sk_if_softc *);
 static void sk_stop(struct sk_if_softc *);
@@ -242,6 +246,9 @@
 static void sk_setmulti(struct sk_if_softc *);
 static void sk_setpromisc(struct sk_if_softc *);
 
+static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high);
+static int sysctl_hw_sk_int_mod(SYSCTL_HANDLER_ARGS);
+
 #ifdef SK_USEIOSPACE
 #define SK_RES		SYS_RES_IOPORT
 #define SK_RID		SK_PCI_LOIO
@@ -474,6 +481,7 @@
 		free(sc->sk_vpd_readonly, M_DEVBUF);
 	sc->sk_vpd_prodname = NULL;
 	sc->sk_vpd_readonly = NULL;
+	sc->sk_vpd_readonly_len = 0;
 
 	sk_vpd_read_res(sc, &res, pos);
 
@@ -491,10 +499,12 @@
 
 	pos += sizeof(res);
 	sc->sk_vpd_prodname = malloc(res.vr_len + 1, M_DEVBUF, M_NOWAIT);
-	for (i = 0; i < res.vr_len; i++)
-		sc->sk_vpd_prodname[i] = sk_vpd_readbyte(sc, i + pos);
-	sc->sk_vpd_prodname[i] = '\0';
-	pos += i;
+	if (sc->sk_vpd_prodname != NULL) {
+		for (i = 0; i < res.vr_len; i++)
+			sc->sk_vpd_prodname[i] = sk_vpd_readbyte(sc, i + pos);
+		sc->sk_vpd_prodname[i] = '\0';
+	}
+	pos += res.vr_len;
 
 	sk_vpd_read_res(sc, &res, pos);
 
@@ -508,6 +518,7 @@
 	sc->sk_vpd_readonly = malloc(res.vr_len, M_DEVBUF, M_NOWAIT);
 	for (i = 0; i < res.vr_len; i++)
 		sc->sk_vpd_readonly[i] = sk_vpd_readbyte(sc, i + pos);
+	sc->sk_vpd_readonly_len = res.vr_len;
 
 	return;
 }
@@ -790,6 +801,7 @@
 	struct ifmultiaddr	*ifma;
 	u_int8_t		dummy[] = { 0, 0, 0, 0, 0 ,0 };
 
+	SK_IF_LOCK_ASSERT(sc_if);
 
 	/* First, zot all the existing filters. */
 	switch(sc->sk_type) {
@@ -877,6 +889,8 @@
 	struct sk_softc		*sc = sc_if->sk_softc;
 	struct ifnet		*ifp = &sc_if->arpcom.ac_if;
 
+	SK_IF_LOCK_ASSERT(sc_if);
+
 	switch(sc->sk_type) {
 	case SK_GENESIS:
 		if (ifp->if_flags & IFF_PROMISC) {
@@ -1086,15 +1100,16 @@
 sk_free_jumbo_mem(sc_if)
 	struct sk_if_softc	*sc_if;
 {
-	int			retval = 0;
 	struct sk_jpool_entry	*entry;
 
 	SK_JLIST_LOCK(sc_if);
 
-	/* Wait for the "inuse" list to drain. */
-	if (!SLIST_EMPTY(&sc_if->sk_jinuse_listhead))
-		retval = msleep(sc_if, &sc_if->sk_jlist_mtx, PZERO,
-			"skfjm", 5 * hz);
+	/* We cannot release external mbuf storage while in use. */
+	if (!SLIST_EMPTY(&sc_if->sk_jinuse_listhead)) {
+		printf("sk%d: will leak jumbo buffer memory!\n", sc_if->sk_unit);
+		SK_JLIST_UNLOCK(sc_if);
+		return;
+	}
 
 	while (!SLIST_EMPTY(&sc_if->sk_jfree_listhead)) {
 		entry = SLIST_FIRST(&sc_if->sk_jfree_listhead);
@@ -1230,13 +1245,15 @@
 
 	switch(command) {
 	case SIOCSIFMTU:
+		SK_IF_LOCK(sc_if);
 		if (ifr->ifr_mtu > SK_JUMBO_MTU)
 			error = EINVAL;
 		else {
 			ifp->if_mtu = ifr->ifr_mtu;
 			ifp->if_flags &= ~IFF_RUNNING;
-			sk_init(sc_if);
+			sk_init_locked(sc_if);
 		}
+		SK_IF_UNLOCK(sc_if);
 		break;
 	case SIOCSIFFLAGS:
 		SK_IF_LOCK(sc_if);
@@ -1248,7 +1265,7 @@
 					sk_setmulti(sc_if);
 				}
 			} else
-				sk_init(sc_if);
+				sk_init_locked(sc_if);
 		} else {
 			if (ifp->if_flags & IFF_RUNNING)
 				sk_stop(sc_if);
@@ -1259,12 +1276,12 @@
 		break;
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
+		SK_IF_LOCK(sc_if);
 		if (ifp->if_flags & IFF_RUNNING) {
-			SK_IF_LOCK(sc_if);
 			sk_setmulti(sc_if);
-			SK_IF_UNLOCK(sc_if);
 			error = 0;
 		}
+		SK_IF_UNLOCK(sc_if);
 		break;
 	case SIOCGIFMEDIA:
 	case SIOCSIFMEDIA:
@@ -1343,7 +1360,10 @@
 	 * register represents 18.825ns, so to specify a timeout in
 	 * microseconds, we have to multiply by 54.
 	 */
-	sk_win_write_4(sc, SK_IMTIMERINIT, SK_IM_USECS(200));
+	if (bootverbose)
+		printf("skc%d: interrupt moderation is %d us\n",
+		    sc->sk_unit, sc->sk_int_mod);
+	sk_win_write_4(sc, SK_IMTIMERINIT, SK_IM_USECS(sc->sk_int_mod));
 	sk_win_write_4(sc, SK_IMMR, SK_ISR_TX1_S_EOF|SK_ISR_TX2_S_EOF|
 	    SK_ISR_RX1_EOF|SK_ISR_RX2_EOF);
 	sk_win_write_1(sc, SK_IMTIMERCTL, SK_IMCTL_START);
@@ -1609,6 +1629,25 @@
 		goto fail;
 	}
 
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+		OID_AUTO, "int_mod", CTLTYPE_INT|CTLFLAG_RW,
+		&sc->sk_int_mod, 0, sysctl_hw_sk_int_mod, "I",
+		"SK interrupt moderation");
+
+	/* Pull in device tunables. */
+	sc->sk_int_mod = SK_IM_DEFAULT;
+	error = resource_int_value(device_get_name(dev), unit,
+		"int_mod", &sc->sk_int_mod);
+	if (error == 0) {
+		if (sc->sk_int_mod < SK_IM_MIN ||
+		    sc->sk_int_mod > SK_IM_MAX) {
+			printf("skc%d: int_mod value out of range; "
+			    "using default: %d\n", unit, SK_IM_DEFAULT);
+			sc->sk_int_mod = SK_IM_DEFAULT;
+		}
+	}
+
 	/* Reset the adapter. */
 	sk_reset(sc);
 
@@ -1639,7 +1678,7 @@
 			break;
 		default:
 			printf("skc%d: unknown ram size: %d\n",
-			    sc->sk_unit, sk_win_read_1(sc, SK_EPROM0));
+			    sc->sk_unit, skrs);
 			error = ENXIO;
 			goto fail;
 		}
@@ -1752,16 +1791,74 @@
 		revstr = "";
 	}
 
-	/* Announce the product name. */
-	device_printf(dev, "%s rev. %s(0x%x)\n", pname, revstr, sc->sk_rev);
+	/* Announce the product name and more VPD data if there. */
+	device_printf(dev, "%s rev. %s(0x%x)\n",
+		pname != NULL ? pname : "<unknown>", revstr, sc->sk_rev);
+
+	if (bootverbose) {
+		if (sc->sk_vpd_readonly != NULL &&
+		    sc->sk_vpd_readonly_len != 0) {
+			char buf[256];
+			char *dp = sc->sk_vpd_readonly;
+			uint16_t l, len = sc->sk_vpd_readonly_len;
+
+			while (len >= 3) {
+				if ((*dp == 'P' && *(dp+1) == 'N') ||
+				    (*dp == 'E' && *(dp+1) == 'C') ||
+				    (*dp == 'M' && *(dp+1) == 'N') ||
+				    (*dp == 'S' && *(dp+1) == 'N')) {
+					l = 0;
+					while (l < *(dp+2)) {
+						buf[l] = *(dp+3+l);
+						++l;
+					}
+					buf[l] = '\0';
+					device_printf(dev, "%c%c: %s\n",
+					    *dp, *(dp+1), buf);
+					len -= (3 + l);
+					dp += (3 + l);
+				} else {
+					len -= (3 + *(dp+2));
+					dp += (3 + *(dp+2));
+				}
+			}
+		}
+		device_printf(dev, "chip ver  = 0x%02x\n", sc->sk_type);
+		device_printf(dev, "chip rev  = 0x%02x\n", sc->sk_rev);
+		device_printf(dev, "SK_EPROM0 = 0x%02x\n", skrs);
+		device_printf(dev, "SRAM size = 0x%06x\n", sc->sk_ramsize);
+	}
+
 	sc->sk_devs[SK_PORT_A] = device_add_child(dev, "sk", -1);
+	if (sc->sk_devs[SK_PORT_A] == NULL) {
+		device_printf(dev, "failed to add child for PORT_A\n");
+		error = ENXIO;
+		goto fail;
+	}
 	port = malloc(sizeof(int), M_DEVBUF, M_NOWAIT);
+	if (port == NULL) {
+		device_printf(dev, "failed to allocate memory for "
+		    "ivars of PORT_A\n");
+		error = ENXIO;
+		goto fail;
+	}
 	*port = SK_PORT_A;
 	device_set_ivars(sc->sk_devs[SK_PORT_A], port);
 
 	if (!(sk_win_read_1(sc, SK_CONFIG) & SK_CONFIG_SINGLEMAC)) {
 		sc->sk_devs[SK_PORT_B] = device_add_child(dev, "sk", -1);
+		if (sc->sk_devs[SK_PORT_B] == NULL) {
+			device_printf(dev, "failed to add child for PORT_B\n");
+			error = ENXIO;
+			goto fail;
+		}
 		port = malloc(sizeof(int), M_DEVBUF, M_NOWAIT);
+		if (port == NULL) {
+			device_printf(dev, "failed to allocate memory for "
+			    "ivars of PORT_B\n");
+			error = ENXIO;
+			goto fail;
+		}
 		*port = SK_PORT_B;
 		device_set_ivars(sc->sk_devs[SK_PORT_B], port);
 	}
@@ -1769,7 +1866,11 @@
 	/* Turn on the 'driver is loaded' LED. */
 	CSR_WRITE_2(sc, SK_LED, SK_LED_GREEN_ON);
 
-	bus_generic_attach(dev);
+	error = bus_generic_attach(dev);
+	if (error) {
+		device_printf(dev, "failed to attach port(s)\n");
+		goto fail;
+	}
 
 	/* Hook interrupt last to avoid having to lock softc */
 	error = bus_setup_intr(dev, sc->sk_irq, INTR_TYPE_NET|INTR_MPSAFE,
@@ -1930,6 +2031,21 @@
 sk_start(ifp)
 	struct ifnet		*ifp;
 {
+	struct sk_if_softc *sc_if;
+
+	sc_if = ifp->if_softc;
+
+	SK_IF_LOCK(sc_if);
+	sk_start_locked(ifp);
+	SK_IF_UNLOCK(sc_if);
+
+	return;
+}
+
+static void
+sk_start_locked(ifp)
+	struct ifnet		*ifp;
+{
         struct sk_softc		*sc;
         struct sk_if_softc	*sc_if;
         struct mbuf		*m_head = NULL;
@@ -1938,7 +2054,7 @@
 	sc_if = ifp->if_softc;
 	sc = sc_if->sk_softc;
 
-	SK_IF_LOCK(sc_if);
+	SK_IF_LOCK_ASSERT(sc_if);
 
 	idx = sc_if->sk_cdata.sk_tx_prod;
 
@@ -1973,7 +2089,6 @@
 		/* Set a timeout in case the chip goes out to lunch. */
 		ifp->if_timer = 5;
 	}
-	SK_IF_UNLOCK(sc_if);
 
 	return;
 }
@@ -1988,8 +2103,10 @@
 	sc_if = ifp->if_softc;
 
 	printf("sk%d: watchdog timeout\n", sc_if->sk_unit);
+	SK_IF_LOCK(sc_if);
 	ifp->if_flags &= ~IFF_RUNNING;
-	sk_init(sc_if);
+	sk_init_locked(sc_if);
+	SK_IF_UNLOCK(sc_if);
 
 	return;
 }
@@ -2358,9 +2475,9 @@
 	CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask);
 
 	if (ifp0 != NULL && !IFQ_DRV_IS_EMPTY(&ifp0->if_snd))
-		sk_start(ifp0);
+		sk_start_locked(ifp0);
 	if (ifp1 != NULL && !IFQ_DRV_IS_EMPTY(&ifp1->if_snd))
-		sk_start(ifp1);
+		sk_start_locked(ifp1);
 
 	SK_UNLOCK(sc);
 
@@ -2546,7 +2663,7 @@
 	ifp = &sc_if->arpcom.ac_if;
 
 	if (sc->sk_type == SK_YUKON_LITE &&
-	    sc->sk_rev == SK_YUKON_LITE_REV_A3) {
+	    sc->sk_rev >= SK_YUKON_LITE_REV_A3) {
 		/* Take PHY out of reset. */
 		sk_win_write_4(sc, SK_GPIO,
 			(sk_win_read_4(sc, SK_GPIO) | SK_GPIO_DIR9) & ~SK_GPIO_DAT9);
@@ -2650,21 +2767,32 @@
 	void			*xsc;
 {
 	struct sk_if_softc	*sc_if = xsc;
+
+	SK_IF_LOCK(sc_if);
+	sk_init_locked(sc_if);
+	SK_IF_UNLOCK(sc_if);
+
+	return;
+}
+
+static void
+sk_init_locked(sc_if)
+	struct sk_if_softc	*sc_if;
+{
 	struct sk_softc		*sc;
 	struct ifnet		*ifp;
 	struct mii_data		*mii;
 	u_int16_t		reg;
+	u_int32_t		imr;
 
-	SK_IF_LOCK(sc_if);
+	SK_IF_LOCK_ASSERT(sc_if);
 
 	ifp = &sc_if->arpcom.ac_if;
 	sc = sc_if->sk_softc;
 	mii = device_get_softc(sc_if->sk_miibus);
 
-	if (ifp->if_flags & IFF_RUNNING) {
-		SK_IF_UNLOCK(sc_if);
+	if (ifp->if_flags & IFF_RUNNING)
 		return;
-	}
 
 	/* Cancel pending I/O and free all RX/TX buffers. */
 	sk_stop(sc_if);
@@ -2746,11 +2874,21 @@
 		printf("sk%d: initialization failed: no "
 		    "memory for rx buffers\n", sc_if->sk_unit);
 		sk_stop(sc_if);
-		SK_IF_UNLOCK(sc_if);
 		return;
 	}
 	sk_init_tx_ring(sc_if);
 
+	/* Set interrupt moderation if changed via sysctl. */
+	/* SK_LOCK(sc); */
+	imr = sk_win_read_4(sc, SK_IMTIMERINIT);
+	if (imr != SK_IM_USECS(sc->sk_int_mod)) {
+		sk_win_write_4(sc, SK_IMTIMERINIT, SK_IM_USECS(sc->sk_int_mod));
+		if (bootverbose)
+			printf("skc%d: interrupt moderation is %d us\n",
+			    sc->sk_unit, sc->sk_int_mod);
+	}
+	/* SK_UNLOCK(sc); */
+
 	/* Configure interrupt handling */
 	CSR_READ_4(sc, SK_ISSR);
 	if (sc_if->sk_port == SK_PORT_A)
@@ -2783,8 +2921,6 @@
 	ifp->if_flags |= IFF_RUNNING;
 	ifp->if_flags &= ~IFF_OACTIVE;
 
-	SK_IF_UNLOCK(sc_if);
-
 	return;
 }
 
@@ -2796,7 +2932,7 @@
 	struct sk_softc		*sc;
 	struct ifnet		*ifp;
 
-	SK_IF_LOCK(sc_if);
+	SK_IF_LOCK_ASSERT(sc_if);
 	sc = sc_if->sk_softc;
 	ifp = &sc_if->arpcom.ac_if;
 
@@ -2867,6 +3003,29 @@
 	}
 
 	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
-	SK_IF_UNLOCK(sc_if);
+
 	return;
 }
+
+static int
+sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high)
+{
+	int error, value;
+
+	if (!arg1)
+		return (EINVAL);
+	value = *(int *)arg1;
+	error = sysctl_handle_int(oidp, &value, 0, req);
+	if (error || !req->newptr)
+		return (error);
+	if (value < low || value > high)
+		return (EINVAL);
+	*(int *)arg1 = value;
+	return (0);
+}
+
+static int
+sysctl_hw_sk_int_mod(SYSCTL_HANDLER_ARGS)
+{
+	return (sysctl_int_range(oidp, arg1, arg2, req, SK_IM_MIN, SK_IM_MAX));
+}
Index: if_skreg.h
===================================================================
RCS file: /home/ncvs/src/sys/pci/if_skreg.h,v
retrieving revision 1.20.2.5
diff -u -r1.20.2.5 if_skreg.h
--- if_skreg.h	28 Mar 2005 16:21:16 -0000	1.20.2.5
+++ if_skreg.h	10 Aug 2005 22:23:38 -0000
@@ -376,6 +376,10 @@
 #define SK_IMTIMER_TICKS	54
 #define SK_IM_USECS(x)		((x) * SK_IMTIMER_TICKS)
 
+#define	SK_IM_MIN	10
+#define	SK_IM_DEFAULT	100
+#define	SK_IM_MAX	10000
+
 /*
  * The SK_EPROM0 register contains a byte that describes the
  * amount of SRAM mounted on the NIC. The value also tells if
@@ -1437,10 +1441,12 @@
 	u_int8_t		spare;
 	char			*sk_vpd_prodname;
 	char			*sk_vpd_readonly;
+	uint16_t		sk_vpd_readonly_len;
 	u_int32_t		sk_rboff;	/* RAMbuffer offset */
 	u_int32_t		sk_ramsize;	/* amount of RAM on NIC */
 	u_int32_t		sk_pmd;		/* physical media type */
 	u_int32_t		sk_intrmask;
+	int			sk_int_mod;
 	struct sk_if_softc	*sk_if[2];
 	device_t		sk_devs[2];
 	struct mtx		sk_mtx;


More information about the freebsd-stable mailing list