#include "drv/amd_am79c973.hpp"
#include <cstdint>
#include <new>
#include "hwcomm/PCI.hpp"
#include "print.hpp"
using namespace drv;
using namespace hwcomm;
amd_am79c973::amd_am79c973(const PCIDeviceDescr &dev,
InterruptManager &interrupts)
: InterruptHandler(dev.interrupt + interrupts.getIRQBase()),
macAddress0Port(dev.portBase),
macAddress2Port(dev.portBase + 0x02),
macAddress4Port(dev.portBase + 0x04),
registerDataPort(dev.portBase + 0x10),
registerAddressPort(dev.portBase + 0x12),
resetPort(dev.portBase + 0x14),
busControlRegisterDataPort(dev.portBase + 0x16)
{
currentSendBuffer = 0;
currentRecvBuffer = 0;
std::uint64_t MAC0 = macAddress0Port.read() % 256;
std::uint64_t MAC1 = macAddress0Port.read() / 256;
std::uint64_t MAC2 = macAddress2Port.read() % 256;
std::uint64_t MAC3 = macAddress2Port.read() / 256;
std::uint64_t MAC4 = macAddress4Port.read() % 256;
std::uint64_t MAC5 = macAddress4Port.read() / 256;
std::uint64_t MAC = MAC5 << 40
| MAC4 << 32
| MAC3 << 24
| MAC2 << 16
| MAC1 << 8
| MAC0;
// 32 bit mode.
registerAddressPort.write(20);
busControlRegisterDataPort.write(0x102);
// STOP reset.
registerAddressPort.write(0);
registerDataPort.write(0x04);
initBlock.mode = 0x0000; // Promiscuous mode = false.
initBlock.reserved1 = 0;
initBlock.numSendBuffers = 3;
initBlock.reserved2 = 0;
initBlock.numRecvBuffers = 3;
initBlock.physicalAddress = MAC;
initBlock.reserved3 = 0;
initBlock.logicalAddress = 0;
auto addr = [](void *ptr) {
return reinterpret_cast<std::uint32_t>(ptr);
};
auto align = [&addr](void *ptr) {
auto mask = ~static_cast<std::uint32_t>(0xf);
return ((addr(ptr) + 15) & mask);
};
auto alignP = [&align](void *ptr) {
return reinterpret_cast<void *>(align(ptr));
};
sendBufferDescr = new(alignP(&sendBufferDescrMem[0])) BufferDescriptor[8];
initBlock.sendBufferDescrAddress = addr(sendBufferDescr);
recvBufferDescr = new(alignP(&recvBufferDescrMem[0])) BufferDescriptor[8];
initBlock.recvBufferDescrAddress = addr(recvBufferDescr);
for (std::uint8_t i = 0; i < 8; ++i) {
sendBufferDescr[i].address = align(&sendBuffers[i]);
sendBufferDescr[i].flags = 0x7ff
| 0xf000;
sendBufferDescr[i].flags2 = 0;
sendBufferDescr[i].avail = 0;
recvBufferDescr[i].address = align(&recvBuffers[i]);
recvBufferDescr[i].flags = 0xf7ff
| 0x80000000;
recvBufferDescr[i].flags2 = 0;
sendBufferDescr[i].avail = 0;
}
registerAddressPort.write(1);
registerDataPort.write(addr(&initBlock) & 0xffff);
registerAddressPort.write(2);
registerDataPort.write((addr(&initBlock) >> 16) & 0xffff);
}
void
amd_am79c973::activate()
{
registerAddressPort.write(0);
registerDataPort.write(0x41);
registerAddressPort.write(4);
std::uint32_t temp = registerDataPort.read();
registerAddressPort.write(4);
registerDataPort.write(temp | 0xC00);
registerAddressPort.write(0);
registerDataPort.write(0x42);
}
int
amd_am79c973::reset()
{
resetPort.read();
resetPort.write(0);
return 10;
}
const char *
amd_am79c973::getName() const
{
return "amd_am79c973";
}
std::uint32_t
amd_am79c973::handleInterrupt(std::uint32_t esp)
{
kprint("INTERRUPT FROM AMD am79c973\n");
registerAddressPort.write(0);
std::uint32_t temp = registerDataPort.read();
if ((temp & 0x8000) == 0x8000) kprint("AMD am79c973 ERROR\n");
if ((temp & 0x2000) == 0x2000) kprint("AMD am79c973 COLLISION ERROR\n");
if ((temp & 0x1000) == 0x1000) kprint("AMD am79c973 MISSED FRAME\n");
if ((temp & 0x0800) == 0x0800) kprint("AMD am79c973 MEMORY ERROR\n");
if ((temp & 0x0400) == 0x0400) receive();
if ((temp & 0x0200) == 0x0200) kprint("AMD am79c973 DATA SENT\n");
// Acknowledge.
registerAddressPort.write(0);
registerDataPort.write(temp);
if((temp & 0x0100) == 0x0100) kprint("AMD am79c973 INIT DONE\n");
return esp;
}
void
amd_am79c973::send(span<const std::uint8_t> msg)
{
BufferDescriptor &descr = sendBufferDescr[currentSendBuffer];
currentSendBuffer = (currentSendBuffer + 1) % 8;
if (msg.size() > 1518) {
msg = msg.first(1518);
}
auto dst = reinterpret_cast<std::uint8_t *>(descr.address);
for (std::uint8_t b : msg) {
*dst++ = b;
}
descr.avail = 0;
descr.flags2 = 0;
descr.flags = 0x8300f000
| (static_cast<std::uint16_t>((-msg.size()) & 0xfff));
registerAddressPort.write(0);
registerDataPort.write(0x48);
}
void
amd_am79c973::receive()
{
kprint("AMD am79c973 DATA RECEIVED\n");
for (; (recvBufferDescr[currentRecvBuffer].flags & 0x80000000) == 0;
currentRecvBuffer = (currentRecvBuffer + 1) % 8) {
BufferDescriptor &descr = recvBufferDescr[currentRecvBuffer];
if (!(descr.flags & 0x40000000) &&
(descr.flags & 0x03000000) == 0x03000000)
{
std::uint32_t size = descr.flags & 0xFFF;
if (size > 64) {
// Drop checksum.
size -= 4;
}
auto buffer = reinterpret_cast<std::uint8_t *>(descr.address);
if (handler != nullptr) {
span<std::uint8_t> payload(buffer, size);
if (handler->onRawDataReceived(payload)) {
send(payload);
}
}
}
descr.flags2 = 0;
descr.flags = 0x8000f7ff;
}
}
NetOrder<std::uint64_t>
amd_am79c973::getMAC() const
{
return netOrder(initBlock.physicalAddress);
}
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"
Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/tos
Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/tos
You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a
pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master