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>(udmaControl
);
209 pkt
->set
<uint16_t>(primaryTiming
);
211 case SecondaryTiming
:
212 pkt
->set
<uint16_t>(secondaryTiming
);
215 pkt
->set
<uint16_t>(udmaTiming
);
218 pkt
->set
<uint16_t>(ideConfig
);
221 panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
224 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 2 data: %#x\n", offset
,
225 (uint32_t)pkt
->get
<uint16_t>());
227 case sizeof(uint32_t):
230 pkt
->set
<uint32_t>(primaryTiming
);
233 pkt
->set
<uint32_t>(ideConfig
);
236 panic("No 32bit reads implemented for this device.");
238 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 4 data: %#x\n", offset
,
239 (uint32_t)pkt
->get
<uint32_t>());
242 panic("invalid access size(?) for PCI configspace!\n");
244 pkt
->makeAtomicResponse();
250 IdeController::writeConfig(PacketPtr pkt
)
252 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
253 if (offset
< PCI_DEVICE_SPECIFIC
) {
254 PciDevice::writeConfig(pkt
);
256 switch (pkt
->getSize()) {
257 case sizeof(uint8_t):
260 deviceTiming
= pkt
->get
<uint8_t>();
263 udmaControl
= pkt
->get
<uint8_t>();
266 replaceBits(ideConfig
, 7, 0, pkt
->get
<uint8_t>());
269 replaceBits(ideConfig
, 15, 8, pkt
->get
<uint8_t>());
272 panic("Invalid PCI configuration write "
273 "for size 1 offset: %#x!\n", offset
);
275 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 1 data: %#x\n",
276 offset
, (uint32_t)pkt
->get
<uint8_t>());
278 case sizeof(uint16_t):
281 udmaControl
= pkt
->get
<uint16_t>();
284 primaryTiming
= pkt
->get
<uint16_t>();
286 case SecondaryTiming
:
287 secondaryTiming
= pkt
->get
<uint16_t>();
290 udmaTiming
= pkt
->get
<uint16_t>();
293 ideConfig
= pkt
->get
<uint16_t>();
296 panic("Invalid PCI configuration write "
297 "for size 2 offset: %#x!\n",
300 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 2 data: %#x\n",
301 offset
, (uint32_t)pkt
->get
<uint16_t>());
303 case sizeof(uint32_t):
306 primaryTiming
= pkt
->get
<uint32_t>();
309 ideConfig
= pkt
->get
<uint32_t>();
312 panic("Write of unimplemented PCI config. register: %x\n", offset
);
316 panic("invalid access size(?) for PCI configspace!\n");
318 pkt
->makeAtomicResponse();
321 /* Trap command register writes and enable IO/BM as appropriate as well as
324 case PCI0_BASE_ADDR0
:
325 if (BARAddrs
[0] != 0)
326 primary
.cmdAddr
= BARAddrs
[0];
329 case PCI0_BASE_ADDR1
:
330 if (BARAddrs
[1] != 0)
331 primary
.ctrlAddr
= BARAddrs
[1];
334 case PCI0_BASE_ADDR2
:
335 if (BARAddrs
[2] != 0)
336 secondary
.cmdAddr
= BARAddrs
[2];
339 case PCI0_BASE_ADDR3
:
340 if (BARAddrs
[3] != 0)
341 secondary
.ctrlAddr
= BARAddrs
[3];
344 case PCI0_BASE_ADDR4
:
345 if (BARAddrs
[4] != 0)
346 bmiAddr
= BARAddrs
[4];
350 DPRINTF(IdeCtrl
, "Writing to PCI Command val: %#x\n", config
.command
);
351 ioEnabled
= (config
.command
& htole(PCI_CMD_IOSE
));
352 bmEnabled
= (config
.command
& htole(PCI_CMD_BME
));
359 IdeController::Channel::accessCommand(Addr offset
,
360 int size
, uint8_t *data
, bool read
)
362 const Addr SelectOffset
= 6;
363 const uint8_t SelectDevBit
= 0x10;
365 if (!read
&& offset
== SelectOffset
)
366 select(*data
& SelectDevBit
);
368 if (selected
== NULL
) {
369 assert(size
== sizeof(uint8_t));
372 selected
->readCommand(offset
, size
, data
);
374 selected
->writeCommand(offset
, size
, data
);
379 IdeController::Channel::accessControl(Addr offset
,
380 int size
, uint8_t *data
, bool read
)
382 if (selected
== NULL
) {
383 assert(size
== sizeof(uint8_t));
386 selected
->readControl(offset
, size
, data
);
388 selected
->writeControl(offset
, size
, data
);
393 IdeController::Channel::accessBMI(Addr offset
,
394 int size
, uint8_t *data
, bool read
)
396 assert(offset
+ size
<= sizeof(BMIRegs
));
398 memcpy(data
, (uint8_t *)&bmiRegs
+ offset
, size
);
403 if (size
!= sizeof(uint8_t))
404 panic("Invalid BMIC write size: %x\n", size
);
406 BMICommandReg oldVal
= bmiRegs
.command
;
407 BMICommandReg newVal
= *data
;
409 // if a DMA transfer is in progress, R/W control cannot change
410 if (oldVal
.startStop
&& oldVal
.rw
!= newVal
.rw
)
411 oldVal
.rw
= newVal
.rw
;
413 if (oldVal
.startStop
!= newVal
.startStop
) {
414 if (selected
== NULL
)
415 panic("DMA start for disk which does not exist\n");
417 if (oldVal
.startStop
) {
418 DPRINTF(IdeCtrl
, "Stopping DMA transfer\n");
419 bmiRegs
.status
.active
= 0;
421 selected
->abortDma();
423 DPRINTF(IdeCtrl
, "Starting DMA transfer\n");
424 bmiRegs
.status
.active
= 1;
426 selected
->startDma(letoh(bmiRegs
.bmidtp
));
430 bmiRegs
.command
= newVal
;
435 if (size
!= sizeof(uint8_t))
436 panic("Invalid BMIS write size: %x\n", size
);
438 BMIStatusReg oldVal
= bmiRegs
.status
;
439 BMIStatusReg newVal
= *data
;
441 // the BMIDEA bit is read only
442 newVal
.active
= oldVal
.active
;
444 // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
445 if ((oldVal
.intStatus
== 1) && (newVal
.intStatus
== 1)) {
446 newVal
.intStatus
= 0; // clear the interrupt?
448 // Assigning two bitunion fields to each other does not
449 // work as intended, so we need to use this temporary variable
450 // to get around the bug.
451 uint8_t tmp
= oldVal
.intStatus
;
452 newVal
.intStatus
= tmp
;
454 if ((oldVal
.dmaError
== 1) && (newVal
.dmaError
== 1)) {
457 uint8_t tmp
= oldVal
.dmaError
;
458 newVal
.dmaError
= tmp
;
461 bmiRegs
.status
= newVal
;
464 case BMIDescTablePtr
:
465 if (size
!= sizeof(uint32_t))
466 panic("Invalid BMIDTP write size: %x\n", size
);
467 bmiRegs
.bmidtp
= htole(*(uint32_t *)data
& ~0x3);
470 if (size
!= sizeof(uint8_t) && size
!= sizeof(uint16_t) &&
471 size
!= sizeof(uint32_t))
472 panic("IDE controller write of invalid write size: %x\n", size
);
473 memcpy((uint8_t *)&bmiRegs
+ offset
, data
, size
);
479 IdeController::dispatchAccess(PacketPtr pkt
, bool read
)
481 if (pkt
->getSize() != 1 && pkt
->getSize() != 2 && pkt
->getSize() !=4)
482 panic("Bad IDE read size: %d\n", pkt
->getSize());
485 pkt
->makeAtomicResponse();
486 DPRINTF(IdeCtrl
, "io not enabled\n");
490 Addr addr
= pkt
->getAddr();
491 int size
= pkt
->getSize();
492 uint8_t *dataPtr
= pkt
->getPtr
<uint8_t>();
494 if (addr
>= primary
.cmdAddr
&&
495 addr
< (primary
.cmdAddr
+ primary
.cmdSize
)) {
496 addr
-= primary
.cmdAddr
;
497 // linux may have shifted the address by ioShift,
498 // here we shift it back, similarly for ctrlOffset.
500 primary
.accessCommand(addr
, size
, dataPtr
, read
);
501 } else if (addr
>= primary
.ctrlAddr
&&
502 addr
< (primary
.ctrlAddr
+ primary
.ctrlSize
)) {
503 addr
-= primary
.ctrlAddr
;
505 primary
.accessControl(addr
, size
, dataPtr
, read
);
506 } else if (addr
>= secondary
.cmdAddr
&&
507 addr
< (secondary
.cmdAddr
+ secondary
.cmdSize
)) {
508 addr
-= secondary
.cmdAddr
;
509 secondary
.accessCommand(addr
, size
, dataPtr
, read
);
510 } else if (addr
>= secondary
.ctrlAddr
&&
511 addr
< (secondary
.ctrlAddr
+ secondary
.ctrlSize
)) {
512 addr
-= secondary
.ctrlAddr
;
513 secondary
.accessControl(addr
, size
, dataPtr
, read
);
514 } else if (addr
>= bmiAddr
&& addr
< (bmiAddr
+ bmiSize
)) {
515 if (!read
&& !bmEnabled
)
518 if (addr
< sizeof(Channel::BMIRegs
)) {
519 primary
.accessBMI(addr
, size
, dataPtr
, read
);
521 addr
-= sizeof(Channel::BMIRegs
);
522 secondary
.accessBMI(addr
, size
, dataPtr
, read
);
525 panic("IDE controller access to invalid address: %#x\n", addr
);
530 if (pkt
->getSize() == 1)
531 data
= pkt
->get
<uint8_t>();
532 else if (pkt
->getSize() == 2)
533 data
= pkt
->get
<uint16_t>();
535 data
= pkt
->get
<uint32_t>();
536 DPRINTF(IdeCtrl
, "%s from offset: %#x size: %#x data: %#x\n",
537 read
? "Read" : "Write", pkt
->getAddr(), pkt
->getSize(), data
);
540 pkt
->makeAtomicResponse();
544 IdeController::read(PacketPtr pkt
)
546 dispatchAccess(pkt
, true);
551 IdeController::write(PacketPtr pkt
)
553 dispatchAccess(pkt
, false);
558 IdeController::serialize(CheckpointOut
&cp
) const
560 // Serialize the PciDevice base class
561 PciDevice::serialize(cp
);
563 // Serialize channels
564 primary
.serialize("primary", cp
);
565 secondary
.serialize("secondary", cp
);
567 // Serialize config registers
568 SERIALIZE_SCALAR(primaryTiming
);
569 SERIALIZE_SCALAR(secondaryTiming
);
570 SERIALIZE_SCALAR(deviceTiming
);
571 SERIALIZE_SCALAR(udmaControl
);
572 SERIALIZE_SCALAR(udmaTiming
);
573 SERIALIZE_SCALAR(ideConfig
);
575 // Serialize internal state
576 SERIALIZE_SCALAR(ioEnabled
);
577 SERIALIZE_SCALAR(bmEnabled
);
578 SERIALIZE_SCALAR(bmiAddr
);
579 SERIALIZE_SCALAR(bmiSize
);
583 IdeController::Channel::serialize(const std::string
&base
,
584 CheckpointOut
&cp
) const
586 paramOut(cp
, base
+ ".cmdAddr", cmdAddr
);
587 paramOut(cp
, base
+ ".cmdSize", cmdSize
);
588 paramOut(cp
, base
+ ".ctrlAddr", ctrlAddr
);
589 paramOut(cp
, base
+ ".ctrlSize", ctrlSize
);
590 uint8_t command
= bmiRegs
.command
;
591 paramOut(cp
, base
+ ".bmiRegs.command", command
);
592 paramOut(cp
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
593 uint8_t status
= bmiRegs
.status
;
594 paramOut(cp
, base
+ ".bmiRegs.status", status
);
595 paramOut(cp
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
596 paramOut(cp
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
597 paramOut(cp
, base
+ ".selectBit", selectBit
);
601 IdeController::unserialize(CheckpointIn
&cp
)
603 // Unserialize the PciDevice base class
604 PciDevice::unserialize(cp
);
606 // Unserialize channels
607 primary
.unserialize("primary", cp
);
608 secondary
.unserialize("secondary", cp
);
610 // Unserialize config registers
611 UNSERIALIZE_SCALAR(primaryTiming
);
612 UNSERIALIZE_SCALAR(secondaryTiming
);
613 UNSERIALIZE_SCALAR(deviceTiming
);
614 UNSERIALIZE_SCALAR(udmaControl
);
615 UNSERIALIZE_SCALAR(udmaTiming
);
616 UNSERIALIZE_SCALAR(ideConfig
);
618 // Unserialize internal state
619 UNSERIALIZE_SCALAR(ioEnabled
);
620 UNSERIALIZE_SCALAR(bmEnabled
);
621 UNSERIALIZE_SCALAR(bmiAddr
);
622 UNSERIALIZE_SCALAR(bmiSize
);
626 IdeController::Channel::unserialize(const std::string
&base
, CheckpointIn
&cp
)
628 paramIn(cp
, base
+ ".cmdAddr", cmdAddr
);
629 paramIn(cp
, base
+ ".cmdSize", cmdSize
);
630 paramIn(cp
, base
+ ".ctrlAddr", ctrlAddr
);
631 paramIn(cp
, base
+ ".ctrlSize", ctrlSize
);
633 paramIn(cp
, base
+".bmiRegs.command", command
);
634 bmiRegs
.command
= command
;
635 paramIn(cp
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
637 paramIn(cp
, base
+ ".bmiRegs.status", status
);
638 bmiRegs
.status
= status
;
639 paramIn(cp
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
640 paramIn(cp
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
641 paramIn(cp
, base
+ ".selectBit", selectBit
);
646 IdeControllerParams::create()
648 return new IdeController(this);