still working on getting past initialization
[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 "sim/builder.hh"
42 #include "sim/stats.hh"
43 #include "sim/system.hh"
44
45 using namespace iGbReg;
46
47 IGbE::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
80 Tick
81 IGbE::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
96 Tick
97 IGbE::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
155 Tick
156 IGbE::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
261 bool
262 IGbE::ethRxPkt(EthPacketPtr packet)
263 {
264 panic("Need to implemenet\n");
265 }
266
267
268 void
269 IGbE::ethTxDone()
270 {
271 panic("Need to implemenet\n");
272 }
273
274 void
275 IGbE::serialize(std::ostream &os)
276 {
277 panic("Need to implemenet\n");
278 }
279
280 void
281 IGbE::unserialize(Checkpoint *cp, const std::string &section)
282 {
283 panic("Need to implemenet\n");
284 }
285
286
287 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IGbEInt)
288
289 SimObjectParam<EtherInt *> peer;
290 SimObjectParam<IGbE *> device;
291
292 END_DECLARE_SIM_OBJECT_PARAMS(IGbEInt)
293
294 BEGIN_INIT_SIM_OBJECT_PARAMS(IGbEInt)
295
296 INIT_PARAM_DFLT(peer, "peer interface", NULL),
297 INIT_PARAM(device, "Ethernet device of this interface")
298
299 END_INIT_SIM_OBJECT_PARAMS(IGbEInt)
300
301 CREATE_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
314 REGISTER_SIM_OBJECT("IGbEInt", IGbEInt)
315
316
317 BEGIN_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
328 END_DECLARE_SIM_OBJECT_PARAMS(IGbE)
329
330 BEGIN_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
341 END_INIT_SIM_OBJECT_PARAMS(IGbE)
342
343
344 CREATE_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
361 REGISTER_SIM_OBJECT("IGbE", IGbE)