Overhauled DMA bus master reads and writes and cleaned up the AMD PCnet code a bit (network queue implementation is pending).

This commit is contained in:
OBattler
2020-04-28 01:01:39 +02:00
parent bc3a2a3b20
commit 59822c6c0e
13 changed files with 361 additions and 232 deletions

View File

@@ -240,6 +240,7 @@ typedef struct {
uint32_t cLinkDownReported;
/** MS to wait before we enable the link. */
uint32_t cMsLinkUpDelay;
int transfer_size;
uint8_t maclocal[6]; /* configured MAC (local) address */
pc_timer_t timer_soft_int, timer_restore;
} nic_t;
@@ -423,6 +424,7 @@ pcnetIsLinkUp(nic_t *dev)
return !dev->fLinkTempDown && dev->fLinkUp;
}
/**
* Load transmit message descriptor
* Make sure we read the own flag first.
@@ -435,34 +437,36 @@ pcnetIsLinkUp(nic_t *dev)
static __inline int
pcnetTmdLoad(nic_t *dev, TMD *tmd, uint32_t addr, int fRetIfNotOwn)
{
uint8_t ownbyte;
uint8_t ownbyte, bytes[4] = { 0, 0, 0, 0 };
uint16_t xda[4];
uint32_t xda32[4];
if (BCR_SWSTYLE(dev) == 0) {
uint16_t xda[4];
DMAPageRead(addr+3, &ownbyte, 1);
dma_bm_read(addr, (uint8_t *) bytes, 4, dev->transfer_size);
ownbyte = bytes[3];
if (!(ownbyte & 0x80) && fRetIfNotOwn)
return 0;
DMAPageRead(addr, (uint8_t*)&xda[0], sizeof(xda));
dma_bm_read(addr, (uint8_t*)&xda[0], sizeof(xda), dev->transfer_size);
((uint32_t *)tmd)[0] = (uint32_t)xda[0] | ((uint32_t)(xda[1] & 0x00ff) << 16);
((uint32_t *)tmd)[1] = (uint32_t)xda[2] | ((uint32_t)(xda[1] & 0xff00) << 16);
((uint32_t *)tmd)[2] = (uint32_t)xda[3] << 16;
((uint32_t *)tmd)[3] = 0;
} else if (BCR_SWSTYLE(dev) != 3) {
DMAPageRead(addr+7, &ownbyte, 1);
dma_bm_read(addr + 4, (uint8_t *) bytes, 4, dev->transfer_size);
ownbyte = bytes[3];
if (!(ownbyte & 0x80) && fRetIfNotOwn)
return 0;
DMAPageRead(addr, (uint8_t*)tmd, 16);
dma_bm_read(addr, (uint8_t*)tmd, 16, dev->transfer_size);
} else {
uint32_t xda[4];
DMAPageRead(addr+7, &ownbyte, 1);
dma_bm_read(addr + 4, (uint8_t *) bytes, 4, dev->transfer_size);
ownbyte = bytes[3];
if (!(ownbyte & 0x80) && fRetIfNotOwn)
return 0;
DMAPageRead(addr, (uint8_t*)&xda[0], sizeof(xda));
((uint32_t *)tmd)[0] = xda[2];
((uint32_t *)tmd)[1] = xda[1];
((uint32_t *)tmd)[2] = xda[0];
((uint32_t *)tmd)[3] = xda[3];
dma_bm_read(addr, (uint8_t*)&xda32[0], sizeof(xda32), dev->transfer_size);
((uint32_t *)tmd)[0] = xda32[2];
((uint32_t *)tmd)[1] = xda32[1];
((uint32_t *)tmd)[2] = xda32[0];
((uint32_t *)tmd)[3] = xda32[3];
}
/* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */
if (tmd->tmd1.own == 1 && !(ownbyte & 0x80))
@@ -481,30 +485,39 @@ pcnetTmdLoad(nic_t *dev, TMD *tmd, uint32_t addr, int fRetIfNotOwn)
static __inline void
pcnetTmdStorePassHost(nic_t *dev, TMD *tmd, uint32_t addr)
{
uint8_t bytes[4] = { 0, 0, 0, 0 };
uint16_t xda[4];
uint32_t xda32[3];
if (BCR_SWSTYLE(dev) == 0) {
uint16_t xda[4];
dma_bm_read(addr, (uint8_t *) bytes, sizeof(xda), dev->transfer_size);
xda[0] = ((uint32_t *)tmd)[0] & 0xffff;
xda[1] = ((((uint32_t *)tmd)[0] >> 16) & 0xff) | ((((uint32_t *)tmd)[1]>>16) & 0xff00);
xda[2] = ((uint32_t *)tmd)[1] & 0xffff;
xda[3] = ((uint32_t *)tmd)[2] >> 16;
#if 0
xda[1] |= 0x8000;
DMAPageWrite(addr, (uint8_t*)&xda[0], sizeof(xda));
dma_bm_write(addr, (uint8_t*)&xda[0], sizeof(xda), dev->transfer_size);
#endif
xda[1] &= ~0x8000;
DMAPageWrite(addr+3, (uint8_t*)xda + 3, 1);
dma_bm_write(addr, (uint8_t*)&xda[0], sizeof(xda), dev->transfer_size);
} else if (BCR_SWSTYLE(dev) != 3) {
#if 0
((uint32_t*)tmd)[1] |= 0x80000000;
DMAPageWrite(addr, (uint8_t*)tmd, 12);
dma_bm_write(addr, (uint8_t*)tmd, 12, dev->transfer_size);
#endif
((uint32_t*)tmd)[1] &= ~0x80000000;
DMAPageWrite(addr+7, (uint8_t*)tmd + 7, 1);
dma_bm_write(addr, (uint8_t*)tmd, 12, dev->transfer_size);
} else {
uint32_t xda[3];
xda[0] = ((uint32_t *)tmd)[2];
xda[1] = ((uint32_t *)tmd)[1];
xda[2] = ((uint32_t *)tmd)[0];
xda[1] |= 0x80000000;
DMAPageWrite(addr, (uint8_t*)&xda[0], sizeof(xda));
xda[1] &= ~0x80000000;
DMAPageWrite(addr+7, (uint8_t*)xda + 7, 1);
xda32[0] = ((uint32_t *)tmd)[2];
xda32[1] = ((uint32_t *)tmd)[1];
xda32[2] = ((uint32_t *)tmd)[0];
#if 0
xda32[1] |= 0x80000000;
dma_bm_write(addr, (uint8_t*)&xda32[0], sizeof(xda32), dev->transfer_size);
#endif
xda32[1] &= ~0x80000000;
dma_bm_write(addr, (uint8_t*)&xda32[0], sizeof(xda32), dev->transfer_size);
}
}
@@ -521,33 +534,36 @@ pcnetTmdStorePassHost(nic_t *dev, TMD *tmd, uint32_t addr)
static __inline int
pcnetRmdLoad(nic_t *dev, RMD *rmd, uint32_t addr, int fRetIfNotOwn)
{
uint8_t ownbyte;
uint8_t ownbyte, bytes[4] = { 0, 0, 0, 0 };
uint16_t rda[4];
uint32_t rda32[4];
if (BCR_SWSTYLE(dev) == 0) {
uint16_t rda[4];
DMAPageRead(addr+3, &ownbyte, 1);
dma_bm_read(addr, (uint8_t *) bytes, 4, dev->transfer_size);
ownbyte = bytes[3];
if (!(ownbyte & 0x80) && fRetIfNotOwn)
return 0;
DMAPageRead(addr, (uint8_t*)&rda[0], sizeof(rda));
dma_bm_read(addr, (uint8_t*)&rda[0], sizeof(rda), dev->transfer_size);
((uint32_t *)rmd)[0] = (uint32_t)rda[0] | ((rda[1] & 0x00ff) << 16);
((uint32_t *)rmd)[1] = (uint32_t)rda[2] | ((rda[1] & 0xff00) << 16);
((uint32_t *)rmd)[2] = (uint32_t)rda[3];
((uint32_t *)rmd)[3] = 0;
} else if (BCR_SWSTYLE(dev) != 3) {
DMAPageRead(addr+7, &ownbyte, 1);
dma_bm_read(addr + 4, (uint8_t *) bytes, 4, dev->transfer_size);
ownbyte = bytes[3];
if (!(ownbyte & 0x80) && fRetIfNotOwn)
return 0;
DMAPageRead(addr, (uint8_t*)rmd, 16);
dma_bm_read(addr, (uint8_t*)rmd, 16, dev->transfer_size);
} else {
uint32_t rda[4];
DMAPageRead(addr+7, &ownbyte, 1);
dma_bm_read(addr + 4, (uint8_t *) bytes, 4, dev->transfer_size);
ownbyte = bytes[3];
if (!(ownbyte & 0x80) && fRetIfNotOwn)
return 0;
DMAPageRead(addr, (uint8_t*)&rda[0], sizeof(rda));
((uint32_t *)rmd)[0] = rda[2];
((uint32_t *)rmd)[1] = rda[1];
((uint32_t *)rmd)[2] = rda[0];
((uint32_t *)rmd)[3] = rda[3];
dma_bm_read(addr, (uint8_t*)&rda32[0], sizeof(rda32), dev->transfer_size);
((uint32_t *)rmd)[0] = rda32[2];
((uint32_t *)rmd)[1] = rda32[1];
((uint32_t *)rmd)[2] = rda32[0];
((uint32_t *)rmd)[3] = rda32[3];
}
/* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */
if (rmd->rmd1.own == 1 && !(ownbyte & 0x80))
@@ -567,52 +583,41 @@ pcnetRmdLoad(nic_t *dev, RMD *rmd, uint32_t addr, int fRetIfNotOwn)
static __inline void
pcnetRmdStorePassHost(nic_t *dev, RMD *rmd, uint32_t addr)
{
uint16_t rda[4];
uint32_t rda32[3];
if (BCR_SWSTYLE(dev) == 0) {
uint16_t rda[4];
rda[0] = ((uint32_t *)rmd)[0] & 0xffff;
rda[1] = ((((uint32_t *)rmd)[0]>>16) & 0xff) | ((((uint32_t *)rmd)[1]>>16) & 0xff00);
rda[2] = ((uint32_t *)rmd)[1] & 0xffff;
rda[3] = ((uint32_t *)rmd)[2] & 0xffff;
#if 0
rda[1] |= 0x8000;
DMAPageWrite(addr, (uint8_t*)&rda[0], sizeof(rda));
dma_bm_write(addr, (uint8_t*)&rda[0], sizeof(rda), dev->transfer_size);
#endif
rda[1] &= ~0x8000;
DMAPageWrite(addr+3, (uint8_t*)rda + 3, 1);
dma_bm_write(addr, (uint8_t*)&rda[0], sizeof(rda), dev->transfer_size);
} else if (BCR_SWSTYLE(dev) != 3) {
#if 0
((uint32_t*)rmd)[1] |= 0x80000000;
DMAPageWrite(addr, (uint8_t*)rmd, 12);
dma_bm_write(addr, (uint8_t*)rmd, 12, dev->transfer_size);
#endif
((uint32_t*)rmd)[1] &= ~0x80000000;
DMAPageWrite(addr+7, (uint8_t*)rmd + 7, 1);
dma_bm_write(addr, (uint8_t*)rmd, 12, dev->transfer_size);
} else {
uint32_t rda[3];
rda[0] = ((uint32_t *)rmd)[2];
rda[1] = ((uint32_t *)rmd)[1];
rda[2] = ((uint32_t *)rmd)[0];
rda[1] |= 0x80000000;
DMAPageWrite(addr, (uint8_t*)&rda[0], sizeof(rda));
rda[1] &= ~0x80000000;
DMAPageWrite(addr+7, (uint8_t*)rda + 7, 1);
rda32[0] = ((uint32_t *)rmd)[2];
rda32[1] = ((uint32_t *)rmd)[1];
rda32[2] = ((uint32_t *)rmd)[0];
#if 0
rda32[1] |= 0x80000000;
dma_bm_write(addr, (uint8_t*)&rda32[0], sizeof(rda32), dev->transfer_size);
#endif
rda32[1] &= ~0x80000000;
dma_bm_write(addr, (uint8_t*)&rda32[0], sizeof(rda32), dev->transfer_size);
}
}
/**
* Read+Write a TX/RX descriptor to prevent DMAPageWrite() allocating
* pages later when we shouldn't schedule to EMT. Temporarily hack.
*/
static void
pcnetDescTouch(nic_t *dev, uint32_t addr)
{
uint8_t aBuf[16];
int cbDesc;
if (BCR_SWSTYLE(dev) == 0)
cbDesc = 8;
else
cbDesc = 16;
DMAPageRead(addr, aBuf, cbDesc);
DMAPageWrite(addr, aBuf, cbDesc);
}
/** Checks if it's a bad (as in invalid) RMD.*/
#define IS_RMD_BAD(rmd) ((rmd).rmd1.ones != 15)
@@ -926,8 +931,8 @@ pcnetInit(nic_t *dev)
/** @todo Documentation says that RCVRL and XMTRL are stored as two's complement!
* Software is allowed to write these registers directly. */
#define PCNET_INIT() do { \
DMAPageRead(PHYSADDR(dev, CSR_IADR(dev)), \
(uint8_t *)&initblk, sizeof(initblk)); \
dma_bm_read(PHYSADDR(dev, CSR_IADR(dev)), \
(uint8_t *)&initblk, sizeof(initblk), dev->transfer_size); \
dev->aCSR[15] = le16_to_cpu(initblk.mode); \
CSR_RCVRL(dev) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \
CSR_XMTRL(dev) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \
@@ -964,7 +969,6 @@ pcnetInit(nic_t *dev)
RMD rmd;
uint32_t rdaddr = PHYSADDR(dev, pcnetRdraAddr(dev, i));
pcnetDescTouch(dev, rdaddr);
/* At this time it is not guaranteed that the buffers are already initialized. */
if (pcnetRmdLoad(dev, &rmd, rdaddr, 0)) {
uint32_t cbBuf = 4096U-rmd.rmd1.bcnt;
@@ -972,12 +976,6 @@ pcnetInit(nic_t *dev)
}
}
for (i = CSR_XMTRL(dev); i >= 1; i--) {
uint32_t tdaddr = PHYSADDR(dev, pcnetTdraAddr(dev, i));
pcnetDescTouch(dev, tdaddr);
}
/*
* Heuristics: The Solaris pcn driver allocates too few RX buffers (128 buffers of a
* size of 128 bytes are 16KB in summary) leading to frequent RX buffer overflows. In
@@ -1339,8 +1337,8 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size)
* forbidden as long as it is owned by the device
* - we don't cache any register state beyond this point
*/
DMAPageWrite(rbadr, src, cbBuf);
dma_bm_write(rbadr, src, cbBuf, dev->transfer_size);
/* RX disabled in the meantime? If so, abort RX. */
if (CSR_DRX(dev) || CSR_STOP(dev) || CSR_SPND(dev)) {
@@ -1383,7 +1381,7 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size)
/* We have to leave the critical section here or we risk deadlocking
* with EMT when the write is to an unallocated page or has an access
* handler associated with it. See above for additional comments. */
DMAPageWrite(rbadr2, src, cbBuf);
dma_bm_write(rbadr2, src, cbBuf, dev->transfer_size);
/* RX disabled in the meantime? If so, abort RX. */
if (CSR_DRX(dev) || CSR_STOP(dev) || CSR_SPND(dev)) {
@@ -1508,7 +1506,7 @@ pcnetAsyncTransmit(nic_t *dev)
* zero length if it is not the last one in the chain. */
if (cb <= MAX_FRAME) {
dev->xmit_pos = cb;
DMAPageRead(PHYSADDR(dev, tmd.tmd0.tbadr), dev->abLoopBuf, cb);
dma_bm_read(PHYSADDR(dev, tmd.tmd0.tbadr), dev->abLoopBuf, cb, dev->transfer_size);
if (fLoopback) {
if (HOST_IS_OWNER(CSR_CRST(dev)))
@@ -1574,7 +1572,7 @@ pcnetAsyncTransmit(nic_t *dev)
*/
unsigned cb = 4096 - tmd.tmd1.bcnt;
dev->xmit_pos = pcnetCalcPacketLen(dev, cb);
DMAPageRead(PHYSADDR(dev, tmd.tmd0.tbadr), dev->abLoopBuf, cb);
dma_bm_read(PHYSADDR(dev, tmd.tmd0.tbadr), dev->abLoopBuf, cb, dev->transfer_size);
for (;;) {
/*
@@ -1613,7 +1611,7 @@ pcnetAsyncTransmit(nic_t *dev)
if (dev->xmit_pos + cb <= MAX_FRAME) { /** @todo this used to be ... + cb < MAX_FRAME. */
int off = dev->xmit_pos;
dev->xmit_pos = cb + off;
DMAPageRead(PHYSADDR(dev, tmd.tmd0.tbadr), dev->abLoopBuf + off, cb);
dma_bm_read(PHYSADDR(dev, tmd.tmd0.tbadr), dev->abLoopBuf + off, cb, dev->transfer_size);
}
/*
@@ -2834,6 +2832,11 @@ pcnet_init(const device_t *info)
dev->is_vlb = !!(info->flags & DEVICE_VLB);
dev->is_isa = !!(info->flags & (DEVICE_ISA | DEVICE_AT));
if (dev->is_pci || dev->is_vlb)
dev->transfer_size = 4;
else
dev->transfer_size = 2;
if (dev->is_pci) {
pcnet_mem_init(dev, 0x0fffff00);
pcnet_mem_disable(dev);