2 * Copyright (c) 2013 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Copyright (c) 2004-2005 The Regents of The University of Michigan
15 * All rights reserved.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 * Authors: Andrew Schultz
47 #include "cpu/intr_control.hh"
48 #include "debug/IdeCtrl.hh"
49 #include "dev/ide_ctrl.hh"
50 #include "dev/ide_disk.hh"
51 #include "mem/packet.hh"
52 #include "mem/packet_access.hh"
53 #include "params/IdeController.hh"
54 #include "sim/byteswap.hh"
56 // clang complains about std::set being overloaded with Packet::set if
57 // we open up the entire namespace std
60 // Bus master IDE registers
67 // PCI config space registers
70 SecondaryTiming
= 0x42,
77 static const uint16_t timeRegWithDecodeEn
= 0x8000;
79 IdeController::Channel::Channel(
80 string newName
, Addr _cmdSize
, Addr _ctrlSize
) :
82 cmdAddr(0), cmdSize(_cmdSize
), ctrlAddr(0), ctrlSize(_ctrlSize
),
83 master(NULL
), slave(NULL
), selected(NULL
)
85 memset(&bmiRegs
, 0, sizeof(bmiRegs
));
86 bmiRegs
.status
.dmaCap0
= 1;
87 bmiRegs
.status
.dmaCap1
= 1;
90 IdeController::Channel::~Channel()
94 IdeController::IdeController(Params
*p
)
95 : PciDevice(p
), primary(name() + ".primary", BARSize
[0], BARSize
[1]),
96 secondary(name() + ".secondary", BARSize
[2], BARSize
[3]),
97 bmiAddr(0), bmiSize(BARSize
[4]),
98 primaryTiming(htole(timeRegWithDecodeEn
)),
99 secondaryTiming(htole(timeRegWithDecodeEn
)),
100 deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
101 ioEnabled(false), bmEnabled(false),
102 ioShift(p
->io_shift
), ctrlOffset(p
->ctrl_offset
)
104 if (params()->disks
.size() > 3)
105 panic("IDE controllers support a maximum of 4 devices attached!\n");
107 // Assign the disks to channels
108 int numDisks
= params()->disks
.size();
110 primary
.master
= params()->disks
[0];
112 primary
.slave
= params()->disks
[1];
114 secondary
.master
= params()->disks
[2];
116 secondary
.slave
= params()->disks
[3];
118 for (int i
= 0; i
< params()->disks
.size(); i
++) {
119 params()->disks
[i
]->setController(this);
121 primary
.select(false);
122 secondary
.select(false);
124 if ((BARAddrs
[0] & ~BAR_IO_MASK
) && (!legacyIO
[0] || ioShift
)) {
125 primary
.cmdAddr
= BARAddrs
[0]; primary
.cmdSize
= BARSize
[0];
126 primary
.ctrlAddr
= BARAddrs
[1]; primary
.ctrlSize
= BARSize
[1];
128 if ((BARAddrs
[2] & ~BAR_IO_MASK
) && (!legacyIO
[2] || ioShift
)) {
129 secondary
.cmdAddr
= BARAddrs
[2]; secondary
.cmdSize
= BARSize
[2];
130 secondary
.ctrlAddr
= BARAddrs
[3]; secondary
.ctrlSize
= BARSize
[3];
133 ioEnabled
= (config
.command
& htole(PCI_CMD_IOSE
));
134 bmEnabled
= (config
.command
& htole(PCI_CMD_BME
));
138 IdeController::isDiskSelected(IdeDisk
*diskPtr
)
140 return (primary
.selected
== diskPtr
|| secondary
.selected
== diskPtr
);
144 IdeController::intrPost()
146 primary
.bmiRegs
.status
.intStatus
= 1;
147 PciDevice::intrPost();
151 IdeController::setDmaComplete(IdeDisk
*disk
)
154 if (disk
== primary
.master
|| disk
== primary
.slave
) {
156 } else if (disk
== secondary
.master
|| disk
== secondary
.slave
) {
157 channel
= &secondary
;
159 panic("Unable to find disk based on pointer %#x\n", disk
);
162 channel
->bmiRegs
.command
.startStop
= 0;
163 channel
->bmiRegs
.status
.active
= 0;
164 channel
->bmiRegs
.status
.intStatus
= 1;
168 IdeController::readConfig(PacketPtr pkt
)
170 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
171 if (offset
< PCI_DEVICE_SPECIFIC
) {
172 return PciDevice::readConfig(pkt
);
175 switch (pkt
->getSize()) {
176 case sizeof(uint8_t):
179 pkt
->set
<uint8_t>(deviceTiming
);
182 pkt
->set
<uint8_t>(udmaControl
);
184 case PrimaryTiming
+ 1:
185 pkt
->set
<uint8_t>(bits(htole(primaryTiming
), 15, 8));
187 case SecondaryTiming
+ 1:
188 pkt
->set
<uint8_t>(bits(htole(secondaryTiming
), 15, 8));
191 pkt
->set
<uint8_t>(bits(htole(ideConfig
), 7, 0));
194 pkt
->set
<uint8_t>(bits(htole(ideConfig
), 15, 8));
197 panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
200 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 1 data: %#x\n", offset
,
201 (uint32_t)pkt
->get
<uint8_t>());
203 case sizeof(uint16_t):
206 pkt
->set
<uint16_t>(primaryTiming
);
208 case SecondaryTiming
:
209 pkt
->set
<uint16_t>(secondaryTiming
);
212 pkt
->set
<uint16_t>(udmaTiming
);
215 pkt
->set
<uint16_t>(ideConfig
);
218 panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
221 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 2 data: %#x\n", offset
,
222 (uint32_t)pkt
->get
<uint16_t>());
224 case sizeof(uint32_t):
225 if (offset
== IDEConfig
)
226 pkt
->set
<uint32_t>(ideConfig
);
228 panic("No 32bit reads implemented for this device.");
229 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 4 data: %#x\n", offset
,
230 (uint32_t)pkt
->get
<uint32_t>());
233 panic("invalid access size(?) for PCI configspace!\n");
235 pkt
->makeAtomicResponse();
241 IdeController::writeConfig(PacketPtr pkt
)
243 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
244 if (offset
< PCI_DEVICE_SPECIFIC
) {
245 PciDevice::writeConfig(pkt
);
247 switch (pkt
->getSize()) {
248 case sizeof(uint8_t):
251 deviceTiming
= pkt
->get
<uint8_t>();
254 udmaControl
= pkt
->get
<uint8_t>();
257 replaceBits(ideConfig
, 7, 0, pkt
->get
<uint8_t>());
260 replaceBits(ideConfig
, 15, 8, pkt
->get
<uint8_t>());
263 panic("Invalid PCI configuration write "
264 "for size 1 offset: %#x!\n", offset
);
266 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 1 data: %#x\n",
267 offset
, (uint32_t)pkt
->get
<uint8_t>());
269 case sizeof(uint16_t):
272 primaryTiming
= pkt
->get
<uint16_t>();
274 case SecondaryTiming
:
275 secondaryTiming
= pkt
->get
<uint16_t>();
278 udmaTiming
= pkt
->get
<uint16_t>();
281 ideConfig
= pkt
->get
<uint16_t>();
284 panic("Invalid PCI configuration write "
285 "for size 2 offset: %#x!\n",
288 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 2 data: %#x\n",
289 offset
, (uint32_t)pkt
->get
<uint16_t>());
291 case sizeof(uint32_t):
292 if (offset
== IDEConfig
)
293 ideConfig
= pkt
->get
<uint32_t>();
295 panic("Write of unimplemented PCI config. register: %x\n", offset
);
298 panic("invalid access size(?) for PCI configspace!\n");
300 pkt
->makeAtomicResponse();
303 /* Trap command register writes and enable IO/BM as appropriate as well as
306 case PCI0_BASE_ADDR0
:
307 if (BARAddrs
[0] != 0)
308 primary
.cmdAddr
= BARAddrs
[0];
311 case PCI0_BASE_ADDR1
:
312 if (BARAddrs
[1] != 0)
313 primary
.ctrlAddr
= BARAddrs
[1];
316 case PCI0_BASE_ADDR2
:
317 if (BARAddrs
[2] != 0)
318 secondary
.cmdAddr
= BARAddrs
[2];
321 case PCI0_BASE_ADDR3
:
322 if (BARAddrs
[3] != 0)
323 secondary
.ctrlAddr
= BARAddrs
[3];
326 case PCI0_BASE_ADDR4
:
327 if (BARAddrs
[4] != 0)
328 bmiAddr
= BARAddrs
[4];
332 DPRINTF(IdeCtrl
, "Writing to PCI Command val: %#x\n", config
.command
);
333 ioEnabled
= (config
.command
& htole(PCI_CMD_IOSE
));
334 bmEnabled
= (config
.command
& htole(PCI_CMD_BME
));
341 IdeController::Channel::accessCommand(Addr offset
,
342 int size
, uint8_t *data
, bool read
)
344 const Addr SelectOffset
= 6;
345 const uint8_t SelectDevBit
= 0x10;
347 if (!read
&& offset
== SelectOffset
)
348 select(*data
& SelectDevBit
);
350 if (selected
== NULL
) {
351 assert(size
== sizeof(uint8_t));
354 selected
->readCommand(offset
, size
, data
);
356 selected
->writeCommand(offset
, size
, data
);
361 IdeController::Channel::accessControl(Addr offset
,
362 int size
, uint8_t *data
, bool read
)
364 if (selected
== NULL
) {
365 assert(size
== sizeof(uint8_t));
368 selected
->readControl(offset
, size
, data
);
370 selected
->writeControl(offset
, size
, data
);
375 IdeController::Channel::accessBMI(Addr offset
,
376 int size
, uint8_t *data
, bool read
)
378 assert(offset
+ size
<= sizeof(BMIRegs
));
380 memcpy(data
, (uint8_t *)&bmiRegs
+ offset
, size
);
385 if (size
!= sizeof(uint8_t))
386 panic("Invalid BMIC write size: %x\n", size
);
388 BMICommandReg oldVal
= bmiRegs
.command
;
389 BMICommandReg newVal
= *data
;
391 // if a DMA transfer is in progress, R/W control cannot change
392 if (oldVal
.startStop
&& oldVal
.rw
!= newVal
.rw
)
393 oldVal
.rw
= newVal
.rw
;
395 if (oldVal
.startStop
!= newVal
.startStop
) {
396 if (selected
== NULL
)
397 panic("DMA start for disk which does not exist\n");
399 if (oldVal
.startStop
) {
400 DPRINTF(IdeCtrl
, "Stopping DMA transfer\n");
401 bmiRegs
.status
.active
= 0;
403 selected
->abortDma();
405 DPRINTF(IdeCtrl
, "Starting DMA transfer\n");
406 bmiRegs
.status
.active
= 1;
408 selected
->startDma(letoh(bmiRegs
.bmidtp
));
412 bmiRegs
.command
= newVal
;
417 if (size
!= sizeof(uint8_t))
418 panic("Invalid BMIS write size: %x\n", size
);
420 BMIStatusReg oldVal
= bmiRegs
.status
;
421 BMIStatusReg newVal
= *data
;
423 // the BMIDEA bit is read only
424 newVal
.active
= oldVal
.active
;
426 // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
427 if ((oldVal
.intStatus
== 1) && (newVal
.intStatus
== 1)) {
428 newVal
.intStatus
= 0; // clear the interrupt?
430 // Assigning two bitunion fields to each other does not
431 // work as intended, so we need to use this temporary variable
432 // to get around the bug.
433 uint8_t tmp
= oldVal
.intStatus
;
434 newVal
.intStatus
= tmp
;
436 if ((oldVal
.dmaError
== 1) && (newVal
.dmaError
== 1)) {
439 uint8_t tmp
= oldVal
.dmaError
;
440 newVal
.dmaError
= tmp
;
443 bmiRegs
.status
= newVal
;
446 case BMIDescTablePtr
:
447 if (size
!= sizeof(uint32_t))
448 panic("Invalid BMIDTP write size: %x\n", size
);
449 bmiRegs
.bmidtp
= htole(*(uint32_t *)data
& ~0x3);
452 if (size
!= sizeof(uint8_t) && size
!= sizeof(uint16_t) &&
453 size
!= sizeof(uint32_t))
454 panic("IDE controller write of invalid write size: %x\n", size
);
455 memcpy((uint8_t *)&bmiRegs
+ offset
, data
, size
);
461 IdeController::dispatchAccess(PacketPtr pkt
, bool read
)
463 if (pkt
->getSize() != 1 && pkt
->getSize() != 2 && pkt
->getSize() !=4)
464 panic("Bad IDE read size: %d\n", pkt
->getSize());
467 pkt
->makeAtomicResponse();
468 DPRINTF(IdeCtrl
, "io not enabled\n");
472 Addr addr
= pkt
->getAddr();
473 int size
= pkt
->getSize();
474 uint8_t *dataPtr
= pkt
->getPtr
<uint8_t>();
476 if (addr
>= primary
.cmdAddr
&&
477 addr
< (primary
.cmdAddr
+ primary
.cmdSize
)) {
478 addr
-= primary
.cmdAddr
;
479 // linux may have shifted the address by ioShift,
480 // here we shift it back, similarly for ctrlOffset.
482 primary
.accessCommand(addr
, size
, dataPtr
, read
);
483 } else if (addr
>= primary
.ctrlAddr
&&
484 addr
< (primary
.ctrlAddr
+ primary
.ctrlSize
)) {
485 addr
-= primary
.ctrlAddr
;
487 primary
.accessControl(addr
, size
, dataPtr
, read
);
488 } else if (addr
>= secondary
.cmdAddr
&&
489 addr
< (secondary
.cmdAddr
+ secondary
.cmdSize
)) {
490 addr
-= secondary
.cmdAddr
;
491 secondary
.accessCommand(addr
, size
, dataPtr
, read
);
492 } else if (addr
>= secondary
.ctrlAddr
&&
493 addr
< (secondary
.ctrlAddr
+ secondary
.ctrlSize
)) {
494 addr
-= secondary
.ctrlAddr
;
495 secondary
.accessControl(addr
, size
, dataPtr
, read
);
496 } else if (addr
>= bmiAddr
&& addr
< (bmiAddr
+ bmiSize
)) {
497 if (!read
&& !bmEnabled
)
500 if (addr
< sizeof(Channel::BMIRegs
)) {
501 primary
.accessBMI(addr
, size
, dataPtr
, read
);
503 addr
-= sizeof(Channel::BMIRegs
);
504 secondary
.accessBMI(addr
, size
, dataPtr
, read
);
507 panic("IDE controller access to invalid address: %#x\n", addr
);
512 if (pkt
->getSize() == 1)
513 data
= pkt
->get
<uint8_t>();
514 else if (pkt
->getSize() == 2)
515 data
= pkt
->get
<uint16_t>();
517 data
= pkt
->get
<uint32_t>();
518 DPRINTF(IdeCtrl
, "%s from offset: %#x size: %#x data: %#x\n",
519 read
? "Read" : "Write", pkt
->getAddr(), pkt
->getSize(), data
);
522 pkt
->makeAtomicResponse();
526 IdeController::read(PacketPtr pkt
)
528 dispatchAccess(pkt
, true);
533 IdeController::write(PacketPtr pkt
)
535 dispatchAccess(pkt
, false);
540 IdeController::serialize(std::ostream
&os
)
542 // Serialize the PciDevice base class
543 PciDevice::serialize(os
);
545 // Serialize channels
546 primary
.serialize("primary", os
);
547 secondary
.serialize("secondary", os
);
549 // Serialize config registers
550 SERIALIZE_SCALAR(primaryTiming
);
551 SERIALIZE_SCALAR(secondaryTiming
);
552 SERIALIZE_SCALAR(deviceTiming
);
553 SERIALIZE_SCALAR(udmaControl
);
554 SERIALIZE_SCALAR(udmaTiming
);
555 SERIALIZE_SCALAR(ideConfig
);
557 // Serialize internal state
558 SERIALIZE_SCALAR(ioEnabled
);
559 SERIALIZE_SCALAR(bmEnabled
);
560 SERIALIZE_SCALAR(bmiAddr
);
561 SERIALIZE_SCALAR(bmiSize
);
565 IdeController::Channel::serialize(const std::string
&base
, std::ostream
&os
)
567 paramOut(os
, base
+ ".cmdAddr", cmdAddr
);
568 paramOut(os
, base
+ ".cmdSize", cmdSize
);
569 paramOut(os
, base
+ ".ctrlAddr", ctrlAddr
);
570 paramOut(os
, base
+ ".ctrlSize", ctrlSize
);
571 uint8_t command
= bmiRegs
.command
;
572 paramOut(os
, base
+ ".bmiRegs.command", command
);
573 paramOut(os
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
574 uint8_t status
= bmiRegs
.status
;
575 paramOut(os
, base
+ ".bmiRegs.status", status
);
576 paramOut(os
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
577 paramOut(os
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
578 paramOut(os
, base
+ ".selectBit", selectBit
);
582 IdeController::unserialize(Checkpoint
*cp
, const std::string
§ion
)
584 // Unserialize the PciDevice base class
585 PciDevice::unserialize(cp
, section
);
587 // Unserialize channels
588 primary
.unserialize("primary", cp
, section
);
589 secondary
.unserialize("secondary", cp
, section
);
591 // Unserialize config registers
592 UNSERIALIZE_SCALAR(primaryTiming
);
593 UNSERIALIZE_SCALAR(secondaryTiming
);
594 UNSERIALIZE_SCALAR(deviceTiming
);
595 UNSERIALIZE_SCALAR(udmaControl
);
596 UNSERIALIZE_SCALAR(udmaTiming
);
597 UNSERIALIZE_SCALAR(ideConfig
);
599 // Unserialize internal state
600 UNSERIALIZE_SCALAR(ioEnabled
);
601 UNSERIALIZE_SCALAR(bmEnabled
);
602 UNSERIALIZE_SCALAR(bmiAddr
);
603 UNSERIALIZE_SCALAR(bmiSize
);
607 IdeController::Channel::unserialize(const std::string
&base
, Checkpoint
*cp
,
608 const std::string
§ion
)
610 paramIn(cp
, section
, base
+ ".cmdAddr", cmdAddr
);
611 paramIn(cp
, section
, base
+ ".cmdSize", cmdSize
);
612 paramIn(cp
, section
, base
+ ".ctrlAddr", ctrlAddr
);
613 paramIn(cp
, section
, base
+ ".ctrlSize", ctrlSize
);
615 paramIn(cp
, section
, base
+".bmiRegs.command", command
);
616 bmiRegs
.command
= command
;
617 paramIn(cp
, section
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
619 paramIn(cp
, section
, base
+ ".bmiRegs.status", status
);
620 bmiRegs
.status
= status
;
621 paramIn(cp
, section
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
622 paramIn(cp
, section
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
623 paramIn(cp
, section
, base
+ ".selectBit", selectBit
);
628 IdeControllerParams::create()
630 return new IdeController(this);