i8254xGBe.cc revision 4218
17949SAli.Saidi@ARM.com/*
27949SAli.Saidi@ARM.com * Copyright (c) 2006 The Regents of The University of Michigan
37949SAli.Saidi@ARM.com * All rights reserved.
47949SAli.Saidi@ARM.com *
57949SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without
67949SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are
77949SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright
87949SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer;
97949SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright
107949SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the
117949SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution;
127949SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its
137949SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from
147949SAli.Saidi@ARM.com * this software without specific prior written permission.
157949SAli.Saidi@ARM.com *
167949SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177949SAli.Saidi@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187949SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197949SAli.Saidi@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207949SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217949SAli.Saidi@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227949SAli.Saidi@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237949SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247949SAli.Saidi@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257949SAli.Saidi@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267949SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277949SAli.Saidi@ARM.com *
287949SAli.Saidi@ARM.com * Authors: Ali Saidi
297949SAli.Saidi@ARM.com */
307949SAli.Saidi@ARM.com
317949SAli.Saidi@ARM.com/* @file
327949SAli.Saidi@ARM.com * Device model for Intel's 8254x line of gigabit ethernet controllers.
337949SAli.Saidi@ARM.com * In particular an 82547 revision 2 (82547GI) MAC because it seems to have the
347949SAli.Saidi@ARM.com * fewest workarounds in the driver. It will probably work with most of the
357949SAli.Saidi@ARM.com * other MACs with slight modifications.
367949SAli.Saidi@ARM.com */
377949SAli.Saidi@ARM.com
387949SAli.Saidi@ARM.com#include "base/inet.hh"
397949SAli.Saidi@ARM.com#include "dev/i8254xGBe.hh"
407949SAli.Saidi@ARM.com#include "mem/packet.hh"
417949SAli.Saidi@ARM.com#include "mem/packet_access.hh"
427949SAli.Saidi@ARM.com#include "sim/builder.hh"
437949SAli.Saidi@ARM.com#include "sim/stats.hh"
447949SAli.Saidi@ARM.com#include "sim/system.hh"
459330Schander.sudanthi@arm.com
469330Schander.sudanthi@arm.comusing namespace iGbReg;
477949SAli.Saidi@ARM.com
487949SAli.Saidi@ARM.comIGbE::IGbE(Params *p)
497949SAli.Saidi@ARM.com    : PciDev(p), etherInt(NULL), useFlowControl(p->use_flow_control)
508229Snate@binkert.org{
519330Schander.sudanthi@arm.com    // Initialized internal registers per Intel documentation
528635Schris.emmons@arm.com    regs.tctl(0);
537949SAli.Saidi@ARM.com    regs.rctl(0);
547949SAli.Saidi@ARM.com    regs.ctrl(0);
557949SAli.Saidi@ARM.com    regs.ctrl.fd(1);
567949SAli.Saidi@ARM.com    regs.ctrl.lrst(1);
578229Snate@binkert.org    regs.ctrl.speed(2);
587949SAli.Saidi@ARM.com    regs.ctrl.frcspd(1);
597949SAli.Saidi@ARM.com    regs.sts(0);
609330Schander.sudanthi@arm.com    regs.sts.speed(3); // Say we're 1000Mbps
619330Schander.sudanthi@arm.com    regs.sts.fd(1); // full duplex
629330Schander.sudanthi@arm.com    regs.eecd(0);
638635Schris.emmons@arm.com    regs.eecd.fwe(1);
649330Schander.sudanthi@arm.com    regs.eecd.ee_type(1);
657949SAli.Saidi@ARM.com    regs.eerd(0);
667949SAli.Saidi@ARM.com    regs.icr(0);
677949SAli.Saidi@ARM.com    regs.rctl(0);
687949SAli.Saidi@ARM.com    regs.tctl(0);
697949SAli.Saidi@ARM.com    regs.fcrtl(0);
707949SAli.Saidi@ARM.com    regs.fcrth(1);
717949SAli.Saidi@ARM.com    regs.manc(0);
727949SAli.Saidi@ARM.com
737949SAli.Saidi@ARM.com    regs.pba.rxa(0x30);
747949SAli.Saidi@ARM.com    regs.pba.txa(0x10);
757949SAli.Saidi@ARM.com
767949SAli.Saidi@ARM.com    eeOpBits            = 0;
777949SAli.Saidi@ARM.com    eeAddrBits          = 0;
787949SAli.Saidi@ARM.com    eeDataBits          = 0;
797949SAli.Saidi@ARM.com    eeOpcode            = 0;
807949SAli.Saidi@ARM.com
817949SAli.Saidi@ARM.com    // clear all 64 16 bit words of the eeprom
827949SAli.Saidi@ARM.com    memset(&flash, 0, EEPROM_SIZE*2);
837949SAli.Saidi@ARM.com
847949SAli.Saidi@ARM.com    //We'll need to instert the MAC address into the flash
857949SAli.Saidi@ARM.com    flash[0] = 0xA4A4;
867949SAli.Saidi@ARM.com    flash[1] = 0xB6B6;
877949SAli.Saidi@ARM.com    flash[2] = 0xC8C8;
887949SAli.Saidi@ARM.com
897949SAli.Saidi@ARM.com    uint16_t csum = 0;
907949SAli.Saidi@ARM.com    for (int x = 0; x < EEPROM_SIZE; x++)
917949SAli.Saidi@ARM.com        csum += flash[x];
927949SAli.Saidi@ARM.com
937949SAli.Saidi@ARM.com    // Magic happy checksum value
947949SAli.Saidi@ARM.com    flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
957949SAli.Saidi@ARM.com}
967949SAli.Saidi@ARM.com
977949SAli.Saidi@ARM.com
987949SAli.Saidi@ARM.comTick
997949SAli.Saidi@ARM.comIGbE::writeConfig(PacketPtr pkt)
1007949SAli.Saidi@ARM.com{
1017949SAli.Saidi@ARM.com    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1027949SAli.Saidi@ARM.com    if (offset < PCI_DEVICE_SPECIFIC)
1037949SAli.Saidi@ARM.com        PciDev::writeConfig(pkt);
1047949SAli.Saidi@ARM.com    else
1057949SAli.Saidi@ARM.com        panic("Device specific PCI config space not implemented.\n");
1067949SAli.Saidi@ARM.com
1077949SAli.Saidi@ARM.com    ///
1087949SAli.Saidi@ARM.com    /// Some work may need to be done here based for the pci COMMAND bits.
1097949SAli.Saidi@ARM.com    ///
1107949SAli.Saidi@ARM.com
1117949SAli.Saidi@ARM.com    return pioDelay;
1127949SAli.Saidi@ARM.com}
1137949SAli.Saidi@ARM.com
1147949SAli.Saidi@ARM.comTick
1157949SAli.Saidi@ARM.comIGbE::read(PacketPtr pkt)
1167949SAli.Saidi@ARM.com{
1177949SAli.Saidi@ARM.com    int bar;
1187949SAli.Saidi@ARM.com    Addr daddr;
1197949SAli.Saidi@ARM.com
1207949SAli.Saidi@ARM.com    if (!getBAR(pkt->getAddr(), bar, daddr))
1217949SAli.Saidi@ARM.com        panic("Invalid PCI memory access to unmapped memory.\n");
1227949SAli.Saidi@ARM.com
1237949SAli.Saidi@ARM.com    // Only Memory register BAR is allowed
1247949SAli.Saidi@ARM.com    assert(bar == 0);
1257949SAli.Saidi@ARM.com
1267949SAli.Saidi@ARM.com    // Only 32bit accesses allowed
1277949SAli.Saidi@ARM.com    assert(pkt->getSize() == 4);
1287949SAli.Saidi@ARM.com
1297949SAli.Saidi@ARM.com    //DPRINTF(Ethernet, "Read device register %#X\n", daddr);
1307949SAli.Saidi@ARM.com
1317949SAli.Saidi@ARM.com    pkt->allocate();
1327949SAli.Saidi@ARM.com
1337949SAli.Saidi@ARM.com    ///
1347949SAli.Saidi@ARM.com    /// Handle read of register here
1357949SAli.Saidi@ARM.com    ///
1367949SAli.Saidi@ARM.com
1377949SAli.Saidi@ARM.com
1387949SAli.Saidi@ARM.com    switch (daddr) {
1397949SAli.Saidi@ARM.com      case REG_CTRL:
1407949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.ctrl());
1417949SAli.Saidi@ARM.com        break;
1427949SAli.Saidi@ARM.com      case REG_STATUS:
1437949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.sts());
1447949SAli.Saidi@ARM.com        break;
1457949SAli.Saidi@ARM.com      case REG_EECD:
1467949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.eecd());
1477949SAli.Saidi@ARM.com        break;
1487949SAli.Saidi@ARM.com      case REG_EERD:
1497949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.eerd());
1507949SAli.Saidi@ARM.com        break;
1517949SAli.Saidi@ARM.com      case REG_CTRL_EXT:
1527949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.ctrl_ext());
1537949SAli.Saidi@ARM.com        break;
1547949SAli.Saidi@ARM.com      case REG_MDIC:
1557949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.mdic());
1567949SAli.Saidi@ARM.com        break;
1577949SAli.Saidi@ARM.com      case REG_ICR:
1587949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.icr());
1597949SAli.Saidi@ARM.com        // handle auto setting mask from IAM
1607949SAli.Saidi@ARM.com        break;
1617949SAli.Saidi@ARM.com      case REG_ITR:
1627949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.itr());
1637949SAli.Saidi@ARM.com        break;
1647949SAli.Saidi@ARM.com      case REG_RCTL:
1657949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.rctl());
1667949SAli.Saidi@ARM.com        break;
1677949SAli.Saidi@ARM.com      case REG_FCTTV:
1687949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.fcttv());
1697949SAli.Saidi@ARM.com        break;
1707949SAli.Saidi@ARM.com      case REG_TCTL:
1717949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.tctl());
1727949SAli.Saidi@ARM.com        break;
1737949SAli.Saidi@ARM.com      case REG_PBA:
1747949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.pba());
1757949SAli.Saidi@ARM.com        break;
1767949SAli.Saidi@ARM.com      case REG_WUC:
1777949SAli.Saidi@ARM.com      case REG_LEDCTL:
1787949SAli.Saidi@ARM.com        pkt->set<uint32_t>(0); // We don't care, so just return 0
1797949SAli.Saidi@ARM.com        break;
1807949SAli.Saidi@ARM.com      case REG_FCRTL:
1817949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.fcrtl());
1827949SAli.Saidi@ARM.com        break;
1837949SAli.Saidi@ARM.com      case REG_FCRTH:
1847949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.fcrth());
1857949SAli.Saidi@ARM.com        break;
1867949SAli.Saidi@ARM.com      case REG_RDBAL:
1877949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.rdba.rdbal());
1887949SAli.Saidi@ARM.com        break;
1897949SAli.Saidi@ARM.com      case REG_RDBAH:
1907949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.rdba.rdbah());
1917949SAli.Saidi@ARM.com        break;
1927949SAli.Saidi@ARM.com      case REG_RDLEN:
1937949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.rdlen());
1947949SAli.Saidi@ARM.com        break;
1957949SAli.Saidi@ARM.com      case REG_RDH:
1967949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.rdh());
1977949SAli.Saidi@ARM.com        break;
1987949SAli.Saidi@ARM.com      case REG_RDT:
1997949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.rdt());
2007949SAli.Saidi@ARM.com        break;
2017949SAli.Saidi@ARM.com      case REG_RDTR:
2027949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.rdtr());
2037949SAli.Saidi@ARM.com        break;
2047949SAli.Saidi@ARM.com      case REG_RADV:
2057949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.radv());
2067949SAli.Saidi@ARM.com        break;
2077949SAli.Saidi@ARM.com      case REG_TDBAL:
2087949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.tdba.tdbal());
2097949SAli.Saidi@ARM.com        break;
2107949SAli.Saidi@ARM.com      case REG_TDBAH:
2117949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.tdba.tdbah());
2127949SAli.Saidi@ARM.com        break;
2137949SAli.Saidi@ARM.com      case REG_TDLEN:
2147949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.tdlen());
2157949SAli.Saidi@ARM.com        break;
2167949SAli.Saidi@ARM.com      case REG_TDH:
2177949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.tdh());
2187949SAli.Saidi@ARM.com        break;
2197949SAli.Saidi@ARM.com      case REG_TDT:
2207949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.tdt());
2217949SAli.Saidi@ARM.com        break;
2227949SAli.Saidi@ARM.com      case REG_TIDV:
2237949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.tidv());
2247949SAli.Saidi@ARM.com        break;
2257949SAli.Saidi@ARM.com      case REG_TXDCTL:
2267949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.txdctl());
2277949SAli.Saidi@ARM.com        break;
2287949SAli.Saidi@ARM.com      case REG_TADV:
2297949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.tadv());
2307949SAli.Saidi@ARM.com        break;
2317949SAli.Saidi@ARM.com      case REG_RXCSUM:
2327949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.rxcsum());
2337949SAli.Saidi@ARM.com        break;
2347949SAli.Saidi@ARM.com      case REG_MANC:
2357949SAli.Saidi@ARM.com        pkt->set<uint32_t>(regs.manc());
2367949SAli.Saidi@ARM.com        break;
2377949SAli.Saidi@ARM.com      default:
2387949SAli.Saidi@ARM.com        if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
2397949SAli.Saidi@ARM.com            !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
2407949SAli.Saidi@ARM.com            !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)) &&
2417949SAli.Saidi@ARM.com            !(daddr >= REG_CRCERRS && daddr < (REG_CRCERRS + STATS_REGS_SIZE)))
2427949SAli.Saidi@ARM.com            panic("Read request to unknown register number: %#x\n", daddr);
2437949SAli.Saidi@ARM.com        else
2447949SAli.Saidi@ARM.com            pkt->set<uint32_t>(0);
2457949SAli.Saidi@ARM.com    };
2467949SAli.Saidi@ARM.com
2477949SAli.Saidi@ARM.com    pkt->result = Packet::Success;
2487949SAli.Saidi@ARM.com    return pioDelay;
2497949SAli.Saidi@ARM.com}
2507949SAli.Saidi@ARM.com
2517949SAli.Saidi@ARM.comTick
2527949SAli.Saidi@ARM.comIGbE::write(PacketPtr pkt)
2537949SAli.Saidi@ARM.com{
2547949SAli.Saidi@ARM.com    int bar;
2557949SAli.Saidi@ARM.com    Addr daddr;
2567949SAli.Saidi@ARM.com
2577949SAli.Saidi@ARM.com
2587949SAli.Saidi@ARM.com    if (!getBAR(pkt->getAddr(), bar, daddr))
2597949SAli.Saidi@ARM.com        panic("Invalid PCI memory access to unmapped memory.\n");
2607949SAli.Saidi@ARM.com
2617949SAli.Saidi@ARM.com    // Only Memory register BAR is allowed
2627949SAli.Saidi@ARM.com    assert(bar == 0);
2637949SAli.Saidi@ARM.com
2647949SAli.Saidi@ARM.com    // Only 32bit accesses allowed
2657949SAli.Saidi@ARM.com    assert(pkt->getSize() == sizeof(uint32_t));
2667949SAli.Saidi@ARM.com
2677949SAli.Saidi@ARM.com    //DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>());
2687949SAli.Saidi@ARM.com
2697949SAli.Saidi@ARM.com    ///
2707949SAli.Saidi@ARM.com    /// Handle write of register here
2717949SAli.Saidi@ARM.com    ///
2727949SAli.Saidi@ARM.com    uint32_t val = pkt->get<uint32_t>();
2737949SAli.Saidi@ARM.com
2747949SAli.Saidi@ARM.com    switch (daddr) {
2757949SAli.Saidi@ARM.com      case REG_CTRL:
2767949SAli.Saidi@ARM.com        regs.ctrl = val;
2777949SAli.Saidi@ARM.com        if (regs.ctrl.tfce())
2787949SAli.Saidi@ARM.com            warn("TX Flow control enabled, should implement\n");
2797949SAli.Saidi@ARM.com        if (regs.ctrl.rfce())
2807949SAli.Saidi@ARM.com            warn("RX Flow control enabled, should implement\n");
2817949SAli.Saidi@ARM.com        break;
2827949SAli.Saidi@ARM.com      case REG_CTRL_EXT:
2837949SAli.Saidi@ARM.com        regs.ctrl_ext = val;
2847949SAli.Saidi@ARM.com        break;
2857949SAli.Saidi@ARM.com      case REG_STATUS:
2867949SAli.Saidi@ARM.com        regs.sts = val;
2877949SAli.Saidi@ARM.com        break;
2887949SAli.Saidi@ARM.com      case REG_EECD:
2897949SAli.Saidi@ARM.com        int oldClk;
2907949SAli.Saidi@ARM.com        oldClk = regs.eecd.sk();
2917949SAli.Saidi@ARM.com        regs.eecd = val;
2927949SAli.Saidi@ARM.com        // See if this is a eeprom access and emulate accordingly
2937949SAli.Saidi@ARM.com        if (!oldClk && regs.eecd.sk()) {
2947949SAli.Saidi@ARM.com            if (eeOpBits < 8) {
2957949SAli.Saidi@ARM.com                eeOpcode = eeOpcode << 1 | regs.eecd.din();
2967949SAli.Saidi@ARM.com                eeOpBits++;
2977949SAli.Saidi@ARM.com            } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
2987949SAli.Saidi@ARM.com                eeAddr = eeAddr << 1 | regs.eecd.din();
2997949SAli.Saidi@ARM.com                eeAddrBits++;
3007949SAli.Saidi@ARM.com            } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
3017949SAli.Saidi@ARM.com                assert(eeAddr>>1 < EEPROM_SIZE);
3027949SAli.Saidi@ARM.com                DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n",
3037949SAli.Saidi@ARM.com                        flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]);
3047949SAli.Saidi@ARM.com                regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1);
3057949SAli.Saidi@ARM.com                eeDataBits++;
3067949SAli.Saidi@ARM.com            } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) {
3077949SAli.Saidi@ARM.com                regs.eecd.dout(0);
3087949SAli.Saidi@ARM.com                eeDataBits++;
3097949SAli.Saidi@ARM.com            } else
3107949SAli.Saidi@ARM.com                panic("What's going on with eeprom interface? opcode:"
3117949SAli.Saidi@ARM.com                       " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode,
3127949SAli.Saidi@ARM.com                       (uint32_t)eeOpBits, (uint32_t)eeAddr,
3137949SAli.Saidi@ARM.com                       (uint32_t)eeAddrBits, (uint32_t)eeDataBits);
3147949SAli.Saidi@ARM.com
3157949SAli.Saidi@ARM.com            // Reset everything for the next command
3167949SAli.Saidi@ARM.com            if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) ||
3179330Schander.sudanthi@arm.com               (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) {
3187949SAli.Saidi@ARM.com                eeOpBits = 0;
3197949SAli.Saidi@ARM.com                eeAddrBits = 0;
3207949SAli.Saidi@ARM.com                eeDataBits = 0;
3217949SAli.Saidi@ARM.com               eeOpcode = 0;
3227949SAli.Saidi@ARM.com                eeAddr = 0;
3237949SAli.Saidi@ARM.com            }
3247949SAli.Saidi@ARM.com
3259330Schander.sudanthi@arm.com           DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n",
3269330Schander.sudanthi@arm.com                    (uint32_t)eeOpcode, (uint32_t) eeOpBits,
3277949SAli.Saidi@ARM.com                    (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits);
3287949SAli.Saidi@ARM.com           if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI ||
3297949SAli.Saidi@ARM.com                                   eeOpcode == EEPROM_RDSR_OPCODE_SPI ))
330                panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode,
331                        (uint32_t)eeOpBits);
332
333
334        }
335        // If driver requests eeprom access, immediately give it to it
336        regs.eecd.ee_gnt(regs.eecd.ee_req());
337        break;
338      case REG_EERD:
339        regs.eerd = val;
340        break;
341      case REG_MDIC:
342        regs.mdic = val;
343        if (regs.mdic.i())
344            panic("No support for interrupt on mdic complete\n");
345        if (regs.mdic.phyadd() != 1)
346            panic("No support for reading anything but phy\n");
347        DPRINTF(Ethernet, "%s phy address %x\n", regs.mdic.op() == 1 ? "Writing"
348                : "Reading", regs.mdic.regadd());
349        switch (regs.mdic.regadd()) {
350            case PHY_PSTATUS:
351                regs.mdic.data(0x796D); // link up
352                break;
353            case PHY_PID:
354                regs.mdic.data(0x02A8);
355                break;
356            case PHY_EPID:
357                regs.mdic.data(0x0380);
358                break;
359            case PHY_GSTATUS:
360                regs.mdic.data(0x7C00);
361                break;
362            case PHY_EPSTATUS:
363                regs.mdic.data(0x3000);
364                break;
365            case PHY_AGC:
366                regs.mdic.data(0x180); // some random length
367                break;
368            default:
369                regs.mdic.data(0);
370                warn("Accessing unknown phy register %d\n", regs.mdic.regadd());
371        }
372        regs.mdic.r(1);
373        break;
374      case REG_ICR:
375        regs.icr = val;
376        // handle auto setting mask from IAM
377        break;
378      case REG_ITR:
379        regs.itr = val;
380        break;
381      case REG_ICS:
382        regs.icr = val | regs.icr();
383        // generate an interrupt if needed here
384        break;
385       case REG_IMS:
386        regs.imr |= val;
387        // handle interrupts if needed here
388        break;
389      case REG_IMC:
390        regs.imr |= ~val;
391        // handle interrupts if needed here
392        break;
393      case REG_IAM:
394        regs.iam = val;
395        break;
396      case REG_RCTL:
397        regs.rctl = val;
398        break;
399      case REG_FCTTV:
400        regs.fcttv = val;
401        break;
402      case REG_TCTL:
403        regs.tctl = val;
404        break;
405      case REG_PBA:
406        regs.pba.rxa(val);
407        regs.pba.txa(64 - regs.pba.rxa());
408        break;
409      case REG_WUC:
410      case REG_LEDCTL:
411      case REG_FCAL:
412      case REG_FCAH:
413      case REG_FCT:
414      case REG_VET:
415      case REG_AIFS:
416      case REG_TIPG:
417        ; // We don't care, so don't store anything
418        break;
419      case REG_FCRTL:
420        regs.fcrtl = val;
421        break;
422      case REG_FCRTH:
423        regs.fcrth = val;
424        break;
425      case REG_RDBAL:
426        regs.rdba.rdbal( val & ~mask(4));
427        break;
428      case REG_RDBAH:
429        regs.rdba.rdbah(val);
430        break;
431      case REG_RDLEN:
432        regs.rdlen = val & ~mask(7);
433        break;
434      case REG_RDH:
435        regs.rdh = val;
436        break;
437      case REG_RDT:
438        regs.rdt = val;
439        break;
440      case REG_RDTR:
441        regs.rdtr = val;
442        break;
443      case REG_RADV:
444        regs.radv = val;
445        break;
446      case REG_TDBAL:
447        regs.tdba.tdbal( val & ~mask(4));
448        break;
449      case REG_TDBAH:
450        regs.tdba.tdbah(val);
451        break;
452      case REG_TDLEN:
453        regs.tdlen = val & ~mask(7);
454        break;
455      case REG_TDH:
456        regs.tdh = val;
457        break;
458      case REG_TDT:
459        regs.tdt = val;
460        break;
461      case REG_TIDV:
462        regs.tidv = val;
463        break;
464      case REG_TXDCTL:
465        regs.txdctl = val;
466        break;
467      case REG_TADV:
468        regs.tadv = val;
469        break;
470      case REG_RXCSUM:
471        regs.rxcsum = val;
472        break;
473      case REG_MANC:
474        regs.manc = val;
475        break;
476      default:
477       if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
478           !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
479           !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)))
480           panic("Write request to unknown register number: %#x\n", daddr);
481    };
482
483    pkt->result = Packet::Success;
484    return pioDelay;
485}
486
487
488bool
489IGbE::ethRxPkt(EthPacketPtr packet)
490{
491    panic("Need to implemenet\n");
492}
493
494
495void
496IGbE::ethTxDone()
497{
498    panic("Need to implemenet\n");
499}
500
501void
502IGbE::serialize(std::ostream &os)
503{
504    panic("Need to implemenet\n");
505}
506
507void
508IGbE::unserialize(Checkpoint *cp, const std::string &section)
509{
510    panic("Need to implemenet\n");
511}
512
513
514BEGIN_DECLARE_SIM_OBJECT_PARAMS(IGbEInt)
515
516    SimObjectParam<EtherInt *> peer;
517    SimObjectParam<IGbE *> device;
518
519END_DECLARE_SIM_OBJECT_PARAMS(IGbEInt)
520
521BEGIN_INIT_SIM_OBJECT_PARAMS(IGbEInt)
522
523    INIT_PARAM_DFLT(peer, "peer interface", NULL),
524    INIT_PARAM(device, "Ethernet device of this interface")
525
526END_INIT_SIM_OBJECT_PARAMS(IGbEInt)
527
528CREATE_SIM_OBJECT(IGbEInt)
529{
530    IGbEInt *dev_int = new IGbEInt(getInstanceName(), device);
531
532    EtherInt *p = (EtherInt *)peer;
533    if (p) {
534        dev_int->setPeer(p);
535        p->setPeer(dev_int);
536    }
537
538    return dev_int;
539}
540
541REGISTER_SIM_OBJECT("IGbEInt", IGbEInt)
542
543
544BEGIN_DECLARE_SIM_OBJECT_PARAMS(IGbE)
545
546    SimObjectParam<System *> system;
547    SimObjectParam<Platform *> platform;
548    SimObjectParam<PciConfigData *> configdata;
549    Param<uint32_t> pci_bus;
550    Param<uint32_t> pci_dev;
551    Param<uint32_t> pci_func;
552    Param<Tick> pio_latency;
553    Param<Tick> config_latency;
554
555END_DECLARE_SIM_OBJECT_PARAMS(IGbE)
556
557BEGIN_INIT_SIM_OBJECT_PARAMS(IGbE)
558
559    INIT_PARAM(system, "System pointer"),
560    INIT_PARAM(platform, "Platform pointer"),
561    INIT_PARAM(configdata, "PCI Config data"),
562    INIT_PARAM(pci_bus, "PCI bus ID"),
563    INIT_PARAM(pci_dev, "PCI device number"),
564    INIT_PARAM(pci_func, "PCI function code"),
565    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
566    INIT_PARAM(config_latency, "Number of cycles for a config read or write")
567
568END_INIT_SIM_OBJECT_PARAMS(IGbE)
569
570
571CREATE_SIM_OBJECT(IGbE)
572{
573    IGbE::Params *params = new IGbE::Params;
574
575    params->name = getInstanceName();
576    params->platform = platform;
577    params->system = system;
578    params->configData = configdata;
579    params->busNum = pci_bus;
580    params->deviceNum = pci_dev;
581    params->functionNum = pci_func;
582    params->pio_delay = pio_latency;
583    params->config_delay = config_latency;
584
585    return new IGbE(params);
586}
587
588REGISTER_SIM_OBJECT("IGbE", IGbE)
589