Init network chip for read without IRQ (PCNet/Am79C970A)
Posted: Mon Nov 30, 2020 1:52 pm
Hello!
I try to change network card in my project from e1000 to Amd PCNet(Am79C970A). The method described inhttps://wiki.osdev.org/AMD_PCNET
But I don't use interrupt for receive. My variant of code can send packets but cannot receive. Receive takes back descriptor with errors BUFF and OFLO.
The code is JOS MIT operating system. I do this project for myself.
I don't have any idea where is error as its not LAPPEN mode. All the receive descriptor owned by card.
Is it possible to read without interrupt using polling?
How to init receiving without interrupt?
This is my code of init receive and send based on https://wiki.osdev.org/AMD_PCNET
I try to change network card in my project from e1000 to Amd PCNet(Am79C970A). The method described inhttps://wiki.osdev.org/AMD_PCNET
But I don't use interrupt for receive. My variant of code can send packets but cannot receive. Receive takes back descriptor with errors BUFF and OFLO.
The code is JOS MIT operating system. I do this project for myself.
I don't have any idea where is error as its not LAPPEN mode. All the receive descriptor owned by card.
Is it possible to read without interrupt using polling?
How to init receiving without interrupt?
This is my code of init receive and send based on https://wiki.osdev.org/AMD_PCNET
Code: Select all
#include <kern/pmap.h>
#include <inc/string.h>
#include <inc/x86.h>
#include <kern/picirq.h>
volatile void *bar_va;
int rx_buffer_ptr = 0;
int tx_buffer_ptr = 0; // pointers to transmit/receive buffers
const int buffer_size = 1518; // length of each packet buffer
int rx_buffer_count = 128;
int tx_buffer_count = 8;
const int de_size = 16; // length of descriptor entry
uint8_t rdes[16*128]; // pointer to ring buffer of receive DEs
uint8_t tdes[16*8]; // pointer to ring buffer of transmit DEs
uint8_t rx_buffers[1518*128]; // physical address of actual receive buffers (< 4 GiB)
uint8_t tx_buffers[1518*8]; // physical address of actual transmit buffers (< 4 GiB)
uint32_t E1000_MAC[6] = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56};
uint8_t manager[6000];
// does the driver own the particular buffer?
int driverOwns(uint8_t *des, int idx)
{
return (des[de_size * idx + 7] & 0x80) == 0;
}
// get the next transmit buffer index
int nextTxIdx(int cur_tx_idx)
{
int ret = cur_tx_idx + 1;
if(ret == tx_buffer_count)
ret = 0;
return ret;
}
// get the next receive buffer index
int nextRxIdx(int cur_rx_idx)
{
int ret = cur_rx_idx + 1;
if(ret == rx_buffer_count)
ret = 0;
return ret;
}
// initialize a DE
void initDE(uint8_t *des, int idx, int is_tx)
{
memset(&des[idx * de_size], 0, de_size);
// first 4 bytes are the physical address of the actual buffer
uint32_t buf_addr = rx_buffers;
if(is_tx)
buf_addr = tx_buffers;
*(uint32_t *)&des[idx * de_size] =PADDR( buf_addr + idx * buffer_size);
// next 2 bytes are 0xf000 OR'd with the first 12 bits of the 2s complement of the length
uint16_t bcnt = (uint16_t)(-buffer_size);
bcnt &= 0x0fff;
bcnt |= 0xf000;
*(uint16_t *)&des[idx * de_size + 4] = bcnt;
// finally, set ownership bit - transmit buffers are owned by us, receive buffers by the card
if(!is_tx)
des[idx * de_size + 7] = 0x80;
}
void writeRAP32(uint32_t val)
{
outl(E1000REG(0x14), val);
}
void writeRAP16(uint16_t val)
{
outw(E1000REG(0x12), val);
}
uint32_t readCSR32(uint32_t csr_no)
{
writeRAP32(csr_no);
return inl(E1000REG(0x10));
}
uint16_t readCSR16(uint16_t csr_no)
{
writeRAP16(csr_no);
return inw(E1000REG(0x10));
}
void writeCSR32(uint32_t csr_no, uint32_t val)
{
writeRAP32(csr_no);
outl(E1000REG(0x10), val);
}
void writeCSR16(uint16_t csr_no, uint16_t val)
{
writeRAP16(csr_no);
outw(E1000REG(0x10), val);
}
void Reset()
{
uint32_t a = *( (uint32_t*)E1000REG(0x18));
uint16_t b = *( (uint16_t*)E1000REG(0x14));
int i = 0;
while(i<16000000)
{
i++;
}
writeCSR32(0, 0);
uint32_t csr58 = readCSR32(58);
csr58 &= 0xFF00; // SWSTYLE is 8 bits (7:0)
csr58 |= 2;
writeCSR32(58, csr58);
uint32_t bcr2 = inl(E1000REG(0x1c));
bcr2 |= 2;
writeRAP32(58);
outl(E1000REG(0x1c), csr58);
}
static void am79c973_init()
{
uint8_t l = 3;
uint8_t l2 = 7;
*(manager+3) = l<<4; //tr len
*(manager+2) = l2<<4; //rx len
*((uint16_t*)manager)=0x0000;
*(manager+4)=E1000_MAC[0];
*(manager+5)=E1000_MAC[1];
*(manager+6)=E1000_MAC[2];
*(manager+7)=E1000_MAC[3];
*(manager+8)=E1000_MAC[4];
*(manager+9)=E1000_MAC[5];
*(manager+10)=0;
*(manager+11)=0;
*(manager+12)=0;
*(manager+13)=0;
*(manager+14)=0;
*(manager+15)=0;
*(manager+16)=0;
*(manager+17)=0;
*(manager+18)=0;
*(manager+19)=0;
*((uint32_t*)(manager+20))=PADDR(rdes); // descriptor phys addr
*((uint32_t*)(manager+24))=PADDR(tdes);
rx_buffer_ptr = 0;
tx_buffer_ptr = 0;
int i;
//init descriptors
for( i = 0; i < 8; i++)
{
initDE(tdes, i, 1);
}
for( i = 0; i < 128; i++)
{
initDE(rdes, i, 0);
}
// write init structure addr
writeCSR32 (1, PADDR(manager) & 0xFFFF );
writeCSR32 (2, (PADDR(manager) >> 16) & 0xFFFF );
// disable interrupts
uint32_t csr3 =readCSR32(3);
csr3 |= 1UL << 10;
csr3 |= 1UL << 8;
csr3 |= 1UL << 9;
writeCSR32(3, csr3);
// begin inititalization
uint32_t st = readCSR32(0);
//set
st |= 1UL << 0;
writeCSR32(0, st);
// wait for complete
do{
st = readCSR32(0);
} while(!(st&(1UL << 8)));
// start the board
st = readCSR32(0);
st |= 1UL << 1;
writeCSR32(0, st);
}
int e1000_attachfn(struct pci_func *pcif)
{
pci_func_enable(pcif);
cprintf("reg_base:%x, reg_size:%x\n", pcif->reg_base[0], pcif->reg_size[0]);
//Exercise4 create virtual memory mapping
bar_va =pcif->reg_base[0];
Reset();
am79c973_init();
return 0;
}
int e1000_transmit(void *buffer, size_t size)
{
if(!driverOwns(tdes, tx_buffer_ptr))
{
return -E_TRANSMIT_RETRY;
}
memcpy((void *)(tx_buffers + tx_buffer_ptr * buffer_size), buffer, size);
tdes[tx_buffer_ptr * de_size + 7] |= 0x2;
tdes[tx_buffer_ptr * de_size + 7] |= 0x1;
uint16_t bcnt = (uint16_t)(-size);
bcnt &= 0xfff;
bcnt |= 0xf000;
*(uint16_t *)&tdes[tx_buffer_ptr * de_size + 4] = bcnt;
// finally, flip the ownership bit back to the card
tdes[tx_buffer_ptr * de_size + 7] |= 0x80;
// update the next transmit pointer
tx_buffer_ptr = nextTxIdx(tx_buffer_ptr);
return 0;
}
int e1000_receive(void *addr, size_t *len)
{
*len =0;
int ret = -E_RECEIVE_RETRY;
char* shiftedAddr = addr;
while(driverOwns(rdes, rx_buffer_ptr))
{
// packet length is given by bytes 8 and 9 of the descriptor
// (no need to negate it unlike BCNT above)
uint16_t plen = *(uint16_t *)&rdes[rx_buffer_ptr * de_size + 8];
// the packet itself is written somewhere in the receive buffer
void *pbuf = (void *)(rx_buffers + rx_buffer_ptr * buffer_size);
memcpy(shiftedAddr, pbuf, plen);
*len+=plen;
shiftedAddr+=plen;
// hand the buffer back to the card
rdes[rx_buffer_ptr * de_size + 7] = 0x80;
// increment rx_buffer_ptr;
rx_buffer_ptr = nextRxIdx(rx_buffer_ptr);
ret =0;
}
return ret;
}