pci.c

来自「linux 内核源代码」· C语言 代码 · 共 1,653 行 · 第 1/3 页

C
1,653
字号
	for (i = 0; i < 6; i++)		if (bars & (1 << i))			pci_release_region(pdev, i);}/** * pci_request_selected_regions - Reserve selected PCI I/O and memory resources * @pdev: PCI device whose resources are to be reserved * @bars: Bitmask of BARs to be requested * @res_name: Name to be associated with resource */int pci_request_selected_regions(struct pci_dev *pdev, int bars,				 const char *res_name){	int i;	for (i = 0; i < 6; i++)		if (bars & (1 << i))			if(pci_request_region(pdev, i, res_name))				goto err_out;	return 0;err_out:	while(--i >= 0)		if (bars & (1 << i))			pci_release_region(pdev, i);	return -EBUSY;}/** *	pci_release_regions - Release reserved PCI I/O and memory resources *	@pdev: PCI device whose resources were previously reserved by pci_request_regions * *	Releases all PCI I/O and memory resources previously reserved by a *	successful call to pci_request_regions.  Call this function only *	after all use of the PCI regions has ceased. */void pci_release_regions(struct pci_dev *pdev){	pci_release_selected_regions(pdev, (1 << 6) - 1);}/** *	pci_request_regions - Reserved PCI I/O and memory resources *	@pdev: PCI device whose resources are to be reserved *	@res_name: Name to be associated with resource. * *	Mark all PCI regions associated with PCI device @pdev as *	being reserved by owner @res_name.  Do not access any *	address inside the PCI regions unless this call returns *	successfully. * *	Returns 0 on success, or %EBUSY on error.  A warning *	message is also printed on failure. */int pci_request_regions(struct pci_dev *pdev, const char *res_name){	return pci_request_selected_regions(pdev, ((1 << 6) - 1), res_name);}/** * pci_set_master - enables bus-mastering for device dev * @dev: the PCI device to enable * * Enables bus-mastering on the device and calls pcibios_set_master() * to do the needed arch specific settings. */voidpci_set_master(struct pci_dev *dev){	u16 cmd;	pci_read_config_word(dev, PCI_COMMAND, &cmd);	if (! (cmd & PCI_COMMAND_MASTER)) {		pr_debug("PCI: Enabling bus mastering for device %s\n", pci_name(dev));		cmd |= PCI_COMMAND_MASTER;		pci_write_config_word(dev, PCI_COMMAND, cmd);	}	dev->is_busmaster = 1;	pcibios_set_master(dev);}#ifdef PCI_DISABLE_MWIint pci_set_mwi(struct pci_dev *dev){	return 0;}int pci_try_set_mwi(struct pci_dev *dev){	return 0;}void pci_clear_mwi(struct pci_dev *dev){}#else#ifndef PCI_CACHE_LINE_BYTES#define PCI_CACHE_LINE_BYTES L1_CACHE_BYTES#endif/* This can be overridden by arch code. *//* Don't forget this is measured in 32-bit words, not bytes */u8 pci_cache_line_size = PCI_CACHE_LINE_BYTES / 4;/** * pci_set_cacheline_size - ensure the CACHE_LINE_SIZE register is programmed * @dev: the PCI device for which MWI is to be enabled * * Helper function for pci_set_mwi. * Originally copied from drivers/net/acenic.c. * Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>. * * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */static intpci_set_cacheline_size(struct pci_dev *dev){	u8 cacheline_size;	if (!pci_cache_line_size)		return -EINVAL;		/* The system doesn't support MWI. */	/* Validate current setting: the PCI_CACHE_LINE_SIZE must be	   equal to or multiple of the right value. */	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cacheline_size);	if (cacheline_size >= pci_cache_line_size &&	    (cacheline_size % pci_cache_line_size) == 0)		return 0;	/* Write the correct value. */	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size);	/* Read it back. */	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cacheline_size);	if (cacheline_size == pci_cache_line_size)		return 0;	printk(KERN_DEBUG "PCI: cache line size of %d is not supported "	       "by device %s\n", pci_cache_line_size << 2, pci_name(dev));	return -EINVAL;}/** * pci_set_mwi - enables memory-write-invalidate PCI transaction * @dev: the PCI device for which MWI is enabled * * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND. * * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */intpci_set_mwi(struct pci_dev *dev){	int rc;	u16 cmd;	rc = pci_set_cacheline_size(dev);	if (rc)		return rc;	pci_read_config_word(dev, PCI_COMMAND, &cmd);	if (! (cmd & PCI_COMMAND_INVALIDATE)) {		pr_debug("PCI: Enabling Mem-Wr-Inval for device %s\n",			pci_name(dev));		cmd |= PCI_COMMAND_INVALIDATE;		pci_write_config_word(dev, PCI_COMMAND, cmd);	}		return 0;}/** * pci_try_set_mwi - enables memory-write-invalidate PCI transaction * @dev: the PCI device for which MWI is enabled * * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND. * Callers are not required to check the return value. * * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */int pci_try_set_mwi(struct pci_dev *dev){	int rc = pci_set_mwi(dev);	return rc;}/** * pci_clear_mwi - disables Memory-Write-Invalidate for device dev * @dev: the PCI device to disable * * Disables PCI Memory-Write-Invalidate transaction on the device */voidpci_clear_mwi(struct pci_dev *dev){	u16 cmd;	pci_read_config_word(dev, PCI_COMMAND, &cmd);	if (cmd & PCI_COMMAND_INVALIDATE) {		cmd &= ~PCI_COMMAND_INVALIDATE;		pci_write_config_word(dev, PCI_COMMAND, cmd);	}}#endif /* ! PCI_DISABLE_MWI *//** * pci_intx - enables/disables PCI INTx for device dev * @pdev: the PCI device to operate on * @enable: boolean: whether to enable or disable PCI INTx * * Enables/disables PCI INTx for device dev */voidpci_intx(struct pci_dev *pdev, int enable){	u16 pci_command, new;	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);	if (enable) {		new = pci_command & ~PCI_COMMAND_INTX_DISABLE;	} else {		new = pci_command | PCI_COMMAND_INTX_DISABLE;	}	if (new != pci_command) {		struct pci_devres *dr;		pci_write_config_word(pdev, PCI_COMMAND, new);		dr = find_pci_dr(pdev);		if (dr && !dr->restore_intx) {			dr->restore_intx = 1;			dr->orig_intx = !enable;		}	}}/** * pci_msi_off - disables any msi or msix capabilities * @dev: the PCI device to operate on * * If you want to use msi see pci_enable_msi and friends. * This is a lower level primitive that allows us to disable * msi operation at the device level. */void pci_msi_off(struct pci_dev *dev){	int pos;	u16 control;	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);	if (pos) {		pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);		control &= ~PCI_MSI_FLAGS_ENABLE;		pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);	}	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);	if (pos) {		pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);		control &= ~PCI_MSIX_FLAGS_ENABLE;		pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);	}}#ifndef HAVE_ARCH_PCI_SET_DMA_MASK/* * These can be overridden by arch-specific implementations */intpci_set_dma_mask(struct pci_dev *dev, u64 mask){	if (!pci_dma_supported(dev, mask))		return -EIO;	dev->dma_mask = mask;	return 0;}    intpci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask){	if (!pci_dma_supported(dev, mask))		return -EIO;	dev->dev.coherent_dma_mask = mask;	return 0;}#endif/** * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count * @dev: PCI device to query * * Returns mmrbc: maximum designed memory read count in bytes *    or appropriate error value. */int pcix_get_max_mmrbc(struct pci_dev *dev){	int err, cap;	u32 stat;	cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);	if (!cap)		return -EINVAL;	err = pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat);	if (err)		return -EINVAL;	return (stat & PCI_X_STATUS_MAX_READ) >> 12;}EXPORT_SYMBOL(pcix_get_max_mmrbc);/** * pcix_get_mmrbc - get PCI-X maximum memory read byte count * @dev: PCI device to query * * Returns mmrbc: maximum memory read count in bytes *    or appropriate error value. */int pcix_get_mmrbc(struct pci_dev *dev){	int ret, cap;	u32 cmd;	cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);	if (!cap)		return -EINVAL;	ret = pci_read_config_dword(dev, cap + PCI_X_CMD, &cmd);	if (!ret)		ret = 512 << ((cmd & PCI_X_CMD_MAX_READ) >> 2);	return ret;}EXPORT_SYMBOL(pcix_get_mmrbc);/** * pcix_set_mmrbc - set PCI-X maximum memory read byte count * @dev: PCI device to query * @mmrbc: maximum memory read count in bytes *    valid values are 512, 1024, 2048, 4096 * * If possible sets maximum memory read byte count, some bridges have erratas * that prevent this. */int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc){	int cap, err = -EINVAL;	u32 stat, cmd, v, o;	if (mmrbc < 512 || mmrbc > 4096 || !is_power_of_2(mmrbc))		goto out;	v = ffs(mmrbc) - 10;	cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);	if (!cap)		goto out;	err = pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat);	if (err)		goto out;	if (v > (stat & PCI_X_STATUS_MAX_READ) >> 21)		return -E2BIG;	err = pci_read_config_dword(dev, cap + PCI_X_CMD, &cmd);	if (err)		goto out;	o = (cmd & PCI_X_CMD_MAX_READ) >> 2;	if (o != v) {		if (v > o && dev->bus &&		   (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MMRBC))			return -EIO;		cmd &= ~PCI_X_CMD_MAX_READ;		cmd |= v << 2;		err = pci_write_config_dword(dev, cap + PCI_X_CMD, cmd);	}out:	return err;}EXPORT_SYMBOL(pcix_set_mmrbc);/** * pcie_get_readrq - get PCI Express read request size * @dev: PCI device to query * * Returns maximum memory read request in bytes *    or appropriate error value. */int pcie_get_readrq(struct pci_dev *dev){	int ret, cap;	u16 ctl;	cap = pci_find_capability(dev, PCI_CAP_ID_EXP);	if (!cap)		return -EINVAL;	ret = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);	if (!ret)	ret = 128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12);	return ret;}EXPORT_SYMBOL(pcie_get_readrq);/** * pcie_set_readrq - set PCI Express maximum memory read request * @dev: PCI device to query * @rq: maximum memory read count in bytes *    valid values are 128, 256, 512, 1024, 2048, 4096 * * If possible sets maximum read byte count */int pcie_set_readrq(struct pci_dev *dev, int rq){	int cap, err = -EINVAL;	u16 ctl, v;	if (rq < 128 || rq > 4096 || !is_power_of_2(rq))		goto out;	v = (ffs(rq) - 8) << 12;	cap = pci_find_capability(dev, PCI_CAP_ID_EXP);	if (!cap)		goto out;	err = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);	if (err)		goto out;	if ((ctl & PCI_EXP_DEVCTL_READRQ) != v) {		ctl &= ~PCI_EXP_DEVCTL_READRQ;		ctl |= v;		err = pci_write_config_dword(dev, cap + PCI_EXP_DEVCTL, ctl);	}out:	return err;}EXPORT_SYMBOL(pcie_set_readrq);/** * pci_select_bars - Make BAR mask from the type of resource * @dev: the PCI device for which BAR mask is made * @flags: resource type mask to be selected * * This helper routine makes bar mask from the type of resource. */int pci_select_bars(struct pci_dev *dev, unsigned long flags){	int i, bars = 0;	for (i = 0; i < PCI_NUM_RESOURCES; i++)		if (pci_resource_flags(dev, i) & flags)			bars |= (1 << i);	return bars;}static void __devinit pci_no_domains(void){#ifdef CONFIG_PCI_DOMAINS	pci_domains_supported = 0;#endif}static int __devinit pci_init(void){	struct pci_dev *dev = NULL;	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {		pci_fixup_device(pci_fixup_final, dev);	}	return 0;}static int __devinit pci_setup(char *str){	while (str) {		char *k = strchr(str, ',');		if (k)			*k++ = 0;		if (*str && (str = pcibios_setup(str)) && *str) {			if (!strcmp(str, "nomsi")) {				pci_no_msi();			} else if (!strcmp(str, "noaer")) {				pci_no_aer();			} else if (!strcmp(str, "nodomains")) {				pci_no_domains();			} else if (!strncmp(str, "cbiosize=", 9)) {				pci_cardbus_io_size = memparse(str + 9, &str);			} else if (!strncmp(str, "cbmemsize=", 10)) {				pci_cardbus_mem_size = memparse(str + 10, &str);			} else {				printk(KERN_ERR "PCI: Unknown option `%s'\n",						str);			}		}		str = k;	}	return 0;}early_param("pci", pci_setup);device_initcall(pci_init);EXPORT_SYMBOL_GPL(pci_restore_bars);EXPORT_SYMBOL(pci_reenable_device);EXPORT_SYMBOL(pci_enable_device_bars);EXPORT_SYMBOL(pci_enable_device);EXPORT_SYMBOL(pcim_enable_device);EXPORT_SYMBOL(pcim_pin_device);EXPORT_SYMBOL(pci_disable_device);EXPORT_SYMBOL(pci_find_capability);EXPORT_SYMBOL(pci_bus_find_capability);EXPORT_SYMBOL(pci_release_regions);EXPORT_SYMBOL(pci_request_regions);EXPORT_SYMBOL(pci_release_region);EXPORT_SYMBOL(pci_request_region);EXPORT_SYMBOL(pci_release_selected_regions);EXPORT_SYMBOL(pci_request_selected_regions);EXPORT_SYMBOL(pci_set_master);EXPORT_SYMBOL(pci_set_mwi);EXPORT_SYMBOL(pci_try_set_mwi);EXPORT_SYMBOL(pci_clear_mwi);EXPORT_SYMBOL_GPL(pci_intx);EXPORT_SYMBOL(pci_set_dma_mask);EXPORT_SYMBOL(pci_set_consistent_dma_mask);EXPORT_SYMBOL(pci_assign_resource);EXPORT_SYMBOL(pci_find_parent_resource);EXPORT_SYMBOL(pci_select_bars);EXPORT_SYMBOL(pci_set_power_state);EXPORT_SYMBOL(pci_save_state);EXPORT_SYMBOL(pci_restore_state);EXPORT_SYMBOL(pci_enable_wake);EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);

⌨️ 快捷键说明

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