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

📄 pci.c

📁 i386的bootloader源码grub
💻 C
字号:
/*** Support for NE2000 PCI clones added David Monro June 1997** Generalised to other NICs by Ken Yap July 1997**** Most of this is taken from:**** /usr/src/linux/drivers/pci/pci.c** /usr/src/linux/include/linux/pci.h** /usr/src/linux/arch/i386/bios32.c** /usr/src/linux/include/linux/bios32.h** /usr/src/linux/drivers/net/ne.c*//* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. */#include "etherboot.h"#include "pci.h"/*#define	DEBUG	1*/#define DEBUG	0#ifdef	CONFIG_PCI_DIRECT#define  PCIBIOS_SUCCESSFUL                0x00/* * Functions for accessing PCI configuration space with type 1 accesses */#define CONFIG_CMD(bus, device_fn, where)   (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn,			       unsigned int where, unsigned char *value){    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);    *value = inb(0xCFC + (where&3));    return PCIBIOS_SUCCESSFUL;}int pcibios_read_config_word (unsigned int bus,    unsigned int device_fn, unsigned int where, unsigned short *value){    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);    *value = inw(0xCFC + (where&2));    return PCIBIOS_SUCCESSFUL;}int pcibios_read_config_dword (unsigned int bus, unsigned int device_fn,				 unsigned int where, unsigned int *value){    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);    *value = inl(0xCFC);    return PCIBIOS_SUCCESSFUL;}int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn,				 unsigned int where, unsigned char value){    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);    outb(value, 0xCFC + (where&3));    return PCIBIOS_SUCCESSFUL;}int pcibios_write_config_word (unsigned int bus, unsigned int device_fn,				 unsigned int where, unsigned short value){    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);    outw(value, 0xCFC + (where&2));    return PCIBIOS_SUCCESSFUL;}int pcibios_write_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value){    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);    outl(value, 0xCFC);    return PCIBIOS_SUCCESSFUL;}#undef CONFIG_CMD#else	 /* CONFIG_PCI_DIRECT  not defined */static struct {	unsigned long address;	unsigned short segment;} bios32_indirect = { 0, KERN_CODE_SEG };static long pcibios_entry;static struct {	unsigned long address;	unsigned short segment;} pci_indirect = { 0, KERN_CODE_SEG };static unsigned long bios32_service(unsigned long service){	unsigned char return_code;	/* %al */	unsigned long address;		/* %ebx */	unsigned long length;		/* %ecx */	unsigned long entry;		/* %edx */	unsigned long flags;	save_flags(flags);	__asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK		"lcall (%%edi)"#else		"lcall *(%%edi)"#endif		: "=a" (return_code),		  "=b" (address),		  "=c" (length),		  "=d" (entry)		: "0" (service),		  "1" (0),		  "D" (&bios32_indirect));	restore_flags(flags);	switch (return_code) {		case 0:			return address + entry;		case 0x80:	/* Not present */			printf("bios32_service(%d) : not present\n", service);			return 0;		default: /* Shouldn't happen */			printf("bios32_service(%d) : returned %#X, mail drew@colorado.edu\n",				service, return_code);			return 0;	}}int pcibios_read_config_byte(unsigned int bus,        unsigned int device_fn, unsigned int where, unsigned char *value){        unsigned long ret;        unsigned long bx = (bus << 8) | device_fn;        unsigned long flags;        save_flags(flags);        __asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK		"lcall (%%esi)\n\t"#else		"lcall *(%%esi)\n\t"#endif                "jc 1f\n\t"                "xor %%ah, %%ah\n"                "1:"                : "=c" (*value),                  "=a" (ret)                : "1" (PCIBIOS_READ_CONFIG_BYTE),                  "b" (bx),                  "D" ((long) where),                  "S" (&pci_indirect));        restore_flags(flags);        return (int) (ret & 0xff00) >> 8;}int pcibios_read_config_word(unsigned int bus,        unsigned int device_fn, unsigned int where, unsigned short *value){        unsigned long ret;        unsigned long bx = (bus << 8) | device_fn;        unsigned long flags;        save_flags(flags);        __asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK		"lcall (%%esi)\n\t"#else		"lcall *(%%esi)\n\t"#endif                "jc 1f\n\t"                "xor %%ah, %%ah\n"                "1:"                : "=c" (*value),                  "=a" (ret)                : "1" (PCIBIOS_READ_CONFIG_WORD),                  "b" (bx),                  "D" ((long) where),                  "S" (&pci_indirect));        restore_flags(flags);        return (int) (ret & 0xff00) >> 8;}int pcibios_read_config_dword(unsigned int bus,        unsigned int device_fn, unsigned int where, unsigned int *value){        unsigned long ret;        unsigned long bx = (bus << 8) | device_fn;        unsigned long flags;        save_flags(flags);        __asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK		"lcall (%%esi)\n\t"#else		"lcall *(%%esi)\n\t"#endif                "jc 1f\n\t"                "xor %%ah, %%ah\n"                "1:"                : "=c" (*value),                  "=a" (ret)                : "1" (PCIBIOS_READ_CONFIG_DWORD),                  "b" (bx),                  "D" ((long) where),                  "S" (&pci_indirect));        restore_flags(flags);        return (int) (ret & 0xff00) >> 8;}int pcibios_write_config_byte (unsigned int bus,	unsigned int device_fn, unsigned int where, unsigned char value){	unsigned long ret;	unsigned long bx = (bus << 8) | device_fn;	unsigned long flags;	save_flags(flags); cli();	__asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK		"lcall (%%esi)\n\t"#else		"lcall *(%%esi)\n\t"#endif		"jc 1f\n\t"		"xor %%ah, %%ah\n"		"1:"		: "=a" (ret)		: "0" (PCIBIOS_WRITE_CONFIG_BYTE),		  "c" (value),		  "b" (bx),		  "D" ((long) where),		  "S" (&pci_indirect));	restore_flags(flags);	return (int) (ret & 0xff00) >> 8;}int pcibios_write_config_word (unsigned int bus,	unsigned int device_fn, unsigned int where, unsigned short value){	unsigned long ret;	unsigned long bx = (bus << 8) | device_fn;	unsigned long flags;	save_flags(flags); cli();	__asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK		"lcall (%%esi)\n\t"#else		"lcall *(%%esi)\n\t"#endif		"jc 1f\n\t"		"xor %%ah, %%ah\n"		"1:"		: "=a" (ret)		: "0" (PCIBIOS_WRITE_CONFIG_WORD),		  "c" (value),		  "b" (bx),		  "D" ((long) where),		  "S" (&pci_indirect));	restore_flags(flags);	return (int) (ret & 0xff00) >> 8;}int pcibios_write_config_dword (unsigned int bus,	unsigned int device_fn, unsigned int where, unsigned int value){	unsigned long ret;	unsigned long bx = (bus << 8) | device_fn;	unsigned long flags;	save_flags(flags); cli();	__asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK		"lcall (%%esi)\n\t"#else		"lcall *(%%esi)\n\t"#endif		"jc 1f\n\t"		"xor %%ah, %%ah\n"		"1:"		: "=a" (ret)		: "0" (PCIBIOS_WRITE_CONFIG_DWORD),		  "c" (value),		  "b" (bx),		  "D" ((long) where),		  "S" (&pci_indirect));	restore_flags(flags);	return (int) (ret & 0xff00) >> 8;}static void check_pcibios(void){	unsigned long signature;	unsigned char present_status;	unsigned char major_revision;	unsigned char minor_revision;	unsigned long flags;	int pack;	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {		pci_indirect.address = pcibios_entry;		save_flags(flags);		__asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK			"lcall (%%edi)\n\t"#else			"lcall *(%%edi)\n\t"#endif			"jc 1f\n\t"			"xor %%ah, %%ah\n"			"1:\tshl $8, %%eax\n\t"			"movw %%bx, %%ax"			: "=d" (signature),			  "=a" (pack)			: "1" (PCIBIOS_PCI_BIOS_PRESENT),			  "D" (&pci_indirect)			: "bx", "cx");		restore_flags(flags);		present_status = (pack >> 16) & 0xff;		major_revision = (pack >> 8) & 0xff;		minor_revision = pack & 0xff;		if (present_status || (signature != PCI_SIGNATURE)) {			printf("ERROR: BIOS32 says PCI BIOS, but no PCI "				"BIOS????\n");			pcibios_entry = 0;		}#if	DEBUG		if (pcibios_entry) {			printf ("pcibios_init : PCI BIOS revision %hhX.%hhX"				" entry at %#X\n", major_revision,				minor_revision, pcibios_entry);		}#endif	}}static void pcibios_init(void){	union bios32 *check;	unsigned char sum;	int i, length;	unsigned long bios32_entry = 0;	/*	 * Follow the standard procedure for locating the BIOS32 Service	 * directory by scanning the permissible address range from	 * 0xe0000 through 0xfffff for a valid BIOS32 structure.	 *	 */	for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) {		if (check->fields.signature != BIOS32_SIGNATURE)			continue;		length = check->fields.length * 16;		if (!length)			continue;		sum = 0;		for (i = 0; i < length ; ++i)			sum += check->chars[i];		if (sum != 0)			continue;		if (check->fields.revision != 0) {			printf("pcibios_init : unsupported revision %d at %#X, mail drew@colorado.edu\n",				check->fields.revision, check);			continue;		}#if	DEBUG		printf("pcibios_init : BIOS32 Service Directory "			"structure at %#X\n", check);#endif		if (!bios32_entry) {			if (check->fields.entry >= 0x100000) {				printf("pcibios_init: entry in high "					"memory, giving up\n");				return;			} else {				bios32_entry = check->fields.entry;#if	DEBUG				printf("pcibios_init : BIOS32 Service Directory"					" entry at %#X\n", bios32_entry);#endif				bios32_indirect.address = bios32_entry;			}		}	}	if (bios32_entry)		check_pcibios();}#endif	/* CONFIG_PCI_DIRECT not defined*/static void scan_bus(struct pci_device *pcidev){	unsigned int devfn, l, bus, buses;	unsigned char hdr_type = 0;	unsigned short vendor, device;	unsigned int membase, ioaddr, romaddr;	int i, reg;	unsigned int pci_ioaddr = 0;	/* Scan all PCI buses, until we find our card.	 * We could be smart only scan the required busses but that	 * is error prone, and tricky.	 * By scanning all possible pci busses in order we should find	 * our card eventually. 	 */	buses=256;	for (bus = 0; bus < buses; ++bus) {		for (devfn = 0; devfn < 0xff; ++devfn) {			if (PCI_FUNC (devfn) == 0)				pcibios_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);			else if (!(hdr_type & 0x80))	/* not a multi-function device */				continue;			pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l);			/* some broken boards return 0 if a slot is empty: */			if (l == 0xffffffff || l == 0x00000000) {				hdr_type = 0;				continue;			}			vendor = l & 0xffff;			device = (l >> 16) & 0xffff;#if	DEBUG			printf("bus %hhX, function %hhX, vendor %hX, device %hX\n",				bus, devfn, vendor, device);#endif			for (i = 0; pcidev[i].vendor != 0; i++) {				if (vendor != pcidev[i].vendor				    || device != pcidev[i].dev_id)					continue;				pcidev[i].devfn = devfn;				pcidev[i].bus = bus;				for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {					pcibios_read_config_dword(bus, devfn, reg, &ioaddr);					if ((ioaddr & PCI_BASE_ADDRESS_IO_MASK) == 0 || (ioaddr & PCI_BASE_ADDRESS_SPACE_IO) == 0)						continue;					/* Strip the I/O address out of the returned value */					ioaddr &= PCI_BASE_ADDRESS_IO_MASK;					/* Get the memory base address */					pcibios_read_config_dword(bus, devfn,						PCI_BASE_ADDRESS_1, &membase);					/* Get the ROM base address */					pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr);					romaddr >>= 10;					printf("Found %s at %#hx, ROM address %#hx\n",						pcidev[i].name, ioaddr, romaddr);					/* Take the first one or the one that matches in boot ROM address */					if (pci_ioaddr == 0 || romaddr == ((unsigned long) rom.rom_segment << 4)) {						pcidev[i].membase = membase;						pcidev[i].ioaddr = ioaddr;						return;					}				}			}		}	}}void eth_pci_init(struct pci_device *pcidev){#ifndef	CONFIG_PCI_DIRECT	pcibios_init();	if (!pcibios_entry) {		printf("pci_init: no BIOS32 detected\n");		return;	}#endif	scan_bus(pcidev);	/* return values are in pcidev structures */}/* *	Set device to be a busmaster in case BIOS neglected to do so. *	Also adjust PCI latency timer to a reasonable value, 32. */void adjust_pci_device(struct pci_device *p){	unsigned short	new_command, pci_command;	unsigned char	pci_latency;	pcibios_read_config_word(p->bus, p->devfn, PCI_COMMAND, &pci_command);	new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;	if (pci_command != new_command) {		printf("The PCI BIOS has not enabled this device!\nUpdating PCI command %hX->%hX. pci_bus %hhX pci_device_fn %hhX\n",			   pci_command, new_command, p->bus, p->devfn);		pcibios_write_config_word(p->bus, p->devfn, PCI_COMMAND, new_command);	}	pcibios_read_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, &pci_latency);	if (pci_latency < 32) {		printf("PCI latency timer (CFLT) is unreasonably low at %d. Setting to 32 clocks.\n", pci_latency);		pcibios_write_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, 32);	}}

⌨️ 快捷键说明

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