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
45 #include "dev/storage/ide_ctrl.hh"
49 #include "cpu/intr_control.hh"
50 #include "debug/IdeCtrl.hh"
51 #include "dev/storage/ide_disk.hh"
52 #include "mem/packet.hh"
53 #include "mem/packet_access.hh"
54 #include "params/IdeController.hh"
55 #include "sim/byteswap.hh"
57 // clang complains about std::set being overloaded with Packet::set if
58 // we open up the entire namespace std
61 // Bus master IDE registers
68 // PCI config space registers
71 SecondaryTiming
= 0x42,
78 static const uint16_t timeRegWithDecodeEn
= 0x8000;
80 IdeController::Channel::Channel(
81 string newName
, Addr _cmdSize
, Addr _ctrlSize
) :
83 cmdAddr(0), cmdSize(_cmdSize
), ctrlAddr(0), ctrlSize(_ctrlSize
),
84 master(NULL
), slave(NULL
), selected(NULL
)
86 memset(&bmiRegs
, 0, sizeof(bmiRegs
));
87 bmiRegs
.status
.dmaCap0
= 1;
88 bmiRegs
.status
.dmaCap1
= 1;
91 IdeController::Channel::~Channel()
95 IdeController::IdeController(Params
*p
)
96 : PciDevice(p
), primary(name() + ".primary", BARSize
[0], BARSize
[1]),
97 secondary(name() + ".secondary", BARSize
[2], BARSize
[3]),
98 bmiAddr(0), bmiSize(BARSize
[4]),
99 primaryTiming(htole(timeRegWithDecodeEn
)),
100 secondaryTiming(htole(timeRegWithDecodeEn
)),
101 deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
102 ioEnabled(false), bmEnabled(false),
103 ioShift(p
->io_shift
), ctrlOffset(p
->ctrl_offset
)
105 if (params()->disks
.size() > 3)
106 panic("IDE controllers support a maximum of 4 devices attached!\n");
108 // Assign the disks to channels
109 int numDisks
= params()->disks
.size();
111 primary
.master
= params()->disks
[0];
113 primary
.slave
= params()->disks
[1];
115 secondary
.master
= params()->disks
[2];
117 secondary
.slave
= params()->disks
[3];
119 for (int i
= 0; i
< params()->disks
.size(); i
++) {
120 params()->disks
[i
]->setController(this);
122 primary
.select(false);
123 secondary
.select(false);
125 if ((BARAddrs
[0] & ~BAR_IO_MASK
) && (!legacyIO
[0] || ioShift
)) {
126 primary
.cmdAddr
= BARAddrs
[0]; primary
.cmdSize
= BARSize
[0];
127 primary
.ctrlAddr
= BARAddrs
[1]; primary
.ctrlSize
= BARSize
[1];
129 if ((BARAddrs
[2] & ~BAR_IO_MASK
) && (!legacyIO
[2] || ioShift
)) {
130 secondary
.cmdAddr
= BARAddrs
[2]; secondary
.cmdSize
= BARSize
[2];
131 secondary
.ctrlAddr
= BARAddrs
[3]; secondary
.ctrlSize
= BARSize
[3];
134 ioEnabled
= (config
.command
& htole(PCI_CMD_IOSE
));
135 bmEnabled
= (config
.command
& htole(PCI_CMD_BME
));
139 IdeController::isDiskSelected(IdeDisk
*diskPtr
)
141 return (primary
.selected
== diskPtr
|| secondary
.selected
== diskPtr
);
145 IdeController::intrPost()
147 primary
.bmiRegs
.status
.intStatus
= 1;
148 PciDevice::intrPost();
152 IdeController::setDmaComplete(IdeDisk
*disk
)
155 if (disk
== primary
.master
|| disk
== primary
.slave
) {
157 } else if (disk
== secondary
.master
|| disk
== secondary
.slave
) {
158 channel
= &secondary
;
160 panic("Unable to find disk based on pointer %#x\n", disk
);
163 channel
->bmiRegs
.command
.startStop
= 0;
164 channel
->bmiRegs
.status
.active
= 0;
165 channel
->bmiRegs
.status
.intStatus
= 1;
169 IdeController::readConfig(PacketPtr pkt
)
171 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
172 if (offset
< PCI_DEVICE_SPECIFIC
) {
173 return PciDevice::readConfig(pkt
);
176 switch (pkt
->getSize()) {
177 case sizeof(uint8_t):
180 pkt
->set
<uint8_t>(deviceTiming
);
183 pkt
->set
<uint8_t>(udmaControl
);
185 case PrimaryTiming
+ 1:
186 pkt
->set
<uint8_t>(bits(htole(primaryTiming
), 15, 8));
188 case SecondaryTiming
+ 1:
189 pkt
->set
<uint8_t>(bits(htole(secondaryTiming
), 15, 8));
192 pkt
->set
<uint8_t>(bits(htole(ideConfig
), 7, 0));
195 pkt
->set
<uint8_t>(bits(htole(ideConfig
), 15, 8));
198 panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
201 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 1 data: %#x\n", offset
,
202 (uint32_t)pkt
->get
<uint8_t>());
204 case sizeof(uint16_t):
207 pkt
->set
<uint16_t>(udmaControl
);
210 pkt
->set
<uint16_t>(primaryTiming
);
212 case SecondaryTiming
:
213 pkt
->set
<uint16_t>(secondaryTiming
);
216 pkt
->set
<uint16_t>(udmaTiming
);
219 pkt
->set
<uint16_t>(ideConfig
);
222 panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
225 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 2 data: %#x\n", offset
,
226 (uint32_t)pkt
->get
<uint16_t>());
228 case sizeof(uint32_t):
231 pkt
->set
<uint32_t>(primaryTiming
);
234 pkt
->set
<uint32_t>(ideConfig
);
237 panic("No 32bit reads implemented for this device.");
239 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 4 data: %#x\n", offset
,
240 (uint32_t)pkt
->get
<uint32_t>());
243 panic("invalid access size(?) for PCI configspace!\n");
245 pkt
->makeAtomicResponse();
251 IdeController::writeConfig(PacketPtr pkt
)
253 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
254 if (offset
< PCI_DEVICE_SPECIFIC
) {
255 PciDevice::writeConfig(pkt
);
257 switch (pkt
->getSize()) {
258 case sizeof(uint8_t):
261 deviceTiming
= pkt
->get
<uint8_t>();
264 udmaControl
= pkt
->get
<uint8_t>();
267 replaceBits(ideConfig
, 7, 0, pkt
->get
<uint8_t>());
270 replaceBits(ideConfig
, 15, 8, pkt
->get
<uint8_t>());
273 panic("Invalid PCI configuration write "
274 "for size 1 offset: %#x!\n", offset
);
276 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 1 data: %#x\n",
277 offset
, (uint32_t)pkt
->get
<uint8_t>());
279 case sizeof(uint16_t):
282 udmaControl
= pkt
->get
<uint16_t>();
285 primaryTiming
= pkt
->get
<uint16_t>();
287 case SecondaryTiming
:
288 secondaryTiming
= pkt
->get
<uint16_t>();
291 udmaTiming
= pkt
->get
<uint16_t>();
294 ideConfig
= pkt
->get
<uint16_t>();
297 panic("Invalid PCI configuration write "
298 "for size 2 offset: %#x!\n",
301 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 2 data: %#x\n",
302 offset
, (uint32_t)pkt
->get
<uint16_t>());
304 case sizeof(uint32_t):
307 primaryTiming
= pkt
->get
<uint32_t>();
310 ideConfig
= pkt
->get
<uint32_t>();
313 panic("Write of unimplemented PCI config. register: %x\n", offset
);
317 panic("invalid access size(?) for PCI configspace!\n");
319 pkt
->makeAtomicResponse();
322 /* Trap command register writes and enable IO/BM as appropriate as well as
325 case PCI0_BASE_ADDR0
:
326 if (BARAddrs
[0] != 0)
327 primary
.cmdAddr
= BARAddrs
[0];
330 case PCI0_BASE_ADDR1
:
331 if (BARAddrs
[1] != 0)
332 primary
.ctrlAddr
= BARAddrs
[1];
335 case PCI0_BASE_ADDR2
:
336 if (BARAddrs
[2] != 0)
337 secondary
.cmdAddr
= BARAddrs
[2];
340 case PCI0_BASE_ADDR3
:
341 if (BARAddrs
[3] != 0)
342 secondary
.ctrlAddr
= BARAddrs
[3];
345 case PCI0_BASE_ADDR4
:
346 if (BARAddrs
[4] != 0)
347 bmiAddr
= BARAddrs
[4];
351 DPRINTF(IdeCtrl
, "Writing to PCI Command val: %#x\n", config
.command
);
352 ioEnabled
= (config
.command
& htole(PCI_CMD_IOSE
));
353 bmEnabled
= (config
.command
& htole(PCI_CMD_BME
));
360 IdeController::Channel::accessCommand(Addr offset
,
361 int size
, uint8_t *data
, bool read
)
363 const Addr SelectOffset
= 6;
364 const uint8_t SelectDevBit
= 0x10;
366 if (!read
&& offset
== SelectOffset
)
367 select(*data
& SelectDevBit
);
369 if (selected
== NULL
) {
370 assert(size
== sizeof(uint8_t));
373 selected
->readCommand(offset
, size
, data
);
375 selected
->writeCommand(offset
, size
, data
);
380 IdeController::Channel::accessControl(Addr offset
,
381 int size
, uint8_t *data
, bool read
)
383 if (selected
== NULL
) {
384 assert(size
== sizeof(uint8_t));
387 selected
->readControl(offset
, size
, data
);
389 selected
->writeControl(offset
, size
, data
);
394 IdeController::Channel::accessBMI(Addr offset
,
395 int size
, uint8_t *data
, bool read
)
397 assert(offset
+ size
<= sizeof(BMIRegs
));
399 memcpy(data
, (uint8_t *)&bmiRegs
+ offset
, size
);
404 if (size
!= sizeof(uint8_t))
405 panic("Invalid BMIC write size: %x\n", size
);
407 BMICommandReg oldVal
= bmiRegs
.command
;
408 BMICommandReg newVal
= *data
;
410 // if a DMA transfer is in progress, R/W control cannot change
411 if (oldVal
.startStop
&& oldVal
.rw
!= newVal
.rw
)
412 oldVal
.rw
= newVal
.rw
;
414 if (oldVal
.startStop
!= newVal
.startStop
) {
415 if (selected
== NULL
)
416 panic("DMA start for disk which does not exist\n");
418 if (oldVal
.startStop
) {
419 DPRINTF(IdeCtrl
, "Stopping DMA transfer\n");
420 bmiRegs
.status
.active
= 0;
422 selected
->abortDma();
424 DPRINTF(IdeCtrl
, "Starting DMA transfer\n");
425 bmiRegs
.status
.active
= 1;
427 selected
->startDma(letoh(bmiRegs
.bmidtp
));
431 bmiRegs
.command
= newVal
;
436 if (size
!= sizeof(uint8_t))
437 panic("Invalid BMIS write size: %x\n", size
);
439 BMIStatusReg oldVal
= bmiRegs
.status
;
440 BMIStatusReg newVal
= *data
;
442 // the BMIDEA bit is read only
443 newVal
.active
= oldVal
.active
;
445 // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
446 if ((oldVal
.intStatus
== 1) && (newVal
.intStatus
== 1)) {
447 newVal
.intStatus
= 0; // clear the interrupt?
449 // Assigning two bitunion fields to each other does not
450 // work as intended, so we need to use this temporary variable
451 // to get around the bug.
452 uint8_t tmp
= oldVal
.intStatus
;
453 newVal
.intStatus
= tmp
;
455 if ((oldVal
.dmaError
== 1) && (newVal
.dmaError
== 1)) {
458 uint8_t tmp
= oldVal
.dmaError
;
459 newVal
.dmaError
= tmp
;
462 bmiRegs
.status
= newVal
;
465 case BMIDescTablePtr
:
466 if (size
!= sizeof(uint32_t))
467 panic("Invalid BMIDTP write size: %x\n", size
);
468 bmiRegs
.bmidtp
= htole(*(uint32_t *)data
& ~0x3);
471 if (size
!= sizeof(uint8_t) && size
!= sizeof(uint16_t) &&
472 size
!= sizeof(uint32_t))
473 panic("IDE controller write of invalid write size: %x\n", size
);
474 memcpy((uint8_t *)&bmiRegs
+ offset
, data
, size
);
480 IdeController::dispatchAccess(PacketPtr pkt
, bool read
)
482 if (pkt
->getSize() != 1 && pkt
->getSize() != 2 && pkt
->getSize() !=4)
483 panic("Bad IDE read size: %d\n", pkt
->getSize());
486 pkt
->makeAtomicResponse();
487 DPRINTF(IdeCtrl
, "io not enabled\n");
491 Addr addr
= pkt
->getAddr();
492 int size
= pkt
->getSize();
493 uint8_t *dataPtr
= pkt
->getPtr
<uint8_t>();
495 if (addr
>= primary
.cmdAddr
&&
496 addr
< (primary
.cmdAddr
+ primary
.cmdSize
)) {
497 addr
-= primary
.cmdAddr
;
498 // linux may have shifted the address by ioShift,
499 // here we shift it back, similarly for ctrlOffset.
501 primary
.accessCommand(addr
, size
, dataPtr
, read
);
502 } else if (addr
>= primary
.ctrlAddr
&&
503 addr
< (primary
.ctrlAddr
+ primary
.ctrlSize
)) {
504 addr
-= primary
.ctrlAddr
;
506 primary
.accessControl(addr
, size
, dataPtr
, read
);
507 } else if (addr
>= secondary
.cmdAddr
&&
508 addr
< (secondary
.cmdAddr
+ secondary
.cmdSize
)) {
509 addr
-= secondary
.cmdAddr
;
510 secondary
.accessCommand(addr
, size
, dataPtr
, read
);
511 } else if (addr
>= secondary
.ctrlAddr
&&
512 addr
< (secondary
.ctrlAddr
+ secondary
.ctrlSize
)) {
513 addr
-= secondary
.ctrlAddr
;
514 secondary
.accessControl(addr
, size
, dataPtr
, read
);
515 } else if (addr
>= bmiAddr
&& addr
< (bmiAddr
+ bmiSize
)) {
516 if (!read
&& !bmEnabled
)
519 if (addr
< sizeof(Channel::BMIRegs
)) {
520 primary
.accessBMI(addr
, size
, dataPtr
, read
);
522 addr
-= sizeof(Channel::BMIRegs
);
523 secondary
.accessBMI(addr
, size
, dataPtr
, read
);
526 panic("IDE controller access to invalid address: %#x\n", addr
);
531 if (pkt
->getSize() == 1)
532 data
= pkt
->get
<uint8_t>();
533 else if (pkt
->getSize() == 2)
534 data
= pkt
->get
<uint16_t>();
536 data
= pkt
->get
<uint32_t>();
537 DPRINTF(IdeCtrl
, "%s from offset: %#x size: %#x data: %#x\n",
538 read
? "Read" : "Write", pkt
->getAddr(), pkt
->getSize(), data
);
541 pkt
->makeAtomicResponse();
545 IdeController::read(PacketPtr pkt
)
547 dispatchAccess(pkt
, true);
552 IdeController::write(PacketPtr pkt
)
554 dispatchAccess(pkt
, false);
559 IdeController::serialize(CheckpointOut
&cp
) const
561 // Serialize the PciDevice base class
562 PciDevice::serialize(cp
);
564 // Serialize channels
565 primary
.serialize("primary", cp
);
566 secondary
.serialize("secondary", cp
);
568 // Serialize config registers
569 SERIALIZE_SCALAR(primaryTiming
);
570 SERIALIZE_SCALAR(secondaryTiming
);
571 SERIALIZE_SCALAR(deviceTiming
);
572 SERIALIZE_SCALAR(udmaControl
);
573 SERIALIZE_SCALAR(udmaTiming
);
574 SERIALIZE_SCALAR(ideConfig
);
576 // Serialize internal state
577 SERIALIZE_SCALAR(ioEnabled
);
578 SERIALIZE_SCALAR(bmEnabled
);
579 SERIALIZE_SCALAR(bmiAddr
);
580 SERIALIZE_SCALAR(bmiSize
);
584 IdeController::Channel::serialize(const std::string
&base
,
585 CheckpointOut
&cp
) const
587 paramOut(cp
, base
+ ".cmdAddr", cmdAddr
);
588 paramOut(cp
, base
+ ".cmdSize", cmdSize
);
589 paramOut(cp
, base
+ ".ctrlAddr", ctrlAddr
);
590 paramOut(cp
, base
+ ".ctrlSize", ctrlSize
);
591 uint8_t command
= bmiRegs
.command
;
592 paramOut(cp
, base
+ ".bmiRegs.command", command
);
593 paramOut(cp
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
594 uint8_t status
= bmiRegs
.status
;
595 paramOut(cp
, base
+ ".bmiRegs.status", status
);
596 paramOut(cp
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
597 paramOut(cp
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
598 paramOut(cp
, base
+ ".selectBit", selectBit
);
602 IdeController::unserialize(CheckpointIn
&cp
)
604 // Unserialize the PciDevice base class
605 PciDevice::unserialize(cp
);
607 // Unserialize channels
608 primary
.unserialize("primary", cp
);
609 secondary
.unserialize("secondary", cp
);
611 // Unserialize config registers
612 UNSERIALIZE_SCALAR(primaryTiming
);
613 UNSERIALIZE_SCALAR(secondaryTiming
);
614 UNSERIALIZE_SCALAR(deviceTiming
);
615 UNSERIALIZE_SCALAR(udmaControl
);
616 UNSERIALIZE_SCALAR(udmaTiming
);
617 UNSERIALIZE_SCALAR(ideConfig
);
619 // Unserialize internal state
620 UNSERIALIZE_SCALAR(ioEnabled
);
621 UNSERIALIZE_SCALAR(bmEnabled
);
622 UNSERIALIZE_SCALAR(bmiAddr
);
623 UNSERIALIZE_SCALAR(bmiSize
);
627 IdeController::Channel::unserialize(const std::string
&base
, CheckpointIn
&cp
)
629 paramIn(cp
, base
+ ".cmdAddr", cmdAddr
);
630 paramIn(cp
, base
+ ".cmdSize", cmdSize
);
631 paramIn(cp
, base
+ ".ctrlAddr", ctrlAddr
);
632 paramIn(cp
, base
+ ".ctrlSize", ctrlSize
);
634 paramIn(cp
, base
+".bmiRegs.command", command
);
635 bmiRegs
.command
= command
;
636 paramIn(cp
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
638 paramIn(cp
, base
+ ".bmiRegs.status", status
);
639 bmiRegs
.status
= status
;
640 paramIn(cp
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
641 paramIn(cp
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
642 paramIn(cp
, base
+ ".selectBit", selectBit
);
647 IdeControllerParams::create()
649 return new IdeController(this);