This source file includes following definitions.
- mii_phy_setmedia
- mii_phy_auto
- mii_phy_auto_timeout
- mii_phy_tick
- mii_phy_reset
- mii_phy_down
- mii_phy_status
- mii_phy_update
- mii_phy_statusmsg
- mii_phy_add_media
- mii_phy_delete_media
- mii_phy_activate
- mii_phy_detach
- mii_phy_match
- mii_phy_flowstatus
- mii_anar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 #include <sys/param.h>
46 #include <sys/device.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/socket.h>
50 #include <sys/errno.h>
51 #include <sys/proc.h>
52
53 #include <net/if.h>
54 #include <net/if_media.h>
55
56 #include <dev/mii/mii.h>
57 #include <dev/mii/miivar.h>
58
59
60
61
62
63 const struct mii_media mii_media_table[] = {
64
65 { BMCR_ISO, ANAR_CSMA, 0 },
66
67 { BMCR_S10, ANAR_CSMA|ANAR_10, 0 },
68
69 { BMCR_S10|BMCR_FDX, ANAR_CSMA|ANAR_10_FD, 0 },
70
71 { BMCR_S100, ANAR_CSMA|ANAR_T4, 0 },
72
73 { BMCR_S100, ANAR_CSMA|ANAR_TX, 0 },
74
75 { BMCR_S100|BMCR_FDX, ANAR_CSMA|ANAR_TX_FD, 0 },
76
77 { BMCR_S1000, ANAR_CSMA, 0 },
78
79 { BMCR_S1000|BMCR_FDX, ANAR_CSMA, 0 },
80
81 { BMCR_S1000, ANAR_CSMA, GTCR_ADV_1000THDX },
82
83 { BMCR_S1000|BMCR_FDX, ANAR_CSMA, GTCR_ADV_1000TFDX },
84 };
85
86 void
87 mii_phy_setmedia(struct mii_softc *sc)
88 {
89 struct mii_data *mii = sc->mii_pdata;
90 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
91 int bmcr, anar, gtcr;
92
93 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
94 if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0 ||
95 (sc->mii_flags & MIIF_FORCEANEG))
96 (void) mii_phy_auto(sc, 1);
97 return;
98 }
99
100
101
102
103 #ifdef DIAGNOSTIC
104 if (ife->ifm_data < 0 || ife->ifm_data >= MII_NMEDIA)
105 panic("mii_phy_setmedia");
106 #endif
107
108 anar = mii_media_table[ife->ifm_data].mm_anar;
109 bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
110 gtcr = mii_media_table[ife->ifm_data].mm_gtcr;
111
112 if (mii->mii_media.ifm_media & IFM_ETH_MASTER) {
113 switch (IFM_SUBTYPE(ife->ifm_media)) {
114 case IFM_1000_T:
115 gtcr |= GTCR_MAN_MS|GTCR_ADV_MS;
116 break;
117
118 default:
119 panic("mii_phy_setmedia: MASTER on wrong media");
120 }
121 }
122
123 if (ife->ifm_media & IFM_LOOP)
124 bmcr |= BMCR_LOOP;
125
126 PHY_WRITE(sc, MII_ANAR, anar);
127 PHY_WRITE(sc, MII_BMCR, bmcr);
128 if (sc->mii_flags & MIIF_HAVE_GTCR)
129 PHY_WRITE(sc, MII_100T2CR, gtcr);
130 }
131
132 int
133 mii_phy_auto(struct mii_softc *sc, int waitfor)
134 {
135 int bmsr, i;
136
137 if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
138
139
140
141
142 if (sc->mii_flags & MIIF_IS_1000X) {
143 uint16_t anar = 0;
144
145 if (sc->mii_extcapabilities & EXTSR_1000XFDX)
146 anar |= ANAR_X_FD;
147 if (sc->mii_extcapabilities & EXTSR_1000XHDX)
148 anar |= ANAR_X_HD;
149
150 if (sc->mii_flags & MIIF_DOPAUSE &&
151 sc->mii_extcapabilities & EXTSR_1000XFDX)
152 anar |= ANAR_X_PAUSE_TOWARDS;
153
154 PHY_WRITE(sc, MII_ANAR, anar);
155 } else {
156 uint16_t anar;
157
158 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) |
159 ANAR_CSMA;
160
161
162
163
164
165 if (sc->mii_flags & MIIF_DOPAUSE) {
166 if (sc->mii_capabilities & BMSR_100TXFDX)
167 anar |= ANAR_FC;
168 if (sc->mii_extcapabilities & EXTSR_1000TFDX)
169 anar |= ANAR_PAUSE_TOWARDS;
170 }
171 PHY_WRITE(sc, MII_ANAR, anar);
172 if (sc->mii_flags & MIIF_HAVE_GTCR) {
173 uint16_t gtcr = 0;
174
175 if (sc->mii_extcapabilities & EXTSR_1000TFDX)
176 gtcr |= GTCR_ADV_1000TFDX;
177 if (sc->mii_extcapabilities & EXTSR_1000THDX)
178 gtcr |= GTCR_ADV_1000THDX;
179
180 PHY_WRITE(sc, MII_100T2CR, gtcr);
181 }
182 }
183 PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
184 }
185
186 if (waitfor) {
187
188 for (i = 0; i < 500; i++) {
189 if ((bmsr = PHY_READ(sc, MII_BMSR)) & BMSR_ACOMP)
190 return (0);
191 delay(1000);
192 }
193
194
195
196
197
198
199 return (EIO);
200 }
201
202
203
204
205
206
207 if (sc->mii_flags & MIIF_AUTOTSLEEP) {
208 sc->mii_flags |= MIIF_DOINGAUTO;
209 tsleep(&sc->mii_flags, PZERO, "miiaut", hz >> 1);
210 mii_phy_auto_timeout(sc);
211 } else if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
212 sc->mii_flags |= MIIF_DOINGAUTO;
213 timeout_set(&sc->mii_phy_timo, mii_phy_auto_timeout, sc);
214 timeout_add(&sc->mii_phy_timo, hz / 2);
215 }
216 return (EJUSTRETURN);
217 }
218
219 void
220 mii_phy_auto_timeout(void *arg)
221 {
222 struct mii_softc *sc = arg;
223 int s, bmsr;
224
225 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
226 return;
227
228 s = splnet();
229 sc->mii_flags &= ~MIIF_DOINGAUTO;
230 bmsr = PHY_READ(sc, MII_BMSR);
231
232
233 (void) PHY_SERVICE(sc, sc->mii_pdata, MII_POLLSTAT);
234 splx(s);
235 }
236
237 int
238 mii_phy_tick(struct mii_softc *sc)
239 {
240 struct mii_data *mii = sc->mii_pdata;
241 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
242 int reg;
243
244
245 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
246 return (EJUSTRETURN);
247
248
249
250
251
252
253
254 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
255 return (0);
256
257
258 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
259 if (reg & BMSR_LINK) {
260
261
262
263 return (0);
264 }
265
266
267
268
269 if (!sc->mii_anegticks)
270 sc->mii_anegticks = MII_ANEGTICKS;
271
272 if (++sc->mii_ticks <= sc->mii_anegticks)
273 return (EJUSTRETURN);
274
275 sc->mii_ticks = 0;
276 PHY_RESET(sc);
277
278 if (mii_phy_auto(sc, 0) == EJUSTRETURN)
279 return (EJUSTRETURN);
280
281
282
283
284
285 return (0);
286 }
287
288 void
289 mii_phy_reset(struct mii_softc *sc)
290 {
291 int reg, i;
292
293 if (sc->mii_flags & MIIF_NOISOLATE)
294 reg = BMCR_RESET;
295 else
296 reg = BMCR_RESET | BMCR_ISO;
297 PHY_WRITE(sc, MII_BMCR, reg);
298
299
300
301
302
303
304
305
306
307 delay(500);
308
309
310 for (i = 0; i < 100; i++) {
311 reg = PHY_READ(sc, MII_BMCR);
312 if ((reg & BMCR_RESET) == 0)
313 break;
314 delay(1000);
315 }
316
317 if (sc->mii_inst != 0 && ((sc->mii_flags & MIIF_NOISOLATE) == 0))
318 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
319 }
320
321 void
322 mii_phy_down(struct mii_softc *sc)
323 {
324 if (sc->mii_flags & MIIF_DOINGAUTO) {
325 sc->mii_flags &= ~MIIF_DOINGAUTO;
326 timeout_del(&sc->mii_phy_timo);
327 }
328 }
329
330
331 void
332 mii_phy_status(struct mii_softc *sc)
333 {
334 PHY_STATUS(sc);
335 }
336
337 void
338 mii_phy_update(struct mii_softc *sc, int cmd)
339 {
340 struct mii_data *mii = sc->mii_pdata;
341 struct ifnet *ifp = mii->mii_ifp;
342 int announce, s;
343
344 if (sc->mii_media_active != mii->mii_media_active ||
345 sc->mii_media_status != mii->mii_media_status ||
346 cmd == MII_MEDIACHG) {
347 announce = mii_phy_statusmsg(sc);
348 (*mii->mii_statchg)(sc->mii_dev.dv_parent);
349 sc->mii_media_active = mii->mii_media_active;
350 sc->mii_media_status = mii->mii_media_status;
351
352 if (announce) {
353 s = splnet();
354 if_link_state_change(ifp);
355 splx(s);
356 }
357 }
358 }
359
360 int
361 mii_phy_statusmsg(struct mii_softc *sc)
362 {
363 struct mii_data *mii = sc->mii_pdata;
364 struct ifnet *ifp = mii->mii_ifp;
365 int baudrate, link_state, announce = 0;
366
367 if (mii->mii_media_status & IFM_AVALID) {
368 if (mii->mii_media_status & IFM_ACTIVE) {
369 if (mii->mii_media_active & IFM_FDX)
370 link_state = LINK_STATE_FULL_DUPLEX;
371 else if (mii->mii_media_active & IFM_HDX)
372 link_state = LINK_STATE_HALF_DUPLEX;
373 else
374 link_state = LINK_STATE_UP;
375 } else
376 link_state = LINK_STATE_DOWN;
377 } else
378 link_state = LINK_STATE_UNKNOWN;
379
380 baudrate = ifmedia_baudrate(mii->mii_media_active);
381
382 if (link_state != ifp->if_link_state) {
383 ifp->if_link_state = link_state;
384
385
386
387
388
389 announce = 1;
390 }
391
392 if (baudrate != ifp->if_baudrate) {
393 ifp->if_baudrate = baudrate;
394 announce = 1;
395 }
396
397 return (announce);
398 }
399
400
401
402
403
404
405 void
406 mii_phy_add_media(struct mii_softc *sc)
407 {
408 struct mii_data *mii = sc->mii_pdata;
409
410 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
411
412 if ((sc->mii_flags & MIIF_NOISOLATE) == 0)
413 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
414 MII_MEDIA_NONE);
415
416 if (sc->mii_capabilities & BMSR_10THDX) {
417 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
418 MII_MEDIA_10_T);
419 }
420 if (sc->mii_capabilities & BMSR_10TFDX) {
421 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
422 MII_MEDIA_10_T_FDX);
423 }
424 if (sc->mii_capabilities & BMSR_100TXHDX) {
425 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
426 MII_MEDIA_100_TX);
427 }
428 if (sc->mii_capabilities & BMSR_100TXFDX) {
429 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
430 MII_MEDIA_100_TX_FDX);
431 }
432 if (sc->mii_capabilities & BMSR_100T4) {
433 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
434 MII_MEDIA_100_T4);
435 }
436 if (sc->mii_extcapabilities & EXTSR_MEDIAMASK) {
437
438
439
440
441 if (sc->mii_extcapabilities & EXTSR_1000XHDX) {
442 sc->mii_anegticks = MII_ANEGTICKS_GIGE;
443 sc->mii_flags |= MIIF_IS_1000X;
444 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,
445 sc->mii_inst), MII_MEDIA_1000_X);
446 }
447 if (sc->mii_extcapabilities & EXTSR_1000XFDX) {
448 sc->mii_anegticks = MII_ANEGTICKS_GIGE;
449 sc->mii_flags |= MIIF_IS_1000X;
450 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
451 sc->mii_inst), MII_MEDIA_1000_X_FDX);
452 }
453
454
455
456
457
458
459
460
461
462 if (sc->mii_extcapabilities & EXTSR_1000THDX) {
463 sc->mii_anegticks = MII_ANEGTICKS_GIGE;
464 sc->mii_flags |= MIIF_HAVE_GTCR;
465 mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
466 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
467 sc->mii_inst), MII_MEDIA_1000_T);
468 }
469 if (sc->mii_extcapabilities & EXTSR_1000TFDX) {
470 sc->mii_anegticks = MII_ANEGTICKS_GIGE;
471 sc->mii_flags |= MIIF_HAVE_GTCR;
472 mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
473 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
474 sc->mii_inst), MII_MEDIA_1000_T_FDX);
475 }
476 }
477
478 if (sc->mii_capabilities & BMSR_ANEG) {
479 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
480 MII_NMEDIA);
481 }
482 #undef ADD
483 }
484
485 void
486 mii_phy_delete_media(struct mii_softc *sc)
487 {
488 struct mii_data *mii = sc->mii_pdata;
489
490 ifmedia_delete_instance(&mii->mii_media, sc->mii_inst);
491 }
492
493 int
494 mii_phy_activate(struct device *self, enum devact act)
495 {
496 int rv = 0;
497
498 switch (act) {
499 case DVACT_ACTIVATE:
500 rv = EOPNOTSUPP;
501 break;
502
503 case DVACT_DEACTIVATE:
504
505 break;
506 }
507
508 return (rv);
509 }
510
511 int
512 mii_phy_detach(struct device *self, int flags)
513 {
514 struct mii_softc *sc = (void *) self;
515
516 if (sc->mii_flags & MIIF_DOINGAUTO)
517 timeout_del(&sc->mii_phy_timo);
518
519 mii_phy_delete_media(sc);
520
521 return (0);
522 }
523
524 const struct mii_phydesc *
525 mii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd)
526 {
527
528 for (; mpd->mpd_name != NULL; mpd++) {
529 if (MII_OUI(ma->mii_id1, ma->mii_id2) == mpd->mpd_oui &&
530 MII_MODEL(ma->mii_id2) == mpd->mpd_model)
531 return (mpd);
532 }
533 return (NULL);
534 }
535
536
537
538
539 int
540 mii_phy_flowstatus(struct mii_softc *sc)
541 {
542 int anar, anlpar;
543
544 if ((sc->mii_flags & MIIF_DOPAUSE) == 0)
545 return (0);
546
547 anar = PHY_READ(sc, MII_ANAR);
548 anlpar = PHY_READ(sc, MII_ANLPAR);
549
550
551 if (sc->mii_flags & MIIF_IS_1000X) {
552 anar <<= 3;
553 anlpar <<= 3;
554 }
555
556 if ((anar & ANAR_PAUSE_SYM) & (anlpar & ANLPAR_PAUSE_SYM))
557 return (IFM_FLOW|IFM_ETH_TXPAUSE|IFM_ETH_RXPAUSE);
558
559 if ((anar & ANAR_PAUSE_SYM) == 0) {
560 if ((anar & ANAR_PAUSE_ASYM) &&
561 ((anlpar & ANLPAR_PAUSE_TOWARDS) == ANLPAR_PAUSE_TOWARDS))
562 return (IFM_FLOW|IFM_ETH_TXPAUSE);
563 else
564 return (0);
565 }
566
567 if ((anar & ANAR_PAUSE_ASYM) == 0) {
568 if (anlpar & ANLPAR_PAUSE_SYM)
569 return (IFM_FLOW|IFM_ETH_TXPAUSE|IFM_ETH_RXPAUSE);
570 else
571 return (0);
572 }
573
574 switch ((anlpar & ANLPAR_PAUSE_TOWARDS)) {
575 case ANLPAR_PAUSE_NONE:
576 return (0);
577
578 case ANLPAR_PAUSE_ASYM:
579 return (IFM_FLOW|IFM_ETH_RXPAUSE);
580
581 default:
582 return (IFM_FLOW|IFM_ETH_RXPAUSE|IFM_ETH_TXPAUSE);
583 }
584
585 }
586
587
588
589
590 int
591 mii_anar(int media)
592 {
593 int rv;
594
595 switch (media & (IFM_TMASK|IFM_NMASK|IFM_FDX)) {
596 case IFM_ETHER|IFM_10_T:
597 rv = ANAR_10|ANAR_CSMA;
598 break;
599 case IFM_ETHER|IFM_10_T|IFM_FDX:
600 rv = ANAR_10_FD|ANAR_CSMA;
601 break;
602 case IFM_ETHER|IFM_100_TX:
603 rv = ANAR_TX|ANAR_CSMA;
604 break;
605 case IFM_ETHER|IFM_100_TX|IFM_FDX:
606 rv = ANAR_TX_FD|ANAR_CSMA;
607 break;
608 case IFM_ETHER|IFM_100_T4:
609 rv = ANAR_T4|ANAR_CSMA;
610 break;
611 default:
612 rv = 0;
613 break;
614 }
615
616 return (rv);
617 }