pci 구동 프레임 워 크

13939 단어 링크 ux 구동
1. 데이터 구 조 를 살 펴 본다.
struct pci_bus {
	//             ,    ,            
	struct list_head node;		/* node in list of buses */	
	//pci      
	struct pci_bus	*parent;	/* parent bus this bridge is on */
	//  pci           
	struct list_head children;	/* list of child buses */
	//  pci   pci       
	struct list_head devices;	/* list of devices on this bus */
	//    pci          
	struct pci_dev	*self;		/* bridge device as seen by parent */
	//  pci          
	struct list_head slots;		/* list of slots on this bus */
	struct resource *resource[PCI_BRIDGE_RESOURCE_NUM];
	struct list_head resources;	/* address space routed to this bus */
	//  pci              
	struct pci_ops	*ops;		/* configuration access functions */
	void		*sysdata;	/* hook for sys-specific extension */
	struct proc_dir_entry *procdir;	/* directory entry in /proc/bus/pci */

	unsigned char	number;		/* bus number */	//    
	unsigned char	primary;	/* number of primary bridge */	//    pci   pci_dev    
	unsigned char	secondary;	/* number of secondary bridge */	//    pci   pci_dev    
	unsigned char	subordinate;	/* max number of subordinate buses */	//  pci   subordinate       
	unsigned char	max_bus_speed;	/* enum pci_bus_speed */
	unsigned char	cur_bus_speed;	/* enum pci_bus_speed */

	char		name[48];

	unsigned short  bridge_ctl;	/* manage NO_ISA/FBB/et al behaviors */
	pci_bus_flags_t bus_flags;	/* Inherited by child busses */
	struct device		*bridge;	//     pci   pci_dev   device  
	struct device		dev;	//        
	struct bin_attribute	*legacy_io; /* legacy I/O for this bus */
	struct bin_attribute	*legacy_mem; /* legacy mem */
	unsigned int		is_added:1;
};
struct pci_dev {
	//       pci        
	struct list_head bus_list;	/* node in per-bus list */
	//      pci  
	struct pci_bus	*bus;		/* bus this device is on */
	//    pci_dev          ,        
	struct pci_bus	*subordinate;	/* bus this device bridges to */

	void		*sysdata;	/* hook for sys-specific extension */
	struct proc_dir_entry *procent;	/* device entry in /proc/bus/pci */
	//             
	struct pci_slot	*slot;		/* Physical slot this device is in */

	unsigned int	devfn;		/* encoded device & function index */		//pci      
	unsigned short	vendor;		//  ID
	unsigned short	device;		//  ID
	unsigned short	subsystem_vendor;	//     ID
	unsigned short	subsystem_device;	//     ID
	unsigned int	class;		/* 3 bytes: (base,sub,prog-if) */
	u8		revision;	/* PCI revision, low byte of class word */
	u8		hdr_type;	/* PCI header type (`multi' flag masked out) */
	u8		pcie_cap;	/* PCI-E capability offset */
	u8		pcie_type:4;	/* PCI-E device/port type */
	u8		pcie_mpss:3;	/* PCI-E Max Payload Size Supported */
	//ROM       pci        
	u8		rom_base_reg;	/* which config register controls the ROM */
	u8		pin;  		/* which interrupt pin this device uses */
	//    pci_dev    pci_driver
	struct pci_driver *driver;	/* which driver has allocated this device */
	u64		dma_mask;	/* Mask of the bits of bus address this
					   device implements.  Normally this is
					   0xffffffff.  You only need to change
					   this if your device has broken DMA
					   or supports 64-bit transfers.  */

	struct device_dma_parameters dma_parms;

	pci_power_t     current_state;  /* Current operating state. In ACPI-speak,
					   this is D0-D3, D0 being fully functional,
					   and D3 being off. */
	int		pm_cap;		/* PM capability offset in the
					   configuration space */
	unsigned int	pme_support:5;	/* Bitmask of states from which PME#
					   can be generated */
	unsigned int	pme_interrupt:1;
	unsigned int	d1_support:1;	/* Low power state D1 is supported */
	unsigned int	d2_support:1;	/* Low power state D2 is supported */
	unsigned int	no_d1d2:1;	/* Only allow D0 and D3 */
	unsigned int	mmio_always_on:1;	/* disallow turning off io/mem
						   decoding during bar sizing */
	unsigned int	wakeup_prepared:1;
	unsigned int	d3_delay;	/* D3->D0 transition time in ms */

#ifdef CONFIG_PCIEASPM
	struct pcie_link_state	*link_state;	/* ASPM link state. */
#endif

	pci_channel_state_t error_state;	/* current connectivity state */
	//         
	struct	device	dev;		/* Generic device interface */

	int		cfg_size;	/* Size of configuration space */

	/*
	 * Instead of touching interrupt line and base address registers
	 * directly, use the values stored here. They might be different!
	 */
	unsigned int	irq;
	struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
	resource_size_t	fw_addr[DEVICE_COUNT_RESOURCE]; /* FW-assigned addr */

	/* These fields are used by common fixups */
	unsigned int	transparent:1;	/* Transparent PCI bridge */
	unsigned int	multifunction:1;/* Part of multi-function device */
	/* keep track of device state */
	unsigned int	is_added:1;
	unsigned int	is_busmaster:1; /* device is busmaster */
	unsigned int	no_msi:1;	/* device may not use msi */
	unsigned int	block_ucfg_access:1;	/* userspace config space access is blocked */
	unsigned int	broken_parity_status:1;	/* Device generates false positive parity */
	unsigned int	irq_reroute_variant:2;	/* device needs IRQ rerouting variant */
	unsigned int 	msi_enabled:1;
	unsigned int	msix_enabled:1;
	unsigned int	ari_enabled:1;	/* ARI forwarding */
	unsigned int	is_managed:1;
	unsigned int	is_pcie:1;	/* Obsolete. Will be removed.
					   Use pci_is_pcie() instead */
	unsigned int    needs_freset:1; /* Dev requires fundamental reset */
	unsigned int	state_saved:1;
	unsigned int	is_physfn:1;
	unsigned int	is_virtfn:1;
	unsigned int	reset_fn:1;
	unsigned int    is_hotplug_bridge:1;
	unsigned int    __aer_firmware_first_valid:1;
	unsigned int	__aer_firmware_first:1;
	pci_dev_flags_t dev_flags;
	atomic_t	enable_cnt;	/* pci_enable_device has been called */

	u32		saved_config_space[16]; /* config space saved at suspend time */
	struct hlist_head saved_cap_space;
	struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */
	int rom_attr_enabled;		/* has display of the rom attribute been enabled? */
	struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
	struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */
#ifdef CONFIG_PCI_MSI
	struct list_head msi_list;
#endif
	struct pci_vpd *vpd;
#ifdef CONFIG_PCI_IOV
	union {
		struct pci_sriov *sriov;	/* SR-IOV capability related */
		struct pci_dev *physfn;	/* the PF this VF is associated with */
	};
	struct pci_ats	*ats;	/* Address Translation Service */
#endif
};
pci_dev 는 논리 장 치 를 묘사 하 는데 usb 시스템 의 (usb devie 와 usb interface) 개념 과 약간 유사 하 다.설정 이 든 스 캔 이 든 모두 Pci 논리 장치 에 기반 합 니 다.그러나 핫 플러그 는 반드시 Pci 물리 장 치 를 대상 으로 Pci 물리 장 치 를 묘사 하 는 구조 체 는 Pci 입 니 다.slot。
struct pci_slot {
	struct pci_bus *bus;		/* The bus this slot is on */		//  slot   pci  
	struct list_head list;		/* node in list of slots on this bus */	//  pci   slot   
	struct hotplug_slot *hotplug;	/* Hotplug info (migrate over time) */
	unsigned char number;		/* PCI_SLOT(pci_dev->devfn) */
	struct kobject kobj;
};
2. x86 구조의 Pci 시스템 초기 화
(1)pci_bus 클래스 초기 화 (initcall 2)
static int __init pcibus_class_init(void)
{
	return class_register(&pcibus_class);
}
postcore_initcall(pcibus_class_init);
(2) Pci 버스 초기 화 (initcall 2)
static int __init pci_driver_init(void)
{
	return bus_register(&pci_bus_type);
}

postcore_initcall(pci_driver_init);
(3) pci 설정 접근 방법의 초기 화 (initcall 3)
pci_arch_init 의 주요 목적 은 rawpci_ops 또는 rawpci_ext_ops 할당 은 Pci 설정 공간 에 접근 하 는 작업 표를 가리 키 기 때문에 Pci 스 캔 전에 완료 해 야 합 니 다.
이 함수 의 논 리 는: pci 를 먼저 호출 하 는 것 입 니 다.direct_probe 함수 검사 메커니즘 \ # 1 (또는 메커니즘 \ # 2), pci 호출pcibios_init 함수 검사 pci bios 방식, 마지막 으로 pci 호출direct_init 함 수 는 메커니즘 을 사용 해 야 하 는 지 돌아 보 았 습 니 다. \ # 1 (또는 메커니즘 \ # 2), 이러한 호출 순 서 는 우선 사용 메커니즘 \ # 1 (또는 메커니즘 \ # 2) 을 확보 합 니 다.
static __init int pci_arch_init(void)
{
#ifdef CONFIG_PCI_DIRECT
	int type = 0;

	type = pci_direct_probe();
#endif

	if (!(pci_probe & PCI_PROBE_NOEARLY))
		pci_mmcfg_early_init();

	if (x86_init.pci.arch_init && !x86_init.pci.arch_init())
		return 0;

#ifdef CONFIG_PCI_BIOS
	pci_pcbios_init();
#endif
	/*
	 * don't check for raw_pci_ops here because we want pcbios as last
	 * fallback, yet it's needed to run first to set pcibios_last_bus
	 * in case legacy PCI probing is used. otherwise detecting peer busses
	 * fails.
	 */
#ifdef CONFIG_PCI_DIRECT
	pci_direct_init(type);
#endif
	if (!raw_pci_ops && !raw_pci_ext_ops)
		printk(KERN_ERR
		"PCI: Fatal: No config space access function found
"); dmi_check_pciprobe(); dmi_check_skip_isa_align(); return 0; } arch_initcall(pci_arch_init);
(4) Pci 버스 스 캔 (initcall 4)
pci 버스 스캐닝 프로 세 스 pcisubsys_init 함수 시작, 주로 세 가지 문 제 를 해결 합 니 다:
Pci 버스 스 캔 을 통 해 시스템 의 각급 버스 에 있 는 Pci 장 치 를 발견 하고 모든 Pci 장 치 를 설정 합 니 다.
메모리 에 각 Pci 장치 에 대응 하 는 데이터 구 조 를 구축 하여 후속 적 으로 조작 할 수 있 도록 합 니 다.
sysfs 파일 시스템 에 Pci 디 렉 터 리 트 리 를 구축 하여 사용자 공간 에 정 보 를 내 보 내 고 제어 인 터 페 이 스 를 제공 합 니 다.
int __init pci_subsys_init(void)
{
	/*
	 * The init function returns an non zero value when
	 * pci_legacy_init should be invoked.
	 */
	if (x86_init.pci.init())
		pci_legacy_init();	//       pci  ,    

	pcibios_fixup_peer_bridges();
	x86_init.pci.init_irq();	//pci        
	pcibios_init();		//pci        

	return 0;
}
subsys_initcall(pci_subsys_init);
int __init pci_legacy_init(void)
{
	if (!raw_pci_ops) {
		printk("PCI: System does not support PCI
"); return 0; } printk("PCI: Probing PCI hardware
"); pci_root_bus = pcibios_scan_root(0); // pci if (pci_root_bus) pci_bus_add_devices(pci_root_bus); // pci pci sysfs return 0; }
pci_legacy_init
pci_scan_bus_parented
pci_create_bus
pci_scan_child_bus
pci_scan_slot
pci_scan_single_device
pci_scan_device
alloc_pci_dev
pci_setup_device
pci_device_add
pci_scan_bridge
pci_add_new_bus
pci_alloc_child_bus
pci_scan_child_bus
pci 인 터 럽 트 루트 초기 화
void __init pcibios_irq_init(void)
{
	DBG(KERN_DEBUG "PCI: IRQ init
"); if (raw_pci_ops == NULL) return; dmi_check_system(pciirq_dmi_table); pirq_table = pirq_find_routing_table(); // #ifdef CONFIG_PCI_BIOS if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN)) pirq_table = pcibios_get_irq_routing_table(); // #endif if (pirq_table) { // pirq_peer_trick(); // pci pci , pirq_find_router(&pirq_router); // , pirq_router if (pirq_table->exclusive_irqs) { int i; for (i = 0; i < 16; i++) if (!(pirq_table->exclusive_irqs & (1 << i))) pirq_penalty[i] += 100; } /* * If we're using the I/O APIC, avoid using the PCI IRQ * routing table */ if (io_apic_assign_pci_irqs) pirq_table = NULL; } x86_init.pci.fixup_irqs(); // ISA IRQ if (io_apic_assign_pci_irqs && pci_routeirq) { struct pci_dev *dev = NULL; /* * PCI IRQ routing is set up by pci_enable_device(), but we * also do it here in case there are still broken drivers that * don't use pci_enable_device(). */ printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified
"); for_each_pci_dev(dev) pirq_enable_irq(dev); } }
Pci 자원 배분 절차 초기 화
int __init pcibios_init(void)
{
	if (!raw_pci_ops) {
		printk(KERN_WARNING "PCI: System does not support PCI
"); return 0; } pcibios_set_cache_line_size(); pcibios_resource_survey(); if (pci_bf_sort >= pci_force_bf) pci_sort_breadthfirst(); return 0; } void __init pcibios_resource_survey(void) { DBG("PCI: Allocating resources
"); pcibios_allocate_bus_resources(&pci_root_buses); pcibios_allocate_resources(0); pcibios_allocate_resources(1); e820_reserve_resources_late(); /* * Insert the IO APIC resources after PCI initialization has * occurred to handle IO APICS that are mapped in on a BAR in * PCI space, but before trying to assign unassigned pci res. */ ioapic_insert_resources(); }
pcibios_allocate_bus_resources 함 수 는 모든 하위 버스 에 자원 창 을 저장 하고 유지 할 수 있다 면 자원 을 부모 자원 의 링크 에 걸 어 줍 니 다.
pcibios_allocate_resources (0) 시 작 된 Pci 장치 처리
pcibios_allocate_resources (1) 사용 하지 않 는 Pci 장치 처리
3. pci 장치 구동 에 대한 소개
struct pci_driver {
	struct list_head node;
	const char *name;
	const struct pci_device_id *id_table;	/* must be non-NULL for probe to be called */
	int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);	/* New device inserted */
	void (*remove) (struct pci_dev *dev);	/* Device removed (NULL if not a hot-plug capable driver) */
	int  (*suspend) (struct pci_dev *dev, pm_message_t state);	/* Device suspended */
	int  (*suspend_late) (struct pci_dev *dev, pm_message_t state);
	int  (*resume_early) (struct pci_dev *dev);
	int  (*resume) (struct pci_dev *dev);	                /* Device woken up */
	void (*shutdown) (struct pci_dev *dev);
	struct pci_error_handlers *err_handler;
	struct device_driver	driver;
	struct pci_dynids dynids;
};
pci_register_driver 등록 pci 드라이버
pci_register_driver
driver_register
bus_add_driver
driver_attach
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)
__driver_attach
driver_match_device
pci_bus_match
pci_match_device / / 현재 동적 Id 체인 테이블 에서 일치 하고 정적 ID 테이블 에서 일치 합 니 다
driver_probe_device
really_probe
dev->bus->probe(dev)
pci_device_probe
__pci_device_probe
pci_match_device
pci_call_probe
local_pci_probe
ddi->drv->probe(ddi->dev, ddi->id)
여기까지 Pci 프레임 워 크 는 대체적으로 소개 되 었 고 구체 적 인 스 캔 과정 은 을 참조 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기