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 "debug/IdeCtrl.hh"
38 #include "dev/ide_ctrl.hh"
39 #include "dev/ide_disk.hh"
40 #include "mem/packet.hh"
41 #include "mem/packet_access.hh"
42 #include "params/IdeController.hh"
43 #include "sim/byteswap.hh"
47 // Bus master IDE registers
54 // PCI config space registers
57 SecondaryTiming
= 0x42,
64 static const uint16_t timeRegWithDecodeEn
= 0x8000;
66 IdeController::Channel::Channel(
67 string newName
, Addr _cmdSize
, Addr _ctrlSize
) :
69 cmdAddr(0), cmdSize(_cmdSize
), ctrlAddr(0), ctrlSize(_ctrlSize
),
70 master(NULL
), slave(NULL
), selected(NULL
)
72 memset(&bmiRegs
, 0, sizeof(bmiRegs
));
73 bmiRegs
.status
.dmaCap0
= 1;
74 bmiRegs
.status
.dmaCap1
= 1;
77 IdeController::Channel::~Channel()
81 IdeController::IdeController(Params
*p
)
82 : PciDev(p
), primary(name() + ".primary", BARSize
[0], BARSize
[1]),
83 secondary(name() + ".secondary", BARSize
[2], BARSize
[3]),
84 bmiAddr(0), bmiSize(BARSize
[4]),
85 primaryTiming(htole(timeRegWithDecodeEn
)),
86 secondaryTiming(htole(timeRegWithDecodeEn
)),
87 deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
88 ioEnabled(false), bmEnabled(false),
89 ioShift(p
->io_shift
), ctrlOffset(p
->ctrl_offset
)
91 if (params()->disks
.size() > 3)
92 panic("IDE controllers support a maximum of 4 devices attached!\n");
94 // Assign the disks to channels
95 int numDisks
= params()->disks
.size();
97 primary
.master
= params()->disks
[0];
99 primary
.slave
= params()->disks
[1];
101 secondary
.master
= params()->disks
[2];
103 secondary
.slave
= params()->disks
[3];
105 for (int i
= 0; i
< params()->disks
.size(); i
++) {
106 params()->disks
[i
]->setController(this);
108 primary
.select(false);
109 secondary
.select(false);
111 if ((BARAddrs
[0] & ~BAR_IO_MASK
) && (!legacyIO
[0] || ioShift
)) {
112 primary
.cmdAddr
= BARAddrs
[0]; primary
.cmdSize
= BARSize
[0];
113 primary
.ctrlAddr
= BARAddrs
[1]; primary
.ctrlSize
= BARAddrs
[1];
115 if ((BARAddrs
[2] & ~BAR_IO_MASK
) && (!legacyIO
[2] || ioShift
)) {
116 secondary
.cmdAddr
= BARAddrs
[2]; secondary
.cmdSize
= BARSize
[2];
117 secondary
.ctrlAddr
= BARAddrs
[3]; secondary
.ctrlSize
= BARAddrs
[3];
120 ioEnabled
= (config
.command
& htole(PCI_CMD_IOSE
));
121 bmEnabled
= (config
.command
& htole(PCI_CMD_BME
));
125 IdeController::isDiskSelected(IdeDisk
*diskPtr
)
127 return (primary
.selected
== diskPtr
|| secondary
.selected
== diskPtr
);
131 IdeController::intrPost()
133 primary
.bmiRegs
.status
.intStatus
= 1;
138 IdeController::setDmaComplete(IdeDisk
*disk
)
141 if (disk
== primary
.master
|| disk
== primary
.slave
) {
143 } else if (disk
== secondary
.master
|| disk
== secondary
.slave
) {
144 channel
= &secondary
;
146 panic("Unable to find disk based on pointer %#x\n", disk
);
149 channel
->bmiRegs
.command
.startStop
= 0;
150 channel
->bmiRegs
.status
.active
= 0;
151 channel
->bmiRegs
.status
.intStatus
= 1;
155 IdeController::readConfig(PacketPtr pkt
)
157 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
158 if (offset
< PCI_DEVICE_SPECIFIC
) {
159 return PciDev::readConfig(pkt
);
164 switch (pkt
->getSize()) {
165 case sizeof(uint8_t):
168 pkt
->set
<uint8_t>(deviceTiming
);
171 pkt
->set
<uint8_t>(udmaControl
);
173 case PrimaryTiming
+ 1:
174 pkt
->set
<uint8_t>(bits(htole(primaryTiming
), 15, 8));
176 case SecondaryTiming
+ 1:
177 pkt
->set
<uint8_t>(bits(htole(secondaryTiming
), 15, 8));
180 pkt
->set
<uint8_t>(bits(htole(ideConfig
), 7, 0));
183 pkt
->set
<uint8_t>(bits(htole(ideConfig
), 15, 8));
186 panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
189 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 1 data: %#x\n", offset
,
190 (uint32_t)pkt
->get
<uint8_t>());
192 case sizeof(uint16_t):
195 pkt
->set
<uint16_t>(primaryTiming
);
197 case SecondaryTiming
:
198 pkt
->set
<uint16_t>(secondaryTiming
);
201 pkt
->set
<uint16_t>(udmaTiming
);
204 pkt
->set
<uint16_t>(ideConfig
);
207 panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
210 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 2 data: %#x\n", offset
,
211 (uint32_t)pkt
->get
<uint16_t>());
213 case sizeof(uint32_t):
214 if (offset
== IDEConfig
)
215 pkt
->set
<uint32_t>(ideConfig
);
217 panic("No 32bit reads implemented for this device.");
218 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 4 data: %#x\n", offset
,
219 (uint32_t)pkt
->get
<uint32_t>());
222 panic("invalid access size(?) for PCI configspace!\n");
224 pkt
->makeAtomicResponse();
230 IdeController::writeConfig(PacketPtr pkt
)
232 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
233 if (offset
< PCI_DEVICE_SPECIFIC
) {
234 PciDev::writeConfig(pkt
);
236 switch (pkt
->getSize()) {
237 case sizeof(uint8_t):
240 deviceTiming
= pkt
->get
<uint8_t>();
243 udmaControl
= pkt
->get
<uint8_t>();
246 replaceBits(ideConfig
, 7, 0, pkt
->get
<uint8_t>());
249 replaceBits(ideConfig
, 15, 8, pkt
->get
<uint8_t>());
252 panic("Invalid PCI configuration write "
253 "for size 1 offset: %#x!\n", offset
);
255 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 1 data: %#x\n",
256 offset
, (uint32_t)pkt
->get
<uint8_t>());
258 case sizeof(uint16_t):
261 primaryTiming
= pkt
->get
<uint16_t>();
263 case SecondaryTiming
:
264 secondaryTiming
= pkt
->get
<uint16_t>();
267 udmaTiming
= pkt
->get
<uint16_t>();
270 ideConfig
= pkt
->get
<uint16_t>();
273 panic("Invalid PCI configuration write "
274 "for size 2 offset: %#x!\n",
277 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 2 data: %#x\n",
278 offset
, (uint32_t)pkt
->get
<uint16_t>());
280 case sizeof(uint32_t):
281 if (offset
== IDEConfig
)
282 ideConfig
= pkt
->get
<uint32_t>();
284 panic("Write of unimplemented PCI config. register: %x\n", offset
);
287 panic("invalid access size(?) for PCI configspace!\n");
289 pkt
->makeAtomicResponse();
292 /* Trap command register writes and enable IO/BM as appropriate as well as
295 case PCI0_BASE_ADDR0
:
296 if (BARAddrs
[0] != 0)
297 primary
.cmdAddr
= BARAddrs
[0];
300 case PCI0_BASE_ADDR1
:
301 if (BARAddrs
[1] != 0)
302 primary
.ctrlAddr
= BARAddrs
[1];
305 case PCI0_BASE_ADDR2
:
306 if (BARAddrs
[2] != 0)
307 secondary
.cmdAddr
= BARAddrs
[2];
310 case PCI0_BASE_ADDR3
:
311 if (BARAddrs
[3] != 0)
312 secondary
.ctrlAddr
= BARAddrs
[3];
315 case PCI0_BASE_ADDR4
:
316 if (BARAddrs
[4] != 0)
317 bmiAddr
= BARAddrs
[4];
321 DPRINTF(IdeCtrl
, "Writing to PCI Command val: %#x\n", config
.command
);
322 ioEnabled
= (config
.command
& htole(PCI_CMD_IOSE
));
323 bmEnabled
= (config
.command
& htole(PCI_CMD_BME
));
330 IdeController::Channel::accessCommand(Addr offset
,
331 int size
, uint8_t *data
, bool read
)
333 const Addr SelectOffset
= 6;
334 const uint8_t SelectDevBit
= 0x10;
336 if (!read
&& offset
== SelectOffset
)
337 select(*data
& SelectDevBit
);
339 if (selected
== NULL
) {
340 assert(size
== sizeof(uint8_t));
343 selected
->readCommand(offset
, size
, data
);
345 selected
->writeCommand(offset
, size
, data
);
350 IdeController::Channel::accessControl(Addr offset
,
351 int size
, uint8_t *data
, bool read
)
353 if (selected
== NULL
) {
354 assert(size
== sizeof(uint8_t));
357 selected
->readControl(offset
, size
, data
);
359 selected
->writeControl(offset
, size
, data
);
364 IdeController::Channel::accessBMI(Addr offset
,
365 int size
, uint8_t *data
, bool read
)
367 assert(offset
+ size
<= sizeof(BMIRegs
));
369 memcpy(data
, (uint8_t *)&bmiRegs
+ offset
, size
);
374 if (size
!= sizeof(uint8_t))
375 panic("Invalid BMIC write size: %x\n", size
);
377 BMICommandReg oldVal
= bmiRegs
.command
;
378 BMICommandReg newVal
= *data
;
380 // if a DMA transfer is in progress, R/W control cannot change
381 if (oldVal
.startStop
&& oldVal
.rw
!= newVal
.rw
)
382 oldVal
.rw
= newVal
.rw
;
384 if (oldVal
.startStop
!= newVal
.startStop
) {
385 if (selected
== NULL
)
386 panic("DMA start for disk which does not exist\n");
388 if (oldVal
.startStop
) {
389 DPRINTF(IdeCtrl
, "Stopping DMA transfer\n");
390 bmiRegs
.status
.active
= 0;
392 selected
->abortDma();
394 DPRINTF(IdeCtrl
, "Starting DMA transfer\n");
395 bmiRegs
.status
.active
= 1;
397 selected
->startDma(letoh(bmiRegs
.bmidtp
));
401 bmiRegs
.command
= newVal
;
406 if (size
!= sizeof(uint8_t))
407 panic("Invalid BMIS write size: %x\n", size
);
409 BMIStatusReg oldVal
= bmiRegs
.status
;
410 BMIStatusReg newVal
= *data
;
412 // the BMIDEA bit is read only
413 newVal
.active
= oldVal
.active
;
415 // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
416 if (oldVal
.intStatus
&& newVal
.intStatus
)
417 newVal
.intStatus
= 0; // clear the interrupt?
419 newVal
.intStatus
= oldVal
.intStatus
;
420 if (oldVal
.dmaError
&& newVal
.dmaError
)
423 newVal
.dmaError
= oldVal
.dmaError
;
425 bmiRegs
.status
= newVal
;
428 case BMIDescTablePtr
:
429 if (size
!= sizeof(uint32_t))
430 panic("Invalid BMIDTP write size: %x\n", size
);
431 bmiRegs
.bmidtp
= htole(*(uint32_t *)data
& ~0x3);
434 if (size
!= sizeof(uint8_t) && size
!= sizeof(uint16_t) &&
435 size
!= sizeof(uint32_t))
436 panic("IDE controller write of invalid write size: %x\n", size
);
437 memcpy((uint8_t *)&bmiRegs
+ offset
, data
, size
);
443 IdeController::dispatchAccess(PacketPtr pkt
, bool read
)
446 if (pkt
->getSize() != 1 && pkt
->getSize() != 2 && pkt
->getSize() !=4)
447 panic("Bad IDE read size: %d\n", pkt
->getSize());
450 pkt
->makeAtomicResponse();
451 DPRINTF(IdeCtrl
, "io not enabled\n");
455 Addr addr
= pkt
->getAddr();
456 int size
= pkt
->getSize();
457 uint8_t *dataPtr
= pkt
->getPtr
<uint8_t>();
459 if (addr
>= primary
.cmdAddr
&&
460 addr
< (primary
.cmdAddr
+ primary
.cmdSize
)) {
461 addr
-= primary
.cmdAddr
;
462 // linux may have shifted the address by ioShift,
463 // here we shift it back, similarly for ctrlOffset.
465 primary
.accessCommand(addr
, size
, dataPtr
, read
);
466 } else if (addr
>= primary
.ctrlAddr
&&
467 addr
< (primary
.ctrlAddr
+ primary
.ctrlSize
)) {
468 addr
-= primary
.ctrlAddr
;
470 primary
.accessControl(addr
, size
, dataPtr
, read
);
471 } else if (addr
>= secondary
.cmdAddr
&&
472 addr
< (secondary
.cmdAddr
+ secondary
.cmdSize
)) {
473 addr
-= secondary
.cmdAddr
;
474 secondary
.accessCommand(addr
, size
, dataPtr
, read
);
475 } else if (addr
>= secondary
.ctrlAddr
&&
476 addr
< (secondary
.ctrlAddr
+ secondary
.ctrlSize
)) {
477 addr
-= secondary
.ctrlAddr
;
478 secondary
.accessControl(addr
, size
, dataPtr
, read
);
479 } else if (addr
>= bmiAddr
&& addr
< (bmiAddr
+ bmiSize
)) {
480 if (!read
&& !bmEnabled
)
483 if (addr
< sizeof(Channel::BMIRegs
)) {
484 primary
.accessBMI(addr
, size
, dataPtr
, read
);
486 addr
-= sizeof(Channel::BMIRegs
);
487 secondary
.accessBMI(addr
, size
, dataPtr
, read
);
490 panic("IDE controller access to invalid address: %#x\n", addr
);
495 if (pkt
->getSize() == 1)
496 data
= pkt
->get
<uint8_t>();
497 else if (pkt
->getSize() == 2)
498 data
= pkt
->get
<uint16_t>();
500 data
= pkt
->get
<uint32_t>();
501 DPRINTF(IdeCtrl
, "%s from offset: %#x size: %#x data: %#x\n",
502 read
? "Read" : "Write", pkt
->getAddr(), pkt
->getSize(), data
);
505 pkt
->makeAtomicResponse();
509 IdeController::read(PacketPtr pkt
)
511 dispatchAccess(pkt
, true);
516 IdeController::write(PacketPtr pkt
)
518 dispatchAccess(pkt
, false);
523 IdeController::serialize(std::ostream
&os
)
525 // Serialize the PciDev base class
526 PciDev::serialize(os
);
528 // Serialize channels
529 primary
.serialize("primary", os
);
530 secondary
.serialize("secondary", os
);
532 // Serialize config registers
533 SERIALIZE_SCALAR(primaryTiming
);
534 SERIALIZE_SCALAR(secondaryTiming
);
535 SERIALIZE_SCALAR(deviceTiming
);
536 SERIALIZE_SCALAR(udmaControl
);
537 SERIALIZE_SCALAR(udmaTiming
);
538 SERIALIZE_SCALAR(ideConfig
);
540 // Serialize internal state
541 SERIALIZE_SCALAR(ioEnabled
);
542 SERIALIZE_SCALAR(bmEnabled
);
543 SERIALIZE_SCALAR(bmiAddr
);
544 SERIALIZE_SCALAR(bmiSize
);
548 IdeController::Channel::serialize(const std::string
&base
, std::ostream
&os
)
550 paramOut(os
, base
+ ".cmdAddr", cmdAddr
);
551 paramOut(os
, base
+ ".cmdSize", cmdSize
);
552 paramOut(os
, base
+ ".ctrlAddr", ctrlAddr
);
553 paramOut(os
, base
+ ".ctrlSize", ctrlSize
);
554 uint8_t command
= bmiRegs
.command
;
555 paramOut(os
, base
+ ".bmiRegs.command", command
);
556 paramOut(os
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
557 uint8_t status
= bmiRegs
.status
;
558 paramOut(os
, base
+ ".bmiRegs.status", status
);
559 paramOut(os
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
560 paramOut(os
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
561 paramOut(os
, base
+ ".selectBit", selectBit
);
565 IdeController::unserialize(Checkpoint
*cp
, const std::string
§ion
)
567 // Unserialize the PciDev base class
568 PciDev::unserialize(cp
, section
);
570 // Unserialize channels
571 primary
.unserialize("primary", cp
, section
);
572 secondary
.unserialize("secondary", cp
, section
);
574 // Unserialize config registers
575 UNSERIALIZE_SCALAR(primaryTiming
);
576 UNSERIALIZE_SCALAR(secondaryTiming
);
577 UNSERIALIZE_SCALAR(deviceTiming
);
578 UNSERIALIZE_SCALAR(udmaControl
);
579 UNSERIALIZE_SCALAR(udmaTiming
);
580 UNSERIALIZE_SCALAR(ideConfig
);
582 // Unserialize internal state
583 UNSERIALIZE_SCALAR(ioEnabled
);
584 UNSERIALIZE_SCALAR(bmEnabled
);
585 UNSERIALIZE_SCALAR(bmiAddr
);
586 UNSERIALIZE_SCALAR(bmiSize
);
590 IdeController::Channel::unserialize(const std::string
&base
, Checkpoint
*cp
,
591 const std::string
§ion
)
593 paramIn(cp
, section
, base
+ ".cmdAddr", cmdAddr
);
594 paramIn(cp
, section
, base
+ ".cmdSize", cmdSize
);
595 paramIn(cp
, section
, base
+ ".ctrlAddr", ctrlAddr
);
596 paramIn(cp
, section
, base
+ ".ctrlSize", ctrlSize
);
598 paramIn(cp
, section
, base
+".bmiRegs.command", command
);
599 bmiRegs
.command
= command
;
600 paramIn(cp
, section
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
602 paramIn(cp
, section
, base
+ ".bmiRegs.status", status
);
603 bmiRegs
.status
= status
;
604 paramIn(cp
, section
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
605 paramIn(cp
, section
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
606 paramIn(cp
, section
, base
+ ".selectBit", selectBit
);
611 IdeControllerParams::create()
613 return new IdeController(this);