X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fdev%2Fio_device.hh;h=36787c13efd84f4be44694af2c155d465ba6b81b;hb=9957035a42653a0666e30c744ab02fb0074db3a3;hp=fa3f982476b106c6459b88ec450be5ea1af7d68d;hpb=44974a4462e019cfc5c65d20ad620faa9bc7f8cf;p=gem5.git diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh index fa3f98247..36787c13e 100644 --- a/src/dev/io_device.hh +++ b/src/dev/io_device.hh @@ -32,12 +32,16 @@ #ifndef __DEV_IO_DEVICE_HH__ #define __DEV_IO_DEVICE_HH__ -#include "base/chunk_generator.hh" +#include "base/fast_alloc.hh" #include "mem/mem_object.hh" -#include "mem/packet_impl.hh" -#include "sim/eventq.hh" +#include "mem/packet.hh" +#include "mem/tport.hh" +#include "params/BasicPioDevice.hh" +#include "params/DmaDevice.hh" +#include "params/PioDevice.hh" #include "sim/sim_object.hh" +class Event; class Platform; class PioDevice; class DmaDevice; @@ -48,94 +52,29 @@ class System; * sensitive to an address range use. The port takes all the memory * access types and roles them into one read() and write() call that the device * must respond to. The device must also provide the addressRanges() function - * with which it returns the address ranges it is interested in. An extra - * sendTiming() function is implemented which takes an delay. In this way the - * device can immediatly call sendTiming(pkt, time) after processing a request - * and the request will be handled by the port even if the port bus the device - * connects to is blocked. + * with which it returns the address ranges it is interested in. */ -class PioPort : public Port +class PioPort : public SimpleTimingPort { protected: /** The device that this port serves. */ PioDevice *device; - /** The system that device/port are in. This is used to select which mode - * we are currently operating in. */ - System *sys; - - /** A list of outgoing timing response packets that haven't been serviced - * yet. */ - std::list transmitList; - - /** The current status of the peer(bus) that we are connected to. */ - Status peerStatus; - - virtual bool recvTiming(Packet *pkt); - - virtual Tick recvAtomic(Packet *pkt); - - virtual void recvFunctional(Packet *pkt) ; - - virtual void recvStatusChange(Status status) - { peerStatus = status; } - - virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop); - - void resendNacked(Packet *pkt); - - /** - * This class is used to implemented sendTiming() with a delay. When a delay - * is requested a new event is created. When the event time expires it - * attempts to send the packet. If it cannot, the packet is pushed onto the - * transmit list to be sent when recvRetry() is called. */ - class SendEvent : public Event - { - PioPort *port; - Packet *packet; - - SendEvent(PioPort *p, Packet *pkt, Tick t) - : Event(&mainEventQueue), port(p), packet(pkt) - { schedule(curTick + t); } - - virtual void process(); - - virtual const char *description() - { return "Future scheduled sendTiming event"; } - - friend class PioPort; - }; - - /** Number of timing requests that are emulating the device timing before - * attempting to end up on the bus. - */ - int outTiming; - - /** If we need to drain, keep the drain event around until we're done - * here.*/ - Event *drainEvent; + virtual Tick recvAtomic(PacketPtr pkt); - /** Schedule a sendTiming() event to be called in the future. */ - void sendTiming(Packet *pkt, Tick time) - { outTiming++; new PioPort::SendEvent(this, pkt, time); } - - /** This function is notification that the device should attempt to send a - * packet again. */ - virtual void recvRetry(); + virtual void getDeviceAddressRanges(AddrRangeList &resp, + bool &snoop); public: - PioPort(PioDevice *dev, System *s, std::string pname = "-pioport"); - unsigned int drain(Event *de); - - friend class PioPort::SendEvent; + PioPort(PioDevice *dev, System *s, std::string pname = "-pioport"); }; class DmaPort : public Port { protected: - struct DmaReqState : public Packet::SenderState + struct DmaReqState : public Packet::SenderState, public FastAlloc { /** Event to call on the device when this transaction (all packets) * complete. */ @@ -150,13 +89,18 @@ class DmaPort : public Port /** Number of bytes that have been acked for this transaction. */ Addr numBytes; - DmaReqState(Event *ce, Port *p, Addr tb) - : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0) + /** Amount to delay completion of dma by */ + Tick delay; + + + DmaReqState(Event *ce, Port *p, Addr tb, Tick _delay) + : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0), + delay(_delay) {} }; - DmaDevice *device; - std::list transmitList; + MemObject *device; + std::list transmitList; /** The system that device/port are in. This is used to select which mode * we are currently operating in. */ @@ -172,30 +116,76 @@ class DmaPort : public Port * here.*/ Event *drainEvent; - virtual bool recvTiming(Packet *pkt); - virtual Tick recvAtomic(Packet *pkt) - { panic("dma port shouldn't be used for pio access."); } - virtual void recvFunctional(Packet *pkt) - { panic("dma port shouldn't be used for pio access."); } + /** time to wait between sending another packet, increases as NACKs are + * recived, decreases as responses are recived. */ + Tick backoffTime; + + /** Minimum time that device should back off for after failed sendTiming */ + Tick minBackoffDelay; + + /** Maximum time that device should back off for after failed sendTiming */ + Tick maxBackoffDelay; + + /** If the port is currently waiting for a retry before it can send whatever + * it is that it's sending. */ + bool inRetry; + + /** Port accesses a cache which requires snooping */ + bool recvSnoops; + + /** Records snoop response so we only reply once to a status change */ + bool snoopRangeSent; + + virtual bool recvTiming(PacketPtr pkt); + virtual Tick recvAtomic(PacketPtr pkt) + { + if (recvSnoops) return 0; + + panic("dma port shouldn't be used for pio access."); M5_DUMMY_RETURN + } + virtual void recvFunctional(PacketPtr pkt) + { + if (recvSnoops) return; + + panic("dma port shouldn't be used for pio access."); + } virtual void recvStatusChange(Status status) - { ; } + { + if (recvSnoops) { + if (status == RangeChange) { + if (!snoopRangeSent) { + snoopRangeSent = true; + sendStatusChange(Port::RangeChange); + } + return; + } + panic("Unexpected recvStatusChange\n"); + } + } virtual void recvRetry() ; - virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) - { resp.clear(); snoop.clear(); } + virtual void getDeviceAddressRanges(AddrRangeList &resp, + bool &snoop) + { resp.clear(); snoop = recvSnoops; } + + void queueDma(PacketPtr pkt, bool front = false); + void sendDma(); - void sendDma(Packet *pkt, bool front = false); + /** event to give us a kick every time we backoff time is reached. */ + EventWrapper backoffEvent; public: - DmaPort(DmaDevice *dev, System *s); + DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff, + bool recv_snoops = false); void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, - uint8_t *data = NULL); + uint8_t *data, Tick delay, Request::Flags flag = 0); bool dmaPending() { return pendingCount > 0; } + unsigned cacheBlockSize() const { return peerBlockSize(); } unsigned int drain(Event *de); }; @@ -206,7 +196,6 @@ class DmaPort : public Port * mode we are in, etc is handled by the PioPort so the device doesn't have to * bother. */ - class PioDevice : public MemObject { protected: @@ -223,77 +212,43 @@ class PioDevice : public MemObject virtual void addressRanges(AddrRangeList &range_list) = 0; - /** As far as the devices are concerned they only accept atomic transactions - * which are converted to either a write or a read. */ - Tick recvAtomic(Packet *pkt) - { return pkt->isRead() ? this->read(pkt) : this->write(pkt); } - - /** Pure virtual function that the device must implement. Called when a read - * command is recieved by the port. + /** Pure virtual function that the device must implement. Called + * when a read command is recieved by the port. * @param pkt Packet describing this request * @return number of ticks it took to complete */ - virtual Tick read(Packet *pkt) = 0; + virtual Tick read(PacketPtr pkt) = 0; /** Pure virtual function that the device must implement. Called when a * write command is recieved by the port. * @param pkt Packet describing this request * @return number of ticks it took to complete */ - virtual Tick write(Packet *pkt) = 0; + virtual Tick write(PacketPtr pkt) = 0; public: - /** Params struct which is extended through each device based on the - * parameters it needs. Since we are re-writing everything, we might as well - * start from the bottom this time. */ + typedef PioDeviceParams Params; + PioDevice(const Params *p); + virtual ~PioDevice(); - struct Params + const Params * + params() const { - std::string name; - Platform *platform; - System *system; - }; - - protected: - Params *_params; - - public: - const Params *params() const { return _params; } - - PioDevice(Params *p) - : MemObject(p->name), platform(p->platform), sys(p->system), - pioPort(NULL), _params(p) - {} - - virtual ~PioDevice(); + return dynamic_cast(_params); + } virtual void init(); virtual unsigned int drain(Event *de); - virtual Port *getPort(const std::string &if_name, int idx = -1) - { - if (if_name == "pio") { - if (pioPort != NULL) - panic("pio port already connected to."); - pioPort = new PioPort(this, sys); - return pioPort; - } else - return NULL; - } + virtual Port *getPort(const std::string &if_name, int idx = -1); + friend class PioPort; }; class BasicPioDevice : public PioDevice { - public: - struct Params : public PioDevice::Params - { - Addr pio_addr; - Tick pio_delay; - }; - protected: /** Address that the device listens to. */ Addr pioAddr; @@ -305,12 +260,17 @@ class BasicPioDevice : public PioDevice Tick pioDelay; public: - BasicPioDevice(Params *p) - : PioDevice(p), pioAddr(p->pio_addr), pioSize(0), pioDelay(p->pio_delay) - {} + typedef BasicPioDeviceParams Params; + BasicPioDevice(const Params *p); + + const Params * + params() const + { + return dynamic_cast(_params); + } /** return the address ranges that this device responds to. - * @params range_list range list to populate with ranges + * @param range_list range list to populate with ranges */ void addressRanges(AddrRangeList &range_list); @@ -318,38 +278,37 @@ class BasicPioDevice : public PioDevice class DmaDevice : public PioDevice { - protected: + protected: DmaPort *dmaPort; public: - DmaDevice(Params *p); + typedef DmaDeviceParams Params; + DmaDevice(const Params *p); virtual ~DmaDevice(); - void dmaWrite(Addr addr, int size, Event *event, uint8_t *data) - { dmaPort->dmaAction(Packet::WriteReq, addr, size, event, data) ; } + const Params * + params() const + { + return dynamic_cast(_params); + } + + void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0) + { + dmaPort->dmaAction(MemCmd::WriteReq, addr, size, event, data, delay); + } - void dmaRead(Addr addr, int size, Event *event, uint8_t *data = NULL) - { dmaPort->dmaAction(Packet::ReadReq, addr, size, event, data); } + void dmaRead(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0) + { + dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data, delay); + } bool dmaPending() { return dmaPort->dmaPending(); } virtual unsigned int drain(Event *de); - virtual Port *getPort(const std::string &if_name, int idx = -1) - { - if (if_name == "pio") { - if (pioPort != NULL) - panic("pio port already connected to."); - pioPort = new PioPort(this, sys); - return pioPort; - } else if (if_name == "dma") { - if (dmaPort != NULL) - panic("dma port already connected to."); - dmaPort = new DmaPort(this, sys); - return dmaPort; - } else - return NULL; - } + unsigned cacheBlockSize() const { return dmaPort->cacheBlockSize(); } + + virtual Port *getPort(const std::string &if_name, int idx = -1); friend class DmaPort; };