5476ef9eba41ab808eb91ca939e1812c79c620f9
[gem5.git] / src / dev / i8254xGBe.cc
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
46 using namespace iGbReg;
47
48 IGbE::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
98 Tick
99 IGbE::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
114 Tick
115 IGbE::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
251 Tick
252 IGbE::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
488 bool
489 IGbE::ethRxPkt(EthPacketPtr packet)
490 {
491 panic("Need to implemenet\n");
492 }
493
494
495 void
496 IGbE::ethTxDone()
497 {
498 panic("Need to implemenet\n");
499 }
500
501 void
502 IGbE::serialize(std::ostream &os)
503 {
504 panic("Need to implemenet\n");
505 }
506
507 void
508 IGbE::unserialize(Checkpoint *cp, const std::string &section)
509 {
510 panic("Need to implemenet\n");
511 }
512
513
514 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IGbEInt)
515
516 SimObjectParam<EtherInt *> peer;
517 SimObjectParam<IGbE *> device;
518
519 END_DECLARE_SIM_OBJECT_PARAMS(IGbEInt)
520
521 BEGIN_INIT_SIM_OBJECT_PARAMS(IGbEInt)
522
523 INIT_PARAM_DFLT(peer, "peer interface", NULL),
524 INIT_PARAM(device, "Ethernet device of this interface")
525
526 END_INIT_SIM_OBJECT_PARAMS(IGbEInt)
527
528 CREATE_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
541 REGISTER_SIM_OBJECT("IGbEInt", IGbEInt)
542
543
544 BEGIN_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
555 END_DECLARE_SIM_OBJECT_PARAMS(IGbE)
556
557 BEGIN_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
568 END_INIT_SIM_OBJECT_PARAMS(IGbE)
569
570
571 CREATE_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
588 REGISTER_SIM_OBJECT("IGbE", IGbE)