kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / dev / netif / mii_layer / dcphy.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: src/sys/dev/mii/dcphy.c,v 1.2.2.2 2000/10/14 00:44:40 wpaul Exp $
33  * $DragonFly: src/sys/dev/netif/mii_layer/dcphy.c,v 1.3 2003/08/07 21:17:03 dillon Exp $
34  *
35  * $FreeBSD: src/sys/dev/mii/dcphy.c,v 1.2.2.2 2000/10/14 00:44:40 wpaul Exp $
36  */
37
38 /*
39  * Pseudo-driver for internal NWAY support on DEC 21143 and workalike
40  * controllers. Technically we're abusing the miibus code to handle
41  * media selection and NWAY support here since there is no MII
42  * interface. However the logical operations are roughly the same,
43  * and the alternative is to create a fake MII interface in the driver,
44  * which is harder to do.
45  */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/socket.h>
51 #include <sys/errno.h>
52 #include <sys/module.h>
53 #include <sys/bus.h>
54
55 #include <net/if.h>
56 #include <net/if_arp.h>
57 #include <net/if_media.h>
58
59 #include "mii.h"
60 #include "miivar.h"
61 #include "miidevs.h"
62
63 #include <machine/clock.h>
64 #include <machine/bus_pio.h>
65 #include <machine/bus_memio.h>
66 #include <machine/bus.h>
67 #include <machine/resource.h>
68 #include <sys/bus.h>
69
70 #include <bus/pci/pcivar.h>
71 #include "../dc/if_dcreg.h"
72
73 #include "miibus_if.h"
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 #define MIIF_AUTOTIMEOUT        0x0004
84
85 /*
86  * This is the subsystem ID for the built-in 21143 ethernet
87  * in several Compaq Presario systems. Apparently these are
88  * 10Mbps only, so we need to treat them specially.
89  */
90 #define COMPAQ_PRESARIO_ID      0xb0bb0e11
91
92 static int dcphy_probe          __P((device_t));
93 static int dcphy_attach         __P((device_t));
94 static int dcphy_detach         __P((device_t));
95
96 static device_method_t dcphy_methods[] = {
97         /* device interface */
98         DEVMETHOD(device_probe,         dcphy_probe),
99         DEVMETHOD(device_attach,        dcphy_attach),
100         DEVMETHOD(device_detach,        dcphy_detach),
101         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
102         { 0, 0 }
103 };
104
105 static devclass_t dcphy_devclass;
106
107 static driver_t dcphy_driver = {
108         "dcphy",
109         dcphy_methods,
110         sizeof(struct mii_softc)
111 };
112
113 DRIVER_MODULE(dcphy, miibus, dcphy_driver, dcphy_devclass, 0, 0);
114
115 int     dcphy_service __P((struct mii_softc *, struct mii_data *, int));
116 void    dcphy_status __P((struct mii_softc *));
117 static int dcphy_auto           __P((struct mii_softc *, int));
118 static void dcphy_reset         __P((struct mii_softc *));
119
120 static int dcphy_probe(dev)
121         device_t                dev;
122 {
123         struct mii_attach_args *ma;
124
125         ma = device_get_ivars(dev);
126
127         /*
128          * The dc driver will report the 21143 vendor and device
129          * ID to let us know that it wants us to attach.
130          */
131         if (ma->mii_id1 != DC_VENDORID_DEC ||
132             ma->mii_id2 != DC_DEVICEID_21143)
133                 return(ENXIO);
134
135         device_set_desc(dev, "Intel 21143 NWAY media interface");
136
137         return (0);
138 }
139
140 static int dcphy_attach(dev)
141         device_t                dev;
142 {
143         struct mii_softc *sc;
144         struct mii_attach_args *ma;
145         struct mii_data *mii;
146         struct dc_softc         *dc_sc;
147
148         sc = device_get_softc(dev);
149         ma = device_get_ivars(dev);
150         sc->mii_dev = device_get_parent(dev);
151         mii = device_get_softc(sc->mii_dev);
152         LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
153
154         sc->mii_inst = mii->mii_instance;
155         sc->mii_phy = ma->mii_phyno;
156         sc->mii_service = dcphy_service;
157         sc->mii_pdata = mii;
158
159         sc->mii_flags |= MIIF_NOISOLATE;
160         mii->mii_instance++;
161
162 #define ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
163
164         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
165             BMCR_ISO);
166
167         /*dcphy_reset(sc);*/
168         dc_sc = mii->mii_ifp->if_softc;
169         CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0);
170         CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0);
171
172         switch(pci_read_config(device_get_parent(sc->mii_dev),
173             DC_PCI_CSID, 4)) {
174         case COMPAQ_PRESARIO_ID:
175                 /* Example of how to only allow 10Mbps modes. */
176                 sc->mii_capabilities = BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX;
177                 break;
178         default:
179                 if (dc_sc->dc_pmode == DC_PMODE_SIA) {
180                         sc->mii_capabilities =
181                             BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX;
182                 } else {
183                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP,
184                             sc->mii_inst), BMCR_LOOP|BMCR_S100);
185
186                         sc->mii_capabilities =
187                             BMSR_ANEG|BMSR_100TXFDX|BMSR_100TXHDX|
188                             BMSR_10TFDX|BMSR_10THDX;
189                 }
190                 break;
191         }
192
193         sc->mii_capabilities &= ma->mii_capmask;
194         device_printf(dev, " ");
195         if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
196                 printf("no media present");
197         else
198                 mii_add_media(mii, sc->mii_capabilities, sc->mii_inst);
199         printf("\n");
200 #undef ADD
201
202         MIIBUS_MEDIAINIT(sc->mii_dev);
203         return(0);
204 }
205
206 static int dcphy_detach(dev)
207         device_t                dev;
208 {
209         struct mii_softc *sc;
210         struct mii_data *mii;
211
212         sc = device_get_softc(dev);
213         mii = device_get_softc(device_get_parent(dev));
214         sc->mii_dev = NULL;
215         LIST_REMOVE(sc, mii_list);
216
217         return(0);
218 }
219
220 int
221 dcphy_service(sc, mii, cmd)
222         struct mii_softc *sc;
223         struct mii_data *mii;
224         int cmd;
225 {
226         struct dc_softc         *dc_sc;
227         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
228         int reg;
229         u_int32_t               mode;
230
231         dc_sc = mii->mii_ifp->if_softc;
232
233         switch (cmd) {
234         case MII_POLLSTAT:
235                 /*
236                  * If we're not polling our PHY instance, just return.
237                  */
238                 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
239                         return (0);
240                 }
241                 break;
242
243         case MII_MEDIACHG:
244                 /*
245                  * If the media indicates a different PHY instance,
246                  * isolate ourselves.
247                  */
248                 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
249                         return (0);
250                 }
251
252                 /*
253                  * If the interface is not up, don't do anything.
254                  */
255                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
256                         break;
257
258                 sc->mii_flags = 0;
259                 mii->mii_media_active = IFM_NONE;
260                 mode = CSR_READ_4(dc_sc, DC_NETCFG);
261                 mode &= ~(DC_NETCFG_FULLDUPLEX|DC_NETCFG_PORTSEL|
262                     DC_NETCFG_PCS|DC_NETCFG_SCRAMBLER|DC_NETCFG_SPEEDSEL);
263
264                 switch (IFM_SUBTYPE(ife->ifm_media)) {
265                 case IFM_AUTO:
266                         /*dcphy_reset(sc);*/
267                         sc->mii_flags &= ~MIIF_DOINGAUTO;
268                         (void) dcphy_auto(sc, 0);
269                         break;
270                 case IFM_100_T4:
271                         /*
272                          * XXX Not supported as a manual setting right now.
273                          */
274                         return (EINVAL);
275                 case IFM_100_TX:
276                         dcphy_reset(sc);
277                         DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
278                         mode |= DC_NETCFG_PORTSEL|DC_NETCFG_PCS|
279                             DC_NETCFG_SCRAMBLER;
280                         if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
281                                 mode |= DC_NETCFG_FULLDUPLEX;
282                         else
283                                 mode &= ~DC_NETCFG_FULLDUPLEX;
284                         CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
285                         break;
286                 case IFM_10_T:
287                         DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
288                         DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF);
289                         if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
290                                 DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D);
291                         else
292                                 DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F);
293                         DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
294                         DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
295                         mode &= ~DC_NETCFG_PORTSEL;
296                         mode |= DC_NETCFG_SPEEDSEL;
297                         if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
298                                 mode |= DC_NETCFG_FULLDUPLEX;
299                         else
300                                 mode &= ~DC_NETCFG_FULLDUPLEX;
301                         CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
302                         break;
303                 default:
304                         return(EINVAL);
305                         break;
306                 }
307                 break;
308
309         case MII_TICK:
310                 /*
311                  * If we're not currently selected, just return.
312                  */
313                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
314                         return (0);
315
316                 /*
317                  * Only used for autonegotiation.
318                  */
319                 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
320                         return (0);
321
322                 /*
323                  * Is the interface even up?
324                  */
325                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
326                         return (0);
327
328                 reg = CSR_READ_4(dc_sc, DC_10BTSTAT) &
329                     (DC_TSTAT_LS10|DC_TSTAT_LS100);
330
331                 if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
332                         return(0);
333
334                 /*
335                  * Only retry autonegotiation every 5 seconds.
336                  */
337                 if (++sc->mii_ticks != 50)
338                         return (0);
339
340                 sc->mii_ticks = 0;
341                 /*if (DC_IS_INTEL(dc_sc))*/
342                         sc->mii_flags &= ~MIIF_DOINGAUTO;
343                 dcphy_auto(sc, 0);
344
345                 break;
346         }
347
348         /* Update the media status. */
349         dcphy_status(sc);
350
351         /* Callback if something changed. */
352         if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
353                 MIIBUS_STATCHG(sc->mii_dev);
354                 sc->mii_active = mii->mii_media_active;
355         }
356         return (0);
357 }
358
359 void
360 dcphy_status(sc)
361         struct mii_softc *sc;
362 {
363         struct mii_data *mii = sc->mii_pdata;
364         int reg, anlpar, tstat = 0;
365         struct dc_softc         *dc_sc;
366
367         dc_sc = mii->mii_ifp->if_softc;
368
369         mii->mii_media_status = IFM_AVALID;
370         mii->mii_media_active = IFM_ETHER;
371
372         if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
373                 return;
374
375         reg = CSR_READ_4(dc_sc, DC_10BTSTAT) &
376             (DC_TSTAT_LS10|DC_TSTAT_LS100);
377
378         if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
379                 mii->mii_media_status |= IFM_ACTIVE;
380
381         if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL) {
382                 /* Erg, still trying, I guess... */
383                 tstat = CSR_READ_4(dc_sc, DC_10BTSTAT);
384                 if ((tstat & DC_TSTAT_ANEGSTAT) != DC_ASTAT_AUTONEGCMP) {
385                         if ((DC_IS_MACRONIX(dc_sc) || DC_IS_PNICII(dc_sc)) &&
386                             (tstat & DC_TSTAT_ANEGSTAT) == DC_ASTAT_DISABLE)
387                                 goto skip;
388                         mii->mii_media_active |= IFM_NONE;
389                         return;
390                 }
391
392                 if (tstat & DC_TSTAT_LP_CAN_NWAY) {
393                         anlpar = tstat >> 16;
394                         if (anlpar & ANLPAR_T4 &&
395                             sc->mii_capabilities & BMSR_100TXHDX)
396                                 mii->mii_media_active |= IFM_100_T4;
397                         else if (anlpar & ANLPAR_TX_FD &&
398                             sc->mii_capabilities & BMSR_100TXFDX)
399                                 mii->mii_media_active |= IFM_100_TX|IFM_FDX;
400                         else if (anlpar & ANLPAR_TX &&
401                             sc->mii_capabilities & BMSR_100TXHDX)
402                                 mii->mii_media_active |= IFM_100_TX;
403                         else if (anlpar & ANLPAR_10_FD)
404                                 mii->mii_media_active |= IFM_10_T|IFM_FDX;
405                         else if (anlpar & ANLPAR_10)
406                                 mii->mii_media_active |= IFM_10_T;
407                         else
408                                 mii->mii_media_active |= IFM_NONE;
409                         if (DC_IS_INTEL(dc_sc))
410                                 DC_CLRBIT(dc_sc, DC_10BTCTRL,
411                                     DC_TCTL_AUTONEGENBL);
412                         return;
413                 }
414                 /*
415                  * If the other side doesn't support NWAY, then the
416                  * best we can do is determine if we have a 10Mbps or
417                  * 100Mbps link. There's no way to know if the link 
418                  * is full or half duplex, so we default to half duplex
419                  * and hope that the user is clever enough to manually
420                  * change the media settings if we're wrong.
421                  */
422                 if (!(reg & DC_TSTAT_LS100))
423                         mii->mii_media_active |= IFM_100_TX;
424                 else if (!(reg & DC_TSTAT_LS10))
425                         mii->mii_media_active |= IFM_10_T;
426                 else
427                         mii->mii_media_active |= IFM_NONE;
428                 if (DC_IS_INTEL(dc_sc))
429                         DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
430                 return;
431         }
432
433 skip:
434
435         if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
436                 mii->mii_media_active |= IFM_10_T;
437         else
438                 mii->mii_media_active |= IFM_100_TX;
439         if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
440                 mii->mii_media_active |= IFM_FDX;
441
442         return;
443 }
444
445 static int
446 dcphy_auto(mii, waitfor)
447         struct mii_softc        *mii;
448         int                     waitfor;
449 {
450         int                     i;
451         struct dc_softc         *sc;
452
453         sc = mii->mii_pdata->mii_ifp->if_softc;
454
455         if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
456                 DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
457                 DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
458                 DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
459                 if (mii->mii_capabilities & BMSR_100TXHDX)
460                         CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF);
461                 else
462                         CSR_WRITE_4(sc, DC_10BTCTRL, 0xFFFF);
463                 DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
464                 DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
465                 DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE);
466         }
467
468         if (waitfor) {
469                 /* Wait 500ms for it to complete. */
470                 for (i = 0; i < 500; i++) {
471                         if ((CSR_READ_4(sc, DC_10BTSTAT) & DC_TSTAT_ANEGSTAT)
472                             == DC_ASTAT_AUTONEGCMP)
473                                 return(0);
474                         DELAY(1000);
475                 }
476                 /*
477                  * Don't need to worry about clearing MIIF_DOINGAUTO.
478                  * If that's set, a timeout is pending, and it will
479                  * clear the flag.
480                  */
481                 return(EIO);
482         }
483
484         /*
485          * Just let it finish asynchronously.  This is for the benefit of
486          * the tick handler driving autonegotiation.  Don't want 500ms
487          * delays all the time while the system is running!
488          */
489         if ((mii->mii_flags & MIIF_DOINGAUTO) == 0)
490                 mii->mii_flags |= MIIF_DOINGAUTO;
491
492         return(EJUSTRETURN);
493 }
494
495 static void
496 dcphy_reset(mii)
497         struct mii_softc        *mii;
498 {
499         struct dc_softc         *sc;
500
501         sc = mii->mii_pdata->mii_ifp->if_softc;
502
503         DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
504         DELAY(1000);
505         DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
506
507         return;
508 }
509