Deleted Added
full compact
pnphy.c (95667) pnphy.c (95722)
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 *
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: head/sys/dev/dc/pnphy.c 95667 2002-04-28 19:25:07Z phk $
32 * $FreeBSD: head/sys/dev/dc/pnphy.c 95722 2002-04-29 13:07:38Z phk $
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)
71static const char rcsid[] =
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)
71static const char rcsid[] =
72 "$FreeBSD: head/sys/dev/dc/pnphy.c 95667 2002-04-28 19:25:07Z phk $";
72 "$FreeBSD: head/sys/dev/dc/pnphy.c 95722 2002-04-29 13:07:38Z phk $";
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
83static int pnphy_probe (device_t);
84static int pnphy_attach (device_t);
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
83static int pnphy_probe (device_t);
84static int pnphy_attach (device_t);
85static int pnphy_detach (device_t);
86
87static device_method_t pnphy_methods[] = {
88 /* device interface */
89 DEVMETHOD(device_probe, pnphy_probe),
90 DEVMETHOD(device_attach, pnphy_attach),
85
86static device_method_t pnphy_methods[] = {
87 /* device interface */
88 DEVMETHOD(device_probe, pnphy_probe),
89 DEVMETHOD(device_attach, pnphy_attach),
91 DEVMETHOD(device_detach, pnphy_detach),
90 DEVMETHOD(device_detach, mii_phy_detach),
92 DEVMETHOD(device_shutdown, bus_generic_shutdown),
93 { 0, 0 }
94};
95
96static devclass_t pnphy_devclass;
97
98static driver_t pnphy_driver = {
99 "pnphy",
100 pnphy_methods,
101 sizeof(struct mii_softc)
102};
103
104DRIVER_MODULE(pnphy, miibus, pnphy_driver, pnphy_devclass, 0, 0);
105
106static int pnphy_service(struct mii_softc *, struct mii_data *, int);
107static void pnphy_status(struct mii_softc *);
108
109static int 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
129static int pnphy_attach(dev)
130 device_t dev;
131{
132 struct mii_softc *sc;
133 struct mii_attach_args *ma;
134 struct mii_data *mii;
135
136 sc = device_get_softc(dev);
137 ma = device_get_ivars(dev);
138 sc->mii_dev = device_get_parent(dev);
139 mii = device_get_softc(sc->mii_dev);
140 LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
141
142 sc->mii_inst = mii->mii_instance;
143 sc->mii_phy = ma->mii_phyno;
144 sc->mii_service = pnphy_service;
145 sc->mii_pdata = mii;
146
147 sc->mii_flags |= MIIF_NOISOLATE;
148 mii->mii_instance++;
149
150#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
151
152 sc->mii_capabilities =
153 BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX|BMSR_10THDX;
154 sc->mii_capabilities &= ma->mii_capmask;
155 device_printf(dev, " ");
156 mii_add_media(sc);
157 printf("\n");
158 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
159 BMCR_ISO);
160
161 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
162 BMCR_LOOP|BMCR_S100);
163
164#undef ADD
165
166 MIIBUS_MEDIAINIT(sc->mii_dev);
167 return(0);
168}
169
91 DEVMETHOD(device_shutdown, bus_generic_shutdown),
92 { 0, 0 }
93};
94
95static devclass_t pnphy_devclass;
96
97static driver_t pnphy_driver = {
98 "pnphy",
99 pnphy_methods,
100 sizeof(struct mii_softc)
101};
102
103DRIVER_MODULE(pnphy, miibus, pnphy_driver, pnphy_devclass, 0, 0);
104
105static int pnphy_service(struct mii_softc *, struct mii_data *, int);
106static void pnphy_status(struct mii_softc *);
107
108static int pnphy_probe(dev)
109 device_t dev;
110{
111 struct mii_attach_args *ma;
112
113 ma = device_get_ivars(dev);
114
115 /*
116 * The dc driver will report the 82c168 vendor and device
117 * ID to let us know that it wants us to attach.
118 */
119 if (ma->mii_id1 != DC_VENDORID_LO ||
120 ma->mii_id2 != DC_DEVICEID_82C168)
121 return(ENXIO);
122
123 device_set_desc(dev, "PNIC 82c168 media interface");
124
125 return (0);
126}
127
128static int pnphy_attach(dev)
129 device_t dev;
130{
131 struct mii_softc *sc;
132 struct mii_attach_args *ma;
133 struct mii_data *mii;
134
135 sc = device_get_softc(dev);
136 ma = device_get_ivars(dev);
137 sc->mii_dev = device_get_parent(dev);
138 mii = device_get_softc(sc->mii_dev);
139 LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
140
141 sc->mii_inst = mii->mii_instance;
142 sc->mii_phy = ma->mii_phyno;
143 sc->mii_service = pnphy_service;
144 sc->mii_pdata = mii;
145
146 sc->mii_flags |= MIIF_NOISOLATE;
147 mii->mii_instance++;
148
149#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
150
151 sc->mii_capabilities =
152 BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX|BMSR_10THDX;
153 sc->mii_capabilities &= ma->mii_capmask;
154 device_printf(dev, " ");
155 mii_add_media(sc);
156 printf("\n");
157 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
158 BMCR_ISO);
159
160 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
161 BMCR_LOOP|BMCR_S100);
162
163#undef ADD
164
165 MIIBUS_MEDIAINIT(sc->mii_dev);
166 return(0);
167}
168
170static int pnphy_detach(dev)
171 device_t dev;
172{
173 struct mii_softc *sc;
174 struct mii_data *mii;
175
176 sc = device_get_softc(dev);
177 mii = device_get_softc(device_get_parent(dev));
178 sc->mii_dev = NULL;
179 LIST_REMOVE(sc, mii_list);
180
181 return(0);
182}
183
184static int
185pnphy_service(sc, mii, cmd)
186 struct mii_softc *sc;
187 struct mii_data *mii;
188 int cmd;
189{
190 struct dc_softc *dc_sc;
191 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
192
193 dc_sc = mii->mii_ifp->if_softc;
194
195 switch (cmd) {
196 case MII_POLLSTAT:
197 /*
198 * If we're not polling our PHY instance, just return.
199 */
200 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
201 return (0);
202 }
203 break;
204
205 case MII_MEDIACHG:
206 /*
207 * If the media indicates a different PHY instance,
208 * isolate ourselves.
209 */
210 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
211 return (0);
212
213 /*
214 * If the interface is not up, don't do anything.
215 */
216 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
217 break;
218
219 sc->mii_flags = 0;
220
221 switch (IFM_SUBTYPE(ife->ifm_media)) {
222 case IFM_AUTO:
223 /* NWAY is busted on this chip */
224 case IFM_100_T4:
225 /*
226 * XXX Not supported as a manual setting right now.
227 */
228 return (EINVAL);
229 case IFM_100_TX:
230 mii->mii_media_active = IFM_ETHER|IFM_100_TX;
231 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
232 mii->mii_media_active |= IFM_FDX;
233 MIIBUS_STATCHG(sc->mii_dev);
234 return(0);
235 break;
236 case IFM_10_T:
237 mii->mii_media_active = IFM_ETHER|IFM_10_T;
238 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
239 mii->mii_media_active |= IFM_FDX;
240 MIIBUS_STATCHG(sc->mii_dev);
241 return(0);
242 break;
243 default:
244 return(EINVAL);
245 break;
246 }
247 break;
248
249 case MII_TICK:
250 /*
251 * If we're not currently selected, just return.
252 */
253 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
254 return (0);
255
256 /*
257 * Is the interface even up?
258 */
259 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
260 return (0);
261
262 break;
263 }
264
265 /* Update the media status. */
266 pnphy_status(sc);
267
268 /* Callback if something changed. */
269 mii_phy_update(sc, cmd);
270 return (0);
271}
272
273static void
274pnphy_status(sc)
275 struct mii_softc *sc;
276{
277 struct mii_data *mii = sc->mii_pdata;
278 int reg;
279 struct dc_softc *dc_sc;
280
281 dc_sc = mii->mii_ifp->if_softc;
282
283 mii->mii_media_status = IFM_AVALID;
284 mii->mii_media_active = IFM_ETHER;
285
286 reg = CSR_READ_4(dc_sc, DC_ISR);
287
288 if (!(reg & DC_ISR_LINKFAIL))
289 mii->mii_media_status |= IFM_ACTIVE;
290
291 if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
292 mii->mii_media_active |= IFM_10_T;
293 else
294 mii->mii_media_active |= IFM_100_TX;
295 if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
296 mii->mii_media_active |= IFM_FDX;
297
298 return;
299}
169static int
170pnphy_service(sc, mii, cmd)
171 struct mii_softc *sc;
172 struct mii_data *mii;
173 int cmd;
174{
175 struct dc_softc *dc_sc;
176 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
177
178 dc_sc = mii->mii_ifp->if_softc;
179
180 switch (cmd) {
181 case MII_POLLSTAT:
182 /*
183 * If we're not polling our PHY instance, just return.
184 */
185 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
186 return (0);
187 }
188 break;
189
190 case MII_MEDIACHG:
191 /*
192 * If the media indicates a different PHY instance,
193 * isolate ourselves.
194 */
195 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
196 return (0);
197
198 /*
199 * If the interface is not up, don't do anything.
200 */
201 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
202 break;
203
204 sc->mii_flags = 0;
205
206 switch (IFM_SUBTYPE(ife->ifm_media)) {
207 case IFM_AUTO:
208 /* NWAY is busted on this chip */
209 case IFM_100_T4:
210 /*
211 * XXX Not supported as a manual setting right now.
212 */
213 return (EINVAL);
214 case IFM_100_TX:
215 mii->mii_media_active = IFM_ETHER|IFM_100_TX;
216 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
217 mii->mii_media_active |= IFM_FDX;
218 MIIBUS_STATCHG(sc->mii_dev);
219 return(0);
220 break;
221 case IFM_10_T:
222 mii->mii_media_active = IFM_ETHER|IFM_10_T;
223 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
224 mii->mii_media_active |= IFM_FDX;
225 MIIBUS_STATCHG(sc->mii_dev);
226 return(0);
227 break;
228 default:
229 return(EINVAL);
230 break;
231 }
232 break;
233
234 case MII_TICK:
235 /*
236 * If we're not currently selected, just return.
237 */
238 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
239 return (0);
240
241 /*
242 * Is the interface even up?
243 */
244 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
245 return (0);
246
247 break;
248 }
249
250 /* Update the media status. */
251 pnphy_status(sc);
252
253 /* Callback if something changed. */
254 mii_phy_update(sc, cmd);
255 return (0);
256}
257
258static void
259pnphy_status(sc)
260 struct mii_softc *sc;
261{
262 struct mii_data *mii = sc->mii_pdata;
263 int reg;
264 struct dc_softc *dc_sc;
265
266 dc_sc = mii->mii_ifp->if_softc;
267
268 mii->mii_media_status = IFM_AVALID;
269 mii->mii_media_active = IFM_ETHER;
270
271 reg = CSR_READ_4(dc_sc, DC_ISR);
272
273 if (!(reg & DC_ISR_LINKFAIL))
274 mii->mii_media_status |= IFM_ACTIVE;
275
276 if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
277 mii->mii_media_active |= IFM_10_T;
278 else
279 mii->mii_media_active |= IFM_100_TX;
280 if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
281 mii->mii_media_active |= IFM_FDX;
282
283 return;
284}