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 if_t *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(if_t );
154 static void e6060sw_ifmedia_sts(if_t , 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(if_t ) * 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 if_t
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 if_t 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(if_t ifp)
887 {
888 struct e6060sw_softc *sc;
889 struct mii_data *mii;
890
891 sc = if_getsoftc(ifp);
892 mii = e6060sw_miiforport(sc, ifp->if_dunit); /* XXX - DRVAPI */
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(if_t ifp, struct ifmediareq *ifmr)
903 {
904 struct e6060sw_softc *sc;
905 struct mii_data *mii;
906
907 sc = if_getsoftc(ifp);
908 mii = e6060sw_miiforport(sc, ifp->if_dunit); /* XXX - DRVAPI */
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
1026 DRIVER_MODULE(e6060sw, mdio, e6060sw_driver, 0, 0);
1027 DRIVER_MODULE(miibus, e6060sw, miibus_driver, 0, 0);
1028 DRIVER_MODULE(mdio, e6060sw, mdio_driver, 0, 0);
1029 DRIVER_MODULE(etherswitch, e6060sw, etherswitch_driver, 0, 0);
1030 MODULE_VERSION(e6060sw, 1);
1031 MODULE_DEPEND(e6060sw, miibus, 1, 1, 1); /* XXX which versions? */
1032 MODULE_DEPEND(e6060sw, etherswitch, 1, 1, 1); /* XXX which versions? */
Cache object: 23def91188093c05bab7a4f2a2710651
|