Download presentation
Presentation is loading. Please wait.
1
PCI가 어렵울 거라는 생각을 지금부터 버리도록 합시다.
FA리눅스공개세미나 오 재 경 PCI가 어렵울 거라는 생각을 지금부터 버리도록 합시다.
2
버스(BUS)란? 32Bit MCU의 메모리 공간의 크기 4GByte 버스의 여러종류
로컬버스, PCI, I2C, AC97, USB, ATA, IEEE1394, etc … 두가지 버스의 구분 (접근방법에 따른, 극히 개인적인) Indirect BUS (USB, SCSI, IEEE1394, I2C) Direct BUS (Local-BUS, PCI) 하드웨어적인 전기적인 연결과 이를 제어하는 소프트웨어의 표준 인터페이스를 제공하여 디바이스의 확장을 용이하게 해주는 것
3
BUS 의 예 HDD 0xFFFF FFFF 32bit MCU HDD PCI to HDD PCI-BUS 0x8000 0000
PCI to USB USB Device USB Device USB Device AC97 Codec AC97-BUS 각 버스의 특징을 색을 보며 설명한다. 0x LOCAL-BUS Flash 0x
4
PCI 버스의 특징 직접적인 메모리 방식의 제어를 통해 엑세스가 가능하다.
직접 제어방식이라 프로토콜 계층이 없어 소프트웨어적으로 간결하다. 이와는 반대로 USB등과 같이 프로토콜 계층이 존재하는 방식의 장단점을 비교한다.
5
PCI 버스의 주소할당 PC 보드에서 PCI 슬롯에 카드들을 임의 대로 꽂아도 시스템에서는 잘 인식한다. 어떻게 가능한 것인가? 컨피큐레이션 사이클이라는 특별한 전송이 존재하며 이것은 특정 슬롯을 지정하여 전송할 수 있다. MCU PCI 버스 주소를 할당하는 방법을 설명하며 주소가 할당된 이 후에는 쉽게 접근이 가능하다는 것을 인지시킨다.
6
PCI Configuration 영역 31 16 15 Device ID Vender ID Status Command
Device ID Vender ID Status Command Class ID Rev ID BIST Header Type Latency CacheLineSize Base Address #0 (I/O 전용) Base Address #1 (MEM 전용) Base Address #2 (MEM 전용) Base Address #3 (MEM 전용) Reserved …. 0x00 0x04 0x08 0x0C 0x10 0x14 0x18 0x1C 0x20 Configuration 의 기본적인 사항을 설명하며 이 영역을 읽음으로써 하드웨어 결선 상태를 확인할 수 있다.
7
PCI 디바이스의 Base 주소 MEM Base Address P B IO Base Address 1
IO Base Address 1 P : 메모리 프리패치 가능 메모리일 경우 D0 = 0 IO일 경우 D1:D0 = 01 bit 16 12 8 4 커널이 주소를 어떤 방식으로 할당하며 PCI 디바이스가 점유하는 공간은 어떻게 알아내는지 설명한다. 1 Base Register 에 0xFFFF FFFF 를 쓴 후 다시 읽어 각비트의 값을 보고 필요로 하는 주소의 크기를 판단한다. Read Only
8
주소할당의 예 할당된 주소를 확인하는 방법과 컨피규레이션 영역의 값들을 살펴본다. lspci 유틸리티의 사용방법을 소개한다.
9
IO 영역과 MEM 영역의 차이 io 영역은 한번에 하나씩의 데이터를 엑세스하는 곳이며 prefetch가 일어나지 않는다.
mem 영역은 prefetch가 가능하며 burst 전송이 가능하다. mem 영역은 할당되는 크기의 제한이 거의 없으며 DMA 전송도 지원하여 고속의 데이타전송이 가능하다.
10
PCI 버스의 핀(32bit PCI) AD[0..31] : 어드레스/데이터 공통
C/BE[0..3] : Commad/BUS-Enable FRAME# : 사이클 시작신호 DEVSEL# : 사이클 응답신호(주소에 대한) IRDY# : 버스상의 데이터가 유효함을 알림 TRDY# : 데이터를 받을 수 있음을 알림 REQ#, GNT# : 버스점유 요구, 허락 PAR : 짝수패리티 SERR# , PERR# : 어드레스에러, 데이타에러 CLK, RST#, STOP#, INT[A...D]# IDSEL : 환경영역을 엑세스할 때 사용
11
PCI 버스의 기본적인 동작 버스의 타이밍을 설명하며 하드웨어 디버깅시 필요한 테스트 포인터를 알려준다.
12
PCI 하드웨어 설계 시 주의점 회로 설계시 아트웍 시 문제점 버스의 드라이빙 능력 버스 아비터의 개수 클럭버퍼의 사용
OC 핀의 풀업저항 아트웍 시 클럭신호는 한 디바이스 까지의 버스들의 평균거리로 설정 버스내 각 신호선간의 길이는 가급적 동일하게 설정(20% 오차까지(?)) 문제점 보드가 너무 작을 경우 동일한 버스 길이를 설정하기 힘들다. PCI 디바이스가 너무 많을 경우 외부 아비터나 버스 브릿지를 고려해본다. (버스 브릿지는 비추천.. 하지만 달아야 한다면 ㅜ.ㅜ) 클럭신호가 왜 평균거리가 필요한지 설명한다. 통신하는 칩들간의 평균거리임을 주지시킨다.
13
PCI 디바이스 회로도 Idsel 핀과 인터럽트선을 어떤 규칙에 의해 배치하는지 설명한다.
풀업저항은 3.3V 일때 8.2K, 5V 일때 4.7K 임을 말하고 10K 저항을 사용한 이유를 설명한다.
14
PCI 하드웨어 디버깅 디바이스의 전원이 정상인지 확인한다. 디바이스의 클럭이 공급되는지 확인한다.
디바이스의 RESET 신호가 정상인지 확인한다. 회로도가 이상이 없는지 넷트의 이름과 칩의 핀배치가 일치하는지 확인한다. 주변 저항등 칩들이 모두 정상으로 붙어있는지 확인한다. 디바이스의 configuraion 레지스터를 읽는다. (lspci 유틸리티) Frame# 신호화 함게 디바이스의 IDSEL 핀이 High 로 선택되는지 확인한다. Devsel# 신호가 동기 되는지 확인한다. PERR#, SERR# 가 발생하는지 확인한다. 버스의 신호가 전혀나오지 않는다면 MCU 레지스터 설정과 커널의 PCI 관련 동작이 활성화 되어있느지 또는 나의 보드에 맞게 포팅되어 있는지 확인한다. 하드웨어 디버깅의 왕도는 없다. 1~5 번까지의 내용은 일반 하드웨어 디버깅도 동일하다. 6번까지의 내용은 소프트웨어 엔지니어도 충분히 가능한 내용임을 설명한다.
15
PCI 버스를 지원하는 MCU 구조 MCU PCI/MEM PCI/IO PCI Device
0x PCI MEM-Base + PCI MEM-Base 0x 0x PCI IO-Base 0x PCI IO-Base 일반적인 MCU 들이 PCI 버스로 주소를 어떻게 사상(표출)하는지 설명한다.
16
리눅스커널이 부팅시 하는 일 Configuration 싸이클을 이용하여 주소 할당
BUS, SLOT, FUNC 번호를 이용한 IRQ 등록 커널의 하는일이 많지 않음을 설명한다.
17
디바이스 드라이버의 최초 실행 static int __init spci_init( void ) {
return pci_module_init(&spci_driver); } static void __exit spci_exit( void ) pci_unregister_driver(&spci_driver); module_init(spci_init); module_exit(spci_exit); insmod 유틸리티를 이용하여 드라이버를 커널에 적재할때 호출되는 함수 init_module() rmmod 유틸리티를 실행하면 호출되는 함수 cleanup_module() __init, __exit 를 설명한다.
18
PCI 디바이스 드라이버 등록 PCI 드라이버 등록 구조체 인자 struct pci_driver spci_driver = {
.name = DEV_NAME, .id_table = spci_tbl, .probe = spci_probe, .remove = spci_remove, }; PCI 드라이버 초기화 함수 pci_module_init(&spci_driver); // #define pci_module_init pci_register_driver PCI 드라이버 해제 함수 pci_unregister_driver(&spci_driver); pci_register_driver probe pci_unregister_driver remove
19
struct pci_device_id struct pci_device_id { // linux/mod_devicetable.h
__u32 vendor, device; __u32 subvendor, subdevice; __u32 class, class_mask; kernel_ulong_t driver_data; }; static struct pci_device_id spci_tbl[] = { {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SPCI_PRIVATE_NUMBER }, {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SPCI_PRIVATE_NUMBER }, {0,} }; Vendor, Product ID 설명
20
struct pci_driver member 함수
int spci_probe ( struct pci_dev *pdev, const struct pci_device_id *ent ) { // 디바이스가 정상인지 확인 // 디바이스가 점유하는 베이스주소 얻기 // 사용할 메모리 할당 // 인터럽트 함수 등록 // 클래스에 맞는 드라이버 등록 ex) register_chrdev() // 디바이스 초기화 실행 } void spci_remove ( struct pci_dev *pdev ) // 점유한 리소스 반환 각 함수에서 해야하는 일 설명
21
주소 (Resource) 얻기 struct pci_dev *pdev; // 함수의 인자
int win_nr = 0; // PCI configuration base-address index // 0번은 IO 베이스 주소 // 1~5 번은 메모리 베이스 주소 unsigned long base = pci_resource_start (pdev, win_nr); unsigned long end = pci_resource_end (pdev, win_nr); unsigned long flags = pci_resource_flags (pdev, win_nr); unsigned long len = pci_resource_len (pdev, win_nr); unsigned int irq = pdev->irq; PCI 디바이스에 할당된 주소를 얻어온다.
22
struct pci_dev struct pci_dev { struct pci_bus *bus;
unsigned int devfn; unsigned short vendor; unsigned short device; unsigned int class; u pin; struct pci_driver *driver; struct device dev; int cfg_size; unsigned int irq; struct resource resource[DEVICE_COUNT_RESOURCE];
23
주소 맵핑(mapping) Configuration Base-Address 에 등록(할당)된 주소는 물리주소이다.
리눅스 커널에서는 물리주소를 바로 사용할 수 없다. 이를 사용하기 위해서는 가상주소로 변환하여 사용하여야 한다. vir_addr = ioremap( phy_address, len ); iounmap( vir_addr ); ioremap_nocache(), ioremap_cache(); PCI 영역중 mem 영역은 가상영역으로 변환하여야 한다. PCI 영역중 IO 영역은 변환하지 않고 사용한다. 인텔의 CPU i386 Core 에 대해 설명한 후 mem, io 영역이 다른이유를 설명한다. 드라이버 포팅시 이분에 주의 해야 함을 말한다.
24
버스접근 함수 PCI-IO 영역 접근함수 inb(), outb(), inw(), outw(), inl(), outl()
PCI-MEM 영역 접근함수 readb(), writeb(), readw(), writew(), readl(), writel() inclue/asm/io.h 참고(중요소스)
25
인터럽트 처리 request_irq( irq, spci_callback,
SA_INTERRUPT | SA_SHIRQ, “sample”, NULL ); irqreturn_t spci_interrupt( int irq, void *dev_id, struct pt_regs *regs ) { if ( 내가 다루는 디바이스가 인터럽트를 발생시켰는가 ) // 인터럽트 라인이 해제될 수 있도록 처리한다. return IRQ_HANDLED; } else return IRQ_NONE; 인터럽트가 공유된다는 것을 숙지 시킨다.
26
PCI 버스의 DMA 전송 PCI 버스가 빠른것은 DMA 전송을 지원하기 때문이다. 이 기능을 사용하지 않고는 PCI 디바이스를 사용할 이유가 반감된다. DMA 전송을 위해서는 물리적으로 연속된 메모리를 획득한다. 연속된 물리메모리를 획득하였다면 PCI 디바이스의 특정 영역에 호스트측의 물리 메모리 주소와 PCI 디바이스의 물리주소 그리고 전송할 데이터의 크기를 넣은 후 DMA 전송 명령을 내린다. DMA 전송명령을 위해서는 PCI 디바이스 레지스터를 접근하여 특정값을 넣어야 한다. 커널에 따로 이를 위한 함수는 준비되어 있지 않다. PCI 버스에서 DMA 전송의 버스 마스터는 PCI 디바이스에 있다.
27
DMA 메모리 획득(K2.6.10 이상) 1-page 이하의 크기 (4KByte) 1-page 이상의 크기
kmalloc( b-size, GFP_KERNEL ), kfree( virt ) 1-page 이상의 크기 kmalloc( b-size, GFP_DMA ); void *dma_alloc_coherent( struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp ); dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle ); 예제 dma_addr_t dma; // DMA 용 물리주소 void *virt = dma_alloc_coherent( pdev->dev, 1M, &dma, GFP_KERNEL );
28
PCI 디바이스 드라이버 소스 소스를 봅시다. ^^
29
예제 드라이버 실행 결과
30
끝 이페이지를인쇄한분들은인쇄하기전에내용을살피지않고오셨거나공짜로사용할수있는회사나학교의용지를사용하셨거나한페이지에여러페이지인쇄를하신분들입니다아니면종이가많은부자이거나어찌됬든이번강의를위해이페이지까지아낌없어투자하신분들은꼭성공하실겁니다부족한강의를끝까지들어주셔서감사합니다나가는문이어느쪽이든남은강의열심히들으신후경품도타가시는행운을누리시기바랍니다
Similar presentations