]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mii/rlswitch.c
MFV r288408:
[FreeBSD/FreeBSD.git] / sys / dev / mii / rlswitch.c
1 /*-
2  * Copyright (c) 1997, 1998, 1999
3  *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4  * Copyright (c) 2006 Bernd Walter.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Bill Paul.
17  * 4. Neither the name of the author nor the names of any co-contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 /*
38  * driver for RealTek 8305 pseudo PHYs
39  */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/module.h>
45 #include <sys/socket.h>
46 #include <sys/bus.h>
47 #include <sys/taskqueue.h>      /* XXXGL: if_rlreg.h contamination */
48
49 #include <net/if.h>
50 #include <net/if_arp.h>
51 #include <net/if_media.h>
52
53 #include <dev/mii/mii.h>
54 #include <dev/mii/miivar.h>
55 #include "miidevs.h"
56
57 #include <machine/bus.h>
58 #include <dev/rl/if_rlreg.h>
59
60 #include "miibus_if.h"
61
62 //#define RL_DEBUG
63 #define RL_VLAN
64
65 static int rlswitch_probe(device_t);
66 static int rlswitch_attach(device_t);
67
68 static device_method_t rlswitch_methods[] = {
69         /* device interface */
70         DEVMETHOD(device_probe,         rlswitch_probe),
71         DEVMETHOD(device_attach,        rlswitch_attach),
72         DEVMETHOD(device_detach,        mii_phy_detach),
73         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
74         DEVMETHOD_END
75 };
76
77 static devclass_t rlswitch_devclass;
78
79 static driver_t rlswitch_driver = {
80         "rlswitch",
81         rlswitch_methods,
82         sizeof(struct mii_softc)
83 };
84
85 DRIVER_MODULE(rlswitch, miibus, rlswitch_driver, rlswitch_devclass, 0, 0);
86
87 static int      rlswitch_service(struct mii_softc *, struct mii_data *, int);
88 static void     rlswitch_status(struct mii_softc *);
89
90 #ifdef RL_DEBUG
91 static void     rlswitch_phydump(device_t dev);
92 #endif
93
94 static const struct mii_phydesc rlswitches[] = {
95         MII_PHY_DESC(REALTEK, RTL8305SC),
96         MII_PHY_END
97 };
98
99 static const struct mii_phy_funcs rlswitch_funcs = {
100         rlswitch_service,
101         rlswitch_status,
102         mii_phy_reset
103 };
104
105 static int
106 rlswitch_probe(device_t dev)
107 {
108         int rv;
109
110         rv = mii_phy_dev_probe(dev, rlswitches, BUS_PROBE_DEFAULT);
111         if (rv <= 0)
112                 return (rv);
113
114         return (ENXIO);
115 }
116
117 static int
118 rlswitch_attach(device_t dev)
119 {
120         struct mii_softc        *sc;
121
122         sc = device_get_softc(dev);
123
124         /*
125          * We handle all pseudo PHYs in a single instance.
126          */
127         mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE,
128             &rlswitch_funcs, 0);
129
130         sc->mii_capabilities = BMSR_100TXFDX & sc->mii_capmask;
131         device_printf(dev, " ");
132         mii_phy_add_media(sc);
133         printf("\n");
134 #ifdef RL_DEBUG
135         rlswitch_phydump(dev);
136 #endif
137         
138 #ifdef RL_VLAN
139         int val;
140
141         /* Global Control 0 */
142         val = 0;
143         val |= 0 << 10;         /* enable 802.1q VLAN Tag support */
144         val |= 0 << 9;          /* enable VLAN ingress filtering */
145         val |= 1 << 8;          /* disable VLAN tag admit control */
146         val |= 1 << 6;          /* internal use */
147         val |= 1 << 5;          /* internal use */
148         val |= 1 << 4;          /* internal use */
149         val |= 1 << 3;          /* internal use */
150         val |= 1 << 1;          /* reserved */
151         MIIBUS_WRITEREG(sc->mii_dev, 0, 16, val);
152
153         /* Global Control 2 */
154         val = 0;
155         val |= 1 << 15;         /* reserved */
156         val |= 0 << 14;         /* enable 1552 Bytes support */
157         val |= 1 << 13;         /* enable broadcast input drop */
158         val |= 1 << 12;         /* forward reserved control frames */
159         val |= 1 << 11;         /* disable forwarding unicast frames to other VLAN's */
160         val |= 1 << 10;         /* disable forwarding ARP broadcasts to other VLAN's */
161         val |= 1 << 9;          /* enable 48 pass 1 */
162         val |= 0 << 8;          /* enable VLAN */
163         val |= 1 << 7;          /* reserved */
164         val |= 1 << 6;          /* enable defer */
165         val |= 1 << 5;          /* 43ms LED blink time */
166         val |= 3 << 3;          /* 16:1 queue weight */
167         val |= 1 << 2;          /* disable broadcast storm control */
168         val |= 1 << 1;          /* enable power-on LED blinking */
169         val |= 1 << 0;          /* reserved */
170         MIIBUS_WRITEREG(sc->mii_dev, 0, 18, val);
171
172         /* Port 0 Control Register 0 */
173         val = 0;
174         val |= 1 << 15;         /* reserved */
175         val |= 1 << 11;         /* drop received packets with wrong VLAN tag */
176         val |= 1 << 10;         /* disable 802.1p priority classification */
177         val |= 1 << 9;          /* disable diffserv priority classification */
178         val |= 1 << 6;          /* internal use */
179         val |= 3 << 4;          /* internal use */
180         val |= 1 << 3;          /* internal use */
181         val |= 1 << 2;          /* internal use */
182         val |= 1 << 0;          /* remove VLAN tags on output */
183         MIIBUS_WRITEREG(sc->mii_dev, 0, 22, val);
184
185         /* Port 1 Control Register 0 */
186         val = 0;
187         val |= 1 << 15;         /* reserved */
188         val |= 1 << 11;         /* drop received packets with wrong VLAN tag */
189         val |= 1 << 10;         /* disable 802.1p priority classification */
190         val |= 1 << 9;          /* disable diffserv priority classification */
191         val |= 1 << 6;          /* internal use */
192         val |= 3 << 4;          /* internal use */
193         val |= 1 << 3;          /* internal use */
194         val |= 1 << 2;          /* internal use */
195         val |= 1 << 0;          /* remove VLAN tags on output */
196         MIIBUS_WRITEREG(sc->mii_dev, 1, 22, val);
197
198         /* Port 2 Control Register 0 */
199         val = 0;
200         val |= 1 << 15;         /* reserved */
201         val |= 1 << 11;         /* drop received packets with wrong VLAN tag */
202         val |= 1 << 10;         /* disable 802.1p priority classification */
203         val |= 1 << 9;          /* disable diffserv priority classification */
204         val |= 1 << 6;          /* internal use */
205         val |= 3 << 4;          /* internal use */
206         val |= 1 << 3;          /* internal use */
207         val |= 1 << 2;          /* internal use */
208         val |= 1 << 0;          /* remove VLAN tags on output */
209         MIIBUS_WRITEREG(sc->mii_dev, 2, 22, val);
210
211         /* Port 3 Control Register 0 */
212         val = 0;
213         val |= 1 << 15;         /* reserved */
214         val |= 1 << 11;         /* drop received packets with wrong VLAN tag */
215         val |= 1 << 10;         /* disable 802.1p priority classification */
216         val |= 1 << 9;          /* disable diffserv priority classification */
217         val |= 1 << 6;          /* internal use */
218         val |= 3 << 4;          /* internal use */
219         val |= 1 << 3;          /* internal use */
220         val |= 1 << 2;          /* internal use */
221         val |= 1 << 0;          /* remove VLAN tags on output */
222         MIIBUS_WRITEREG(sc->mii_dev, 3, 22, val);
223
224         /* Port 4 (system port) Control Register 0 */
225         val = 0;
226         val |= 1 << 15;         /* reserved */
227         val |= 0 << 11;         /* don't drop received packets with wrong VLAN tag */
228         val |= 1 << 10;         /* disable 802.1p priority classification */
229         val |= 1 << 9;          /* disable diffserv priority classification */
230         val |= 1 << 6;          /* internal use */
231         val |= 3 << 4;          /* internal use */
232         val |= 1 << 3;          /* internal use */
233         val |= 1 << 2;          /* internal use */
234         val |= 2 << 0;          /* add VLAN tags for untagged packets on output */
235         MIIBUS_WRITEREG(sc->mii_dev, 4, 22, val);
236
237         /* Port 0 Control Register 1 and VLAN A */
238         val = 0;
239         val |= 0x0 << 12;       /* Port 0 VLAN Index */
240         val |= 1 << 11;         /* internal use */
241         val |= 1 << 10;         /* internal use */
242         val |= 1 << 9;          /* internal use */
243         val |= 1 << 7;          /* internal use */
244         val |= 1 << 6;          /* internal use */
245         val |= 0x11 << 0;       /* VLAN A membership */
246         MIIBUS_WRITEREG(sc->mii_dev, 0, 24, val);
247
248         /* Port 0 Control Register 2 and VLAN A */
249         val = 0;
250         val |= 1 << 15;         /* internal use */
251         val |= 1 << 14;         /* internal use */
252         val |= 1 << 13;         /* internal use */
253         val |= 1 << 12;         /* internal use */
254         val |= 0x100 << 0;      /* VLAN A ID */
255         MIIBUS_WRITEREG(sc->mii_dev, 0, 25, val);
256
257         /* Port 1 Control Register 1 and VLAN B */
258         val = 0;
259         val |= 0x1 << 12;       /* Port 1 VLAN Index */
260         val |= 1 << 11;         /* internal use */
261         val |= 1 << 10;         /* internal use */
262         val |= 1 << 9;          /* internal use */
263         val |= 1 << 7;          /* internal use */
264         val |= 1 << 6;          /* internal use */
265         val |= 0x12 << 0;       /* VLAN B membership */
266         MIIBUS_WRITEREG(sc->mii_dev, 1, 24, val);
267
268         /* Port 1 Control Register 2 and VLAN B */
269         val = 0;
270         val |= 1 << 15;         /* internal use */
271         val |= 1 << 14;         /* internal use */
272         val |= 1 << 13;         /* internal use */
273         val |= 1 << 12;         /* internal use */
274         val |= 0x101 << 0;      /* VLAN B ID */
275         MIIBUS_WRITEREG(sc->mii_dev, 1, 25, val);
276
277         /* Port 2 Control Register 1 and VLAN C */
278         val = 0;
279         val |= 0x2 << 12;       /* Port 2 VLAN Index */
280         val |= 1 << 11;         /* internal use */
281         val |= 1 << 10;         /* internal use */
282         val |= 1 << 9;          /* internal use */
283         val |= 1 << 7;          /* internal use */
284         val |= 1 << 6;          /* internal use */
285         val |= 0x14 << 0;       /* VLAN C membership */
286         MIIBUS_WRITEREG(sc->mii_dev, 2, 24, val);
287
288         /* Port 2 Control Register 2 and VLAN C */
289         val = 0;
290         val |= 1 << 15;         /* internal use */
291         val |= 1 << 14;         /* internal use */
292         val |= 1 << 13;         /* internal use */
293         val |= 1 << 12;         /* internal use */
294         val |= 0x102 << 0;      /* VLAN C ID */
295         MIIBUS_WRITEREG(sc->mii_dev, 2, 25, val);
296
297         /* Port 3 Control Register 1 and VLAN D */
298         val = 0;
299         val |= 0x3 << 12;       /* Port 3 VLAN Index */
300         val |= 1 << 11;         /* internal use */
301         val |= 1 << 10;         /* internal use */
302         val |= 1 << 9;          /* internal use */
303         val |= 1 << 7;          /* internal use */
304         val |= 1 << 6;          /* internal use */
305         val |= 0x18 << 0;       /* VLAN D membership */
306         MIIBUS_WRITEREG(sc->mii_dev, 3, 24, val);
307
308         /* Port 3 Control Register 2 and VLAN D */
309         val = 0;
310         val |= 1 << 15;         /* internal use */
311         val |= 1 << 14;         /* internal use */
312         val |= 1 << 13;         /* internal use */
313         val |= 1 << 12;         /* internal use */
314         val |= 0x103 << 0;      /* VLAN D ID */
315         MIIBUS_WRITEREG(sc->mii_dev, 3, 25, val);
316
317         /* Port 4 Control Register 1 and VLAN E */
318         val = 0;
319         val |= 0x0 << 12;       /* Port 4 VLAN Index */
320         val |= 1 << 11;         /* internal use */
321         val |= 1 << 10;         /* internal use */
322         val |= 1 << 9;          /* internal use */
323         val |= 1 << 7;          /* internal use */
324         val |= 1 << 6;          /* internal use */
325         val |= 0 << 0;          /* VLAN E membership */
326         MIIBUS_WRITEREG(sc->mii_dev, 4, 24, val);
327
328         /* Port 4 Control Register 2 and VLAN E */
329         val = 0;
330         val |= 1 << 15;         /* internal use */
331         val |= 1 << 14;         /* internal use */
332         val |= 1 << 13;         /* internal use */
333         val |= 1 << 12;         /* internal use */
334         val |= 0x104 << 0;      /* VLAN E ID */
335         MIIBUS_WRITEREG(sc->mii_dev, 4, 25, val);
336 #endif
337
338 #ifdef RL_DEBUG
339         rlswitch_phydump(dev);
340 #endif
341         MIIBUS_MEDIAINIT(sc->mii_dev);
342         return (0);
343 }
344
345 static int
346 rlswitch_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
347 {
348
349         switch (cmd) {
350         case MII_POLLSTAT:
351                 break;
352
353         case MII_MEDIACHG:
354                 break;
355
356         case MII_TICK:
357                 break;
358         }
359
360         /* Update the media status. */
361         PHY_STATUS(sc);
362
363         /* Callback if something changed. */
364         // mii_phy_update(sc, cmd);
365         return (0);
366 }
367
368 static void
369 rlswitch_status(struct mii_softc *phy)
370 {
371         struct mii_data *mii = phy->mii_pdata;
372
373         mii->mii_media_status = IFM_AVALID;
374         mii->mii_media_active = IFM_ETHER;
375         mii->mii_media_status |= IFM_ACTIVE;
376         mii->mii_media_active |=
377             IFM_100_TX | IFM_FDX | mii_phy_flowstatus(phy);
378 }
379
380 #ifdef RL_DEBUG
381 static void
382 rlswitch_phydump(device_t dev) {
383         int phy, reg, val;
384         struct mii_softc *sc;
385
386         sc = device_get_softc(dev);
387         device_printf(dev, "rlswitchphydump\n");
388         for (phy = 0; phy <= 5; phy++) {
389                 printf("PHY%i:", phy);
390                 for (reg = 0; reg <= 31; reg++) {
391                         val = MIIBUS_READREG(sc->mii_dev, phy, reg);
392                         printf(" 0x%x", val);
393                 }
394                 printf("\n");
395         }
396 }
397 #endif