]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/etherswitch/e6000sw/e6060sw.c
MFV r347989:
[FreeBSD/FreeBSD.git] / sys / dev / etherswitch / e6000sw / e6060sw.c
1 /*-
2  * Copyright (c) 2016-2017 Hiroki Mori
3  * Copyright (c) 2013 Luiz Otavio O Souza.
4  * Copyright (c) 2011-2012 Stefan Bethke.
5  * Copyright (c) 2012 Adrian Chadd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 /*
33  * This code is Marvell 88E6060 ethernet switch support code on etherswitch
34  * framework. 
35  * 88E6060 support is only port vlan support. Not support ingress/egress
36  * trailer.
37  * 88E6065 support is port and dot1q vlan. Also group base tag support.
38  */
39
40 #include <sys/param.h>
41 #include <sys/bus.h>
42 #include <sys/errno.h>
43 #include <sys/kernel.h>
44 #include <sys/lock.h>
45 #include <sys/malloc.h>
46 #include <sys/module.h>
47 #include <sys/mutex.h>
48 #include <sys/socket.h>
49 #include <sys/sockio.h>
50 #include <sys/sysctl.h>
51 #include <sys/systm.h>
52
53 #include <net/if.h>
54 #include <net/if_var.h>
55 #include <net/ethernet.h>
56 #include <net/if_media.h>
57 #include <net/if_types.h>
58
59 #include <machine/bus.h>
60 #include <dev/mii/mii.h>
61 #include <dev/mii/miivar.h>
62 #include <dev/mdio/mdio.h>
63
64 #include <dev/etherswitch/etherswitch.h>
65
66 #include "mdio_if.h"
67 #include "miibus_if.h"
68 #include "etherswitch_if.h"
69
70 #define CORE_REGISTER   0x8
71 #define SWITCH_ID       3
72
73 #define PORT_CONTROL    4
74 #define ENGRESSFSHIFT   2
75 #define ENGRESSFMASK    3
76 #define ENGRESSTAGSHIFT 12
77 #define ENGRESSTAGMASK  3
78
79 #define PORT_VLAN_MAP   6
80 #define FORCEMAPSHIFT   8
81 #define FORCEMAPMASK    1
82
83 #define PORT_DEFVLAN    7
84 #define DEFVIDMASK      0xfff
85 #define DEFPRIMASK      7
86
87 #define PORT_CONTROL2   8
88 #define DOT1QMODESHIFT  10
89 #define DOT1QMODEMASK   3
90 #define DOT1QNONE       0
91 #define DOT1QFALLBACK   1
92 #define DOT1QCHECK      2
93 #define DOT1QSECURE     3
94
95 #define GLOBAL_REGISTER 0xf
96
97 #define VTU_OPERATION   5
98 #define VTU_VID_REG     6
99 #define VTU_DATA1_REG   7
100 #define VTU_DATA2_REG   8
101 #define VTU_DATA3_REG   9
102 #define VTU_BUSY        0x8000
103 #define VTU_FLASH       1
104 #define VTU_LOAD_PURGE  3
105 #define VTU_GET_NEXT    4
106 #define VTU_VIOLATION   7
107
108 MALLOC_DECLARE(M_E6060SW);
109 MALLOC_DEFINE(M_E6060SW, "e6060sw", "e6060sw data structures");
110
111 struct e6060sw_softc {
112         struct mtx      sc_mtx;         /* serialize access to softc */
113         device_t        sc_dev;
114         int             vlan_mode;
115         int             media;          /* cpu port media */
116         int             cpuport;        /* which PHY is connected to the CPU */
117         int             phymask;        /* PHYs we manage */
118         int             numports;       /* number of ports */
119         int             ifpport[MII_NPHY];
120         int             *portphy;
121         char            **ifname;
122         device_t        **miibus;
123         struct ifnet    **ifp;
124         struct callout  callout_tick;
125         etherswitch_info_t      info;
126         int             smi_offset;
127         int             sw_model;
128 };
129
130 /* Switch Identifier DeviceID */
131
132 #define E6060           0x60
133 #define E6063           0x63            
134 #define E6065           0x65            
135
136 #define E6060SW_LOCK(_sc)                       \
137             mtx_lock(&(_sc)->sc_mtx)
138 #define E6060SW_UNLOCK(_sc)                     \
139             mtx_unlock(&(_sc)->sc_mtx)
140 #define E6060SW_LOCK_ASSERT(_sc, _what) \
141             mtx_assert(&(_sc)->sc_mtx, (_what))
142 #define E6060SW_TRYLOCK(_sc)                    \
143             mtx_trylock(&(_sc)->sc_mtx)
144
145 #if defined(DEBUG)
146 #define DPRINTF(dev, args...) device_printf(dev, args)
147 #else
148 #define DPRINTF(dev, args...)
149 #endif
150
151 static inline int e6060sw_portforphy(struct e6060sw_softc *, int);
152 static void e6060sw_tick(void *);
153 static int e6060sw_ifmedia_upd(struct ifnet *);
154 static void e6060sw_ifmedia_sts(struct ifnet *, struct ifmediareq *);
155
156 static void e6060sw_setup(device_t dev);
157 static int e6060sw_read_vtu(device_t dev, int num, int *data1, int *data2);
158 static void e6060sw_set_vtu(device_t dev, int num, int data1, int data2);
159
160 static int
161 e6060sw_probe(device_t dev)
162 {
163         int data;
164         struct e6060sw_softc *sc;
165         int devid, i;
166         char *devname;
167         char desc[80];
168
169         sc = device_get_softc(dev);
170         bzero(sc, sizeof(*sc));
171
172         devid = 0;
173         for (i = 0; i < 2; ++i) {
174                 data = MDIO_READREG(device_get_parent(dev), 
175                     CORE_REGISTER + i * 0x10, SWITCH_ID);
176                 if (bootverbose)
177                         device_printf(dev,"Switch Identifier Register %x\n",
178                             data);
179
180                 devid = data >> 4;
181                 if (devid == E6060 || 
182                     devid == E6063 || devid == E6065) {
183                         sc->sw_model = devid;
184                         sc->smi_offset = i * 0x10;
185                         break;
186                 }
187         }
188
189         if (devid == E6060)
190                 devname = "88E6060";
191         else if (devid == E6063)
192                 devname = "88E6063";
193         else if (devid == E6065)
194                 devname = "88E6065";
195         else
196                 return (ENXIO);
197
198         sprintf(desc, "Marvell %s MDIO switch driver at 0x%02x",
199             devname, sc->smi_offset);
200         device_set_desc_copy(dev, desc);
201
202         return (BUS_PROBE_DEFAULT);
203 }
204
205 static int
206 e6060sw_attach_phys(struct e6060sw_softc *sc)
207 {
208         int phy, port, err;
209         char name[IFNAMSIZ];
210
211         port = 0;
212         err = 0;
213         /* PHYs need an interface, so we generate a dummy one */
214         snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
215         for (phy = 0; phy < sc->numports; phy++) {
216                 if (((1 << phy) & sc->phymask) == 0)
217                         continue;
218                 sc->ifpport[phy] = port;
219                 sc->portphy[port] = phy;
220                 sc->ifp[port] = if_alloc(IFT_ETHER);
221                 if (sc->ifp[port] == NULL) {
222                         device_printf(sc->sc_dev, "couldn't allocate ifnet structure\n");
223                         err = ENOMEM;
224                         break;
225                 }
226
227                 sc->ifp[port]->if_softc = sc;
228                 sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST |
229                     IFF_DRV_RUNNING | IFF_SIMPLEX;
230                 if_initname(sc->ifp[port], name, port);
231                 sc->miibus[port] = malloc(sizeof(device_t), M_E6060SW,
232                     M_WAITOK | M_ZERO);
233                 err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port],
234                     e6060sw_ifmedia_upd, e6060sw_ifmedia_sts, \
235                     BMSR_DEFCAPMASK, phy + sc->smi_offset, MII_OFFSET_ANY, 0);
236                 DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
237                     device_get_nameunit(*sc->miibus[port]),
238                     sc->ifp[port]->if_xname);
239                 if (err != 0) {
240                         device_printf(sc->sc_dev,
241                             "attaching PHY %d failed\n",
242                             phy);
243                         break;
244                 }
245                 ++port;
246         }
247         sc->info.es_nports = port;
248         if (sc->cpuport != -1) {
249                 /* assume cpuport is last one */
250                 sc->ifpport[sc->cpuport] = port;
251                 sc->portphy[port] = sc->cpuport;
252                 ++sc->info.es_nports;
253         }
254         return (err);
255 }
256
257 static int
258 e6060sw_attach(device_t dev)
259 {
260         struct e6060sw_softc *sc;
261         int err;
262
263         sc = device_get_softc(dev);
264         err = 0;
265
266         sc->sc_dev = dev;
267         mtx_init(&sc->sc_mtx, "e6060sw", NULL, MTX_DEF);
268         strlcpy(sc->info.es_name, device_get_desc(dev),
269             sizeof(sc->info.es_name));
270
271         /* XXX Defaults */
272         if (sc->sw_model == E6063) {
273                 sc->numports = 3;
274                 sc->phymask = 0x07;
275                 sc->cpuport = 2;
276         } else {
277                 sc->numports = 6;
278                 sc->phymask = 0x1f;
279                 sc->cpuport = 5;
280         }
281         sc->media = 100;
282
283         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
284             "numports", &sc->numports);
285         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
286             "phymask", &sc->phymask);
287         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
288             "cpuport", &sc->cpuport);
289         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
290             "media", &sc->media);
291
292         if (sc->sw_model == E6060) {
293                 sc->info.es_nvlangroups = sc->numports;
294                 sc->info.es_vlan_caps = ETHERSWITCH_VLAN_PORT;
295         } else {
296                 sc->info.es_nvlangroups = 64;
297                 sc->info.es_vlan_caps = ETHERSWITCH_VLAN_PORT | 
298                     ETHERSWITCH_VLAN_DOT1Q;
299         }
300
301         e6060sw_setup(dev);
302
303         sc->ifp = malloc(sizeof(struct ifnet *) * sc->numports, M_E6060SW,
304             M_WAITOK | M_ZERO);
305         sc->ifname = malloc(sizeof(char *) * sc->numports, M_E6060SW,
306             M_WAITOK | M_ZERO);
307         sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_E6060SW,
308             M_WAITOK | M_ZERO);
309         sc->portphy = malloc(sizeof(int) * sc->numports, M_E6060SW,
310             M_WAITOK | M_ZERO);
311
312         /*
313          * Attach the PHYs and complete the bus enumeration.
314          */
315         err = e6060sw_attach_phys(sc);
316         if (err != 0)
317                 return (err);
318
319         bus_generic_probe(dev);
320         bus_enumerate_hinted_children(dev);
321         err = bus_generic_attach(dev);
322         if (err != 0)
323                 return (err);
324         
325         callout_init(&sc->callout_tick, 0);
326
327         e6060sw_tick(sc);
328         
329         return (err);
330 }
331
332 static int
333 e6060sw_detach(device_t dev)
334 {
335         struct e6060sw_softc *sc;
336         int i, port;
337
338         sc = device_get_softc(dev);
339
340         callout_drain(&sc->callout_tick);
341
342         for (i = 0; i < MII_NPHY; i++) {
343                 if (((1 << i) & sc->phymask) == 0)
344                         continue;
345                 port = e6060sw_portforphy(sc, i);
346                 if (sc->miibus[port] != NULL)
347                         device_delete_child(dev, (*sc->miibus[port]));
348                 if (sc->ifp[port] != NULL)
349                         if_free(sc->ifp[port]);
350                 free(sc->ifname[port], M_E6060SW);
351                 free(sc->miibus[port], M_E6060SW);
352         }
353
354         free(sc->portphy, M_E6060SW);
355         free(sc->miibus, M_E6060SW);
356         free(sc->ifname, M_E6060SW);
357         free(sc->ifp, M_E6060SW);
358
359         bus_generic_detach(dev);
360         mtx_destroy(&sc->sc_mtx);
361
362         return (0);
363 }
364
365 /*
366  * Convert PHY number to port number.
367  */
368 static inline int
369 e6060sw_portforphy(struct e6060sw_softc *sc, int phy)
370 {
371
372         return (sc->ifpport[phy]);
373 }
374
375 static inline struct mii_data *
376 e6060sw_miiforport(struct e6060sw_softc *sc, int port)
377 {
378
379         if (port < 0 || port > sc->numports)
380                 return (NULL);
381         if (port == sc->cpuport)
382                 return (NULL);
383         return (device_get_softc(*sc->miibus[port]));
384 }
385
386 static inline struct ifnet *
387 e6060sw_ifpforport(struct e6060sw_softc *sc, int port)
388 {
389
390         if (port < 0 || port > sc->numports)
391                 return (NULL);
392         return (sc->ifp[port]);
393 }
394
395 /*
396  * Poll the status for all PHYs.
397  */
398 static void
399 e6060sw_miipollstat(struct e6060sw_softc *sc)
400 {
401         int i, port;
402         struct mii_data *mii;
403         struct mii_softc *miisc;
404
405         E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
406
407         for (i = 0; i < MII_NPHY; i++) {
408                 if (((1 << i) & sc->phymask) == 0)
409                         continue;
410                 port = e6060sw_portforphy(sc, i);
411                 if ((*sc->miibus[port]) == NULL)
412                         continue;
413                 mii = device_get_softc(*sc->miibus[port]);
414                 LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
415                         if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
416                             miisc->mii_inst)
417                                 continue;
418                         ukphy_status(miisc);
419                         mii_phy_update(miisc, MII_POLLSTAT);
420                 }
421         }
422 }
423
424 static void
425 e6060sw_tick(void *arg)
426 {
427         struct e6060sw_softc *sc;
428
429         sc = arg;
430
431         e6060sw_miipollstat(sc);
432         callout_reset(&sc->callout_tick, hz, e6060sw_tick, sc);
433 }
434
435 static void
436 e6060sw_lock(device_t dev)
437 {
438         struct e6060sw_softc *sc;
439
440         sc = device_get_softc(dev);
441
442         E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
443         E6060SW_LOCK(sc);
444 }
445
446 static void
447 e6060sw_unlock(device_t dev)
448 {
449         struct e6060sw_softc *sc;
450
451         sc = device_get_softc(dev);
452
453         E6060SW_LOCK_ASSERT(sc, MA_OWNED);
454         E6060SW_UNLOCK(sc);
455 }
456
457 static etherswitch_info_t *
458 e6060sw_getinfo(device_t dev)
459 {
460         struct e6060sw_softc *sc;
461         
462         sc = device_get_softc(dev);
463
464         return (&sc->info);
465 }
466
467 static int
468 e6060sw_getport(device_t dev, etherswitch_port_t *p)
469 {
470         struct e6060sw_softc *sc;
471         struct mii_data *mii;
472         struct ifmediareq *ifmr;
473         int err, phy;
474
475         sc = device_get_softc(dev);
476         ifmr = &p->es_ifmr;
477
478         if (p->es_port < 0 || p->es_port >= sc->numports)
479                 return (ENXIO);
480
481         p->es_pvid = 0;
482         if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
483                 p->es_pvid = MDIO_READREG(device_get_parent(dev), 
484                     CORE_REGISTER + sc->smi_offset + p->es_port,
485                     PORT_DEFVLAN) & 0xfff;
486         }
487
488         phy = sc->portphy[p->es_port];
489         mii = e6060sw_miiforport(sc, p->es_port);
490         if (sc->cpuport != -1 && phy == sc->cpuport) {
491                 /* fill in fixed values for CPU port */
492                 p->es_flags |= ETHERSWITCH_PORT_CPU;
493                 ifmr->ifm_count = 0;
494                 if (sc->media == 100)
495                         ifmr->ifm_current = ifmr->ifm_active =
496                             IFM_ETHER | IFM_100_TX | IFM_FDX;
497                 else
498                         ifmr->ifm_current = ifmr->ifm_active =
499                             IFM_ETHER | IFM_1000_T | IFM_FDX;
500                 ifmr->ifm_mask = 0;
501                 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
502         } else if (mii != NULL) {
503                 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
504                     &mii->mii_media, SIOCGIFMEDIA);
505                 if (err)
506                         return (err);
507         } else {
508                 return (ENXIO);
509         }
510         return (0);
511 }
512
513 static int
514 e6060sw_setport(device_t dev, etherswitch_port_t *p)
515 {
516         struct e6060sw_softc *sc;
517         struct ifmedia *ifm;
518         struct mii_data *mii;
519         struct ifnet *ifp;
520         int err;
521         int data;
522
523         sc = device_get_softc(dev);
524
525         if (p->es_port < 0 || p->es_port >= sc->numports)
526                 return (ENXIO);
527
528         if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
529                 data = MDIO_READREG(device_get_parent(dev), 
530                     CORE_REGISTER + sc->smi_offset + p->es_port,
531                     PORT_DEFVLAN);
532                 data &= ~0xfff;
533                 data |= p->es_pvid;
534                 data |= 1 << 12;
535                 MDIO_WRITEREG(device_get_parent(dev), 
536                     CORE_REGISTER + sc->smi_offset + p->es_port,
537                     PORT_DEFVLAN, data);
538         }
539
540         if (sc->portphy[p->es_port] == sc->cpuport)
541                 return(0);
542
543         mii = e6060sw_miiforport(sc, p->es_port);
544         if (mii == NULL)
545                 return (ENXIO);
546
547         ifp = e6060sw_ifpforport(sc, p->es_port);
548
549         ifm = &mii->mii_media;
550         err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA);
551         return (err);
552 }
553
554 static int
555 e6060sw_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
556 {
557         struct e6060sw_softc *sc;
558         int data1, data2;
559         int vid;
560         int i, tag;
561
562         sc = device_get_softc(dev);
563
564         if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
565                 vg->es_vid = ETHERSWITCH_VID_VALID;
566                 vg->es_vid |= vg->es_vlangroup;
567                 data1 = MDIO_READREG(device_get_parent(dev), 
568                     CORE_REGISTER + sc->smi_offset + vg->es_vlangroup,
569                     PORT_VLAN_MAP);
570                 vg->es_member_ports = data1 & 0x3f;
571                 vg->es_untagged_ports = vg->es_member_ports;
572                 vg->es_fid = 0;
573         } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
574                 if (vg->es_vlangroup == 0)
575                         return (0);
576                 vid = e6060sw_read_vtu(dev, vg->es_vlangroup, &data1, &data2);
577                 if (vid > 0) {
578                         vg->es_vid = ETHERSWITCH_VID_VALID;
579                         vg->es_vid |= vid;
580                         vg->es_member_ports = 0;
581                         vg->es_untagged_ports = 0;
582                         for (i = 0; i < 4; ++i) {
583                                 tag = data1 >> (i * 4) & 3;
584                                 if (tag == 0 || tag == 1) {
585                                         vg->es_member_ports |= 1 << i;
586                                         vg->es_untagged_ports |= 1 << i;
587                                 } else if (tag == 2) {
588                                         vg->es_member_ports |= 1 << i;
589                                 }
590                         }
591                         for (i = 0; i < 2; ++i) {
592                                 tag = data2 >> (i * 4) & 3;
593                                 if (tag == 0 || tag == 1) {
594                                         vg->es_member_ports |= 1 << (i + 4);
595                                         vg->es_untagged_ports |= 1 << (i + 4);
596                                 } else if (tag == 2) {
597                                         vg->es_member_ports |= 1 << (i + 4);
598                                 }
599                         }
600
601                 }
602         } else {
603                 vg->es_vid = 0;
604         }
605         return (0);
606 }
607
608 static int
609 e6060sw_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
610 {
611         struct e6060sw_softc *sc;
612         int data1, data2;
613         int i;
614
615         sc = device_get_softc(dev);
616
617         if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
618                 data1 = MDIO_READREG(device_get_parent(dev),
619                     CORE_REGISTER + sc->smi_offset + vg->es_vlangroup,
620                     PORT_VLAN_MAP);
621                 data1 &= ~0x3f;
622                 data1 |= vg->es_member_ports;
623                 MDIO_WRITEREG(device_get_parent(dev),
624                     CORE_REGISTER + sc->smi_offset + vg->es_vlangroup,
625                     PORT_VLAN_MAP, data1); 
626         } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
627                 if (vg->es_vlangroup == 0)
628                         return (0);
629                 data1 = 0;
630                 data2 = 0;
631                 for (i = 0; i < 6; ++i) {
632                         if (vg->es_member_ports & 
633                             vg->es_untagged_ports & (1 << i)) {
634                                 if (i < 4) {
635                                         data1 |= (0xd << i * 4);
636                                 } else {
637                                         data2 |= (0xd << (i - 4) * 4);
638                                 }
639                         } else if (vg->es_member_ports & (1 << i)) {
640                                 if (i < 4) {
641                                         data1 |= (0xe << i * 4);
642                                 } else {
643                                         data2 |= (0xe << (i - 4) * 4);
644                                 }
645                         } else {
646                                 if (i < 4) {
647                                         data1 |= (0x3 << i * 4);
648                                 } else {
649                                         data2 |= (0x3 << (i - 4) * 4);
650                                 }
651                         }
652                 }
653                 e6060sw_set_vtu(dev, vg->es_vlangroup, data1, data2);
654         }
655         return (0);
656 }
657
658 static void
659 e6060sw_reset_vlans(device_t dev)
660 {
661         struct e6060sw_softc *sc;
662         uint32_t ports;
663         int i;
664         int data;
665
666         sc = device_get_softc(dev);
667
668         for (i = 0; i <= sc->numports; i++) {
669                 ports = (1 << (sc->numports + 1)) - 1;
670                 ports &= ~(1 << i);
671                 if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
672                         data = i << 12;
673                 } else if (sc->vlan_mode == 0) {
674                         data = 1 << 8;
675                 } else {
676                         data = 0;
677                 }
678                 data |= ports;
679                 MDIO_WRITEREG(device_get_parent(dev),
680                     CORE_REGISTER + sc->smi_offset + i, PORT_VLAN_MAP, data);
681         }
682 }
683
684 static void
685 e6060sw_setup(device_t dev)
686 {
687         struct e6060sw_softc *sc;
688         int i;
689         int data;
690
691         sc = device_get_softc(dev);
692
693         for (i = 0; i <= sc->numports; i++) {
694                 if (sc->sw_model == E6063 || sc->sw_model == E6065) {
695                         data = MDIO_READREG(device_get_parent(dev),
696                             CORE_REGISTER + sc->smi_offset + i, PORT_VLAN_MAP);
697                         data &= ~(FORCEMAPMASK << FORCEMAPSHIFT);
698                         MDIO_WRITEREG(device_get_parent(dev),
699                             CORE_REGISTER + sc->smi_offset + i,
700                             PORT_VLAN_MAP, data);
701
702                         data = MDIO_READREG(device_get_parent(dev),
703                             CORE_REGISTER + sc->smi_offset + i, PORT_CONTROL);
704                         data |= 3 << ENGRESSFSHIFT;
705                         MDIO_WRITEREG(device_get_parent(dev),
706                             CORE_REGISTER + sc->smi_offset + i, 
707                             PORT_CONTROL, data);
708                 }
709         }
710 }
711
712 static void
713 e6060sw_dot1q_mode(device_t dev, int mode)
714 {
715         struct e6060sw_softc *sc;
716         int i;
717         int data;
718
719         sc = device_get_softc(dev);
720
721         for (i = 0; i <= sc->numports; i++) {
722                 data = MDIO_READREG(device_get_parent(dev),
723                     CORE_REGISTER + sc->smi_offset + i, PORT_CONTROL2);
724                 data &= ~(DOT1QMODEMASK << DOT1QMODESHIFT);
725                 data |= mode << DOT1QMODESHIFT;
726                 MDIO_WRITEREG(device_get_parent(dev),
727                     CORE_REGISTER + sc->smi_offset + i, PORT_CONTROL2, data);
728
729                 data = MDIO_READREG(device_get_parent(dev), 
730                     CORE_REGISTER + sc->smi_offset + i,
731                     PORT_DEFVLAN);
732                 data &= ~0xfff;
733                 data |= 1;
734                 MDIO_WRITEREG(device_get_parent(dev), 
735                     CORE_REGISTER + sc->smi_offset + i,
736                     PORT_DEFVLAN, data);
737         }
738 }
739
740 static int
741 e6060sw_getconf(device_t dev, etherswitch_conf_t *conf)
742 {
743         struct e6060sw_softc *sc;
744         
745         sc = device_get_softc(dev);
746
747         /* Return the VLAN mode. */
748         conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
749         conf->vlan_mode = sc->vlan_mode;
750
751         return (0);
752 }
753
754 static void
755 e6060sw_init_vtu(device_t dev)
756 {
757         struct e6060sw_softc *sc;
758         int busy;
759
760         sc = device_get_softc(dev);
761
762         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
763             VTU_OPERATION, VTU_BUSY | (VTU_FLASH << 12));
764         while (1) {
765                 busy = MDIO_READREG(device_get_parent(dev),
766                     GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION);
767                 if ((busy & VTU_BUSY) == 0)
768                         break;
769         }
770
771         /* initial member set at vlan 1*/
772         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
773             VTU_DATA1_REG, 0xcccc);
774         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
775             VTU_DATA2_REG, 0x00cc);
776         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
777             VTU_VID_REG, 0x1000 | 1);
778         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
779             VTU_OPERATION, VTU_BUSY | (VTU_LOAD_PURGE << 12) | 1);
780         while (1) {
781                 busy = MDIO_READREG(device_get_parent(dev),
782                     GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION);
783                 if ((busy & VTU_BUSY) == 0)
784                         break;
785         }
786 }
787
788 static void
789 e6060sw_set_vtu(device_t dev, int num, int data1, int data2)
790 {
791         struct e6060sw_softc *sc;
792         int busy;
793
794         sc = device_get_softc(dev);
795
796         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
797             VTU_DATA1_REG, data1);
798         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
799             VTU_DATA2_REG, data2);
800         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
801             VTU_VID_REG, 0x1000 | num);
802         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
803             VTU_OPERATION, VTU_BUSY | (VTU_LOAD_PURGE << 12) | num);
804         while (1) {
805                 busy = MDIO_READREG(device_get_parent(dev),
806                     GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION);
807                 if ((busy & VTU_BUSY) == 0)
808                         break;
809         }
810
811 }
812
813 static int
814 e6060sw_read_vtu(device_t dev, int num, int *data1, int *data2)
815 {
816         struct e6060sw_softc *sc;
817         int busy;
818
819         sc = device_get_softc(dev);
820
821         num = num - 1;
822
823         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
824             VTU_VID_REG, num & 0xfff);
825         /* Get Next */
826         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
827             VTU_OPERATION, VTU_BUSY | (VTU_GET_NEXT << 12));
828         while (1) {
829                 busy = MDIO_READREG(device_get_parent(dev),
830                     GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION);
831                 if ((busy & VTU_BUSY) == 0)
832                         break;
833         }
834
835         int vid = MDIO_READREG(device_get_parent(dev),
836             GLOBAL_REGISTER + sc->smi_offset, VTU_VID_REG);
837         if (vid & 0x1000) {
838                 *data1 = MDIO_READREG(device_get_parent(dev),
839                     GLOBAL_REGISTER + sc->smi_offset, VTU_DATA1_REG);
840                 *data2 = MDIO_READREG(device_get_parent(dev),
841                     GLOBAL_REGISTER + sc->smi_offset, VTU_DATA2_REG);
842                     
843                 return (vid & 0xfff);
844         }
845
846         return (-1);
847 }
848
849 static int
850 e6060sw_setconf(device_t dev, etherswitch_conf_t *conf)
851 {
852         struct e6060sw_softc *sc;
853
854         sc = device_get_softc(dev);
855
856         /* Set the VLAN mode. */
857         if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) {
858                 if (conf->vlan_mode == ETHERSWITCH_VLAN_PORT) {
859                         sc->vlan_mode = ETHERSWITCH_VLAN_PORT;
860                         e6060sw_dot1q_mode(dev, DOT1QNONE);
861                         e6060sw_reset_vlans(dev);
862                 } else if ((sc->sw_model == E6063 || sc->sw_model == E6065) &&
863                     conf->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
864                         sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q;
865                         e6060sw_dot1q_mode(dev, DOT1QSECURE);
866                         e6060sw_init_vtu(dev);
867                 } else {
868                         sc->vlan_mode = 0;
869                         /* Reset VLANs. */
870                         e6060sw_dot1q_mode(dev, DOT1QNONE);
871                         e6060sw_reset_vlans(dev);
872                 }
873         }
874
875         return (0);
876 }
877
878 static void
879 e6060sw_statchg(device_t dev)
880 {
881
882         DPRINTF(dev, "%s\n", __func__);
883 }
884
885 static int
886 e6060sw_ifmedia_upd(struct ifnet *ifp)
887 {
888         struct e6060sw_softc *sc;
889         struct mii_data *mii;
890
891         sc = ifp->if_softc;
892         mii = e6060sw_miiforport(sc, ifp->if_dunit);
893
894         DPRINTF(sc->sc_dev, "%s\n", __func__);
895         if (mii == NULL)
896                 return (ENXIO);
897         mii_mediachg(mii);
898         return (0);
899 }
900
901 static void
902 e6060sw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
903 {
904         struct e6060sw_softc *sc;
905         struct mii_data *mii;
906
907         sc = ifp->if_softc;
908         mii = e6060sw_miiforport(sc, ifp->if_dunit);
909
910         DPRINTF(sc->sc_dev, "%s\n", __func__);
911
912         if (mii == NULL)
913                 return;
914         mii_pollstat(mii);
915         ifmr->ifm_active = mii->mii_media_active;
916         ifmr->ifm_status = mii->mii_media_status;
917 }
918
919 static int
920 e6060sw_readphy(device_t dev, int phy, int reg)
921 {
922         struct e6060sw_softc *sc;
923         int data;
924
925         sc = device_get_softc(dev);
926         E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
927
928         if (phy < 0 || phy >= 32)
929                 return (ENXIO);
930         if (reg < 0 || reg >= 32)
931                 return (ENXIO);
932
933         E6060SW_LOCK(sc);
934         data = MDIO_READREG(device_get_parent(dev), phy, reg);
935         E6060SW_UNLOCK(sc);
936
937         return (data);
938 }
939
940 static int
941 e6060sw_writephy(device_t dev, int phy, int reg, int data)
942 {
943         struct e6060sw_softc *sc;
944         int err;
945
946         sc = device_get_softc(dev);
947         E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
948
949         if (phy < 0 || phy >= 32)
950                 return (ENXIO);
951         if (reg < 0 || reg >= 32)
952                 return (ENXIO);
953
954         E6060SW_LOCK(sc);
955         err = MDIO_WRITEREG(device_get_parent(dev), phy, reg, data);
956         E6060SW_UNLOCK(sc);
957
958         return (err);
959 }
960
961 /* addr is 5-8 bit is SMI Device Addres, 0-4 bit is SMI Register Address */
962
963 static int
964 e6060sw_readreg(device_t dev, int addr)
965 {
966         int devaddr, regaddr;
967
968         devaddr = (addr >> 5) & 0x1f;
969         regaddr = addr & 0x1f;
970
971         return MDIO_READREG(device_get_parent(dev), devaddr, regaddr);
972 }
973
974 /* addr is 5-8 bit is SMI Device Addres, 0-4 bit is SMI Register Address */
975
976 static int
977 e6060sw_writereg(device_t dev, int addr, int value)
978 {
979         int devaddr, regaddr;
980
981         devaddr = (addr >> 5) & 0x1f;
982         regaddr = addr & 0x1f;
983
984         return (MDIO_WRITEREG(device_get_parent(dev), devaddr, regaddr, value));
985 }
986
987 static device_method_t e6060sw_methods[] = {
988         /* Device interface */
989         DEVMETHOD(device_probe,         e6060sw_probe),
990         DEVMETHOD(device_attach,        e6060sw_attach),
991         DEVMETHOD(device_detach,        e6060sw_detach),
992         
993         /* bus interface */
994         DEVMETHOD(bus_add_child,        device_add_child_ordered),
995         
996         /* MII interface */
997         DEVMETHOD(miibus_readreg,       e6060sw_readphy),
998         DEVMETHOD(miibus_writereg,      e6060sw_writephy),
999         DEVMETHOD(miibus_statchg,       e6060sw_statchg),
1000
1001         /* MDIO interface */
1002         DEVMETHOD(mdio_readreg,         e6060sw_readphy),
1003         DEVMETHOD(mdio_writereg,        e6060sw_writephy),
1004
1005         /* etherswitch interface */
1006         DEVMETHOD(etherswitch_lock,     e6060sw_lock),
1007         DEVMETHOD(etherswitch_unlock,   e6060sw_unlock),
1008         DEVMETHOD(etherswitch_getinfo,  e6060sw_getinfo),
1009         DEVMETHOD(etherswitch_readreg,  e6060sw_readreg),
1010         DEVMETHOD(etherswitch_writereg, e6060sw_writereg),
1011         DEVMETHOD(etherswitch_readphyreg,       e6060sw_readphy),
1012         DEVMETHOD(etherswitch_writephyreg,      e6060sw_writephy),
1013         DEVMETHOD(etherswitch_getport,  e6060sw_getport),
1014         DEVMETHOD(etherswitch_setport,  e6060sw_setport),
1015         DEVMETHOD(etherswitch_getvgroup,        e6060sw_getvgroup),
1016         DEVMETHOD(etherswitch_setvgroup,        e6060sw_setvgroup),
1017         DEVMETHOD(etherswitch_setconf,  e6060sw_setconf),
1018         DEVMETHOD(etherswitch_getconf,  e6060sw_getconf),
1019
1020         DEVMETHOD_END
1021 };
1022
1023 DEFINE_CLASS_0(e6060sw, e6060sw_driver, e6060sw_methods,
1024     sizeof(struct e6060sw_softc));
1025 static devclass_t e6060sw_devclass;
1026
1027 DRIVER_MODULE(e6060sw, mdio, e6060sw_driver, e6060sw_devclass, 0, 0);
1028 DRIVER_MODULE(miibus, e6060sw, miibus_driver, miibus_devclass, 0, 0);
1029 DRIVER_MODULE(mdio, e6060sw, mdio_driver, mdio_devclass, 0, 0);
1030 DRIVER_MODULE(etherswitch, e6060sw, etherswitch_driver, etherswitch_devclass, 0, 0);
1031 MODULE_VERSION(e6060sw, 1);
1032 MODULE_DEPEND(e6060sw, miibus, 1, 1, 1); /* XXX which versions? */
1033 MODULE_DEPEND(e6060sw, etherswitch, 1, 1, 1); /* XXX which versions? */