OSDev.org

The Place to Start for Operating System Developers
It is currently Mon May 20, 2024 3:37 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 1 post ] 
Author Message
 Post subject: Init network chip for read without IRQ (PCNet/Am79C970A)
PostPosted: Mon Nov 30, 2020 1:52 pm 
Offline

Joined: Sun Nov 29, 2020 2:04 am
Posts: 1
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
Code:

#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;
       
}




Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1 post ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: SemrushBot [Bot] and 17 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group