BNX2X: usability fixups
[akaros.git] / kern / drivers / net / mii.c
1 /*
2
3         mii.c: MII interface library
4
5         Ported to gPXE by Daniel Verkamp <daniel@drv.nu>
6         from Linux drivers/net/mii.c
7
8         Maintained by Jeff Garzik <jgarzik@pobox.com>
9         Copyright 2001,2002 Jeff Garzik
10
11         Various code came from myson803.c and other files by
12         Donald Becker.  Copyright:
13
14                 Written 1998-2002 by Donald Becker.
15
16                 This software may be used and distributed according
17                 to the terms of the GNU General Public License (GPL),
18                 incorporated herein by reference.  Drivers based on
19                 or derived from this code fall under the GPL and must
20                 retain the authorship, copyright and license notice.
21                 This file is not a complete program and may only be
22                 used when the entire operating system is licensed
23                 under the GPL.
24
25                 The author may be reached as becker@scyld.com, or C/O
26                 Scyld Computing Corporation
27                 410 Severn Ave., Suite 210
28                 Annapolis MD 21403
29
30 */
31
32 #include <vfs.h>
33 #include <kfs.h>
34 #include <slab.h>
35 #include <kmalloc.h>
36 #include <kref.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <assert.h>
40 #include <error.h>
41 #include <cpio.h>
42 #include <pmap.h>
43 #include <smp.h>
44 #include <ip.h>
45 #include <mii.h>
46
47 /**
48  * mii_link_ok - is link status up/ok
49  * @mii: the MII interface
50  *
51  * Returns 1 if the MII reports link status up/ok, 0 otherwise.
52  */
53 int mii_link_ok(struct mii_if_info *mii)
54 {
55         /* first, a dummy read, needed to latch some MII phys */
56         mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
57         if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
58                 return 1;
59         return 0;
60 }
61
62 /**
63  * mii_check_link - check MII link status
64  * @mii: MII interface
65  *
66  * If the link status changed (previous != current), call
67  * netif_carrier_on() if current link status is Up or call
68  * netif_carrier_off() if current link status is Down.
69  */
70 void mii_check_link(struct mii_if_info *mii)
71 {
72 #warning "figure out what to do about etherboot netdev; does ours work?"
73 #if 0
74         int cur_link = mii_link_ok(mii);
75         int prev_link = netdev_link_ok(mii->dev);
76
77         if (cur_link && !prev_link)
78                 netdev_link_up(mii->dev);
79         else if (prev_link && !cur_link)
80                 netdev_link_down(mii->dev);
81 #endif
82 }
83
84 /**
85  * mii_check_media - check the MII interface for a duplex change
86  * @mii: the MII interface
87  * @ok_to_print: OK to print link up/down messages
88  * @init_media: OK to save duplex mode in @mii
89  *
90  * Returns 1 if the duplex mode changed, 0 if not.
91  * If the media type is forced, always returns 0.
92  */
93 unsigned int
94 mii_check_media(struct mii_if_info *mii,
95                                 unsigned int ok_to_print, unsigned int init_media)
96 {
97         unsigned int old_carrier, new_carrier = 0;
98         int advertise, lpa, media, duplex;
99         int lpa2 = 0;
100
101         /* if forced media, go no further */
102         if (mii->force_media)
103                 return 0;       /* duplex did not change */
104
105         /* check current and old link status */
106         old_carrier = 0;        //netdev_link_ok ( mii->dev ) ? 1 : 0;
107         new_carrier = (unsigned int)mii_link_ok(mii);
108
109         /* if carrier state did not change, this is a "bounce",
110          * just exit as everything is already set correctly
111          */
112         if ((!init_media) && (old_carrier == new_carrier))
113                 return 0;       /* duplex did not change */
114
115         /* no carrier, nothing much to do */
116         if (!new_carrier) {
117                 //netdev_link_down ( mii->dev );
118                 if (ok_to_print)
119                         printd("%s: link down\n", mii->dev->name);
120                 return 0;       /* duplex did not change */
121         }
122
123         /*
124          * we have carrier, see who's on the other end
125          */
126         //netdev_link_up ( mii->dev );
127
128         /* get MII advertise and LPA values */
129         if ((!init_media) && (mii->advertising)) {
130                 advertise = mii->advertising;
131         } else {
132                 advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
133                 mii->advertising = advertise;
134         }
135         lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
136         if (mii->supports_gmii)
137                 lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
138
139         /* figure out media and duplex from advertise and LPA values */
140         media = mii_nway_result(lpa & advertise);
141         duplex = (media & ADVERTISE_FULL) ? 1 : 0;
142         if (lpa2 & LPA_1000FULL)
143                 duplex = 1;
144
145         if (ok_to_print)
146                 printd("%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n", "noname",        //mii->dev->name,
147                            lpa2 & (LPA_1000FULL | LPA_1000HALF) ? "1000" :
148                            media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? "100" : "10",
149                            duplex ? "full" : "half", lpa);
150
151         if ((init_media) || (mii->full_duplex != duplex)) {
152                 mii->full_duplex = duplex;
153                 return 1;       /* duplex changed */
154         }
155
156         return 0;       /* duplex did not change */
157 }