Page 1 of 1

[Solved] Help! My E1000 Driver Cannot Receive Anything

Posted: Tue Aug 17, 2021 11:04 am
by nifanfa
Hello! I'm trying to implement E1000 support for MOSA.
But i don't know why my driver can only send packet but cannot receive packet.
Here's my code:

Code: Select all

using Mosa.External.x86;
using Mosa.Kernel;
using Mosa.Kernel.x86;
using Mosa.Runtime;
using System.Runtime.InteropServices;
using static Mosa.External.x86.MMIO;

namespace MOSA9
{
    public static unsafe class Intel82540EM
    {
        public static uint BAR0;

        public static uint RXDescs;

        public static uint TXDescs;

        public static void Init()
        {
            PCIDevice device = PCI.GetDevice(VendorID.Intel, (DeviceID)0x100E);
            Console.WriteLine("Intel 82540EM Exist");
            device.EnableDevice();

            BAR0 = (uint)(device.BAR0 & (~3));
            Map(BAR0, 0x10000);
            Console.WriteLine($"BAR0:{BAR0.ToString("x2")}");

            WriteRegister(0x14, 0x1);
            bool HasEEPROM = false;
            for (int i = 0; i < 1024; i++)
            {
                if ((ReadRegister(0x14) & 0x10) != 0)
                {
                    HasEEPROM = true;
                    break;
                }
            }
            if (!HasEEPROM) 
            {
                Panic.Error("No EEPROM Found On This Network Card");
            }
            else 
            {
                Console.WriteLine("EEPROM Exist");
            }

            Ethernet.MACAddress = new byte[6];
            Ethernet.MACAddress[0] = (byte)(ReadROM(0) & 0xFF);
            Ethernet.MACAddress[1] = (byte)(ReadROM(0) >> 8);
            Ethernet.MACAddress[2] = (byte)(ReadROM(1) & 0xFF);
            Ethernet.MACAddress[3] = (byte)(ReadROM(1) >> 8);
            Ethernet.MACAddress[4] = (byte)(ReadROM(2) & 0xFF);
            Ethernet.MACAddress[5] = (byte)(ReadROM(2) >> 8);
            Console.Write("MAC Address: ");
            for (int i = 0; i < 6; i++) Console.Write($"{Ethernet.MACAddress[i].ToString("x2").PadLeft(2, '0')}{((i == 5) ? "" : ":")}");
            Console.WriteLine();

            Linkup();
            for (int i = 0; i < 0x80; i++)
                WriteRegister((ushort)(0x5200 + i * 4), 0);

            Console.WriteLine($"IRQ:{device.InterruptLine}");

            RXInit();
            TXInit();

            WriteRegister(0x00D0, 0x1F6DC);
            WriteRegister(0x00D0, 0xFF & ~4);
            ReadRegister(0xC0);

            Console.WriteLine("Intel 82540EM Configuration Done");
        }

        private static void TXInit()
        {
            TXDescs = (uint)GC.AllocateObject(8 * 16);

            for (int i = 0; i < 8; i++)
            {
                TXDesc* desc = (TXDesc*)(TXDescs + (i * 16));
                desc->addr = 0;
                desc->cmd = 0;
            }

            WriteRegister(0x3800, TXDescs);
            WriteRegister(0x3804, 0);
            WriteRegister(0x3808, 8 * 16);
            WriteRegister(0x3810, 0);
            WriteRegister(0x3818, 0);

            WriteRegister(0x0400, (1 << 1) | (1 << 3));
        }

        public static uint RXCurr = 0;
        public static uint TXCurr = 0;

        private static void RXInit()
        {
            RXDescs = (uint)GC.AllocateObject(32 * 16);

            for (uint i = 0; i < 32; i++)
            {
                RXDesc* desc = (RXDesc*)(RXDescs + (i * 16));
                desc->addr = (ulong)(void*)GC.AllocateObject(2048 + 16);
                desc->status = 0;
            }

            WriteRegister(0x2800, RXDescs);
            WriteRegister(0x2804, 0);

            WriteRegister(0x2808, 32 * 16);
            WriteRegister(0x2810, 0);
            WriteRegister(0x2818, 32 - 1);

            WriteRegister(0x0100,
                     (1 << 1) |
                     (1 << 2) |
                     (1 << 3) |
                     (1 << 4) |
                     (0 << 6) |
                     (0 << 8) |
                    (1 << 15) |
                    (1 << 26) |
                    (0 << 16)
                );
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct RXDesc
        {
            public ulong addr;
            public ushort length;
            public ushort checksum;
            public byte status;
            public byte errors;
            public ushort special;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct TXDesc
        {
            public ulong addr;
            public ushort length;
            public byte cso;
            public byte cmd;
            public byte status;
            public byte css;
            public ushort special;
        }

        public static void WriteRegister(ushort Reg, uint Val)
        {
            Out32(BAR0 + Reg, Val);
        }

        public static uint ReadRegister(ushort Reg)
        {
            return In32(BAR0 + Reg);
        }

        public static ushort ReadROM(uint Addr)
        {
            uint Temp;
            WriteRegister(0x14, 1 | (Addr << 8));
            while (((Temp = ReadRegister(0x14)) & 0x10) == 0) ;
            return ((ushort)((Temp >> 16) & 0xFFFF));
        }

        internal static void OnInterrupt()
        {
            uint Status = ReadRegister(0xC0);

            if ((Status & 0x04) != 0)
            {
                //Console.WriteLine("Linking Up");
                Linkup();
            }
            if ((Status & 0x10) != 0)
            {
                //Console.WriteLine("Good Threshold");
            }

            if ((Status & 0x80) != 0)
            {
                //Console.WriteLine("Packet Received");
                uint _RXCurr = RXCurr;
                RXDesc* desc = (RXDesc*)(RXDescs + (RXCurr * 16));
                while ((desc->status & 0x1) != 0)
                {
                    Ethernet.HandlePacket((byte*)desc->addr,desc->length);
                    //desc->addr;
                    desc->status = 0;
                    RXCurr = (RXCurr + 1) % 32;
                    WriteRegister(0x2818, _RXCurr);
                }
            }
        }

        private static void Linkup()
        {
            WriteRegister(0, ReadRegister(0) | 0x40);
        }

        public static void Send(byte* Buffer, ushort Length)
        {
            TXDesc* desc = (TXDesc*)(TXDescs + (TXCurr * 16));
            desc->addr = (ulong)Buffer;
            desc->length = Length;
            desc->cmd = (1 << 0) | (1 << 1) | (1 << 3);
            desc->status = 0;

            byte _TXCurr = (byte)TXCurr;
            TXCurr = (TXCurr + 1) % 8;
            WriteRegister(0x3818, TXCurr);
            while ((desc->status & 0xff) == 0) ;
        }
    }
}

Re: Help! My E1000 Driver Cannot Receive Anything

Posted: Tue Aug 17, 2021 4:57 pm
by nifanfa
It actually works fine yesterday. and i don't why it suddenly not work and i didn't modified anything of it

Image

Re: Help! My E1000 Driver Cannot Receive Anything

Posted: Tue Aug 17, 2021 5:00 pm
by nifanfa
The interrupt won't be triggered

Re: Help! My E1000 Driver Cannot Receive Anything

Posted: Wed Aug 18, 2021 12:01 am
by nifanfa
and there's another same situation. i wrote a rtl8139 driver. it cannot receive the buffer neither. but both e1000 and rtl8139 can send buffer successfully to windows host.

Re: Help! My E1000 Driver Cannot Receive Anything

Posted: Wed Aug 18, 2021 12:01 am
by nifanfa
And i did enabled bus mastering.

Re: Help! My E1000 Driver Cannot Receive Anything

Posted: Wed Aug 18, 2021 12:35 am
by nifanfa
Um. i can make it work if i use IRQ0 instead of the InterruptLine. But i don't wish to do that...

Re: Help! My E1000 Driver Cannot Receive Anything

Posted: Wed Aug 18, 2021 12:37 am
by nifanfa
The situation is I can send or receive(Use IRQ0 PIT Clock Interrupt) buffers. But i cannot use the interrupt from InterruptLine.

Re: Help! My E1000 Driver Cannot Receive Anything

Posted: Wed Aug 18, 2021 1:22 am
by nifanfa
Image

I still don't know where's the problem is. I think i can only use thread temporally

Re: Help! My E1000 Driver Cannot Receive Anything

Posted: Wed Aug 18, 2021 8:24 am
by Octocontrabass
Where is your code to unmask the IRQ in the interrupt controller?

Re: Help! My E1000 Driver Cannot Receive Anything

Posted: Wed Aug 18, 2021 1:43 pm
by nifanfa
Octocontrabass wrote:Where is your code to unmask the IRQ in the interrupt controller?
Thank you very much. that's why i can't receive interrupt !!!!!!

Re: Help! My E1000 Driver Cannot Receive Anything

Posted: Wed Aug 18, 2021 1:50 pm
by nifanfa
Octocontrabass wrote:Where is your code to unmask the IRQ in the interrupt controller?
Hey. and i got a question. why i don't clear the mask of Mouse Interrupt (IRQ12) but i can still receive it? but why if i don't clear the mask of netcard it just not work?

Re: [Solved] Help! My E1000 Driver Cannot Receive Anything

Posted: Wed Aug 18, 2021 1:57 pm
by Octocontrabass
Did the BIOS clear the IRQ12 mask before it loaded your OS?

Re: [Solved] Help! My E1000 Driver Cannot Receive Anything

Posted: Wed Aug 18, 2021 5:04 pm
by nifanfa
Octocontrabass wrote:Did the BIOS clear the IRQ12 mask before it loaded your OS?
i don't know

Re: [Solved] Help! My E1000 Driver Cannot Receive Anything

Posted: Wed Aug 18, 2021 5:50 pm
by Octocontrabass
You can read the interrupt mask register to check.