#ifdef CONFIG_PCI_MSI /* * For MSI, show the first MSI IRQ; for all other cases including * MSI-X, show the legacy INTx IRQ.
*/ if (pdev->msi_enabled) return sysfs_emit(buf, "%u\n", pci_irq_vector(pdev, 0)); #endif
/* We read PCI_EXP_LNKCAP, so we need the device to be accessible. */
pci_config_pm_runtime_get(pdev);
ret = sysfs_emit(buf, "%u\n", pcie_get_width_cap(pdev));
pci_config_pm_runtime_put(pdev);
/* this can crash the machine when done on the "wrong" device */ if (!capable(CAP_SYS_ADMIN)) return -EPERM;
if (kstrtoul(buf, 0, &val) < 0) return -EINVAL;
device_lock(dev); if (dev->driver)
result = -EBUSY; elseif (val)
result = pci_enable_device(pdev); elseif (pci_is_enabled(pdev))
pci_disable_device(pdev); else
result = -EIO;
device_unlock(dev);
/* * "no_msi" and "bus_flags" only affect what happens when a driver * requests MSI or MSI-X. They don't affect any drivers that have * already requested MSI or MSI-X.
*/ if (!subordinate) {
pdev->no_msi = !val;
pci_info(pdev, "MSI/MSI-X %s for future drivers\n",
val ? "allowed" : "disallowed"); return count;
}
if (val)
subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI; else
subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
dev_info(&subordinate->dev, "MSI/MSI-X %s for future drivers of devices on this bus\n",
val ? "allowed" : "disallowed"); return count;
} static DEVICE_ATTR_RW(msi_bus);
/* * llseek operation for mmappable PCI resources. * May be left unused if the arch doesn't provide them.
*/ static __maybe_unused loff_t
pci_llseek_resource(struct file *filep, struct kobject *kobj __always_unused, conststruct bin_attribute *attr,
loff_t offset, int whence)
{ return fixed_size_llseek(filep, offset, whence, attr->size);
}
#ifdef HAVE_PCI_LEGACY /** * pci_read_legacy_io - read byte(s) from legacy I/O port space * @filp: open sysfs file * @kobj: kobject corresponding to file to read from * @bin_attr: struct bin_attribute for this file * @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).
*/ static ssize_t pci_read_legacy_io(struct file *filp, struct kobject *kobj, conststruct bin_attribute *bin_attr, char *buf, loff_t off, size_t count)
{ struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
/* Only support 1, 2 or 4 byte accesses */ if (count != 1 && count != 2 && count != 4) return -EINVAL;
/** * pci_write_legacy_io - write byte(s) to legacy I/O port space * @filp: open sysfs file * @kobj: kobject corresponding to file to read from * @bin_attr: struct bin_attribute for this file * @buf: buffer containing value to be written * @off: offset into legacy I/O port space * @count: number of bytes to write * * Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific * callback routine (pci_legacy_write).
*/ static ssize_t pci_write_legacy_io(struct file *filp, struct kobject *kobj, conststruct bin_attribute *bin_attr, char *buf, loff_t off, size_t count)
{ struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
/* Only support 1, 2 or 4 byte accesses */ if (count != 1 && count != 2 && count != 4) return -EINVAL;
/** * pci_mmap_legacy_mem - map legacy PCI memory into user memory space * @filp: open sysfs file * @kobj: kobject corresponding to device to be mapped * @attr: struct bin_attribute for this file * @vma: struct vm_area_struct passed to mmap * * Uses an arch specific callback, pci_mmap_legacy_mem_page_range, to mmap * legacy memory space (first meg of bus space) into application virtual * memory space.
*/ staticint pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj, conststruct bin_attribute *attr, struct vm_area_struct *vma)
{ struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
/** * pci_mmap_legacy_io - map legacy PCI IO into user memory space * @filp: open sysfs file * @kobj: kobject corresponding to device to be mapped * @attr: struct bin_attribute for this file * @vma: struct vm_area_struct passed to mmap * * Uses an arch specific callback, pci_mmap_legacy_io_page_range, to mmap * legacy IO space (first meg of bus space) into application virtual * memory space. Returns -ENOSYS if the operation isn't supported
*/ staticint pci_mmap_legacy_io(struct file *filp, struct kobject *kobj, conststruct bin_attribute *attr, struct vm_area_struct *vma)
{ struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
/** * pci_adjust_legacy_attr - adjustment of legacy file attributes * @b: bus to create files under * @mmap_type: I/O port or memory * * Stub implementation. Can be overridden by arch if necessary.
*/ void __weak pci_adjust_legacy_attr(struct pci_bus *b, enum pci_mmap_state mmap_type)
{
}
/** * pci_create_legacy_files - create legacy I/O port and memory files * @b: bus to create files under * * Some platforms allow access to legacy I/O port and ISA memory space on * a per-bus basis. This routine creates the files and ties them into * their associated read, write and mmap files from pci-sysfs.c * * On error unwind, but don't propagate the error to the caller * as it is ok to set up the PCI bus without these files.
*/ void pci_create_legacy_files(struct pci_bus *b)
{ int error;
if (!sysfs_initialized) return;
b->legacy_io = kcalloc(2, sizeof(struct bin_attribute),
GFP_ATOMIC); if (!b->legacy_io) goto kzalloc_err;
/* Allocated above after the legacy_io struct */
b->legacy_mem = b->legacy_io + 1;
sysfs_bin_attr_init(b->legacy_mem);
b->legacy_mem->attr.name = "legacy_mem";
b->legacy_mem->size = 1024*1024;
b->legacy_mem->attr.mode = 0600;
b->legacy_mem->mmap = pci_mmap_legacy_mem; /* See pci_create_attr() for motivation */
b->legacy_mem->llseek = pci_llseek_resource;
b->legacy_mem->f_mapping = iomem_get_mapping;
pci_adjust_legacy_attr(b, pci_mmap_mem);
error = device_create_bin_file(&b->dev, b->legacy_mem); if (error) goto legacy_mem_err;
return;
legacy_mem_err:
device_remove_bin_file(&b->dev, b->legacy_io);
legacy_io_err:
kfree(b->legacy_io);
b->legacy_io = NULL;
kzalloc_err:
dev_warn(&b->dev, "could not create legacy I/O port and ISA memory resources in sysfs\n");
}
void pci_remove_legacy_files(struct pci_bus *b)
{ if (b->legacy_io) {
device_remove_bin_file(&b->dev, b->legacy_io);
device_remove_bin_file(&b->dev, b->legacy_mem);
kfree(b->legacy_io); /* both are allocated here */
}
} #endif/* HAVE_PCI_LEGACY */
#ifdefined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE) /** * pci_mmap_resource - map a PCI resource into user memory space * @kobj: kobject for mapping * @attr: struct bin_attribute for the file being mapped * @vma: struct vm_area_struct passed into the mmap * @write_combine: 1 for write_combine mapping * * Use the regular PCI mapping routines to map a PCI resource into userspace.
*/ staticint pci_mmap_resource(struct kobject *kobj, conststruct bin_attribute *attr, struct vm_area_struct *vma, int write_combine)
{ struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); int bar = (unsignedlong)attr->private; enum pci_mmap_state mmap_type; struct resource *res = &pdev->resource[bar]; int ret;
ret = security_locked_down(LOCKDOWN_PCI_ACCESS); if (ret) return ret;
if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start)) return -EINVAL;
if (!pci_mmap_fits(pdev, bar, vma, PCI_MMAP_SYSFS)) return -EINVAL;
/** * pci_remove_resource_files - cleanup resource files * @pdev: dev to cleanup * * If we created resource files for @pdev, remove them from sysfs and * free their resources.
*/ staticvoid pci_remove_resource_files(struct pci_dev *pdev)
{ int i;
for (i = 0; i < PCI_STD_NUM_BARS; i++) { struct bin_attribute *res_attr;
res_attr = pdev->res_attr[i]; if (res_attr) {
sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
kfree(res_attr);
}
staticint pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
{ /* allocate attribute structure, piggyback attribute name */ int name_len = write_combine ? 13 : 10; struct bin_attribute *res_attr; char *res_attr_name; int retval;
res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC); if (!res_attr) return -ENOMEM;
res_attr_name = (char *)(res_attr + 1);
sysfs_bin_attr_init(res_attr); if (write_combine) {
sprintf(res_attr_name, "resource%d_wc", num);
res_attr->mmap = pci_mmap_resource_wc;
} else {
sprintf(res_attr_name, "resource%d", num); if (pci_resource_flags(pdev, num) & IORESOURCE_IO) {
res_attr->read = pci_read_resource_io;
res_attr->write = pci_write_resource_io; if (arch_can_pci_mmap_io())
res_attr->mmap = pci_mmap_resource_uc;
} else {
res_attr->mmap = pci_mmap_resource_uc;
}
} if (res_attr->mmap) {
res_attr->f_mapping = iomem_get_mapping; /* * generic_file_llseek() consults f_mapping->host to determine * the file size. As iomem_inode knows nothing about the * attribute, it's not going to work, so override it as well.
*/
res_attr->llseek = pci_llseek_resource;
}
res_attr->attr.name = res_attr_name;
res_attr->attr.mode = 0600;
res_attr->size = pci_resource_len(pdev, num);
res_attr->private = (void *)(unsignedlong)num;
retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); if (retval) {
kfree(res_attr); return retval;
}
if (write_combine)
pdev->res_attr_wc[num] = res_attr; else
pdev->res_attr[num] = res_attr;
return 0;
}
/** * pci_create_resource_files - create resource files in sysfs for @dev * @pdev: dev in question * * Walk the resources in @pdev creating files for each resource available.
*/ staticint pci_create_resource_files(struct pci_dev *pdev)
{ int i; int retval;
/* Skip devices with non-mappable BARs */ if (pdev->non_mappable_bars) return 0;
/* Expose the PCI resources from this device as files */ for (i = 0; i < PCI_STD_NUM_BARS; i++) {
/* skip empty resources */ if (!pci_resource_len(pdev, i)) continue;
retval = pci_create_attr(pdev, i, 0); /* for prefetchable resources, create a WC mappable file */ if (!retval && arch_can_pci_mmap_wc() &&
pdev->resource[i].flags & IORESOURCE_PREFETCH)
retval = pci_create_attr(pdev, i, 1); if (retval) {
pci_remove_resource_files(pdev); return retval;
}
} return 0;
} #else/* !(defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)) */ int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; } void __weak pci_remove_resource_files(struct pci_dev *dev) { return; } #endif
/** * pci_write_rom - used to enable access to the PCI ROM display * @filp: sysfs file * @kobj: kernel object handle * @bin_attr: struct bin_attribute for this file * @buf: user input * @off: file offset * @count: number of byte in input * * writing anything except 0 enables it
*/ static ssize_t pci_write_rom(struct file *filp, struct kobject *kobj, conststruct bin_attribute *bin_attr, char *buf,
loff_t off, size_t count)
{ struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
/** * pci_read_rom - read a PCI ROM * @filp: sysfs file * @kobj: kernel object handle * @bin_attr: struct bin_attribute for this file * @buf: where to put the data we read from the ROM * @off: file offset * @count: number of bytes to read * * Put @count bytes starting at @off into @buf from the ROM in the PCI * device corresponding to @kobj.
*/ static ssize_t pci_read_rom(struct file *filp, struct kobject *kobj, conststruct bin_attribute *bin_attr, char *buf,
loff_t off, size_t count)
{ struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); void __iomem *rom;
size_t size;
if (!pdev->rom_attr_enabled) return -EINVAL;
rom = pci_map_rom(pdev, &size); /* size starts out as PCI window size */ if (!rom || !size) return -EIO;
if (off >= size)
count = 0; else { if (off + count > size)
count = size - off;
memcpy_fromio(buf, rom + off, count);
}
pci_unmap_rom(pdev, rom);
int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev)
{ if (!sysfs_initialized) return -EACCES;
return pci_create_resource_files(pdev);
}
/** * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files * @pdev: device whose entries we should free * * Cleanup when @pdev is removed from sysfs.
*/ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
{ if (!sysfs_initialized) return;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.