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