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.
41 #include "dev/storage/ide_ctrl.hh"
45 #include "cpu/intr_control.hh"
46 #include "debug/IdeCtrl.hh"
47 #include "dev/storage/ide_disk.hh"
48 #include "mem/packet.hh"
49 #include "mem/packet_access.hh"
50 #include "params/IdeController.hh"
51 #include "sim/byteswap.hh"
53 // clang complains about std::set being overloaded with Packet::set if
54 // we open up the entire namespace std
57 // Bus master IDE registers
64 // PCI config space registers
67 SecondaryTiming
= 0x42,
74 static const uint16_t timeRegWithDecodeEn
= 0x8000;
76 IdeController::Channel::Channel(string newName
) : _name(newName
)
79 bmiRegs
.status
.dmaCap0
= 1;
80 bmiRegs
.status
.dmaCap1
= 1;
83 IdeController::IdeController(const Params
&p
)
84 : PciDevice(p
), primary(name() + ".primary"),
85 secondary(name() + ".secondary"),
86 primaryTiming(htole(timeRegWithDecodeEn
)),
87 secondaryTiming(htole(timeRegWithDecodeEn
)),
88 ioShift(p
.io_shift
), ctrlOffset(p
.ctrl_offset
)
91 // Assign the disks to channels
92 for (int i
= 0; i
< params().disks
.size(); i
++) {
93 if (!params().disks
[i
])
97 primary
.device0
= params().disks
[0];
100 primary
.device1
= params().disks
[1];
103 secondary
.device0
= params().disks
[2];
106 secondary
.device1
= params().disks
[3];
109 panic("IDE controllers support a maximum "
110 "of 4 devices attached!\n");
112 // Arbitrarily set the chunk size to 4K.
113 params().disks
[i
]->setController(this, 4 * 1024);
116 primary
.select(false);
117 secondary
.select(false);
121 IdeController::isDiskSelected(IdeDisk
*diskPtr
)
123 return (primary
.selected
== diskPtr
|| secondary
.selected
== diskPtr
);
127 IdeController::intrPost()
129 primary
.bmiRegs
.status
.intStatus
= 1;
130 PciDevice::intrPost();
134 IdeController::setDmaComplete(IdeDisk
*disk
)
137 if (disk
== primary
.device0
|| disk
== primary
.device1
) {
139 } else if (disk
== secondary
.device0
|| disk
== secondary
.device1
) {
140 channel
= &secondary
;
142 panic("Unable to find disk based on pointer %#x\n", disk
);
145 channel
->bmiRegs
.command
.startStop
= 0;
146 channel
->bmiRegs
.status
.active
= 0;
147 channel
->bmiRegs
.status
.intStatus
= 1;
151 IdeController::readConfig(PacketPtr pkt
)
153 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
154 if (offset
< PCI_DEVICE_SPECIFIC
) {
155 return PciDevice::readConfig(pkt
);
158 switch (pkt
->getSize()) {
159 case sizeof(uint8_t):
162 pkt
->setLE
<uint8_t>(deviceTiming
);
165 pkt
->setLE
<uint8_t>(udmaControl
);
167 case PrimaryTiming
+ 1:
168 pkt
->setLE
<uint8_t>(bits(htole(primaryTiming
), 15, 8));
170 case SecondaryTiming
+ 1:
171 pkt
->setLE
<uint8_t>(bits(htole(secondaryTiming
), 15, 8));
174 pkt
->setLE
<uint8_t>(bits(htole(ideConfig
), 7, 0));
177 pkt
->setLE
<uint8_t>(bits(htole(ideConfig
), 15, 8));
180 panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
183 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 1 data: %#x\n", offset
,
184 (uint32_t)pkt
->getLE
<uint8_t>());
186 case sizeof(uint16_t):
189 pkt
->setLE
<uint16_t>(udmaControl
);
192 pkt
->setLE
<uint16_t>(primaryTiming
);
194 case SecondaryTiming
:
195 pkt
->setLE
<uint16_t>(secondaryTiming
);
198 pkt
->setLE
<uint16_t>(udmaTiming
);
201 pkt
->setLE
<uint16_t>(ideConfig
);
204 panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
207 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 2 data: %#x\n", offset
,
208 (uint32_t)pkt
->getLE
<uint16_t>());
210 case sizeof(uint32_t):
213 pkt
->setLE
<uint32_t>(primaryTiming
);
216 pkt
->setLE
<uint32_t>(ideConfig
);
219 panic("No 32bit reads implemented for this device.");
221 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 4 data: %#x\n", offset
,
222 (uint32_t)pkt
->getLE
<uint32_t>());
225 panic("invalid access size(?) for PCI configspace!\n");
227 pkt
->makeAtomicResponse();
233 IdeController::writeConfig(PacketPtr pkt
)
235 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
236 if (offset
< PCI_DEVICE_SPECIFIC
) {
237 PciDevice::writeConfig(pkt
);
239 switch (pkt
->getSize()) {
240 case sizeof(uint8_t):
243 deviceTiming
= pkt
->getLE
<uint8_t>();
246 udmaControl
= pkt
->getLE
<uint8_t>();
249 replaceBits(ideConfig
, 7, 0, pkt
->getLE
<uint8_t>());
252 replaceBits(ideConfig
, 15, 8, pkt
->getLE
<uint8_t>());
255 panic("Invalid PCI configuration write "
256 "for size 1 offset: %#x!\n", offset
);
258 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 1 data: %#x\n",
259 offset
, (uint32_t)pkt
->getLE
<uint8_t>());
261 case sizeof(uint16_t):
264 udmaControl
= pkt
->getLE
<uint16_t>();
267 primaryTiming
= pkt
->getLE
<uint16_t>();
269 case SecondaryTiming
:
270 secondaryTiming
= pkt
->getLE
<uint16_t>();
273 udmaTiming
= pkt
->getLE
<uint16_t>();
276 ideConfig
= pkt
->getLE
<uint16_t>();
279 panic("Invalid PCI configuration write "
280 "for size 2 offset: %#x!\n",
283 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 2 data: %#x\n",
284 offset
, (uint32_t)pkt
->getLE
<uint16_t>());
286 case sizeof(uint32_t):
289 primaryTiming
= pkt
->getLE
<uint32_t>();
292 ideConfig
= pkt
->getLE
<uint32_t>();
295 panic("Write of unimplemented PCI config. register: %x\n", offset
);
299 panic("invalid access size(?) for PCI configspace!\n");
301 pkt
->makeAtomicResponse();
307 IdeController::Channel::accessCommand(Addr offset
,
308 int size
, uint8_t *data
, bool read
)
310 const Addr SelectOffset
= 6;
311 const uint8_t SelectDevBit
= 0x10;
313 if (!read
&& offset
== SelectOffset
)
314 select(*data
& SelectDevBit
);
316 if (selected
== NULL
) {
317 assert(size
== sizeof(uint8_t));
320 selected
->readCommand(offset
, size
, data
);
322 selected
->writeCommand(offset
, size
, data
);
327 IdeController::Channel::accessControl(Addr offset
,
328 int size
, uint8_t *data
, bool read
)
330 if (selected
== NULL
) {
331 assert(size
== sizeof(uint8_t));
334 selected
->readControl(offset
, size
, data
);
336 selected
->writeControl(offset
, size
, data
);
341 IdeController::Channel::accessBMI(Addr offset
,
342 int size
, uint8_t *data
, bool read
)
344 assert(offset
+ size
<= sizeof(BMIRegs
));
346 memcpy(data
, (uint8_t *)&bmiRegs
+ offset
, size
);
351 if (size
!= sizeof(uint8_t))
352 panic("Invalid BMIC write size: %x\n", size
);
354 BMICommandReg oldVal
= bmiRegs
.command
;
355 BMICommandReg newVal
= *data
;
357 // if a DMA transfer is in progress, R/W control cannot change
358 if (oldVal
.startStop
&& oldVal
.rw
!= newVal
.rw
)
359 oldVal
.rw
= newVal
.rw
;
361 if (oldVal
.startStop
!= newVal
.startStop
) {
362 if (selected
== NULL
)
363 panic("DMA start for disk which does not exist\n");
365 if (oldVal
.startStop
) {
366 DPRINTF(IdeCtrl
, "Stopping DMA transfer\n");
367 bmiRegs
.status
.active
= 0;
369 selected
->abortDma();
371 DPRINTF(IdeCtrl
, "Starting DMA transfer\n");
372 bmiRegs
.status
.active
= 1;
374 selected
->startDma(letoh(bmiRegs
.bmidtp
));
378 bmiRegs
.command
= newVal
;
383 if (size
!= sizeof(uint8_t))
384 panic("Invalid BMIS write size: %x\n", size
);
386 BMIStatusReg oldVal
= bmiRegs
.status
;
387 BMIStatusReg newVal
= *data
;
389 // the BMIDEA bit is read only
390 newVal
.active
= oldVal
.active
;
392 // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
393 if ((oldVal
.intStatus
== 1) && (newVal
.intStatus
== 1)) {
394 newVal
.intStatus
= 0; // clear the interrupt?
396 // Assigning two bitunion fields to each other does not
397 // work as intended, so we need to use this temporary variable
398 // to get around the bug.
399 uint8_t tmp
= oldVal
.intStatus
;
400 newVal
.intStatus
= tmp
;
402 if ((oldVal
.dmaError
== 1) && (newVal
.dmaError
== 1)) {
405 uint8_t tmp
= oldVal
.dmaError
;
406 newVal
.dmaError
= tmp
;
409 bmiRegs
.status
= newVal
;
412 case BMIDescTablePtr
:
413 if (size
!= sizeof(uint32_t))
414 panic("Invalid BMIDTP write size: %x\n", size
);
415 bmiRegs
.bmidtp
= htole(*(uint32_t *)data
& ~0x3);
418 if (size
!= sizeof(uint8_t) && size
!= sizeof(uint16_t) &&
419 size
!= sizeof(uint32_t))
420 panic("IDE controller write of invalid write size: %x\n", size
);
421 memcpy((uint8_t *)&bmiRegs
+ offset
, data
, size
);
427 IdeController::dispatchAccess(PacketPtr pkt
, bool read
)
429 if (pkt
->getSize() != 1 && pkt
->getSize() != 2 && pkt
->getSize() !=4)
430 panic("Bad IDE read size: %d\n", pkt
->getSize());
432 Addr addr
= pkt
->getAddr();
433 int size
= pkt
->getSize();
434 uint8_t *dataPtr
= pkt
->getPtr
<uint8_t>();
438 panic_if(!getBAR(addr
, bar_num
, offset
),
439 "IDE controller access to invalid address: %#x.", addr
);
443 // linux may have shifted the address by ioShift,
444 // here we shift it back, similarly for ctrlOffset.
446 primary
.accessCommand(offset
, size
, dataPtr
, read
);
449 offset
+= ctrlOffset
;
450 primary
.accessControl(offset
, size
, dataPtr
, read
);
453 secondary
.accessCommand(offset
, size
, dataPtr
, read
);
456 secondary
.accessControl(offset
, size
, dataPtr
, read
);
460 PciCommandRegister command
= letoh(config
.command
);
461 if (!read
&& !command
.busMaster
)
464 if (offset
< sizeof(Channel::BMIRegs
)) {
465 primary
.accessBMI(offset
, size
, dataPtr
, read
);
467 offset
-= sizeof(Channel::BMIRegs
);
468 secondary
.accessBMI(offset
, size
, dataPtr
, read
);
475 if (pkt
->getSize() == 1)
476 data
= pkt
->getLE
<uint8_t>();
477 else if (pkt
->getSize() == 2)
478 data
= pkt
->getLE
<uint16_t>();
480 data
= pkt
->getLE
<uint32_t>();
481 DPRINTF(IdeCtrl
, "%s from offset: %#x size: %#x data: %#x\n",
482 read
? "Read" : "Write", pkt
->getAddr(), pkt
->getSize(), data
);
485 pkt
->makeAtomicResponse();
489 IdeController::read(PacketPtr pkt
)
491 dispatchAccess(pkt
, true);
496 IdeController::write(PacketPtr pkt
)
498 dispatchAccess(pkt
, false);
503 IdeController::serialize(CheckpointOut
&cp
) const
505 // Serialize the PciDevice base class
506 PciDevice::serialize(cp
);
508 // Serialize channels
509 primary
.serialize("primary", cp
);
510 secondary
.serialize("secondary", cp
);
512 // Serialize config registers
513 SERIALIZE_SCALAR(primaryTiming
);
514 SERIALIZE_SCALAR(secondaryTiming
);
515 SERIALIZE_SCALAR(deviceTiming
);
516 SERIALIZE_SCALAR(udmaControl
);
517 SERIALIZE_SCALAR(udmaTiming
);
518 SERIALIZE_SCALAR(ideConfig
);
522 IdeController::Channel::serialize(const std::string
&base
,
523 CheckpointOut
&cp
) const
525 uint8_t command
= bmiRegs
.command
;
526 paramOut(cp
, base
+ ".bmiRegs.command", command
);
527 paramOut(cp
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
528 uint8_t status
= bmiRegs
.status
;
529 paramOut(cp
, base
+ ".bmiRegs.status", status
);
530 paramOut(cp
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
531 paramOut(cp
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
532 paramOut(cp
, base
+ ".selectBit", selectBit
);
536 IdeController::unserialize(CheckpointIn
&cp
)
538 // Unserialize the PciDevice base class
539 PciDevice::unserialize(cp
);
541 // Unserialize channels
542 primary
.unserialize("primary", cp
);
543 secondary
.unserialize("secondary", cp
);
545 // Unserialize config registers
546 UNSERIALIZE_SCALAR(primaryTiming
);
547 UNSERIALIZE_SCALAR(secondaryTiming
);
548 UNSERIALIZE_SCALAR(deviceTiming
);
549 UNSERIALIZE_SCALAR(udmaControl
);
550 UNSERIALIZE_SCALAR(udmaTiming
);
551 UNSERIALIZE_SCALAR(ideConfig
);
555 IdeController::Channel::unserialize(const std::string
&base
, CheckpointIn
&cp
)
558 paramIn(cp
, base
+".bmiRegs.command", command
);
559 bmiRegs
.command
= command
;
560 paramIn(cp
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
562 paramIn(cp
, base
+ ".bmiRegs.status", status
);
563 bmiRegs
.status
= status
;
564 paramIn(cp
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
565 paramIn(cp
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
566 paramIn(cp
, base
+ ".selectBit", selectBit
);
571 IdeControllerParams::create() const
573 return new IdeController(*this);