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