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-amd64
mailing list