7fc68f4e7abcb2674a306cc0fb5fc380376f09e7
[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)
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
86 Tick
87 IGbE::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
102 Tick
103 IGbE::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
174 Tick
175 IGbE::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
292 bool
293 IGbE::ethRxPkt(EthPacketPtr packet)
294 {
295 panic("Need to implemenet\n");
296 }
297
298
299 void
300 IGbE::ethTxDone()
301 {
302 panic("Need to implemenet\n");
303 }
304
305 void
306 IGbE::serialize(std::ostream &os)
307 {
308 panic("Need to implemenet\n");
309 }
310
311 void
312 IGbE::unserialize(Checkpoint *cp, const std::string &section)
313 {
314 panic("Need to implemenet\n");
315 }
316
317
318 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IGbEInt)
319
320 SimObjectParam<EtherInt *> peer;
321 SimObjectParam<IGbE *> device;
322
323 END_DECLARE_SIM_OBJECT_PARAMS(IGbEInt)
324
325 BEGIN_INIT_SIM_OBJECT_PARAMS(IGbEInt)
326
327 INIT_PARAM_DFLT(peer, "peer interface", NULL),
328 INIT_PARAM(device, "Ethernet device of this interface")
329
330 END_INIT_SIM_OBJECT_PARAMS(IGbEInt)
331
332 CREATE_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
345 REGISTER_SIM_OBJECT("IGbEInt", IGbEInt)
346
347
348 BEGIN_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
359 END_DECLARE_SIM_OBJECT_PARAMS(IGbE)
360
361 BEGIN_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
372 END_INIT_SIM_OBJECT_PARAMS(IGbE)
373
374
375 CREATE_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
392 REGISTER_SIM_OBJECT("IGbE", IGbE)