timeout/untimeout ==> callout_*
[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.5 2004/09/18 19:32:59 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          (device_t);
93 static int dcphy_attach         (device_t);
94 static int dcphy_detach         (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 (struct mii_softc *, struct mii_data *, int);
116 void    dcphy_status (struct mii_softc *);
117 static int dcphy_auto           (struct mii_softc *, int);
118 static void dcphy_reset         (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         mii_softc_init(sc);
151         sc->mii_dev = device_get_parent(dev);
152         mii = device_get_softc(sc->mii_dev);
153         LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
154
155         sc->mii_inst = mii->mii_instance;
156         sc->mii_phy = ma->mii_phyno;
157         sc->mii_service = dcphy_service;
158         sc->mii_pdata = mii;
159
160         sc->mii_flags |= MIIF_NOISOLATE;
161         mii->mii_instance++;
162
163 #define ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
164
165         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
166             BMCR_ISO);
167
168         /*dcphy_reset(sc);*/
169         dc_sc = mii->mii_ifp->if_softc;
170         CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0);
171         CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0);
172
173         switch(pci_read_config(device_get_parent(sc->mii_dev),
174             DC_PCI_CSID, 4)) {
175         case COMPAQ_PRESARIO_ID:
176                 /* Example of how to only allow 10Mbps modes. */
177                 sc->mii_capabilities = BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX;
178                 break;
179         default:
180                 if (dc_sc->dc_pmode == DC_PMODE_SIA) {
181                         sc->mii_capabilities =
182                             BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX;
183                 } else {
184                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP,
185                             sc->mii_inst), BMCR_LOOP|BMCR_S100);
186
187                         sc->mii_capabilities =
188                             BMSR_ANEG|BMSR_100TXFDX|BMSR_100TXHDX|
189                             BMSR_10TFDX|BMSR_10THDX;
190                 }
191                 break;
192         }
193
194         sc->mii_capabilities &= ma->mii_capmask;
195         device_printf(dev, " ");
196         if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
197                 printf("no media present");
198         else
199                 mii_add_media(mii, sc->mii_capabilities, sc->mii_inst);
200         printf("\n");
201 #undef ADD
202
203         MIIBUS_MEDIAINIT(sc->mii_dev);
204         return(0);
205 }
206
207 static int dcphy_detach(dev)
208         device_t                dev;
209 {
210         struct mii_softc *sc;
211         struct mii_data *mii;
212
213         sc = device_get_softc(dev);
214         mii = device_get_softc(device_get_parent(dev));
215         sc->mii_dev = NULL;
216         LIST_REMOVE(sc, mii_list);
217
218         return(0);
219 }
220
221 int
222 dcphy_service(sc, mii, cmd)
223         struct mii_softc *sc;
224         struct mii_data *mii;
225         int cmd;
226 {
227         struct dc_softc         *dc_sc;
228         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
229         int reg;
230         u_int32_t               mode;
231
232         dc_sc = mii->mii_ifp->if_softc;
233
234         switch (cmd) {
235         case MII_POLLSTAT:
236                 /*
237                  * If we're not polling our PHY instance, just return.
238                  */
239                 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
240                         return (0);
241                 }
242                 break;
243
244         case MII_MEDIACHG:
245                 /*
246                  * If the media indicates a different PHY instance,
247                  * isolate ourselves.
248                  */
249                 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
250                         return (0);
251                 }
252
253                 /*
254                  * If the interface is not up, don't do anything.
255                  */
256                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
257                         break;
258
259                 sc->mii_flags = 0;
260                 mii->mii_media_active = IFM_NONE;
261                 mode = CSR_READ_4(dc_sc, DC_NETCFG);
262                 mode &= ~(DC_NETCFG_FULLDUPLEX|DC_NETCFG_PORTSEL|
263                     DC_NETCFG_PCS|DC_NETCFG_SCRAMBLER|DC_NETCFG_SPEEDSEL);
264
265                 switch (IFM_SUBTYPE(ife->ifm_media)) {
266                 case IFM_AUTO:
267                         /*dcphy_reset(sc);*/
268                         sc->mii_flags &= ~MIIF_DOINGAUTO;
269                         (void) dcphy_auto(sc, 0);
270                         break;
271                 case IFM_100_T4:
272                         /*
273                          * XXX Not supported as a manual setting right now.
274                          */
275                         return (EINVAL);
276                 case IFM_100_TX:
277                         dcphy_reset(sc);
278                         DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
279                         mode |= DC_NETCFG_PORTSEL|DC_NETCFG_PCS|
280                             DC_NETCFG_SCRAMBLER;
281                         if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
282                                 mode |= DC_NETCFG_FULLDUPLEX;
283                         else
284                                 mode &= ~DC_NETCFG_FULLDUPLEX;
285                         CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
286                         break;
287                 case IFM_10_T:
288                         DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
289                         DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF);
290                         if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
291                                 DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D);
292                         else
293                                 DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F);
294                         DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
295                         DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
296                         mode &= ~DC_NETCFG_PORTSEL;
297                         mode |= DC_NETCFG_SPEEDSEL;
298                         if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
299                                 mode |= DC_NETCFG_FULLDUPLEX;
300                         else
301                                 mode &= ~DC_NETCFG_FULLDUPLEX;
302                         CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
303                         break;
304                 default:
305                         return(EINVAL);
306                         break;
307                 }
308                 break;
309
310         case MII_TICK:
311                 /*
312                  * If we're not currently selected, just return.
313                  */
314                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
315                         return (0);
316
317                 /*
318                  * Only used for autonegotiation.
319                  */
320                 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
321                         return (0);
322
323                 /*
324                  * Is the interface even up?
325                  */
326                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
327                         return (0);
328
329                 reg = CSR_READ_4(dc_sc, DC_10BTSTAT) &
330                     (DC_TSTAT_LS10|DC_TSTAT_LS100);
331
332                 if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
333                         return(0);
334
335                 /*
336                  * Only retry autonegotiation every 5 seconds.
337                  */
338                 if (++sc->mii_ticks != 50)
339                         return (0);
340
341                 sc->mii_ticks = 0;
342                 /*if (DC_IS_INTEL(dc_sc))*/
343                         sc->mii_flags &= ~MIIF_DOINGAUTO;
344                 dcphy_auto(sc, 0);
345
346                 break;
347         }
348
349         /* Update the media status. */
350         dcphy_status(sc);
351
352         /* Callback if something changed. */
353         if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
354                 MIIBUS_STATCHG(sc->mii_dev);
355                 sc->mii_active = mii->mii_media_active;
356         }
357         return (0);
358 }
359
360 void
361 dcphy_status(sc)
362         struct mii_softc *sc;
363 {
364         struct mii_data *mii = sc->mii_pdata;
365         int reg, anlpar, tstat = 0;
366         struct dc_softc         *dc_sc;
367
368         dc_sc = mii->mii_ifp->if_softc;
369
370         mii->mii_media_status = IFM_AVALID;
371         mii->mii_media_active = IFM_ETHER;
372
373         if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
374                 return;
375
376         reg = CSR_READ_4(dc_sc, DC_10BTSTAT) &
377             (DC_TSTAT_LS10|DC_TSTAT_LS100);
378
379         if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
380                 mii->mii_media_status |= IFM_ACTIVE;
381
382         if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL) {
383                 /* Erg, still trying, I guess... */
384                 tstat = CSR_READ_4(dc_sc, DC_10BTSTAT);
385                 if ((tstat & DC_TSTAT_ANEGSTAT) != DC_ASTAT_AUTONEGCMP) {
386                         if ((DC_IS_MACRONIX(dc_sc) || DC_IS_PNICII(dc_sc)) &&
387                             (tstat & DC_TSTAT_ANEGSTAT) == DC_ASTAT_DISABLE)
388                                 goto skip;
389                         mii->mii_media_active |= IFM_NONE;
390                         return;
391                 }
392
393                 if (tstat & DC_TSTAT_LP_CAN_NWAY) {
394                         anlpar = tstat >> 16;
395                         if (anlpar & ANLPAR_T4 &&
396                             sc->mii_capabilities & BMSR_100TXHDX)
397                                 mii->mii_media_active |= IFM_100_T4;
398                         else if (anlpar & ANLPAR_TX_FD &&
399                             sc->mii_capabilities & BMSR_100TXFDX)
400                                 mii->mii_media_active |= IFM_100_TX|IFM_FDX;
401                         else if (anlpar & ANLPAR_TX &&
402                             sc->mii_capabilities & BMSR_100TXHDX)
403                                 mii->mii_media_active |= IFM_100_TX;
404                         else if (anlpar & ANLPAR_10_FD)
405                                 mii->mii_media_active |= IFM_10_T|IFM_FDX;
406                         else if (anlpar & ANLPAR_10)
407                                 mii->mii_media_active |= IFM_10_T;
408                         else
409                                 mii->mii_media_active |= IFM_NONE;
410                         if (DC_IS_INTEL(dc_sc))
411                                 DC_CLRBIT(dc_sc, DC_10BTCTRL,
412                                     DC_TCTL_AUTONEGENBL);
413                         return;
414                 }
415                 /*
416                  * If the other side doesn't support NWAY, then the
417                  * best we can do is determine if we have a 10Mbps or
418                  * 100Mbps link. There's no way to know if the link 
419                  * is full or half duplex, so we default to half duplex
420                  * and hope that the user is clever enough to manually
421                  * change the media settings if we're wrong.
422                  */
423                 if (!(reg & DC_TSTAT_LS100))
424                         mii->mii_media_active |= IFM_100_TX;
425                 else if (!(reg & DC_TSTAT_LS10))
426                         mii->mii_media_active |= IFM_10_T;
427                 else
428                         mii->mii_media_active |= IFM_NONE;
429                 if (DC_IS_INTEL(dc_sc))
430                         DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
431                 return;
432         }
433
434 skip:
435
436         if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
437                 mii->mii_media_active |= IFM_10_T;
438         else
439                 mii->mii_media_active |= IFM_100_TX;
440         if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
441                 mii->mii_media_active |= IFM_FDX;
442
443         return;
444 }
445
446 static int
447 dcphy_auto(mii, waitfor)
448         struct mii_softc        *mii;
449         int                     waitfor;
450 {
451         int                     i;
452         struct dc_softc         *sc;
453
454         sc = mii->mii_pdata->mii_ifp->if_softc;
455
456         if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
457                 DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
458                 DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
459                 DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
460                 if (mii->mii_capabilities & BMSR_100TXHDX)
461                         CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF);
462                 else
463                         CSR_WRITE_4(sc, DC_10BTCTRL, 0xFFFF);
464                 DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
465                 DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
466                 DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE);
467         }
468
469         if (waitfor) {
470                 /* Wait 500ms for it to complete. */
471                 for (i = 0; i < 500; i++) {
472                         if ((CSR_READ_4(sc, DC_10BTSTAT) & DC_TSTAT_ANEGSTAT)
473                             == DC_ASTAT_AUTONEGCMP)
474                                 return(0);
475                         DELAY(1000);
476                 }
477                 /*
478                  * Don't need to worry about clearing MIIF_DOINGAUTO.
479                  * If that's set, a timeout is pending, and it will
480                  * clear the flag.
481                  */
482                 return(EIO);
483         }
484
485         /*
486          * Just let it finish asynchronously.  This is for the benefit of
487          * the tick handler driving autonegotiation.  Don't want 500ms
488          * delays all the time while the system is running!
489          */
490         if ((mii->mii_flags & MIIF_DOINGAUTO) == 0)
491                 mii->mii_flags |= MIIF_DOINGAUTO;
492
493         return(EJUSTRETURN);
494 }
495
496 static void
497 dcphy_reset(mii)
498         struct mii_softc        *mii;
499 {
500         struct dc_softc         *sc;
501
502         sc = mii->mii_pdata->mii_ifp->if_softc;
503
504         DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
505         DELAY(1000);
506         DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
507
508         return;
509 }
510