rlswitch.c revision 213364
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 213364 2010-10-02 18:53:12Z marius $");
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);
120213229Smarius	mii = ma->mii_data;
121165782Sticso	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
122165782Sticso
123213364Smarius	sc->mii_inst = mii->mii_instance++;
124165782Sticso	sc->mii_phy = ma->mii_phyno;
125165782Sticso	sc->mii_service = rlswitch_service;
126165782Sticso	sc->mii_pdata = mii;
127165782Sticso
128213364Smarius	/*
129213364Smarius	 * We handle all pseudo PHYs in a single instance.
130213364Smarius	 */
131165782Sticso	sc->mii_flags |= MIIF_NOISOLATE;
132165782Sticso
133165782Sticso#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
134165782Sticso
135165782Sticso#if 0
136165782Sticso	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
137213364Smarius	    MII_MEDIA_100_TX);
138165782Sticso#endif
139165782Sticso
140165782Sticso	sc->mii_capabilities = BMSR_100TXFDX & ma->mii_capmask;
141165782Sticso	device_printf(dev, " ");
142165782Sticso	mii_phy_add_media(sc);
143165782Sticso	printf("\n");
144165782Sticso#undef ADD
145165782Sticso#ifdef RL_DEBUG
146165782Sticso	rlswitch_phydump(dev);
147165782Sticso#endif
148165782Sticso
149165782Sticso#ifdef RL_VLAN
150165782Sticso	int val;
151165782Sticso
152165782Sticso	/* Global Control 0 */
153165782Sticso	val = 0;
154165782Sticso	val |= 0 << 10;		/* enable 802.1q VLAN Tag support */
155165782Sticso	val |= 0 << 9;		/* enable VLAN ingress filtering */
156165782Sticso	val |= 1 << 8;		/* disable VLAN tag admit control */
157165782Sticso	val |= 1 << 6;		/* internal use */
158165782Sticso	val |= 1 << 5;		/* internal use */
159165782Sticso	val |= 1 << 4;		/* internal use */
160165782Sticso	val |= 1 << 3;		/* internal use */
161165782Sticso	val |= 1 << 1;		/* reserved */
162165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 0, 16, val);
163165782Sticso
164165782Sticso	/* Global Control 2 */
165165782Sticso	val = 0;
166165782Sticso	val |= 1 << 15;		/* reserved */
167165782Sticso	val |= 0 << 14;		/* enable 1552 Bytes support */
168165782Sticso	val |= 1 << 13;		/* enable broadcast input drop */
169165782Sticso	val |= 1 << 12;		/* forward reserved control frames */
170165782Sticso	val |= 1 << 11;		/* disable forwarding unicast frames to other VLAN's */
171165782Sticso	val |= 1 << 10;		/* disable forwarding ARP broadcasts to other VLAN's */
172165782Sticso	val |= 1 << 9;		/* enable 48 pass 1 */
173165782Sticso	val |= 0 << 8;		/* enable VLAN */
174165782Sticso	val |= 1 << 7;		/* reserved */
175165782Sticso	val |= 1 << 6;		/* enable defer */
176165782Sticso	val |= 1 << 5;		/* 43ms LED blink time */
177165782Sticso	val |= 3 << 3;		/* 16:1 queue weight */
178165782Sticso	val |= 1 << 2;		/* disable broadcast storm control */
179165782Sticso	val |= 1 << 1;		/* enable power-on LED blinking */
180165782Sticso	val |= 1 << 0;		/* reserved */
181165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 0, 18, val);
182165782Sticso
183165782Sticso	/* Port 0 Control Register 0 */
184165782Sticso	val = 0;
185165782Sticso	val |= 1 << 15;		/* reserved */
186165782Sticso	val |= 1 << 11;		/* drop received packets with wrong VLAN tag */
187165782Sticso	val |= 1 << 10;		/* disable 802.1p priority classification */
188165782Sticso	val |= 1 << 9;		/* disable diffserv priority classification */
189165782Sticso	val |= 1 << 6;		/* internal use */
190165782Sticso	val |= 3 << 4;		/* internal use */
191165782Sticso	val |= 1 << 3;		/* internal use */
192165782Sticso	val |= 1 << 2;		/* internal use */
193165782Sticso	val |= 1 << 0;		/* remove VLAN tags on output */
194165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 0, 22, val);
195165782Sticso
196165782Sticso	/* Port 1 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, 1, 22, val);
208165782Sticso
209165782Sticso	/* Port 2 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, 2, 22, val);
221165782Sticso
222165782Sticso	/* Port 3 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, 3, 22, val);
234165782Sticso
235165782Sticso	/* Port 4 (system port) Control Register 0 */
236165782Sticso	val = 0;
237165782Sticso	val |= 1 << 15;		/* reserved */
238165782Sticso	val |= 0 << 11;		/* don't 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 |= 2 << 0;		/* add VLAN tags for untagged packets on output */
246165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 4, 22, val);
247165782Sticso
248165782Sticso	/* Port 0 Control Register 1 and VLAN A */
249165782Sticso	val = 0;
250165782Sticso	val |= 0x0 << 12;	/* Port 0 VLAN Index */
251165782Sticso	val |= 1 << 11;		/* internal use */
252165782Sticso	val |= 1 << 10;		/* internal use */
253165782Sticso	val |= 1 << 9;		/* internal use */
254165782Sticso	val |= 1 << 7;		/* internal use */
255165782Sticso	val |= 1 << 6;		/* internal use */
256165782Sticso	val |= 0x11 << 0;	/* VLAN A membership */
257165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 0, 24, val);
258165782Sticso
259165782Sticso	/* Port 0 Control Register 2 and VLAN A */
260165782Sticso	val = 0;
261165782Sticso	val |= 1 << 15;		/* internal use */
262165782Sticso	val |= 1 << 14;		/* internal use */
263165782Sticso	val |= 1 << 13;		/* internal use */
264165782Sticso	val |= 1 << 12;		/* internal use */
265165782Sticso	val |= 0x100 << 0;	/* VLAN A ID */
266165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 0, 25, val);
267165782Sticso
268165782Sticso	/* Port 1 Control Register 1 and VLAN B */
269165782Sticso	val = 0;
270165782Sticso	val |= 0x1 << 12;	/* Port 1 VLAN Index */
271165782Sticso	val |= 1 << 11;		/* internal use */
272165782Sticso	val |= 1 << 10;		/* internal use */
273165782Sticso	val |= 1 << 9;		/* internal use */
274165782Sticso	val |= 1 << 7;		/* internal use */
275165782Sticso	val |= 1 << 6;		/* internal use */
276165782Sticso	val |= 0x12 << 0;	/* VLAN B membership */
277165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 1, 24, val);
278165782Sticso
279165782Sticso	/* Port 1 Control Register 2 and VLAN B */
280165782Sticso	val = 0;
281165782Sticso	val |= 1 << 15;		/* internal use */
282165782Sticso	val |= 1 << 14;		/* internal use */
283165782Sticso	val |= 1 << 13;		/* internal use */
284165782Sticso	val |= 1 << 12;		/* internal use */
285165782Sticso	val |= 0x101 << 0;	/* VLAN B ID */
286165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 1, 25, val);
287165782Sticso
288165782Sticso	/* Port 2 Control Register 1 and VLAN C */
289165782Sticso	val = 0;
290165782Sticso	val |= 0x2 << 12;	/* Port 2 VLAN Index */
291165782Sticso	val |= 1 << 11;		/* internal use */
292165782Sticso	val |= 1 << 10;		/* internal use */
293165782Sticso	val |= 1 << 9;		/* internal use */
294165782Sticso	val |= 1 << 7;		/* internal use */
295165782Sticso	val |= 1 << 6;		/* internal use */
296165782Sticso	val |= 0x14 << 0;	/* VLAN C membership */
297165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 2, 24, val);
298165782Sticso
299165782Sticso	/* Port 2 Control Register 2 and VLAN C */
300165782Sticso	val = 0;
301165782Sticso	val |= 1 << 15;		/* internal use */
302165782Sticso	val |= 1 << 14;		/* internal use */
303165782Sticso	val |= 1 << 13;		/* internal use */
304165782Sticso	val |= 1 << 12;		/* internal use */
305165782Sticso	val |= 0x102 << 0;	/* VLAN C ID */
306165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 2, 25, val);
307165782Sticso
308165782Sticso	/* Port 3 Control Register 1 and VLAN D */
309165782Sticso	val = 0;
310165782Sticso	val |= 0x3 << 12;	/* Port 3 VLAN Index */
311165782Sticso	val |= 1 << 11;		/* internal use */
312165782Sticso	val |= 1 << 10;		/* internal use */
313165782Sticso	val |= 1 << 9;		/* internal use */
314165782Sticso	val |= 1 << 7;		/* internal use */
315165782Sticso	val |= 1 << 6;		/* internal use */
316165782Sticso	val |= 0x18 << 0;	/* VLAN D membership */
317165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 3, 24, val);
318165782Sticso
319165782Sticso	/* Port 3 Control Register 2 and VLAN D */
320165782Sticso	val = 0;
321165782Sticso	val |= 1 << 15;		/* internal use */
322165782Sticso	val |= 1 << 14;		/* internal use */
323165782Sticso	val |= 1 << 13;		/* internal use */
324165782Sticso	val |= 1 << 12;		/* internal use */
325165782Sticso	val |= 0x103 << 0;	/* VLAN D ID */
326165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 3, 25, val);
327165782Sticso
328165782Sticso	/* Port 4 Control Register 1 and VLAN E */
329165782Sticso	val = 0;
330165782Sticso	val |= 0x0 << 12;	/* Port 4 VLAN Index */
331165782Sticso	val |= 1 << 11;		/* internal use */
332165782Sticso	val |= 1 << 10;		/* internal use */
333165782Sticso	val |= 1 << 9;		/* internal use */
334165782Sticso	val |= 1 << 7;		/* internal use */
335165782Sticso	val |= 1 << 6;		/* internal use */
336165782Sticso	val |= 0 << 0;		/* VLAN E membership */
337165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 4, 24, val);
338165782Sticso
339165782Sticso	/* Port 4 Control Register 2 and VLAN E */
340165782Sticso	val = 0;
341165782Sticso	val |= 1 << 15;		/* internal use */
342165782Sticso	val |= 1 << 14;		/* internal use */
343165782Sticso	val |= 1 << 13;		/* internal use */
344165782Sticso	val |= 1 << 12;		/* internal use */
345165782Sticso	val |= 0x104 << 0;	/* VLAN E ID */
346165782Sticso	MIIBUS_WRITEREG(sc->mii_dev, 4, 25, val);
347165782Sticso#endif
348165782Sticso
349165782Sticso#ifdef RL_DEBUG
350165782Sticso	rlswitch_phydump(dev);
351165782Sticso#endif
352165782Sticso	MIIBUS_MEDIAINIT(sc->mii_dev);
353165782Sticso	return (0);
354165782Sticso}
355165782Sticso
356165782Sticsostatic int
357165782Sticsorlswitch_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
358165782Sticso{
359165782Sticso
360165782Sticso	switch (cmd) {
361165782Sticso	case MII_POLLSTAT:
362165782Sticso		break;
363165782Sticso
364165782Sticso	case MII_MEDIACHG:
365165782Sticso		break;
366165782Sticso
367165782Sticso	case MII_TICK:
368165782Sticso		/*
369165782Sticso		 * Is the interface even up?
370165782Sticso		 */
371165782Sticso		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
372165782Sticso			return (0);
373165782Sticso		break;
374165782Sticso	}
375165782Sticso
376165782Sticso	/* Update the media status. */
377165782Sticso	rlswitch_status(sc);
378165782Sticso
379165782Sticso	/* Callback if something changed. */
380165782Sticso	// mii_phy_update(sc, cmd);
381165782Sticso	return (0);
382165782Sticso}
383165782Sticso
384165782Sticsostatic void
385165782Sticsorlswitch_status(struct mii_softc *phy)
386165782Sticso{
387165782Sticso	struct mii_data *mii = phy->mii_pdata;
388165782Sticso
389165782Sticso	mii->mii_media_status = IFM_AVALID;
390165782Sticso	mii->mii_media_active = IFM_ETHER;
391165782Sticso	mii->mii_media_status |= IFM_ACTIVE;
392165782Sticso	mii->mii_media_active |= IFM_100_TX|IFM_FDX;
393165782Sticso}
394165782Sticso
395165782Sticso#ifdef RL_DEBUG
396165782Sticsostatic void
397165782Sticsorlswitch_phydump(device_t dev) {
398165782Sticso	int phy, reg, val;
399165782Sticso	struct mii_softc *sc;
400165782Sticso
401165782Sticso	sc = device_get_softc(dev);
402165782Sticso	device_printf(dev, "rlswitchphydump\n");
403165782Sticso	for (phy = 0; phy <= 5; phy++) {
404165782Sticso		printf("PHY%i:", phy);
405165782Sticso		for (reg = 0; reg <= 31; reg++) {
406165782Sticso			val = MIIBUS_READREG(sc->mii_dev, phy, reg);
407165782Sticso			printf(" 0x%x", val);
408165782Sticso		}
409165782Sticso		printf("\n");
410165782Sticso	}
411165782Sticso}
412165782Sticso#endif
413