i8254xGBe.cc revision 3405
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 "mem/packet_access.hh" 42#include "sim/builder.hh" 43#include "sim/stats.hh" 44#include "sim/system.hh" 45 46using namespace iGbReg; 47 48IGbE::IGbE(Params *p) 49 : PciDev(p), etherInt(NULL) 50{ 51 // Initialized internal registers per Intel documentation 52 regs.tctl.reg = 0; 53 regs.rctl.reg = 0; 54 regs.ctrl.reg = 0; 55 regs.ctrl.fd = 1; 56 regs.ctrl.lrst = 1; 57 regs.ctrl.speed = 2; 58 regs.ctrl.frcspd = 1; 59 regs.sts.reg = 0; 60 regs.eecd.reg = 0; 61 regs.eecd.fwe = 1; 62 regs.eecd.ee_type = 1; 63 regs.eerd.reg = 0; 64 regs.icd.reg = 0; 65 regs.imc.reg = 0; 66 regs.rctl.reg = 0; 67 regs.tctl.reg = 0; 68 regs.manc.reg = 0; 69 70 regs.pba.rxa = 0x30; 71 regs.pba.txa = 0x10; 72 73 eeOpBits = 0; 74 eeAddrBits = 0; 75 eeDataBits = 0; 76 eeOpcode = 0; 77 78 // clear all 64 16 bit words of the eeprom 79 memset(&flash, 0, EEPROM_SIZE*2); 80 81 // Magic happy checksum value 82 flash[0] = 0xBABA; 83} 84 85 86Tick 87IGbE::writeConfig(PacketPtr pkt) 88{ 89 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 90 if (offset < PCI_DEVICE_SPECIFIC) 91 PciDev::writeConfig(pkt); 92 else 93 panic("Device specific PCI config space not implemented.\n"); 94 95 /// 96 /// Some work may need to be done here based for the pci COMMAND bits. 97 /// 98 99 return pioDelay; 100} 101 102Tick 103IGbE::read(PacketPtr pkt) 104{ 105 int bar; 106 Addr daddr; 107 108 if (!getBAR(pkt->getAddr(), bar, daddr)) 109 panic("Invalid PCI memory access to unmapped memory.\n"); 110 111 // Only Memory register BAR is allowed 112 assert(bar == 0); 113 114 // Only 32bit accesses allowed 115 assert(pkt->getSize() == 4); 116 117 //DPRINTF(Ethernet, "Read device register %#X\n", daddr); 118 119 pkt->allocate(); 120 121 /// 122 /// Handle read of register here 123 /// 124 125 126 switch (daddr) { 127 case CTRL: 128 pkt->set<uint32_t>(regs.ctrl.reg); 129 break; 130 case STATUS: 131 pkt->set<uint32_t>(regs.sts.reg); 132 break; 133 case EECD: 134 pkt->set<uint32_t>(regs.eecd.reg); 135 break; 136 case EERD: 137 pkt->set<uint32_t>(regs.eerd.reg); 138 break; 139 case ICR: 140 pkt->set<uint32_t>(regs.icd.reg); 141 break; 142 case IMC: 143 pkt->set<uint32_t>(regs.imc.reg); 144 break; 145 case RCTL: 146 pkt->set<uint32_t>(regs.rctl.reg); 147 break; 148 case TCTL: 149 pkt->set<uint32_t>(regs.tctl.reg); 150 break; 151 case PBA: 152 pkt->set<uint32_t>(regs.pba.reg); 153 break; 154 case WUC: 155 case LEDCTL: 156 pkt->set<uint32_t>(0); // We don't care, so just return 0 157 break; 158 case MANC: 159 pkt->set<uint32_t>(regs.manc.reg); 160 break; 161 default: 162 if (!(daddr >= VFTA && daddr < (VFTA + VLAN_FILTER_TABLE_SIZE)*4) && 163 !(daddr >= RAL && daddr < (RAL + RCV_ADDRESS_TABLE_SIZE)*4) && 164 !(daddr >= MTA && daddr < (MTA + MULTICAST_TABLE_SIZE)*4)) 165 pkt->set<uint32_t>(0); 166 else 167 panic("Read request to unknown register number: %#x\n", daddr); 168 }; 169 170 pkt->result = Packet::Success; 171 return pioDelay; 172} 173 174Tick 175IGbE::write(PacketPtr pkt) 176{ 177 int bar; 178 Addr daddr; 179 180 181 if (!getBAR(pkt->getAddr(), bar, daddr)) 182 panic("Invalid PCI memory access to unmapped memory.\n"); 183 184 // Only Memory register BAR is allowed 185 assert(bar == 0); 186 187 // Only 32bit accesses allowed 188 assert(pkt->getSize() == sizeof(uint32_t)); 189 190 //DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>()); 191 192 /// 193 /// Handle write of register here 194 /// 195 uint32_t val = pkt->get<uint32_t>(); 196 197 switch (daddr) { 198 case CTRL: 199 regs.ctrl.reg = val; 200 break; 201 case STATUS: 202 regs.sts.reg = val; 203 break; 204 case EECD: 205 int oldClk; 206 oldClk = regs.eecd.sk; 207 regs.eecd.reg = val; 208 // See if this is a eeprom access and emulate accordingly 209 if (!oldClk && regs.eecd.sk) { 210 if (eeOpBits < 8) { 211 eeOpcode = eeOpcode << 1 | regs.eecd.din; 212 eeOpBits++; 213 } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) { 214 eeAddr = eeAddr << 1 | regs.eecd.din; 215 eeAddrBits++; 216 } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) { 217 assert(eeAddr>>1 < EEPROM_SIZE); 218 DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n", 219 flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]); 220 regs.eecd.dout = (flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1; 221 eeDataBits++; 222 } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) { 223 regs.eecd.dout = 0; 224 eeDataBits++; 225 } else 226 panic("What's going on with eeprom interface? opcode:" 227 " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode, 228 (uint32_t)eeOpBits, (uint32_t)eeAddr, 229 (uint32_t)eeAddrBits, (uint32_t)eeDataBits); 230 231 // Reset everything for the next command 232 if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) || 233 (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) { 234 eeOpBits = 0; 235 eeAddrBits = 0; 236 eeDataBits = 0; 237 eeOpcode = 0; 238 eeAddr = 0; 239 } 240 241 DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n", 242 (uint32_t)eeOpcode, (uint32_t) eeOpBits, 243 (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits); 244 if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI || 245 eeOpcode == EEPROM_RDSR_OPCODE_SPI )) 246 panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode, 247 (uint32_t)eeOpBits); 248 249 250 } 251 // If driver requests eeprom access, immediately give it to it 252 regs.eecd.ee_gnt = regs.eecd.ee_req; 253 break; 254 case EERD: 255 regs.eerd.reg = val; 256 break; 257 case ICR: 258 regs.icd.reg = val; 259 break; 260 case IMC: 261 regs.imc.reg = val; 262 break; 263 case RCTL: 264 regs.rctl.reg = val; 265 break; 266 case TCTL: 267 regs.tctl.reg = val; 268 break; 269 case PBA: 270 regs.pba.rxa = val; 271 regs.pba.txa = 64 - regs.pba.rxa; 272 break; 273 case WUC: 274 case LEDCTL: 275 ; // We don't care, so don't store anything 276 break; 277 case MANC: 278 regs.manc.reg = val; 279 break; 280 default: 281 if (!(daddr >= VFTA && daddr < (VFTA + VLAN_FILTER_TABLE_SIZE)*4) && 282 !(daddr >= RAL && daddr < (RAL + RCV_ADDRESS_TABLE_SIZE)*4) && 283 !(daddr >= MTA && daddr < (MTA + MULTICAST_TABLE_SIZE)*4)) 284 panic("Write request to unknown register number: %#x\n", daddr); 285 }; 286 287 pkt->result = Packet::Success; 288 return pioDelay; 289} 290 291 292bool 293IGbE::ethRxPkt(EthPacketPtr packet) 294{ 295 panic("Need to implemenet\n"); 296} 297 298 299void 300IGbE::ethTxDone() 301{ 302 panic("Need to implemenet\n"); 303} 304 305void 306IGbE::serialize(std::ostream &os) 307{ 308 panic("Need to implemenet\n"); 309} 310 311void 312IGbE::unserialize(Checkpoint *cp, const std::string §ion) 313{ 314 panic("Need to implemenet\n"); 315} 316 317 318BEGIN_DECLARE_SIM_OBJECT_PARAMS(IGbEInt) 319 320 SimObjectParam<EtherInt *> peer; 321 SimObjectParam<IGbE *> device; 322 323END_DECLARE_SIM_OBJECT_PARAMS(IGbEInt) 324 325BEGIN_INIT_SIM_OBJECT_PARAMS(IGbEInt) 326 327 INIT_PARAM_DFLT(peer, "peer interface", NULL), 328 INIT_PARAM(device, "Ethernet device of this interface") 329 330END_INIT_SIM_OBJECT_PARAMS(IGbEInt) 331 332CREATE_SIM_OBJECT(IGbEInt) 333{ 334 IGbEInt *dev_int = new IGbEInt(getInstanceName(), device); 335 336 EtherInt *p = (EtherInt *)peer; 337 if (p) { 338 dev_int->setPeer(p); 339 p->setPeer(dev_int); 340 } 341 342 return dev_int; 343} 344 345REGISTER_SIM_OBJECT("IGbEInt", IGbEInt) 346 347 348BEGIN_DECLARE_SIM_OBJECT_PARAMS(IGbE) 349 350 SimObjectParam<System *> system; 351 SimObjectParam<Platform *> platform; 352 SimObjectParam<PciConfigData *> configdata; 353 Param<uint32_t> pci_bus; 354 Param<uint32_t> pci_dev; 355 Param<uint32_t> pci_func; 356 Param<Tick> pio_latency; 357 Param<Tick> config_latency; 358 359END_DECLARE_SIM_OBJECT_PARAMS(IGbE) 360 361BEGIN_INIT_SIM_OBJECT_PARAMS(IGbE) 362 363 INIT_PARAM(system, "System pointer"), 364 INIT_PARAM(platform, "Platform pointer"), 365 INIT_PARAM(configdata, "PCI Config data"), 366 INIT_PARAM(pci_bus, "PCI bus ID"), 367 INIT_PARAM(pci_dev, "PCI device number"), 368 INIT_PARAM(pci_func, "PCI function code"), 369 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 370 INIT_PARAM(config_latency, "Number of cycles for a config read or write") 371 372END_INIT_SIM_OBJECT_PARAMS(IGbE) 373 374 375CREATE_SIM_OBJECT(IGbE) 376{ 377 IGbE::Params *params = new IGbE::Params; 378 379 params->name = getInstanceName(); 380 params->platform = platform; 381 params->system = system; 382 params->configData = configdata; 383 params->busNum = pci_bus; 384 params->deviceNum = pci_dev; 385 params->functionNum = pci_func; 386 params->pio_delay = pio_latency; 387 params->config_delay = config_latency; 388 389 return new IGbE(params); 390} 391 392REGISTER_SIM_OBJECT("IGbE", IGbE) 393