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