akaros/kern/drivers/net/ethermii.c
<<
>>
Prefs
   1/* This file is part of the UCB release of Plan 9. It is subject to the license
   2 * terms in the LICENSE file found in the top-level directory of this
   3 * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
   4 * part of the UCB release of Plan 9, including this file, may be copied,
   5 * modified, propagated, or distributed except according to the terms contained
   6 * in the LICENSE file. */
   7
   8#include <assert.h>
   9#include <cpio.h>
  10#include <error.h>
  11#include <kmalloc.h>
  12#include <kref.h>
  13#include <pmap.h>
  14#include <slab.h>
  15#include <smp.h>
  16#include <stdio.h>
  17#include <string.h>
  18
  19#include "ethermii.h"
  20
  21static int miiprobe(struct mii *mii, int mask)
  22{
  23        struct miiphy *miiphy;
  24        int bit, oui, phyno, r, rmask;
  25
  26        /*
  27         * Probe through mii for PHYs in mask;
  28         * return the mask of those found in the current probe.
  29         * If the PHY has not already been probed, update
  30         * the Mii information.
  31         */
  32        rmask = 0;
  33        for (phyno = 0; phyno < NMiiPhy; phyno++) {
  34                bit = 1 << phyno;
  35                if (!(mask & bit))
  36                        continue;
  37                if (mii->mask & bit) {
  38                        rmask |= bit;
  39                        continue;
  40                }
  41                if (mii->rw(mii, 0, phyno, Bmsr, 0) == -1)
  42                        continue;
  43                r = mii->rw(mii, 0, phyno, Phyidr1, 0) << 16;
  44                r |= mii->rw(mii, 0, phyno, Phyidr2, 0);
  45                oui = (r >> 10) & 0xffff;
  46                if (oui == 0xffff || oui == 0)
  47                        continue;
  48
  49                if ((miiphy = kzmalloc(sizeof(struct miiphy), 0)) == NULL)
  50                        continue;
  51
  52                miiphy->mii = mii;
  53                miiphy->phyno = phyno;
  54                miiphy->phyid = r;
  55                miiphy->oui = oui;
  56
  57                miiphy->anar = ~0;
  58                miiphy->fc = ~0;
  59                miiphy->mscr = ~0;
  60
  61                mii->phy[phyno] = miiphy;
  62                if (mii->curphy == NULL)
  63                        mii->curphy = miiphy;
  64                mii->mask |= bit;
  65                mii->nphy++;
  66
  67                rmask |= bit;
  68        }
  69        return rmask;
  70}
  71
  72int miimir(struct mii *mii, int r)
  73{
  74        if (mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
  75                return -1;
  76        return mii->rw(mii, 0, mii->curphy->phyno, r, 0);
  77}
  78
  79int miimiw(struct mii *mii, int r, int data)
  80{
  81        if (mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
  82                return -1;
  83        return mii->rw(mii, 1, mii->curphy->phyno, r, data);
  84}
  85
  86int miireset(struct mii *mii)
  87{
  88        int bmcr, timeo;
  89
  90        if (mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
  91                return -1;
  92        bmcr = mii->rw(mii, 0, mii->curphy->phyno, Bmcr, 0);
  93        mii->rw(mii, 1, mii->curphy->phyno, Bmcr, BmcrR | bmcr);
  94        for (timeo = 0; timeo < 1000; timeo++) {
  95                bmcr = mii->rw(mii, 0, mii->curphy->phyno, Bmcr, 0);
  96                if (!(bmcr & BmcrR))
  97                        break;
  98                udelay(1);
  99        }
 100        if (bmcr & BmcrR)
 101                return -1;
 102        if (bmcr & BmcrI)
 103                mii->rw(mii, 1, mii->curphy->phyno, Bmcr, bmcr & ~BmcrI);
 104        return 0;
 105}
 106
 107int miiane(struct mii *mii, int a, int p, int e)
 108{
 109        int anar, bmsr, mscr, r, phyno;
 110
 111        if (mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
 112                return -1;
 113        phyno = mii->curphy->phyno;
 114
 115        mii->rw(mii, 1, phyno, Bmsr, 0);
 116        bmsr = mii->rw(mii, 0, phyno, Bmsr, 0);
 117        if (!(bmsr & BmsrAna))
 118                return -1;
 119
 120        if (a != ~0)
 121                anar = (AnaTXFD | AnaTXHD | Ana10FD | Ana10HD) & a;
 122        else if (mii->curphy->anar != ~0)
 123                anar = mii->curphy->anar;
 124        else {
 125                anar = mii->rw(mii, 0, phyno, Anar, 0);
 126                anar &= ~(AnaAP | AnaP | AnaT4 | AnaTXFD | AnaTXHD | Ana10FD |
 127                          Ana10HD);
 128                if (bmsr & Bmsr10THD)
 129                        anar |= Ana10HD;
 130                if (bmsr & Bmsr10TFD)
 131                        anar |= Ana10FD;
 132                if (bmsr & Bmsr100TXHD)
 133                        anar |= AnaTXHD;
 134                if (bmsr & Bmsr100TXFD)
 135                        anar |= AnaTXFD;
 136        }
 137        mii->curphy->anar = anar;
 138
 139        if (p != ~0)
 140                anar |= (AnaAP | AnaP) & p;
 141        else if (mii->curphy->fc != ~0)
 142                anar |= mii->curphy->fc;
 143        mii->curphy->fc = (AnaAP | AnaP) & anar;
 144
 145        if (bmsr & BmsrEs) {
 146                mscr = mii->rw(mii, 0, phyno, Mscr, 0);
 147                mscr &= ~(Mscr1000TFD | Mscr1000THD);
 148                if (e != ~0)
 149                        mscr |= (Mscr1000TFD | Mscr1000THD) & e;
 150                else if (mii->curphy->mscr != ~0)
 151                        mscr = mii->curphy->mscr;
 152                else {
 153                        r = mii->rw(mii, 0, phyno, Esr, 0);
 154                        if (r & Esr1000THD)
 155                                mscr |= Mscr1000THD;
 156                        if (r & Esr1000TFD)
 157                                mscr |= Mscr1000TFD;
 158                }
 159                mii->curphy->mscr = mscr;
 160                mii->rw(mii, 1, phyno, Mscr, mscr);
 161        } else
 162                mii->curphy->mscr = 0;
 163        mii->rw(mii, 1, phyno, Anar, anar);
 164
 165        r = mii->rw(mii, 0, phyno, Bmcr, 0);
 166        if (!(r & BmcrR)) {
 167                r |= BmcrAne | BmcrRan;
 168                mii->rw(mii, 1, phyno, Bmcr, r);
 169        }
 170
 171        return 0;
 172}
 173
 174int miistatus(struct mii *mii)
 175{
 176        struct miiphy *phy;
 177        int anlpar, bmsr, p, r, phyno;
 178
 179        if (mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
 180                return -1;
 181        phy = mii->curphy;
 182        phyno = phy->phyno;
 183
 184        /*
 185         * Check Auto-Negotiation is complete and link is up.
 186         * (Read status twice as the Ls bit is sticky).
 187         */
 188        bmsr = mii->rw(mii, 0, phyno, Bmsr, 0);
 189        if (!(bmsr & (BmsrAnc | BmsrAna)))
 190                return -1;
 191
 192        bmsr = mii->rw(mii, 0, phyno, Bmsr, 0);
 193        if (!(bmsr & BmsrLs)) {
 194                phy->link = 0;
 195                return -1;
 196        }
 197
 198        phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
 199        if (phy->mscr) {
 200                r = mii->rw(mii, 0, phyno, Mssr, 0);
 201                if ((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)) {
 202                        phy->speed = 1000;
 203                        phy->fd = 1;
 204                } else if ((phy->mscr & Mscr1000THD) && (r & Mssr1000THD))
 205                        phy->speed = 1000;
 206        }
 207
 208        anlpar = mii->rw(mii, 0, phyno, Anlpar, 0);
 209        if (phy->speed == 0) {
 210                r = phy->anar & anlpar;
 211                if (r & AnaTXFD) {
 212                        phy->speed = 100;
 213                        phy->fd = 1;
 214                } else if (r & AnaTXHD)
 215                        phy->speed = 100;
 216                else if (r & Ana10FD) {
 217                        phy->speed = 10;
 218                        phy->fd = 1;
 219                } else if (r & Ana10HD)
 220                        phy->speed = 10;
 221        }
 222        if (phy->speed == 0)
 223                return -1;
 224
 225        if (phy->fd) {
 226                p = phy->fc;
 227                r = anlpar & (AnaAP | AnaP);
 228                if (p == AnaAP && r == (AnaAP | AnaP))
 229                        phy->tfc = 1;
 230                else if (p == (AnaAP | AnaP) && r == AnaAP)
 231                        phy->rfc = 1;
 232                else if ((p & AnaP) && (r & AnaP))
 233                        phy->rfc = phy->tfc = 1;
 234        }
 235
 236        phy->link = 1;
 237
 238        return 0;
 239}
 240
 241char *miidumpphy(struct mii *mii, char *p, char *e)
 242{
 243        int i, r;
 244
 245        if (mii == NULL || mii->curphy == NULL)
 246                return p;
 247
 248        p = seprintf(p, e, "phy:   ");
 249        for (i = 0; i < NMiiPhyr; i++) {
 250                if (i && ((i & 0x07) == 0))
 251                        p = seprintf(p, e, "\n       ");
 252                r = mii->rw(mii, 0, mii->curphy->phyno, i, 0);
 253                p = seprintf(p, e, " %4.4ux", r);
 254        }
 255        p = seprintf(p, e, "\n");
 256
 257        return p;
 258}
 259
 260void miidetach(struct mii *mii)
 261{
 262        int i;
 263
 264        for (i = 0; i < NMiiPhy; i++) {
 265                if (mii->phy[i] == NULL)
 266                        continue;
 267                kfree(mii);
 268                mii->phy[i] = NULL;
 269        }
 270        kfree(mii);
 271}
 272
 273struct mii *miiattach(void *ctlr, int mask,
 274                      int (*rw)(struct mii *, int unused_int, int, int, int))
 275{
 276        struct mii *mii;
 277
 278        if ((mii = kzmalloc(sizeof(struct mii), 0)) == NULL)
 279                return NULL;
 280        mii->ctlr = ctlr;
 281        mii->rw = rw;
 282
 283        if (miiprobe(mii, mask) == 0) {
 284                kfree(mii);
 285                mii = NULL;
 286        }
 287
 288        return mii;
 289}
 290