first bit of life from the intel gigabit model
--HG-- extra : convert_revision : d8944a53f6b585df21651c4e624518d5c49a7837
This commit is contained in:
parent
2c47413a7a
commit
e8dc1723ee
4 changed files with 224 additions and 113 deletions
|
@ -59,8 +59,8 @@ IGbE::IGbE(Params *p)
|
||||||
rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
|
rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
|
||||||
txTick(false), rdtrEvent(this), radvEvent(this), tadvEvent(this),
|
txTick(false), rdtrEvent(this), radvEvent(this), tadvEvent(this),
|
||||||
tidvEvent(this), tickEvent(this), interEvent(this),
|
tidvEvent(this), tickEvent(this), interEvent(this),
|
||||||
rxDescCache(this, name()+".TxDesc", p->rx_desc_cache_size),
|
rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
|
||||||
txDescCache(this, name()+".RxDesc", p->tx_desc_cache_size), clock(p->clock)
|
txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), clock(p->clock)
|
||||||
{
|
{
|
||||||
// Initialized internal registers per Intel documentation
|
// Initialized internal registers per Intel documentation
|
||||||
// All registers intialized to 0 by per register constructor
|
// All registers intialized to 0 by per register constructor
|
||||||
|
@ -70,6 +70,7 @@ IGbE::IGbE(Params *p)
|
||||||
regs.ctrl.frcspd(1);
|
regs.ctrl.frcspd(1);
|
||||||
regs.sts.speed(3); // Say we're 1000Mbps
|
regs.sts.speed(3); // Say we're 1000Mbps
|
||||||
regs.sts.fd(1); // full duplex
|
regs.sts.fd(1); // full duplex
|
||||||
|
regs.sts.lu(1); // link up
|
||||||
regs.eecd.fwe(1);
|
regs.eecd.fwe(1);
|
||||||
regs.eecd.ee_type(1);
|
regs.eecd.ee_type(1);
|
||||||
regs.imr = 0;
|
regs.imr = 0;
|
||||||
|
@ -89,14 +90,15 @@ IGbE::IGbE(Params *p)
|
||||||
// clear all 64 16 bit words of the eeprom
|
// clear all 64 16 bit words of the eeprom
|
||||||
memset(&flash, 0, EEPROM_SIZE*2);
|
memset(&flash, 0, EEPROM_SIZE*2);
|
||||||
|
|
||||||
//We'll need to instert the MAC address into the flash
|
// Set the MAC address
|
||||||
flash[0] = 0xA4A4;
|
memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN);
|
||||||
flash[1] = 0xB6B6;
|
for (int x = 0; x < ETH_ADDR_LEN/2; x++)
|
||||||
flash[2] = 0xC8C8;
|
flash[x] = htobe(flash[x]);
|
||||||
|
|
||||||
uint16_t csum = 0;
|
uint16_t csum = 0;
|
||||||
for (int x = 0; x < EEPROM_SIZE; x++)
|
for (int x = 0; x < EEPROM_SIZE; x++)
|
||||||
csum += flash[x];
|
csum += htobe(flash[x]);
|
||||||
|
|
||||||
|
|
||||||
// Magic happy checksum value
|
// Magic happy checksum value
|
||||||
flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
|
flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
|
||||||
|
@ -137,7 +139,7 @@ IGbE::read(PacketPtr pkt)
|
||||||
// Only 32bit accesses allowed
|
// Only 32bit accesses allowed
|
||||||
assert(pkt->getSize() == 4);
|
assert(pkt->getSize() == 4);
|
||||||
|
|
||||||
//DPRINTF(Ethernet, "Read device register %#X\n", daddr);
|
DPRINTF(Ethernet, "Read device register %#X\n", daddr);
|
||||||
|
|
||||||
pkt->allocate();
|
pkt->allocate();
|
||||||
|
|
||||||
|
@ -166,13 +168,16 @@ IGbE::read(PacketPtr pkt)
|
||||||
pkt->set<uint32_t>(regs.mdic());
|
pkt->set<uint32_t>(regs.mdic());
|
||||||
break;
|
break;
|
||||||
case REG_ICR:
|
case REG_ICR:
|
||||||
|
DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(),
|
||||||
|
regs.imr, regs.iam, regs.ctrl_ext.iame());
|
||||||
pkt->set<uint32_t>(regs.icr());
|
pkt->set<uint32_t>(regs.icr());
|
||||||
if (regs.icr.int_assert())
|
if (regs.icr.int_assert() || regs.imr == 0) {
|
||||||
regs.imr &= regs.iam;
|
regs.icr = regs.icr() & ~mask(30);
|
||||||
if (regs.imr == 0 || (regs.icr.int_assert() && regs.ctrl_ext.iame())) {
|
DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr());
|
||||||
regs.icr(0);
|
|
||||||
cpuClearInt();
|
|
||||||
}
|
}
|
||||||
|
if (regs.ctrl_ext.iame() && regs.icr.int_assert())
|
||||||
|
regs.imr &= ~regs.iam;
|
||||||
|
chkInterrupt();
|
||||||
break;
|
break;
|
||||||
case REG_ITR:
|
case REG_ITR:
|
||||||
pkt->set<uint32_t>(regs.itr());
|
pkt->set<uint32_t>(regs.itr());
|
||||||
|
@ -221,13 +226,6 @@ IGbE::read(PacketPtr pkt)
|
||||||
postInterrupt(IT_RXT);
|
postInterrupt(IT_RXT);
|
||||||
regs.rdtr.fpd(0);
|
regs.rdtr.fpd(0);
|
||||||
}
|
}
|
||||||
if (regs.rdtr.delay()) {
|
|
||||||
Tick t = regs.rdtr.delay() * Clock::Int::ns * 1024;
|
|
||||||
if (rdtrEvent.scheduled())
|
|
||||||
rdtrEvent.reschedule(curTick + t);
|
|
||||||
else
|
|
||||||
rdtrEvent.schedule(curTick + t);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case REG_RADV:
|
case REG_RADV:
|
||||||
pkt->set<uint32_t>(regs.radv());
|
pkt->set<uint32_t>(regs.radv());
|
||||||
|
@ -292,7 +290,7 @@ IGbE::write(PacketPtr pkt)
|
||||||
// Only 32bit accesses allowed
|
// Only 32bit accesses allowed
|
||||||
assert(pkt->getSize() == sizeof(uint32_t));
|
assert(pkt->getSize() == sizeof(uint32_t));
|
||||||
|
|
||||||
//DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>());
|
DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>());
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Handle write of register here
|
/// Handle write of register here
|
||||||
|
@ -398,19 +396,16 @@ IGbE::write(PacketPtr pkt)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
regs.mdic.data(0);
|
regs.mdic.data(0);
|
||||||
warn("Accessing unknown phy register %d\n", regs.mdic.regadd());
|
|
||||||
}
|
}
|
||||||
regs.mdic.r(1);
|
regs.mdic.r(1);
|
||||||
break;
|
break;
|
||||||
case REG_ICR:
|
case REG_ICR:
|
||||||
if (regs.icr.int_assert())
|
DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(),
|
||||||
regs.imr &= regs.iam;
|
regs.imr, regs.iam, regs.ctrl_ext.iame());
|
||||||
|
if (regs.ctrl_ext.iame())
|
||||||
|
regs.imr &= ~regs.iam;
|
||||||
regs.icr = ~bits(val,30,0) & regs.icr();
|
regs.icr = ~bits(val,30,0) & regs.icr();
|
||||||
// if no more bits are set clear the int_asserted bit
|
chkInterrupt();
|
||||||
if (!bits(regs.icr(),31,31))
|
|
||||||
cpuClearInt();
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case REG_ITR:
|
case REG_ITR:
|
||||||
regs.itr = val;
|
regs.itr = val;
|
||||||
|
@ -439,8 +434,7 @@ IGbE::write(PacketPtr pkt)
|
||||||
}
|
}
|
||||||
if (regs.rctl.en())
|
if (regs.rctl.en())
|
||||||
rxTick = true;
|
rxTick = true;
|
||||||
if ((rxTick || txTick) && !tickEvent.scheduled())
|
restartClock();
|
||||||
tickEvent.schedule(curTick + cycles(1));
|
|
||||||
break;
|
break;
|
||||||
case REG_FCTTV:
|
case REG_FCTTV:
|
||||||
regs.fcttv = val;
|
regs.fcttv = val;
|
||||||
|
@ -451,8 +445,7 @@ IGbE::write(PacketPtr pkt)
|
||||||
regs.tctl = val;
|
regs.tctl = val;
|
||||||
if (regs.tctl.en())
|
if (regs.tctl.en())
|
||||||
txTick = true;
|
txTick = true;
|
||||||
if ((rxTick || txTick) && !tickEvent.scheduled())
|
restartClock();
|
||||||
tickEvent.schedule(curTick + cycles(1));
|
|
||||||
if (regs.tctl.en() && !oldtctl.en()) {
|
if (regs.tctl.en() && !oldtctl.en()) {
|
||||||
txDescCache.reset();
|
txDescCache.reset();
|
||||||
}
|
}
|
||||||
|
@ -496,8 +489,7 @@ IGbE::write(PacketPtr pkt)
|
||||||
case REG_RDT:
|
case REG_RDT:
|
||||||
regs.rdt = val;
|
regs.rdt = val;
|
||||||
rxTick = true;
|
rxTick = true;
|
||||||
if ((rxTick || txTick) && !tickEvent.scheduled())
|
restartClock();
|
||||||
tickEvent.schedule(curTick + cycles(1));
|
|
||||||
break;
|
break;
|
||||||
case REG_RDTR:
|
case REG_RDTR:
|
||||||
regs.rdtr = val;
|
regs.rdtr = val;
|
||||||
|
@ -524,8 +516,7 @@ IGbE::write(PacketPtr pkt)
|
||||||
case REG_TDT:
|
case REG_TDT:
|
||||||
regs.tdt = val;
|
regs.tdt = val;
|
||||||
txTick = true;
|
txTick = true;
|
||||||
if ((rxTick || txTick) && !tickEvent.scheduled())
|
restartClock();
|
||||||
tickEvent.schedule(curTick + cycles(1));
|
|
||||||
break;
|
break;
|
||||||
case REG_TIDV:
|
case REG_TIDV:
|
||||||
regs.tidv = val;
|
regs.tidv = val;
|
||||||
|
@ -556,21 +547,23 @@ IGbE::write(PacketPtr pkt)
|
||||||
void
|
void
|
||||||
IGbE::postInterrupt(IntTypes t, bool now)
|
IGbE::postInterrupt(IntTypes t, bool now)
|
||||||
{
|
{
|
||||||
|
assert(t);
|
||||||
|
|
||||||
// Interrupt is already pending
|
// Interrupt is already pending
|
||||||
if (t & regs.icr())
|
if (t & regs.icr())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (regs.icr() & regs.imr)
|
if (regs.icr() & regs.imr)
|
||||||
{
|
{
|
||||||
// already in an interrupt state, set new int and done
|
|
||||||
regs.icr = regs.icr() | t;
|
regs.icr = regs.icr() | t;
|
||||||
|
if (!interEvent.scheduled())
|
||||||
|
interEvent.schedule(curTick + Clock::Int::ns * 256 *
|
||||||
|
regs.itr.interval());
|
||||||
} else {
|
} else {
|
||||||
regs.icr = regs.icr() | t;
|
regs.icr = regs.icr() | t;
|
||||||
if (regs.itr.interval() == 0 || now) {
|
if (regs.itr.interval() == 0 || now) {
|
||||||
if (now) {
|
if (interEvent.scheduled())
|
||||||
if (interEvent.scheduled())
|
interEvent.deschedule();
|
||||||
interEvent.deschedule();
|
|
||||||
}
|
|
||||||
cpuPostInt();
|
cpuPostInt();
|
||||||
} else {
|
} else {
|
||||||
DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n",
|
DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n",
|
||||||
|
@ -610,21 +603,35 @@ IGbE::cpuPostInt()
|
||||||
void
|
void
|
||||||
IGbE::cpuClearInt()
|
IGbE::cpuClearInt()
|
||||||
{
|
{
|
||||||
regs.icr.int_assert(0);
|
if (regs.icr.int_assert()) {
|
||||||
DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n",
|
regs.icr.int_assert(0);
|
||||||
regs.icr());
|
DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n",
|
||||||
intrClear();
|
regs.icr());
|
||||||
|
intrClear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IGbE::chkInterrupt()
|
IGbE::chkInterrupt()
|
||||||
{
|
{
|
||||||
// Check if we need to clear the cpu interrupt
|
// Check if we need to clear the cpu interrupt
|
||||||
if (!(regs.icr() & regs.imr))
|
if (!(regs.icr() & regs.imr)) {
|
||||||
cpuClearInt();
|
if (interEvent.scheduled())
|
||||||
|
interEvent.deschedule();
|
||||||
|
if (regs.icr.int_assert())
|
||||||
|
cpuClearInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regs.icr() & regs.imr) {
|
||||||
|
if (regs.itr.interval() == 0) {
|
||||||
|
cpuPostInt();
|
||||||
|
} else {
|
||||||
|
if (!interEvent.scheduled())
|
||||||
|
interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check if we need to set the cpu interupt
|
|
||||||
postInterrupt(IT_NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -638,6 +645,8 @@ bool
|
||||||
IGbE::RxDescCache::writePacket(EthPacketPtr packet)
|
IGbE::RxDescCache::writePacket(EthPacketPtr packet)
|
||||||
{
|
{
|
||||||
// We shouldn't have to deal with any of these yet
|
// 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(packet->length < igbe->regs.rctl.descSize());
|
||||||
|
|
||||||
if (!unusedCache.size())
|
if (!unusedCache.size())
|
||||||
|
@ -645,7 +654,8 @@ IGbE::RxDescCache::writePacket(EthPacketPtr packet)
|
||||||
|
|
||||||
pktPtr = packet;
|
pktPtr = packet;
|
||||||
|
|
||||||
igbe->dmaWrite(unusedCache.front()->buf, packet->length, &pktEvent, packet->data);
|
igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf),
|
||||||
|
packet->length, &pktEvent, packet->data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -656,7 +666,13 @@ IGbE::RxDescCache::pktComplete()
|
||||||
RxDesc *desc;
|
RxDesc *desc;
|
||||||
desc = unusedCache.front();
|
desc = unusedCache.front();
|
||||||
|
|
||||||
desc->len = pktPtr->length;
|
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
|
// no support for anything but starting at 0
|
||||||
assert(igbe->regs.rxcsum.pcss() == 0);
|
assert(igbe->regs.rxcsum.pcss() == 0);
|
||||||
|
|
||||||
|
@ -669,7 +685,7 @@ IGbE::RxDescCache::pktComplete()
|
||||||
if (igbe->regs.rxcsum.ipofld()) {
|
if (igbe->regs.rxcsum.ipofld()) {
|
||||||
DPRINTF(EthernetDesc, "RxDesc: Checking IP checksum\n");
|
DPRINTF(EthernetDesc, "RxDesc: Checking IP checksum\n");
|
||||||
status |= RXDS_IPCS;
|
status |= RXDS_IPCS;
|
||||||
desc->csum = cksum(ip);
|
desc->csum = htole(cksum(ip));
|
||||||
if (cksum(ip) != 0) {
|
if (cksum(ip) != 0) {
|
||||||
err |= RXDE_IPE;
|
err |= RXDE_IPE;
|
||||||
DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n");
|
DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n");
|
||||||
|
@ -679,7 +695,7 @@ IGbE::RxDescCache::pktComplete()
|
||||||
if (tcp && igbe->regs.rxcsum.tuofld()) {
|
if (tcp && igbe->regs.rxcsum.tuofld()) {
|
||||||
DPRINTF(EthernetDesc, "RxDesc: Checking TCP checksum\n");
|
DPRINTF(EthernetDesc, "RxDesc: Checking TCP checksum\n");
|
||||||
status |= RXDS_TCPCS;
|
status |= RXDS_TCPCS;
|
||||||
desc->csum = cksum(tcp);
|
desc->csum = htole(cksum(tcp));
|
||||||
if (cksum(tcp) != 0) {
|
if (cksum(tcp) != 0) {
|
||||||
DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n");
|
DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n");
|
||||||
err |= RXDE_TCPE;
|
err |= RXDE_TCPE;
|
||||||
|
@ -690,7 +706,7 @@ IGbE::RxDescCache::pktComplete()
|
||||||
if (udp && igbe->regs.rxcsum.tuofld()) {
|
if (udp && igbe->regs.rxcsum.tuofld()) {
|
||||||
DPRINTF(EthernetDesc, "RxDesc: Checking UDP checksum\n");
|
DPRINTF(EthernetDesc, "RxDesc: Checking UDP checksum\n");
|
||||||
status |= RXDS_UDPCS;
|
status |= RXDS_UDPCS;
|
||||||
desc->csum = cksum(udp);
|
desc->csum = htole(cksum(udp));
|
||||||
if (cksum(tcp) != 0) {
|
if (cksum(tcp) != 0) {
|
||||||
DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n");
|
DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n");
|
||||||
err |= RXDE_TCPE;
|
err |= RXDE_TCPE;
|
||||||
|
@ -698,8 +714,8 @@ IGbE::RxDescCache::pktComplete()
|
||||||
}
|
}
|
||||||
} // if ip
|
} // if ip
|
||||||
|
|
||||||
desc->status = status;
|
desc->status = htole(status);
|
||||||
desc->errors = err;
|
desc->errors = htole(err);
|
||||||
|
|
||||||
// No vlan support at this point... just set it to 0
|
// No vlan support at this point... just set it to 0
|
||||||
desc->vlan = 0;
|
desc->vlan = 0;
|
||||||
|
@ -724,7 +740,14 @@ IGbE::RxDescCache::pktComplete()
|
||||||
igbe->intClock());
|
igbe->intClock());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if neither radv or rdtr, maybe itr is set...
|
||||||
|
if (!igbe->regs.rdtr.delay()) {
|
||||||
|
DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
|
||||||
|
igbe->postInterrupt(IT_RXT);
|
||||||
|
}
|
||||||
|
|
||||||
// If the packet is small enough, interrupt appropriately
|
// If the packet is small enough, interrupt appropriately
|
||||||
|
// I wonder if this is delayed or not?!
|
||||||
if (pktPtr->length <= igbe->regs.rsrpd.idv())
|
if (pktPtr->length <= igbe->regs.rsrpd.idv())
|
||||||
igbe->postInterrupt(IT_SRPD);
|
igbe->postInterrupt(IT_SRPD);
|
||||||
|
|
||||||
|
@ -740,9 +763,7 @@ void
|
||||||
IGbE::RxDescCache::enableSm()
|
IGbE::RxDescCache::enableSm()
|
||||||
{
|
{
|
||||||
igbe->rxTick = true;
|
igbe->rxTick = true;
|
||||||
if ((igbe->rxTick || igbe->txTick) && !igbe->tickEvent.scheduled())
|
igbe->restartClock();
|
||||||
igbe->tickEvent.schedule((curTick/igbe->cycles(1)) * igbe->cycles(1) +
|
|
||||||
igbe->cycles(1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -759,7 +780,7 @@ IGbE::RxDescCache::packetDone()
|
||||||
|
|
||||||
IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
|
IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
|
||||||
: DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false),
|
: DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false),
|
||||||
pktEvent(this)
|
hLen(0), pktEvent(this)
|
||||||
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -813,7 +834,8 @@ IGbE::TxDescCache::getPacketData(EthPacketPtr p)
|
||||||
pktWaiting = true;
|
pktWaiting = true;
|
||||||
|
|
||||||
DPRINTF(EthernetDesc, "TxDesc: Starting DMA of packet\n");
|
DPRINTF(EthernetDesc, "TxDesc: Starting DMA of packet\n");
|
||||||
igbe->dmaRead(TxdOp::getBuf(desc), TxdOp::getLen(desc), &pktEvent, p->data);
|
igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)),
|
||||||
|
TxdOp::getLen(desc), &pktEvent, p->data + hLen);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -828,9 +850,28 @@ IGbE::TxDescCache::pktComplete()
|
||||||
|
|
||||||
DPRINTF(EthernetDesc, "TxDesc: DMA of packet complete\n");
|
DPRINTF(EthernetDesc, "TxDesc: DMA of packet complete\n");
|
||||||
|
|
||||||
|
|
||||||
desc = unusedCache.front();
|
desc = unusedCache.front();
|
||||||
assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
|
assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
|
||||||
|
|
||||||
|
DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
|
||||||
|
|
||||||
|
if (!TxdOp::eop(desc)) {
|
||||||
|
assert(hLen == 0);
|
||||||
|
hLen = TxdOp::getLen(desc);
|
||||||
|
unusedCache.pop_front();
|
||||||
|
usedCache.push_back(desc);
|
||||||
|
pktDone = true;
|
||||||
|
pktWaiting = false;
|
||||||
|
pktPtr = NULL;
|
||||||
|
|
||||||
|
DPRINTF(EthernetDesc, "TxDesc: Partial Packet Descriptor Done\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the length of the data in the EtherPacket
|
||||||
|
pktPtr->length = TxdOp::getLen(desc) + hLen;
|
||||||
|
|
||||||
// no support for vlans
|
// no support for vlans
|
||||||
assert(!TxdOp::vle(desc));
|
assert(!TxdOp::vle(desc));
|
||||||
|
|
||||||
|
@ -843,6 +884,8 @@ IGbE::TxDescCache::pktComplete()
|
||||||
// set that this packet is done
|
// set that this packet is done
|
||||||
TxdOp::setDd(desc);
|
TxdOp::setDd(desc);
|
||||||
|
|
||||||
|
DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
|
||||||
|
|
||||||
// Checksums are only ofloaded for new descriptor types
|
// Checksums are only ofloaded for new descriptor types
|
||||||
if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
|
if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
|
||||||
DPRINTF(EthernetDesc, "TxDesc: Calculating checksums for packet\n");
|
DPRINTF(EthernetDesc, "TxDesc: Calculating checksums for packet\n");
|
||||||
|
@ -888,13 +931,25 @@ IGbE::TxDescCache::pktComplete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unusedCache.pop_front();
|
unusedCache.pop_front();
|
||||||
usedCache.push_back(desc);
|
usedCache.push_back(desc);
|
||||||
pktDone = true;
|
pktDone = true;
|
||||||
pktWaiting = false;
|
pktWaiting = false;
|
||||||
pktPtr = NULL;
|
pktPtr = NULL;
|
||||||
|
|
||||||
|
hLen = 0;
|
||||||
DPRINTF(EthernetDesc, "TxDesc: Descriptor Done\n");
|
DPRINTF(EthernetDesc, "TxDesc: Descriptor Done\n");
|
||||||
|
|
||||||
|
if (igbe->regs.txdctl.wthresh() == 0) {
|
||||||
|
DPRINTF(EthernetDesc, "TxDesc: WTHRESH == 0, writing back descriptor\n");
|
||||||
|
writeback(0);
|
||||||
|
} else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) {
|
||||||
|
DPRINTF(EthernetDesc, "TxDesc: used > WTHRESH, writing back descriptor\n");
|
||||||
|
writeback((igbe->cacheBlockSize()-1)>>4);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -911,9 +966,7 @@ void
|
||||||
IGbE::TxDescCache::enableSm()
|
IGbE::TxDescCache::enableSm()
|
||||||
{
|
{
|
||||||
igbe->txTick = true;
|
igbe->txTick = true;
|
||||||
if ((igbe->rxTick || igbe->txTick) && !igbe->tickEvent.scheduled())
|
igbe->restartClock();
|
||||||
igbe->tickEvent.schedule((curTick/igbe->cycles(1)) * igbe->cycles(1) +
|
|
||||||
igbe->cycles(1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -921,16 +974,27 @@ IGbE::TxDescCache::enableSm()
|
||||||
|
|
||||||
///////////////////////////////////// IGbE /////////////////////////////////
|
///////////////////////////////////// IGbE /////////////////////////////////
|
||||||
|
|
||||||
|
void
|
||||||
|
IGbE::restartClock()
|
||||||
|
{
|
||||||
|
if (!tickEvent.scheduled() && (rxTick || txTick))
|
||||||
|
tickEvent.schedule((curTick/cycles(1)) * cycles(1) + cycles(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
IGbE::txStateMachine()
|
IGbE::txStateMachine()
|
||||||
{
|
{
|
||||||
if (!regs.tctl.en()) {
|
if (!regs.tctl.en()) {
|
||||||
txTick = false;
|
txTick = false;
|
||||||
DPRINTF(EthernetSM, "TXS: RX disabled, stopping ticking\n");
|
DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (txPacket && txDescCache.packetAvailable()) {
|
// If we have a packet available and it's length is not 0 (meaning it's not
|
||||||
|
// a multidescriptor packet) put it in the fifo, otherwise an the next
|
||||||
|
// iteration we'll get the rest of the data
|
||||||
|
if (txPacket && txDescCache.packetAvailable() && txPacket->length) {
|
||||||
bool success;
|
bool success;
|
||||||
DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
|
DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
|
||||||
success = txFifo.push(txPacket);
|
success = txFifo.push(txPacket);
|
||||||
|
@ -952,25 +1016,27 @@ IGbE::txStateMachine()
|
||||||
|
|
||||||
if (!txDescCache.packetWaiting()) {
|
if (!txDescCache.packetWaiting()) {
|
||||||
if (txDescCache.descLeft() == 0) {
|
if (txDescCache.descLeft() == 0) {
|
||||||
DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing writeback\n");
|
DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
|
||||||
|
"writeback stopping ticking and posting TXQE\n");
|
||||||
txDescCache.writeback(0);
|
txDescCache.writeback(0);
|
||||||
DPRINTF(EthernetSM, "TXS: No descriptors left, stopping ticking\n");
|
|
||||||
txTick = false;
|
txTick = false;
|
||||||
|
postInterrupt(IT_TXQE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!(txDescCache.descUnused())) {
|
if (!(txDescCache.descUnused())) {
|
||||||
DPRINTF(EthernetSM, "TXS: No descriptors available in cache, stopping ticking\n");
|
DPRINTF(EthernetSM, "TXS: No descriptors available in cache, fetching and stopping ticking\n");
|
||||||
txTick = false;
|
txTick = false;
|
||||||
DPRINTF(EthernetSM, "TXS: No descriptors left, fetching\n");
|
|
||||||
txDescCache.fetchDescriptors();
|
txDescCache.fetchDescriptors();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int size;
|
int size;
|
||||||
size = txDescCache.getPacketSize();
|
size = txDescCache.getPacketSize();
|
||||||
if (size > 0 && rxFifo.avail() > size) {
|
if (size > 0 && txFifo.avail() > size) {
|
||||||
DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining DMA of next packet\n");
|
DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining "
|
||||||
rxFifo.reserve(size);
|
"DMA of next packet\n", size);
|
||||||
|
txFifo.reserve(size);
|
||||||
txDescCache.getPacketData(txPacket);
|
txDescCache.getPacketData(txPacket);
|
||||||
} else {
|
} else {
|
||||||
DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n");
|
DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n");
|
||||||
|
@ -994,7 +1060,7 @@ IGbE::ethRxPkt(EthPacketPtr pkt)
|
||||||
rxTick = true;
|
rxTick = true;
|
||||||
if ((rxTick || txTick) && !tickEvent.scheduled()) {
|
if ((rxTick || txTick) && !tickEvent.scheduled()) {
|
||||||
DPRINTF(EthernetSM, "RXS: received packet into fifo, starting ticking\n");
|
DPRINTF(EthernetSM, "RXS: received packet into fifo, starting ticking\n");
|
||||||
tickEvent.schedule(curTick/cycles(1) + cycles(1));
|
restartClock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rxFifo.push(pkt)) {
|
if (!rxFifo.push(pkt)) {
|
||||||
|
@ -1040,7 +1106,10 @@ IGbE::rxStateMachine()
|
||||||
|
|
||||||
if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
|
if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
|
||||||
DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n");
|
DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n");
|
||||||
rxDescCache.writeback(cacheBlockSize()-1);
|
if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
|
||||||
|
rxDescCache.writeback(regs.rxdctl.wthresh()-1);
|
||||||
|
else
|
||||||
|
rxDescCache.writeback((cacheBlockSize()-1)>>4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
|
if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
|
||||||
|
@ -1101,16 +1170,12 @@ IGbE::txWire()
|
||||||
txFifo.pop();
|
txFifo.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (txFifo.empty()) {
|
|
||||||
postInterrupt(IT_TXQE);
|
|
||||||
DPRINTF(Ethernet, "TxFIFO: Empty, posting interruppt\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IGbE::tick()
|
IGbE::tick()
|
||||||
{
|
{
|
||||||
DPRINTF(EthernetSM, "IGbE: -------------- Cycle -------------- ");
|
DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n");
|
||||||
|
|
||||||
if (rxTick)
|
if (rxTick)
|
||||||
rxStateMachine();
|
rxStateMachine();
|
||||||
|
@ -1129,8 +1194,7 @@ IGbE::ethTxDone()
|
||||||
{
|
{
|
||||||
// restart the state machines if they are stopped
|
// restart the state machines if they are stopped
|
||||||
txTick = true;
|
txTick = true;
|
||||||
if ((rxTick || txTick) && !tickEvent.scheduled())
|
restartClock();
|
||||||
tickEvent.schedule(curTick/cycles(1) + cycles(1));
|
|
||||||
DPRINTF(Ethernet, "TxFIFO: Transmission complete\n");
|
DPRINTF(Ethernet, "TxFIFO: Transmission complete\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1187,6 +1251,14 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(IGbE)
|
||||||
Param<uint32_t> pci_func;
|
Param<uint32_t> pci_func;
|
||||||
Param<Tick> pio_latency;
|
Param<Tick> pio_latency;
|
||||||
Param<Tick> config_latency;
|
Param<Tick> config_latency;
|
||||||
|
Param<std::string> hardware_address;
|
||||||
|
Param<bool> use_flow_control;
|
||||||
|
Param<int> rx_fifo_size;
|
||||||
|
Param<int> tx_fifo_size;
|
||||||
|
Param<int> rx_desc_cache_size;
|
||||||
|
Param<int> tx_desc_cache_size;
|
||||||
|
Param<Tick> clock;
|
||||||
|
|
||||||
|
|
||||||
END_DECLARE_SIM_OBJECT_PARAMS(IGbE)
|
END_DECLARE_SIM_OBJECT_PARAMS(IGbE)
|
||||||
|
|
||||||
|
@ -1199,7 +1271,14 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(IGbE)
|
||||||
INIT_PARAM(pci_dev, "PCI device number"),
|
INIT_PARAM(pci_dev, "PCI device number"),
|
||||||
INIT_PARAM(pci_func, "PCI function code"),
|
INIT_PARAM(pci_func, "PCI function code"),
|
||||||
INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
|
INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
|
||||||
INIT_PARAM(config_latency, "Number of cycles for a config read or write")
|
INIT_PARAM(config_latency, "Number of cycles for a config read or write"),
|
||||||
|
INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
|
||||||
|
INIT_PARAM(use_flow_control,"Should the device use xon/off packets"),
|
||||||
|
INIT_PARAM(rx_fifo_size,"Size of the RX FIFO"),
|
||||||
|
INIT_PARAM(tx_fifo_size,"Size of the TX FIFO"),
|
||||||
|
INIT_PARAM(rx_desc_cache_size,"Size of the RX descriptor cache"),
|
||||||
|
INIT_PARAM(tx_desc_cache_size,"Size of the TX descriptor cache"),
|
||||||
|
INIT_PARAM(clock,"Clock rate for the device to tick at")
|
||||||
|
|
||||||
END_INIT_SIM_OBJECT_PARAMS(IGbE)
|
END_INIT_SIM_OBJECT_PARAMS(IGbE)
|
||||||
|
|
||||||
|
@ -1217,6 +1296,14 @@ CREATE_SIM_OBJECT(IGbE)
|
||||||
params->functionNum = pci_func;
|
params->functionNum = pci_func;
|
||||||
params->pio_delay = pio_latency;
|
params->pio_delay = pio_latency;
|
||||||
params->config_delay = config_latency;
|
params->config_delay = config_latency;
|
||||||
|
params->hardware_address = hardware_address;
|
||||||
|
params->use_flow_control = use_flow_control;
|
||||||
|
params->rx_fifo_size = rx_fifo_size;
|
||||||
|
params->tx_fifo_size = tx_fifo_size;
|
||||||
|
params->rx_desc_cache_size = rx_desc_cache_size;
|
||||||
|
params->tx_desc_cache_size = tx_desc_cache_size;
|
||||||
|
params->clock = clock;
|
||||||
|
|
||||||
|
|
||||||
return new IGbE(params);
|
return new IGbE(params);
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,12 +78,12 @@ class IGbE : public PciDev
|
||||||
bool txTick;
|
bool txTick;
|
||||||
|
|
||||||
// Event and function to deal with RDTR timer expiring
|
// Event and function to deal with RDTR timer expiring
|
||||||
void rdtrProcess() { postInterrupt(iGbReg::IT_RXDMT, true); }
|
void rdtrProcess() { rxDescCache.writeback(0); postInterrupt(iGbReg::IT_RXT, true); }
|
||||||
//friend class EventWrapper<IGbE, &IGbE::rdtrProcess>;
|
//friend class EventWrapper<IGbE, &IGbE::rdtrProcess>;
|
||||||
EventWrapper<IGbE, &IGbE::rdtrProcess> rdtrEvent;
|
EventWrapper<IGbE, &IGbE::rdtrProcess> rdtrEvent;
|
||||||
|
|
||||||
// Event and function to deal with RADV timer expiring
|
// Event and function to deal with RADV timer expiring
|
||||||
void radvProcess() { postInterrupt(iGbReg::IT_RXDMT, true); }
|
void radvProcess() { rxDescCache.writeback(0); postInterrupt(iGbReg::IT_RXT, true); }
|
||||||
//friend class EventWrapper<IGbE, &IGbE::radvProcess>;
|
//friend class EventWrapper<IGbE, &IGbE::radvProcess>;
|
||||||
EventWrapper<IGbE, &IGbE::radvProcess> radvEvent;
|
EventWrapper<IGbE, &IGbE::radvProcess> radvEvent;
|
||||||
|
|
||||||
|
@ -131,6 +131,8 @@ class IGbE : public PciDev
|
||||||
|
|
||||||
Tick intClock() { return Clock::Int::ns * 1024; }
|
Tick intClock() { return Clock::Int::ns * 1024; }
|
||||||
|
|
||||||
|
void restartClock();
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
class DescCache
|
class DescCache
|
||||||
{
|
{
|
||||||
|
@ -141,6 +143,7 @@ class IGbE : public PciDev
|
||||||
virtual long descLen() const = 0;
|
virtual long descLen() const = 0;
|
||||||
virtual void updateHead(long h) = 0;
|
virtual void updateHead(long h) = 0;
|
||||||
virtual void enableSm() = 0;
|
virtual void enableSm() = 0;
|
||||||
|
virtual void intAfterWb() const {}
|
||||||
|
|
||||||
std::deque<T*> usedCache;
|
std::deque<T*> usedCache;
|
||||||
std::deque<T*> unusedCache;
|
std::deque<T*> unusedCache;
|
||||||
|
@ -206,7 +209,7 @@ class IGbE : public PciDev
|
||||||
void writeback(Addr aMask)
|
void writeback(Addr aMask)
|
||||||
{
|
{
|
||||||
int curHead = descHead();
|
int curHead = descHead();
|
||||||
int max_to_wb = usedCache.size() + curHead;
|
int max_to_wb = usedCache.size();
|
||||||
|
|
||||||
DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
|
DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
|
||||||
"%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
|
"%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
|
||||||
|
@ -226,13 +229,13 @@ class IGbE : public PciDev
|
||||||
moreToWb = false;
|
moreToWb = false;
|
||||||
wbAlignment = aMask;
|
wbAlignment = aMask;
|
||||||
|
|
||||||
if (max_to_wb > descLen()) {
|
if (max_to_wb + curHead > descLen()) {
|
||||||
max_to_wb = descLen() - curHead;
|
max_to_wb = descLen() - curHead;
|
||||||
moreToWb = true;
|
moreToWb = true;
|
||||||
// this is by definition aligned correctly
|
// this is by definition aligned correctly
|
||||||
} else if (aMask != 0) {
|
} else if (aMask != 0) {
|
||||||
// align the wb point to the mask
|
// align the wb point to the mask
|
||||||
max_to_wb = max_to_wb & ~(aMask>>4);
|
max_to_wb = max_to_wb & ~aMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
|
DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
|
||||||
|
@ -240,7 +243,7 @@ class IGbE : public PciDev
|
||||||
if (max_to_wb <= 0 || wbOut)
|
if (max_to_wb <= 0 || wbOut)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wbOut = max_to_wb - curHead;
|
wbOut = max_to_wb;
|
||||||
|
|
||||||
for (int x = 0; x < wbOut; x++)
|
for (int x = 0; x < wbOut; x++)
|
||||||
memcpy(&wbBuf[x], usedCache[x], sizeof(T));
|
memcpy(&wbBuf[x], usedCache[x], sizeof(T));
|
||||||
|
@ -251,8 +254,10 @@ class IGbE : public PciDev
|
||||||
usedCache.pop_front();
|
usedCache.pop_front();
|
||||||
};
|
};
|
||||||
|
|
||||||
igbe->dmaWrite(descBase() + curHead * sizeof(T), wbOut * sizeof(T),
|
|
||||||
&wbEvent, (uint8_t*)wbBuf);
|
assert(wbOut);
|
||||||
|
igbe->dmaWrite(igbe->platform->pciToDma(descBase() + curHead * sizeof(T)),
|
||||||
|
wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fetch a chunk of descriptors into the descriptor cache.
|
/** Fetch a chunk of descriptors into the descriptor cache.
|
||||||
|
@ -260,7 +265,7 @@ class IGbE : public PciDev
|
||||||
*/
|
*/
|
||||||
void fetchDescriptors()
|
void fetchDescriptors()
|
||||||
{
|
{
|
||||||
size_t max_to_fetch = cachePnt - descTail();
|
size_t max_to_fetch = descTail() - cachePnt;
|
||||||
if (max_to_fetch < 0)
|
if (max_to_fetch < 0)
|
||||||
max_to_fetch = descLen() - cachePnt;
|
max_to_fetch = descLen() - cachePnt;
|
||||||
|
|
||||||
|
@ -268,7 +273,7 @@ class IGbE : public PciDev
|
||||||
unusedCache.size()));
|
unusedCache.size()));
|
||||||
|
|
||||||
DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
|
DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
|
||||||
"%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
|
"%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
|
||||||
descHead(), descTail(), descLen(), cachePnt,
|
descHead(), descTail(), descLen(), cachePnt,
|
||||||
max_to_fetch, descLeft());
|
max_to_fetch, descLeft());
|
||||||
|
|
||||||
|
@ -279,7 +284,13 @@ class IGbE : public PciDev
|
||||||
// So we don't have two descriptor fetches going on at once
|
// So we don't have two descriptor fetches going on at once
|
||||||
curFetching = max_to_fetch;
|
curFetching = max_to_fetch;
|
||||||
|
|
||||||
igbe->dmaRead(descBase() + cachePnt * sizeof(T),
|
DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
|
||||||
|
descBase() + cachePnt * sizeof(T),
|
||||||
|
igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)),
|
||||||
|
curFetching * sizeof(T));
|
||||||
|
|
||||||
|
assert(curFetching);
|
||||||
|
igbe->dmaRead(igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)),
|
||||||
curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf);
|
curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,6 +314,8 @@ class IGbE : public PciDev
|
||||||
if (cachePnt > descLen())
|
if (cachePnt > descLen())
|
||||||
cachePnt -= descLen();
|
cachePnt -= descLen();
|
||||||
|
|
||||||
|
curFetching = 0;
|
||||||
|
|
||||||
DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
|
DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
|
||||||
oldCp, cachePnt);
|
oldCp, cachePnt);
|
||||||
|
|
||||||
|
@ -330,7 +343,7 @@ class IGbE : public PciDev
|
||||||
// Update the head
|
// Update the head
|
||||||
updateHead(curHead);
|
updateHead(curHead);
|
||||||
|
|
||||||
DPRINTF(EthernetDesc, "Writeback complete cachePnt %d -> %d\n",
|
DPRINTF(EthernetDesc, "Writeback complete curHead %d -> %d\n",
|
||||||
oldHead, curHead);
|
oldHead, curHead);
|
||||||
|
|
||||||
// If we still have more to wb, call wb now
|
// If we still have more to wb, call wb now
|
||||||
|
@ -338,6 +351,7 @@ class IGbE : public PciDev
|
||||||
DPRINTF(EthernetDesc, "Writeback has more todo\n");
|
DPRINTF(EthernetDesc, "Writeback has more todo\n");
|
||||||
writeback(wbAlignment);
|
writeback(wbAlignment);
|
||||||
}
|
}
|
||||||
|
intAfterWb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -352,7 +366,7 @@ class IGbE : public PciDev
|
||||||
if (cachePnt - descTail() >= 0)
|
if (cachePnt - descTail() >= 0)
|
||||||
left += (cachePnt - descTail());
|
left += (cachePnt - descTail());
|
||||||
else
|
else
|
||||||
left += (descLen() - cachePnt);
|
left += (descTail() - cachePnt);
|
||||||
|
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
@ -428,10 +442,12 @@ class IGbE : public PciDev
|
||||||
virtual long descLen() const { return igbe->regs.tdlen() >> 4; }
|
virtual long descLen() const { return igbe->regs.tdlen() >> 4; }
|
||||||
virtual void updateHead(long h) { igbe->regs.tdh(h); }
|
virtual void updateHead(long h) { igbe->regs.tdh(h); }
|
||||||
virtual void enableSm();
|
virtual void enableSm();
|
||||||
|
virtual void intAfterWb() const { igbe->postInterrupt(iGbReg::IT_TXDW);}
|
||||||
|
|
||||||
bool pktDone;
|
bool pktDone;
|
||||||
bool isTcp;
|
bool isTcp;
|
||||||
bool pktWaiting;
|
bool pktWaiting;
|
||||||
|
int hLen;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TxDescCache(IGbE *i, std::string n, int s);
|
TxDescCache(IGbE *i, std::string n, int s);
|
||||||
|
@ -467,6 +483,7 @@ class IGbE : public PciDev
|
||||||
public:
|
public:
|
||||||
struct Params : public PciDev::Params
|
struct Params : public PciDev::Params
|
||||||
{
|
{
|
||||||
|
Net::EthAddr hardware_address;
|
||||||
bool use_flow_control;
|
bool use_flow_control;
|
||||||
int rx_fifo_size;
|
int rx_fifo_size;
|
||||||
int tx_fifo_size;
|
int tx_fifo_size;
|
||||||
|
|
|
@ -173,18 +173,18 @@ Addr getBuf(TxDesc *d) { assert(isLegacy(d) || isData(d)); return d->d1; }
|
||||||
Addr getLen(TxDesc *d) { if (isLegacy(d)) return bits(d->d2,15,0); else return bits(d->d2, 19,0); }
|
Addr getLen(TxDesc *d) { if (isLegacy(d)) return bits(d->d2,15,0); else return bits(d->d2, 19,0); }
|
||||||
void setDd(TxDesc *d)
|
void setDd(TxDesc *d)
|
||||||
{
|
{
|
||||||
replaceBits(d->d1, 35, 32, 1);
|
replaceBits(d->d2, 35, 32, ULL(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ide(TxDesc *d) { return bits(d->d2, 31,31); }
|
bool ide(TxDesc *d) { return bits(d->d2, 31,31); }
|
||||||
bool vle(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 30,30); }
|
bool vle(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 30,30); }
|
||||||
bool rs(TxDesc *d) { return bits(d->d2, 28,28); }
|
bool rs(TxDesc *d) { return bits(d->d2, 27,27); }
|
||||||
bool ic(TxDesc *d) { assert(isLegacy(d) || isData(d)); return isLegacy(d) && bits(d->d2, 27,27); }
|
bool ic(TxDesc *d) { assert(isLegacy(d) || isData(d)); return isLegacy(d) && bits(d->d2, 26,26); }
|
||||||
bool tse(TxDesc *d) { return (isData(d) || isContext(d)) && bits(d->d2, 27,27); }
|
bool tse(TxDesc *d) { return (isData(d) || isContext(d)) && bits(d->d2, 26,26); }
|
||||||
bool ifcs(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 26,26); }
|
bool ifcs(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 25,25); }
|
||||||
bool eop(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 25,25); }
|
bool eop(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 24,24); }
|
||||||
bool ip(TxDesc *d) { assert(isContext(d)); return bits(d->d2, 26,26); }
|
bool ip(TxDesc *d) { assert(isContext(d)); return bits(d->d2, 25,25); }
|
||||||
bool tcp(TxDesc *d) { assert(isContext(d)); return bits(d->d2, 25,25); }
|
bool tcp(TxDesc *d) { assert(isContext(d)); return bits(d->d2, 24,24); }
|
||||||
|
|
||||||
uint8_t getCso(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 23,16); }
|
uint8_t getCso(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 23,16); }
|
||||||
uint8_t getCss(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 47,40); }
|
uint8_t getCss(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 47,40); }
|
||||||
|
@ -351,7 +351,7 @@ struct Regs {
|
||||||
ADD_FIELD32(txdlow,15,1) // transmit desc low thresh
|
ADD_FIELD32(txdlow,15,1) // transmit desc low thresh
|
||||||
ADD_FIELD32(srpd,16,1) // small receive packet detected
|
ADD_FIELD32(srpd,16,1) // small receive packet detected
|
||||||
ADD_FIELD32(ack,17,1); // receive ack frame
|
ADD_FIELD32(ack,17,1); // receive ack frame
|
||||||
ADD_FIELD32(int_assert, 31,0); // interrupt caused a system interrupt
|
ADD_FIELD32(int_assert, 31,1); // interrupt caused a system interrupt
|
||||||
};
|
};
|
||||||
ICR icr;
|
ICR icr;
|
||||||
|
|
||||||
|
@ -393,10 +393,10 @@ struct Regs {
|
||||||
int descSize()
|
int descSize()
|
||||||
{
|
{
|
||||||
switch(bsize()) {
|
switch(bsize()) {
|
||||||
case 0: return bsex() ? 2048 : -1;
|
case 0: return bsex() == 0 ? 2048 : -1;
|
||||||
case 1: return bsex() ? 1024 : 16384;
|
case 1: return bsex() == 0 ? 1024 : 16384;
|
||||||
case 2: return bsex() ? 512 : 8192;
|
case 2: return bsex() == 0 ? 512 : 8192;
|
||||||
case 3: return bsex() ? 256 : 4096;
|
case 3: return bsex() == 0 ? 256 : 4096;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -451,7 +451,7 @@ struct Regs {
|
||||||
|
|
||||||
struct RDBA : public Reg<uint64_t> { // 0x2800 RDBA Register
|
struct RDBA : public Reg<uint64_t> { // 0x2800 RDBA Register
|
||||||
using Reg<uint64_t>::operator=;
|
using Reg<uint64_t>::operator=;
|
||||||
ADD_FIELD64(rdbal,4,28); // base address of rx descriptor ring
|
ADD_FIELD64(rdbal,0,32); // base address of rx descriptor ring
|
||||||
ADD_FIELD64(rdbah,32,32); // base address of rx descriptor ring
|
ADD_FIELD64(rdbah,32,32); // base address of rx descriptor ring
|
||||||
};
|
};
|
||||||
RDBA rdba;
|
RDBA rdba;
|
||||||
|
@ -506,7 +506,7 @@ struct Regs {
|
||||||
|
|
||||||
struct TDBA : public Reg<uint64_t> { // 0x3800 TDBAL Register
|
struct TDBA : public Reg<uint64_t> { // 0x3800 TDBAL Register
|
||||||
using Reg<uint64_t>::operator=;
|
using Reg<uint64_t>::operator=;
|
||||||
ADD_FIELD64(tdbal,4,28); // base address of transmit descriptor ring
|
ADD_FIELD64(tdbal,0,32); // base address of transmit descriptor ring
|
||||||
ADD_FIELD64(tdbah,32,32); // base address of transmit descriptor ring
|
ADD_FIELD64(tdbah,32,32); // base address of transmit descriptor ring
|
||||||
};
|
};
|
||||||
TDBA tdba;
|
TDBA tdba;
|
||||||
|
|
|
@ -67,7 +67,14 @@ if build_env['ALPHA_TLASER']:
|
||||||
|
|
||||||
class IGbE(PciDevice):
|
class IGbE(PciDevice):
|
||||||
type = 'IGbE'
|
type = 'IGbE'
|
||||||
hardware_address = Param.EthernetAddr(NextEthernetAddr, "Ethernet Hardware Address")
|
hardware_address = Param.String("Ethernet Hardware Address")
|
||||||
|
use_flow_control = Param.Bool(False, "Should we use xon/xoff flow contorl (UNIMPLMENTD)")
|
||||||
|
rx_fifo_size = Param.MemorySize('384kB', "Size of the rx FIFO")
|
||||||
|
tx_fifo_size = Param.MemorySize('384kB', "Size of the tx FIFO")
|
||||||
|
rx_desc_cache_size = Param.Int(64, "Number of enteries in the rx descriptor cache")
|
||||||
|
tx_desc_cache_size = Param.Int(64, "Number of enteries in the rx descriptor cache")
|
||||||
|
clock = Param.Clock('500MHz', "Clock speed of the device")
|
||||||
|
|
||||||
|
|
||||||
class IGbEPciData(PciConfigData):
|
class IGbEPciData(PciConfigData):
|
||||||
VendorID = 0x8086
|
VendorID = 0x8086
|
||||||
|
|
Loading…
Reference in a new issue