⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci.c

📁 newos is new operation system
💻 C
📖 第 1 页 / 共 3 页
字号:
/*** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.** Distributed under the terms of the NewOS License.*/#include <kernel/kernel.h>#include <kernel/debug.h>#include <kernel/lock.h>#include <kernel/smp.h>#include <kernel/int.h>#include <kernel/heap.h>#include <kernel/thread.h>#include <kernel/module.h>#include <kernel/vm.h>#include <newos/errors.h>#include <string.h>#include <kernel/bus/pci/pci.h>//#include "pcihdr.h"#define TRACE_PCI 1#if TRACE_PCI#	define TRACE(x) dprintf x#else#	define TRACE(x) ;#endifstruct pci_device {	struct pci_device *next;	int type;	pci_info *info;};struct pci_bus {	struct pci_bus *next;	pci_info *info;};enum {	PCI_DEVICE = 0,	PCI_HOST_BUS,	PCI_BRIDGE,	PCI_CARDBUS};static struct pci_device *pci_devices = NULL;static struct pci_bus    *pci_busses  = NULL;static spinlock_t pci_config_lock = 0;  /* lock for config space access */static int        pci_mode = 1;         /* The pci config mechanism we're using.                                         * NB defaults to 1 as this is more common, but                                         * checked at runtime                                         */static int        bus_max_devices = 32; /* max devices that any bus can support                                         * Yes, if we're using pci_mode == 2 then                                         * this is only 16, instead of the 32 we                                         * have with pci_mode == 1                                         */static int        pci_max_bus = 0;      /* maximum bus we've found/configured */static region_id  pci_region;           /* pci_bios region we map */static void *     pci_bios_ptr = NULL;  /* virtual address of memory we map */static void pci_scan_bus(uint8 bus);static void pci_bridge(uint8 bus, uint8 dev, uint8 func);static void fill_basic_pci_structure(pci_info *pcii);static uint32 read_pci_config(uchar, uchar, uchar, uchar, uchar);static void write_pci_config (uchar, uchar, uchar, uchar, uchar, uint32);/* XXX - move these to a header file */#define PCI_VENDOR_INTEL                 0x8086#define PCI_PRODUCT_INTEL_82371AB_ISA    0x7110 /* PIIX4 ISA */#define PCI_PRODUCT_INTEL_82371AB_IDE    0x7111 /* PIIX4 IDE */#define PCI_PRODUCT_INTEL_82371AB_USB    0x7112 /* PIIX4 USB */#define PCI_PRODUCT_INTEL_82371AB_PMC    0x7113 /* PIIX4 Power Management */#define PCI_PRODUCT_INTEL_82443BX        0x7190#define PCI_PRODUCT_INTEL_82443BX_AGP    0x7191#define PCI_PRODUCT_INTEL_82443BX_NOAGP  0x7192#define PCI_PRODUCT_INTEL_82845_AGP      0x1a31/* Config space locking! * We need to make sure we only have one access at a time into the config space, * so we'll use a spinlock and also disbale interrupts so if we're smp we * won't have problems. */#define PCI_LOCK_CONFIG() \{ \	int_disable_interrupts(); \	acquire_spinlock(&pci_config_lock); \}#define PCI_UNLOCK_CONFIG() \{ \	release_spinlock(&pci_config_lock); \	int_restore_interrupts(); \}/* decode_class * DEBUG DEBUG DEBUG * Provide a string that describes the class and sub-class. * This could/should (?) be expanded to use the api as well. */static char *decode_class(uint8 base, uint8 sub_class){	switch(base) {		case 0:			switch (sub_class) {				case 0:					return "legacy (non VGA)";				case 1:					return "legacy VGA";			}		case 0x01:			switch (sub_class) {				case 0:					return "mass storage: scsi";				case 1:					return "mass storage: ide";				case 2:					return "mass storage: floppy";				case 3:					return "mass storage: ipi";				case 4:					return "mass storage: raid";				case 5:					return "mass storage: ata";				case 6:					return "mass storage: sata";				case 0x80:					return "mass storage: other";			}		case 0x02:			switch (sub_class) {				case 0:					return "network: ethernet";				case 1:					return "network: token ring";				case 2:					return "network: fddi";				case 3:					return "network: atm";				case 4:					return "network: isdn";				case 0x80:					return "network: other";			}		case 0x03:			switch (sub_class) {				case 0:					return "display: vga";				case 1:					return "display: xga";				case 2:					return "display: 3d";				case 0x80:					return "display: other";			}		case 0x04:			switch (sub_class) {				case 0:					return "multimedia device: video";				case 1:					return "multimedia device: audio";				case 2:					return "multimedia device: telephony";				case 0x80:					return "multimedia device: other";			}		case 0x05:			switch (sub_class) {				case 0:					return "memory: ram";				case 1:					return "memory: flash";				case 0x80:					return "memory: other";			}		case 0x06:			switch (sub_class) {				case 0:					return "bridge: host bridge";				case 1:					return "bridge: isa";				case 2:					return "bridge: eisa";				case 3:					return "bridge: microchannel";				case 4:					return "bridge: PCI";				case 5:					return "bridge: PC Card";				case 6:					return "bridge: nubus";				case 7:					return "bridge: CardBus";				case 8:					return "bridge: raceway";				case 9:					return "bridge: stpci";				case 10:					return "bridge: infiniband";				case 0x80:					return "bridge: other";			}		case 0x07: return "simple comms controller";		case 0x08: return "base system peripheral";		case 0x09: return "input device";		case 0x0a: return "docking station";		case 0x0b: return "processor";		case 0x0c:			switch (sub_class) {				case 0:					return "bus: IEEE1394 FireWire";				case 1:					return "bus: ACCESS.bus";				case 2:					return "bus: SSA";				case 3:					return "bus: USB";				case 4:					return "bus: fibre channel";			}		case 0x0d: return "wireless";		case 0x0e: return "intelligent i/o ??";		case 0x0f: return "satellite";		case 0x10: return "encryption";		case 0x11: return "signal processing";		default: return "unknown";	}}static voidshow_pci_details(struct pci_info *p){#if TRACE_PCI	uint16 ss_vend, ss_dev;#endif	uint8 irq = 0;	if (p->header_type == PCI_header_type_generic)		irq = p->u.h0.interrupt_line;	else		irq = p->u.h1.interrupt_line;	dprintf("0x%04x:0x%04x : ", p->vendor_id, p->device_id);	if (irq > 0)		dprintf("irq %d : ", irq);	dprintf("location %d:%d:%d : ", p->bus, p->device, p->function);	dprintf("class %02x:%02x:%02x", p->class_base, p->class_sub,	        p->class_api);	dprintf(" => %s\n", decode_class(p->class_base, p->class_sub));#if TRACE_PCI	dprintf("\trevision    : %02x\n", p->revision);	dprintf("\tstatus      : %04x\n",	        read_pci_config(p->bus, p->device, p->function, PCI_status, 2));	dprintf("\tcommand     : %04x\n",	        read_pci_config(p->bus, p->device, p->function, PCI_command, 2));	dprintf("\tbase address: %08x\n",	        read_pci_config(p->bus, p->device, p->function, PCI_base_registers, 4));	dprintf("\tline_size   : %02x\n", p->line_size);	dprintf("\theader_type : %02x\n", p->header_type);	if (p->header_type == PCI_header_type_generic) {		dprintf("Header Type 0 (Generic)\n");		dprintf("\tcardbus_cis         : %08lx\n", p->u.h0.cardbus_cis);		dprintf("\trom_base_pci        : %08lx\n", p->u.h0.rom_base_pci);		dprintf("\tinterrupt_line      : %02x\n", p->u.h0.interrupt_line);		dprintf("\tinterrupt_pin       : %02x\n", p->u.h0.interrupt_pin);		ss_vend = p->u.h0.subsystem_vendor_id;		ss_dev = p->u.h0.subsystem_id;	} else if (p->header_type == PCI_header_type_PCI_to_PCI_bridge) {		dprintf("Header Type 1 (PCI-PCI bridge)\n");		dprintf("\trom_base_pci        : %08lx\n", p->u.h1.rom_base_pci);		dprintf("\tinterrupt_line      : %02x\n", p->u.h1.interrupt_line);		dprintf("\tinterrupt_pin       : %02x\n", p->u.h1.interrupt_pin);		dprintf("\t2ndry status        : %04x\n", p->u.h1.secondary_status);		dprintf("\tprimary_bus         : %d\n", p->u.h1.primary_bus);		dprintf("\tsecondary_bus       : %d\n", p->u.h1.secondary_bus);		dprintf("\tsubordinate_bus     : %d\n", p->u.h1.subordinate_bus);		ss_vend = p->u.h1.subsystem_vendor_id;		ss_dev = p->u.h1.subsystem_id;	} else {		ss_vend = 0;		ss_dev = 0;	}	dprintf("\tsubsystem_id        : %04x\n", ss_dev);	dprintf("\tsubsystem_vendor_id : %04x\n", ss_vend);#endif}/* PCI has 2 Configuration Mechanisms. We need to decide which one the * PCI Host Bridge is speaking and then speak to it correctly. This is decided * in set_pci_mechanism() where the pci_mode value is set to the appropriate * value and the bus_max_devices value is set correctly. * * Mechanism 1 * =========== * Mechanism 1 is the more common one found on modern computers, so presently * that's the one that has been tested and added. * * This has 2 ranges, one for addressing and for data. Basically we write in the details of * the configuration information we want (bus, device and function) and then either * read or write from the data port. * * Apparently most modern hardware no longer has Configuration Type #2. * * XXX - add code for Mechanism Two * * */#define CONFIG_REQ_PORT    0xCF8#define CONFIG_DATA_PORT   0xCFC#define CONFIG_ADDR_1(bus, device, func, reg) \	(0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (reg & ~3))#define CONFIG_ADDR_2(dev, reg) \	(uint16)(0xC00 | (dev << 8) | reg)static uint32read_pci_config(uchar bus, uchar device, uchar function, uchar reg, uchar size){	uint32 val = 0;	PCI_LOCK_CONFIG();	if (pci_mode == 1) {		/* write request details */		out32(CONFIG_ADDR_1(bus, device, function, reg), CONFIG_REQ_PORT);		/* Now read data back from the data port...		 * offset for 1 byte can be 1,2 or 3		 * offset for 2 bytes can be 1 or 2		 */		switch (size) {			case 1:				val = in8 (CONFIG_DATA_PORT + (reg & 3));				break;			case 2:				if ((reg & 3) != 3)					val = in16(CONFIG_DATA_PORT + (reg & 3));				else {					val = ERR_INVALID_ARGS;					dprintf("ERROR: read_pci_config: can't read 2 bytes at reg %d (offset 3)!\n",reg);				}				break;			case 4:				if ((reg & 3) == 0)					val = in32(CONFIG_DATA_PORT);				else {					val = ERR_INVALID_ARGS;					dprintf("ERROR: read_pci_config: can't read 4 bytes at reg %d (offset != 0)!\n",reg);				}				break;			default:				dprintf("ERROR: mech #1: read_pci_config: called for %d bytes!!\n", size);		}	} else if (pci_mode == 2) {		if (!(device & 0x10)) {			out8((uint8)(0xF0 | (function << 1)), 0xCF8);			out8(bus, 0xCFA);			switch (size) {				case 1:					val = in8 (CONFIG_ADDR_2(device, reg));					break;				case 2:					val = in16(CONFIG_ADDR_2(device, reg));					break;				case 4:					val = in32(CONFIG_ADDR_2(device, reg));					break;				default:					dprintf("ERROR: mech #2: read_pci_config: called for %d bytes!!\n", size);			}			out8(0, 0xCF8);		} else			val = ERR_INVALID_ARGS;	} else		dprintf("PCI: Config Mechanism %d isn't known!\n", pci_mode);	PCI_UNLOCK_CONFIG();	return val;}static voidwrite_pci_config(uchar bus, uchar device, uchar function, uchar reg, uchar size, uint32 value){	PCI_LOCK_CONFIG();	if (pci_mode == 1) {		/* write request details */		out32(CONFIG_ADDR_1(bus, device, function, reg), CONFIG_REQ_PORT);		/* Now read data back from the data port...		 * offset for 1 byte can be 1,2 or 3		 * offset for 2 bytes can be 1 or 2		 */		switch (size) {			case 1:				out8 (value, CONFIG_DATA_PORT + (reg & 3));				break;			case 2:				if ((reg & 3) != 3)					out16(value, CONFIG_DATA_PORT + (reg & 3));				else					dprintf("ERROR: write_pci_config: can't write 2 bytes at reg %d (offset 3)!\n",reg);				break;			case 4:				if ((reg & 3) == 0)					out32(value, CONFIG_DATA_PORT);				else					dprintf("ERROR: write_pci_config: can't write 4 bytes at reg %d (offset != 0)!\n",reg);				break;			default:				dprintf("ERROR: write_pci_config: called for %d bytes!!\n", size);		}	} else if (pci_mode == 2) {		if (!(device & 0x10)) {			out8((uint8)(0xF0 | (function << 1)), 0xCF8);			out8(bus, 0xCFA);			switch (size) {				case 1:					out8 (value, CONFIG_ADDR_2(device, reg));					break;				case 2:					out16(value, CONFIG_ADDR_2(device, reg));					break;				case 4:					out32(value, CONFIG_ADDR_2(device, reg));					break;				default:					dprintf("ERROR: write_pci_config: called for %d bytes!!\n", size);			}			out8(0, 0xCF8);		}	} else		dprintf("PCI: Config Mechanism %d isn't known!\n", pci_mode);	PCI_UNLOCK_CONFIG();	return;}/* pci_get_capability * Try to get the offset and value of the specified capability from the * devices capability list. * returns 0 if unable, 1 if succesful */static intpci_get_capability(uint8 bus, uint8 dev, uint8 func, uint8 cap, uint8 *offs){	uint16 status;	uint8 cap_data;	uint8 hdr_type;	uint8 ofs;	int maxcount;	status = read_pci_config(bus, dev, func, PCI_status, 2);	if (!(status & PCI_status_capabilities))		return 0;	hdr_type = read_pci_config(bus, dev, func, PCI_header_type, 1);	switch (hdr_type & 0x7f) { /* mask off multi function device indicator bit */		case PCI_header_type_generic:			ofs = PCI_capabilities_ptr;			break;		case PCI_header_type_PCI_to_PCI_bridge:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -