pci-sysfs.c

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

C
715
字号
/* * drivers/pci/pci-sysfs.c * * (C) Copyright 2002-2004 Greg Kroah-Hartman <greg@kroah.com> * (C) Copyright 2002-2004 IBM Corp. * (C) Copyright 2003 Matthew Wilcox * (C) Copyright 2003 Hewlett-Packard * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com> * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com> * * File attributes for PCI devices * * Modeled after usb's driverfs.c  * */#include <linux/kernel.h>#include <linux/pci.h>#include <linux/stat.h>#include <linux/topology.h>#include <linux/mm.h>#include <linux/capability.h>#include "pci.h"static int sysfs_initialized;	/* = 0 *//* show configuration fields */#define pci_config_attr(field, format_string)				\static ssize_t								\field##_show(struct device *dev, struct device_attribute *attr, char *buf)				\{									\	struct pci_dev *pdev;						\									\	pdev = to_pci_dev (dev);					\	return sprintf (buf, format_string, pdev->field);		\}pci_config_attr(vendor, "0x%04x\n");pci_config_attr(device, "0x%04x\n");pci_config_attr(subsystem_vendor, "0x%04x\n");pci_config_attr(subsystem_device, "0x%04x\n");pci_config_attr(class, "0x%06x\n");pci_config_attr(irq, "%u\n");static ssize_t broken_parity_status_show(struct device *dev,					 struct device_attribute *attr,					 char *buf){	struct pci_dev *pdev = to_pci_dev(dev);	return sprintf (buf, "%u\n", pdev->broken_parity_status);}static ssize_t broken_parity_status_store(struct device *dev,					  struct device_attribute *attr,					  const char *buf, size_t count){	struct pci_dev *pdev = to_pci_dev(dev);	ssize_t consumed = -EINVAL;	if ((count > 0) && (*buf == '0' || *buf == '1')) {		pdev->broken_parity_status = *buf == '1' ? 1 : 0;		consumed = count;	}	return consumed;}static ssize_t local_cpus_show(struct device *dev,			struct device_attribute *attr, char *buf){			cpumask_t mask;	int len;	mask = pcibus_to_cpumask(to_pci_dev(dev)->bus);	len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask);	strcat(buf,"\n"); 	return 1+len;}/* show resources */static ssize_tresource_show(struct device * dev, struct device_attribute *attr, char * buf){	struct pci_dev * pci_dev = to_pci_dev(dev);	char * str = buf;	int i;	int max = 7;	resource_size_t start, end;	if (pci_dev->subordinate)		max = DEVICE_COUNT_RESOURCE;	for (i = 0; i < max; i++) {		struct resource *res =  &pci_dev->resource[i];		pci_resource_to_user(pci_dev, i, res, &start, &end);		str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n",			       (unsigned long long)start,			       (unsigned long long)end,			       (unsigned long long)res->flags);	}	return (str - buf);}static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf){	struct pci_dev *pci_dev = to_pci_dev(dev);	return sprintf(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n",		       pci_dev->vendor, pci_dev->device,		       pci_dev->subsystem_vendor, pci_dev->subsystem_device,		       (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8),		       (u8)(pci_dev->class));}static ssize_t is_enabled_store(struct device *dev,				struct device_attribute *attr, const char *buf,				size_t count){	ssize_t result = -EINVAL;	struct pci_dev *pdev = to_pci_dev(dev);	/* this can crash the machine when done on the "wrong" device */	if (!capable(CAP_SYS_ADMIN))		return count;	if (*buf == '0') {		if (atomic_read(&pdev->enable_cnt) != 0)			pci_disable_device(pdev);		else			result = -EIO;	} else if (*buf == '1')		result = pci_enable_device(pdev);	return result < 0 ? result : count;}static ssize_t is_enabled_show(struct device *dev,			       struct device_attribute *attr, char *buf){	struct pci_dev *pdev;	pdev = to_pci_dev (dev);	return sprintf (buf, "%u\n", atomic_read(&pdev->enable_cnt));}#ifdef CONFIG_NUMAstatic ssize_tnuma_node_show(struct device *dev, struct device_attribute *attr, char *buf){	return sprintf (buf, "%d\n", dev->numa_node);}#endifstatic ssize_tmsi_bus_show(struct device *dev, struct device_attribute *attr, char *buf){	struct pci_dev *pdev = to_pci_dev(dev);	if (!pdev->subordinate)		return 0;	return sprintf (buf, "%u\n",			!(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI));}static ssize_tmsi_bus_store(struct device *dev, struct device_attribute *attr,	      const char *buf, size_t count){	struct pci_dev *pdev = to_pci_dev(dev);	/* bad things may happen if the no_msi flag is changed	 * while some drivers are loaded */	if (!capable(CAP_SYS_ADMIN))		return count;	if (!pdev->subordinate)		return count;	if (*buf == '0') {		pdev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;		dev_warn(&pdev->dev, "forced subordinate bus to not support MSI,"			 " bad things could happen.\n");	}	if (*buf == '1') {		pdev->subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI;		dev_warn(&pdev->dev, "forced subordinate bus to support MSI,"			 " bad things could happen.\n");	}	return count;}struct device_attribute pci_dev_attrs[] = {	__ATTR_RO(resource),	__ATTR_RO(vendor),	__ATTR_RO(device),	__ATTR_RO(subsystem_vendor),	__ATTR_RO(subsystem_device),	__ATTR_RO(class),	__ATTR_RO(irq),	__ATTR_RO(local_cpus),	__ATTR_RO(modalias),#ifdef CONFIG_NUMA	__ATTR_RO(numa_node),#endif	__ATTR(enable, 0600, is_enabled_show, is_enabled_store),	__ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),		broken_parity_status_show,broken_parity_status_store),	__ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store),	__ATTR_NULL,};static ssize_tpci_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,		char *buf, loff_t off, size_t count){	struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));	unsigned int size = 64;	loff_t init_off = off;	u8 *data = (u8*) buf;	/* Several chips lock up trying to read undefined config space */	if (capable(CAP_SYS_ADMIN)) {		size = dev->cfg_size;	} else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {		size = 128;	}	if (off > size)		return 0;	if (off + count > size) {		size -= off;		count = size;	} else {		size = count;	}	if ((off & 1) && size) {		u8 val;		pci_user_read_config_byte(dev, off, &val);		data[off - init_off] = val;		off++;		size--;	}	if ((off & 3) && size > 2) {		u16 val;		pci_user_read_config_word(dev, off, &val);		data[off - init_off] = val & 0xff;		data[off - init_off + 1] = (val >> 8) & 0xff;		off += 2;		size -= 2;	}	while (size > 3) {		u32 val;		pci_user_read_config_dword(dev, off, &val);		data[off - init_off] = val & 0xff;		data[off - init_off + 1] = (val >> 8) & 0xff;		data[off - init_off + 2] = (val >> 16) & 0xff;		data[off - init_off + 3] = (val >> 24) & 0xff;		off += 4;		size -= 4;	}	if (size >= 2) {		u16 val;		pci_user_read_config_word(dev, off, &val);		data[off - init_off] = val & 0xff;		data[off - init_off + 1] = (val >> 8) & 0xff;		off += 2;		size -= 2;	}	if (size > 0) {		u8 val;		pci_user_read_config_byte(dev, off, &val);		data[off - init_off] = val;		off++;		--size;	}	return count;}static ssize_tpci_write_config(struct kobject *kobj, struct bin_attribute *bin_attr,		 char *buf, loff_t off, size_t count){	struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));	unsigned int size = count;	loff_t init_off = off;	u8 *data = (u8*) buf;	if (off > dev->cfg_size)		return 0;	if (off + count > dev->cfg_size) {		size = dev->cfg_size - off;		count = size;	}		if ((off & 1) && size) {		pci_user_write_config_byte(dev, off, data[off - init_off]);		off++;		size--;	}		if ((off & 3) && size > 2) {		u16 val = data[off - init_off];		val |= (u16) data[off - init_off + 1] << 8;                pci_user_write_config_word(dev, off, val);                off += 2;                size -= 2;        }	while (size > 3) {		u32 val = data[off - init_off];		val |= (u32) data[off - init_off + 1] << 8;		val |= (u32) data[off - init_off + 2] << 16;		val |= (u32) data[off - init_off + 3] << 24;		pci_user_write_config_dword(dev, off, val);		off += 4;		size -= 4;	}		if (size >= 2) {		u16 val = data[off - init_off];		val |= (u16) data[off - init_off + 1] << 8;		pci_user_write_config_word(dev, off, val);		off += 2;		size -= 2;	}	if (size) {		pci_user_write_config_byte(dev, off, data[off - init_off]);		off++;		--size;	}	return count;}#ifdef HAVE_PCI_LEGACY/** * pci_read_legacy_io - read byte(s) from legacy I/O port space * @kobj: kobject corresponding to file to read from * @buf: buffer to store results * @off: offset into legacy I/O port space * @count: number of bytes to read * * Reads 1, 2, or 4 bytes from legacy I/O port space using an arch specific * callback routine (pci_legacy_read). */ssize_tpci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,		   char *buf, loff_t off, size_t count)

⌨️ 快捷键说明

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