From 3bfb59f70d4bf8ca7b9e6a0bdbcacdbbebf41403 Mon Sep 17 00:00:00 2001 From: Andrew Schultz Date: Tue, 11 May 2004 18:06:50 -0400 Subject: [PATCH] Changes to fix bad DMA handling by disk when using scatter gather page mappings (writes still unverified, and read could probably be looked over a bit more too) dev/ide_disk.cc: dev/ide_disk.hh: Major changes to fix bogus handling of dma transfers. The read seems to work pretty well, but the write is unverfied until we can get a disk image that actually tries to write. dev/tsunami_pchip.cc: Change mask to properly mask 13 bits not 12 --HG-- extra : convert_revision : 08fe9bc32970e449cd045de479553a96a4e389d6 --- dev/ide_disk.cc | 94 ++++++++++++++++++++++++++++++++++++++++++-- dev/ide_disk.hh | 2 + dev/tsunami_pchip.cc | 2 +- 3 files changed, 94 insertions(+), 4 deletions(-) diff --git a/dev/ide_disk.cc b/dev/ide_disk.cc index f4e73c833..38d6a919b 100644 --- a/dev/ide_disk.cc +++ b/dev/ide_disk.cc @@ -35,6 +35,7 @@ #include #include +#include "arch/alpha/pmap.h" #include "base/cprintf.hh" // csprintf #include "base/trace.hh" #include "dev/disk_image.hh" @@ -60,7 +61,7 @@ IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, dmaWriteWaitEvent(this), dmaPrdReadEvent(this), dmaReadEvent(this), dmaWriteEvent(this) { - diskDelay = (delay * ticksPerSecond / 1000) / image->size(); + diskDelay = (delay * ticksPerSecond / 100000); // initialize the data buffer and shadow registers dataBuffer = new uint8_t[MAX_DMA_SIZE]; @@ -153,6 +154,15 @@ IdeDisk::~IdeDisk() delete [] dataBuffer; } +Addr +IdeDisk::pciToDma(Addr &pciAddr) +{ + if (ctrl) + return ctrl->tsunami->pchip->translatePciToDma(pciAddr); + else + panic("Access to unset controller!\n"); +} + //// // Device registers read/write //// @@ -309,6 +319,51 @@ IdeDisk::doDmaRead() void IdeDisk::dmaReadDone() { + + Addr curAddr = 0, dmaAddr = 0; + uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0; + + // set initial address + curAddr = curPrd.getBaseAddr(); + + // clear out the data buffer + memset(dataBuffer, 0, MAX_DMA_SIZE); + + // read the data from memory via DMA into a data buffer + while (bytesWritten < curPrd.getByteCount()) { + if (cmdBytesLeft <= 0) + panic("DMA data is larger than # of sectors specified\n"); + + dmaAddr = pciToDma(curAddr); + + // calculate how many bytes are in the current page + bytesLeft = curPrd.getByteCount() - bytesWritten; + bytesInPage = (bytesLeft > ALPHA_PGBYTES) ? ALPHA_PGBYTES : bytesLeft; + // check to make sure we don't cross a page boundary + if ((curAddr + bytesInPage) > + (alpha_trunc_page(curAddr) + ALPHA_PGBYTES)) + + bytesInPage = alpha_round_page(curAddr) - curAddr; + + // copy the data from memory into the data buffer + /** @todo Use real DMA with interfaces here */ + memcpy((void *)(dataBuffer + bytesWritten), + physmem->dma_addr(dmaAddr, bytesInPage), + bytesInPage); + + curAddr += bytesInPage; + bytesWritten += bytesInPage; + cmdBytesLeft -= bytesInPage; + } + + // write the data to the disk image + for (bytesWritten = 0; + bytesWritten < curPrd.getByteCount(); + bytesWritten += SectorSize) + + writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); + +#if 0 // actually copy the data from memory to data buffer Addr dmaAddr = ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr()); @@ -327,6 +382,7 @@ IdeDisk::dmaReadDone() bytesWritten += SectorSize; cmdBytesLeft -= SectorSize; } +#endif // check for the EOT if (curPrd.getEOT()){ @@ -364,27 +420,59 @@ IdeDisk::doDmaWrite() void IdeDisk::dmaWriteDone() { - uint32_t bytesRead = 0; + Addr curAddr = 0, pageAddr = 0, dmaAddr = 0; + uint32_t bytesRead = 0, bytesInPage = 0; + + // setup the initial page and DMA address + curAddr = curPrd.getBaseAddr(); + pageAddr = alpha_trunc_page(curAddr); + dmaAddr = pciToDma(curAddr); // clear out the data buffer memset(dataBuffer, 0, MAX_DMA_SIZE); while (bytesRead < curPrd.getByteCount()) { + // see if we have crossed into a new page + if (pageAddr != alpha_trunc_page(curAddr)) { + // write the data to memory + /** @todo Do real DMA using interfaces here */ + memcpy(physmem->dma_addr(dmaAddr, bytesInPage), + (void *)(dataBuffer + (bytesRead - bytesInPage)), + bytesInPage); + + // update the DMA address and page address + pageAddr = alpha_trunc_page(curAddr); + dmaAddr = pciToDma(curAddr); + + bytesInPage = 0; + } + if (cmdBytesLeft <= 0) panic("DMA requested data is larger than # sectors specified\n"); readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); + curAddr += SectorSize; bytesRead += SectorSize; + bytesInPage += SectorSize; cmdBytesLeft -= SectorSize; } - // copy the data to memory + // write the last page worth read to memory + /** @todo Do real DMA using interfaces here */ + if (bytesInPage != 0) { + memcpy(physmem->dma_addr(dmaAddr, bytesInPage), + (void *)(dataBuffer + (bytesRead - bytesInPage)), + bytesInPage); + } + +#if 0 Addr dmaAddr = ctrl->tsunami->pchip-> translatePciToDma(curPrd.getBaseAddr()); memcpy(physmem->dma_addr(dmaAddr, curPrd.getByteCount()), (void *)dataBuffer, curPrd.getByteCount()); +#endif // check for the EOT if (curPrd.getEOT()) { diff --git a/dev/ide_disk.hh b/dev/ide_disk.hh index 016f827cc..88a492cbc 100644 --- a/dev/ide_disk.hh +++ b/dev/ide_disk.hh @@ -313,6 +313,8 @@ class IdeDisk : public SimObject (cmdReg.cyl_low << 8) | (cmdReg.sec_num)); } + inline Addr pciToDma(Addr &pciAddr); + /** * Serialize this object to the given output stream. * @param os The stream to serialize to. diff --git a/dev/tsunami_pchip.cc b/dev/tsunami_pchip.cc index ea23cce08..dabf6bf40 100644 --- a/dev/tsunami_pchip.cc +++ b/dev/tsunami_pchip.cc @@ -263,7 +263,7 @@ TsunamiPChip::translatePciToDma(Addr busAddr) physmem->dma_addr(pteAddr, sizeof(uint64_t)), sizeof(uint64_t)); - dmaAddr = ((pteEntry & ~0x1) << 12) | (busAddr & 0xfff); + dmaAddr = ((pteEntry & ~0x1) << 12) | (busAddr & 0x1fff); } else { baMask = (wsm[i] & (0x7ff << 20)) | 0xfffff;