rlswitch.c revision 165782
1165782Sticso/*-
2165782Sticso * Copyright (c) 1997, 1998, 1999
3165782Sticso *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4165782Sticso * Copyright (c) 2006 Bernd Walter.  All rights reserved.
5165782Sticso *
6165782Sticso * Redistribution and use in source and binary forms, with or without
7165782Sticso * modification, are permitted provided that the following conditions
8165782Sticso * are met:
9165782Sticso * 1. Redistributions of source code must retain the above copyright
10165782Sticso *    notice, this list of conditions and the following disclaimer.
11165782Sticso * 2. Redistributions in binary form must reproduce the above copyright
12165782Sticso *    notice, this list of conditions and the following disclaimer in the
13165782Sticso *    documentation and/or other materials provided with the distribution.
14165782Sticso * 3. All advertising materials mentioning features or use of this software
15165782Sticso *    must display the following acknowledgement:
16165782Sticso *	This product includes software developed by Bill Paul.
17165782Sticso * 4. Neither the name of the author nor the names of any co-contributors
18165782Sticso *    may be used to endorse or promote products derived from this software
19165782Sticso *    without specific prior written permission.
20165782Sticso *
21165782Sticso * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
22165782Sticso * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23165782Sticso * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24165782Sticso * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
25165782Sticso * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26165782Sticso * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27165782Sticso * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28165782Sticso * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29165782Sticso * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30165782Sticso * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31165782Sticso * THE POSSIBILITY OF SUCH DAMAGE.
32165782Sticso */
33165782Sticso
34165782Sticso#include <sys/cdefs.h>
35165782Sticso__FBSDID("$FreeBSD: head/sys/dev/mii/rlswitch.c 165782 2007-01-05 01:46:26Z ticso $");
36165782Sticso
37165782Sticso/*
38165782Sticso * driver for RealTek 8305 pseudo PHYs
39165782Sticso */
40165782Sticso
41165782Sticso#include <sys/param.h>
42165782Sticso#include <sys/systm.h>
43165782Sticso#include <sys/kernel.h>
44165782Sticso#include <sys/module.h>
45165782Sticso#include <sys/socket.h>
46165782Sticso#include <sys/bus.h>
47165782Sticso
48165782Sticso#include <net/if.h>
49165782Sticso#include <net/if_arp.h>
50165782Sticso#include <net/if_media.h>
51165782Sticso
52165782Sticso#include <dev/mii/mii.h>
53165782Sticso#include <dev/mii/miivar.h>
54165782Sticso#include "miidevs.h"
55165782Sticso
56165782Sticso#include <machine/bus.h>
57165782Sticso#include <pci/if_rlreg.h>
58165782Sticso
59165782Sticso#include "miibus_if.h"
60165782Sticso
61165782Sticso//#define RL_DEBUG
62165782Sticso#define RL_VLAN
63165782Sticso
64165782Sticsostatic int rlswitch_probe(device_t);
65165782Sticsostatic int rlswitch_attach(device_t);
66165782Sticso
67165782Sticsostatic device_method_t rlswitch_methods[] = {
68165782Sticso	/* device interface */
69165782Sticso	DEVMETHOD(device_probe,		rlswitch_probe),
70165782Sticso	DEVMETHOD(device_attach,	rlswitch_attach),
71165782Sticso	DEVMETHOD(device_detach,	mii_phy_detach),
72165782Sticso	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
73165782Sticso	{ 0, 0 }
74165782Sticso};
75165782Sticso
76165782Sticsostatic devclass_t rlswitch_devclass;
77165782Sticso
78165782Sticsostatic driver_t rlswitch_driver = {
79165782Sticso	"rlswitch",
80165782Sticso	rlswitch_methods,
81165782Sticso	sizeof(struct mii_softc)
82165782Sticso};
83165782Sticso
84165782SticsoDRIVER_MODULE(rlswitch, miibus, rlswitch_driver, rlswitch_devclass, 0, 0);
85165782Sticso
86165782Sticsostatic int	rlswitch_service(struct mii_softc *, struct mii_data *, int);
87165782Sticsostatic void	rlswitch_status(struct mii_softc *);
88165782Sticso
89165782Sticso#ifdef RL_DEBUG
90165782Sticsostatic void	rlswitch_phydump(device_t dev);
91165782Sticso#endif
92165782Sticso
93165782Sticsostatic const struct mii_phydesc rlswitches[] = {
94165782Sticso	MII_PHY_DESC(xxREALTEK, RTL8305SC),
95165782Sticso	MII_PHY_END
96165782Sticso};
97165782Sticso
98165782Sticsostatic int
99165782Sticsorlswitch_probe(device_t dev)
100165782Sticso{
101165782Sticso	int rv;
102165782Sticso
103165782Sticso	rv = mii_phy_dev_probe(dev, rlswitches, BUS_PROBE_DEFAULT);
104165782Sticso	if (rv <= 0)
105165782Sticso		return (rv);
106165782Sticso
107165782Sticso	return (ENXIO);
108165782Sticso}
109165782Sticso
110165782Sticsostatic int
111165782Sticsorlswitch_attach(device_t dev)
112165782Sticso{
113165782Sticso	struct mii_softc	*sc;
114165782Sticso	struct mii_attach_args	*ma;
115165782Sticso	struct mii_data		*mii;
116165782Sticso
117165782Sticso	sc = device_get_softc(dev);
118165782Sticso	ma = device_get_ivars(dev);
119165782Sticso	sc->mii_dev = device_get_parent(dev);
120165782Sticso	mii = device_get_softc(sc->mii_dev);
121165782Sticso
122165782Sticso	/*
123165782Sticso	 * We handle all pseudo PHY in a single instance, so never allow
124165782Sticso	 * non-zero * instances!
125165782Sticso	 */
126165782Sticso	if (mii->mii_instance != 0) {
127165782Sticso		device_printf(dev, "ignoring this PHY, non-zero instance\n");
128165782Sticso		return (ENXIO);
129165782Sticso	}
130165782Sticso
131165782Sticso	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
132165782Sticso
133165782Sticso	sc->mii_inst = mii->mii_instance;
134165782Sticso	sc->mii_phy = ma->mii_phyno;
135165782Sticso	sc->mii_service = rlswitch_service;
136165782Sticso	sc->mii_pdata = mii;
137165782Sticso	mii->mii_instance++;
138165782Sticso
139165782Sticso	sc->mii_flags |= MIIF_NOISOLATE;
140165782Sticso
141165782Sticso#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
142165782Sticso
143165782Sticso#if 0 /* See above. */
144165782Sticso	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
145165782Sticso	    BMCR_ISO);
146165782Sticso#endif
147165782Sticso
148165782Sticso#if 0
149165782Sticso	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
150165782Sticso	    BMCR_LOOP|BMCR_S100);
151165782Sticso#endif
152165782Sticso
153165782Sticso	sc->mii_capabilities = BMSR_100TXFDX & ma->mii_capmask;
154165782Sticso	device_printf(dev, " ");
155165782Sticso	mii_phy_add_media(sc);
156165782Sticso	printf("\n");
157165782Sticso#undef ADD
158165782Sticso#ifdef RL_DEBUG
159165782Sticso	rlswitch_phydump(dev);
160165782Sticso#endif
161165782Sticso
162165782Sticso#ifdef RL_VLAN
163165782Sticso	int val;
164165782Sticso
165165782Sticso	/* Global Control 0 */
166165782Sticso	val = 0;
167165782Sticso	val |= 0 << 10;		/* enable 802.1q VLAN Tag support */
168165782Sticso	val |= 0 << 9;		/* enable VLAN ingress filtering */
169165782Sticso	val |= 1 << 8;		/* disable VLAN tag admit control */
170165782Sticso	val |= 1 << 6;		/* internal use */
171165782Sticso	val |= 1 << 5;		/* internal use */
172165782Sticso	val |= 1 << 4;		/* internal use */
173165782Sticso	val |= 1 << 3;		/* internal use */
174165782Sticso	val |= 1 << 1;		/* reserved */
175165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 0, 16, val);
176165782Sticso
177165782Sticso	/* Global Control 2 */
178165782Sticso	val = 0;
179165782Sticso	val |= 1 << 15;		/* reserved */
180165782Sticso	val |= 0 << 14;		/* enable 1552 Bytes support */
181165782Sticso	val |= 1 << 13;		/* enable broadcast input drop */
182165782Sticso	val |= 1 << 12;		/* forward reserved control frames */
183165782Sticso	val |= 1 << 11;		/* disable forwarding unicast frames to other VLAN's */
184165782Sticso	val |= 1 << 10;		/* disable forwarding ARP broadcasts to other VLAN's */
185165782Sticso	val |= 1 << 9;		/* enable 48 pass 1 */
186165782Sticso	val |= 0 << 8;		/* enable VLAN */
187165782Sticso	val |= 1 << 7;		/* reserved */
188165782Sticso	val |= 1 << 6;		/* enable defer */
189165782Sticso	val |= 1 << 5;		/* 43ms LED blink time */
190165782Sticso	val |= 3 << 3;		/* 16:1 queue weight */
191165782Sticso	val |= 1 << 2;		/* disable broadcast storm control */
192165782Sticso	val |= 1 << 1;		/* enable power-on LED blinking */
193165782Sticso	val |= 1 << 0;		/* reserved */
194165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 0, 18, val);
195165782Sticso
196165782Sticso	/* Port 0 Control Register 0 */
197165782Sticso	val = 0;
198165782Sticso	val |= 1 << 15;		/* reserved */
199165782Sticso	val |= 1 << 11;		/* drop received packets with wrong VLAN tag */
200165782Sticso	val |= 1 << 10;		/* disable 802.1p priority classification */
201165782Sticso	val |= 1 << 9;		/* disable diffserv priority classification */
202165782Sticso	val |= 1 << 6;		/* internal use */
203165782Sticso	val |= 3 << 4;		/* internal use */
204165782Sticso	val |= 1 << 3;		/* internal use */
205165782Sticso	val |= 1 << 2;		/* internal use */
206165782Sticso	val |= 1 << 0;		/* remove VLAN tags on output */
207165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 0, 22, val);
208165782Sticso
209165782Sticso	/* Port 1 Control Register 0 */
210165782Sticso	val = 0;
211165782Sticso	val |= 1 << 15;		/* reserved */
212165782Sticso	val |= 1 << 11;		/* drop received packets with wrong VLAN tag */
213165782Sticso	val |= 1 << 10;		/* disable 802.1p priority classification */
214165782Sticso	val |= 1 << 9;		/* disable diffserv priority classification */
215165782Sticso	val |= 1 << 6;		/* internal use */
216165782Sticso	val |= 3 << 4;		/* internal use */
217165782Sticso	val |= 1 << 3;		/* internal use */
218165782Sticso	val |= 1 << 2;		/* internal use */
219165782Sticso	val |= 1 << 0;		/* remove VLAN tags on output */
220165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 1, 22, val);
221165782Sticso
222165782Sticso	/* Port 2 Control Register 0 */
223165782Sticso	val = 0;
224165782Sticso	val |= 1 << 15;		/* reserved */
225165782Sticso	val |= 1 << 11;		/* drop received packets with wrong VLAN tag */
226165782Sticso	val |= 1 << 10;		/* disable 802.1p priority classification */
227165782Sticso	val |= 1 << 9;		/* disable diffserv priority classification */
228165782Sticso	val |= 1 << 6;		/* internal use */
229165782Sticso	val |= 3 << 4;		/* internal use */
230165782Sticso	val |= 1 << 3;		/* internal use */
231165782Sticso	val |= 1 << 2;		/* internal use */
232165782Sticso	val |= 1 << 0;		/* remove VLAN tags on output */
233165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 2, 22, val);
234165782Sticso
235165782Sticso	/* Port 3 Control Register 0 */
236165782Sticso	val = 0;
237165782Sticso	val |= 1 << 15;		/* reserved */
238165782Sticso	val |= 1 << 11;		/* drop received packets with wrong VLAN tag */
239165782Sticso	val |= 1 << 10;		/* disable 802.1p priority classification */
240165782Sticso	val |= 1 << 9;		/* disable diffserv priority classification */
241165782Sticso	val |= 1 << 6;		/* internal use */
242165782Sticso	val |= 3 << 4;		/* internal use */
243165782Sticso	val |= 1 << 3;		/* internal use */
244165782Sticso	val |= 1 << 2;		/* internal use */
245165782Sticso	val |= 1 << 0;		/* remove VLAN tags on output */
246165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 3, 22, val);
247165782Sticso
248165782Sticso	/* Port 4 (system port) Control Register 0 */
249165782Sticso	val = 0;
250165782Sticso	val |= 1 << 15;		/* reserved */
251165782Sticso	val |= 0 << 11;		/* don't drop received packets with wrong VLAN tag */
252165782Sticso	val |= 1 << 10;		/* disable 802.1p priority classification */
253165782Sticso	val |= 1 << 9;		/* disable diffserv priority classification */
254165782Sticso	val |= 1 << 6;		/* internal use */
255165782Sticso	val |= 3 << 4;		/* internal use */
256165782Sticso	val |= 1 << 3;		/* internal use */
257165782Sticso	val |= 1 << 2;		/* internal use */
258165782Sticso	val |= 2 << 0;		/* add VLAN tags for untagged packets on output */
259165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 4, 22, val);
260165782Sticso
261165782Sticso	/* Port 0 Control Register 1 and VLAN A */
262165782Sticso	val = 0;
263165782Sticso	val |= 0x0 << 12;	/* Port 0 VLAN Index */
264165782Sticso	val |= 1 << 11;		/* internal use */
265165782Sticso	val |= 1 << 10;		/* internal use */
266165782Sticso	val |= 1 << 9;		/* internal use */
267165782Sticso	val |= 1 << 7;		/* internal use */
268165782Sticso	val |= 1 << 6;		/* internal use */
269165782Sticso	val |= 0x11 << 0;	/* VLAN A membership */
270165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 0, 24, val);
271165782Sticso
272165782Sticso	/* Port 0 Control Register 2 and VLAN A */
273165782Sticso	val = 0;
274165782Sticso	val |= 1 << 15;		/* internal use */
275165782Sticso	val |= 1 << 14;		/* internal use */
276165782Sticso	val |= 1 << 13;		/* internal use */
277165782Sticso	val |= 1 << 12;		/* internal use */
278165782Sticso	val |= 0x100 << 0;	/* VLAN A ID */
279165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 0, 25, val);
280165782Sticso
281165782Sticso	/* Port 1 Control Register 1 and VLAN B */
282165782Sticso	val = 0;
283165782Sticso	val |= 0x1 << 12;	/* Port 1 VLAN Index */
284165782Sticso	val |= 1 << 11;		/* internal use */
285165782Sticso	val |= 1 << 10;		/* internal use */
286165782Sticso	val |= 1 << 9;		/* internal use */
287165782Sticso	val |= 1 << 7;		/* internal use */
288165782Sticso	val |= 1 << 6;		/* internal use */
289165782Sticso	val |= 0x12 << 0;	/* VLAN B membership */
290165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 1, 24, val);
291165782Sticso
292165782Sticso	/* Port 1 Control Register 2 and VLAN B */
293165782Sticso	val = 0;
294165782Sticso	val |= 1 << 15;		/* internal use */
295165782Sticso	val |= 1 << 14;		/* internal use */
296165782Sticso	val |= 1 << 13;		/* internal use */
297165782Sticso	val |= 1 << 12;		/* internal use */
298165782Sticso	val |= 0x101 << 0;	/* VLAN B ID */
299165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 1, 25, val);
300165782Sticso
301165782Sticso	/* Port 2 Control Register 1 and VLAN C */
302165782Sticso	val = 0;
303165782Sticso	val |= 0x2 << 12;	/* Port 2 VLAN Index */
304165782Sticso	val |= 1 << 11;		/* internal use */
305165782Sticso	val |= 1 << 10;		/* internal use */
306165782Sticso	val |= 1 << 9;		/* internal use */
307165782Sticso	val |= 1 << 7;		/* internal use */
308165782Sticso	val |= 1 << 6;		/* internal use */
309165782Sticso	val |= 0x14 << 0;	/* VLAN C membership */
310165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 2, 24, val);
311165782Sticso
312165782Sticso	/* Port 2 Control Register 2 and VLAN C */
313165782Sticso	val = 0;
314165782Sticso	val |= 1 << 15;		/* internal use */
315165782Sticso	val |= 1 << 14;		/* internal use */
316165782Sticso	val |= 1 << 13;		/* internal use */
317165782Sticso	val |= 1 << 12;		/* internal use */
318165782Sticso	val |= 0x102 << 0;	/* VLAN C ID */
319165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 2, 25, val);
320165782Sticso
321165782Sticso	/* Port 3 Control Register 1 and VLAN D */
322165782Sticso	val = 0;
323165782Sticso	val |= 0x3 << 12;	/* Port 3 VLAN Index */
324165782Sticso	val |= 1 << 11;		/* internal use */
325165782Sticso	val |= 1 << 10;		/* internal use */
326165782Sticso	val |= 1 << 9;		/* internal use */
327165782Sticso	val |= 1 << 7;		/* internal use */
328165782Sticso	val |= 1 << 6;		/* internal use */
329165782Sticso	val |= 0x18 << 0;	/* VLAN D membership */
330165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 3, 24, val);
331165782Sticso
332165782Sticso	/* Port 3 Control Register 2 and VLAN D */
333165782Sticso	val = 0;
334165782Sticso	val |= 1 << 15;		/* internal use */
335165782Sticso	val |= 1 << 14;		/* internal use */
336165782Sticso	val |= 1 << 13;		/* internal use */
337165782Sticso	val |= 1 << 12;		/* internal use */
338165782Sticso	val |= 0x103 << 0;	/* VLAN D ID */
339165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 3, 25, val);
340165782Sticso
341165782Sticso	/* Port 4 Control Register 1 and VLAN E */
342165782Sticso	val = 0;
343165782Sticso	val |= 0x0 << 12;	/* Port 4 VLAN Index */
344165782Sticso	val |= 1 << 11;		/* internal use */
345165782Sticso	val |= 1 << 10;		/* internal use */
346165782Sticso	val |= 1 << 9;		/* internal use */
347165782Sticso	val |= 1 << 7;		/* internal use */
348165782Sticso	val |= 1 << 6;		/* internal use */
349165782Sticso	val |= 0 << 0;		/* VLAN E membership */
350165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 4, 24, val);
351165782Sticso
352165782Sticso	/* Port 4 Control Register 2 and VLAN E */
353165782Sticso	val = 0;
354165782Sticso	val |= 1 << 15;		/* internal use */
355165782Sticso	val |= 1 << 14;		/* internal use */
356165782Sticso	val |= 1 << 13;		/* internal use */
357165782Sticso	val |= 1 << 12;		/* internal use */
358165782Sticso	val |= 0x104 << 0;	/* VLAN E ID */
359165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 4, 25, val);
360165782Sticso#endif
361165782Sticso
362165782Sticso#ifdef RL_DEBUG
363165782Sticso	rlswitch_phydump(dev);
364165782Sticso#endif
365165782Sticso	MIIBUS_MEDIAINIT(sc->mii_dev);
366165782Sticso	return (0);
367165782Sticso}
368165782Sticso
369165782Sticsostatic int
370165782Sticsorlswitch_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
371165782Sticso{
372165782Sticso
373165782Sticso	switch (cmd) {
374165782Sticso	case MII_POLLSTAT:
375165782Sticso		break;
376165782Sticso
377165782Sticso	case MII_MEDIACHG:
378165782Sticso		break;
379165782Sticso
380165782Sticso	case MII_TICK:
381165782Sticso		/*
382165782Sticso		 * Is the interface even up?
383165782Sticso		 */
384165782Sticso		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
385165782Sticso			return (0);
386165782Sticso		break;
387165782Sticso	}
388165782Sticso
389165782Sticso	/* Update the media status. */
390165782Sticso	rlswitch_status(sc);
391165782Sticso
392165782Sticso	/* Callback if something changed. */
393165782Sticso	// mii_phy_update(sc, cmd);
394165782Sticso	return (0);
395165782Sticso}
396165782Sticso
397165782Sticsostatic void
398165782Sticsorlswitch_status(struct mii_softc *phy)
399165782Sticso{
400165782Sticso	struct mii_data *mii = phy->mii_pdata;
401165782Sticso
402165782Sticso	mii->mii_media_status = IFM_AVALID;
403165782Sticso	mii->mii_media_active = IFM_ETHER;
404165782Sticso	mii->mii_media_status |= IFM_ACTIVE;
405165782Sticso	mii->mii_media_active |= IFM_100_TX|IFM_FDX;
406165782Sticso}
407165782Sticso
408165782Sticso#ifdef RL_DEBUG
409165782Sticsostatic void
410165782Sticsorlswitch_phydump(device_t dev) {
411165782Sticso	int phy, reg, val;
412165782Sticso	struct mii_softc *sc;
413165782Sticso
414165782Sticso	sc = device_get_softc(dev);
415165782Sticso	device_printf(dev, "rlswitchphydump\n");
416165782Sticso	for (phy = 0; phy <= 5; phy++) {
417165782Sticso		printf("PHY%i:", phy);
418165782Sticso		for (reg = 0; reg <= 31; reg++) {
419165782Sticso			val = MIIBUS_READREG(sc->mii_dev, phy, reg);
420165782Sticso			printf(" 0x%x", val);
421165782Sticso		}
422165782Sticso		printf("\n");
423165782Sticso	}
424165782Sticso}
425165782Sticso#endif
426