i8254xGBe.cc revision 4218
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), useFlowControl(p->use_flow_control) 50{ 51 // Initialized internal registers per Intel documentation 52 regs.tctl(0); 53 regs.rctl(0); 54 regs.ctrl(0); 55 regs.ctrl.fd(1); 56 regs.ctrl.lrst(1); 57 regs.ctrl.speed(2); 58 regs.ctrl.frcspd(1); 59 regs.sts(0); 60 regs.sts.speed(3); // Say we're 1000Mbps 61 regs.sts.fd(1); // full duplex 62 regs.eecd(0); 63 regs.eecd.fwe(1); 64 regs.eecd.ee_type(1); 65 regs.eerd(0); 66 regs.icr(0); 67 regs.rctl(0); 68 regs.tctl(0); 69 regs.fcrtl(0); 70 regs.fcrth(1); 71 regs.manc(0); 72 73 regs.pba.rxa(0x30); 74 regs.pba.txa(0x10); 75 76 eeOpBits = 0; 77 eeAddrBits = 0; 78 eeDataBits = 0; 79 eeOpcode = 0; 80 81 // clear all 64 16 bit words of the eeprom 82 memset(&flash, 0, EEPROM_SIZE*2); 83 84 //We'll need to instert the MAC address into the flash 85 flash[0] = 0xA4A4; 86 flash[1] = 0xB6B6; 87 flash[2] = 0xC8C8; 88 89 uint16_t csum = 0; 90 for (int x = 0; x < EEPROM_SIZE; x++) 91 csum += flash[x]; 92 93 // Magic happy checksum value 94 flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum)); 95} 96 97 98Tick 99IGbE::writeConfig(PacketPtr pkt) 100{ 101 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 102 if (offset < PCI_DEVICE_SPECIFIC) 103 PciDev::writeConfig(pkt); 104 else 105 panic("Device specific PCI config space not implemented.\n"); 106 107 /// 108 /// Some work may need to be done here based for the pci COMMAND bits. 109 /// 110 111 return pioDelay; 112} 113 114Tick 115IGbE::read(PacketPtr pkt) 116{ 117 int bar; 118 Addr daddr; 119 120 if (!getBAR(pkt->getAddr(), bar, daddr)) 121 panic("Invalid PCI memory access to unmapped memory.\n"); 122 123 // Only Memory register BAR is allowed 124 assert(bar == 0); 125 126 // Only 32bit accesses allowed 127 assert(pkt->getSize() == 4); 128 129 //DPRINTF(Ethernet, "Read device register %#X\n", daddr); 130 131 pkt->allocate(); 132 133 /// 134 /// Handle read of register here 135 /// 136 137 138 switch (daddr) { 139 case REG_CTRL: 140 pkt->set<uint32_t>(regs.ctrl()); 141 break; 142 case REG_STATUS: 143 pkt->set<uint32_t>(regs.sts()); 144 break; 145 case REG_EECD: 146 pkt->set<uint32_t>(regs.eecd()); 147 break; 148 case REG_EERD: 149 pkt->set<uint32_t>(regs.eerd()); 150 break; 151 case REG_CTRL_EXT: 152 pkt->set<uint32_t>(regs.ctrl_ext()); 153 break; 154 case REG_MDIC: 155 pkt->set<uint32_t>(regs.mdic()); 156 break; 157 case REG_ICR: 158 pkt->set<uint32_t>(regs.icr()); 159 // handle auto setting mask from IAM 160 break; 161 case REG_ITR: 162 pkt->set<uint32_t>(regs.itr()); 163 break; 164 case REG_RCTL: 165 pkt->set<uint32_t>(regs.rctl()); 166 break; 167 case REG_FCTTV: 168 pkt->set<uint32_t>(regs.fcttv()); 169 break; 170 case REG_TCTL: 171 pkt->set<uint32_t>(regs.tctl()); 172 break; 173 case REG_PBA: 174 pkt->set<uint32_t>(regs.pba()); 175 break; 176 case REG_WUC: 177 case REG_LEDCTL: 178 pkt->set<uint32_t>(0); // We don't care, so just return 0 179 break; 180 case REG_FCRTL: 181 pkt->set<uint32_t>(regs.fcrtl()); 182 break; 183 case REG_FCRTH: 184 pkt->set<uint32_t>(regs.fcrth()); 185 break; 186 case REG_RDBAL: 187 pkt->set<uint32_t>(regs.rdba.rdbal()); 188 break; 189 case REG_RDBAH: 190 pkt->set<uint32_t>(regs.rdba.rdbah()); 191 break; 192 case REG_RDLEN: 193 pkt->set<uint32_t>(regs.rdlen()); 194 break; 195 case REG_RDH: 196 pkt->set<uint32_t>(regs.rdh()); 197 break; 198 case REG_RDT: 199 pkt->set<uint32_t>(regs.rdt()); 200 break; 201 case REG_RDTR: 202 pkt->set<uint32_t>(regs.rdtr()); 203 break; 204 case REG_RADV: 205 pkt->set<uint32_t>(regs.radv()); 206 break; 207 case REG_TDBAL: 208 pkt->set<uint32_t>(regs.tdba.tdbal()); 209 break; 210 case REG_TDBAH: 211 pkt->set<uint32_t>(regs.tdba.tdbah()); 212 break; 213 case REG_TDLEN: 214 pkt->set<uint32_t>(regs.tdlen()); 215 break; 216 case REG_TDH: 217 pkt->set<uint32_t>(regs.tdh()); 218 break; 219 case REG_TDT: 220 pkt->set<uint32_t>(regs.tdt()); 221 break; 222 case REG_TIDV: 223 pkt->set<uint32_t>(regs.tidv()); 224 break; 225 case REG_TXDCTL: 226 pkt->set<uint32_t>(regs.txdctl()); 227 break; 228 case REG_TADV: 229 pkt->set<uint32_t>(regs.tadv()); 230 break; 231 case REG_RXCSUM: 232 pkt->set<uint32_t>(regs.rxcsum()); 233 break; 234 case REG_MANC: 235 pkt->set<uint32_t>(regs.manc()); 236 break; 237 default: 238 if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) && 239 !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) && 240 !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)) && 241 !(daddr >= REG_CRCERRS && daddr < (REG_CRCERRS + STATS_REGS_SIZE))) 242 panic("Read request to unknown register number: %#x\n", daddr); 243 else 244 pkt->set<uint32_t>(0); 245 }; 246 247 pkt->result = Packet::Success; 248 return pioDelay; 249} 250 251Tick 252IGbE::write(PacketPtr pkt) 253{ 254 int bar; 255 Addr daddr; 256 257 258 if (!getBAR(pkt->getAddr(), bar, daddr)) 259 panic("Invalid PCI memory access to unmapped memory.\n"); 260 261 // Only Memory register BAR is allowed 262 assert(bar == 0); 263 264 // Only 32bit accesses allowed 265 assert(pkt->getSize() == sizeof(uint32_t)); 266 267 //DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>()); 268 269 /// 270 /// Handle write of register here 271 /// 272 uint32_t val = pkt->get<uint32_t>(); 273 274 switch (daddr) { 275 case REG_CTRL: 276 regs.ctrl = val; 277 if (regs.ctrl.tfce()) 278 warn("TX Flow control enabled, should implement\n"); 279 if (regs.ctrl.rfce()) 280 warn("RX Flow control enabled, should implement\n"); 281 break; 282 case REG_CTRL_EXT: 283 regs.ctrl_ext = val; 284 break; 285 case REG_STATUS: 286 regs.sts = val; 287 break; 288 case REG_EECD: 289 int oldClk; 290 oldClk = regs.eecd.sk(); 291 regs.eecd = val; 292 // See if this is a eeprom access and emulate accordingly 293 if (!oldClk && regs.eecd.sk()) { 294 if (eeOpBits < 8) { 295 eeOpcode = eeOpcode << 1 | regs.eecd.din(); 296 eeOpBits++; 297 } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) { 298 eeAddr = eeAddr << 1 | regs.eecd.din(); 299 eeAddrBits++; 300 } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) { 301 assert(eeAddr>>1 < EEPROM_SIZE); 302 DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n", 303 flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]); 304 regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1); 305 eeDataBits++; 306 } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) { 307 regs.eecd.dout(0); 308 eeDataBits++; 309 } else 310 panic("What's going on with eeprom interface? opcode:" 311 " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode, 312 (uint32_t)eeOpBits, (uint32_t)eeAddr, 313 (uint32_t)eeAddrBits, (uint32_t)eeDataBits); 314 315 // Reset everything for the next command 316 if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) || 317 (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) { 318 eeOpBits = 0; 319 eeAddrBits = 0; 320 eeDataBits = 0; 321 eeOpcode = 0; 322 eeAddr = 0; 323 } 324 325 DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n", 326 (uint32_t)eeOpcode, (uint32_t) eeOpBits, 327 (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits); 328 if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI || 329 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 §ion) 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