ukswitch.c revision 249651
1249651Sadrian/*-
2249651Sadrian * Copyright (c) 2013 Luiz Otavio O Souza.
3249651Sadrian * Copyright (c) 2011-2012 Stefan Bethke.
4249651Sadrian * Copyright (c) 2012 Adrian Chadd.
5249651Sadrian * All rights reserved.
6249651Sadrian *
7249651Sadrian * Redistribution and use in source and binary forms, with or without
8249651Sadrian * modification, are permitted provided that the following conditions
9249651Sadrian * are met:
10249651Sadrian * 1. Redistributions of source code must retain the above copyright
11249651Sadrian *    notice, this list of conditions and the following disclaimer.
12249651Sadrian * 2. Redistributions in binary form must reproduce the above copyright
13249651Sadrian *    notice, this list of conditions and the following disclaimer in the
14249651Sadrian *    documentation and/or other materials provided with the distribution.
15249651Sadrian *
16249651Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17249651Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18249651Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19249651Sadrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20249651Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21249651Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22249651Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23249651Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24249651Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25249651Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26249651Sadrian * SUCH DAMAGE.
27249651Sadrian *
28249651Sadrian * $FreeBSD: head/sys/dev/etherswitch/ukswitch/ukswitch.c 249651 2013-04-19 17:50:38Z adrian $
29249651Sadrian */
30249651Sadrian
31249651Sadrian#include <sys/param.h>
32249651Sadrian#include <sys/bus.h>
33249651Sadrian#include <sys/errno.h>
34249651Sadrian#include <sys/kernel.h>
35249651Sadrian#include <sys/module.h>
36249651Sadrian#include <sys/socket.h>
37249651Sadrian#include <sys/sockio.h>
38249651Sadrian#include <sys/sysctl.h>
39249651Sadrian#include <sys/systm.h>
40249651Sadrian
41249651Sadrian#include <net/if.h>
42249651Sadrian#include <net/if_arp.h>
43249651Sadrian#include <net/ethernet.h>
44249651Sadrian#include <net/if_dl.h>
45249651Sadrian#include <net/if_media.h>
46249651Sadrian#include <net/if_types.h>
47249651Sadrian
48249651Sadrian#include <machine/bus.h>
49249651Sadrian#include <dev/mii/mii.h>
50249651Sadrian#include <dev/mii/miivar.h>
51249651Sadrian#include <dev/etherswitch/mdio.h>
52249651Sadrian
53249651Sadrian#include <dev/etherswitch/etherswitch.h>
54249651Sadrian
55249651Sadrian#include "mdio_if.h"
56249651Sadrian#include "miibus_if.h"
57249651Sadrian#include "etherswitch_if.h"
58249651Sadrian
59249651SadrianMALLOC_DECLARE(M_UKSWITCH);
60249651SadrianMALLOC_DEFINE(M_UKSWITCH, "ukswitch", "ukswitch data structures");
61249651Sadrian
62249651Sadrianstruct ukswitch_softc {
63249651Sadrian	struct mtx	sc_mtx;		/* serialize access to softc */
64249651Sadrian	device_t	sc_dev;
65249651Sadrian	int		media;		/* cpu port media */
66249651Sadrian	int		cpuport;	/* which PHY is connected to the CPU */
67249651Sadrian	int		phymask;	/* PHYs we manage */
68249651Sadrian	int		numports;	/* number of ports */
69249651Sadrian	int		ifpport[MII_NPHY];
70249651Sadrian	int		*portphy;
71249651Sadrian	char		**ifname;
72249651Sadrian	device_t	**miibus;
73249651Sadrian	struct ifnet	**ifp;
74249651Sadrian	struct callout	callout_tick;
75249651Sadrian	etherswitch_info_t	info;
76249651Sadrian};
77249651Sadrian
78249651Sadrian#define UKSWITCH_LOCK(_sc)			\
79249651Sadrian	    mtx_lock(&(_sc)->sc_mtx)
80249651Sadrian#define UKSWITCH_UNLOCK(_sc)			\
81249651Sadrian	    mtx_unlock(&(_sc)->sc_mtx)
82249651Sadrian#define UKSWITCH_LOCK_ASSERT(_sc, _what)	\
83249651Sadrian	    mtx_assert(&(_sc)->sc_mtx, (_what))
84249651Sadrian#define UKSWITCH_TRYLOCK(_sc)			\
85249651Sadrian	    mtx_trylock(&(_sc)->sc_mtx)
86249651Sadrian
87249651Sadrian#if defined(DEBUG)
88249651Sadrian#define	DPRINTF(dev, args...) device_printf(dev, args)
89249651Sadrian#else
90249651Sadrian#define	DPRINTF(dev, args...)
91249651Sadrian#endif
92249651Sadrian
93249651Sadrianstatic inline int ukswitch_portforphy(struct ukswitch_softc *, int);
94249651Sadrianstatic void ukswitch_tick(void *);
95249651Sadrianstatic int ukswitch_ifmedia_upd(struct ifnet *);
96249651Sadrianstatic void ukswitch_ifmedia_sts(struct ifnet *, struct ifmediareq *);
97249651Sadrian
98249651Sadrianstatic int
99249651Sadrianukswitch_probe(device_t dev)
100249651Sadrian{
101249651Sadrian	struct ukswitch_softc *sc;
102249651Sadrian
103249651Sadrian	sc = device_get_softc(dev);
104249651Sadrian	bzero(sc, sizeof(*sc));
105249651Sadrian
106249651Sadrian	device_set_desc_copy(dev, "Generic MDIO switch driver");
107249651Sadrian	return (BUS_PROBE_DEFAULT);
108249651Sadrian}
109249651Sadrian
110249651Sadrianstatic int
111249651Sadrianukswitch_attach_phys(struct ukswitch_softc *sc)
112249651Sadrian{
113249651Sadrian	int phy, port = 0, err = 0;
114249651Sadrian	char name[IFNAMSIZ];
115249651Sadrian
116249651Sadrian	/* PHYs need an interface, so we generate a dummy one */
117249651Sadrian	snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
118249651Sadrian	for (phy = 0; phy < MII_NPHY; phy++) {
119249651Sadrian		if (((1 << phy) & sc->phymask) == 0)
120249651Sadrian			continue;
121249651Sadrian		sc->ifpport[phy] = port;
122249651Sadrian		sc->portphy[port] = phy;
123249651Sadrian//		if (phy == sc->cpuport)
124249651Sadrian//			sc->info.es_cpuport = port;
125249651Sadrian		sc->ifp[port] = if_alloc(IFT_ETHER);
126249651Sadrian		sc->ifp[port]->if_softc = sc;
127249651Sadrian		sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST |
128249651Sadrian		    IFF_DRV_RUNNING | IFF_SIMPLEX;
129249651Sadrian		sc->ifname[port] = malloc(strlen(name)+1, M_UKSWITCH, M_WAITOK);
130249651Sadrian		bcopy(name, sc->ifname[port], strlen(name)+1);
131249651Sadrian		if_initname(sc->ifp[port], sc->ifname[port], port);
132249651Sadrian		sc->miibus[port] = malloc(sizeof(device_t), M_UKSWITCH,
133249651Sadrian		    M_WAITOK | M_ZERO);
134249651Sadrian		err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port],
135249651Sadrian		    ukswitch_ifmedia_upd, ukswitch_ifmedia_sts, \
136249651Sadrian		    BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
137249651Sadrian		DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
138249651Sadrian		    device_get_nameunit(*sc->miibus[port]),
139249651Sadrian		    sc->ifp[port]->if_xname);
140249651Sadrian		if (err != 0) {
141249651Sadrian			device_printf(sc->sc_dev,
142249651Sadrian			    "attaching PHY %d failed\n",
143249651Sadrian			    phy);
144249651Sadrian			break;
145249651Sadrian		}
146249651Sadrian		sc->info.es_nports = port + 1;
147249651Sadrian		if (++port >= sc->numports)
148249651Sadrian			break;
149249651Sadrian	}
150249651Sadrian	return (err);
151249651Sadrian}
152249651Sadrian
153249651Sadrianstatic int
154249651Sadrianukswitch_attach(device_t dev)
155249651Sadrian{
156249651Sadrian	struct ukswitch_softc *sc;
157249651Sadrian	int err = 0;
158249651Sadrian
159249651Sadrian	sc = device_get_softc(dev);
160249651Sadrian
161249651Sadrian	sc->sc_dev = dev;
162249651Sadrian	mtx_init(&sc->sc_mtx, "ukswitch", NULL, MTX_DEF);
163249651Sadrian	strlcpy(sc->info.es_name, device_get_desc(dev),
164249651Sadrian	    sizeof(sc->info.es_name));
165249651Sadrian
166249651Sadrian	/* XXX Defaults */
167249651Sadrian	sc->numports = 6;
168249651Sadrian	sc->phymask = 0x0f;
169249651Sadrian	sc->cpuport = 5;
170249651Sadrian	sc->media = 100;
171249651Sadrian
172249651Sadrian	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
173249651Sadrian	    "numports", &sc->numports);
174249651Sadrian	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
175249651Sadrian	    "phymask", &sc->phymask);
176249651Sadrian	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
177249651Sadrian	    "cpuport", &sc->cpuport);
178249651Sadrian	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
179249651Sadrian	    "media", &sc->media);
180249651Sadrian
181249651Sadrian	/* Support only fast and giga ethernet. */
182249651Sadrian	if (sc->media != 100 && sc->media != 1000)
183249651Sadrian		sc->media = 100;
184249651Sadrian
185249651Sadrian	/* Always attach the cpu port. */
186249651Sadrian	sc->phymask |= (1 << sc->cpuport);
187249651Sadrian//	sc->info.es_cpuport = sc->cpuport;
188249651Sadrian
189249651Sadrian	/* We do not support any vlan groups. */
190249651Sadrian	sc->info.es_nvlangroups = 0;
191249651Sadrian
192249651Sadrian	sc->ifp = malloc(sizeof(struct ifnet *) * sc->numports, M_UKSWITCH,
193249651Sadrian	    M_WAITOK | M_ZERO);
194249651Sadrian	sc->ifname = malloc(sizeof(char *) * sc->numports, M_UKSWITCH,
195249651Sadrian	    M_WAITOK | M_ZERO);
196249651Sadrian	sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_UKSWITCH,
197249651Sadrian	    M_WAITOK | M_ZERO);
198249651Sadrian	sc->portphy = malloc(sizeof(int) * sc->numports, M_UKSWITCH,
199249651Sadrian	    M_WAITOK | M_ZERO);
200249651Sadrian
201249651Sadrian	/*
202249651Sadrian	 * Attach the PHYs and complete the bus enumeration.
203249651Sadrian	 */
204249651Sadrian	err = ukswitch_attach_phys(sc);
205249651Sadrian	if (err != 0)
206249651Sadrian		return (err);
207249651Sadrian
208249651Sadrian	bus_generic_probe(dev);
209249651Sadrian	bus_enumerate_hinted_children(dev);
210249651Sadrian	err = bus_generic_attach(dev);
211249651Sadrian	if (err != 0)
212249651Sadrian		return (err);
213249651Sadrian
214249651Sadrian	callout_init(&sc->callout_tick, 0);
215249651Sadrian
216249651Sadrian	ukswitch_tick(sc);
217249651Sadrian
218249651Sadrian	return (err);
219249651Sadrian}
220249651Sadrian
221249651Sadrianstatic int
222249651Sadrianukswitch_detach(device_t dev)
223249651Sadrian{
224249651Sadrian	struct ukswitch_softc *sc = device_get_softc(dev);
225249651Sadrian	int i, port;
226249651Sadrian
227249651Sadrian	callout_drain(&sc->callout_tick);
228249651Sadrian
229249651Sadrian	for (i=0; i < MII_NPHY; i++) {
230249651Sadrian		if (((1 << i) & sc->phymask) == 0)
231249651Sadrian			continue;
232249651Sadrian		port = ukswitch_portforphy(sc, i);
233249651Sadrian		if (sc->miibus[port] != NULL)
234249651Sadrian			device_delete_child(dev, (*sc->miibus[port]));
235249651Sadrian		if (sc->ifp[port] != NULL)
236249651Sadrian			if_free(sc->ifp[port]);
237249651Sadrian		free(sc->ifname[port], M_UKSWITCH);
238249651Sadrian		free(sc->miibus[port], M_UKSWITCH);
239249651Sadrian	}
240249651Sadrian
241249651Sadrian	free(sc->portphy, M_UKSWITCH);
242249651Sadrian	free(sc->miibus, M_UKSWITCH);
243249651Sadrian	free(sc->ifname, M_UKSWITCH);
244249651Sadrian	free(sc->ifp, M_UKSWITCH);
245249651Sadrian
246249651Sadrian	bus_generic_detach(dev);
247249651Sadrian	mtx_destroy(&sc->sc_mtx);
248249651Sadrian
249249651Sadrian	return (0);
250249651Sadrian}
251249651Sadrian
252249651Sadrian/*
253249651Sadrian * Convert PHY number to port number.
254249651Sadrian */
255249651Sadrianstatic inline int
256249651Sadrianukswitch_portforphy(struct ukswitch_softc *sc, int phy)
257249651Sadrian{
258249651Sadrian
259249651Sadrian	return (sc->ifpport[phy]);
260249651Sadrian}
261249651Sadrian
262249651Sadrianstatic inline struct mii_data *
263249651Sadrianukswitch_miiforport(struct ukswitch_softc *sc, int port)
264249651Sadrian{
265249651Sadrian
266249651Sadrian	if (port < 0 || port > sc->numports)
267249651Sadrian		return (NULL);
268249651Sadrian	return (device_get_softc(*sc->miibus[port]));
269249651Sadrian}
270249651Sadrian
271249651Sadrianstatic inline struct ifnet *
272249651Sadrianukswitch_ifpforport(struct ukswitch_softc *sc, int port)
273249651Sadrian{
274249651Sadrian
275249651Sadrian	if (port < 0 || port > sc->numports)
276249651Sadrian		return (NULL);
277249651Sadrian	return (sc->ifp[port]);
278249651Sadrian}
279249651Sadrian
280249651Sadrian/*
281249651Sadrian * Poll the status for all PHYs.
282249651Sadrian */
283249651Sadrianstatic void
284249651Sadrianukswitch_miipollstat(struct ukswitch_softc *sc)
285249651Sadrian{
286249651Sadrian	int i, port;
287249651Sadrian	struct mii_data *mii;
288249651Sadrian	struct mii_softc *miisc;
289249651Sadrian
290249651Sadrian	UKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
291249651Sadrian
292249651Sadrian	for (i = 0; i < MII_NPHY; i++) {
293249651Sadrian		if (((1 << i) & sc->phymask) == 0)
294249651Sadrian			continue;
295249651Sadrian		port = ukswitch_portforphy(sc, i);
296249651Sadrian		if ((*sc->miibus[port]) == NULL)
297249651Sadrian			continue;
298249651Sadrian		mii = device_get_softc(*sc->miibus[port]);
299249651Sadrian		LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
300249651Sadrian			if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
301249651Sadrian			    miisc->mii_inst)
302249651Sadrian				continue;
303249651Sadrian			ukphy_status(miisc);
304249651Sadrian			mii_phy_update(miisc, MII_POLLSTAT);
305249651Sadrian		}
306249651Sadrian	}
307249651Sadrian}
308249651Sadrian
309249651Sadrianstatic void
310249651Sadrianukswitch_tick(void *arg)
311249651Sadrian{
312249651Sadrian	struct ukswitch_softc *sc = arg;
313249651Sadrian
314249651Sadrian	ukswitch_miipollstat(sc);
315249651Sadrian	callout_reset(&sc->callout_tick, hz, ukswitch_tick, sc);
316249651Sadrian}
317249651Sadrian
318249651Sadrianstatic void
319249651Sadrianukswitch_lock(device_t dev)
320249651Sadrian{
321249651Sadrian	struct ukswitch_softc *sc = device_get_softc(dev);
322249651Sadrian
323249651Sadrian	UKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
324249651Sadrian	UKSWITCH_LOCK(sc);
325249651Sadrian}
326249651Sadrian
327249651Sadrianstatic void
328249651Sadrianukswitch_unlock(device_t dev)
329249651Sadrian{
330249651Sadrian	struct ukswitch_softc *sc = device_get_softc(dev);
331249651Sadrian
332249651Sadrian	UKSWITCH_LOCK_ASSERT(sc, MA_OWNED);
333249651Sadrian	UKSWITCH_UNLOCK(sc);
334249651Sadrian}
335249651Sadrian
336249651Sadrianstatic etherswitch_info_t *
337249651Sadrianukswitch_getinfo(device_t dev)
338249651Sadrian{
339249651Sadrian	struct ukswitch_softc *sc = device_get_softc(dev);
340249651Sadrian
341249651Sadrian	return (&sc->info);
342249651Sadrian}
343249651Sadrian
344249651Sadrianstatic int
345249651Sadrianukswitch_getport(device_t dev, etherswitch_port_t *p)
346249651Sadrian{
347249651Sadrian	struct ukswitch_softc *sc = device_get_softc(dev);
348249651Sadrian	struct mii_data *mii;
349249651Sadrian	struct ifmediareq *ifmr = &p->es_ifmr;
350249651Sadrian	int err;
351249651Sadrian
352249651Sadrian	if (p->es_port < 0 || p->es_port >= sc->numports)
353249651Sadrian		return (ENXIO);
354249651Sadrian	p->es_vlangroup = 0;
355249651Sadrian
356249651Sadrian	mii = ukswitch_miiforport(sc, p->es_port);
357249651Sadrian	if (sc->portphy[p->es_port] == sc->cpuport) {
358249651Sadrian		/* fill in fixed values for CPU port */
359249651Sadrian		ifmr->ifm_count = 0;
360249651Sadrian		if (sc->media == 100)
361249651Sadrian			ifmr->ifm_current = ifmr->ifm_active =
362249651Sadrian			    IFM_ETHER | IFM_100_TX | IFM_FDX;
363249651Sadrian		else
364249651Sadrian			ifmr->ifm_current = ifmr->ifm_active =
365249651Sadrian			    IFM_ETHER | IFM_1000_T | IFM_FDX;
366249651Sadrian		ifmr->ifm_mask = 0;
367249651Sadrian		ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
368249651Sadrian	} else if (mii != NULL) {
369249651Sadrian		err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
370249651Sadrian		    &mii->mii_media, SIOCGIFMEDIA);
371249651Sadrian		if (err)
372249651Sadrian			return (err);
373249651Sadrian	} else {
374249651Sadrian		return (ENXIO);
375249651Sadrian	}
376249651Sadrian	return (0);
377249651Sadrian}
378249651Sadrian
379249651Sadrianstatic int
380249651Sadrianukswitch_setport(device_t dev, etherswitch_port_t *p)
381249651Sadrian{
382249651Sadrian	struct ukswitch_softc *sc = device_get_softc(dev);
383249651Sadrian	struct ifmedia *ifm;
384249651Sadrian	struct mii_data *mii;
385249651Sadrian	struct ifnet *ifp;
386249651Sadrian	int err;
387249651Sadrian
388249651Sadrian	if (p->es_port < 0 || p->es_port >= sc->numports)
389249651Sadrian		return (ENXIO);
390249651Sadrian
391249651Sadrian	if (sc->portphy[p->es_port] == sc->cpuport)
392249651Sadrian		return (ENXIO);
393249651Sadrian
394249651Sadrian	mii = ukswitch_miiforport(sc, p->es_port);
395249651Sadrian	if (mii == NULL)
396249651Sadrian		return (ENXIO);
397249651Sadrian
398249651Sadrian	ifp = ukswitch_ifpforport(sc, p->es_port);
399249651Sadrian
400249651Sadrian	ifm = &mii->mii_media;
401249651Sadrian	err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA);
402249651Sadrian	return (err);
403249651Sadrian}
404249651Sadrian
405249651Sadrianstatic int
406249651Sadrianukswitch_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
407249651Sadrian{
408249651Sadrian
409249651Sadrian	/* Not supported. */
410249651Sadrian	vg->es_vid = 0;
411249651Sadrian	vg->es_member_ports = 0;
412249651Sadrian	vg->es_untagged_ports = 0;
413249651Sadrian	vg->es_fid = 0;
414249651Sadrian	return (0);
415249651Sadrian}
416249651Sadrian
417249651Sadrianstatic int
418249651Sadrianukswitch_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
419249651Sadrian{
420249651Sadrian
421249651Sadrian	/* Not supported. */
422249651Sadrian	return (0);
423249651Sadrian}
424249651Sadrian
425249651Sadrianstatic void
426249651Sadrianukswitch_statchg(device_t dev)
427249651Sadrian{
428249651Sadrian
429249651Sadrian	DPRINTF(dev, "%s\n", __func__);
430249651Sadrian}
431249651Sadrian
432249651Sadrianstatic int
433249651Sadrianukswitch_ifmedia_upd(struct ifnet *ifp)
434249651Sadrian{
435249651Sadrian	struct ukswitch_softc *sc = ifp->if_softc;
436249651Sadrian	struct mii_data *mii = ukswitch_miiforport(sc, ifp->if_dunit);
437249651Sadrian
438249651Sadrian	DPRINTF(sc->sc_dev, "%s\n", __func__);
439249651Sadrian	if (mii == NULL)
440249651Sadrian		return (ENXIO);
441249651Sadrian	mii_mediachg(mii);
442249651Sadrian	return (0);
443249651Sadrian}
444249651Sadrian
445249651Sadrianstatic void
446249651Sadrianukswitch_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
447249651Sadrian{
448249651Sadrian	struct ukswitch_softc *sc = ifp->if_softc;
449249651Sadrian	struct mii_data *mii = ukswitch_miiforport(sc, ifp->if_dunit);
450249651Sadrian
451249651Sadrian	DPRINTF(sc->sc_dev, "%s\n", __func__);
452249651Sadrian
453249651Sadrian	if (mii == NULL)
454249651Sadrian		return;
455249651Sadrian	mii_pollstat(mii);
456249651Sadrian	ifmr->ifm_active = mii->mii_media_active;
457249651Sadrian	ifmr->ifm_status = mii->mii_media_status;
458249651Sadrian}
459249651Sadrian
460249651Sadrianstatic int
461249651Sadrianukswitch_readphy(device_t dev, int phy, int reg)
462249651Sadrian{
463249651Sadrian	struct ukswitch_softc *sc;
464249651Sadrian	int data;
465249651Sadrian
466249651Sadrian	sc = device_get_softc(dev);
467249651Sadrian	UKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
468249651Sadrian
469249651Sadrian	if (phy < 0 || phy >= 32)
470249651Sadrian		return (ENXIO);
471249651Sadrian	if (reg < 0 || reg >= 32)
472249651Sadrian		return (ENXIO);
473249651Sadrian
474249651Sadrian	UKSWITCH_LOCK(sc);
475249651Sadrian	data = MDIO_READREG(device_get_parent(dev), phy, reg);
476249651Sadrian	UKSWITCH_UNLOCK(sc);
477249651Sadrian
478249651Sadrian	return (data);
479249651Sadrian}
480249651Sadrian
481249651Sadrianstatic int
482249651Sadrianukswitch_writephy(device_t dev, int phy, int reg, int data)
483249651Sadrian{
484249651Sadrian	struct ukswitch_softc *sc;
485249651Sadrian	int err;
486249651Sadrian
487249651Sadrian	sc = device_get_softc(dev);
488249651Sadrian	UKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
489249651Sadrian
490249651Sadrian	if (phy < 0 || phy >= 32)
491249651Sadrian		return (ENXIO);
492249651Sadrian	if (reg < 0 || reg >= 32)
493249651Sadrian		return (ENXIO);
494249651Sadrian
495249651Sadrian	UKSWITCH_LOCK(sc);
496249651Sadrian	err = MDIO_WRITEREG(device_get_parent(dev), phy, reg, data);
497249651Sadrian	UKSWITCH_UNLOCK(sc);
498249651Sadrian
499249651Sadrian	return (err);
500249651Sadrian}
501249651Sadrian
502249651Sadrianstatic int
503249651Sadrianukswitch_readreg(device_t dev, int addr)
504249651Sadrian{
505249651Sadrian	struct ukswitch_softc *sc;
506249651Sadrian
507249651Sadrian	sc = device_get_softc(dev);
508249651Sadrian	UKSWITCH_LOCK_ASSERT(sc, MA_OWNED);
509249651Sadrian
510249651Sadrian	/* Not supported. */
511249651Sadrian	return (0);
512249651Sadrian}
513249651Sadrian
514249651Sadrianstatic int
515249651Sadrianukswitch_writereg(device_t dev, int addr, int value)
516249651Sadrian{
517249651Sadrian	struct ukswitch_softc *sc;
518249651Sadrian
519249651Sadrian	sc = device_get_softc(dev);
520249651Sadrian	UKSWITCH_LOCK_ASSERT(sc, MA_OWNED);
521249651Sadrian
522249651Sadrian	/* Not supported. */
523249651Sadrian	return (0);
524249651Sadrian}
525249651Sadrian
526249651Sadrianstatic device_method_t ukswitch_methods[] = {
527249651Sadrian	/* Device interface */
528249651Sadrian	DEVMETHOD(device_probe,		ukswitch_probe),
529249651Sadrian	DEVMETHOD(device_attach,	ukswitch_attach),
530249651Sadrian	DEVMETHOD(device_detach,	ukswitch_detach),
531249651Sadrian
532249651Sadrian	/* bus interface */
533249651Sadrian	DEVMETHOD(bus_add_child,	device_add_child_ordered),
534249651Sadrian
535249651Sadrian	/* MII interface */
536249651Sadrian	DEVMETHOD(miibus_readreg,	ukswitch_readphy),
537249651Sadrian	DEVMETHOD(miibus_writereg,	ukswitch_writephy),
538249651Sadrian	DEVMETHOD(miibus_statchg,	ukswitch_statchg),
539249651Sadrian
540249651Sadrian	/* MDIO interface */
541249651Sadrian	DEVMETHOD(mdio_readreg,		ukswitch_readphy),
542249651Sadrian	DEVMETHOD(mdio_writereg,	ukswitch_writephy),
543249651Sadrian
544249651Sadrian	/* etherswitch interface */
545249651Sadrian	DEVMETHOD(etherswitch_lock,	ukswitch_lock),
546249651Sadrian	DEVMETHOD(etherswitch_unlock,	ukswitch_unlock),
547249651Sadrian	DEVMETHOD(etherswitch_getinfo,	ukswitch_getinfo),
548249651Sadrian	DEVMETHOD(etherswitch_readreg,	ukswitch_readreg),
549249651Sadrian	DEVMETHOD(etherswitch_writereg,	ukswitch_writereg),
550249651Sadrian	DEVMETHOD(etherswitch_readphyreg,	ukswitch_readphy),
551249651Sadrian	DEVMETHOD(etherswitch_writephyreg,	ukswitch_writephy),
552249651Sadrian	DEVMETHOD(etherswitch_getport,	ukswitch_getport),
553249651Sadrian	DEVMETHOD(etherswitch_setport,	ukswitch_setport),
554249651Sadrian	DEVMETHOD(etherswitch_getvgroup,	ukswitch_getvgroup),
555249651Sadrian	DEVMETHOD(etherswitch_setvgroup,	ukswitch_setvgroup),
556249651Sadrian
557249651Sadrian	DEVMETHOD_END
558249651Sadrian};
559249651Sadrian
560249651SadrianDEFINE_CLASS_0(ukswitch, ukswitch_driver, ukswitch_methods,
561249651Sadrian    sizeof(struct ukswitch_softc));
562249651Sadrianstatic devclass_t ukswitch_devclass;
563249651Sadrian
564249651SadrianDRIVER_MODULE(ukswitch, mdio, ukswitch_driver, ukswitch_devclass, 0, 0);
565249651SadrianDRIVER_MODULE(miibus, ukswitch, miibus_driver, miibus_devclass, 0, 0);
566249651SadrianDRIVER_MODULE(mdio, ukswitch, mdio_driver, mdio_devclass, 0, 0);
567249651SadrianDRIVER_MODULE(etherswitch, ukswitch, etherswitch_driver, etherswitch_devclass, 0, 0);
568249651SadrianMODULE_VERSION(ukswitch, 1);
569249651SadrianMODULE_DEPEND(ukswitch, miibus, 1, 1, 1); /* XXX which versions? */
570249651SadrianMODULE_DEPEND(ukswitch, etherswitch, 1, 1, 1); /* XXX which versions? */
571