pci.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 807 行 · 第 1/2 页

C
807
字号
/* *	$Id: pci.c,v 1.91 1999/01/21 13:34:01 davem Exp $ * *	PCI Bus Services, see include/linux/pci.h for further explanation. * *	Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, *	David Mosberger-Tang * *	Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz> */#include <linux/delay.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/module.h>#include <linux/spinlock.h>#include <asm/dma.h>	/* isa_dma_bridge_buggy */#undef DEBUG#ifdef DEBUG#define DBG(x...) printk(x)#else#define DBG(x...)#endif/** * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children * @bus: pointer to PCI bus structure to search * * Given a PCI bus, returns the highest PCI bus number present in the set * including the given PCI bus and its list of child PCI buses. */unsigned char __devinitpci_bus_max_busnr(struct pci_bus* bus){	struct list_head *tmp;	unsigned char max, n;	max = bus->number;	list_for_each(tmp, &bus->children) {		n = pci_bus_max_busnr(pci_bus_b(tmp));		if(n > max)			max = n;	}	return max;}/** * pci_max_busnr - returns maximum PCI bus number * * Returns the highest PCI bus number present in the system global list of * PCI buses. */unsigned char __devinitpci_max_busnr(void){	struct pci_bus *bus = NULL;	unsigned char max, n;	max = 0;	while ((bus = pci_find_next_bus(bus)) != NULL) {		n = pci_bus_max_busnr(bus);		if(n > max)			max = n;	}	return max;}static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_type, int cap){	u16 status;	u8 pos, id;	int ttl = 48;	pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);	if (!(status & PCI_STATUS_CAP_LIST))		return 0;	switch (hdr_type) {	case PCI_HEADER_TYPE_NORMAL:	case PCI_HEADER_TYPE_BRIDGE:		pci_bus_read_config_byte(bus, devfn, PCI_CAPABILITY_LIST, &pos);		break;	case PCI_HEADER_TYPE_CARDBUS:		pci_bus_read_config_byte(bus, devfn, PCI_CB_CAPABILITY_LIST, &pos);		break;	default:		return 0;	}	while (ttl-- && pos >= 0x40) {		pos &= ~3;		pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, &id);		if (id == 0xff)			break;		if (id == cap)			return pos;		pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_NEXT, &pos);	}	return 0;}/** * pci_find_capability - query for devices' capabilities  * @dev: PCI device to query * @cap: capability code * * Tell if a device supports a given PCI capability. * Returns the address of the requested capability structure within the * device's PCI configuration space or 0 in case the device does not * support it.  Possible values for @cap: * *  %PCI_CAP_ID_PM           Power Management  *  %PCI_CAP_ID_AGP          Accelerated Graphics Port  *  %PCI_CAP_ID_VPD          Vital Product Data  *  %PCI_CAP_ID_SLOTID       Slot Identification  *  %PCI_CAP_ID_MSI          Message Signalled Interrupts *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap  *  %PCI_CAP_ID_PCIX         PCI-X *  %PCI_CAP_ID_EXP          PCI Express */int pci_find_capability(struct pci_dev *dev, int cap){	return __pci_bus_find_cap(dev->bus, dev->devfn, dev->hdr_type, cap);}/** * pci_bus_find_capability - query for devices' capabilities  * @bus:   the PCI bus to query * @devfn: PCI device to query * @cap:   capability code * * Like pci_find_capability() but works for pci devices that do not have a * pci_dev structure set up yet.  * * Returns the address of the requested capability structure within the * device's PCI configuration space or 0 in case the device does not * support it. */int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap){	u8 hdr_type;	pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);	return __pci_bus_find_cap(bus, devfn, hdr_type & 0x7f, cap);}/** * pci_find_ext_capability - Find an extended capability * @dev: PCI device to query * @cap: capability code * * Returns the address of the requested extended capability structure * within the device's PCI configuration space or 0 if the device does * not support it.  Possible values for @cap: * *  %PCI_EXT_CAP_ID_ERR		Advanced Error Reporting *  %PCI_EXT_CAP_ID_VC		Virtual Channel *  %PCI_EXT_CAP_ID_DSN		Device Serial Number *  %PCI_EXT_CAP_ID_PWR		Power Budgeting */int pci_find_ext_capability(struct pci_dev *dev, int cap){	u32 header;	int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */	int pos = 0x100;	if (dev->cfg_size <= 256)		return 0;	if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)		return 0;	/*	 * If we have no capabilities, this is indicated by cap ID,	 * cap version and next pointer all being 0.	 */	if (header == 0)		return 0;	while (ttl-- > 0) {		if (PCI_EXT_CAP_ID(header) == cap)			return pos;		pos = PCI_EXT_CAP_NEXT(header);		if (pos < 0x100)			break;		if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)			break;	}	return 0;}/** * pci_find_parent_resource - return resource region of parent bus of given region * @dev: PCI device structure contains resources to be searched * @res: child resource record for which parent is sought * *  For given resource region of given device, return the resource *  region of parent bus the given region is contained in or where *  it should be allocated from. */struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res){	const struct pci_bus *bus = dev->bus;	int i;	struct resource *best = NULL;	for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {		struct resource *r = bus->resource[i];		if (!r)			continue;		if (res->start && !(res->start >= r->start && res->end <= r->end))			continue;	/* Not contained */		if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))			continue;	/* Wrong type */		if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))			return r;	/* Exact match */		if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH))			best = r;	/* Approximating prefetchable by non-prefetchable */	}	return best;}/** * pci_set_power_state - Set the power state of a PCI device * @dev: PCI device to be suspended * @state: Power state we're entering * * Transition a device to a new power state, using the Power Management  * Capabilities in the device's config space. * * RETURN VALUE:  * -EINVAL if trying to enter a lower state than we're already in. * 0 if we're already in the requested state. * -EIO if device does not support PCI PM. * 0 if we can successfully change the power state. */intpci_set_power_state(struct pci_dev *dev, int state){	int pm;	u16 pmcsr;	/* bound the state we're entering */	if (state > 3) state = 3;	/* Validate current state:	 * Can enter D0 from any state, but if we can only go deeper 	 * to sleep if we're already in a low power state	 */	if (state > 0 && dev->current_state > state)		return -EINVAL;	else if (dev->current_state == state) 		return 0;        /* we're already there */	/* find PCI PM capability in list */	pm = pci_find_capability(dev, PCI_CAP_ID_PM);		/* abort if the device doesn't support PM capabilities */	if (!pm) return -EIO; 	/* check if this device supports the desired state */	if (state == 1 || state == 2) {		u16 pmc;		pci_read_config_word(dev,pm + PCI_PM_PMC,&pmc);		if (state == 1 && !(pmc & PCI_PM_CAP_D1)) return -EIO;		else if (state == 2 && !(pmc & PCI_PM_CAP_D2)) return -EIO;	}	/* If we're in D3, force entire word to 0.	 * This doesn't affect PME_Status, disables PME_En, and	 * sets PowerState to 0.	 */	if (dev->current_state >= 3)		pmcsr = 0;	else {		pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;		pmcsr |= state;	}	/* enter specified state */	pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr);	/* Mandatory power management transition delays */	/* see PCI PM 1.1 5.6.1 table 18 */	if(state == 3 || dev->current_state == 3)		msleep(10);	else if(state == 2 || dev->current_state == 2)		udelay(200);	dev->current_state = state;	return 0;}/** * pci_save_state - save the PCI configuration space of a device before suspending * @dev: - PCI device that we're dealing with * @buffer: - buffer to hold config space context * * @buffer must be large enough to hold the entire PCI 2.2 config space  * (>= 64 bytes). */intpci_save_state(struct pci_dev *dev, u32 *buffer){	int i;	if (buffer) {		/* XXX: 100% dword access ok here? */		for (i = 0; i < 16; i++)			pci_read_config_dword(dev, i * 4,&buffer[i]);	}	return 0;}/**  * pci_restore_state - Restore the saved state of a PCI device * @dev: - PCI device that we're dealing with * @buffer: - saved PCI config space * */int pci_restore_state(struct pci_dev *dev, u32 *buffer){	int i;	if (buffer) {		for (i = 0; i < 16; i++)			pci_write_config_dword(dev,i * 4, buffer[i]);	}	/*	 * otherwise, write the context information we know from bootup.	 * This works around a problem where warm-booting from Windows	 * combined with a D3(hot)->D0 transition causes PCI config	 * header data to be forgotten.	 */		else {		for (i = 0; i < 6; i ++)			pci_write_config_dword(dev,					       PCI_BASE_ADDRESS_0 + (i * 4),					       dev->resource[i].start);		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);	}	return 0;}/** * pci_enable_device_bars - Initialize some of a device for use * @dev: PCI device to be initialized * @bars: bitmask of BAR's that must be configured * *  Initialize device before it's used by a driver. Ask low-level code *  to enable selected I/O and memory resources. Wake up the device if it  *  was suspended. Beware, this function can fail. */ intpci_enable_device_bars(struct pci_dev *dev, int bars){	int err;	pci_set_power_state(dev, 0);	if ((err = pcibios_enable_device(dev, bars)) < 0)		return err;	return 0;}/** * pci_enable_device - Initialize device before it's used by a driver. * @dev: PCI device to be initialized * *  Initialize device before it's used by a driver. Ask low-level code *  to enable I/O and memory. Wake up the device if it was suspended. *  Beware, this function can fail. */intpci_enable_device(struct pci_dev *dev){	dev->is_enabled = 1;	return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);}/** * pci_disable_device - Disable PCI device after use * @dev: PCI device to be disabled * * Signal to the system that the PCI device is not in use by the system * anymore.  This only involves disabling PCI bus-mastering, if active. */voidpci_disable_device(struct pci_dev *dev){	u16 pci_command;		dev->is_enabled = 0;	dev->is_busmaster = 0;	pci_read_config_word(dev, PCI_COMMAND, &pci_command);

⌨️ 快捷键说明

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