]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/etherswitch/e6000sw/e6000sw.c
Checkpoint initial integration work
[FreeBSD/FreeBSD.git] / sys / dev / etherswitch / e6000sw / e6000sw.c
1 /*-
2  * Copyright (c) 2015 Semihalf
3  * Copyright (c) 2015 Stormshield
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/sockio.h>
35 #include <sys/kernel.h>
36 #include <sys/kthread.h>
37 #include <sys/socket.h>
38 #include <sys/module.h>
39 #include <sys/errno.h>
40 #include <sys/bus.h>
41 #include <sys/conf.h>
42 #include <sys/uio.h>
43 #include <sys/fcntl.h>
44
45 #include <net/if.h>
46 #include <net/if_media.h>
47 #include <net/if_types.h>
48
49 #include <machine/bus.h>
50 #include <machine/resource.h>
51
52 #include <arm/mv/mvwin.h>
53 #include <arm/mv/mvreg.h>
54 #include <arm/mv/mvvar.h>
55
56 #include <dev/etherswitch/etherswitch.h>
57 #include <dev/mdio/mdio.h>
58 #include <dev/mii/mii.h>
59 #include <dev/mii/miivar.h>
60 #include <dev/mge/if_mgevar.h>
61
62 #include "e6000swreg.h"
63 #include "etherswitch_if.h"
64 #include "miibus_if.h"
65 #include "mdio_if.h"
66
67 MALLOC_DECLARE(M_E6000SW);
68 MALLOC_DEFINE(M_E6000SW, "e6000sw", "e6000sw switch");
69
70 #define E6000SW_LOCK(_sc)                       \
71             sx_xlock(&(_sc)->sx)
72 #define E6000SW_UNLOCK(_sc)                     \
73             sx_unlock(&(_sc)->sx)
74 #define E6000SW_LOCK_ASSERT(_sc, _what)         \
75             sx_assert(&(_sc)->sx, (_what))
76 #define E6000SW_TRYLOCK(_sc)                    \
77             sx_tryxlock(&(_sc)->sx)
78
79 typedef struct e6000sw_softc {
80         device_t                dev;
81
82         struct sx               sx;
83         struct ifnet            *ifp[E6000SW_NUM_PHYS];
84         char                    *ifname[E6000SW_NUM_PHYS];
85         device_t                miibus[E6000SW_NUM_PHYS];
86         struct mii_data         *mii[E6000SW_NUM_PHYS];
87         struct callout          tick_callout;
88
89         uint32_t                cpuports_mask;
90
91         int                     vid[E6000SW_NUM_VGROUPS];
92         int                     members[E6000SW_NUM_VGROUPS];
93         int                     vgroup[E6000SW_NUM_PORTS];
94 } e6000sw_softc_t;
95
96 static etherswitch_info_t etherswitch_info = {
97         .es_nports =            E6000SW_NUM_PORTS,
98         .es_nvlangroups =       E6000SW_NUM_VGROUPS,
99         .es_name =              "Marvell 6000 series switch"
100 };
101
102 static void e6000sw_identify(driver_t *driver, device_t parent);
103 static int e6000sw_probe(device_t dev);
104 static int e6000sw_attach(device_t dev);
105 static int e6000sw_detach(device_t dev);
106 static int e6000sw_readphy(device_t dev, int phy, int reg);
107 static int e6000sw_writephy(device_t dev, int phy, int reg, int data);
108 static etherswitch_info_t* e6000sw_getinfo(device_t dev);
109 static void e6000sw_lock(device_t dev);
110 static void e6000sw_unlock(device_t dev);
111 static int e6000sw_getport(device_t dev, etherswitch_port_t *p);
112 static int e6000sw_setport(device_t dev, etherswitch_port_t *p);
113 static int e6000sw_readreg_wrapper(device_t dev, int addr_reg);
114 static int e6000sw_writereg_wrapper(device_t dev, int addr_reg, int val);
115 static int e6000sw_readphy_wrapper(device_t dev, int phy, int reg);
116 static int e6000sw_writephy_wrapper(device_t dev, int phy, int reg, int data);
117 static int e6000sw_getvgroup_wrapper(device_t dev, etherswitch_vlangroup_t *vg);
118 static int e6000sw_setvgroup_wrapper(device_t dev, etherswitch_vlangroup_t *vg);
119 static int e6000sw_setvgroup(device_t dev, etherswitch_vlangroup_t *vg);
120 static int e6000sw_getvgroup(device_t dev, etherswitch_vlangroup_t *vg);
121 static void e6000sw_setup(device_t dev, e6000sw_softc_t *sc);
122 static void e6000sw_port_vlan_conf(e6000sw_softc_t *sc);
123 static void e6000sw_tick(void *arg);
124 static void e6000sw_set_atustat(device_t dev, e6000sw_softc_t *sc, int bin,
125     int flag);
126 static int e6000sw_atu_flush(device_t dev, e6000sw_softc_t *sc, int flag);
127 static __inline void e6000sw_writereg(e6000sw_softc_t *sc, int addr, int reg,
128     int val);
129 static __inline uint32_t e6000sw_readreg(e6000sw_softc_t *sc, int addr,
130     int reg);
131 static int e6000sw_ifmedia_upd(struct ifnet *ifp);
132 static void e6000sw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
133 static int e6000sw_atu_mac_table(device_t dev, e6000sw_softc_t *sc, struct
134     atu_opt *atu, int flag);
135 static int e6000sw_get_pvid(e6000sw_softc_t *sc, int port, int *pvid);
136 static int e6000sw_set_pvid(e6000sw_softc_t *sc, int port, int pvid);
137 static __inline int e6000sw_cpuport(e6000sw_softc_t *sc, int port);
138 static __inline struct mii_data *e6000sw_miiforphy(e6000sw_softc_t *sc,
139     unsigned int phy);
140
141 static struct proc *e6000sw_kproc;
142
143 static device_method_t e6000sw_methods[] = {
144         /* device interface */
145         DEVMETHOD(device_identify,              e6000sw_identify),
146         DEVMETHOD(device_probe,                 e6000sw_probe),
147         DEVMETHOD(device_attach,                e6000sw_attach),
148         DEVMETHOD(device_detach,                e6000sw_detach),
149
150         /* bus interface */
151         DEVMETHOD(bus_add_child,                device_add_child_ordered),
152
153         /* mii interface */
154         DEVMETHOD(miibus_readreg,               e6000sw_readphy),
155         DEVMETHOD(miibus_writereg,              e6000sw_writephy),
156
157         /* etherswitch interface */
158         DEVMETHOD(etherswitch_getinfo,          e6000sw_getinfo),
159         DEVMETHOD(etherswitch_lock,             e6000sw_lock),
160         DEVMETHOD(etherswitch_unlock,           e6000sw_unlock),
161         DEVMETHOD(etherswitch_getport,          e6000sw_getport),
162         DEVMETHOD(etherswitch_setport,          e6000sw_setport),
163         DEVMETHOD(etherswitch_readreg,          e6000sw_readreg_wrapper),
164         DEVMETHOD(etherswitch_writereg,         e6000sw_writereg_wrapper),
165         DEVMETHOD(etherswitch_readphyreg,       e6000sw_readphy_wrapper),
166         DEVMETHOD(etherswitch_writephyreg,      e6000sw_writephy_wrapper),
167         DEVMETHOD(etherswitch_setvgroup,        e6000sw_setvgroup_wrapper),
168         DEVMETHOD(etherswitch_getvgroup,        e6000sw_getvgroup_wrapper),
169
170         DEVMETHOD_END
171 };
172
173 static devclass_t e6000sw_devclass;
174
175 DEFINE_CLASS_0(e6000sw, e6000sw_driver, e6000sw_methods,
176     sizeof(e6000sw_softc_t));
177
178 DRIVER_MODULE(e6000sw, mdio, e6000sw_driver, e6000sw_devclass, 0, 0);
179 DRIVER_MODULE(etherswitch, e6000sw, etherswitch_driver, etherswitch_devclass, 0,
180     0);
181 DRIVER_MODULE(miibus, e6000sw, miibus_driver, miibus_devclass, 0, 0);
182 MODULE_DEPEND(e6000sw, mdio, 1, 1, 1);
183
184 static void
185 e6000sw_identify(driver_t *driver, device_t parent)
186 {
187
188         if (device_find_child(parent, "e6000sw", -1) == NULL)
189                 BUS_ADD_CHILD(parent, 0, "e6000sw", -1);
190 }
191
192 static int
193 e6000sw_probe(device_t dev)
194 {
195         e6000sw_softc_t *sc;
196         const char *description;
197         unsigned int id;
198
199         sc = device_get_softc(dev);
200         bzero(sc, sizeof(e6000sw_softc_t));
201         sc->dev = dev;
202         /* Lock is necessary due to assertions. */
203         sx_init(&sc->sx, "e6000sw");
204         E6000SW_LOCK(sc);
205
206         id = e6000sw_readreg(sc, REG_PORT(0), SWITCH_ID);
207
208         switch (id & 0xfff0) {
209         case 0x3520:
210                 description = "Marvell 88E6352";
211                 break;
212         case 0x1720:
213                 description = "Marvell 88E6172";
214                 break;
215         case 0x1760:
216                 description = "Marvell 88E6176";
217                 break;
218         default:
219                 E6000SW_UNLOCK(sc);
220                 sx_destroy(&sc->sx);
221                 device_printf(dev, "Unrecognized device.\n");
222                 return (ENXIO);
223         }
224
225         device_set_desc(dev, description);
226
227         E6000SW_UNLOCK(sc);
228
229         return (BUS_PROBE_DEFAULT);
230 }
231
232 static int
233 e6000sw_attach(device_t dev)
234 {
235         e6000sw_softc_t *sc;
236         int phy, err, port;
237         char name[IFNAMSIZ];
238
239         err = 0;
240         sc = device_get_softc(dev);
241         E6000SW_LOCK(sc);
242         sc->cpuports_mask = E6000SW_CPUPORTS_MASK;
243         for (port = 0; port < E6000SW_NUM_PORTS; port++)
244                 sc->vgroup[port] = E6000SW_PORT_NO_VGROUP;
245         e6000sw_setup(dev, sc);
246
247         snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->dev));
248         for (phy = 0; phy < E6000SW_NUM_PHYS; phy++) {
249                 sc->ifp[phy] = if_alloc(IFT_ETHER);
250                 if (sc->ifp[phy] == NULL)
251                         goto out_fail;
252                 sc->ifp[phy]->if_softc = sc;
253                 sc->ifp[phy]->if_flags |= IFF_UP | IFF_BROADCAST |
254                     IFF_DRV_RUNNING | IFF_SIMPLEX;
255                 sc->ifname[phy] = malloc(strlen(name) + 1, M_E6000SW, M_WAITOK);
256                 if (sc->ifname[phy] == NULL)
257                         goto out_fail;
258                 bcopy(name, sc->ifname[phy], strlen(name) + 1);
259                 if_initname(sc->ifp[phy], sc->ifname[phy], phy);
260                 err = mii_attach(sc->dev, &sc->miibus[phy], sc->ifp[phy],
261                     e6000sw_ifmedia_upd, e6000sw_ifmedia_sts, BMSR_DEFCAPMASK,
262                     phy, MII_OFFSET_ANY, 0);
263                 if (err != 0) {
264                         device_printf(sc->dev,
265                             "attaching PHY %d failed\n",
266                             phy);
267                         goto out_fail;
268                 }
269                 sc->mii[phy] = device_get_softc(sc->miibus[phy]);
270         }
271         E6000SW_UNLOCK(sc);
272
273         bus_generic_probe(dev);
274         bus_enumerate_hinted_children(dev);
275         bus_generic_attach(dev);
276
277         kproc_create(e6000sw_tick, sc, &e6000sw_kproc, 0, 0,
278             "e6000sw tick kproc");
279
280         return (0);
281
282 out_fail:
283         e6000sw_detach(dev);
284
285         return (ENXIO);
286 }
287
288 static __inline void
289 e6000sw_poll_done(e6000sw_softc_t *sc)
290 {
291
292         while (e6000sw_readreg(sc, REG_GLOBAL2, PHY_CMD) &
293             (1 << PHY_CMD_SMI_BUSY))
294                 continue;
295 }
296
297
298 /*
299  * PHY registers are paged. Put page index in reg 22 (accessible from every
300  * page), then access specific register.
301  */
302 static int
303 e6000sw_readphy(device_t dev, int phy, int reg)
304 {
305         e6000sw_softc_t *sc;
306         uint32_t val;
307
308         sc = device_get_softc(dev);
309         val = 0;
310
311         if (phy >= E6000SW_NUM_PHYS || reg >= E6000SW_NUM_PHY_REGS) {
312                 device_printf(dev, "Wrong register address.\n");
313                 return (EINVAL);
314         }
315
316         E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
317
318         e6000sw_poll_done(sc);
319         val |= 1 << PHY_CMD_SMI_BUSY;
320         val |= PHY_CMD_MODE_MDIO << PHY_CMD_MODE;
321         val |= PHY_CMD_OPCODE_READ << PHY_CMD_OPCODE;
322         val |= (reg << PHY_CMD_REG_ADDR) & PHY_CMD_REG_ADDR_MASK;
323         val |= (phy << PHY_CMD_DEV_ADDR) & PHY_CMD_DEV_ADDR_MASK;
324         e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG, val);
325         e6000sw_poll_done(sc);
326         val = e6000sw_readreg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG)
327                 & PHY_DATA_MASK;
328
329         return (val);
330 }
331
332 static int
333 e6000sw_writephy(device_t dev, int phy, int reg, int data)
334 {
335         e6000sw_softc_t *sc;
336         uint32_t val;
337
338         sc = device_get_softc(dev);
339         val = 0;
340
341         if (phy >= E6000SW_NUM_PHYS || reg >= E6000SW_NUM_PHY_REGS) {
342                 device_printf(dev, "Wrong register address.\n");
343                 return (EINVAL);
344         }
345
346         E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
347
348         e6000sw_poll_done(sc);
349         val |= PHY_CMD_MODE_MDIO << PHY_CMD_MODE;
350         val |= 1 << PHY_CMD_SMI_BUSY;
351         val |= PHY_CMD_OPCODE_WRITE << PHY_CMD_OPCODE;
352         val |= (reg << PHY_CMD_REG_ADDR) & PHY_CMD_REG_ADDR_MASK;
353         val |= (phy << PHY_CMD_DEV_ADDR) & PHY_CMD_DEV_ADDR_MASK;
354         e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG,
355                          data & PHY_DATA_MASK);
356         e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG, val);
357         e6000sw_poll_done(sc);
358
359         return (0);
360 }
361
362 static int
363 e6000sw_detach(device_t dev)
364 {
365         int phy;
366         e6000sw_softc_t *sc;
367
368         sc = device_get_softc(dev);
369         bus_generic_detach(dev);
370         sx_destroy(&sc->sx);
371         for (phy = 0; phy < E6000SW_NUM_PHYS; phy++) {
372                 if (sc->miibus[phy] != NULL)
373                         device_delete_child(dev, sc->miibus[phy]);
374                 if (sc->ifp[phy] != NULL)
375                         if_free(sc->ifp[phy]);
376                 if (sc->ifname[phy] != NULL)
377                         free(sc->ifname[phy], M_E6000SW);
378         }
379
380         return (0);
381 }
382
383 static etherswitch_info_t*
384 e6000sw_getinfo(device_t dev)
385 {
386
387         return (&etherswitch_info);
388 }
389
390 static void
391 e6000sw_lock(device_t dev)
392 {
393         struct e6000sw_softc *sc;
394
395         sc = device_get_softc(dev);
396
397         E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED);
398         E6000SW_LOCK(sc);
399 }
400
401 static void
402 e6000sw_unlock(device_t dev)
403 {
404         struct e6000sw_softc *sc;
405
406         sc = device_get_softc(dev);
407
408         E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
409         E6000SW_UNLOCK(sc);
410 }
411
412 static int
413 e6000sw_getport(device_t dev, etherswitch_port_t *p)
414 {
415         struct mii_data *mii;
416         int err;
417         struct ifmediareq *ifmr;
418
419         err = 0;
420         e6000sw_softc_t *sc = device_get_softc(dev);
421         E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED);
422
423         E6000SW_LOCK(sc);
424
425         if (p->es_port >= E6000SW_NUM_PORTS ||
426             p->es_port < 0) {
427                 err = EINVAL;
428                 goto out;
429         }
430
431         e6000sw_get_pvid(sc, p->es_port, &p->es_pvid);
432
433         if (e6000sw_cpuport(sc, p->es_port)) {
434                 p->es_flags |= ETHERSWITCH_PORT_CPU;
435                 ifmr = &p->es_ifmr;
436                 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
437                 ifmr->ifm_count = 0;
438                 ifmr->ifm_current = ifmr->ifm_active =
439                     IFM_ETHER | IFM_1000_T | IFM_FDX;
440                 ifmr->ifm_mask = 0;
441         } else {
442                 mii = e6000sw_miiforphy(sc, p->es_port);
443                 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
444                     &mii->mii_media, SIOCGIFMEDIA);
445         }
446
447 out:
448         E6000SW_UNLOCK(sc);
449         return (err);
450 }
451
452 static int
453 e6000sw_setport(device_t dev, etherswitch_port_t *p)
454 {
455         e6000sw_softc_t *sc;
456         int err;
457         struct mii_data *mii;
458
459         err = 0;
460         sc = device_get_softc(dev);
461         E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED);
462
463         E6000SW_LOCK(sc);
464
465         if (p->es_port >= E6000SW_NUM_PORTS ||
466             p->es_port < 0) {
467                 err = EINVAL;
468                 goto out;
469         }
470
471         if (p->es_pvid != 0)
472                 e6000sw_set_pvid(sc, p->es_port, p->es_pvid);
473         if (!e6000sw_cpuport(sc, p->es_port)) {
474                 mii = e6000sw_miiforphy(sc, p->es_port);
475                 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, &mii->mii_media,
476                     SIOCSIFMEDIA);
477         }
478
479 out:
480         E6000SW_UNLOCK(sc);
481         return (err);
482 }
483
484 /*
485  * Registers in this switch are divided into sections, specified in
486  * documentation. So as to access any of them, section index and reg index
487  * is necessary. etherswitchcfg uses only one variable, so indexes were
488  * compressed into addr_reg: 32 * section_index + reg_index.
489  */
490 static int
491 e6000sw_readreg_wrapper(device_t dev, int addr_reg)
492 {
493
494         if ((addr_reg > (REG_GLOBAL2 * 32 + REG_NUM_MAX)) ||
495             (addr_reg < (REG_PORT(0) * 32))) {
496                 device_printf(dev, "Wrong register address.\n");
497                 return (EINVAL);
498         }
499
500         return (e6000sw_readreg(device_get_softc(dev), addr_reg / 32,
501             addr_reg % 32));
502 }
503
504 static int
505 e6000sw_writereg_wrapper(device_t dev, int addr_reg, int val)
506 {
507
508         if ((addr_reg > (REG_GLOBAL2 * 32 + REG_NUM_MAX)) ||
509             (addr_reg < (REG_PORT(0) * 32))) {
510                 device_printf(dev, "Wrong register address.\n");
511                 return (EINVAL);
512         }
513         e6000sw_writereg(device_get_softc(dev), addr_reg / 5,
514             addr_reg % 32, val);
515
516         return (0);
517 }
518
519 /*
520  * These wrappers are necessary because PHY accesses from etherswitchcfg
521  * need to be synchronized with locks, while miibus PHY accesses do not.
522  */
523 static int
524 e6000sw_readphy_wrapper(device_t dev, int phy, int reg)
525 {
526         e6000sw_softc_t *sc;
527         int ret;
528
529         sc = device_get_softc(dev);
530         E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED);
531
532         E6000SW_LOCK(sc);
533         ret = e6000sw_readphy(dev, phy, reg);
534         E6000SW_UNLOCK(sc);
535
536         return (ret);
537 }
538
539 static int
540 e6000sw_writephy_wrapper(device_t dev, int phy, int reg, int data)
541 {
542         e6000sw_softc_t *sc;
543         int ret;
544
545         sc = device_get_softc(dev);
546         E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED);
547
548         E6000SW_LOCK(sc);
549         ret = e6000sw_writephy(dev, phy, reg, data);
550         E6000SW_UNLOCK(sc);
551
552         return (ret);
553 }
554
555 /*
556  * setvgroup/getvgroup called from etherswitchfcg need to be locked,
557  * while internal calls do not.
558  */
559 static int
560 e6000sw_setvgroup_wrapper(device_t dev, etherswitch_vlangroup_t *vg)
561 {
562         e6000sw_softc_t *sc;
563         int ret;
564
565         sc = device_get_softc(dev);
566         E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED);
567
568         E6000SW_LOCK(sc);
569         ret = e6000sw_setvgroup(dev, vg);
570         E6000SW_UNLOCK(sc);
571
572         return (ret);
573 }
574
575 static int
576 e6000sw_getvgroup_wrapper(device_t dev, etherswitch_vlangroup_t *vg)
577 {
578         e6000sw_softc_t *sc;
579         int ret;
580
581         sc = device_get_softc(dev);
582         E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED);
583
584         E6000SW_LOCK(sc);
585         ret = e6000sw_getvgroup(dev, vg);
586         E6000SW_UNLOCK(sc);
587
588         return (ret);
589 }
590
591 static __inline void
592 e6000sw_flush_port(e6000sw_softc_t *sc, int port)
593 {
594         uint32_t reg;
595
596         reg = e6000sw_readreg(sc, REG_PORT(port),
597             PORT_VLAN_MAP);
598         reg &= ~PORT_VLAN_MAP_TABLE_MASK;
599         reg &= ~PORT_VLAN_MAP_FID_MASK;
600         e6000sw_writereg(sc, REG_PORT(port),
601             PORT_VLAN_MAP, reg);
602         if (sc->vgroup[port] != E6000SW_PORT_NO_VGROUP) {
603                 /*
604                  * If port belonged somewhere, owner-group
605                  * should have its entry removed.
606                  */
607                 sc->members[sc->vgroup[port]] &= ~(1 << port);
608                 sc->vgroup[port] = E6000SW_PORT_NO_VGROUP;
609         }
610 }
611
612 static __inline void
613 e6000sw_port_assign_vgroup(e6000sw_softc_t *sc, int port, int fid, int vgroup,
614     int members)
615 {
616         uint32_t reg;
617
618         reg = e6000sw_readreg(sc, REG_PORT(port),
619             PORT_VLAN_MAP);
620         reg &= ~PORT_VLAN_MAP_TABLE_MASK;
621         reg &= ~PORT_VLAN_MAP_FID_MASK;
622         reg |= members & ~(1 << port);
623         reg |= (fid << PORT_VLAN_MAP_FID) & PORT_VLAN_MAP_FID_MASK;
624         e6000sw_writereg(sc, REG_PORT(port), PORT_VLAN_MAP,
625             reg);
626         sc->vgroup[port] = vgroup;
627 }
628
629 static int
630 e6000sw_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
631 {
632         e6000sw_softc_t *sc;
633         int port, fid;
634
635         sc = device_get_softc(dev);
636         E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
637
638         if (vg->es_vlangroup >= E6000SW_NUM_VGROUPS)
639                 return (EINVAL);
640         if (vg->es_member_ports != vg->es_untagged_ports) {
641                 device_printf(dev, "Tagged ports not supported.\n");
642                 return (EINVAL);
643         }
644
645         vg->es_untagged_ports &= PORT_VLAN_MAP_TABLE_MASK;
646         fid = vg->es_vlangroup + 1;
647         for (port = 0; port < E6000SW_NUM_PORTS; port++) {
648                 if ((sc->members[vg->es_vlangroup] & (1 << port)) ||
649                     (vg->es_untagged_ports & (1 << port)))
650                         e6000sw_flush_port(sc, port);
651                 if (vg->es_untagged_ports & (1 << port))
652                         e6000sw_port_assign_vgroup(sc, port, fid,
653                             vg->es_vlangroup, vg->es_untagged_ports);
654         }
655         sc->vid[vg->es_vlangroup] = vg->es_vid;
656         sc->members[vg->es_vlangroup] = vg->es_untagged_ports;
657
658         return (0);
659 }
660
661 static int
662 e6000sw_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
663 {
664         e6000sw_softc_t *sc;
665
666         sc = device_get_softc(dev);
667         E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
668
669         if (vg->es_vlangroup >= E6000SW_NUM_VGROUPS)
670                 return (EINVAL);
671         vg->es_untagged_ports = vg->es_member_ports =
672             sc->members[vg->es_vlangroup];
673         vg->es_vid = ETHERSWITCH_VID_VALID;
674
675         return (0);
676 }
677
678 static __inline struct mii_data*
679 e6000sw_miiforphy(e6000sw_softc_t *sc, unsigned int phy)
680 {
681
682         if (phy >= E6000SW_NUM_PHYS)
683                 return (NULL);
684
685         return (device_get_softc(sc->miibus[phy]));
686 }
687
688 static int
689 e6000sw_ifmedia_upd(struct ifnet *ifp)
690 {
691         e6000sw_softc_t *sc;
692         struct mii_data *mii;
693
694         sc = ifp->if_softc;
695         mii = e6000sw_miiforphy(sc, ifp->if_dunit);
696         if (mii == NULL)
697                 return (ENXIO);
698         mii_mediachg(mii);
699
700         return (0);
701 }
702
703 static void
704 e6000sw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
705 {
706         e6000sw_softc_t *sc;
707         struct mii_data *mii;
708
709         sc = ifp->if_softc;
710         mii = e6000sw_miiforphy(sc, ifp->if_dunit);
711
712         if (mii == NULL)
713                 return;
714
715         mii_pollstat(mii);
716         ifmr->ifm_active = mii->mii_media_active;
717         ifmr->ifm_status = mii->mii_media_status;
718 }
719
720 static __inline uint32_t
721 e6000sw_readreg(e6000sw_softc_t *sc, int addr, int reg)
722 {
723
724         E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
725
726         return (MDIO_READREG(device_get_parent(sc->dev), addr, reg));
727 }
728
729 static __inline void
730 e6000sw_writereg(e6000sw_softc_t *sc, int addr, int reg, int val)
731 {
732
733         E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
734
735         MDIO_WRITEREG(device_get_parent(sc->dev), addr, reg, val);
736 }
737
738 static __inline int
739 e6000sw_cpuport(e6000sw_softc_t *sc, int port)
740 {
741
742         return (sc->cpuports_mask & (1 << port));
743 }
744
745 static __inline int
746 e6000sw_set_pvid(e6000sw_softc_t *sc, int port, int pvid)
747 {
748
749         e6000sw_writereg(sc, REG_PORT(port), PORT_VID, pvid &
750             PORT_VID_DEF_VID_MASK);
751
752         return (0);
753 }
754
755 static __inline int
756 e6000sw_get_pvid(e6000sw_softc_t *sc, int port, int *pvid)
757 {
758
759         if (pvid == NULL)
760                 return (ENXIO);
761
762         *pvid = e6000sw_readreg(sc, REG_PORT(port), PORT_VID) &
763             PORT_VID_DEF_VID_MASK;
764
765         return (0);
766 }
767
768 static void
769 e6000sw_tick (void *arg)
770 {
771         e6000sw_softc_t *sc;
772         struct mii_softc *miisc;
773         int i;
774
775         sc = arg;
776
777         E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED);
778         for (;;) {
779                 E6000SW_LOCK(sc);
780                 for (i = 0; i < E6000SW_NUM_PHYS; i++) {
781                         mii_tick(sc->mii[i]);
782                         LIST_FOREACH(miisc, &sc->mii[i]->mii_phys, mii_list) {
783                                 if (IFM_INST(sc->mii[i]->mii_media.ifm_cur->ifm_media)
784                                     != miisc->mii_inst)
785                                         continue;
786                                 mii_phy_update(miisc, MII_POLLSTAT);
787                         }
788                 }
789                 E6000SW_UNLOCK(sc);
790                 pause("e6000sw tick", 1000);
791         }
792 }
793
794 static void
795 e6000sw_setup(device_t dev, e6000sw_softc_t *sc)
796 {
797         uint16_t atu_ctrl, atu_age;
798
799         /* Set aging time */
800         e6000sw_writereg(sc, REG_GLOBAL, ATU_CONTROL,
801             (E6000SW_DEFAULT_AGETIME << ATU_CONTROL_AGETIME) |
802             (1 << ATU_CONTROL_LEARN2ALL));
803
804         /* Send all with specific mac address to cpu port */
805         e6000sw_writereg(sc, REG_GLOBAL2, MGMT_EN_2x, MGMT_EN_ALL);
806         e6000sw_writereg(sc, REG_GLOBAL2, MGMT_EN_0x, MGMT_EN_ALL);
807
808         /* Disable Remote Management */
809         e6000sw_writereg(sc, REG_GLOBAL, SWITCH_GLOBAL_CONTROL2, 0);
810
811         /* Disable loopback filter and flow control messages */
812         e6000sw_writereg(sc, REG_GLOBAL2, SWITCH_MGMT,
813             SWITCH_MGMT_PRI_MASK |
814             (1 << SWITCH_MGMT_RSVD2CPU) |
815             SWITCH_MGMT_FC_PRI_MASK |
816             (1 << SWITCH_MGMT_FORCEFLOW));
817
818         /* Set VLAN configuration */
819         e6000sw_port_vlan_conf(sc);
820
821         e6000sw_atu_flush(dev, sc, NO_OPERATION);
822         e6000sw_atu_mac_table(dev, sc, NULL, NO_OPERATION);
823         e6000sw_set_atustat(dev, sc, 0, COUNT_ALL);
824
825         /* Set ATU AgeTime to 15 seconds */
826         atu_age = 1;
827
828         atu_ctrl = e6000sw_readreg(sc, REG_GLOBAL, ATU_CONTROL);
829
830         /* Set new AgeTime field */
831         atu_ctrl &= ~ATU_CONTROL_AGETIME_MASK;
832         e6000sw_writereg(sc, REG_GLOBAL, ATU_CONTROL, atu_ctrl |
833             (atu_age << ATU_CONTROL_AGETIME));
834 }
835
836 static void
837 e6000sw_port_vlan_conf(e6000sw_softc_t *sc)
838 {
839         int port, ret;
840         etherswitch_vlangroup_t vg;
841         device_t dev;
842
843         dev = sc->dev;
844         /* Disable all ports */
845         for (port = 0; port < E6000SW_NUM_PORTS; port++) {
846                 ret = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL);
847                 e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL,
848                     (ret & ~PORT_CONTROL_ENABLE));
849         }
850
851         /* Set port priority */
852         for (port = 0; port < E6000SW_NUM_PORTS; port++) {
853                 ret = e6000sw_readreg(sc, REG_PORT(port), PORT_VID);
854                 ret &= ~PORT_VID_PRIORITY_MASK;
855                 e6000sw_writereg(sc, REG_PORT(port), PORT_VID, ret);
856         }
857
858         vg.es_vlangroup = 0;
859         vg.es_vid = 0;
860         vg.es_member_ports = vg.es_untagged_ports = E6000SW_DEF_VLANGROUP0;
861         e6000sw_setvgroup(dev, &vg);
862         vg.es_vlangroup = 1;
863         vg.es_vid = 1;
864         vg.es_member_ports = vg.es_untagged_ports = E6000SW_DEF_VLANGROUP1;
865         e6000sw_setvgroup(dev, &vg);
866
867         device_printf(dev, "Default vlangroups set.\n");
868         /* Set VID map */
869         for (port = 0; port < E6000SW_NUM_PORTS; port++) {
870                 ret = e6000sw_readreg(sc, REG_PORT(port), PORT_VID);
871                 ret &= ~PORT_VID_DEF_VID_MASK;
872                 ret |= (port + 1);
873                 e6000sw_writereg(sc, REG_PORT(port), PORT_VID, ret);
874         }
875
876         /* Enable all ports */
877         for (port = 0; port < E6000SW_NUM_PORTS; port++) {
878                 ret = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL);
879                 e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL, (ret |
880                     PORT_CONTROL_ENABLE));
881         }
882 }
883
884 static void
885 e6000sw_set_atustat(device_t dev, e6000sw_softc_t *sc, int bin, int flag)
886 {
887         uint16_t ret;
888
889         ret = e6000sw_readreg(sc, REG_GLOBAL2, ATU_STATS);
890         e6000sw_writereg(sc, REG_GLOBAL2, ATU_STATS, (bin << ATU_STATS_BIN ) |
891             (flag << ATU_STATS_FLAG));
892 }
893
894 static int
895 e6000sw_atu_mac_table(device_t dev, e6000sw_softc_t *sc, struct atu_opt *atu,
896     int flag)
897 {
898         uint16_t ret_opt;
899         uint16_t ret_data;
900         int retries;
901
902         if (flag == NO_OPERATION)
903                 return (0);
904         else if ((flag & (LOAD_FROM_FIB | PURGE_FROM_FIB | GET_NEXT_IN_FIB |
905             GET_VIOLATION_DATA | CLEAR_VIOLATION_DATA)) == 0) {
906                 device_printf(dev, "Wrong Opcode for ATU operation\n");
907                 return (EINVAL);
908         }
909
910         ret_opt = e6000sw_readreg(sc, REG_GLOBAL, ATU_OPERATION);
911
912         if (ret_opt & ATU_UNIT_BUSY) {
913                 device_printf(dev, "ATU unit is busy, cannot access"
914                     "register\n");
915                 return (EBUSY);
916         } else {
917                 if(flag & LOAD_FROM_FIB) {
918                         ret_data = e6000sw_readreg(sc, REG_GLOBAL, ATU_DATA);
919                         e6000sw_writereg(sc, REG_GLOBAL2, ATU_DATA, (ret_data &
920                             ~ENTRY_STATE));
921                 }
922                 e6000sw_writereg(sc, REG_GLOBAL, ATU_MAC_ADDR01, atu->mac_01);
923                 e6000sw_writereg(sc, REG_GLOBAL, ATU_MAC_ADDR23, atu->mac_23);
924                 e6000sw_writereg(sc, REG_GLOBAL, ATU_MAC_ADDR45, atu->mac_45);
925                 e6000sw_writereg(sc, REG_GLOBAL, ATU_FID, atu->fid);
926
927                 e6000sw_writereg(sc, REG_GLOBAL, ATU_OPERATION, (ret_opt |
928                     ATU_UNIT_BUSY | flag));
929
930                 retries = E6000SW_RETRIES;
931                 while (--retries & (e6000sw_readreg(sc, REG_GLOBAL,
932                     ATU_OPERATION) & ATU_UNIT_BUSY))
933                         DELAY(1);
934
935                 if (retries == 0)
936                         device_printf(dev, "Timeout while flushing\n");
937                 else if (flag & GET_NEXT_IN_FIB) {
938                         atu->mac_01 = e6000sw_readreg(sc, REG_GLOBAL,
939                             ATU_MAC_ADDR01);
940                         atu->mac_23 = e6000sw_readreg(sc, REG_GLOBAL,
941                             ATU_MAC_ADDR23);
942                         atu->mac_45 = e6000sw_readreg(sc, REG_GLOBAL,
943                             ATU_MAC_ADDR45);
944                 }
945         }
946
947         return (0);
948 }
949
950 static int
951 e6000sw_atu_flush(device_t dev, e6000sw_softc_t *sc, int flag)
952 {
953         uint16_t ret;
954         int retries;
955
956         if (flag == NO_OPERATION)
957                 return (0);
958
959         ret = e6000sw_readreg(sc, REG_GLOBAL, ATU_OPERATION);
960         if (ret & ATU_UNIT_BUSY) {
961                 device_printf(dev, "Atu unit is busy, cannot flush\n");
962                 return (EBUSY);
963         } else {
964                 e6000sw_writereg(sc, REG_GLOBAL, ATU_OPERATION, (ret |
965                     ATU_UNIT_BUSY | flag));
966                 retries = E6000SW_RETRIES;
967                 while (--retries & (e6000sw_readreg(sc, REG_GLOBAL,
968                     ATU_OPERATION) & ATU_UNIT_BUSY))
969                         DELAY(1);
970
971                 if (retries == 0)
972                         device_printf(dev, "Timeout while flushing\n");
973         }
974
975         return (0);
976 }