qemu/hw/etraxfs_eth.c
<<
>>
Prefs
   1/*
   2 * QEMU ETRAX Ethernet Controller.
   3 *
   4 * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include <stdio.h>
  26#include "hw.h"
  27#include "net.h"
  28#include "etraxfs.h"
  29
  30#define D(x)
  31
  32/* Advertisement control register. */
  33#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
  34#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
  35#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
  36#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
  37
  38/* 
  39 * The MDIO extensions in the TDK PHY model were reversed engineered from the 
  40 * linux driver (PHYID and Diagnostics reg).
  41 * TODO: Add friendly names for the register nums.
  42 */
  43struct qemu_phy
  44{
  45        uint32_t regs[32];
  46
  47        int link;
  48
  49        unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
  50        void (*write)(struct qemu_phy *phy, unsigned int req, 
  51                      unsigned int data);
  52};
  53
  54static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
  55{
  56        int regnum;
  57        unsigned r = 0;
  58
  59        regnum = req & 0x1f;
  60
  61        switch (regnum) {
  62                case 1:
  63                        if (!phy->link)
  64                                break;
  65                        /* MR1.  */
  66                        /* Speeds and modes.  */
  67                        r |= (1 << 13) | (1 << 14);
  68                        r |= (1 << 11) | (1 << 12);
  69                        r |= (1 << 5); /* Autoneg complete.  */
  70                        r |= (1 << 3); /* Autoneg able.  */
  71                        r |= (1 << 2); /* link.  */
  72                        break;
  73                case 5:
  74                        /* Link partner ability.
  75                           We are kind; always agree with whatever best mode
  76                           the guest advertises.  */
  77                        r = 1 << 14; /* Success.  */
  78                        /* Copy advertised modes.  */
  79                        r |= phy->regs[4] & (15 << 5);
  80                        /* Autoneg support.  */
  81                        r |= 1;
  82                        break;
  83                case 18:
  84                {
  85                        /* Diagnostics reg.  */
  86                        int duplex = 0;
  87                        int speed_100 = 0;
  88
  89                        if (!phy->link)
  90                                break;
  91
  92                        /* Are we advertising 100 half or 100 duplex ? */
  93                        speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
  94                        speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
  95
  96                        /* Are we advertising 10 duplex or 100 duplex ? */
  97                        duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
  98                        duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
  99                        r = (speed_100 << 10) | (duplex << 11);
 100                }
 101                break;
 102
 103                default:
 104                        r = phy->regs[regnum];
 105                        break;
 106        }
 107        D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
 108        return r;
 109}
 110
 111static void 
 112tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
 113{
 114        int regnum;
 115
 116        regnum = req & 0x1f;
 117        D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
 118        switch (regnum) {
 119                default:
 120                        phy->regs[regnum] = data;
 121                        break;
 122        }
 123}
 124
 125static void 
 126tdk_init(struct qemu_phy *phy)
 127{
 128        phy->regs[0] = 0x3100;
 129        /* PHY Id.  */
 130        phy->regs[2] = 0x0300;
 131        phy->regs[3] = 0xe400;
 132        /* Autonegotiation advertisement reg.  */
 133        phy->regs[4] = 0x01E1;
 134        phy->link = 1;
 135
 136        phy->read = tdk_read;
 137        phy->write = tdk_write;
 138}
 139
 140struct qemu_mdio
 141{
 142        /* bus.  */
 143        int mdc;
 144        int mdio;
 145
 146        /* decoder.  */
 147        enum {
 148                PREAMBLE,
 149                SOF,
 150                OPC,
 151                ADDR,
 152                REQ,
 153                TURNAROUND,
 154                DATA
 155        } state;
 156        unsigned int drive;
 157
 158        unsigned int cnt;
 159        unsigned int addr;
 160        unsigned int opc;
 161        unsigned int req;
 162        unsigned int data;
 163
 164        struct qemu_phy *devs[32];
 165};
 166
 167static void 
 168mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
 169{
 170        bus->devs[addr & 0x1f] = phy;
 171}
 172
 173#ifdef USE_THIS_DEAD_CODE
 174static void 
 175mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
 176{
 177        bus->devs[addr & 0x1f] = NULL;  
 178}
 179#endif
 180
 181static void mdio_read_req(struct qemu_mdio *bus)
 182{
 183        struct qemu_phy *phy;
 184
 185        phy = bus->devs[bus->addr];
 186        if (phy && phy->read)
 187                bus->data = phy->read(phy, bus->req);
 188        else 
 189                bus->data = 0xffff;
 190}
 191
 192static void mdio_write_req(struct qemu_mdio *bus)
 193{
 194        struct qemu_phy *phy;
 195
 196        phy = bus->devs[bus->addr];
 197        if (phy && phy->write)
 198                phy->write(phy, bus->req, bus->data);
 199}
 200
 201static void mdio_cycle(struct qemu_mdio *bus)
 202{
 203        bus->cnt++;
 204
 205        D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
 206                bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
 207#if 0
 208        if (bus->mdc)
 209                printf("%d", bus->mdio);
 210#endif
 211        switch (bus->state)
 212        {
 213                case PREAMBLE:
 214                        if (bus->mdc) {
 215                                if (bus->cnt >= (32 * 2) && !bus->mdio) {
 216                                        bus->cnt = 0;
 217                                        bus->state = SOF;
 218                                        bus->data = 0;
 219                                }
 220                        }
 221                        break;
 222                case SOF:
 223                        if (bus->mdc) {
 224                                if (bus->mdio != 1)
 225                                        printf("WARNING: no SOF\n");
 226                                if (bus->cnt == 1*2) {
 227                                        bus->cnt = 0;
 228                                        bus->opc = 0;
 229                                        bus->state = OPC;
 230                                }
 231                        }
 232                        break;
 233                case OPC:
 234                        if (bus->mdc) {
 235                                bus->opc <<= 1;
 236                                bus->opc |= bus->mdio & 1;
 237                                if (bus->cnt == 2*2) {
 238                                        bus->cnt = 0;
 239                                        bus->addr = 0;
 240                                        bus->state = ADDR;
 241                                }
 242                        }
 243                        break;
 244                case ADDR:
 245                        if (bus->mdc) {
 246                                bus->addr <<= 1;
 247                                bus->addr |= bus->mdio & 1;
 248
 249                                if (bus->cnt == 5*2) {
 250                                        bus->cnt = 0;
 251                                        bus->req = 0;
 252                                        bus->state = REQ;
 253                                }
 254                        }
 255                        break;
 256                case REQ:
 257                        if (bus->mdc) {
 258                                bus->req <<= 1;
 259                                bus->req |= bus->mdio & 1;
 260                                if (bus->cnt == 5*2) {
 261                                        bus->cnt = 0;
 262                                        bus->state = TURNAROUND;
 263                                }
 264                        }
 265                        break;
 266                case TURNAROUND:
 267                        if (bus->mdc && bus->cnt == 2*2) {
 268                                bus->mdio = 0;
 269                                bus->cnt = 0;
 270
 271                                if (bus->opc == 2) {
 272                                        bus->drive = 1;
 273                                        mdio_read_req(bus);
 274                                        bus->mdio = bus->data & 1;
 275                                }
 276                                bus->state = DATA;
 277                        }
 278                        break;
 279                case DATA:                      
 280                        if (!bus->mdc) {
 281                                if (bus->drive) {
 282                                        bus->mdio = !!(bus->data & (1 << 15));
 283                                        bus->data <<= 1;
 284                                }
 285                        } else {
 286                                if (!bus->drive) {
 287                                        bus->data <<= 1;
 288                                        bus->data |= bus->mdio;
 289                                }
 290                                if (bus->cnt == 16 * 2) {
 291                                        bus->cnt = 0;
 292                                        bus->state = PREAMBLE;
 293                                        if (!bus->drive)
 294                                                mdio_write_req(bus);
 295                                        bus->drive = 0;
 296                                }
 297                        }
 298                        break;
 299                default:
 300                        break;
 301        }
 302}
 303
 304/* ETRAX-FS Ethernet MAC block starts here.  */
 305
 306#define RW_MA0_LO         0x00
 307#define RW_MA0_HI         0x01
 308#define RW_MA1_LO         0x02
 309#define RW_MA1_HI         0x03
 310#define RW_GA_LO          0x04
 311#define RW_GA_HI          0x05
 312#define RW_GEN_CTRL       0x06
 313#define RW_REC_CTRL       0x07
 314#define RW_TR_CTRL        0x08
 315#define RW_CLR_ERR        0x09
 316#define RW_MGM_CTRL       0x0a
 317#define R_STAT            0x0b
 318#define FS_ETH_MAX_REGS   0x17
 319
 320struct fs_eth
 321{
 322        NICState *nic;
 323        NICConf conf;
 324        int ethregs;
 325
 326        /* Two addrs in the filter.  */
 327        uint8_t macaddr[2][6];
 328        uint32_t regs[FS_ETH_MAX_REGS];
 329
 330        struct etraxfs_dma_client *dma_out;
 331        struct etraxfs_dma_client *dma_in;
 332
 333        /* MDIO bus.  */
 334        struct qemu_mdio mdio_bus;
 335        unsigned int phyaddr;
 336        int duplex_mismatch;
 337
 338        /* PHY.  */
 339        struct qemu_phy phy;
 340};
 341
 342static void eth_validate_duplex(struct fs_eth *eth)
 343{
 344        struct qemu_phy *phy;
 345        unsigned int phy_duplex;
 346        unsigned int mac_duplex;
 347        int new_mm = 0;
 348
 349        phy = eth->mdio_bus.devs[eth->phyaddr];
 350        phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
 351        mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
 352
 353        if (mac_duplex != phy_duplex)
 354                new_mm = 1;
 355
 356        if (eth->regs[RW_GEN_CTRL] & 1) {
 357                if (new_mm != eth->duplex_mismatch) {
 358                        if (new_mm)
 359                                printf("HW: WARNING "
 360                                       "ETH duplex mismatch MAC=%d PHY=%d\n",
 361                                       mac_duplex, phy_duplex);
 362                        else
 363                                printf("HW: ETH duplex ok.\n");
 364                }
 365                eth->duplex_mismatch = new_mm;
 366        }
 367}
 368
 369static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
 370{
 371        struct fs_eth *eth = opaque;
 372        uint32_t r = 0;
 373
 374        addr >>= 2;
 375
 376        switch (addr) {
 377                case R_STAT:
 378                        r = eth->mdio_bus.mdio & 1;
 379                        break;
 380        default:
 381                r = eth->regs[addr];
 382                D(printf ("%s %x\n", __func__, addr * 4));
 383                break;
 384        }
 385        return r;
 386}
 387
 388static void eth_update_ma(struct fs_eth *eth, int ma)
 389{
 390        int reg;
 391        int i = 0;
 392
 393        ma &= 1;
 394
 395        reg = RW_MA0_LO;
 396        if (ma)
 397                reg = RW_MA1_LO;
 398
 399        eth->macaddr[ma][i++] = eth->regs[reg];
 400        eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
 401        eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
 402        eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
 403        eth->macaddr[ma][i++] = eth->regs[reg + 1];
 404        eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8;
 405
 406        D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
 407                 eth->macaddr[ma][0], eth->macaddr[ma][1],
 408                 eth->macaddr[ma][2], eth->macaddr[ma][3],
 409                 eth->macaddr[ma][4], eth->macaddr[ma][5]));
 410}
 411
 412static void
 413eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
 414{
 415        struct fs_eth *eth = opaque;
 416
 417        addr >>= 2;
 418        switch (addr)
 419        {
 420                case RW_MA0_LO:
 421                case RW_MA0_HI:
 422                        eth->regs[addr] = value;
 423                        eth_update_ma(eth, 0);
 424                        break;
 425                case RW_MA1_LO:
 426                case RW_MA1_HI:
 427                        eth->regs[addr] = value;
 428                        eth_update_ma(eth, 1);
 429                        break;
 430
 431                case RW_MGM_CTRL:
 432                        /* Attach an MDIO/PHY abstraction.  */
 433                        if (value & 2)
 434                                eth->mdio_bus.mdio = value & 1;
 435                        if (eth->mdio_bus.mdc != (value & 4)) {
 436                                mdio_cycle(&eth->mdio_bus);
 437                                eth_validate_duplex(eth);
 438                        }
 439                        eth->mdio_bus.mdc = !!(value & 4);
 440                        eth->regs[addr] = value;
 441                        break;
 442
 443                case RW_REC_CTRL:
 444                        eth->regs[addr] = value;
 445                        eth_validate_duplex(eth);
 446                        break;
 447
 448                default:
 449                        eth->regs[addr] = value;
 450                        D(printf ("%s %x %x\n",
 451                                  __func__, addr, value));
 452                        break;
 453        }
 454}
 455
 456/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
 457   filter dropping group addresses we have not joined.  The filter has 64
 458   bits (m). The has function is a simple nible xor of the group addr.  */
 459static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
 460{
 461        unsigned int hsh;
 462        int m_individual = eth->regs[RW_REC_CTRL] & 4;
 463        int match;
 464
 465        /* First bit on the wire of a MAC address signals multicast or
 466           physical address.  */
 467        if (!m_individual && !sa[0] & 1)
 468                return 0;
 469
 470        /* Calculate the hash index for the GA registers. */
 471        hsh = 0;
 472        hsh ^= (*sa) & 0x3f;
 473        hsh ^= ((*sa) >> 6) & 0x03;
 474        ++sa;
 475        hsh ^= ((*sa) << 2) & 0x03c;
 476        hsh ^= ((*sa) >> 4) & 0xf;
 477        ++sa;
 478        hsh ^= ((*sa) << 4) & 0x30;
 479        hsh ^= ((*sa) >> 2) & 0x3f;
 480        ++sa;
 481        hsh ^= (*sa) & 0x3f;
 482        hsh ^= ((*sa) >> 6) & 0x03;
 483        ++sa;
 484        hsh ^= ((*sa) << 2) & 0x03c;
 485        hsh ^= ((*sa) >> 4) & 0xf;
 486        ++sa;
 487        hsh ^= ((*sa) << 4) & 0x30;
 488        hsh ^= ((*sa) >> 2) & 0x3f;
 489
 490        hsh &= 63;
 491        if (hsh > 31)
 492                match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
 493        else
 494                match = eth->regs[RW_GA_LO] & (1 << hsh);
 495        D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
 496                 eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
 497        return match;
 498}
 499
 500static int eth_can_receive(VLANClientState *nc)
 501{
 502        return 1;
 503}
 504
 505static ssize_t eth_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
 506{
 507        unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 508        struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
 509        int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
 510        int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
 511        int r_bcast = eth->regs[RW_REC_CTRL] & 8;
 512
 513        if (size < 12)
 514                return -1;
 515
 516        D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
 517                 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
 518                 use_ma0, use_ma1, r_bcast));
 519               
 520        /* Does the frame get through the address filters?  */
 521        if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
 522            && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
 523            && (!r_bcast || memcmp(buf, sa_bcast, 6))
 524            && !eth_match_groupaddr(eth, buf))
 525                return size;
 526
 527        /* FIXME: Find another way to pass on the fake csum.  */
 528        etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
 529
 530        return size;
 531}
 532
 533static int eth_tx_push(void *opaque, unsigned char *buf, int len)
 534{
 535        struct fs_eth *eth = opaque;
 536
 537        D(printf("%s buf=%p len=%d\n", __func__, buf, len));
 538        qemu_send_packet(&eth->nic->nc, buf, len);
 539        return len;
 540}
 541
 542static void eth_set_link(VLANClientState *nc)
 543{
 544        struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
 545        D(printf("%s %d\n", __func__, nc->link_down));
 546        eth->phy.link = !nc->link_down;
 547}
 548
 549static CPUReadMemoryFunc * const eth_read[] = {
 550        NULL, NULL,
 551        &eth_readl,
 552};
 553
 554static CPUWriteMemoryFunc * const eth_write[] = {
 555        NULL, NULL,
 556        &eth_writel,
 557};
 558
 559static void eth_cleanup(VLANClientState *nc)
 560{
 561        struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
 562
 563        cpu_unregister_io_memory(eth->ethregs);
 564
 565        qemu_free(eth->dma_out);
 566        qemu_free(eth);
 567}
 568
 569static NetClientInfo net_etraxfs_info = {
 570        .type = NET_CLIENT_TYPE_NIC,
 571        .size = sizeof(NICState),
 572        .can_receive = eth_can_receive,
 573        .receive = eth_receive,
 574        .cleanup = eth_cleanup,
 575        .link_status_changed = eth_set_link,
 576};
 577
 578void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr)
 579{
 580        struct etraxfs_dma_client *dma = NULL;  
 581        struct fs_eth *eth = NULL;
 582
 583        qemu_check_nic_model(nd, "fseth");
 584
 585        dma = qemu_mallocz(sizeof *dma * 2);
 586        eth = qemu_mallocz(sizeof *eth);
 587
 588        dma[0].client.push = eth_tx_push;
 589        dma[0].client.opaque = eth;
 590        dma[1].client.opaque = eth;
 591        dma[1].client.pull = NULL;
 592
 593        eth->dma_out = dma;
 594        eth->dma_in = dma + 1;
 595
 596        /* Connect the phy.  */
 597        eth->phyaddr = phyaddr & 0x1f;
 598        tdk_init(&eth->phy);
 599        mdio_attach(&eth->mdio_bus, &eth->phy, eth->phyaddr);
 600
 601        eth->ethregs = cpu_register_io_memory(eth_read, eth_write, eth);
 602        cpu_register_physical_memory (base, 0x5c, eth->ethregs);
 603
 604        memcpy(eth->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
 605        eth->conf.vlan = nd->vlan;
 606        eth->conf.peer = nd->netdev;
 607
 608        eth->nic = qemu_new_nic(&net_etraxfs_info, &eth->conf,
 609                                nd->model, nd->name, eth);
 610
 611        return dma;
 612}
 613