2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
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.
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.
28 * Authors: Andrew Schultz
35 #include "base/trace.hh"
36 #include "cpu/intr_control.hh"
37 #include "dev/ide_ctrl.hh"
38 #include "dev/ide_disk.hh"
39 #include "mem/packet.hh"
40 #include "mem/packet_access.hh"
41 #include "params/IdeController.hh"
42 #include "sim/byteswap.hh"
46 // Bus master IDE registers
53 // PCI config space registers
56 SecondaryTiming
= 0x42,
63 static const uint16_t timeRegWithDecodeEn
= 0x8000;
65 IdeController::Channel::Channel(
66 string newName
, Addr _cmdSize
, Addr _ctrlSize
) :
68 cmdAddr(0), cmdSize(_cmdSize
), ctrlAddr(0), ctrlSize(_ctrlSize
),
69 master(NULL
), slave(NULL
), selected(NULL
)
71 memset(&bmiRegs
, 0, sizeof(bmiRegs
));
72 bmiRegs
.status
.dmaCap0
= 1;
73 bmiRegs
.status
.dmaCap1
= 1;
76 IdeController::Channel::~Channel()
80 IdeController::IdeController(Params
*p
)
81 : PciDev(p
), primary(name() + ".primary", BARSize
[0], BARSize
[1]),
82 secondary(name() + ".secondary", BARSize
[2], BARSize
[3]),
83 bmiAddr(0), bmiSize(BARSize
[4]),
84 primaryTiming(htole(timeRegWithDecodeEn
)),
85 secondaryTiming(htole(timeRegWithDecodeEn
)),
86 deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
87 ioEnabled(false), bmEnabled(false)
89 if (params()->disks
.size() > 3)
90 panic("IDE controllers support a maximum of 4 devices attached!\n");
92 // Assign the disks to channels
93 int numDisks
= params()->disks
.size();
95 primary
.master
= params()->disks
[0];
97 primary
.slave
= params()->disks
[1];
99 secondary
.master
= params()->disks
[2];
101 secondary
.slave
= params()->disks
[3];
103 for (int i
= 0; i
< params()->disks
.size(); i
++) {
104 params()->disks
[i
]->setController(this);
106 primary
.select(false);
107 secondary
.select(false);
109 ioEnabled
= (config
.command
& htole(PCI_CMD_IOSE
));
110 bmEnabled
= (config
.command
& htole(PCI_CMD_BME
));
114 IdeController::isDiskSelected(IdeDisk
*diskPtr
)
116 return (primary
.selected
== diskPtr
|| secondary
.selected
== diskPtr
);
120 IdeController::intrPost()
122 primary
.bmiRegs
.status
.intStatus
= 1;
127 IdeController::setDmaComplete(IdeDisk
*disk
)
130 if (disk
== primary
.master
|| disk
== primary
.slave
) {
132 } else if (disk
== secondary
.master
|| disk
== secondary
.slave
) {
133 channel
= &secondary
;
135 panic("Unable to find disk based on pointer %#x\n", disk
);
138 channel
->bmiRegs
.command
.startStop
= 0;
139 channel
->bmiRegs
.status
.active
= 0;
140 channel
->bmiRegs
.status
.intStatus
= 1;
144 IdeController::readConfig(PacketPtr pkt
)
146 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
147 if (offset
< PCI_DEVICE_SPECIFIC
) {
148 return PciDev::readConfig(pkt
);
153 switch (pkt
->getSize()) {
154 case sizeof(uint8_t):
157 pkt
->set
<uint8_t>(deviceTiming
);
160 pkt
->set
<uint8_t>(udmaControl
);
162 case PrimaryTiming
+ 1:
163 pkt
->set
<uint8_t>(bits(htole(primaryTiming
), 15, 8));
165 case SecondaryTiming
+ 1:
166 pkt
->set
<uint8_t>(bits(htole(secondaryTiming
), 15, 8));
169 pkt
->set
<uint8_t>(bits(htole(ideConfig
), 7, 0));
172 pkt
->set
<uint8_t>(bits(htole(ideConfig
), 15, 8));
175 panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
178 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 1 data: %#x\n", offset
,
179 (uint32_t)pkt
->get
<uint8_t>());
181 case sizeof(uint16_t):
184 pkt
->set
<uint16_t>(primaryTiming
);
186 case SecondaryTiming
:
187 pkt
->set
<uint16_t>(secondaryTiming
);
190 pkt
->set
<uint16_t>(udmaTiming
);
193 pkt
->set
<uint16_t>(ideConfig
);
196 panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
199 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 2 data: %#x\n", offset
,
200 (uint32_t)pkt
->get
<uint16_t>());
202 case sizeof(uint32_t):
203 panic("No 32bit reads implemented for this device.");
204 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 4 data: %#x\n", offset
,
205 (uint32_t)pkt
->get
<uint32_t>());
208 panic("invalid access size(?) for PCI configspace!\n");
210 pkt
->makeAtomicResponse();
216 IdeController::writeConfig(PacketPtr pkt
)
218 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
219 if (offset
< PCI_DEVICE_SPECIFIC
) {
220 PciDev::writeConfig(pkt
);
222 switch (pkt
->getSize()) {
223 case sizeof(uint8_t):
226 deviceTiming
= pkt
->get
<uint8_t>();
229 udmaControl
= pkt
->get
<uint8_t>();
232 replaceBits(ideConfig
, 7, 0, pkt
->get
<uint8_t>());
235 replaceBits(ideConfig
, 15, 8, pkt
->get
<uint8_t>());
238 panic("Invalid PCI configuration write "
239 "for size 1 offset: %#x!\n", offset
);
241 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 1 data: %#x\n",
242 offset
, (uint32_t)pkt
->get
<uint8_t>());
244 case sizeof(uint16_t):
247 primaryTiming
= pkt
->get
<uint16_t>();
249 case SecondaryTiming
:
250 secondaryTiming
= pkt
->get
<uint16_t>();
253 udmaTiming
= pkt
->get
<uint16_t>();
256 ideConfig
= pkt
->get
<uint16_t>();
259 panic("Invalid PCI configuration write "
260 "for size 2 offset: %#x!\n",
263 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 2 data: %#x\n",
264 offset
, (uint32_t)pkt
->get
<uint16_t>());
266 case sizeof(uint32_t):
267 panic("Write of unimplemented PCI config. register: %x\n", offset
);
270 panic("invalid access size(?) for PCI configspace!\n");
272 pkt
->makeAtomicResponse();
275 /* Trap command register writes and enable IO/BM as appropriate as well as
278 case PCI0_BASE_ADDR0
:
279 if (BARAddrs
[0] != 0)
280 primary
.cmdAddr
= BARAddrs
[0];
283 case PCI0_BASE_ADDR1
:
284 if (BARAddrs
[1] != 0)
285 primary
.ctrlAddr
= BARAddrs
[1];
288 case PCI0_BASE_ADDR2
:
289 if (BARAddrs
[2] != 0)
290 secondary
.cmdAddr
= BARAddrs
[2];
293 case PCI0_BASE_ADDR3
:
294 if (BARAddrs
[3] != 0)
295 secondary
.ctrlAddr
= BARAddrs
[3];
298 case PCI0_BASE_ADDR4
:
299 if (BARAddrs
[4] != 0)
300 bmiAddr
= BARAddrs
[4];
304 ioEnabled
= (config
.command
& htole(PCI_CMD_IOSE
));
305 bmEnabled
= (config
.command
& htole(PCI_CMD_BME
));
312 IdeController::Channel::accessCommand(Addr offset
,
313 int size
, uint8_t *data
, bool read
)
315 const Addr SelectOffset
= 6;
316 const uint8_t SelectDevBit
= 0x10;
318 if (!read
&& offset
== SelectOffset
)
319 select(*data
& SelectDevBit
);
321 if (selected
== NULL
) {
322 assert(size
== sizeof(uint8_t));
325 selected
->readCommand(offset
, size
, data
);
327 selected
->writeCommand(offset
, size
, data
);
332 IdeController::Channel::accessControl(Addr offset
,
333 int size
, uint8_t *data
, bool read
)
335 if (selected
== NULL
) {
336 assert(size
== sizeof(uint8_t));
339 selected
->readControl(offset
, size
, data
);
341 selected
->writeControl(offset
, size
, data
);
346 IdeController::Channel::accessBMI(Addr offset
,
347 int size
, uint8_t *data
, bool read
)
349 assert(offset
+ size
<= sizeof(BMIRegs
));
351 memcpy(data
, (uint8_t *)&bmiRegs
+ offset
, size
);
356 if (size
!= sizeof(uint8_t))
357 panic("Invalid BMIC write size: %x\n", size
);
359 BMICommandReg oldVal
= bmiRegs
.command
;
360 BMICommandReg newVal
= *data
;
362 // if a DMA transfer is in progress, R/W control cannot change
363 if (oldVal
.startStop
&& oldVal
.rw
!= newVal
.rw
)
364 oldVal
.rw
= newVal
.rw
;
366 if (oldVal
.startStop
!= newVal
.startStop
) {
367 if (selected
== NULL
)
368 panic("DMA start for disk which does not exist\n");
370 if (oldVal
.startStop
) {
371 DPRINTF(IdeCtrl
, "Stopping DMA transfer\n");
372 bmiRegs
.status
.active
= 0;
374 selected
->abortDma();
376 DPRINTF(IdeCtrl
, "Starting DMA transfer\n");
377 bmiRegs
.status
.active
= 1;
379 selected
->startDma(letoh(bmiRegs
.bmidtp
));
383 bmiRegs
.command
= newVal
;
388 if (size
!= sizeof(uint8_t))
389 panic("Invalid BMIS write size: %x\n", size
);
391 BMIStatusReg oldVal
= bmiRegs
.status
;
392 BMIStatusReg newVal
= *data
;
394 // the BMIDEA bit is read only
395 newVal
.active
= oldVal
.active
;
397 // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
398 if (oldVal
.intStatus
&& newVal
.intStatus
)
399 newVal
.intStatus
= 0; // clear the interrupt?
401 newVal
.intStatus
= oldVal
.intStatus
;
402 if (oldVal
.dmaError
&& newVal
.dmaError
)
405 newVal
.dmaError
= oldVal
.dmaError
;
407 bmiRegs
.status
= newVal
;
410 case BMIDescTablePtr
:
411 if (size
!= sizeof(uint32_t))
412 panic("Invalid BMIDTP write size: %x\n", size
);
413 bmiRegs
.bmidtp
= htole(*(uint32_t *)data
& ~0x3);
416 if (size
!= sizeof(uint8_t) && size
!= sizeof(uint16_t) &&
417 size
!= sizeof(uint32_t))
418 panic("IDE controller write of invalid write size: %x\n", size
);
419 memcpy((uint8_t *)&bmiRegs
+ offset
, data
, size
);
425 IdeController::dispatchAccess(PacketPtr pkt
, bool read
)
428 if (pkt
->getSize() != 1 && pkt
->getSize() != 2 && pkt
->getSize() !=4)
429 panic("Bad IDE read size: %d\n", pkt
->getSize());
432 pkt
->makeAtomicResponse();
433 DPRINTF(IdeCtrl
, "io not enabled\n");
437 Addr addr
= pkt
->getAddr();
438 int size
= pkt
->getSize();
439 uint8_t *dataPtr
= pkt
->getPtr
<uint8_t>();
441 if (addr
>= primary
.cmdAddr
&&
442 addr
< (primary
.cmdAddr
+ primary
.cmdSize
)) {
443 addr
-= primary
.cmdAddr
;
444 primary
.accessCommand(addr
, size
, dataPtr
, read
);
445 } else if (addr
>= primary
.ctrlAddr
&&
446 addr
< (primary
.ctrlAddr
+ primary
.ctrlSize
)) {
447 addr
-= primary
.ctrlAddr
;
448 primary
.accessControl(addr
, size
, dataPtr
, read
);
449 } else if (addr
>= secondary
.cmdAddr
&&
450 addr
< (secondary
.cmdAddr
+ secondary
.cmdSize
)) {
451 addr
-= secondary
.cmdAddr
;
452 secondary
.accessCommand(addr
, size
, dataPtr
, read
);
453 } else if (addr
>= secondary
.ctrlAddr
&&
454 addr
< (secondary
.ctrlAddr
+ secondary
.ctrlSize
)) {
455 addr
-= secondary
.ctrlAddr
;
456 secondary
.accessControl(addr
, size
, dataPtr
, read
);
457 } else if (addr
>= bmiAddr
&& addr
< (bmiAddr
+ bmiSize
)) {
458 if (!read
&& !bmEnabled
)
461 if (addr
< sizeof(Channel::BMIRegs
)) {
462 primary
.accessBMI(addr
, size
, dataPtr
, read
);
464 addr
-= sizeof(Channel::BMIRegs
);
465 secondary
.accessBMI(addr
, size
, dataPtr
, read
);
468 panic("IDE controller access to invalid address: %#x\n", addr
);
472 if (pkt
->getSize() == 1)
473 data
= pkt
->get
<uint8_t>();
474 else if (pkt
->getSize() == 2)
475 data
= pkt
->get
<uint16_t>();
477 data
= pkt
->get
<uint32_t>();
478 DPRINTF(IdeCtrl
, "%s from offset: %#x size: %#x data: %#x\n",
479 read
? "Read" : "Write", pkt
->getAddr(), pkt
->getSize(), data
);
481 pkt
->makeAtomicResponse();
485 IdeController::read(PacketPtr pkt
)
487 dispatchAccess(pkt
, true);
492 IdeController::write(PacketPtr pkt
)
494 dispatchAccess(pkt
, false);
499 IdeController::serialize(std::ostream
&os
)
501 // Serialize the PciDev base class
502 PciDev::serialize(os
);
504 // Serialize channels
505 primary
.serialize("primary", os
);
506 secondary
.serialize("secondary", os
);
508 // Serialize config registers
509 SERIALIZE_SCALAR(primaryTiming
);
510 SERIALIZE_SCALAR(secondaryTiming
);
511 SERIALIZE_SCALAR(deviceTiming
);
512 SERIALIZE_SCALAR(udmaControl
);
513 SERIALIZE_SCALAR(udmaTiming
);
514 SERIALIZE_SCALAR(ideConfig
);
516 // Serialize internal state
517 SERIALIZE_SCALAR(ioEnabled
);
518 SERIALIZE_SCALAR(bmEnabled
);
519 SERIALIZE_SCALAR(bmiAddr
);
520 SERIALIZE_SCALAR(bmiSize
);
524 IdeController::Channel::serialize(const std::string
&base
, std::ostream
&os
)
526 paramOut(os
, base
+ ".cmdAddr", cmdAddr
);
527 paramOut(os
, base
+ ".cmdSize", cmdSize
);
528 paramOut(os
, base
+ ".ctrlAddr", ctrlAddr
);
529 paramOut(os
, base
+ ".ctrlSize", ctrlSize
);
530 uint8_t command
= bmiRegs
.command
;
531 paramOut(os
, base
+ ".bmiRegs.command", command
);
532 paramOut(os
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
533 uint8_t status
= bmiRegs
.status
;
534 paramOut(os
, base
+ ".bmiRegs.status", status
);
535 paramOut(os
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
536 paramOut(os
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
537 paramOut(os
, base
+ ".selectBit", selectBit
);
541 IdeController::unserialize(Checkpoint
*cp
, const std::string
§ion
)
543 // Unserialize the PciDev base class
544 PciDev::unserialize(cp
, section
);
546 // Unserialize channels
547 primary
.unserialize("primary", cp
, section
);
548 secondary
.unserialize("secondary", cp
, section
);
550 // Unserialize config registers
551 UNSERIALIZE_SCALAR(primaryTiming
);
552 UNSERIALIZE_SCALAR(secondaryTiming
);
553 UNSERIALIZE_SCALAR(deviceTiming
);
554 UNSERIALIZE_SCALAR(udmaControl
);
555 UNSERIALIZE_SCALAR(udmaTiming
);
556 UNSERIALIZE_SCALAR(ideConfig
);
558 // Unserialize internal state
559 UNSERIALIZE_SCALAR(ioEnabled
);
560 UNSERIALIZE_SCALAR(bmEnabled
);
561 UNSERIALIZE_SCALAR(bmiAddr
);
562 UNSERIALIZE_SCALAR(bmiSize
);
566 IdeController::Channel::unserialize(const std::string
&base
, Checkpoint
*cp
,
567 const std::string
§ion
)
569 paramIn(cp
, section
, base
+ ".cmdAddr", cmdAddr
);
570 paramIn(cp
, section
, base
+ ".cmdSize", cmdSize
);
571 paramIn(cp
, section
, base
+ ".ctrlAddr", ctrlAddr
);
572 paramIn(cp
, section
, base
+ ".ctrlSize", ctrlSize
);
574 paramIn(cp
, section
, base
+".bmiRegs.command", command
);
575 bmiRegs
.command
= command
;
576 paramIn(cp
, section
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
578 paramIn(cp
, section
, base
+ ".bmiRegs.status", status
);
579 bmiRegs
.status
= status
;
580 paramIn(cp
, section
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
581 paramIn(cp
, section
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
582 paramIn(cp
, section
, base
+ ".selectBit", selectBit
);
587 IdeControllerParams::create()
589 return new IdeController(this);