Page 1 of 4

accessing the network card

Posted: Fri May 07, 2010 11:09 pm
by aloktiagi
HI

How can we find the network card on the PCI bus and access its memory addresses and registers. Main idea is to initialize the NIC, access its address space.

Can someone provide any links for this information

BR
Alok

Re: accessing the network card

Posted: Sat May 08, 2010 2:30 am
by Combuster
You may want to look up your keywords in the wiki before posting them here: PCI

Re: accessing the network card

Posted: Sat May 08, 2010 7:43 am
by aloktiagi
Hi,

Yes had gone through that before posting!!. My code for now has a bootloader that jumps to c code which has set gdt and idt. Now i want to access pci deivces i.e NIC.

So needed some guidance on that!!

BR
Alok

Re: accessing the network card

Posted: Sat May 08, 2010 8:06 am
by Creature
The article Combuster linked to describes how to access PCI devices; it is now up to you to find the device you need in PCI configuration space and to program it (which is usually somewhat dependant on the device itself). If it's a specific network card you're looking for, you might have some luck browsing through the category.

Re: accessing the network card

Posted: Sat May 08, 2010 10:51 pm
by ehenkes
You should implement functions to scan the pci bus and to read/write to pci registers. Then you will have something like:

Code: Select all

 void pciScan()
 {
    for (uint32_t i=0;i<PCIARRAYSIZE;++i)
    {
        pciDev_Array[i].number = i;
    }
    int number=0;    
    for (uint8_t bus = 0; bus < 4; ++bus) // we scan only four busses of 256 possibles
    {
        for (uint8_t device = 0; device < 32; ++device)
        {
            for (uint8_t func = 0; func < 8; ++func)
            {
                uint16_t vendorID = pci_config_read(bus, device, func, PCI_VENDOR_ID);
                if (vendorID && (vendorID != 0xFFFF))
                {                    
                    //...

                    /// RTL 8139 network card
                    if ((pciDev_Array[number].deviceID == 0x8139))
                    {
                        install_RTL8139(number);
                    }
                    ++number;
The wiki is very helpful regarding PCI bus.

The install routine for the speciifc network card could be like this:

Code: Select all

void install_RTL8139(uint32_t number)
{
    for (uint8_t j=0;j<6;++j) // check network card BARs
    {
        pciDev_Array[number].bar[j].memoryType = pciDev_Array[number].bar[j].baseAddress & 0x01;

        if (pciDev_Array[number].bar[j].baseAddress) // check valid BAR
        {
            if (pciDev_Array[number].bar[j].memoryType == 0)
            {
                BaseAddressRTL8139_MMIO = pciDev_Array[number].bar[j].baseAddress &= 0xFFFFFFF0;

            }
            if (pciDev_Array[number].bar[j].memoryType == 1)
            {
                BaseAddressRTL8139_IO = pciDev_Array[number].bar[j].baseAddress &= 0xFFFC;
            }
        }
    }
Good luck!

Re: accessing the network card

Posted: Sun May 09, 2010 12:58 am
by aloktiagi
Hi

Thanks for the reply

To do this i'll need to implement pci_config_read function also.

One more thing i was following the wiki page http://wiki.osdev.org/RTL8169. Here it tells how to get the MAC address of the card. Is this tutorial correct?

Now to get the I/O base address from PCI configuration space i used lspci command and ifconfig and i got the following

lspci
05:00.0 Ethernet controller: Broadcom Corporation NetXtreme II BCM5708 Gigabit Ethernet (rev 12)
Subsystem: Hewlett-Packard Company NC373i Integrated Multifunction Gigabit Server Adapter
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr+ Stepping- SERR+ FastB2B-
Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
Latency: 64 (16000ns min), Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 130
Region 0: Memory at fa000000 (64-bit, non-prefetchable) [size=32M]
[virtual] Expansion ROM at d1200000 [disabled] [size=2K]
Capabilities: [40] PCI-X non-bridge device
Command: DPERE- ERO- RBC=512 OST=8
Status: Dev=05:00.0 64bit+ 133MHz+ SCD- USC- DC=simple DMMRBC=512 DMOST=8 DMCRS=32 RSCEM- 266MHz- 533MHz-
Capabilities: [48] Power Management version 2
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold+)
Status: D0 PME-Enable- DSel=0 DScale=1 PME-
Capabilities: [50] Vital Product Data
Capabilities: [58] Message Signalled Interrupts: 64bit+ Queue=0/0 Enable+
Address: 00000000fee01000 Data: 4082
and ifconfig i get
eth1 Link encap:Ethernet HWaddr 00:1F:29:CC:BC:12
inet addr:10.58.112.248 Bcast:10.58.112.255 Mask:255.255.255.0
inet6 addr: fe80::21f:29ff:fecc:bc12/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:103895656 errors:1 dropped:0 overruns:0 frame:1
TX packets:73155493 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:702144647 (669.6 MiB) TX bytes:561130821 (535.1 MiB)
Interrupt:82 Memory:fa000000-fa012100
So is the I/O base address fa000000???

Thanks
Alok

Re: accessing the network card

Posted: Sun May 09, 2010 12:44 pm
by Selenic
aloktiagi wrote:So is the I/O base address fa000000???
Kind of. The lspci output (in particular) states that it owns a chunk of *memory* at that location. Not IO address space, which in many cases is only used for legacy compatibility; most stuff uses memory mapping like that.
That chunk of memory will, however, have the various controls registers, buffers and whatever else laid out within it (though you'll likely need to find documentation for that specific card or series of cards)

Re: accessing the network card

Posted: Mon May 10, 2010 1:05 am
by aloktiagi
Hi,

So how do i find out the I/O base address of a device when i jump from my bootloader to the c code without the OS being there i.e no lspci command!!!

Regards
Alok

Re: accessing the network card

Posted: Mon May 10, 2010 2:26 am
by Combuster
So how do i find out the I/O base address of a device when i jump from my bootloader to the c code without the OS being there i.e no lspci command!!!
Please, if you ask an answered question again in the same thread it only makes you look like you are lazy and want to be spoon-fed code. Please read the links posted earlier in this thread before trying again. If you do actually get stuck, at least make some effort showing us what you did so far. (see here why)
I wrote:You may want to look up your keywords in the wiki before posting them here: PCI

Re: accessing the network card

Posted: Mon May 10, 2010 10:08 am
by aloktiagi
Hi,

In code at the PCI Wiki link

Code: Select all

 unsigned short pciConfigReadWord (unsigned short bus, unsigned short slot,
                                   unsigned short func, unsigned short offset)
 {
    unsigned long address;
    unsigned long lbus = (unsigned long)bus;
    unsigned long lslot = (unsigned long)slot;
    unsigned long lfunc = (unsigned long)func;
    unsigned short tmp = 0;
 
    /* create configuration address as per Figure 1 */
    address = (unsigned long)((lbus << 16) | (lslot << 11) |
              (lfunc << 8) | (offset & 0xfc) | ((UINT32)0x80000000));
 
    /* write out the address */
    sysOutLong (0xCF8, address);
    /* read in the data */
    tmp = (unsigned short)((sysInLong (0xCFC) >> ((offset & 2) * 8)) & 0xffff);
    return (tmp);
 }
What is meant by the offset??

Alok

Re: accessing the network card

Posted: Mon May 10, 2010 10:22 am
by Combuster
What do (should) you do when you don't know what a word means: you derive it from the context. The same holds for code:
Enable Bit - Reserved - Bus Number - Device Number - Function Number - Register Number - 00
(...)
/* create configuration address as per Figure 1 */
address = (unsigned long)((lbus << 16) | (lslot << 11) | (lfunc << 8 ) | (offset & 0xfc) | ((UINT32)0x80000000));
Draw the lines and entertain me :wink:

Re: accessing the network card

Posted: Tue May 11, 2010 9:49 am
by aloktiagi
Hi,

Currently my code goes like this (my broadcom BCM5708 card's parameters are bus 3 and device 0)

Code: Select all

for(i=0;i<10;i++)
    {
        idx = 0x80000000 + ((0x03&0xFF)<<16) + ((0x00&0x1F)<<11) + ((0x00&0x7)<<8) + (header&0xFC);
        outl(idx,0xCF8);
        tmp = inl(0xCFC);
        if ( tmp == ~0 ) printf("alok");
        printf( " ADDR=%X REG VAL=%X \n",header, tmp);
        header=header+0x04;
    }
The output i get is
ADDR=0 REG VAL=164C14E4 Device and vendor ID
ADDR=4 REG VAL=2B00156
ADDR=8 REG VAL=2000011
ADDR=C REG VAL=4010
ADDR=10 REG VAL=F8000004
ADDR=14 REG VAL=0
ADDR=18 REG VAL=0
ADDR=1C REG VAL=0
ADDR=20 REG VAL=0
ADDR=24 REG VAL=0
So 0xF800004 is my BAR0 value.

Now the http://wiki.osdev.org/PCI link tells that to retrieve the actual base address of a BAR
we need to mask the lower bits, i.e BAR[x] & 0xFFFFFFF0 for 32 bit. So after this i get the BAR address as 0xF800000.

So from 0xF800000 can i now access the NIC's registers, for e.g get the MAC address values?

Regards
Alok

Re: accessing the network card

Posted: Tue May 11, 2010 10:50 pm
by aloktiagi
Also in addition to the above query one more problem!

From the wiki page http://wiki.osdev.org/Inline_Assembly/Examples i found out the implementation of both inb and outb but i'm having a problem implementing inl

For inb its like

Code: Select all

static __inline__ unsigned char inb(unsigned short port)
{
   unsigned char ret;
   asm volatile ("inb %1,%0":"=a"(ret):"Nd"(port));
   return ret;
}
But how do i do it for inl i've tried replacing %0 with %%eax but that doesn't work !!!

Re: accessing the network card

Posted: Wed May 12, 2010 11:20 am
by mkruk
You have to replace the inb instruction with inl and change the type of ret since an unsigned char is too small for inl (which means in long, btw)
Also, from reading your postings I strongly suggest you to read some C and assembly tutorials ;)

Furthermore, if you get to that point, you need to modify the pci device's control register to be able to access its io address space. If I remember correctly you have to set bit 0 for the io and bit 1 for the memory address space.
If you don't do that, you will just get all zeroes when accessing the device's address space. When I implemented my first PCI device driver I failed to realise this for hours and I only found out after reading the pci specifications :)

Re: accessing the network card

Posted: Wed May 12, 2010 11:55 am
by aloktiagi
Yes i got that after some time char was small for inl!!

The PCI page says that to calculate I/O base address we shud do

(BAR[x] & 0xFFFFFFFC).

Is it same as what u have said
If I remember correctly you have to set bit 0 for the io and bit 1 for the memory address space.