DMASequencer.cc revision 8165:5955406f7ed0
14826Ssaidi@eecs.umich.edu/* 24826Ssaidi@eecs.umich.edu * Copyright (c) 2008 Mark D. Hill and David A. Wood 34826Ssaidi@eecs.umich.edu * All rights reserved. 44826Ssaidi@eecs.umich.edu * 54826Ssaidi@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 64826Ssaidi@eecs.umich.edu * modification, are permitted provided that the following conditions are 74826Ssaidi@eecs.umich.edu * met: redistributions of source code must retain the above copyright 84826Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 94826Ssaidi@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 104826Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 114826Ssaidi@eecs.umich.edu * documentation and/or other materials provided with the distribution; 124826Ssaidi@eecs.umich.edu * neither the name of the copyright holders nor the names of its 134826Ssaidi@eecs.umich.edu * contributors may be used to endorse or promote products derived from 144826Ssaidi@eecs.umich.edu * this software without specific prior written permission. 154826Ssaidi@eecs.umich.edu * 164826Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 174826Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 184826Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 194826Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 204826Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 214826Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 224826Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 234826Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 244826Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 254826Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 264826Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 274826Ssaidi@eecs.umich.edu */ 284826Ssaidi@eecs.umich.edu 294826Ssaidi@eecs.umich.edu#include "mem/protocol/SequencerMsg.hh" 304826Ssaidi@eecs.umich.edu#include "mem/protocol/SequencerRequestType.hh" 314826Ssaidi@eecs.umich.edu#include "mem/ruby/buffers/MessageBuffer.hh" 326330Sgblack@eecs.umich.edu#include "mem/ruby/slicc_interface/AbstractController.hh" 334826Ssaidi@eecs.umich.edu#include "mem/ruby/system/DMASequencer.hh" 344826Ssaidi@eecs.umich.edu#include "mem/ruby/system/System.hh" 354826Ssaidi@eecs.umich.edu 364826Ssaidi@eecs.umich.eduDMASequencer::DMASequencer(const Params *p) 374826Ssaidi@eecs.umich.edu : RubyPort(p) 384826Ssaidi@eecs.umich.edu{ 394826Ssaidi@eecs.umich.edu} 405569Snate@binkert.org 414826Ssaidi@eecs.umich.eduvoid 425569Snate@binkert.orgDMASequencer::init() 437693SAli.Saidi@ARM.com{ 444826Ssaidi@eecs.umich.edu RubyPort::init(); 454826Ssaidi@eecs.umich.edu m_is_busy = false; 465958Sgblack@eecs.umich.edu m_data_block_mask = ~ (~0 << RubySystem::getBlockSizeBits()); 474826Ssaidi@eecs.umich.edu} 484826Ssaidi@eecs.umich.edu 495958Sgblack@eecs.umich.eduRequestStatus 504826Ssaidi@eecs.umich.eduDMASequencer::makeRequest(const RubyRequest &request) 515958Sgblack@eecs.umich.edu{ 524826Ssaidi@eecs.umich.edu if (m_is_busy) { 534826Ssaidi@eecs.umich.edu return RequestStatus_BufferFull; 545498Ssaidi@eecs.umich.edu } 554826Ssaidi@eecs.umich.edu 564826Ssaidi@eecs.umich.edu uint64_t paddr = request.paddr; 574826Ssaidi@eecs.umich.edu uint8_t* data = request.data; 584826Ssaidi@eecs.umich.edu int len = request.len; 594826Ssaidi@eecs.umich.edu bool write = false; 604826Ssaidi@eecs.umich.edu switch(request.type) { 615569Snate@binkert.org case RubyRequestType_LD: 624826Ssaidi@eecs.umich.edu write = false; 634826Ssaidi@eecs.umich.edu break; 644826Ssaidi@eecs.umich.edu case RubyRequestType_ST: 656329Sgblack@eecs.umich.edu write = true; 666329Sgblack@eecs.umich.edu break; 676329Sgblack@eecs.umich.edu default: 686329Sgblack@eecs.umich.edu panic("DMASequencer::makeRequest does not support RubyRequestType"); 696329Sgblack@eecs.umich.edu return RequestStatus_NULL; 706329Sgblack@eecs.umich.edu } 716329Sgblack@eecs.umich.edu 726329Sgblack@eecs.umich.edu assert(!m_is_busy); // only support one outstanding DMA request 736329Sgblack@eecs.umich.edu m_is_busy = true; 746329Sgblack@eecs.umich.edu 756329Sgblack@eecs.umich.edu active_request.start_paddr = paddr; 766329Sgblack@eecs.umich.edu active_request.write = write; 776329Sgblack@eecs.umich.edu active_request.data = data; 786329Sgblack@eecs.umich.edu active_request.len = len; 796329Sgblack@eecs.umich.edu active_request.bytes_completed = 0; 806329Sgblack@eecs.umich.edu active_request.bytes_issued = 0; 816329Sgblack@eecs.umich.edu active_request.pkt = request.pkt; 826329Sgblack@eecs.umich.edu 836329Sgblack@eecs.umich.edu SequencerMsg *msg = new SequencerMsg; 846329Sgblack@eecs.umich.edu msg->getPhysicalAddress() = Address(paddr); 856329Sgblack@eecs.umich.edu msg->getLineAddress() = line_address(msg->getPhysicalAddress()); 866329Sgblack@eecs.umich.edu msg->getType() = write ? SequencerRequestType_ST : SequencerRequestType_LD; 876329Sgblack@eecs.umich.edu int offset = paddr & m_data_block_mask; 886329Sgblack@eecs.umich.edu 896329Sgblack@eecs.umich.edu msg->getLen() = (offset + len) <= RubySystem::getBlockSizeBytes() ? 906329Sgblack@eecs.umich.edu len : RubySystem::getBlockSizeBytes() - offset; 916329Sgblack@eecs.umich.edu 926329Sgblack@eecs.umich.edu if (write && (data != NULL)) { 936329Sgblack@eecs.umich.edu if (active_request.data != NULL) { 946329Sgblack@eecs.umich.edu msg->getDataBlk().setData(data, offset, msg->getLen()); 956329Sgblack@eecs.umich.edu } 966329Sgblack@eecs.umich.edu } 976329Sgblack@eecs.umich.edu 986329Sgblack@eecs.umich.edu assert(m_mandatory_q_ptr != NULL); 997693SAli.Saidi@ARM.com m_mandatory_q_ptr->enqueue(msg); 1007693SAli.Saidi@ARM.com active_request.bytes_issued += msg->getLen(); 1017693SAli.Saidi@ARM.com 1027693SAli.Saidi@ARM.com return RequestStatus_Issued; 1037693SAli.Saidi@ARM.com} 1047693SAli.Saidi@ARM.com 1057693SAli.Saidi@ARM.comvoid 1067693SAli.Saidi@ARM.comDMASequencer::issueNext() 1077693SAli.Saidi@ARM.com{ 1084826Ssaidi@eecs.umich.edu assert(m_is_busy == true); 1094826Ssaidi@eecs.umich.edu active_request.bytes_completed = active_request.bytes_issued; 110 if (active_request.len == active_request.bytes_completed) { 111 // 112 // Must unset the busy flag before calling back the dma port because 113 // the callback may cause a previously nacked request to be reissued 114 // 115 DPRINTF(RubyDma, "DMA request completed\n"); 116 m_is_busy = false; 117 ruby_hit_callback(active_request.pkt); 118 return; 119 } 120 121 SequencerMsg *msg = new SequencerMsg; 122 msg->getPhysicalAddress() = Address(active_request.start_paddr + 123 active_request.bytes_completed); 124 125 assert((msg->getPhysicalAddress().getAddress() & m_data_block_mask) == 0); 126 msg->getLineAddress() = line_address(msg->getPhysicalAddress()); 127 128 msg->getType() = (active_request.write ? SequencerRequestType_ST : 129 SequencerRequestType_LD); 130 131 msg->getLen() = 132 (active_request.len - 133 active_request.bytes_completed < RubySystem::getBlockSizeBytes() ? 134 active_request.len - active_request.bytes_completed : 135 RubySystem::getBlockSizeBytes()); 136 137 if (active_request.write) { 138 msg->getDataBlk(). 139 setData(&active_request.data[active_request.bytes_completed], 140 0, msg->getLen()); 141 msg->getType() = SequencerRequestType_ST; 142 } else { 143 msg->getType() = SequencerRequestType_LD; 144 } 145 146 assert(m_mandatory_q_ptr != NULL); 147 m_mandatory_q_ptr->enqueue(msg); 148 active_request.bytes_issued += msg->getLen(); 149 DPRINTF(RubyDma, 150 "DMA request bytes issued %d, bytes completed %d, total len %d\n", 151 active_request.bytes_issued, active_request.bytes_completed, 152 active_request.len); 153} 154 155void 156DMASequencer::dataCallback(const DataBlock & dblk) 157{ 158 assert(m_is_busy == true); 159 int len = active_request.bytes_issued - active_request.bytes_completed; 160 int offset = 0; 161 if (active_request.bytes_completed == 0) 162 offset = active_request.start_paddr & m_data_block_mask; 163 assert(active_request.write == false); 164 if (active_request.data != NULL) { 165 memcpy(&active_request.data[active_request.bytes_completed], 166 dblk.getData(offset, len), len); 167 } 168 issueNext(); 169} 170 171void 172DMASequencer::ackCallback() 173{ 174 issueNext(); 175} 176 177void 178DMASequencer::printConfig(std::ostream & out) 179{ 180} 181 182DMASequencer * 183DMASequencerParams::create() 184{ 185 return new DMASequencer(this); 186} 187