OSDev.org

The Place to Start for Operating System Developers
It is currently Tue Aug 21, 2018 12:14 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: (Solved) RTL8139 not receiving on real hw.
PostPosted: Tue Aug 07, 2018 10:50 am 
Offline

Joined: Thu Apr 19, 2018 5:31 am
Posts: 12
Hi everyone,

I know that there have been a lot of post here about the rtl8139 NIC, and I have looked at almost all of them but I can't seem to figure out why i am experiencing this particular problem. The last 2 months I think I have been trying to implement a small networking stack for my os, and this is so far going very good. So far I had only tested it on Qemu and there it worked fine with the driver I wrote for the rtl8139 nic. Luckily I also have one of those in my computers, so of course i wanted to test it on real hardware. As expected by the title, this did not work. Sending and receiving works fine on Qemu, but on my real pc the NIC would only send packets. Even if the led blinks, indicating that there is data arriving my interrupt handler does not get called for some reason. Like I have said, I have looked at many forum posts and existing drivers but I can not seem to figure out why my interrupt handler does not get called for received packets, I do get a interrupt when a packet is successfully send.
This is my code to initialize the card:
Code:
void RTL8139::Activate()
{
    printf("Activating RTL8139\n");
    outportb(device->portBase + 0x52, 0x0);

    Reset();

    rx_buffer = (char*) MemoryManager::activeMemoryManager->malloc (8192 + 16 + 1500);
    MemoryOperations::memset(rx_buffer, 0x0, 8192 + 16 + 1500);
    outportl(device->portBase + 0x30, (uint32_t)rx_buffer);

    // Sets the TOK and ROK bits high
    outportw(device->portBase + 0x3C, 0x0005);

    // (1 << 7) is the WRAP bit, 0xf is AB+AM+APM+AAP
    outportl(device->portBase + 0x44, 0xf | (1 << 7));

    // Sets the RE and TE bits high
    outportb(device->portBase + 0x37, 0x0C);
}
void RTL8139::Reset()
{
    printf("Resetting\n");
    outportb(device->portBase + 0x37, 0x10);
    while((inportb(device->portBase + 0x37) & 0x10) != 0) {
        printf(".");
    }
}

The full code can be found here: https://github.com/Remco123/CactusOS/blob/master/src/system/drivers/rtl8139.cpp
And my repo: https://github.com/Remco123/CactusOS

Thank you for reading and hope that anyone knows how to fix this.
By the way: sorry if my English isn't perfect :D


Last edited by GhelloWorld on Wed Aug 08, 2018 3:54 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: RTL8139 not receiving on real hw.
PostPosted: Tue Aug 07, 2018 1:16 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 412
Location: USA
Hi,

Since I am currently working on network documentation, I think I will try to help you with this one.

First, when my code, network or otherwise, works on the emulator but not on real hardware, I look at things that are related to this idea. For example, an emulator may initialize a register to zero, that's just what software tends to do. However, actual hardware usually does not. Therefore, look at these sort of things.

Next, and looking at your code you posted, it doesn't look like you set the length of the buffer. The RTL8139 has a "Len of Buffer" register as well as FIFO threshold and Burst size. If you don't set this register, the hardware might think you have a zero sized input memory block and won't write anything, therefore, not triggering an interrupt saying it received a packet. (More of a RTL8169 issue).
Code:
    // (1 << 7) is the WRAP bit, 0xf is AB+AM+APM+AAP
    outportl(device->portBase + 0x44, 0xf | (1 << 7));

What about the field at bit 13 and bit 11? The first being the FIFO threshold and the second being the length of the buffer. Right now you set it to 8K by writing a zero to it. The FIFO is set to 16 bytes, again writing a zero. The FIFO is something the emulator probably won't emulate, hence this would be something to look into. i.e.: Works on the emulator (that doesn't emulate the FIFO) but doesn't work on real hardware (something that does use an FIFO).

Something that I have noticed with other chips, not the RTL8139 (yet) is that reset might reset the current MAC. For example, the E100 will not receive anything but multi's due to it settings its internal MAC to FF FF FF FF FF FF upon reset. You have to actually tell it what MAC to use. Does the RTL8139 reset its MAC upon reset (something I haven't tested for yet. I simply re-assign a MAC after reset by default). Maybe the emulator always uses the same MAC while the hardware needs the MAC re-assigned after the reset. Try re-writting the MAC back to the RTL8139_IDR0 register, remembering to set the RTL8139_CR9346 register to 0xC0 first (and restoring it after done).

So, with this in mind, and thinking about it, I bet you simply need to restore the MAC address after a reset and before telling the NIC to start receiving packets. The NIC is probably receiving packets, comparing it to your MAC (which is probably 00 00 00 00 00 00 or FF FF FF FF FF FF) and rejecting the packet.

Try it.

Ben
- http://www.fysnet.net/osdesign_book_series.htm


Top
 Profile  
 
 Post subject: (Solved) RTL8139 not receiving on real hw.
PostPosted: Wed Aug 08, 2018 3:48 am 
Offline

Joined: Thu Apr 19, 2018 5:31 am
Posts: 12
Hi Ben,

Thank you for your answer. I can confirm that the mac address of my nic does not get reset, so I don't have to write it to the card. But thank you for thinking about this. I did solve the problem though and it was in the same line of code you suggested.
Code:
    // (1 << 7) is the WRAP bit, 0xf is AB+AM+APM+AAP
    outportl(device->portBase + 0x44, 0xf | (1 << 7));

Before I had this:
Code:
    // (1 << 7) is the WRAP bit, 0xf is AB+AM+APM+AAP
    outportl(device->portBase + 0x44, 0xf | (1 << 7));

    // Sets the RE and TE bits high
    outportb(device->portBase + 0x37, 0x0C);

But when I changed it to this everything works:
Code:
    // Sets the RE and TE bits high
    outportb(device->portBase + 0x37, 0x0C);

    // (1 << 7) is the WRAP bit, 0xf is AB+AM+APM+AAP
    outportl(device->portBase + 0x44, 0xF);

Now I am succesfully receiving arp packets on my real network. Thanks again Ben although I feel like I should have been able to figure it out my self and I am sorry that this was solved so easy.


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 9 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