]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/etherswitch/ukswitch/ukswitch.c
Merge OpenSSL 1.0.2n.
[FreeBSD/FreeBSD.git] / sys / dev / etherswitch / ukswitch / ukswitch.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2013 Luiz Otavio O Souza.
5  * Copyright (c) 2011-2012 Stefan Bethke.
6  * Copyright (c) 2012 Adrian Chadd.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/errno.h>
36 #include <sys/kernel.h>
37 #include <sys/lock.h>
38 #include <sys/malloc.h>
39 #include <sys/module.h>
40 #include <sys/mutex.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <sys/sysctl.h>
44 #include <sys/systm.h>
45
46 #include <net/if.h>
47 #include <net/if_var.h>
48 #include <net/ethernet.h>
49 #include <net/if_media.h>
50 #include <net/if_types.h>
51
52 #include <machine/bus.h>
53 #include <dev/mii/mii.h>
54 #include <dev/mii/miivar.h>
55 #include <dev/mdio/mdio.h>
56
57 #include <dev/etherswitch/etherswitch.h>
58
59 #include "mdio_if.h"
60 #include "miibus_if.h"
61 #include "etherswitch_if.h"
62
63 MALLOC_DECLARE(M_UKSWITCH);
64 MALLOC_DEFINE(M_UKSWITCH, "ukswitch", "ukswitch data structures");
65
66 struct ukswitch_softc {
67         struct mtx      sc_mtx;         /* serialize access to softc */
68         device_t        sc_dev;
69         int             media;          /* cpu port media */
70         int             cpuport;        /* which PHY is connected to the CPU */
71         int             phymask;        /* PHYs we manage */
72         int             phyoffset;      /* PHYs register offset */
73         int             numports;       /* number of ports */
74         int             ifpport[MII_NPHY];
75         int             *portphy;
76         char            **ifname;
77         device_t        **miibus;
78         struct ifnet    **ifp;
79         struct callout  callout_tick;
80         etherswitch_info_t      info;
81 };
82
83 #define UKSWITCH_LOCK(_sc)                      \
84             mtx_lock(&(_sc)->sc_mtx)
85 #define UKSWITCH_UNLOCK(_sc)                    \
86             mtx_unlock(&(_sc)->sc_mtx)
87 #define UKSWITCH_LOCK_ASSERT(_sc, _what)        \
88             mtx_assert(&(_sc)->sc_mtx, (_what))
89 #define UKSWITCH_TRYLOCK(_sc)                   \
90             mtx_trylock(&(_sc)->sc_mtx)
91
92 #if defined(DEBUG)
93 #define DPRINTF(dev, args...) device_printf(dev, args)
94 #else
95 #define DPRINTF(dev, args...)
96 #endif
97
98 static inline int ukswitch_portforphy(struct ukswitch_softc *, int);
99 static void ukswitch_tick(void *);
100 static int ukswitch_ifmedia_upd(struct ifnet *);
101 static void ukswitch_ifmedia_sts(struct ifnet *, struct ifmediareq *);
102
103 static int
104 ukswitch_probe(device_t dev)
105 {
106         struct ukswitch_softc *sc;
107
108         sc = device_get_softc(dev);
109         bzero(sc, sizeof(*sc));
110
111         device_set_desc_copy(dev, "Generic MDIO switch driver");
112         return (BUS_PROBE_DEFAULT);
113 }
114
115 static int
116 ukswitch_attach_phys(struct ukswitch_softc *sc)
117 {
118         int phy, port = 0, err = 0;
119         char name[IFNAMSIZ];
120
121         /* PHYs need an interface, so we generate a dummy one */
122         snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
123         for (phy = 0; phy < MII_NPHY; phy++) {
124                 if (((1 << phy) & sc->phymask) == 0)
125                         continue;
126                 sc->ifpport[phy] = port;
127                 sc->portphy[port] = phy;
128                 sc->ifp[port] = if_alloc(IFT_ETHER);
129                 sc->ifp[port]->if_softc = sc;
130                 sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST |
131                     IFF_DRV_RUNNING | IFF_SIMPLEX;
132                 sc->ifname[port] = malloc(strlen(name)+1, M_UKSWITCH, M_WAITOK);
133                 bcopy(name, sc->ifname[port], strlen(name)+1);
134                 if_initname(sc->ifp[port], sc->ifname[port], port);
135                 sc->miibus[port] = malloc(sizeof(device_t), M_UKSWITCH,
136                     M_WAITOK | M_ZERO);
137                 err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port],
138                     ukswitch_ifmedia_upd, ukswitch_ifmedia_sts, \
139                     BMSR_DEFCAPMASK, phy + sc->phyoffset, MII_OFFSET_ANY, 0);
140                 DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
141                     device_get_nameunit(*sc->miibus[port]),
142                     sc->ifp[port]->if_xname);
143                 if (err != 0) {
144                         device_printf(sc->sc_dev,
145                             "attaching PHY %d failed\n",
146                             phy);
147                         break;
148                 }
149                 sc->info.es_nports = port + 1;
150                 if (++port >= sc->numports)
151                         break;
152         }
153         return (err);
154 }
155
156 static int
157 ukswitch_attach(device_t dev)
158 {
159         struct ukswitch_softc *sc;
160         int err = 0;
161
162         sc = device_get_softc(dev);
163
164         sc->sc_dev = dev;
165         mtx_init(&sc->sc_mtx, "ukswitch", NULL, MTX_DEF);
166         strlcpy(sc->info.es_name, device_get_desc(dev),
167             sizeof(sc->info.es_name));
168
169         /* XXX Defaults */
170         sc->numports = 6;
171         sc->phymask = 0x0f;
172         sc->phyoffset = 0;
173         sc->cpuport = -1;
174         sc->media = 100;
175
176         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
177             "numports", &sc->numports);
178         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
179             "phymask", &sc->phymask);
180         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
181             "phyoffset", &sc->phyoffset);
182         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
183             "cpuport", &sc->cpuport);
184         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
185             "media", &sc->media);
186
187         /* Support only fast and giga ethernet. */
188         if (sc->media != 100 && sc->media != 1000)
189                 sc->media = 100;
190
191         if (sc->cpuport != -1)
192                 /* Always attach the cpu port. */
193                 sc->phymask |= (1 << sc->cpuport);
194
195         /* We do not support any vlan groups. */
196         sc->info.es_nvlangroups = 0;
197
198         sc->ifp = malloc(sizeof(struct ifnet *) * sc->numports, M_UKSWITCH,
199             M_WAITOK | M_ZERO);
200         sc->ifname = malloc(sizeof(char *) * sc->numports, M_UKSWITCH,
201             M_WAITOK | M_ZERO);
202         sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_UKSWITCH,
203             M_WAITOK | M_ZERO);
204         sc->portphy = malloc(sizeof(int) * sc->numports, M_UKSWITCH,
205             M_WAITOK | M_ZERO);
206
207         /*
208          * Attach the PHYs and complete the bus enumeration.
209          */
210         err = ukswitch_attach_phys(sc);
211         if (err != 0)
212                 return (err);
213
214         bus_generic_probe(dev);
215         bus_enumerate_hinted_children(dev);
216         err = bus_generic_attach(dev);
217         if (err != 0)
218                 return (err);
219         
220         callout_init(&sc->callout_tick, 0);
221
222         ukswitch_tick(sc);
223         
224         return (err);
225 }
226
227 static int
228 ukswitch_detach(device_t dev)
229 {
230         struct ukswitch_softc *sc = device_get_softc(dev);
231         int i, port;
232
233         callout_drain(&sc->callout_tick);
234
235         for (i=0; i < MII_NPHY; i++) {
236                 if (((1 << i) & sc->phymask) == 0)
237                         continue;
238                 port = ukswitch_portforphy(sc, i);
239                 if (sc->miibus[port] != NULL)
240                         device_delete_child(dev, (*sc->miibus[port]));
241                 if (sc->ifp[port] != NULL)
242                         if_free(sc->ifp[port]);
243                 free(sc->ifname[port], M_UKSWITCH);
244                 free(sc->miibus[port], M_UKSWITCH);
245         }
246
247         free(sc->portphy, M_UKSWITCH);
248         free(sc->miibus, M_UKSWITCH);
249         free(sc->ifname, M_UKSWITCH);
250         free(sc->ifp, M_UKSWITCH);
251
252         bus_generic_detach(dev);
253         mtx_destroy(&sc->sc_mtx);
254
255         return (0);
256 }
257
258 /*
259  * Convert PHY number to port number.
260  */
261 static inline int
262 ukswitch_portforphy(struct ukswitch_softc *sc, int phy)
263 {
264
265         return (sc->ifpport[phy]);
266 }
267
268 static inline struct mii_data *
269 ukswitch_miiforport(struct ukswitch_softc *sc, int port)
270 {
271
272         if (port < 0 || port > sc->numports)
273                 return (NULL);
274         return (device_get_softc(*sc->miibus[port]));
275 }
276
277 static inline struct ifnet *
278 ukswitch_ifpforport(struct ukswitch_softc *sc, int port)
279 {
280
281         if (port < 0 || port > sc->numports)
282                 return (NULL);
283         return (sc->ifp[port]);
284 }
285
286 /*
287  * Poll the status for all PHYs.
288  */
289 static void
290 ukswitch_miipollstat(struct ukswitch_softc *sc)
291 {
292         int i, port;
293         struct mii_data *mii;
294         struct mii_softc *miisc;
295
296         UKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
297
298         for (i = 0; i < MII_NPHY; i++) {
299                 if (((1 << i) & sc->phymask) == 0)
300                         continue;
301                 port = ukswitch_portforphy(sc, i);
302                 if ((*sc->miibus[port]) == NULL)
303                         continue;
304                 mii = device_get_softc(*sc->miibus[port]);
305                 LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
306                         if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
307                             miisc->mii_inst)
308                                 continue;
309                         ukphy_status(miisc);
310                         mii_phy_update(miisc, MII_POLLSTAT);
311                 }
312         }
313 }
314
315 static void
316 ukswitch_tick(void *arg)
317 {
318         struct ukswitch_softc *sc = arg;
319
320         ukswitch_miipollstat(sc);
321         callout_reset(&sc->callout_tick, hz, ukswitch_tick, sc);
322 }
323
324 static void
325 ukswitch_lock(device_t dev)
326 {
327         struct ukswitch_softc *sc = device_get_softc(dev);
328
329         UKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
330         UKSWITCH_LOCK(sc);
331 }
332
333 static void
334 ukswitch_unlock(device_t dev)
335 {
336         struct ukswitch_softc *sc = device_get_softc(dev);
337
338         UKSWITCH_LOCK_ASSERT(sc, MA_OWNED);
339         UKSWITCH_UNLOCK(sc);
340 }
341
342 static etherswitch_info_t *
343 ukswitch_getinfo(device_t dev)
344 {
345         struct ukswitch_softc *sc = device_get_softc(dev);
346         
347         return (&sc->info);
348 }
349
350 static int
351 ukswitch_getport(device_t dev, etherswitch_port_t *p)
352 {
353         struct ukswitch_softc *sc = device_get_softc(dev);
354         struct mii_data *mii;
355         struct ifmediareq *ifmr = &p->es_ifmr;
356         int err, phy;
357
358         if (p->es_port < 0 || p->es_port >= sc->numports)
359                 return (ENXIO);
360         p->es_pvid = 0;
361
362         phy = sc->portphy[p->es_port];
363         mii = ukswitch_miiforport(sc, p->es_port);
364         if (sc->cpuport != -1 && phy == sc->cpuport) {
365                 /* fill in fixed values for CPU port */
366                 p->es_flags |= ETHERSWITCH_PORT_CPU;
367                 ifmr->ifm_count = 0;
368                 if (sc->media == 100)
369                         ifmr->ifm_current = ifmr->ifm_active =
370                             IFM_ETHER | IFM_100_TX | IFM_FDX;
371                 else
372                         ifmr->ifm_current = ifmr->ifm_active =
373                             IFM_ETHER | IFM_1000_T | IFM_FDX;
374                 ifmr->ifm_mask = 0;
375                 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
376         } else if (mii != NULL) {
377                 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
378                     &mii->mii_media, SIOCGIFMEDIA);
379                 if (err)
380                         return (err);
381         } else {
382                 return (ENXIO);
383         }
384         return (0);
385 }
386
387 static int
388 ukswitch_setport(device_t dev, etherswitch_port_t *p)
389 {
390         struct ukswitch_softc *sc = device_get_softc(dev);
391         struct ifmedia *ifm;
392         struct mii_data *mii;
393         struct ifnet *ifp;
394         int err;
395
396         if (p->es_port < 0 || p->es_port >= sc->numports)
397                 return (ENXIO);
398
399         if (sc->portphy[p->es_port] == sc->cpuport)
400                 return (ENXIO);
401
402         mii = ukswitch_miiforport(sc, p->es_port);
403         if (mii == NULL)
404                 return (ENXIO);
405
406         ifp = ukswitch_ifpforport(sc, p->es_port);
407
408         ifm = &mii->mii_media;
409         err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA);
410         return (err);
411 }
412
413 static int
414 ukswitch_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
415 {
416
417         /* Not supported. */
418         vg->es_vid = 0;
419         vg->es_member_ports = 0;
420         vg->es_untagged_ports = 0;
421         vg->es_fid = 0;
422         return (0);
423 }
424
425 static int
426 ukswitch_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
427 {
428
429         /* Not supported. */
430         return (0);
431 }
432
433 static void
434 ukswitch_statchg(device_t dev)
435 {
436
437         DPRINTF(dev, "%s\n", __func__);
438 }
439
440 static int
441 ukswitch_ifmedia_upd(struct ifnet *ifp)
442 {
443         struct ukswitch_softc *sc = ifp->if_softc;
444         struct mii_data *mii = ukswitch_miiforport(sc, ifp->if_dunit);
445
446         DPRINTF(sc->sc_dev, "%s\n", __func__);
447         if (mii == NULL)
448                 return (ENXIO);
449         mii_mediachg(mii);
450         return (0);
451 }
452
453 static void
454 ukswitch_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
455 {
456         struct ukswitch_softc *sc = ifp->if_softc;
457         struct mii_data *mii = ukswitch_miiforport(sc, ifp->if_dunit);
458
459         DPRINTF(sc->sc_dev, "%s\n", __func__);
460
461         if (mii == NULL)
462                 return;
463         mii_pollstat(mii);
464         ifmr->ifm_active = mii->mii_media_active;
465         ifmr->ifm_status = mii->mii_media_status;
466 }
467
468 static int
469 ukswitch_readphy(device_t dev, int phy, int reg)
470 {
471         struct ukswitch_softc *sc;
472         int data;
473
474         sc = device_get_softc(dev);
475         UKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
476
477         if (phy < 0 || phy >= 32)
478                 return (ENXIO);
479         if (reg < 0 || reg >= 32)
480                 return (ENXIO);
481
482         UKSWITCH_LOCK(sc);
483         data = MDIO_READREG(device_get_parent(dev), phy, reg);
484         UKSWITCH_UNLOCK(sc);
485
486         return (data);
487 }
488
489 static int
490 ukswitch_writephy(device_t dev, int phy, int reg, int data)
491 {
492         struct ukswitch_softc *sc;
493         int err;
494
495         sc = device_get_softc(dev);
496         UKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
497
498         if (phy < 0 || phy >= 32)
499                 return (ENXIO);
500         if (reg < 0 || reg >= 32)
501                 return (ENXIO);
502
503         UKSWITCH_LOCK(sc);
504         err = MDIO_WRITEREG(device_get_parent(dev), phy, reg, data);
505         UKSWITCH_UNLOCK(sc);
506
507         return (err);
508 }
509
510 static int
511 ukswitch_readreg(device_t dev, int addr)
512 {
513         struct ukswitch_softc *sc;
514
515         sc = device_get_softc(dev);
516         UKSWITCH_LOCK_ASSERT(sc, MA_OWNED);
517
518         /* Not supported. */
519         return (0);
520 }
521
522 static int
523 ukswitch_writereg(device_t dev, int addr, int value)
524 {
525         struct ukswitch_softc *sc;
526
527         sc = device_get_softc(dev);
528         UKSWITCH_LOCK_ASSERT(sc, MA_OWNED);
529
530         /* Not supported. */
531         return (0);
532 }
533
534 static device_method_t ukswitch_methods[] = {
535         /* Device interface */
536         DEVMETHOD(device_probe,         ukswitch_probe),
537         DEVMETHOD(device_attach,        ukswitch_attach),
538         DEVMETHOD(device_detach,        ukswitch_detach),
539         
540         /* bus interface */
541         DEVMETHOD(bus_add_child,        device_add_child_ordered),
542         
543         /* MII interface */
544         DEVMETHOD(miibus_readreg,       ukswitch_readphy),
545         DEVMETHOD(miibus_writereg,      ukswitch_writephy),
546         DEVMETHOD(miibus_statchg,       ukswitch_statchg),
547
548         /* MDIO interface */
549         DEVMETHOD(mdio_readreg,         ukswitch_readphy),
550         DEVMETHOD(mdio_writereg,        ukswitch_writephy),
551
552         /* etherswitch interface */
553         DEVMETHOD(etherswitch_lock,     ukswitch_lock),
554         DEVMETHOD(etherswitch_unlock,   ukswitch_unlock),
555         DEVMETHOD(etherswitch_getinfo,  ukswitch_getinfo),
556         DEVMETHOD(etherswitch_readreg,  ukswitch_readreg),
557         DEVMETHOD(etherswitch_writereg, ukswitch_writereg),
558         DEVMETHOD(etherswitch_readphyreg,       ukswitch_readphy),
559         DEVMETHOD(etherswitch_writephyreg,      ukswitch_writephy),
560         DEVMETHOD(etherswitch_getport,  ukswitch_getport),
561         DEVMETHOD(etherswitch_setport,  ukswitch_setport),
562         DEVMETHOD(etherswitch_getvgroup,        ukswitch_getvgroup),
563         DEVMETHOD(etherswitch_setvgroup,        ukswitch_setvgroup),
564
565         DEVMETHOD_END
566 };
567
568 DEFINE_CLASS_0(ukswitch, ukswitch_driver, ukswitch_methods,
569     sizeof(struct ukswitch_softc));
570 static devclass_t ukswitch_devclass;
571
572 DRIVER_MODULE(ukswitch, mdio, ukswitch_driver, ukswitch_devclass, 0, 0);
573 DRIVER_MODULE(miibus, ukswitch, miibus_driver, miibus_devclass, 0, 0);
574 DRIVER_MODULE(mdio, ukswitch, mdio_driver, mdio_devclass, 0, 0);
575 DRIVER_MODULE(etherswitch, ukswitch, etherswitch_driver, etherswitch_devclass, 0, 0);
576 MODULE_VERSION(ukswitch, 1);
577 MODULE_DEPEND(ukswitch, miibus, 1, 1, 1); /* XXX which versions? */
578 MODULE_DEPEND(ukswitch, etherswitch, 1, 1, 1); /* XXX which versions? */