星期二, 4月 11, 2006

Somthing about PCI ..

因為重新build的kernel run起來又有eth0 : PCI Bus error 6200,所以又要digg 一下code..
先看看pci 的一些資料 ( ref : Linux Device Driver):


有關PCI bus的觀念和Linux PCI device driver的說明,在 IBM developerWorld的Linux下pci設備驅動程式開發,有很好的說明。

PCI configuration registers 共有256 bytes,定義在<linux/pci.h>下:
pci_cr

#define PCI_VENDOR_ID 0x00 /* 16 bits */
#define PCI_DEVICE_ID 0x02 /* 16 bits */
#define PCI_COMMAND 0x04 /* 16 bits */
#define PCI_STATUS 0x06 /* 16 bits */
#define PCI_REVISION_ID 0x08 /* Revision ID */
#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
#define PCI_CLASS_DEVICE 0x0a /* Device class */
#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
#define PCI_HEADER_TYPE 0x0e /* 8 bits */
#define PCI_BIST 0x0f /* 8 bits */
#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */
#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */
#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
#define PCI_CARDBUS_CIS 0x28
#define PCI_SUBSYSTEM_VENDOR_ID 0x2c
#define PCI_SUBSYSTEM_ID 0x2e
#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */
/* 0x35-0x3b are reserved */
#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
#define PCI_MIN_GNT 0x3e /* 8 bits */
#define PCI_MAX_LAT 0x3f /* 8 bits */
存取pci configuration register的方法是用<linux/pci.h>中提供(protype)的function :

int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val);
int pci_read_config_word(struct pci_dev *dev, int where, u16 *val);
int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val);
int pci_write_config_byte(struct pci_dev *dev, int where, u8 val);
int pci_write_config_word(struct pci_dev *dev, int where, u16 val);
int pci_write_config_dword(struct pci_dev *dev, int where, u32 val);
由於pci 使用little endian,這幾個多byte r/w function 會依照host machine的nature自動轉換。
pci configuration register的內容可以在 /proc/bus/pci/xx/xx.x 下列出。
其中XX/xx.X就是pci deive的device, function id。
使用lspci (或是 cat /proc/pci ) 可以看到。
舉例來說,我的ethernet card 在lspci 中列出是:
0000:00:11.0 Ethernet controller: Advanced Micro Devices [AMD] 79c970 [PCnet32 LANCE] (rev 10)
所以他的configuration data在 /proc/bus/pci/00/11.0。
因為data是binary,所以要用od 轉成hex ascii 來看:
$ cat /proc/bus/pci/00/11.0 | od
0000000 010042 020000 000007 001200 000020 001000 040000 000000
0000020 010201 000000 000000 000000 000000 000000 000000 000000
0000040 000000 000000 000000 000000 000000 000000 010042 020000
0000060 000000 000000 000000 000000 000000 000000 000412 177406
0000100
對應上面<linux/pci.h>的address定義,可以知道內容。


接下來trace一下boot message中PCI 的部份:
PCI: bus0: Fast back to back transfers disabled
PCI: Configured XX as a PCI slave with 128MB PCI memory
PCI: Each Region size is 16384KB
PCI: Reserved memory from 0x10080000 to 0x12080000 for DMA and mapped to 0x12000000
找..
#grep -i 'as a pci slave' * -r
在 arch/armnommu/mach-xx/pci_xx.c : void xx_pci_init(void *sysdata)
function 放在
struct hw_pci xx_pci = {
init : xx_pci_init,
setup_resources : NULL,
swizzle : no_swizzle,
map_irq : xx_pci_map_irq,
mem_offset : MEMORY_BASE_PCI_MEMORY,
io_offset : MEMORY_BASE_PCI_CONFIG,
};
reference 這個 xx_pci的大概是 arch/armnommu/kernel/bios32.c : void __init pcbios_init(void)
這個function 依照kernel config 的內容,將xx_pci 指定到 struct pci_sys_data->hw。

沒有留言:

網誌存檔