Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 27 Dec 2011 18:18:51 +0100
From:      Stefan Bethke <stb@lassitu.de>
To:        Adrian Chadd <adrian@freebsd.org>
Cc:        Oleksandr Tymoshenko <gonzo@freebsd.org>, "freebsd-embedded@freebsd.org" <freebsd-embedded@freebsd.org>
Subject:   Re: Updated switch/glue patch?
Message-ID:  <267FB3D6-830E-4A2F-8C1C-A96873EDCD31@lassitu.de>
In-Reply-To: <FC8A0B08-5292-44CC-AEC0-08BF170FCEA4@lassitu.de>
References:  <CAJ-Vmon8%2BOXQ4g752zZEB-O0BR0sFWO0QUvw--xp2jsBDkx6tQ@mail.gmail.com> <0F6CC18F-6973-42A2-AC03-F01BF59458AE@lassitu.de> <CAJ-Vmo=Y8pp4iFnw%2B1hcPae6QXFboz=a7puwgC1kVSZ3JwMgPQ@mail.gmail.com> <1100F70E-9DA9-4163-AC9A-423ECE5AA9A3@lassitu.de> <CAJ-VmonrnJ7cC6u2LsL9AGusz_%2BkSwY62Rr1__sg5U_NynJ1SQ@mail.gmail.com> <CAJ-Vmo=WSN1oLM=B2HqSHrWyOaOD9BSwwu8=1Wys0CLRJ_N-TA@mail.gmail.com> <C637C171-A1A2-4296-84FA-6DE97137DC42@lassitu.de> <CAJ-Vmon2boy7OCh_4O0MeCi0yCdZu0OYb5dxHCEK=-%2B46zBGtg@mail.gmail.com> <CAJ-Vmoku5eLEYi5_DXVxK=0=4Ewn2aGepv3YUw4ApuVh_7y2%2Bw@mail.gmail.com> <CAJ-VmonvpnaS1rAO%2BsDRh1E5WfsrZTYE297Kc96prhfKjrM89Q@mail.gmail.com> <CAJ-VmokQxQs2DUKL=ONyxnnS7Q28ytmwZJ_thqvc4SvMkmS=cQ@mail.gmail.com> <18CABB46-9B9A-41CB-8742-6723C5FF4D67@lassitu.de> <C0BF20FD-E30F-4E9C-A0FE-500BE4807B99@bsdimp.com> <CAJ-VmokgiQCEG4et3X=3o_MuCMkO9MqkKqa-fjdpEqQNucn=Lw@mail.gmail.com> <2CBD8651-E132-49DC-A082-37A8F5C626EA@bsdimp.com> <AFE755D6-E462-40B4-A97B-9261303B3A4F@lassitu.de> <09670C 34-0D30-46BC-BA7E-4AAA22193B61@lassitu.de> <CAJ-VmokwSHN8U2=HJQT9kxFQ9oE-6H2h3KDb%2BMHN1Z8sur9=yw@mail.gmail.com> <45529EC2-73BE-4F69-A9BE-E22D9FEAADD7@lassitu.de> <CAJ-VmonmMASxJZBAd2doX4eV6s5TF-3kCB0pLSMrWM8r0UsCmg@mail.gmail.com> <FC8A0B08-5292-44CC-AEC0-08BF170FCEA4@lassitu.de>

next in thread | previous in thread | raw e-mail | index | archive | help

--Apple-Mail=_8BCC333A-BF48-41F3-90E3-140840423ED9
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=us-ascii


Am 27.12.2011 um 01:07 schrieb Stefan Bethke:

> Am 26.12.2011 um 21:46 schrieb Adrian Chadd:
>=20
>> Hi,
>>=20
>> I've tested the two patches.
>>=20
>> * the iicbb patch is fine at first glance, but I haven't yet sat down
>> to figure out whether it's fine for older (and non-rtl8366rb) =
devices.
>> I'll commit it to my repo, so you can just pull it into yours.
>> We should likely change it to default to 10uS to preserve behaviour
>> and then override it in hints (hint.iicbb.0.udelay=3D3) for this
>> particular board.
>>=20
>> * the rtl8366rb change however applied and compiled, but it has
>> completely broken things. I don't get any port status updates and
>> etherswitchcfg doesn't actually return any configuration. Would you
>> mind retesting all of that?
>=20
> Here's a slightly updated patch (pushed to =
https://gitorious.org/~stb/freebsd/stb-adrianchadd-freebsd-work/commits/wo=
rk/ath):

Another update:


--Apple-Mail=_8BCC333A-BF48-41F3-90E3-140840423ED9
Content-Disposition: attachment;
	filename=rtl8366rb.patch
Content-Type: application/octet-stream;
	name="rtl8366rb.patch"
Content-Transfer-Encoding: 7bit

diff --git a/sbin/etherswitchcfg/etherswitchcfg.8 b/sbin/etherswitchcfg/etherswitchcfg.8
index de43a26..538950c 100644
--- a/sbin/etherswitchcfg/etherswitchcfg.8
+++ b/sbin/etherswitchcfg/etherswitchcfg.8
@@ -11,10 +11,18 @@
 .Ar info
 .Nm
 .Op Fl "f control file"
+.Ar phy
+.Ar phy.register[=value]
+.Nm
+.Op Fl "f control file"
 .Ar port%d
 .Ar command parameter
 .Nm
 .Op Fl "f control file"
+.Ar reg
+.Ar register[=value]
+.Nm
+.Op Fl "f control file"
 .Ar vlangroup%d
 .Ar command parameter
 .Sh DESCRIPTION
@@ -23,27 +31,55 @@ The
 utility is used to configure an Ethernet switch built into the system.
 .Nm
 accepts a number of options:
-.Bl -tag -width Fl "f control file" -compact
+.Bl -tag -width ".Fl f" -compact
 .It Fl "f control file"
 Specifies the
 .Xr etherswitch 4
 control file that represents the switch to be configured.
+It defaults to
+.Li /dev/etherswitch0 .
+.It Fl m
+When reporting port information, also list available media options for
+that port.
 .It Fl v
 Produce more verbose output.
 Without this flag, lines that represent inactive or empty configuration
 options are omitted.
 .El
+.Ss phy
+The phy command provides access to the registers of the PHYs attached
+to or integrated into the switch controller.
+PHY registers are specified as phy.register,
+where
+.Ar phy
+is usually the port number, and
+.Ar register
+is the register number.
+Both can be provided as decimal, octal or hexadecimal numbers in any of the formats
+understood by
+.Xr strtol 4 .
+To set the register value, use the form instance.register=value.
 .Ss port
 The port command selects one of the ports of the switch.
 It supports the following commands:
-.Bl -tag -width Ar vlangroup number -compact
+.Bl -tag -width ".Ar vlangroup number" -compact
 .It Ar vlangroup number
 Sets the VLAN group number that is used to process incoming frames that are not tagged.
+.It Ar media mediaspec
+Specifies the physical media configuration to be configured for a port.
+.It Ar mediaopt mediaoption
+Specifies a list of media options for a port. See
+.Xr ifconfig 8
+for details on
+.Ar media and 
+.Ar mediaopt .
 .El
+.Ss reg
+The reg command provides access to the registers of the switch controller.
 .Ss vlangroup
 The vlangroup command selects one of the VLAN groups for configuration.
 It supports the following commands:
-.Bl -tag -width Ar vlangroup -compact
+.Bl -tag -width ".Ar vlangroup" -compact
 .It Ar vlan VID
 Sets the VLAN ID (802.1q VID) for this VLAN group.
 Frames transmitted on tagged member ports of this group will be tagged
diff --git a/sbin/etherswitchcfg/etherswitchcfg.c b/sbin/etherswitchcfg/etherswitchcfg.c
index 9994a3d..e6129f3 100644
--- a/sbin/etherswitchcfg/etherswitchcfg.c
+++ b/sbin/etherswitchcfg/etherswitchcfg.c
@@ -59,7 +59,8 @@ enum cmdmode {
 	MODE_NONE = 0,
 	MODE_PORT,
 	MODE_VLANGROUP,
-	MODE_REGISTER
+	MODE_REGISTER,
+	MODE_PHYREG
 };
 
 struct cfg {
@@ -105,6 +106,30 @@ write_register(struct cfg *cfg, int r, int v)
 		err(EX_OSERR, "ioctl(IOETHERSWITCHSETREG)");
 }
 
+static int
+read_phyregister(struct cfg *cfg, int phy, int reg)
+{
+	struct etherswitch_phyreg er;
+	
+	er.phy = phy;
+	er.reg = reg;
+	if (ioctl(cfg->fd, IOETHERSWITCHGETPHYREG, &er) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHGETPHYREG)");
+	return (er.val);
+}
+
+static void
+write_phyregister(struct cfg *cfg, int phy, int reg, int val)
+{
+	struct etherswitch_phyreg er;
+	
+	er.phy = phy;
+	er.reg = reg;
+	er.val = val;
+	if (ioctl(cfg->fd, IOETHERSWITCHSETPHYREG, &er) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHSETPHYREG)");
+}
+
 static void
 set_port_vlangroup(struct cfg *cfg, char *argv[])
 {
@@ -239,6 +264,29 @@ set_register(struct cfg *cfg, char *arg)
 	return (0);
 }
 
+static int
+set_phyregister(struct cfg *cfg, char *arg)
+{
+	int phy, reg, val;
+	char *c, *d;
+	
+	phy = strtol(arg, &c, 0);
+	if (c==arg)
+		return (1);
+	if (*c != '.')
+		return (1);
+	d = c+1;
+	reg = strtol(d, &c, 0);
+	if (d == c)
+		return (1);
+	if (*c == '=') {
+		val = strtol(c+1, NULL, 0);
+		write_phyregister(cfg, phy, reg, val);
+	}
+	printf("\treg %d.0x%02x=0x%04x\n", phy, reg, read_phyregister(cfg, phy, reg));
+	return (0);
+}
+
 static void
 print_port(struct cfg *cfg, int port)
 {
@@ -351,6 +399,7 @@ newmode(struct cfg *cfg, enum cmdmode mode)
 		print_vlangroup(cfg, cfg->unit);
 		break;
 	case MODE_REGISTER:
+	case MODE_PHYREG:
 		break;
 	}
 	cfg->mode = mode;
@@ -406,6 +455,8 @@ main(int argc, char *argv[])
 				if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nvlangroups)
 					errx(EX_USAGE, "port unit must be between 0 and %d", cfg.info.es_nvlangroups);
 				newmode(&cfg, MODE_VLANGROUP);
+			} else if (strcmp(argv[0], "phy") == 0) {
+				newmode(&cfg, MODE_PHYREG);
 			} else if (strcmp(argv[0], "reg") == 0) {
 				newmode(&cfg, MODE_REGISTER);
 			} else {
@@ -434,6 +485,12 @@ main(int argc, char *argv[])
 				continue;
 			}
 			break;
+		case MODE_PHYREG:
+			if (set_phyregister(&cfg, argv[0]) != 0) {
+				newmode(&cfg, MODE_NONE);
+				continue;
+			}
+			break;
 		}
 		argc--;
 		argv++;
diff --git a/sys/dev/etherswitch/etherswitch.c b/sys/dev/etherswitch/etherswitch.c
index 19b4630..9d1a865 100644
--- a/sys/dev/etherswitch/etherswitch.c
+++ b/sys/dev/etherswitch/etherswitch.c
@@ -202,6 +202,7 @@ etherswitchioctl(struct cdev *cdev, u_long cmd, caddr_t data, int flags, struct
 	device_t etherswitch = device_get_parent(dev);
 	etherswitch_info_t *info;
 	etherswitch_reg_t *reg;
+	etherswitch_phyreg_t *phyreg;
 	int error = 0;
 
 	switch (cmd) {
@@ -210,16 +211,16 @@ etherswitchioctl(struct cdev *cdev, u_long cmd, caddr_t data, int flags, struct
 		bcopy(info, data, sizeof(etherswitch_info_t));
 		break;
 		
-	case IOETHERSWITCHSETREG:
-		reg = (etherswitch_reg_t *)data;
-		error = ETHERSWITCH_WRITEREG(etherswitch, reg->reg, reg->val);
-		break;
-
 	case IOETHERSWITCHGETREG:
 		reg = (etherswitch_reg_t *)data;
 		reg->val = ETHERSWITCH_READREG(etherswitch, reg->reg);
 		break;
 	
+	case IOETHERSWITCHSETREG:
+		reg = (etherswitch_reg_t *)data;
+		error = ETHERSWITCH_WRITEREG(etherswitch, reg->reg, reg->val);
+		break;
+
 	case IOETHERSWITCHGETPORT:
 		error = ETHERSWITCH_GETPORT(etherswitch, (etherswitch_port_t *)data);
 		break;
@@ -236,6 +237,16 @@ etherswitchioctl(struct cdev *cdev, u_long cmd, caddr_t data, int flags, struct
 		error = ETHERSWITCH_SETVGROUP(etherswitch, (etherswitch_vlangroup_t *)data);
 		break;
 
+	case IOETHERSWITCHGETPHYREG:
+		phyreg = (etherswitch_phyreg_t *)data;
+		phyreg->val = ETHERSWITCH_READPHYREG(etherswitch, phyreg->phy, phyreg->reg);
+		break;
+	
+	case IOETHERSWITCHSETPHYREG:
+		phyreg = (etherswitch_phyreg_t *)data;
+		error = ETHERSWITCH_WRITEPHYREG(etherswitch, phyreg->phy, phyreg->reg, phyreg->val);
+		break;
+
 	default:
 		error = ENOTTY;
 	}
diff --git a/sys/dev/etherswitch/etherswitch.h b/sys/dev/etherswitch/etherswitch.h
index df59c12..90ecb48 100644
--- a/sys/dev/etherswitch/etherswitch.h
+++ b/sys/dev/etherswitch/etherswitch.h
@@ -18,6 +18,13 @@ struct etherswitch_reg {
 };
 typedef struct etherswitch_reg etherswitch_reg_t;
 
+struct etherswitch_phyreg {
+	uint16_t	phy;
+	uint16_t	reg;
+	uint16_t	val;
+};
+typedef struct etherswitch_phyreg etherswitch_phyreg_t;
+
 #define ETHERSWITCH_NAMEMAX	64
 
 struct etherswitch_info {
@@ -56,5 +63,7 @@ typedef struct etherswitch_vlangroup etherswitch_vlangroup_t;
 #define IOETHERSWITCHSETPORT		_IOW('i', 5, etherswitch_port_t)
 #define IOETHERSWITCHGETVLANGROUP	_IOWR('i', 6, etherswitch_vlangroup_t)
 #define IOETHERSWITCHSETVLANGROUP	_IOW('i', 7, etherswitch_vlangroup_t)
+#define IOETHERSWITCHGETPHYREG		_IOWR('i', 8, etherswitch_phyreg_t)
+#define IOETHERSWITCHSETPHYREG		_IOW('i', 9, etherswitch_phyreg_t)
 
 #endif
diff --git a/sys/dev/etherswitch/etherswitch_if.m b/sys/dev/etherswitch/etherswitch_if.m
index d704ee3..7429c04 100644
--- a/sys/dev/etherswitch/etherswitch_if.m
+++ b/sys/dev/etherswitch/etherswitch_if.m
@@ -35,6 +35,25 @@ METHOD int writereg {
 };
 
 #
+# Read PHY register
+#
+METHOD int readphyreg {
+	device_t	dev;
+	int		phy;
+	int		reg;
+};
+
+#
+# Write PHY register
+#
+METHOD int writephyreg {
+	device_t	dev;
+	int		phy;
+	int		reg;
+	int		value;
+};
+
+#
 # Get port configuration
 #
 METHOD int getport {
diff --git a/sys/dev/etherswitch/rtl8366rb.c b/sys/dev/etherswitch/rtl8366rb.c
index 6f3e378..b9ca71e 100644
--- a/sys/dev/etherswitch/rtl8366rb.c
+++ b/sys/dev/etherswitch/rtl8366rb.c
@@ -33,6 +33,7 @@
 #include <sys/module.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
+#include <sys/sysctl.h>
 #include <sys/systm.h>
 
 #include <net/if.h>
@@ -43,6 +44,7 @@
 #include <net/if_types.h>
 
 #include <machine/bus.h>
+#include <dev/iicbus/iic.h>
 #include <dev/iicbus/iiconf.h>
 #include <dev/iicbus/iicbus.h>
 #include <dev/mii/mii.h>
@@ -51,16 +53,17 @@
 #include <dev/etherswitch/etherswitch.h>
 #include <dev/etherswitch/rtl8366rbvar.h>
 
+#include "iicbus_if.h"
 #include "miibus_if.h"
 #include "etherswitch_if.h"
 
 
 struct rtl8366rb_softc {
-	struct mtx	sc_mtx;
+	struct mtx	smi_mtx;
 	device_t	dev;
-	char		*ifname[RTL8366RB_NUM_PORTS-1];
-	device_t	miibus[RTL8366RB_NUM_PORTS-1];
-	struct ifnet	*ifp[RTL8366RB_NUM_PORTS-1];
+	char		*ifname[RTL8366RB_NUM_PHYS];
+	device_t	miibus[RTL8366RB_NUM_PHYS];
+	struct ifnet	*ifp[RTL8366RB_NUM_PHYS];
 	device_t	etherswitch;
 	struct callout	callout_tick;
 };
@@ -71,10 +74,29 @@ static etherswitch_info_t etherswitch_info = {
 	.es_name =			"Realtek RTL8366RB"
 };
 
+#if 1 || defined(DEBUG)
+#define DPRINTF(dev, args...) device_printf(dev, args)
+#define DEVERR(dev, err, fmt, args...) do { \
+		if (err != 0) device_printf(dev, fmt, err, args); \
+	} while (0)
+#else
+#define DPRINTF(dev, args...)
+#define DEVERR(dev, err, fmt, args...)
+#endif
+
+static int reset_count = 0;
+static int delayed_select = 0;
+static SYSCTL_NODE(_debug, OID_AUTO, rtl8366rb, CTLFLAG_RD, 0, "rtl8366rb");
+SYSCTL_INT(_debug_rtl8366rb, OID_AUTO, reset_count, CTLFLAG_RW, &reset_count, 0,
+	"number of times the bus had to be reset due to an error");
+SYSCTL_INT(_debug_rtl8366rb, OID_AUTO, delayed_select, CTLFLAG_RW, &delayed_select, 0,
+	"number of times we had to wait for the chip to become selectable");
 
 static int smi_read(device_t dev, uint16_t addr, uint16_t *data);
+static int smi_read_lockheld(device_t dev, uint16_t addr, uint16_t *data);
 static int smi_write(device_t dev, uint16_t addr, uint16_t data);
 static int smi_rmw(device_t dev, uint16_t addr, uint16_t mask, uint16_t data);
+static void smi_reset(device_t dev);
 static void rtl8366rb_tick(void *arg);
 static int rtl8366rb_ifmedia_upd(struct ifnet *);
 static void rtl8366rb_ifmedia_sts(struct ifnet *, struct ifmediareq *);
@@ -97,7 +119,8 @@ rtl8366rb_probe(device_t dev)
 {
 	uint16_t chipid;
 	
-	if (smi_read(dev, RTL8366RB_CIR, &chipid))
+	smi_reset(dev);
+	if (smi_read_lockheld(dev, RTL8366RB_CIR, &chipid))
 		return (ENXIO);
 	if (chipid != RTL8366RB_CIR_ID8366RB)
 		return (ENXIO);
@@ -109,6 +132,10 @@ static void
 rtl8366rb_init(device_t dev)
 {
 	/* Initialisation for TL-WR1043ND */
+	smi_rmw(dev, RTL8366RB_RCR,
+		RTL8366RB_RCR_HARD_RESET,
+		RTL8366RB_RCR_HARD_RESET);
+	DELAY(100000);
 	/* Enable 16 VLAN mode */
 	smi_rmw(dev, RTL8366RB_SGCR,
 		RTL8366RB_SGCR_EN_VLAN | RTL8366RB_SGCR_EN_VLAN_4KTB,
@@ -139,8 +166,7 @@ rtl8366rb_attach(device_t dev)
 
 	sc = device_get_softc(dev);
 	sc->dev = dev;
-	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "rtl8366rb",
-	    MTX_DEF);
+	mtx_init(&sc->smi_mtx, "smi", NULL, MTX_DEF);
 	rtl8366rb_init(dev);
 	smi_read(dev, RTL8366RB_CVCR, &rev);
 	device_printf(dev, "rev. %d\n", rev & 0x000f);
@@ -148,7 +174,7 @@ rtl8366rb_attach(device_t dev)
 	/* attach miibus and phys */
 	/* PHYs need an interface, so we generate a dummy one */
 	/* The sixth port doesn't have a PHY */
-	for (i = 0; i < RTL8366RB_NUM_PORTS-1; i++) {
+	for (i = 0; i < RTL8366RB_NUM_PHYS; i++) {
 		sc->ifp[i] = if_alloc(IFT_ETHER);
 		sc->ifp[i]->if_softc = sc;
 		sc->ifp[i]->if_flags |= IFF_UP | IFF_BROADCAST | IFF_DRV_RUNNING
@@ -165,13 +191,14 @@ rtl8366rb_attach(device_t dev)
 			return (err);
 		}
 	}
+	device_printf(dev, "done attaching phys\n");
 
 	sc->etherswitch = device_add_child(dev, "etherswitch", -1);
 	err = device_probe_and_attach(sc->etherswitch);
 	if (err != 0)
 		return (err);
 	
-	callout_init_mtx(&sc->callout_tick, &sc->sc_mtx, 0);
+	callout_init(&sc->callout_tick, 1);
 	rtl8366rb_tick(sc);
 	
 	return (err);
@@ -186,7 +213,7 @@ rtl8366rb_detach(device_t dev)
 	sc = device_get_softc(dev);
 	if (sc->etherswitch)
 		device_delete_child(dev, sc->etherswitch);
-	for (i=0; i < RTL8366RB_NUM_PORTS-1; i++) {
+	for (i=0; i < RTL8366RB_NUM_PHYS; i++) {
 		if (sc->miibus[i])
 			device_delete_child(dev, sc->miibus[i]);
 		if (sc->ifp[i] != NULL)
@@ -195,11 +222,68 @@ rtl8366rb_detach(device_t dev)
 	}
 	bus_generic_detach(dev);
 	callout_drain(&sc->callout_tick);
-	mtx_destroy(&sc->sc_mtx);
+	mtx_destroy(&sc->smi_mtx);
 
 	return (0);
 }
 
+static int
+rtl8366rb_media_from_portstatus(int portstatus)
+{
+	int media;
+
+	if ((portstatus & RTL8366RB_PLSR_LINK) == 0)
+		return IFM_ETHER | IFM_NONE;
+	media = IFM_ETHER;
+	switch (portstatus & RTL8366RB_PLSR_SPEED_MASK) {
+	case RTL8366RB_PLSR_SPEED_10:
+		media |= IFM_10_T;
+		break;
+	case RTL8366RB_PLSR_SPEED_100:
+		media |= IFM_100_TX;
+		break;
+	case RTL8366RB_PLSR_SPEED_1000:
+		media |= IFM_1000_T;
+		break;
+	}
+	if ((portstatus & RTL8366RB_PLSR_FULLDUPLEX) != 0)
+		media |= IFM_FDX;
+	else
+		media |= IFM_HDX;
+	if ((portstatus & RTL8366RB_PLSR_TXPAUSE) != 0)
+		media |= IFM_ETH_TXPAUSE;
+	if ((portstatus & RTL8366RB_PLSR_RXPAUSE) != 0)
+		media |= IFM_ETH_RXPAUSE;
+	return media;
+}
+
+static void
+rtl833rb_miipollstat(struct rtl8366rb_softc *sc)
+{
+	int i;
+	struct mii_data *mii;
+	struct mii_softc *child;
+	uint16_t value;
+	int portstatus;
+
+	for (i = 0; i < RTL8366RB_NUM_PHYS; i++) {
+		mii = device_get_softc(sc->miibus[i]);
+		if ((i % 2) == 0) {
+			smi_read(sc->dev, RTL8366RB_PLSR_BASE + i/2, &value);
+			portstatus = value & 0xff;
+		} else {
+			portstatus = (value >> 8) & 0xff;
+		}
+		mii->mii_media_status = IFM_AVALID;
+		mii->mii_media_active = rtl8366rb_media_from_portstatus(portstatus);
+		LIST_FOREACH(child, &mii->mii_phys, mii_list) {
+			if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != child->mii_inst)
+				continue;
+			mii_phy_update(child, MII_POLLSTAT);
+		}
+	}	
+}
+
 static void
 rtl833rb_miipollstat(struct rtl8366rb_softc *sc)
 {
@@ -253,80 +337,161 @@ static void
 rtl8366rb_tick(void *arg)
 {
 	struct rtl8366rb_softc *sc = arg;
-	
+
 	rtl833rb_miipollstat(sc);
 	callout_reset(&sc->callout_tick, hz, rtl8366rb_tick, sc);
 }
 
+static void
+smi_reset(device_t dev)
+{
+	device_t iicbus, iicbb;
+	int i;
+	
+	DPRINTF(dev, "resetting bus\n");
+	iicbus = device_get_parent(dev);
+	iicbb = device_get_parent(iicbus);
+	iicbus_reset(iicbus, IIC_FASTEST, RTL8366RB_IIC_ADDR, NULL);
+	for (i=3; i--; ) {
+		IICBUS_STOP(iicbb);
+	}
+	reset_count++;
+}
+
 static int
-smi_read(device_t dev, uint16_t addr, uint16_t *data)
+smi_read_lockheld(device_t dev, uint16_t addr, uint16_t *data)
 {
 	int err;
-	device_t parent = device_get_parent(dev);
+	device_t iicbus = device_get_parent(dev);
 	struct iicbus_ivar *devi = IICBUS_IVAR(dev);
 	int slave = devi->addr;
 	char bytes[2];
-	int xferd;
+	int xferd, i;
 
 	bytes[0] = addr & 0xff;
 	bytes[1] = (addr >> 8) & 0xff;
-	err = iicbus_start(parent, slave | IICBUS_READ, IICBUS_TIMEOUT);
+	/*
+	 * The chip does not use clock stretching when it is busy,
+	 * instead ignoring the command. Retry a few times.
+	 */
+	for (i = RTL_IICBUS_RETRIES; i--; ) {
+		err = iicbus_start(iicbus, slave | RTL_IICBUS_READ, RTL_IICBUS_TIMEOUT);
+		if (err != IIC_ENOACK)
+			break;
+		DELAY(RTL_IICBUS_TIMEOUT);
+		delayed_select++;
+	}
 	if (err != 0)
 		goto out;
-	err = iicbus_write(parent, bytes, 2, &xferd, IICBUS_TIMEOUT);
+	err = iicbus_write(iicbus, bytes, 2, &xferd, RTL_IICBUS_TIMEOUT);
 	if (err != 0)
 		goto out;
-	err = iicbus_read(parent, bytes, 2, &xferd, IIC_LAST_READ, 0);
+	err = iicbus_read(iicbus, bytes, 2, &xferd, IIC_LAST_READ, 0);
 	if (err != 0)
 		goto out;
 	*data = ((bytes[1] & 0xff) << 8) | (bytes[0] & 0xff);
 
 out:
-	iicbus_stop(parent);
+	iicbus_stop(iicbus);
 	return err;
 }
 
 static int
-smi_write(device_t dev, uint16_t addr, uint16_t data)
+smi_write_lockheld(device_t dev, uint16_t addr, uint16_t data)
 {
 	int err;
-	device_t parent = device_get_parent(dev);
+	device_t iicbus = device_get_parent(dev);
 	struct iicbus_ivar *devi = IICBUS_IVAR(dev);
 	int slave = devi->addr;
 	char bytes[4];
-	int xferd;
+	int xferd, i;
 
 	bytes[0] = addr & 0xff;
 	bytes[1] = (addr >> 8) & 0xff;
 	bytes[2] = data & 0xff;
 	bytes[3] = (data >> 8) & 0xff;
 
-	err = iicbus_request_bus(parent, dev, IIC_WAIT);
-	if (err == 0) {
-		err = iicbus_start(parent, slave | IICBUS_WRITE, IICBUS_TIMEOUT);
-		if (err == 0)
-			err = iicbus_write(parent, bytes, 4, &xferd, IICBUS_TIMEOUT);
-		iicbus_stop(parent);
+	/*
+	 * The chip does not use clock stretching when it is busy,
+	 * instead ignoring the command. Retry a few times.
+	 */
+	for (i = RTL_IICBUS_RETRIES; i--; ) {
+		err = iicbus_start(iicbus, slave | RTL_IICBUS_WRITE, RTL_IICBUS_TIMEOUT);
+		if (err != IIC_ENOACK)
+			break;
+		DELAY(RTL_IICBUS_TIMEOUT);
+		delayed_select++;
 	}
-	iicbus_release_bus(parent, dev);
+	if (err == 0)
+		err = iicbus_write(iicbus, bytes, 4, &xferd, RTL_IICBUS_TIMEOUT);
+	iicbus_stop(iicbus);
 
 	return err;
 }
 
 static int
+smi_read(device_t dev, uint16_t addr, uint16_t *data)
+{
+	struct rtl8366rb_softc *sc = device_get_softc(dev);
+	device_t iicbus = device_get_parent(dev);
+	int err;
+	
+	mtx_lock(&sc->smi_mtx);
+	err = iicbus_request_bus(iicbus, dev, IIC_WAIT);
+	if (err == 0)
+		err = smi_read_lockheld(dev, addr, data);
+	iicbus_release_bus(iicbus, dev);
+	if (err != 0)
+		smi_reset(dev);
+	mtx_unlock(&sc->smi_mtx);
+	DEVERR(dev, err, "smi_read()=%d: addr=%04x\n", addr);
+	return (err == 0 ? 0 : EIO);
+}
+
+static int
+smi_write(device_t dev, uint16_t addr, uint16_t data)
+{
+	struct rtl8366rb_softc *sc = device_get_softc(dev);
+	device_t iicbus = device_get_parent(dev);
+	int err;
+	
+	mtx_lock(&sc->smi_mtx);
+	err = iicbus_request_bus(iicbus, dev, IIC_WAIT);
+	if (err == 0)
+		err = smi_write_lockheld(dev, addr, data);
+	iicbus_release_bus(iicbus, dev);
+	if (err != 0)
+		smi_reset(dev);
+	mtx_unlock(&sc->smi_mtx);
+	DEVERR(dev, err, "smi_write()=%d: addr=%04x\n", addr);
+	return (err == 0 ? 0 : EIO);
+}
+
+static int
 smi_rmw(device_t dev, uint16_t addr, uint16_t mask, uint16_t data)
 {
+	struct rtl8366rb_softc *sc = device_get_softc(dev);
+	device_t iicbus = device_get_parent(dev);
 	int err;
 	uint16_t oldv, newv;
 	
-	err = smi_read(dev, addr, &oldv);
+	mtx_lock(&sc->smi_mtx);
+	err = iicbus_request_bus(iicbus, dev, IIC_WAIT);
 	if (err == 0) {
-		newv = oldv & ~mask;
-		newv |= data & mask;
-		if (newv != oldv)
-			err = smi_write(dev, addr, newv);
+		err = smi_read_lockheld(dev, addr, &oldv);
+		if (err == 0) {
+			newv = oldv & ~mask;
+			newv |= data & mask;
+			if (newv != oldv)
+				err = smi_write_lockheld(dev, addr, newv);
+		}
 	}
-	return err;
+	iicbus_release_bus(iicbus, dev);
+	if (err != 0)
+		smi_reset(dev);
+	mtx_unlock(&sc->smi_mtx);
+	DEVERR(dev, err, "smi_rmw()=%d: addr=%04x\n", addr);
+	return (err == 0 ? 0 : EIO);
 }
 
 static etherswitch_info_t *
@@ -365,7 +530,7 @@ rtl_getport(device_t dev, etherswitch_port_t *p)
 	p->es_vlangroup = RTL8366RB_PVCR_GET(p->es_port,
 		rtl_readreg(dev, RTL8366RB_PVCR_REG(p->es_port)));
 	
-	if (p->es_port < RTL8366RB_NUM_PORTS-1) {
+	if (p->es_port < RTL8366RB_NUM_PHYS) {
 		sc = device_get_softc(dev);
 		mii = device_get_softc(sc->miibus[p->es_port]);
 		ifm = &mii->mii_media;
@@ -375,22 +540,9 @@ rtl_getport(device_t dev, etherswitch_port_t *p)
 	} else {
 		/* fill in fixed values for CPU port */
 		ifmr->ifm_count = 0;
-		smi_read(dev, RTL8366RB_PLSR_BASE + (RTL8366RB_NUM_PORTS-1)/2, &v);
-		v = v >> (8 * ((RTL8366RB_NUM_PORTS-1) % 2));
-		switch (v & RTL8366RB_PLSR_SPEED_MASK) {
-			case RTL8366RB_PLSR_SPEED_10:
-				ifmr->ifm_current = IFM_ETHER | IFM_10_T;
-				break;
-			case RTL8366RB_PLSR_SPEED_100:
-				ifmr->ifm_current = IFM_ETHER | IFM_100_TX;
-				break;
-			case RTL8366RB_PLSR_SPEED_1000:
-				ifmr->ifm_current = IFM_ETHER | IFM_1000_T;
-				break;
-		}
-		if ((v & RTL8366RB_PLSR_FULLDUPLEX) != 0)
-			ifmr->ifm_current |= IFM_FDX;
-		ifmr->ifm_active = ifmr->ifm_current;
+		smi_read(dev, RTL8366RB_PLSR_BASE + (RTL8366RB_NUM_PHYS)/2, &v);
+		v = v >> (8 * ((RTL8366RB_NUM_PHYS) % 2));
+		ifmr->ifm_active = ifmr->ifm_current = rtl8366rb_media_from_portstatus(v);
 		ifmr->ifm_mask = 0;
 		ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
 	}
@@ -412,7 +564,7 @@ rtl_setport(device_t dev, etherswitch_port_t *p)
 		RTL8366RB_PVCR_VAL(p->es_port, p->es_vlangroup));
 	if (err)
 		return (err);
-	if (p->es_port >= RTL8366RB_NUM_PORTS-1)
+	if (p->es_port >= RTL8366RB_NUM_PHYS)
 		return (0);
 	sc = device_get_softc(dev);
 	mii = device_get_softc(sc->miibus[p->es_port]);
@@ -455,23 +607,58 @@ rtl_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
 static int
 rtl_readphy(device_t dev, int phy, int reg)
 {
+	struct rtl8366rb_softc *sc = device_get_softc(dev);
+	device_t iicbus = device_get_parent(dev);
 	uint16_t data = 0;
-	
-	smi_write(dev, RTL8366RB_PACR, RTL8366RB_PACR_READ);
-	smi_write(dev, RTL8366RB_PHYREG(phy, 0, reg), 0);
-	smi_read(dev, RTL8366RB_PADR, &data);
+	int err;
+
+	if (phy < 0 || phy >= RTL8366RB_NUM_PHYS)
+		return (ENXIO);
+	if (reg < 0 || reg >= RTL8366RB_NUM_PHY_REG)
+		return (ENXIO);
+	mtx_lock(&sc->smi_mtx);
+	err = iicbus_request_bus(iicbus, dev, IIC_WAIT);
+	if (err == 0)
+		err = smi_write_lockheld(dev, RTL8366RB_PACR, RTL8366RB_PACR_READ);
+	if (err == 0)
+		err = smi_write_lockheld(dev, RTL8366RB_PHYREG(phy, 0, reg), 0);
+	if (err == 0) {
+		DELAY(RTL_IICBUS_PHYDELAY); /* chip needs time to talk to PHY */
+		err = smi_read_lockheld(dev, RTL8366RB_PADR, &data);
+	}
+	iicbus_release_bus(iicbus, dev);
+	if (err != 0)
+		smi_reset(dev);
+	mtx_unlock(&sc->smi_mtx);
+	DEVERR(dev, err, "rtl_readphy()=%d: phy=%d.%02x\n", phy, reg);
 	return (data);
 }
 
 static int
 rtl_writephy(device_t dev, int phy, int reg, int data)
 {
+	struct rtl8366rb_softc *sc = device_get_softc(dev);
+	device_t iicbus = device_get_parent(dev);
 	int err;
 	
-	err = smi_write(dev, RTL8366RB_PACR, RTL8366RB_PACR_WRITE);
-	if (err)
-		return (err);
-	return smi_write(dev, RTL8366RB_PHYREG(phy, 0, reg), data);
+	if (phy < 0 || phy >= RTL8366RB_NUM_PHYS)
+		return (ENXIO);
+	if (reg < 0 || reg >= RTL8366RB_NUM_PHY_REG)
+		return (ENXIO);
+	mtx_lock(&sc->smi_mtx);
+	err = iicbus_request_bus(iicbus, dev, IIC_WAIT);
+	if (err == 0)
+		err = smi_write_lockheld(dev, RTL8366RB_PACR, RTL8366RB_PACR_WRITE);
+	if (err == 0)
+		err = smi_write_lockheld(dev, RTL8366RB_PHYREG(phy, 0, reg), data);
+	if (err == 0)
+		DELAY(RTL_IICBUS_PHYDELAY); /* chip needs time to talk to PHY */
+	iicbus_release_bus(iicbus, dev);
+	if (err != 0)
+		smi_reset(dev);
+	mtx_unlock(&sc->smi_mtx);
+	DEVERR(dev, err, "rtl_writephy()=%d: phy=%d.%02x\n", phy, reg);
+	return (err == 0 ? 0 : EIO);
 }
 
 static int
@@ -511,6 +698,8 @@ static device_method_t rtl8366rb_methods[] = {
 	DEVMETHOD(etherswitch_getinfo,	rtl_getinfo),
 	DEVMETHOD(etherswitch_readreg,	rtl_readreg),
 	DEVMETHOD(etherswitch_writereg,	rtl_writereg),
+	DEVMETHOD(etherswitch_readphyreg,	rtl_readphy),
+	DEVMETHOD(etherswitch_writephyreg,	rtl_writephy),
 	DEVMETHOD(etherswitch_getport,	rtl_getport),
 	DEVMETHOD(etherswitch_setport,	rtl_setport),
 	DEVMETHOD(etherswitch_getvgroup,	rtl_getvgroup),
diff --git a/sys/dev/etherswitch/rtl8366rbvar.h b/sys/dev/etherswitch/rtl8366rbvar.h
index df17cb6..354ca95 100644
--- a/sys/dev/etherswitch/rtl8366rbvar.h
+++ b/sys/dev/etherswitch/rtl8366rbvar.h
@@ -28,9 +28,12 @@
 
 
 #define RTL8366RB_IIC_ADDR	0xa8
-#define IICBUS_TIMEOUT		100	/* us */
-#define IICBUS_READ		1
-#define	IICBUS_WRITE		0
+#define RTL_IICBUS_TIMEOUT	100	/* us */
+#define RTL_IICBUS_READ		1
+#define	RTL_IICBUS_WRITE	0
+/* number of times to try and select the chip on the I2C bus */
+#define RTL_IICBUS_RETRIES	3
+#define RTL_IICBUS_PHYDELAY	500	/* us */
 
 
 /* Register definitions */
@@ -43,8 +46,9 @@
 #define RTL8366RB_SGCR_MAX_LENGTH_1536		0x0010
 #define RTL8366RB_SGCR_MAX_LENGTH_1552		0x0020
 #define RTL8366RB_SGCR_MAX_LENGTH_9216		0x0030
-#define RTL8366RB_SGCR_EN_VLAN				0x2000
-#define RTL8366RB_SGCR_EN_VLAN_4KTB			0x4000
+#define RTL8366RB_SGCR_EN_VLAN			0x2000
+#define RTL8366RB_SGCR_EN_VLAN_4KTB		0x4000
+#define RTL8366RB_SGCR_EN_QOS			0x8000
 
 /* Port Enable Control: DISABLE_PORT[5:0] */
 #define RTL8366RB_PECR				0x0001
@@ -73,20 +77,20 @@
 
 /* VLAN Member Configuration, 3 registers per VLAN */
 #define RTL8366RB_VMCR_BASE			0x0020
-#define RTL8366RB_VMCR_MULT				3
-#define RTL8366RB_VMCR_DOT1Q_REG		0
+#define RTL8366RB_VMCR_MULT		3
+#define RTL8366RB_VMCR_DOT1Q_REG	0
 #define RTL8366RB_VMCR_DOT1Q_VID_SHIFT	0
 #define RTL8366RB_VMCR_DOT1Q_VID_MASK	0x0fff
 #define RTL8366RB_VMCR_DOT1Q_PCP_SHIFT	12
 #define RTL8366RB_VMCR_DOT1Q_PCP_MASK	0x7000
-#define RTL8366RB_VMCR_MU_REG			1
+#define RTL8366RB_VMCR_MU_REG		1
 #define RTL8366RB_VMCR_MU_MEMBER_SHIFT	0
 #define RTL8366RB_VMCR_MU_MEMBER_MASK	0x00ff
 #define RTL8366RB_VMCR_MU_UNTAG_SHIFT	8
 #define RTL8366RB_VMCR_MU_UNTAG_MASK	0xff00
-#define RTL8366RB_VMCR_FID_REG			2
+#define RTL8366RB_VMCR_FID_REG		2
 #define RTL8366RB_VMCR_FID_FID_SHIFT	0
-#define RTL8366RB_VMCR_FID_FID_MASK		0x0007
+#define RTL8366RB_VMCR_FID_FID_MASK	0x0007
 #define RTL8366RB_VMCR(_reg, _vlan) \
 	(RTL8366RB_VMCR_BASE + _reg + _vlan * RTL8366RB_VMCR_MULT)
 /* VLAN Identifier */
@@ -94,13 +98,15 @@
 	(_r[RTL8366RB_VMCR_DOT1Q_REG] & RTL8366RB_VMCR_DOT1Q_VID_MASK)
 /* Priority Code Point */
 #define RTL8366RB_VMCR_PCP(_r) \
-	((_r[RTL8366RB_VMCR_DOT1Q_REG] & RTL8366RB_VMCR_DOT1Q_PCP_MASK) >> RTL8366RB_VMCR_DOT1Q_PCP_SHIFT)
+	((_r[RTL8366RB_VMCR_DOT1Q_REG] & RTL8366RB_VMCR_DOT1Q_PCP_MASK) \
+	>> RTL8366RB_VMCR_DOT1Q_PCP_SHIFT)
 /* Member ports */
 #define RTL8366RB_VMCR_MEMBER(_r) \
 	(_r[RTL8366RB_VMCR_MU_REG] & RTL8366RB_VMCR_MU_MEMBER_MASK)
 /* Untagged ports */
 #define RTL8366RB_VMCR_UNTAG(_r) \
-	((_r[RTL8366RB_VMCR_MU_REG] & RTL8366RB_VMCR_MU_UNTAG_MASK) >> RTL8366RB_VMCR_MU_UNTAG_SHIFT)
+	((_r[RTL8366RB_VMCR_MU_REG] & RTL8366RB_VMCR_MU_UNTAG_MASK) \
+	>> RTL8366RB_VMCR_MU_UNTAG_SHIFT)
 /* Forwarding ID */
 #define RTL8366RB_VMCR_FID(_r) \
 	(_r[RTL8366RB_VMCR_FID_REG] & RTL8366RB_VMCR_FID_FID_MASK)
@@ -136,6 +142,19 @@
 /* VLAN Ingress Control 2: [5:0] */
 #define RTL8366RB_VIC2R				0x037f
 
+/* MIB registers */
+#define RTL8366RB_MCNT_BASE			0x1000
+#define RTL8366RB_MCTLR				0x13f0
+#define RTL8366RB_MCTLR_BUSY		0x0001
+#define RTL8366RB_MCTLR_RESET		0x0002
+#define RTL8366RB_MCTLR_RESET_PORT_MASK	0x00fc
+#define RTL8366RB_MCTLR_RESET_ALL	0x0800
+
+#define RTL8366RB_MCNT(_port, _r) \
+	(RTL8366RB_MCNT_BASE + 0x50 * (_port) + (_r))
+#define RTL8366RB_MCTLR_RESET_PORT(_p) \
+	(1 << ((_p) + 2))
+
 /* PHY Access Control */
 #define RTL8366RB_PACR				0x8000
 #define RTL8366RB_PACR_WRITE		0x0000
@@ -149,5 +168,6 @@
 
 /* general characteristics of the chip */
 #define RTL8366RB_NUM_PORTS			6
+#define RTL8366RB_NUM_PHYS			(RTL8366RB_NUM_PORTS-1)
 #define RTL8366RB_NUM_VLANS			16
-
+#define RTL8366RB_NUM_PHY_REG			32
diff --git a/sys/dev/flash/mx25l.c b/sys/dev/flash/mx25l.c
index d5c2270..3ac1d02 100644
--- a/sys/dev/flash/mx25l.c
+++ b/sys/dev/flash/mx25l.c
@@ -102,6 +102,7 @@ struct mx25l_flash_ident flash_devices[] = {
 	{ "mx25ll128", 0xc2, 0x2018, 64 * 1024, 256, FL_ERASE_4K | FL_ERASE_32K },
 	{ "s25fl128",  0x01, 0x2018, 64 * 1024, 256, FL_NONE },
 	{ "s25sl064a", 0x01, 0x0216, 64 * 1024, 128, FL_NONE },
+	{ "w25q64bv",  0xef, 0x4017, 64 * 1024, 128, FL_ERASE_4K },
 };
 
 static uint8_t
diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c
index 09ebe4e..c6fbaae 100644
--- a/sys/dev/gpio/gpiobus.c
+++ b/sys/dev/gpio/gpiobus.c
@@ -349,7 +349,9 @@ gpiobus_acquire_bus(device_t busdev, device_t child)
 	GPIOBUS_ASSERT_LOCKED(sc);
 
 	if (sc->sc_owner)
-		panic("rb_cpldbus: cannot serialize the access to device.");
+		panic("%s: acquire_bus(%s): already acquired by %s",
+		    device_get_nameunit(busdev), device_get_nameunit(busdev),
+		    device_get_nameunit(child));
 	sc->sc_owner = child;
 }
 
@@ -362,9 +364,12 @@ gpiobus_release_bus(device_t busdev, device_t child)
 	GPIOBUS_ASSERT_LOCKED(sc);
 
 	if (!sc->sc_owner)
-		panic("rb_cpldbus: releasing unowned bus.");
+		panic("%s: release_bus(%s): not owned",
+		    device_get_nameunit(busdev), device_get_nameunit(busdev));
 	if (sc->sc_owner != child)
-		panic("rb_cpldbus: you don't own the bus. game over.");
+		panic("%s: release_bus(%s): acquired by %s",
+		    device_get_nameunit(busdev), device_get_nameunit(busdev),
+		    device_get_nameunit(child));
 
 	sc->sc_owner = NULL;
 }
diff --git a/sys/dev/iicbus/iicbb.c b/sys/dev/iicbus/iicbb.c
index fed203c..a0e6255 100644
--- a/sys/dev/iicbus/iicbb.c
+++ b/sys/dev/iicbus/iicbb.c
@@ -276,24 +276,31 @@ iicbb_zero(device_t dev, int timeout)
 static int
 iicbb_ack(device_t dev, int timeout)
 {
-	struct iicbb_softc *sc = device_get_softc(dev);
-	int noack;
-	int k = 0;
-
-	I2C_SET(sc,dev,0,1);
-	I2C_SET(sc,dev,1,1);
-	do {
-		noack = I2C_GETSDA(dev);
-		if (!noack)
+	struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev);
+	int timeout = sc->iictimeout;
+	int value;
+
+	/* 0 */
+	IICBB_SETSDA(device_get_parent(dev), 1);
+	DELAY(sc->iicdelay);
+	/* 1 */
+	IICBB_SETSCL(device_get_parent(dev), 1);
+	while (1) {
+		DELAY(sc->iicdelay);
+		/* allow clock stretching */
+		if (IICBB_GETSCL(device_get_parent(dev)) != 0)
 			break;
-		DELAY(1);
-		k++;
-	} while (k < timeout);
-
-	I2C_SET(sc,dev,0,1);
-	I2C_DEBUG(printf("%c ",noack?'-':'+'));
-
-	return (noack);
+		if (timeout <= 0)
+			return (-1);
+		timeout -= sc->iicdelay;
+	}
+	/* 2 */
+	value = IICBB_GETSDA(device_get_parent(dev));
+	DELAY(sc->iicdelay);
+	/* 3 */
+	IICBB_SETSCL(device_get_parent(dev), 0);
+	DELAY(sc->iicdelay);
+	return (value != 0 ? 1 : 0);
 }
 
 static void
@@ -346,6 +353,7 @@ static int
 iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
 {
 	return (IICBB_RESET(device_get_parent(dev), speed, addr, oldaddr));
+	i2c_stop(dev);
 }
 
 static int
@@ -354,38 +362,31 @@ iicbb_start(device_t dev, u_char slave, int timeout)
 	struct iicbb_softc *sc = device_get_softc(dev);
 	int error;
 
-	I2C_DEBUG(printf("<"));
-
-	I2C_SET(sc,dev,1,1);
-	I2C_SET(sc,dev,1,0);
-	I2C_SET(sc,dev,0,0);
-
-	/* send address */
-	iicbb_sendbyte(dev, slave, timeout);
-
-	/* check for ack */
-	if (iicbb_ack(dev, timeout)) {
-		error = IIC_ENOACK;
-		goto error;
+	I2C_LOG("<");
+
+	sc->iictimeout = timeout;
+	if (i2c_start(dev) < 0)
+		return (IIC_ENOACK);
+	error = i2c_xmitbyte(dev, slave);
+	if (error < 0)
+		return (IIC_EBUSERR); /* lost arbitration */
+	I2C_LOG("%02x", slave);
+	error = i2c_recvbit(dev);
+	if (error < 0)
+		return (IIC_EBUSERR); /* lost arbitration */
+	I2C_LOG("%c", error != 0 ? '-' : '+');
+	if (error != 0) {
+		iicbb_stop(dev);
+		return (IIC_ENOACK);
 	}
-
-	return(0);
-
-error:
-	iicbb_stop(dev);
-	return (error);
+	return (0);
 }
 
 static int
 iicbb_stop(device_t dev)
 {
-	struct iicbb_softc *sc = device_get_softc(dev);
-
-	I2C_SET(sc,dev,0,0);
-	I2C_SET(sc,dev,1,0);
-	I2C_SET(sc,dev,1,1);
-	I2C_DEBUG(printf(">"));
-	I2C_DEBUG(printf("\n"));
+	i2c_stop(dev);
+	I2C_LOG(">\n");
 	return (0);
 }
 
diff --git a/sys/modules/rtl8366rb/Makefile b/sys/modules/rtl8366rb/Makefile
index 41cacd3..8d9800f 100644
--- a/sys/modules/rtl8366rb/Makefile
+++ b/sys/modules/rtl8366rb/Makefile
@@ -5,6 +5,6 @@ CFLAGS+=	-DDEBUG
 .PATH:	${.CURDIR}/../../dev/etherswitch
 KMOD=	rtl8366rb
 SRCS=	rtl8366rb.c rtl8366rbvar.h 
-SRCS+=	device_if.h bus_if.h miibus_if.h etherswitch_if.h opt_cputype.h
+SRCS+=	device_if.h bus_if.h iicbus_if.h miibus_if.h etherswitch_if.h opt_cputype.h
 
 .include <bsd.kmod.mk>

--Apple-Mail=_8BCC333A-BF48-41F3-90E3-140840423ED9
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=us-ascii



Make code more robust.

o Add ioctls to read and write PHY registers.

o properly stop I2C transaction when selection fails, or the transaction
  fails halfway through.  With debugging enabled,
  debug.rtl8366rb.reset_count counts the number of times the bus has been
  reset after an error.

o Add a DELAY() to reading and writing PHY registers to give the chip
  time to talk to the PHY.  Without this DELAY, the chip may be
  unresponsive.

o Add debugging code to print info on failed I2C transactions.

o When selecting the chip fails, retry a number of times.  With debugging
  enabled, debug.rtl8366rb.delayed_select counts the number of times
  this has happened.

o Don't call PHY_SERVICE() (because that runs the phy service code that
  queries the PHY for the currently selected media); call mii_phy_update()



-- 
Stefan Bethke <stb@lassitu.de>   Fon +49 151 14070811




--Apple-Mail=_8BCC333A-BF48-41F3-90E3-140840423ED9--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?267FB3D6-830E-4A2F-8C1C-A96873EDCD31>