OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [net/] [mii.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 
3
        mii.c: MII interface library
4
 
5
        Maintained by Jeff Garzik <jgarzik@pobox.com>
6
        Copyright 2001,2002 Jeff Garzik
7
 
8
        Various code came from myson803.c and other files by
9
        Donald Becker.  Copyright:
10
 
11
                Written 1998-2002 by Donald Becker.
12
 
13
                This software may be used and distributed according
14
                to the terms of the GNU General Public License (GPL),
15
                incorporated herein by reference.  Drivers based on
16
                or derived from this code fall under the GPL and must
17
                retain the authorship, copyright and license notice.
18
                This file is not a complete program and may only be
19
                used when the entire operating system is licensed
20
                under the GPL.
21
 
22
                The author may be reached as becker@scyld.com, or C/O
23
                Scyld Computing Corporation
24
                410 Severn Ave., Suite 210
25
                Annapolis MD 21403
26
 
27
 
28
 */
29
 
30
#include <linux/kernel.h>
31
#include <linux/module.h>
32
#include <linux/netdevice.h>
33
#include <linux/ethtool.h>
34
#include <linux/mii.h>
35
 
36
/**
37
 * mii_ethtool_gset - get settings that are specified in @ecmd
38
 * @mii: MII interface
39
 * @ecmd: requested ethtool_cmd
40
 *
41
 * Returns 0 for success, negative on error.
42
 */
43
int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
44
{
45
        struct net_device *dev = mii->dev;
46
        u32 advert, bmcr, lpa, nego;
47
        u32 advert2 = 0, bmcr2 = 0, lpa2 = 0;
48
 
49
        ecmd->supported =
50
            (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
51
             SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
52
             SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
53
        if (mii->supports_gmii)
54
                ecmd->supported |= SUPPORTED_1000baseT_Half |
55
                        SUPPORTED_1000baseT_Full;
56
 
57
        /* only supports twisted-pair */
58
        ecmd->port = PORT_MII;
59
 
60
        /* only supports internal transceiver */
61
        ecmd->transceiver = XCVR_INTERNAL;
62
 
63
        /* this isn't fully supported at higher layers */
64
        ecmd->phy_address = mii->phy_id;
65
 
66
        ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
67
        advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
68
        if (mii->supports_gmii)
69
                advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
70
 
71
        if (advert & ADVERTISE_10HALF)
72
                ecmd->advertising |= ADVERTISED_10baseT_Half;
73
        if (advert & ADVERTISE_10FULL)
74
                ecmd->advertising |= ADVERTISED_10baseT_Full;
75
        if (advert & ADVERTISE_100HALF)
76
                ecmd->advertising |= ADVERTISED_100baseT_Half;
77
        if (advert & ADVERTISE_100FULL)
78
                ecmd->advertising |= ADVERTISED_100baseT_Full;
79
        if (advert2 & ADVERTISE_1000HALF)
80
                ecmd->advertising |= ADVERTISED_1000baseT_Half;
81
        if (advert2 & ADVERTISE_1000FULL)
82
                ecmd->advertising |= ADVERTISED_1000baseT_Full;
83
 
84
        bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
85
        lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
86
        if (mii->supports_gmii) {
87
                bmcr2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
88
                lpa2 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
89
        }
90
        if (bmcr & BMCR_ANENABLE) {
91
                ecmd->advertising |= ADVERTISED_Autoneg;
92
                ecmd->autoneg = AUTONEG_ENABLE;
93
 
94
                nego = mii_nway_result(advert & lpa);
95
                if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) &
96
                    (lpa2 >> 2))
97
                        ecmd->speed = SPEED_1000;
98
                else if (nego == LPA_100FULL || nego == LPA_100HALF)
99
                        ecmd->speed = SPEED_100;
100
                else
101
                        ecmd->speed = SPEED_10;
102
                if ((lpa2 & LPA_1000FULL) || nego == LPA_100FULL ||
103
                    nego == LPA_10FULL) {
104
                        ecmd->duplex = DUPLEX_FULL;
105
                        mii->full_duplex = 1;
106
                } else {
107
                        ecmd->duplex = DUPLEX_HALF;
108
                        mii->full_duplex = 0;
109
                }
110
        } else {
111
                ecmd->autoneg = AUTONEG_DISABLE;
112
 
113
                ecmd->speed = ((bmcr & BMCR_SPEED1000 &&
114
                                (bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 :
115
                               (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10);
116
                ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
117
        }
118
 
119
        /* ignore maxtxpkt, maxrxpkt for now */
120
 
121
        return 0;
122
}
123
 
124
/**
125
 * mii_ethtool_sset - set settings that are specified in @ecmd
126
 * @mii: MII interface
127
 * @ecmd: requested ethtool_cmd
128
 *
129
 * Returns 0 for success, negative on error.
130
 */
131
int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
132
{
133
        struct net_device *dev = mii->dev;
134
 
135
        if (ecmd->speed != SPEED_10 &&
136
            ecmd->speed != SPEED_100 &&
137
            ecmd->speed != SPEED_1000)
138
                return -EINVAL;
139
        if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
140
                return -EINVAL;
141
        if (ecmd->port != PORT_MII)
142
                return -EINVAL;
143
        if (ecmd->transceiver != XCVR_INTERNAL)
144
                return -EINVAL;
145
        if (ecmd->phy_address != mii->phy_id)
146
                return -EINVAL;
147
        if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
148
                return -EINVAL;
149
        if ((ecmd->speed == SPEED_1000) && (!mii->supports_gmii))
150
                return -EINVAL;
151
 
152
        /* ignore supported, maxtxpkt, maxrxpkt */
153
 
154
        if (ecmd->autoneg == AUTONEG_ENABLE) {
155
                u32 bmcr, advert, tmp;
156
                u32 advert2 = 0, tmp2 = 0;
157
 
158
                if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
159
                                          ADVERTISED_10baseT_Full |
160
                                          ADVERTISED_100baseT_Half |
161
                                          ADVERTISED_100baseT_Full |
162
                                          ADVERTISED_1000baseT_Half |
163
                                          ADVERTISED_1000baseT_Full)) == 0)
164
                        return -EINVAL;
165
 
166
                /* advertise only what has been requested */
167
                advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
168
                tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
169
                if (mii->supports_gmii) {
170
                        advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
171
                        tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
172
                }
173
                if (ecmd->advertising & ADVERTISED_10baseT_Half)
174
                        tmp |= ADVERTISE_10HALF;
175
                if (ecmd->advertising & ADVERTISED_10baseT_Full)
176
                        tmp |= ADVERTISE_10FULL;
177
                if (ecmd->advertising & ADVERTISED_100baseT_Half)
178
                        tmp |= ADVERTISE_100HALF;
179
                if (ecmd->advertising & ADVERTISED_100baseT_Full)
180
                        tmp |= ADVERTISE_100FULL;
181
                if (mii->supports_gmii) {
182
                        if (ecmd->advertising & ADVERTISED_1000baseT_Half)
183
                                tmp2 |= ADVERTISE_1000HALF;
184
                        if (ecmd->advertising & ADVERTISED_1000baseT_Full)
185
                                tmp2 |= ADVERTISE_1000FULL;
186
                }
187
                if (advert != tmp) {
188
                        mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
189
                        mii->advertising = tmp;
190
                }
191
                if ((mii->supports_gmii) && (advert2 != tmp2))
192
                        mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
193
 
194
                /* turn on autonegotiation, and force a renegotiate */
195
                bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
196
                bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
197
                mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
198
 
199
                mii->force_media = 0;
200
        } else {
201
                u32 bmcr, tmp;
202
 
203
                /* turn off auto negotiation, set speed and duplexity */
204
                bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
205
                tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
206
                               BMCR_SPEED1000 | BMCR_FULLDPLX);
207
                if (ecmd->speed == SPEED_1000)
208
                        tmp |= BMCR_SPEED1000;
209
                else if (ecmd->speed == SPEED_100)
210
                        tmp |= BMCR_SPEED100;
211
                if (ecmd->duplex == DUPLEX_FULL) {
212
                        tmp |= BMCR_FULLDPLX;
213
                        mii->full_duplex = 1;
214
                } else
215
                        mii->full_duplex = 0;
216
                if (bmcr != tmp)
217
                        mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
218
 
219
                mii->force_media = 1;
220
        }
221
        return 0;
222
}
223
 
224
/**
225
 * mii_check_gmii_support - check if the MII supports Gb interfaces
226
 * @mii: the MII interface
227
 */
228
int mii_check_gmii_support(struct mii_if_info *mii)
229
{
230
        int reg;
231
 
232
        reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
233
        if (reg & BMSR_ESTATEN) {
234
                reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
235
                if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
236
                        return 1;
237
        }
238
 
239
        return 0;
240
}
241
 
242
/**
243
 * mii_link_ok - is link status up/ok
244
 * @mii: the MII interface
245
 *
246
 * Returns 1 if the MII reports link status up/ok, 0 otherwise.
247
 */
248
int mii_link_ok (struct mii_if_info *mii)
249
{
250
        /* first, a dummy read, needed to latch some MII phys */
251
        mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
252
        if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
253
                return 1;
254
        return 0;
255
}
256
 
257
/**
258
 * mii_nway_restart - restart NWay (autonegotiation) for this interface
259
 * @mii: the MII interface
260
 *
261
 * Returns 0 on success, negative on error.
262
 */
263
int mii_nway_restart (struct mii_if_info *mii)
264
{
265
        int bmcr;
266
        int r = -EINVAL;
267
 
268
        /* if autoneg is off, it's an error */
269
        bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
270
 
271
        if (bmcr & BMCR_ANENABLE) {
272
                bmcr |= BMCR_ANRESTART;
273
                mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
274
                r = 0;
275
        }
276
 
277
        return r;
278
}
279
 
280
/**
281
 * mii_check_link - check MII link status
282
 * @mii: MII interface
283
 *
284
 * If the link status changed (previous != current), call
285
 * netif_carrier_on() if current link status is Up or call
286
 * netif_carrier_off() if current link status is Down.
287
 */
288
void mii_check_link (struct mii_if_info *mii)
289
{
290
        int cur_link = mii_link_ok(mii);
291
        int prev_link = netif_carrier_ok(mii->dev);
292
 
293
        if (cur_link && !prev_link)
294
                netif_carrier_on(mii->dev);
295
        else if (prev_link && !cur_link)
296
                netif_carrier_off(mii->dev);
297
}
298
 
299
/**
300
 * mii_check_media - check the MII interface for a duplex change
301
 * @mii: the MII interface
302
 * @ok_to_print: OK to print link up/down messages
303
 * @init_media: OK to save duplex mode in @mii
304
 *
305
 * Returns 1 if the duplex mode changed, 0 if not.
306
 * If the media type is forced, always returns 0.
307
 */
308
unsigned int mii_check_media (struct mii_if_info *mii,
309
                              unsigned int ok_to_print,
310
                              unsigned int init_media)
311
{
312
        unsigned int old_carrier, new_carrier;
313
        int advertise, lpa, media, duplex;
314
        int lpa2 = 0;
315
 
316
        /* if forced media, go no further */
317
        if (mii->force_media)
318
                return 0; /* duplex did not change */
319
 
320
        /* check current and old link status */
321
        old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
322
        new_carrier = (unsigned int) mii_link_ok(mii);
323
 
324
        /* if carrier state did not change, this is a "bounce",
325
         * just exit as everything is already set correctly
326
         */
327
        if ((!init_media) && (old_carrier == new_carrier))
328
                return 0; /* duplex did not change */
329
 
330
        /* no carrier, nothing much to do */
331
        if (!new_carrier) {
332
                netif_carrier_off(mii->dev);
333
                if (ok_to_print)
334
                        printk(KERN_INFO "%s: link down\n", mii->dev->name);
335
                return 0; /* duplex did not change */
336
        }
337
 
338
        /*
339
         * we have carrier, see who's on the other end
340
         */
341
        netif_carrier_on(mii->dev);
342
 
343
        /* get MII advertise and LPA values */
344
        if ((!init_media) && (mii->advertising))
345
                advertise = mii->advertising;
346
        else {
347
                advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
348
                mii->advertising = advertise;
349
        }
350
        lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
351
        if (mii->supports_gmii)
352
                lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
353
 
354
        /* figure out media and duplex from advertise and LPA values */
355
        media = mii_nway_result(lpa & advertise);
356
        duplex = (media & ADVERTISE_FULL) ? 1 : 0;
357
        if (lpa2 & LPA_1000FULL)
358
                duplex = 1;
359
 
360
        if (ok_to_print)
361
                printk(KERN_INFO "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n",
362
                       mii->dev->name,
363
                       lpa2 & (LPA_1000FULL | LPA_1000HALF) ? "1000" :
364
                       media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? "100" : "10",
365
                       duplex ? "full" : "half",
366
                       lpa);
367
 
368
        if ((init_media) || (mii->full_duplex != duplex)) {
369
                mii->full_duplex = duplex;
370
                return 1; /* duplex changed */
371
        }
372
 
373
        return 0; /* duplex did not change */
374
}
375
 
376
/**
377
 * generic_mii_ioctl - main MII ioctl interface
378
 * @mii_if: the MII interface
379
 * @mii_data: MII ioctl data structure
380
 * @cmd: MII ioctl command
381
 * @duplex_chg_out: pointer to @duplex_changed status if there was no
382
 *      ioctl error
383
 *
384
 * Returns 0 on success, negative on error.
385
 */
386
int generic_mii_ioctl(struct mii_if_info *mii_if,
387
                      struct mii_ioctl_data *mii_data, int cmd,
388
                      unsigned int *duplex_chg_out)
389
{
390
        int rc = 0;
391
        unsigned int duplex_changed = 0;
392
 
393
        if (duplex_chg_out)
394
                *duplex_chg_out = 0;
395
 
396
        mii_data->phy_id &= mii_if->phy_id_mask;
397
        mii_data->reg_num &= mii_if->reg_num_mask;
398
 
399
        switch(cmd) {
400
        case SIOCGMIIPHY:
401
                mii_data->phy_id = mii_if->phy_id;
402
                /* fall through */
403
 
404
        case SIOCGMIIREG:
405
                mii_data->val_out =
406
                        mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
407
                                          mii_data->reg_num);
408
                break;
409
 
410
        case SIOCSMIIREG: {
411
                u16 val = mii_data->val_in;
412
 
413
                if (!capable(CAP_NET_ADMIN))
414
                        return -EPERM;
415
 
416
                if (mii_data->phy_id == mii_if->phy_id) {
417
                        switch(mii_data->reg_num) {
418
                        case MII_BMCR: {
419
                                unsigned int new_duplex = 0;
420
                                if (val & (BMCR_RESET|BMCR_ANENABLE))
421
                                        mii_if->force_media = 0;
422
                                else
423
                                        mii_if->force_media = 1;
424
                                if (mii_if->force_media &&
425
                                    (val & BMCR_FULLDPLX))
426
                                        new_duplex = 1;
427
                                if (mii_if->full_duplex != new_duplex) {
428
                                        duplex_changed = 1;
429
                                        mii_if->full_duplex = new_duplex;
430
                                }
431
                                break;
432
                        }
433
                        case MII_ADVERTISE:
434
                                mii_if->advertising = val;
435
                                break;
436
                        default:
437
                                /* do nothing */
438
                                break;
439
                        }
440
                }
441
 
442
                mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
443
                                   mii_data->reg_num, val);
444
                break;
445
        }
446
 
447
        default:
448
                rc = -EOPNOTSUPP;
449
                break;
450
        }
451
 
452
        if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
453
                *duplex_chg_out = 1;
454
 
455
        return rc;
456
}
457
 
458
MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
459
MODULE_DESCRIPTION ("MII hardware support library");
460
MODULE_LICENSE("GPL");
461
 
462
EXPORT_SYMBOL(mii_link_ok);
463
EXPORT_SYMBOL(mii_nway_restart);
464
EXPORT_SYMBOL(mii_ethtool_gset);
465
EXPORT_SYMBOL(mii_ethtool_sset);
466
EXPORT_SYMBOL(mii_check_link);
467
EXPORT_SYMBOL(mii_check_media);
468
EXPORT_SYMBOL(mii_check_gmii_support);
469
EXPORT_SYMBOL(generic_mii_ioctl);
470
 

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.