FreeBSD/Linux Kernel Cross Reference
sys/dev/mii/pnphy.c
1 /*
2 * Copyright (c) 1997, 1998, 1999
3 * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
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
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * $FreeBSD: releng/5.0/sys/dev/mii/pnphy.c 105135 2002-10-14 22:31:52Z alfred $
33 */
34
35 /*
36 * Pseudo-driver for media selection on the Lite-On PNIC 82c168
37 * chip. The NWAY support on this chip is horribly broken, so we
38 * only support manual mode selection. This is lame, but getting
39 * NWAY to work right is amazingly difficult.
40 */
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/socket.h>
46 #include <sys/errno.h>
47 #include <sys/lock.h>
48 #include <sys/module.h>
49 #include <sys/mutex.h>
50 #include <sys/bus.h>
51
52 #include <net/if.h>
53 #include <net/if_arp.h>
54 #include <net/if_media.h>
55
56 #include <dev/mii/mii.h>
57 #include <dev/mii/miivar.h>
58 #include <dev/mii/miidevs.h>
59
60 #include <machine/bus_pio.h>
61 #include <machine/bus_memio.h>
62 #include <machine/bus.h>
63 #include <machine/resource.h>
64 #include <sys/bus.h>
65
66 #include <pci/if_dcreg.h>
67
68 #include "miibus_if.h"
69
70 #if !defined(lint)
71 static const char rcsid[] =
72 "$FreeBSD: releng/5.0/sys/dev/mii/pnphy.c 105135 2002-10-14 22:31:52Z alfred $";
73 #endif
74
75 #define DC_SETBIT(sc, reg, x) \
76 CSR_WRITE_4(sc, reg, \
77 CSR_READ_4(sc, reg) | x)
78
79 #define DC_CLRBIT(sc, reg, x) \
80 CSR_WRITE_4(sc, reg, \
81 CSR_READ_4(sc, reg) & ~x)
82
83 static int pnphy_probe(device_t);
84 static int pnphy_attach(device_t);
85
86 static device_method_t pnphy_methods[] = {
87 /* device interface */
88 DEVMETHOD(device_probe, pnphy_probe),
89 DEVMETHOD(device_attach, pnphy_attach),
90 DEVMETHOD(device_detach, mii_phy_detach),
91 DEVMETHOD(device_shutdown, bus_generic_shutdown),
92 { 0, 0 }
93 };
94
95 static devclass_t pnphy_devclass;
96
97 static driver_t pnphy_driver = {
98 "pnphy",
99 pnphy_methods,
100 sizeof(struct mii_softc)
101 };
102
103 DRIVER_MODULE(pnphy, miibus, pnphy_driver, pnphy_devclass, 0, 0);
104
105 static int pnphy_service(struct mii_softc *, struct mii_data *, int);
106 static void pnphy_status(struct mii_softc *);
107
108 static int
109 pnphy_probe(dev)
110 device_t dev;
111 {
112 struct mii_attach_args *ma;
113
114 ma = device_get_ivars(dev);
115
116 /*
117 * The dc driver will report the 82c168 vendor and device
118 * ID to let us know that it wants us to attach.
119 */
120 if (ma->mii_id1 != DC_VENDORID_LO ||
121 ma->mii_id2 != DC_DEVICEID_82C168)
122 return(ENXIO);
123
124 device_set_desc(dev, "PNIC 82c168 media interface");
125
126 return (0);
127 }
128
129 static int
130 pnphy_attach(dev)
131 device_t dev;
132 {
133 struct mii_softc *sc;
134 struct mii_attach_args *ma;
135 struct mii_data *mii;
136
137 sc = device_get_softc(dev);
138 ma = device_get_ivars(dev);
139 sc->mii_dev = device_get_parent(dev);
140 mii = device_get_softc(sc->mii_dev);
141 LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
142
143 sc->mii_inst = mii->mii_instance;
144 sc->mii_phy = ma->mii_phyno;
145 sc->mii_service = pnphy_service;
146 sc->mii_pdata = mii;
147
148 sc->mii_flags |= MIIF_NOISOLATE;
149 mii->mii_instance++;
150
151 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
152
153 sc->mii_capabilities =
154 BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX|BMSR_10THDX;
155 sc->mii_capabilities &= ma->mii_capmask;
156 device_printf(dev, " ");
157 mii_add_media(sc);
158 printf("\n");
159 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
160 BMCR_ISO);
161
162 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
163 BMCR_LOOP|BMCR_S100);
164
165 #undef ADD
166
167 MIIBUS_MEDIAINIT(sc->mii_dev);
168 return(0);
169 }
170
171 static int
172 pnphy_service(sc, mii, cmd)
173 struct mii_softc *sc;
174 struct mii_data *mii;
175 int cmd;
176 {
177 struct dc_softc *dc_sc;
178 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
179
180 dc_sc = mii->mii_ifp->if_softc;
181
182 switch (cmd) {
183 case MII_POLLSTAT:
184 /*
185 * If we're not polling our PHY instance, just return.
186 */
187 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
188 return (0);
189 }
190 break;
191
192 case MII_MEDIACHG:
193 /*
194 * If the media indicates a different PHY instance,
195 * isolate ourselves.
196 */
197 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
198 return (0);
199
200 /*
201 * If the interface is not up, don't do anything.
202 */
203 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
204 break;
205
206 sc->mii_flags = 0;
207
208 switch (IFM_SUBTYPE(ife->ifm_media)) {
209 case IFM_AUTO:
210 /* NWAY is busted on this chip */
211 case IFM_100_T4:
212 /*
213 * XXX Not supported as a manual setting right now.
214 */
215 return (EINVAL);
216 case IFM_100_TX:
217 mii->mii_media_active = IFM_ETHER|IFM_100_TX;
218 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
219 mii->mii_media_active |= IFM_FDX;
220 MIIBUS_STATCHG(sc->mii_dev);
221 return(0);
222 break;
223 case IFM_10_T:
224 mii->mii_media_active = IFM_ETHER|IFM_10_T;
225 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
226 mii->mii_media_active |= IFM_FDX;
227 MIIBUS_STATCHG(sc->mii_dev);
228 return(0);
229 break;
230 default:
231 return(EINVAL);
232 break;
233 }
234 break;
235
236 case MII_TICK:
237 /*
238 * If we're not currently selected, just return.
239 */
240 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
241 return (0);
242
243 /*
244 * Is the interface even up?
245 */
246 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
247 return (0);
248
249 break;
250 }
251
252 /* Update the media status. */
253 pnphy_status(sc);
254
255 /* Callback if something changed. */
256 mii_phy_update(sc, cmd);
257 return (0);
258 }
259
260 static void
261 pnphy_status(sc)
262 struct mii_softc *sc;
263 {
264 struct mii_data *mii = sc->mii_pdata;
265 int reg;
266 struct dc_softc *dc_sc;
267
268 dc_sc = mii->mii_ifp->if_softc;
269
270 mii->mii_media_status = IFM_AVALID;
271 mii->mii_media_active = IFM_ETHER;
272
273 reg = CSR_READ_4(dc_sc, DC_ISR);
274
275 if (!(reg & DC_ISR_LINKFAIL))
276 mii->mii_media_status |= IFM_ACTIVE;
277
278 if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
279 mii->mii_media_active |= IFM_10_T;
280 else
281 mii->mii_media_active |= IFM_100_TX;
282 if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
283 mii->mii_media_active |= IFM_FDX;
284
285 return;
286 }
Cache object: 100aa8207bce237da387816c5ed14e1e
|