dcphy.c revision 213229
1/*-
2 * Copyright (c) 1997, 1998, 1999
3 *	Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/sys/dev/dc/dcphy.c 213229 2010-09-27 20:31:03Z marius $");
35
36/*
37 * Pseudo-driver for internal NWAY support on DEC 21143 and workalike
38 * controllers.  Technically we're abusing the miibus code to handle
39 * media selection and NWAY support here since there is no MII
40 * interface.  However the logical operations are roughly the same,
41 * and the alternative is to create a fake MII interface in the driver,
42 * which is harder to do.
43 */
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/socket.h>
49#include <sys/errno.h>
50#include <sys/lock.h>
51#include <sys/module.h>
52#include <sys/mutex.h>
53#include <sys/bus.h>
54
55#include <net/if.h>
56#include <net/if_arp.h>
57#include <net/if_media.h>
58
59#include <dev/mii/mii.h>
60#include <dev/mii/miivar.h>
61#include "miidevs.h"
62
63#include <machine/bus.h>
64#include <machine/resource.h>
65#include <sys/bus.h>
66
67#include <dev/pci/pcivar.h>
68
69#include <dev/dc/if_dcreg.h>
70
71#include "miibus_if.h"
72
73#define DC_SETBIT(sc, reg, x)                           \
74        CSR_WRITE_4(sc, reg,                            \
75                CSR_READ_4(sc, reg) | x)
76
77#define DC_CLRBIT(sc, reg, x)                           \
78        CSR_WRITE_4(sc, reg,                            \
79                CSR_READ_4(sc, reg) & ~x)
80
81#define MIIF_AUTOTIMEOUT	0x0004
82
83/*
84 * This is the subsystem ID for the built-in 21143 ethernet
85 * in several Compaq Presario systems.  Apparently these are
86 * 10Mbps only, so we need to treat them specially.
87 */
88#define COMPAQ_PRESARIO_ID	0xb0bb0e11
89
90static int dcphy_probe(device_t);
91static int dcphy_attach(device_t);
92
93static device_method_t dcphy_methods[] = {
94	/* device interface */
95	DEVMETHOD(device_probe,		dcphy_probe),
96	DEVMETHOD(device_attach,	dcphy_attach),
97	DEVMETHOD(device_detach,	mii_phy_detach),
98	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
99	{ 0, 0 }
100};
101
102static devclass_t dcphy_devclass;
103
104static driver_t dcphy_driver = {
105	"dcphy",
106	dcphy_methods,
107	sizeof(struct mii_softc)
108};
109
110DRIVER_MODULE(dcphy, miibus, dcphy_driver, dcphy_devclass, 0, 0);
111
112static int	dcphy_service(struct mii_softc *, struct mii_data *, int);
113static void	dcphy_status(struct mii_softc *);
114static void	dcphy_reset(struct mii_softc *);
115static int	dcphy_auto(struct mii_softc *);
116
117static int
118dcphy_probe(device_t dev)
119{
120	struct mii_attach_args *ma;
121
122	ma = device_get_ivars(dev);
123
124	/*
125	 * The dc driver will report the 21143 vendor and device
126	 * ID to let us know that it wants us to attach.
127	 */
128	if (ma->mii_id1 != DC_VENDORID_DEC ||
129	    ma->mii_id2 != DC_DEVICEID_21143)
130		return (ENXIO);
131
132	device_set_desc(dev, "Intel 21143 NWAY media interface");
133
134	return (BUS_PROBE_DEFAULT);
135}
136
137static int
138dcphy_attach(device_t dev)
139{
140	struct mii_softc *sc;
141	struct mii_attach_args *ma;
142	struct mii_data *mii;
143	struct dc_softc		*dc_sc;
144	device_t brdev;
145
146	sc = device_get_softc(dev);
147	ma = device_get_ivars(dev);
148	sc->mii_dev = device_get_parent(dev);
149	mii = ma->mii_data;
150	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
151
152	sc->mii_inst = mii->mii_instance;
153	sc->mii_phy = ma->mii_phyno;
154	sc->mii_service = dcphy_service;
155	sc->mii_pdata = mii;
156
157	/*
158	 * Apparently, we can neither isolate nor do loopback.
159	 */
160	sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP;
161
162	mii->mii_instance++;
163
164	/*dcphy_reset(sc);*/
165	dc_sc = mii->mii_ifp->if_softc;
166	CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0);
167	CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0);
168
169	brdev = device_get_parent(sc->mii_dev);
170	switch (pci_get_subdevice(brdev) << 16 | pci_get_subvendor(brdev)) {
171	case COMPAQ_PRESARIO_ID:
172		/* Example of how to only allow 10Mbps modes. */
173		sc->mii_capabilities = BMSR_ANEG | BMSR_10TFDX | BMSR_10THDX;
174		break;
175	default:
176		if (dc_sc->dc_pmode == DC_PMODE_SIA)
177			sc->mii_capabilities =
178			    BMSR_ANEG | BMSR_10TFDX | BMSR_10THDX;
179		else
180			sc->mii_capabilities =
181			    BMSR_ANEG | BMSR_100TXFDX | BMSR_100TXHDX |
182			    BMSR_10TFDX | BMSR_10THDX;
183		break;
184	}
185
186	sc->mii_capabilities &= ma->mii_capmask;
187	device_printf(dev, " ");
188	mii_phy_add_media(sc);
189	printf("\n");
190
191	MIIBUS_MEDIAINIT(sc->mii_dev);
192	return (0);
193}
194
195static int
196dcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
197{
198	struct dc_softc		*dc_sc;
199	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
200	int reg;
201	u_int32_t		mode;
202
203	dc_sc = mii->mii_ifp->if_softc;
204
205	switch (cmd) {
206	case MII_POLLSTAT:
207		/*
208		 * If we're not polling our PHY instance, just return.
209		 */
210		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
211			return (0);
212		break;
213
214	case MII_MEDIACHG:
215		/*
216		 * If the media indicates a different PHY instance,
217		 * isolate ourselves.
218		 */
219		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
220			return (0);
221
222		/*
223		 * If the interface is not up, don't do anything.
224		 */
225		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
226			break;
227
228		sc->mii_flags = 0;
229		mii->mii_media_active = IFM_NONE;
230		mode = CSR_READ_4(dc_sc, DC_NETCFG);
231		mode &= ~(DC_NETCFG_FULLDUPLEX | DC_NETCFG_PORTSEL |
232		    DC_NETCFG_PCS | DC_NETCFG_SCRAMBLER | DC_NETCFG_SPEEDSEL);
233
234		switch (IFM_SUBTYPE(ife->ifm_media)) {
235		case IFM_AUTO:
236			/*dcphy_reset(sc);*/
237			(void) dcphy_auto(sc);
238			break;
239		case IFM_100_T4:
240			/*
241			 * XXX Not supported as a manual setting right now.
242			 */
243			return (EINVAL);
244		case IFM_100_TX:
245			dcphy_reset(sc);
246			DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
247			mode |= DC_NETCFG_PORTSEL | DC_NETCFG_PCS |
248			    DC_NETCFG_SCRAMBLER;
249			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
250				mode |= DC_NETCFG_FULLDUPLEX;
251			else
252				mode &= ~DC_NETCFG_FULLDUPLEX;
253			CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
254			break;
255		case IFM_10_T:
256			DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
257			DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF);
258			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
259				DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D);
260			else
261				DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F);
262			DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
263			DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
264			mode &= ~DC_NETCFG_PORTSEL;
265			mode |= DC_NETCFG_SPEEDSEL;
266			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
267				mode |= DC_NETCFG_FULLDUPLEX;
268			else
269				mode &= ~DC_NETCFG_FULLDUPLEX;
270			CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
271			break;
272		default:
273			return (EINVAL);
274		}
275		break;
276
277	case MII_TICK:
278		/*
279		 * If we're not currently selected, just return.
280		 */
281		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
282			return (0);
283
284		/*
285		 * Is the interface even up?
286		 */
287		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
288			return (0);
289
290		/*
291		 * Only used for autonegotiation.
292		 */
293		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
294			break;
295
296		reg = CSR_READ_4(dc_sc, DC_10BTSTAT);
297		if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
298			break;
299
300                /*
301                 * Only retry autonegotiation every 5 seconds.
302		 *
303		 * Otherwise, fall through to calling dcphy_status()
304		 * since real Intel 21143 chips don't show valid link
305		 * status until autonegotiation is switched off, and
306		 * that only happens in dcphy_status().  Without this,
307		 * successful autonegotiation is never recognised on
308		 * these chips.
309                 */
310                if (++sc->mii_ticks <= 50)
311			break;
312
313		sc->mii_ticks = 0;
314		dcphy_auto(sc);
315
316		break;
317	}
318
319	/* Update the media status. */
320	dcphy_status(sc);
321
322	/* Callback if something changed. */
323	mii_phy_update(sc, cmd);
324	return (0);
325}
326
327static void
328dcphy_status(struct mii_softc *sc)
329{
330	struct mii_data *mii = sc->mii_pdata;
331	int reg, anlpar, tstat = 0;
332	struct dc_softc		*dc_sc;
333
334	dc_sc = mii->mii_ifp->if_softc;
335
336	mii->mii_media_status = IFM_AVALID;
337	mii->mii_media_active = IFM_ETHER;
338
339	if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
340		return;
341
342	reg = CSR_READ_4(dc_sc, DC_10BTSTAT);
343	if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
344		mii->mii_media_status |= IFM_ACTIVE;
345
346	if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL) {
347		/* Erg, still trying, I guess... */
348		tstat = CSR_READ_4(dc_sc, DC_10BTSTAT);
349		if ((tstat & DC_TSTAT_ANEGSTAT) != DC_ASTAT_AUTONEGCMP) {
350			if ((DC_IS_MACRONIX(dc_sc) || DC_IS_PNICII(dc_sc)) &&
351			    (tstat & DC_TSTAT_ANEGSTAT) == DC_ASTAT_DISABLE)
352				goto skip;
353			mii->mii_media_active |= IFM_NONE;
354			return;
355		}
356
357		if (tstat & DC_TSTAT_LP_CAN_NWAY) {
358			anlpar = tstat >> 16;
359			if (anlpar & ANLPAR_TX_FD &&
360			    sc->mii_capabilities & BMSR_100TXFDX)
361				mii->mii_media_active |= IFM_100_TX | IFM_FDX;
362			else if (anlpar & ANLPAR_T4 &&
363			    sc->mii_capabilities & BMSR_100T4)
364				mii->mii_media_active |= IFM_100_T4;
365			else if (anlpar & ANLPAR_TX &&
366			    sc->mii_capabilities & BMSR_100TXHDX)
367				mii->mii_media_active |= IFM_100_TX;
368			else if (anlpar & ANLPAR_10_FD)
369				mii->mii_media_active |= IFM_10_T | IFM_FDX;
370			else if (anlpar & ANLPAR_10)
371				mii->mii_media_active |= IFM_10_T;
372			else
373				mii->mii_media_active |= IFM_NONE;
374			if (DC_IS_INTEL(dc_sc))
375				DC_CLRBIT(dc_sc, DC_10BTCTRL,
376				    DC_TCTL_AUTONEGENBL);
377			return;
378		}
379
380		/*
381		 * If the other side doesn't support NWAY, then the
382		 * best we can do is determine if we have a 10Mbps or
383		 * 100Mbps link.  There's no way to know if the link
384		 * is full or half duplex, so we default to half duplex
385		 * and hope that the user is clever enough to manually
386		 * change the media settings if we're wrong.
387		 */
388		if (!(reg & DC_TSTAT_LS100))
389			mii->mii_media_active |= IFM_100_TX;
390		else if (!(reg & DC_TSTAT_LS10))
391			mii->mii_media_active |= IFM_10_T;
392		else
393			mii->mii_media_active |= IFM_NONE;
394		if (DC_IS_INTEL(dc_sc))
395			DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
396		return;
397	}
398
399skip:
400	if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
401		mii->mii_media_active |= IFM_10_T;
402	else
403		mii->mii_media_active |= IFM_100_TX;
404	if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
405		mii->mii_media_active |= IFM_FDX;
406}
407
408static int
409dcphy_auto(struct mii_softc *mii)
410{
411	struct dc_softc		*sc;
412
413	sc = mii->mii_pdata->mii_ifp->if_softc;
414
415	DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
416	DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
417	DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
418	if (mii->mii_capabilities & BMSR_100TXHDX)
419		CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF);
420	else
421		CSR_WRITE_4(sc, DC_10BTCTRL, 0xFFFF);
422	DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
423	DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
424	DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE);
425
426	return (EJUSTRETURN);
427}
428
429static void
430dcphy_reset(struct mii_softc *mii)
431{
432	struct dc_softc		*sc;
433
434	sc = mii->mii_pdata->mii_ifp->if_softc;
435
436	DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
437	DELAY(1000);
438	DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
439}
440