+void
+IGbE::postInterrupt(IntTypes t, bool now)
+{
+ assert(t);
+
+ // Interrupt is already pending
+ if (t & regs.icr() && !now)
+ return;
+
+ regs.icr = regs.icr() | t;
+
+ Tick itr_interval = Clock::Int::ns * 256 * regs.itr.interval();
+ DPRINTF(EthernetIntr, "EINT: postInterrupt() curTick: %d itr: %d interval: %d\n",
+ curTick, regs.itr.interval(), itr_interval);
+
+ if (regs.itr.interval() == 0 || now || lastInterrupt + itr_interval <= curTick) {
+ if (interEvent.scheduled()) {
+ deschedule(interEvent);
+ }
+ cpuPostInt();
+ } else {
+ Tick int_time = lastInterrupt + itr_interval;
+ assert(int_time > 0);
+ DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n",
+ int_time);
+ if (!interEvent.scheduled()) {
+ schedule(interEvent, int_time);
+ }
+ }
+}
+
+void
+IGbE::delayIntEvent()
+{
+ cpuPostInt();
+}
+
+
+void
+IGbE::cpuPostInt()
+{
+
+ postedInterrupts++;
+
+ if (!(regs.icr() & regs.imr)) {
+ DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n");
+ return;
+ }
+
+ DPRINTF(Ethernet, "Posting Interrupt\n");
+
+
+ if (interEvent.scheduled()) {
+ deschedule(interEvent);
+ }
+
+ if (rdtrEvent.scheduled()) {
+ regs.icr.rxt0(1);
+ deschedule(rdtrEvent);
+ }
+ if (radvEvent.scheduled()) {
+ regs.icr.rxt0(1);
+ deschedule(radvEvent);
+ }
+ if (tadvEvent.scheduled()) {
+ regs.icr.txdw(1);
+ deschedule(tadvEvent);
+ }
+ if (tidvEvent.scheduled()) {
+ regs.icr.txdw(1);
+ deschedule(tidvEvent);
+ }
+
+ regs.icr.int_assert(1);
+ DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n",
+ regs.icr());
+
+ intrPost();
+
+ lastInterrupt = curTick;
+}
+
+void
+IGbE::cpuClearInt()
+{
+ if (regs.icr.int_assert()) {
+ regs.icr.int_assert(0);
+ DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n",
+ regs.icr());
+ intrClear();
+ }
+}
+
+void
+IGbE::chkInterrupt()
+{
+ DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(),
+ regs.imr);
+ // Check if we need to clear the cpu interrupt
+ if (!(regs.icr() & regs.imr)) {
+ DPRINTF(Ethernet, "Mask cleaned all interrupts\n");
+ if (interEvent.scheduled())
+ deschedule(interEvent);
+ if (regs.icr.int_assert())
+ cpuClearInt();
+ }
+ DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n", regs.itr(), regs.itr.interval());
+
+ if (regs.icr() & regs.imr) {
+ if (regs.itr.interval() == 0) {
+ cpuPostInt();
+ } else {
+ DPRINTF(Ethernet, "Possibly scheduling interrupt because of imr write\n");
+ if (!interEvent.scheduled()) {
+ DPRINTF(Ethernet, "Scheduling for %d\n", curTick + Clock::Int::ns
+ * 256 * regs.itr.interval());
+ schedule(interEvent,
+ curTick + Clock::Int::ns * 256 * regs.itr.interval());
+ }
+ }
+ }
+
+
+}
+
+
+IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
+ : DescCache<RxDesc>(i, n, s), pktDone(false), pktEvent(this)
+
+{
+}
+
+void
+IGbE::RxDescCache::writePacket(EthPacketPtr packet)
+{
+ // We shouldn't have to deal with any of these yet
+ DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
+ packet->length, igbe->regs.rctl.descSize());
+ assert(packet->length < igbe->regs.rctl.descSize());
+
+ assert(unusedCache.size());
+ //if (!unusedCache.size())
+ // return false;
+
+ pktPtr = packet;
+ pktDone = false;
+ igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf),
+ packet->length, &pktEvent, packet->data, igbe->rxWriteDelay);
+}
+
+void
+IGbE::RxDescCache::pktComplete()
+{
+ assert(unusedCache.size());
+ RxDesc *desc;
+ desc = unusedCache.front();
+
+ uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
+ desc->len = htole((uint16_t)(pktPtr->length + crcfixup));
+ DPRINTF(EthernetDesc, "pktPtr->length: %d stripcrc offset: %d value written: %d %d\n",
+ pktPtr->length, crcfixup,
+ htole((uint16_t)(pktPtr->length + crcfixup)),
+ (uint16_t)(pktPtr->length + crcfixup));
+
+ // no support for anything but starting at 0
+ assert(igbe->regs.rxcsum.pcss() == 0);
+
+ DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
+
+ uint8_t status = RXDS_DD | RXDS_EOP;
+ uint8_t err = 0;
+
+ IpPtr ip(pktPtr);
+
+ if (ip) {
+ DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
+
+ if (igbe->regs.rxcsum.ipofld()) {
+ DPRINTF(EthernetDesc, "Checking IP checksum\n");
+ status |= RXDS_IPCS;
+ desc->csum = htole(cksum(ip));
+ igbe->rxIpChecksums++;
+ if (cksum(ip) != 0) {
+ err |= RXDE_IPE;
+ DPRINTF(EthernetDesc, "Checksum is bad!!\n");
+ }
+ }
+ TcpPtr tcp(ip);
+ if (tcp && igbe->regs.rxcsum.tuofld()) {
+ DPRINTF(EthernetDesc, "Checking TCP checksum\n");
+ status |= RXDS_TCPCS;
+ desc->csum = htole(cksum(tcp));
+ igbe->rxTcpChecksums++;
+ if (cksum(tcp) != 0) {
+ DPRINTF(EthernetDesc, "Checksum is bad!!\n");
+ err |= RXDE_TCPE;
+ }
+ }
+
+ UdpPtr udp(ip);
+ if (udp && igbe->regs.rxcsum.tuofld()) {
+ DPRINTF(EthernetDesc, "Checking UDP checksum\n");
+ status |= RXDS_UDPCS;
+ desc->csum = htole(cksum(udp));
+ igbe->rxUdpChecksums++;
+ if (cksum(udp) != 0) {
+ DPRINTF(EthernetDesc, "Checksum is bad!!\n");
+ err |= RXDE_TCPE;
+ }
+ }
+ } else { // if ip
+ DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
+ }
+
+
+ desc->status = htole(status);
+ desc->errors = htole(err);
+
+ // No vlan support at this point... just set it to 0
+ desc->vlan = 0;
+
+ // Deal with the rx timer interrupts
+ if (igbe->regs.rdtr.delay()) {
+ DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n",
+ igbe->regs.rdtr.delay() * igbe->intClock());
+ igbe->reschedule(igbe->rdtrEvent,
+ curTick + igbe->regs.rdtr.delay() * igbe->intClock(), true);
+ }
+
+ if (igbe->regs.radv.idv()) {
+ DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n",
+ igbe->regs.radv.idv() * igbe->intClock());
+ if (!igbe->radvEvent.scheduled()) {
+ igbe->schedule(igbe->radvEvent,
+ curTick + igbe->regs.radv.idv() * igbe->intClock());
+ }
+ }
+
+ // if neither radv or rdtr, maybe itr is set...
+ if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
+ DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
+ igbe->postInterrupt(IT_RXT);
+ }
+
+ // If the packet is small enough, interrupt appropriately
+ // I wonder if this is delayed or not?!
+ if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
+ DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n");
+ igbe->postInterrupt(IT_SRPD);
+ }
+
+ DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
+ unusedCache.pop_front();
+ usedCache.push_back(desc);
+
+
+ pktPtr = NULL;
+ enableSm();
+ pktDone = true;
+ igbe->checkDrain();
+
+}
+
+void
+IGbE::RxDescCache::enableSm()
+{
+ if (!igbe->drainEvent) {
+ igbe->rxTick = true;
+ igbe->restartClock();
+ }
+}
+
+bool
+IGbE::RxDescCache::packetDone()
+{
+ if (pktDone) {
+ pktDone = false;
+ return true;
+ }
+ return false;
+}