source: rtems-libbsd/freebsd/dev/dc/dcphy.c @ 5ad09a1

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 5ad09a1 was 5ad09a1, checked in by Joel Sherrill <joel.sherrill@…>, on 03/22/12 at 13:02:26

Add DEC Tulip, Broadcomm (bce, bfe, bge), and SMC 9111x NICs

  • Property mode set to 100644
File size: 11.8 KB
Line 
1#include <freebsd/machine/rtems-bsd-config.h>
2
3/*-
4 * Copyright (c) 1997, 1998, 1999
5 *      Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *      This product includes software developed by Bill Paul.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <freebsd/sys/cdefs.h>
36__FBSDID("$FreeBSD$");
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 <freebsd/sys/param.h>
48#include <freebsd/sys/systm.h>
49#include <freebsd/sys/kernel.h>
50#include <freebsd/sys/socket.h>
51#include <freebsd/sys/errno.h>
52#include <freebsd/sys/lock.h>
53#include <freebsd/sys/module.h>
54#include <freebsd/sys/mutex.h>
55#include <freebsd/sys/bus.h>
56
57#include <freebsd/net/if.h>
58#include <freebsd/net/if_arp.h>
59#include <freebsd/net/if_media.h>
60
61#include <freebsd/dev/mii/mii.h>
62#include <freebsd/dev/mii/miivar.h>
63#include <freebsd/local/miidevs.h>
64
65#include <freebsd/machine/bus.h>
66#include <freebsd/machine/resource.h>
67#include <freebsd/sys/bus.h>
68
69#include <freebsd/dev/pci/pcivar.h>
70
71#include <freebsd/dev/dc/if_dcreg.h>
72
73#include <freebsd/local/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
92static int dcphy_probe(device_t);
93static int dcphy_attach(device_t);
94
95static device_method_t dcphy_methods[] = {
96        /* device interface */
97        DEVMETHOD(device_probe,         dcphy_probe),
98        DEVMETHOD(device_attach,        dcphy_attach),
99        DEVMETHOD(device_detach,        mii_phy_detach),
100        DEVMETHOD(device_shutdown,      bus_generic_shutdown),
101        { 0, 0 }
102};
103
104static devclass_t dcphy_devclass;
105
106static driver_t dcphy_driver = {
107        "dcphy",
108        dcphy_methods,
109        sizeof(struct mii_softc)
110};
111
112DRIVER_MODULE(dcphy, miibus, dcphy_driver, dcphy_devclass, 0, 0);
113
114static int      dcphy_service(struct mii_softc *, struct mii_data *, int);
115static void     dcphy_status(struct mii_softc *);
116static void     dcphy_reset(struct mii_softc *);
117static int      dcphy_auto(struct mii_softc *);
118
119static int
120dcphy_probe(device_t dev)
121{
122        struct mii_attach_args *ma;
123
124        ma = device_get_ivars(dev);
125
126        /*
127         * The dc driver will report the 21143 vendor and device
128         * ID to let us know that it wants us to attach.
129         */
130        if (ma->mii_id1 != DC_VENDORID_DEC ||
131            ma->mii_id2 != DC_DEVICEID_21143)
132                return (ENXIO);
133
134        device_set_desc(dev, "Intel 21143 NWAY media interface");
135
136        return (BUS_PROBE_DEFAULT);
137}
138
139static int
140dcphy_attach(device_t dev)
141{
142        struct mii_softc *sc;
143        struct mii_attach_args *ma;
144        struct mii_data *mii;
145        struct dc_softc         *dc_sc;
146        device_t brdev;
147
148        sc = device_get_softc(dev);
149        ma = device_get_ivars(dev);
150        sc->mii_dev = device_get_parent(dev);
151        mii = ma->mii_data;
152        LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
153
154        sc->mii_flags = miibus_get_flags(dev);
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        /*
161         * Apparently, we can neither isolate nor do loopback.
162         */
163        sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP;
164
165        /*dcphy_reset(sc);*/
166        dc_sc = mii->mii_ifp->if_softc;
167        CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0);
168        CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0);
169
170        brdev = device_get_parent(sc->mii_dev);
171        switch (pci_get_subdevice(brdev) << 16 | pci_get_subvendor(brdev)) {
172        case COMPAQ_PRESARIO_ID:
173                /* Example of how to only allow 10Mbps modes. */
174                sc->mii_capabilities = BMSR_ANEG | BMSR_10TFDX | BMSR_10THDX;
175                break;
176        default:
177                if (dc_sc->dc_pmode == DC_PMODE_SIA)
178                        sc->mii_capabilities =
179                            BMSR_ANEG | BMSR_10TFDX | BMSR_10THDX;
180                else
181                        sc->mii_capabilities =
182                            BMSR_ANEG | BMSR_100TXFDX | BMSR_100TXHDX |
183                            BMSR_10TFDX | BMSR_10THDX;
184                break;
185        }
186
187        sc->mii_capabilities &= ma->mii_capmask;
188        device_printf(dev, " ");
189        mii_phy_add_media(sc);
190        printf("\n");
191
192        MIIBUS_MEDIAINIT(sc->mii_dev);
193        return (0);
194}
195
196static int
197dcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
198{
199        struct dc_softc         *dc_sc;
200        struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
201        int reg;
202        u_int32_t               mode;
203
204        dc_sc = mii->mii_ifp->if_softc;
205
206        switch (cmd) {
207        case MII_POLLSTAT:
208                break;
209
210        case MII_MEDIACHG:
211                /*
212                 * If the interface is not up, don't do anything.
213                 */
214                if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
215                        break;
216
217                mii->mii_media_active = IFM_NONE;
218                mode = CSR_READ_4(dc_sc, DC_NETCFG);
219                mode &= ~(DC_NETCFG_FULLDUPLEX | DC_NETCFG_PORTSEL |
220                    DC_NETCFG_PCS | DC_NETCFG_SCRAMBLER | DC_NETCFG_SPEEDSEL);
221
222                switch (IFM_SUBTYPE(ife->ifm_media)) {
223                case IFM_AUTO:
224                        /*dcphy_reset(sc);*/
225                        (void) dcphy_auto(sc);
226                        break;
227                case IFM_100_T4:
228                        /*
229                         * XXX Not supported as a manual setting right now.
230                         */
231                        return (EINVAL);
232                case IFM_100_TX:
233                        dcphy_reset(sc);
234                        DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
235                        mode |= DC_NETCFG_PORTSEL | DC_NETCFG_PCS |
236                            DC_NETCFG_SCRAMBLER;
237                        if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
238                                mode |= DC_NETCFG_FULLDUPLEX;
239                        else
240                                mode &= ~DC_NETCFG_FULLDUPLEX;
241                        CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
242                        break;
243                case IFM_10_T:
244                        DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
245                        DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF);
246                        if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
247                                DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D);
248                        else
249                                DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F);
250                        DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
251                        DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
252                        mode &= ~DC_NETCFG_PORTSEL;
253                        mode |= DC_NETCFG_SPEEDSEL;
254                        if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
255                                mode |= DC_NETCFG_FULLDUPLEX;
256                        else
257                                mode &= ~DC_NETCFG_FULLDUPLEX;
258                        CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
259                        break;
260                default:
261                        return (EINVAL);
262                }
263                break;
264
265        case MII_TICK:
266                /*
267                 * Is the interface even up?
268                 */
269                if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
270                        return (0);
271
272                /*
273                 * Only used for autonegotiation.
274                 */
275                if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
276                        break;
277
278                reg = CSR_READ_4(dc_sc, DC_10BTSTAT);
279                if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
280                        break;
281
282                /*
283                 * Only retry autonegotiation every 5 seconds.
284                 *
285                 * Otherwise, fall through to calling dcphy_status()
286                 * since real Intel 21143 chips don't show valid link
287                 * status until autonegotiation is switched off, and
288                 * that only happens in dcphy_status().  Without this,
289                 * successful autonegotiation is never recognised on
290                 * these chips.
291                 */
292                if (++sc->mii_ticks <= 50)
293                        break;
294
295                sc->mii_ticks = 0;
296                dcphy_auto(sc);
297
298                break;
299        }
300
301        /* Update the media status. */
302        dcphy_status(sc);
303
304        /* Callback if something changed. */
305        mii_phy_update(sc, cmd);
306        return (0);
307}
308
309static void
310dcphy_status(struct mii_softc *sc)
311{
312        struct mii_data *mii = sc->mii_pdata;
313        int reg, anlpar, tstat = 0;
314        struct dc_softc         *dc_sc;
315
316        dc_sc = mii->mii_ifp->if_softc;
317
318        mii->mii_media_status = IFM_AVALID;
319        mii->mii_media_active = IFM_ETHER;
320
321        if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
322                return;
323
324        reg = CSR_READ_4(dc_sc, DC_10BTSTAT);
325        if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
326                mii->mii_media_status |= IFM_ACTIVE;
327
328        if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL) {
329                /* Erg, still trying, I guess... */
330                tstat = CSR_READ_4(dc_sc, DC_10BTSTAT);
331                if ((tstat & DC_TSTAT_ANEGSTAT) != DC_ASTAT_AUTONEGCMP) {
332                        if ((DC_IS_MACRONIX(dc_sc) || DC_IS_PNICII(dc_sc)) &&
333                            (tstat & DC_TSTAT_ANEGSTAT) == DC_ASTAT_DISABLE)
334                                goto skip;
335                        mii->mii_media_active |= IFM_NONE;
336                        return;
337                }
338
339                if (tstat & DC_TSTAT_LP_CAN_NWAY) {
340                        anlpar = tstat >> 16;
341                        if (anlpar & ANLPAR_TX_FD &&
342                            sc->mii_capabilities & BMSR_100TXFDX)
343                                mii->mii_media_active |= IFM_100_TX | IFM_FDX;
344                        else if (anlpar & ANLPAR_T4 &&
345                            sc->mii_capabilities & BMSR_100T4)
346                                mii->mii_media_active |= IFM_100_T4 | IFM_HDX;
347                        else if (anlpar & ANLPAR_TX &&
348                            sc->mii_capabilities & BMSR_100TXHDX)
349                                mii->mii_media_active |= IFM_100_TX | IFM_HDX;
350                        else if (anlpar & ANLPAR_10_FD)
351                                mii->mii_media_active |= IFM_10_T | IFM_FDX;
352                        else if (anlpar & ANLPAR_10)
353                                mii->mii_media_active |= IFM_10_T | IFM_HDX;
354                        else
355                                mii->mii_media_active |= IFM_NONE;
356                        if (DC_IS_INTEL(dc_sc))
357                                DC_CLRBIT(dc_sc, DC_10BTCTRL,
358                                    DC_TCTL_AUTONEGENBL);
359                        return;
360                }
361
362                /*
363                 * If the other side doesn't support NWAY, then the
364                 * best we can do is determine if we have a 10Mbps or
365                 * 100Mbps link.  There's no way to know if the link
366                 * is full or half duplex, so we default to half duplex
367                 * and hope that the user is clever enough to manually
368                 * change the media settings if we're wrong.
369                 */
370                if (!(reg & DC_TSTAT_LS100))
371                        mii->mii_media_active |= IFM_100_TX | IFM_HDX;
372                else if (!(reg & DC_TSTAT_LS10))
373                        mii->mii_media_active |= IFM_10_T | IFM_HDX;
374                else
375                        mii->mii_media_active |= IFM_NONE;
376                if (DC_IS_INTEL(dc_sc))
377                        DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
378                return;
379        }
380
381skip:
382        if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
383                mii->mii_media_active |= IFM_10_T;
384        else
385                mii->mii_media_active |= IFM_100_TX;
386        if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
387                mii->mii_media_active |= IFM_FDX;
388        else
389                mii->mii_media_active |= IFM_HDX;
390}
391
392static int
393dcphy_auto(struct mii_softc *mii)
394{
395        struct dc_softc         *sc;
396
397        sc = mii->mii_pdata->mii_ifp->if_softc;
398
399        DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
400        DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
401        DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
402        if (mii->mii_capabilities & BMSR_100TXHDX)
403                CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF);
404        else
405                CSR_WRITE_4(sc, DC_10BTCTRL, 0xFFFF);
406        DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
407        DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
408        DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE);
409
410        return (EJUSTRETURN);
411}
412
413static void
414dcphy_reset(struct mii_softc *mii)
415{
416        struct dc_softc         *sc;
417
418        sc = mii->mii_pdata->mii_ifp->if_softc;
419
420        DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
421        DELAY(1000);
422        DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
423}
Note: See TracBrowser for help on using the repository browser.