Deleted Added
full compact
mii.c (213364) mii.c (213878)
1/* $NetBSD: mii.c,v 1.12 1999/08/03 19:41:49 drochner Exp $ */
2
3/*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,

--- 17 unchanged lines hidden (view full) ---

26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
1/* $NetBSD: mii.c,v 1.12 1999/08/03 19:41:49 drochner Exp $ */
2
3/*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,

--- 17 unchanged lines hidden (view full) ---

26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/sys/dev/mii/mii.c 213364 2010-10-02 18:53:12Z marius $");
34__FBSDID("$FreeBSD: head/sys/dev/mii/mii.c 213878 2010-10-14 22:01:40Z marius $");
35
36/*
37 * MII bus layer, glues MII-capable network interface drivers to sharable
38 * PHY drivers. This exports an interface compatible with BSD/OS 3.0's,
39 * plus some NetBSD extensions.
40 */
41
42#include <sys/param.h>

--- 10 unchanged lines hidden (view full) ---

53#include <dev/mii/mii.h>
54#include <dev/mii/miivar.h>
55
56MODULE_VERSION(miibus, 1);
57
58#include "miibus_if.h"
59
60static int miibus_print_child(device_t dev, device_t child);
35
36/*
37 * MII bus layer, glues MII-capable network interface drivers to sharable
38 * PHY drivers. This exports an interface compatible with BSD/OS 3.0's,
39 * plus some NetBSD extensions.
40 */
41
42#include <sys/param.h>

--- 10 unchanged lines hidden (view full) ---

53#include <dev/mii/mii.h>
54#include <dev/mii/miivar.h>
55
56MODULE_VERSION(miibus, 1);
57
58#include "miibus_if.h"
59
60static int miibus_print_child(device_t dev, device_t child);
61static int miibus_read_ivar(device_t dev, device_t child, int which,
62 uintptr_t *result);
61static int miibus_child_location_str(device_t bus, device_t child, char *buf,
62 size_t buflen);
63static int miibus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
64 size_t buflen);
65static int miibus_readreg(device_t, int, int);
66static int miibus_writereg(device_t, int, int, int);
67static void miibus_statchg(device_t);
68static void miibus_linkchg(device_t);
69static void miibus_mediainit(device_t);
70
71static device_method_t miibus_methods[] = {
72 /* device interface */
73 DEVMETHOD(device_probe, miibus_probe),
74 DEVMETHOD(device_attach, miibus_attach),
75 DEVMETHOD(device_detach, miibus_detach),
76 DEVMETHOD(device_shutdown, bus_generic_shutdown),
77
78 /* bus interface */
79 DEVMETHOD(bus_print_child, miibus_print_child),
63static int miibus_child_location_str(device_t bus, device_t child, char *buf,
64 size_t buflen);
65static int miibus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
66 size_t buflen);
67static int miibus_readreg(device_t, int, int);
68static int miibus_writereg(device_t, int, int, int);
69static void miibus_statchg(device_t);
70static void miibus_linkchg(device_t);
71static void miibus_mediainit(device_t);
72
73static device_method_t miibus_methods[] = {
74 /* device interface */
75 DEVMETHOD(device_probe, miibus_probe),
76 DEVMETHOD(device_attach, miibus_attach),
77 DEVMETHOD(device_detach, miibus_detach),
78 DEVMETHOD(device_shutdown, bus_generic_shutdown),
79
80 /* bus interface */
81 DEVMETHOD(bus_print_child, miibus_print_child),
82 DEVMETHOD(bus_read_ivar, miibus_read_ivar),
80 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
81 DEVMETHOD(bus_child_pnpinfo_str, miibus_child_pnpinfo_str),
82 DEVMETHOD(bus_child_location_str, miibus_child_location_str),
83
84 /* MII interface */
85 DEVMETHOD(miibus_readreg, miibus_readreg),
86 DEVMETHOD(miibus_writereg, miibus_writereg),
87 DEVMETHOD(miibus_statchg, miibus_statchg),

--- 7 unchanged lines hidden (view full) ---

95
96driver_t miibus_driver = {
97 "miibus",
98 miibus_methods,
99 sizeof(struct mii_data)
100};
101
102struct miibus_ivars {
83 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
84 DEVMETHOD(bus_child_pnpinfo_str, miibus_child_pnpinfo_str),
85 DEVMETHOD(bus_child_location_str, miibus_child_location_str),
86
87 /* MII interface */
88 DEVMETHOD(miibus_readreg, miibus_readreg),
89 DEVMETHOD(miibus_writereg, miibus_writereg),
90 DEVMETHOD(miibus_statchg, miibus_statchg),

--- 7 unchanged lines hidden (view full) ---

98
99driver_t miibus_driver = {
100 "miibus",
101 miibus_methods,
102 sizeof(struct mii_data)
103};
104
105struct miibus_ivars {
106 struct ifnet *ifp;
103 ifm_change_cb_t ifmedia_upd;
104 ifm_stat_cb_t ifmedia_sts;
107 ifm_change_cb_t ifmedia_upd;
108 ifm_stat_cb_t ifmedia_sts;
109 int mii_flags;
105};
106
110};
111
107/*
108 * Helper function used by network interface drivers, attaches PHYs
109 * to the network interface driver parent.
110 */
111int
112miibus_probe(device_t dev)
113{
112int
113miibus_probe(device_t dev)
114{
114 struct mii_attach_args ma, *args;
115 struct mii_data *mii;
116 device_t child = NULL, parent;
117 int bmsr, capmask = 0xFFFFFFFF;
118
115
119 mii = device_get_softc(dev);
120 parent = device_get_parent(dev);
121 LIST_INIT(&mii->mii_phys);
122
123 for (ma.mii_phyno = 0; ma.mii_phyno < MII_NPHY; ma.mii_phyno++) {
124 /*
125 * Check to see if there is a PHY at this address. Note,
126 * many braindead PHYs report 0/0 in their ID registers,
127 * so we test for media in the BMSR.
128 */
129 bmsr = MIIBUS_READREG(parent, ma.mii_phyno, MII_BMSR);
130 if (bmsr == 0 || bmsr == 0xffff ||
131 (bmsr & (BMSR_EXTSTAT | BMSR_MEDIAMASK)) == 0) {
132 /* Assume no PHY at this address. */
133 continue;
134 }
135
136 /*
137 * Extract the IDs. Braindead PHYs will be handled by
138 * the `ukphy' driver, as we have no ID information to
139 * match on.
140 */
141 ma.mii_id1 = MIIBUS_READREG(parent, ma.mii_phyno,
142 MII_PHYIDR1);
143 ma.mii_id2 = MIIBUS_READREG(parent, ma.mii_phyno,
144 MII_PHYIDR2);
145
146 ma.mii_data = mii;
147 ma.mii_capmask = capmask;
148
149 args = malloc(sizeof(struct mii_attach_args),
150 M_DEVBUF, M_NOWAIT);
151 bcopy((char *)&ma, (char *)args, sizeof(ma));
152 child = device_add_child(dev, NULL, -1);
153 device_set_ivars(child, args);
154 }
155
156 if (child == NULL)
157 return (ENXIO);
158
159 device_set_desc(dev, "MII bus");
160
116 device_set_desc(dev, "MII bus");
117
161 return (0);
118 return (BUS_PROBE_SPECIFIC);
162}
163
164int
165miibus_attach(device_t dev)
166{
167 struct miibus_ivars *ivars;
119}
120
121int
122miibus_attach(device_t dev)
123{
124 struct miibus_ivars *ivars;
125 struct mii_attach_args *ma;
168 struct mii_data *mii;
126 struct mii_data *mii;
127 device_t *children;
128 int i, nchildren;
169
170 mii = device_get_softc(dev);
129
130 mii = device_get_softc(dev);
171 /*
172 * Note that each NIC's softc must start with an ifnet pointer.
173 * XXX: EVIL HACK!
174 */
175 mii->mii_ifp = *(struct ifnet**)device_get_softc(device_get_parent(dev));
176 mii->mii_ifp->if_capabilities |= IFCAP_LINKSTATE;
177 mii->mii_ifp->if_capenable |= IFCAP_LINKSTATE;
131 nchildren = 0;
132 if (device_get_children(dev, &children, &nchildren) == 0) {
133 for (i = 0; i < nchildren; i++) {
134 ma = device_get_ivars(children[i]);
135 ma->mii_data = mii;
136 }
137 free(children, M_TEMP);
138 }
139 if (nchildren == 0) {
140 device_printf(dev, "cannot get children");
141 return (ENXIO);
142 }
178 ivars = device_get_ivars(dev);
179 ifmedia_init(&mii->mii_media, IFM_IMASK, ivars->ifmedia_upd,
180 ivars->ifmedia_sts);
143 ivars = device_get_ivars(dev);
144 ifmedia_init(&mii->mii_media, IFM_IMASK, ivars->ifmedia_upd,
145 ivars->ifmedia_sts);
181 bus_generic_attach(dev);
146 mii->mii_ifp = ivars->ifp;
147 mii->mii_ifp->if_capabilities |= IFCAP_LINKSTATE;
148 mii->mii_ifp->if_capenable |= IFCAP_LINKSTATE;
149 LIST_INIT(&mii->mii_phys);
182
150
183 return (0);
151 return (bus_generic_attach(dev));
184}
185
186int
187miibus_detach(device_t dev)
188{
189 struct mii_data *mii;
190
191 bus_generic_detach(dev);

--- 14 unchanged lines hidden (view full) ---

206 retval = bus_print_child_header(dev, child);
207 retval += printf(" PHY %d", ma->mii_phyno);
208 retval += bus_print_child_footer(dev, child);
209
210 return (retval);
211}
212
213static int
152}
153
154int
155miibus_detach(device_t dev)
156{
157 struct mii_data *mii;
158
159 bus_generic_detach(dev);

--- 14 unchanged lines hidden (view full) ---

174 retval = bus_print_child_header(dev, child);
175 retval += printf(" PHY %d", ma->mii_phyno);
176 retval += bus_print_child_footer(dev, child);
177
178 return (retval);
179}
180
181static int
214miibus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
182miibus_read_ivar(device_t dev, device_t child __unused, int which,
183 uintptr_t *result)
184{
185 struct miibus_ivars *ivars;
186
187 /*
188 * NB: this uses the instance variables of the miibus rather than
189 * its PHY children.
190 */
191 ivars = device_get_ivars(dev);
192 switch (which) {
193 case MIIBUS_IVAR_FLAGS:
194 *result = ivars->mii_flags;
195 break;
196 default:
197 return (ENOENT);
198 }
199 return (0);
200}
201
202static int
203miibus_child_pnpinfo_str(device_t bus __unused, device_t child, char *buf,
215 size_t buflen)
216{
217 struct mii_attach_args *ma;
218
219 ma = device_get_ivars(child);
220 snprintf(buf, buflen, "oui=0x%x model=0x%x rev=0x%x",
221 MII_OUI(ma->mii_id1, ma->mii_id2),
222 MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2));
223 return (0);
224}
225
226static int
204 size_t buflen)
205{
206 struct mii_attach_args *ma;
207
208 ma = device_get_ivars(child);
209 snprintf(buf, buflen, "oui=0x%x model=0x%x rev=0x%x",
210 MII_OUI(ma->mii_id1, ma->mii_id2),
211 MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2));
212 return (0);
213}
214
215static int
227miibus_child_location_str(device_t bus, device_t child, char *buf,
216miibus_child_location_str(device_t bus __unused, device_t child, char *buf,
228 size_t buflen)
229{
230 struct mii_attach_args *ma;
231
232 ma = device_get_ivars(child);
233 snprintf(buf, buflen, "phyno=%d", ma->mii_phyno);
234 return (0);
235}

--- 66 unchanged lines hidden (view full) ---

302 media = m->ifm_media;
303 if (media == (IFM_ETHER | IFM_AUTO))
304 break;
305 }
306
307 ifmedia_set(&mii->mii_media, media);
308}
309
217 size_t buflen)
218{
219 struct mii_attach_args *ma;
220
221 ma = device_get_ivars(child);
222 snprintf(buf, buflen, "phyno=%d", ma->mii_phyno);
223 return (0);
224}

--- 66 unchanged lines hidden (view full) ---

291 media = m->ifm_media;
292 if (media == (IFM_ETHER | IFM_AUTO))
293 break;
294 }
295
296 ifmedia_set(&mii->mii_media, media);
297}
298
299/*
300 * Helper function used by network interface drivers, attaches the miibus and
301 * the PHYs to the network interface driver parent.
302 */
310int
303int
311mii_phy_probe(device_t dev, device_t *child, ifm_change_cb_t ifmedia_upd,
312 ifm_stat_cb_t ifmedia_sts)
304mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp,
305 ifm_change_cb_t ifmedia_upd, ifm_stat_cb_t ifmedia_sts, int capmask,
306 int phyloc, int offloc, int flags)
313{
307{
314 struct miibus_ivars *ivars;
315 int bmsr, i;
308 struct miibus_ivars *ivars;
309 struct mii_attach_args ma, *args;
310 device_t *children, phy;
311 int bmsr, first, i, nchildren, offset, phymax, phymin, rv;
316
312
317 ivars = malloc(sizeof(*ivars), M_DEVBUF, M_NOWAIT);
318 if (ivars == NULL)
319 return (ENOMEM);
320 ivars->ifmedia_upd = ifmedia_upd;
321 ivars->ifmedia_sts = ifmedia_sts;
322 *child = device_add_child(dev, "miibus", -1);
323 device_set_ivars(*child, ivars);
313 if (phyloc != MII_PHY_ANY && offloc != MII_OFFSET_ANY) {
314 printf("%s: phyloc and offloc specified", __func__);
315 return (EINVAL);
316 }
324
317
325 for (i = 0; i < MII_NPHY; i++) {
326 bmsr = MIIBUS_READREG(dev, i, MII_BMSR);
327 if (bmsr == 0 || bmsr == 0xffff ||
328 (bmsr & (BMSR_EXTSTAT | BMSR_MEDIAMASK)) == 0) {
329 /* Assume no PHY at this address. */
330 continue;
331 } else
332 break;
318 if (offloc != MII_OFFSET_ANY && (offloc < 0 || offloc >= MII_NPHY)) {
319 printf("%s: ivalid offloc %d", __func__, offloc);
320 return (EINVAL);
333 }
334
321 }
322
335 if (i == MII_NPHY) {
336 device_delete_child(dev, *child);
337 *child = NULL;
338 return (ENXIO);
323 if (phyloc == MII_PHY_ANY) {
324 phymin = 0;
325 phymax = MII_NPHY - 1;
326 } else {
327 if (phyloc < 0 || phyloc >= MII_NPHY) {
328 printf("%s: ivalid phyloc %d", __func__, phyloc);
329 return (EINVAL);
330 }
331 phymin = phymax = phyloc;
339 }
340
332 }
333
341 bus_generic_attach(dev);
334 first = 0;
335 if (*miibus == NULL) {
336 first = 1;
337 ivars = malloc(sizeof(*ivars), M_DEVBUF, M_NOWAIT);
338 if (ivars == NULL)
339 return (ENOMEM);
340 ivars->ifp = ifp;
341 ivars->ifmedia_upd = ifmedia_upd;
342 ivars->ifmedia_sts = ifmedia_sts;
343 ivars->mii_flags = flags;
344 *miibus = device_add_child(dev, "miibus", -1);
345 if (*miibus == NULL) {
346 rv = ENXIO;
347 goto fail;
348 }
349 device_set_ivars(*miibus, ivars);
350 } else {
351 ivars = device_get_ivars(*miibus);
352 if (ivars->ifp != ifp || ivars->ifmedia_upd != ifmedia_upd ||
353 ivars->ifmedia_sts != ifmedia_sts ||
354 ivars->mii_flags != flags) {
355 printf("%s: non-matching invariant", __func__);
356 return (EINVAL);
357 }
358 /*
359 * Assignment of the attach arguments mii_data for the first
360 * pass is done in miibus_attach(), i.e. once the miibus softc
361 * has been allocated.
362 */
363 ma.mii_data = device_get_softc(*miibus);
364 }
342
365
366 ma.mii_capmask = capmask;
367
368 phy = NULL;
369 offset = 0;
370 for (ma.mii_phyno = phymin; ma.mii_phyno <= phymax; ma.mii_phyno++) {
371 /*
372 * Make sure we haven't already configured a PHY at this
373 * address. This allows mii_attach() to be called
374 * multiple times.
375 */
376 if (device_get_children(*miibus, &children, &nchildren) == 0) {
377 for (i = 0; i < nchildren; i++) {
378 args = device_get_ivars(children[i]);
379 if (args->mii_phyno == ma.mii_phyno) {
380 /*
381 * Yes, there is already something
382 * configured at this address.
383 */
384 free(children, M_TEMP);
385 goto skip;
386 }
387 }
388 free(children, M_TEMP);
389 }
390
391 /*
392 * Check to see if there is a PHY at this address. Note,
393 * many braindead PHYs report 0/0 in their ID registers,
394 * so we test for media in the BMSR.
395 */
396 bmsr = MIIBUS_READREG(dev, ma.mii_phyno, MII_BMSR);
397 if (bmsr == 0 || bmsr == 0xffff ||
398 (bmsr & (BMSR_EXTSTAT | BMSR_MEDIAMASK)) == 0) {
399 /* Assume no PHY at this address. */
400 continue;
401 }
402
403 /*
404 * There is a PHY at this address. If we were given an
405 * `offset' locator, skip this PHY if it doesn't match.
406 */
407 if (offloc != MII_OFFSET_ANY && offloc != offset)
408 goto skip;
409
410 /*
411 * Extract the IDs. Braindead PHYs will be handled by
412 * the `ukphy' driver, as we have no ID information to
413 * match on.
414 */
415 ma.mii_id1 = MIIBUS_READREG(dev, ma.mii_phyno, MII_PHYIDR1);
416 ma.mii_id2 = MIIBUS_READREG(dev, ma.mii_phyno, MII_PHYIDR2);
417
418 args = malloc(sizeof(struct mii_attach_args), M_DEVBUF,
419 M_NOWAIT);
420 if (args == NULL)
421 goto skip;
422 bcopy((char *)&ma, (char *)args, sizeof(ma));
423 phy = device_add_child(*miibus, NULL, -1);
424 if (phy == NULL) {
425 free(args, M_DEVBUF);
426 goto skip;
427 }
428 device_set_ivars(phy, args);
429 skip:
430 offset++;
431 }
432
433 if (first != 0) {
434 if (phy == NULL) {
435 rv = ENXIO;
436 goto fail;
437 }
438 rv = bus_generic_attach(dev);
439 if (rv != 0)
440 goto fail;
441 }
442 rv = bus_generic_attach(*miibus);
443 if (rv != 0)
444 goto fail;
445
343 return (0);
446 return (0);
447
448 fail:
449 if (*miibus != NULL)
450 device_delete_child(dev, *miibus);
451 free(ivars, M_DEVBUF);
452 if (first != 0)
453 *miibus = NULL;
454 return (rv);
344}
345
455}
456
457int
458mii_phy_probe(device_t dev, device_t *child, ifm_change_cb_t ifmedia_upd,
459 ifm_stat_cb_t ifmedia_sts)
460{
461 struct ifnet *ifp;
462
463 /*
464 * Note that each NIC's softc must start with an ifnet pointer.
465 * XXX: EVIL HACK!
466 */
467 ifp = *(struct ifnet **)device_get_softc(dev);
468 return (mii_attach(dev, child, ifp, ifmedia_upd, ifmedia_sts,
469 BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0));
470}
471
346/*
347 * Media changed; notify all PHYs.
348 */
349int
350mii_mediachg(struct mii_data *mii)
351{
352 struct mii_softc *child;
353 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;

--- 81 unchanged lines hidden ---
472/*
473 * Media changed; notify all PHYs.
474 */
475int
476mii_mediachg(struct mii_data *mii)
477{
478 struct mii_softc *child;
479 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;

--- 81 unchanged lines hidden ---