i8254xGBe.cc revision 3318
1/* 2 * Copyright (c) 2006 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Ali Saidi 29 */ 30 31/* @file 32 * Device model for Intel's 8254x line of gigabit ethernet controllers. 33 * In particular an 82547 revision 2 (82547GI) MAC because it seems to have the 34 * fewest workarounds in the driver. It will probably work with most of the 35 * other MACs with slight modifications. 36 */ 37 38#include "base/inet.hh" 39#include "dev/i8254xGBe.hh" 40#include "mem/packet.hh" 41#include "sim/builder.hh" 42#include "sim/stats.hh" 43#include "sim/system.hh" 44 45using namespace iGbReg; 46 47IGbE::IGbE(Params *p) 48 : PciDev(p), etherInt(NULL) 49{ 50 // Initialized internal registers per Intel documentation 51 regs.tctl.reg = 0; 52 regs.rctl.reg = 0; 53 regs.ctrl.reg = 0; 54 regs.ctrl.fd = 1; 55 regs.ctrl.lrst = 1; 56 regs.ctrl.speed = 2; 57 regs.ctrl.frcspd = 1; 58 regs.sts.reg = 0; 59 regs.eecd.reg = 0; 60 regs.eecd.fwe = 1; 61 regs.eecd.ee_type = 1; 62 regs.eerd.reg = 0; 63 regs.icd.reg = 0; 64 regs.imc.reg = 0; 65 regs.rctl.reg = 0; 66 regs.tctl.reg = 0; 67 regs.manc.reg = 0; 68 69 eeOpBits = 0; 70 eeAddrBits = 0; 71 eeDataBits = 0; 72 eeOpcode = 0; 73 74 memset(&flash, 0, EEPROM_SIZE); 75 // Magic happy checksum value 76 flash[0] = 0xBABA; 77} 78 79 80Tick 81IGbE::writeConfig(Packet *pkt) 82{ 83 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 84 if (offset < PCI_DEVICE_SPECIFIC) 85 PciDev::writeConfig(pkt); 86 else 87 panic("Device specific PCI config space not implemented.\n"); 88 89 /// 90 /// Some work may need to be done here based for the pci COMMAND bits. 91 /// 92 93 return pioDelay; 94} 95 96Tick 97IGbE::read(Packet *pkt) 98{ 99 int bar; 100 Addr daddr; 101 102 if (!getBAR(pkt->getAddr(), bar, daddr)) 103 panic("Invalid PCI memory access to unmapped memory.\n"); 104 105 // Only Memory register BAR is allowed 106 assert(bar == 0); 107 108 // Only 32bit accesses allowed 109 assert(pkt->getSize() == 4); 110 111 DPRINTF(Ethernet, "Read device register %#X\n", daddr); 112 113 pkt->allocate(); 114 115 /// 116 /// Handle read of register here 117 /// 118 119 switch (daddr) { 120 case CTRL: 121 pkt->set<uint32_t>(regs.ctrl.reg); 122 break; 123 case STATUS: 124 pkt->set<uint32_t>(regs.sts.reg); 125 break; 126 case EECD: 127 pkt->set<uint32_t>(regs.eecd.reg); 128 break; 129 case EERD: 130 pkt->set<uint32_t>(regs.eerd.reg); 131 break; 132 case ICR: 133 pkt->set<uint32_t>(regs.icd.reg); 134 break; 135 case IMC: 136 pkt->set<uint32_t>(regs.imc.reg); 137 break; 138 case RCTL: 139 pkt->set<uint32_t>(regs.rctl.reg); 140 break; 141 case TCTL: 142 pkt->set<uint32_t>(regs.tctl.reg); 143 break; 144 case MANC: 145 pkt->set<uint32_t>(regs.manc.reg); 146 break; 147 default: 148 panic("Read request to unknown register number: %#x\n", daddr); 149 }; 150 151 pkt->result = Packet::Success; 152 return pioDelay; 153} 154 155Tick 156IGbE::write(Packet *pkt) 157{ 158 int bar; 159 Addr daddr; 160 161 162 if (!getBAR(pkt->getAddr(), bar, daddr)) 163 panic("Invalid PCI memory access to unmapped memory.\n"); 164 165 // Only Memory register BAR is allowed 166 assert(bar == 0); 167 168 // Only 32bit accesses allowed 169 assert(pkt->getSize() == sizeof(uint32_t)); 170 171 DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>()); 172 173 /// 174 /// Handle write of register here 175 /// 176 uint32_t val = pkt->get<uint32_t>(); 177 178 switch (daddr) { 179 case CTRL: 180 regs.ctrl.reg = val; 181 break; 182 case STATUS: 183 regs.sts.reg = val; 184 break; 185 case EECD: 186 int oldClk; 187 oldClk = regs.eecd.sk; 188 regs.eecd.reg = val; 189 // See if this is a eeprom access and emulate accordingly 190 if (!oldClk && regs.eecd.sk) { 191 if (eeOpBits < 8) { 192 eeOpcode = eeOpcode << 1 | regs.eecd.din; 193 eeOpBits++; 194 } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) { 195 eeAddr = eeAddr << 1 | regs.eecd.din; 196 eeAddrBits++; 197 } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) { 198 assert(eeAddr < EEPROM_SIZE); 199 DPRINTF(Ethernet, "EEPROM bit read: %d word: %#X\n", 200 flash[eeAddr] >> eeDataBits & 0x1, flash[eeAddr]); 201 regs.eecd.dout = (flash[eeAddr] >> eeDataBits) & 0x1; 202 eeDataBits++; 203 } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) { 204 regs.eecd.dout = 0; 205 eeDataBits++; 206 } else 207 panic("What's going on with eeprom interface? opcode:" 208 " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode, 209 (uint32_t)eeOpBits, (uint32_t)eeAddr, 210 (uint32_t)eeAddrBits, (uint32_t)eeDataBits); 211 212 // Reset everything for the next command 213 if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) || 214 (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) { 215 eeOpBits = 0; 216 eeAddrBits = 0; 217 eeDataBits = 0; 218 eeOpcode = 0; 219 eeAddr = 0; 220 } 221 222 DPRINTF(Ethernet, "EEPROM: opcode: %#X:%d\n", 223 (uint32_t)eeOpcode, (uint32_t) eeOpBits); 224 if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI || 225 eeOpcode == EEPROM_RDSR_OPCODE_SPI )) 226 panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode, 227 (uint32_t)eeOpBits); 228 229 230 } 231 // If driver requests eeprom access, immediately give it to it 232 regs.eecd.ee_gnt = regs.eecd.ee_req; 233 break; 234 case EERD: 235 regs.eerd.reg = val; 236 break; 237 case ICR: 238 regs.icd.reg = val; 239 break; 240 case IMC: 241 regs.imc.reg = val; 242 break; 243 case RCTL: 244 regs.rctl.reg = val; 245 break; 246 case TCTL: 247 regs.tctl.reg = val; 248 break; 249 case MANC: 250 regs.manc.reg = val; 251 break; 252 default: 253 panic("Write request to unknown register number: %#x\n", daddr); 254 }; 255 256 pkt->result = Packet::Success; 257 return pioDelay; 258} 259 260 261bool 262IGbE::ethRxPkt(EthPacketPtr packet) 263{ 264 panic("Need to implemenet\n"); 265} 266 267 268void 269IGbE::ethTxDone() 270{ 271 panic("Need to implemenet\n"); 272} 273 274void 275IGbE::serialize(std::ostream &os) 276{ 277 panic("Need to implemenet\n"); 278} 279 280void 281IGbE::unserialize(Checkpoint *cp, const std::string §ion) 282{ 283 panic("Need to implemenet\n"); 284} 285 286 287BEGIN_DECLARE_SIM_OBJECT_PARAMS(IGbEInt) 288 289 SimObjectParam<EtherInt *> peer; 290 SimObjectParam<IGbE *> device; 291 292END_DECLARE_SIM_OBJECT_PARAMS(IGbEInt) 293 294BEGIN_INIT_SIM_OBJECT_PARAMS(IGbEInt) 295 296 INIT_PARAM_DFLT(peer, "peer interface", NULL), 297 INIT_PARAM(device, "Ethernet device of this interface") 298 299END_INIT_SIM_OBJECT_PARAMS(IGbEInt) 300 301CREATE_SIM_OBJECT(IGbEInt) 302{ 303 IGbEInt *dev_int = new IGbEInt(getInstanceName(), device); 304 305 EtherInt *p = (EtherInt *)peer; 306 if (p) { 307 dev_int->setPeer(p); 308 p->setPeer(dev_int); 309 } 310 311 return dev_int; 312} 313 314REGISTER_SIM_OBJECT("IGbEInt", IGbEInt) 315 316 317BEGIN_DECLARE_SIM_OBJECT_PARAMS(IGbE) 318 319 SimObjectParam<System *> system; 320 SimObjectParam<Platform *> platform; 321 SimObjectParam<PciConfigData *> configdata; 322 Param<uint32_t> pci_bus; 323 Param<uint32_t> pci_dev; 324 Param<uint32_t> pci_func; 325 Param<Tick> pio_latency; 326 Param<Tick> config_latency; 327 328END_DECLARE_SIM_OBJECT_PARAMS(IGbE) 329 330BEGIN_INIT_SIM_OBJECT_PARAMS(IGbE) 331 332 INIT_PARAM(system, "System pointer"), 333 INIT_PARAM(platform, "Platform pointer"), 334 INIT_PARAM(configdata, "PCI Config data"), 335 INIT_PARAM(pci_bus, "PCI bus ID"), 336 INIT_PARAM(pci_dev, "PCI device number"), 337 INIT_PARAM(pci_func, "PCI function code"), 338 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 339 INIT_PARAM(config_latency, "Number of cycles for a config read or write") 340 341END_INIT_SIM_OBJECT_PARAMS(IGbE) 342 343 344CREATE_SIM_OBJECT(IGbE) 345{ 346 IGbE::Params *params = new IGbE::Params; 347 348 params->name = getInstanceName(); 349 params->platform = platform; 350 params->system = system; 351 params->configData = configdata; 352 params->busNum = pci_bus; 353 params->deviceNum = pci_dev; 354 params->functionNum = pci_func; 355 params->pio_delay = pio_latency; 356 params->config_delay = config_latency; 357 358 return new IGbE(params); 359} 360 361REGISTER_SIM_OBJECT("IGbE", IGbE) 362