473 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Procfs interface for the PCI bus4 *5 * Copyright (c) 1997--1999 Martin Mares <mj@ucw.cz>6 */7 8#include <linux/init.h>9#include <linux/pci.h>10#include <linux/slab.h>11#include <linux/module.h>12#include <linux/proc_fs.h>13#include <linux/seq_file.h>14#include <linux/capability.h>15#include <linux/uaccess.h>16#include <linux/security.h>17#include <asm/byteorder.h>18#include "pci.h"19 20static int proc_initialized; /* = 0 */21 22static loff_t proc_bus_pci_lseek(struct file *file, loff_t off, int whence)23{24 struct pci_dev *dev = pde_data(file_inode(file));25 return fixed_size_llseek(file, off, whence, dev->cfg_size);26}27 28static ssize_t proc_bus_pci_read(struct file *file, char __user *buf,29 size_t nbytes, loff_t *ppos)30{31 struct pci_dev *dev = pde_data(file_inode(file));32 unsigned int pos = *ppos;33 unsigned int cnt, size;34 35 /*36 * Normal users can read only the standardized portion of the37 * configuration space as several chips lock up when trying to read38 * undefined locations (think of Intel PIIX4 as a typical example).39 */40 41 if (capable(CAP_SYS_ADMIN))42 size = dev->cfg_size;43 else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)44 size = 128;45 else46 size = 64;47 48 if (pos >= size)49 return 0;50 if (nbytes >= size)51 nbytes = size;52 if (pos + nbytes > size)53 nbytes = size - pos;54 cnt = nbytes;55 56 if (!access_ok(buf, cnt))57 return -EINVAL;58 59 pci_config_pm_runtime_get(dev);60 61 if ((pos & 1) && cnt) {62 unsigned char val;63 pci_user_read_config_byte(dev, pos, &val);64 __put_user(val, buf);65 buf++;66 pos++;67 cnt--;68 }69 70 if ((pos & 3) && cnt > 2) {71 unsigned short val;72 pci_user_read_config_word(dev, pos, &val);73 __put_user(cpu_to_le16(val), (__le16 __user *) buf);74 buf += 2;75 pos += 2;76 cnt -= 2;77 }78 79 while (cnt >= 4) {80 unsigned int val;81 pci_user_read_config_dword(dev, pos, &val);82 __put_user(cpu_to_le32(val), (__le32 __user *) buf);83 buf += 4;84 pos += 4;85 cnt -= 4;86 cond_resched();87 }88 89 if (cnt >= 2) {90 unsigned short val;91 pci_user_read_config_word(dev, pos, &val);92 __put_user(cpu_to_le16(val), (__le16 __user *) buf);93 buf += 2;94 pos += 2;95 cnt -= 2;96 }97 98 if (cnt) {99 unsigned char val;100 pci_user_read_config_byte(dev, pos, &val);101 __put_user(val, buf);102 pos++;103 }104 105 pci_config_pm_runtime_put(dev);106 107 *ppos = pos;108 return nbytes;109}110 111static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,112 size_t nbytes, loff_t *ppos)113{114 struct inode *ino = file_inode(file);115 struct pci_dev *dev = pde_data(ino);116 int pos = *ppos;117 int size = dev->cfg_size;118 int cnt, ret;119 120 ret = security_locked_down(LOCKDOWN_PCI_ACCESS);121 if (ret)122 return ret;123 124 if (pos >= size)125 return 0;126 if (nbytes >= size)127 nbytes = size;128 if (pos + nbytes > size)129 nbytes = size - pos;130 cnt = nbytes;131 132 if (!access_ok(buf, cnt))133 return -EINVAL;134 135 pci_config_pm_runtime_get(dev);136 137 if ((pos & 1) && cnt) {138 unsigned char val;139 __get_user(val, buf);140 pci_user_write_config_byte(dev, pos, val);141 buf++;142 pos++;143 cnt--;144 }145 146 if ((pos & 3) && cnt > 2) {147 __le16 val;148 __get_user(val, (__le16 __user *) buf);149 pci_user_write_config_word(dev, pos, le16_to_cpu(val));150 buf += 2;151 pos += 2;152 cnt -= 2;153 }154 155 while (cnt >= 4) {156 __le32 val;157 __get_user(val, (__le32 __user *) buf);158 pci_user_write_config_dword(dev, pos, le32_to_cpu(val));159 buf += 4;160 pos += 4;161 cnt -= 4;162 }163 164 if (cnt >= 2) {165 __le16 val;166 __get_user(val, (__le16 __user *) buf);167 pci_user_write_config_word(dev, pos, le16_to_cpu(val));168 buf += 2;169 pos += 2;170 cnt -= 2;171 }172 173 if (cnt) {174 unsigned char val;175 __get_user(val, buf);176 pci_user_write_config_byte(dev, pos, val);177 pos++;178 }179 180 pci_config_pm_runtime_put(dev);181 182 *ppos = pos;183 i_size_write(ino, dev->cfg_size);184 return nbytes;185}186 187#ifdef HAVE_PCI_MMAP188struct pci_filp_private {189 enum pci_mmap_state mmap_state;190 int write_combine;191};192#endif /* HAVE_PCI_MMAP */193 194static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,195 unsigned long arg)196{197 struct pci_dev *dev = pde_data(file_inode(file));198#ifdef HAVE_PCI_MMAP199 struct pci_filp_private *fpriv = file->private_data;200#endif /* HAVE_PCI_MMAP */201 int ret = 0;202 203 ret = security_locked_down(LOCKDOWN_PCI_ACCESS);204 if (ret)205 return ret;206 207 switch (cmd) {208 case PCIIOC_CONTROLLER:209 ret = pci_domain_nr(dev->bus);210 break;211 212#ifdef HAVE_PCI_MMAP213 case PCIIOC_MMAP_IS_IO:214 if (!arch_can_pci_mmap_io())215 return -EINVAL;216 fpriv->mmap_state = pci_mmap_io;217 break;218 219 case PCIIOC_MMAP_IS_MEM:220 fpriv->mmap_state = pci_mmap_mem;221 break;222 223 case PCIIOC_WRITE_COMBINE:224 if (arch_can_pci_mmap_wc()) {225 if (arg)226 fpriv->write_combine = 1;227 else228 fpriv->write_combine = 0;229 break;230 }231 /* If arch decided it can't, fall through... */232 fallthrough;233#endif /* HAVE_PCI_MMAP */234 default:235 ret = -EINVAL;236 break;237 }238 239 return ret;240}241 242#ifdef HAVE_PCI_MMAP243static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)244{245 struct pci_dev *dev = pde_data(file_inode(file));246 struct pci_filp_private *fpriv = file->private_data;247 resource_size_t start, end;248 int i, ret, write_combine = 0, res_bit = IORESOURCE_MEM;249 250 if (!capable(CAP_SYS_RAWIO) ||251 security_locked_down(LOCKDOWN_PCI_ACCESS))252 return -EPERM;253 254 if (fpriv->mmap_state == pci_mmap_io) {255 if (!arch_can_pci_mmap_io())256 return -EINVAL;257 res_bit = IORESOURCE_IO;258 }259 260 /* Make sure the caller is mapping a real resource for this device */261 for (i = 0; i < PCI_STD_NUM_BARS; i++) {262 if (dev->resource[i].flags & res_bit &&263 pci_mmap_fits(dev, i, vma, PCI_MMAP_PROCFS))264 break;265 }266 267 if (i >= PCI_STD_NUM_BARS)268 return -ENODEV;269 270 if (fpriv->mmap_state == pci_mmap_mem &&271 fpriv->write_combine) {272 if (dev->resource[i].flags & IORESOURCE_PREFETCH)273 write_combine = 1;274 else275 return -EINVAL;276 }277 278 if (dev->resource[i].flags & IORESOURCE_MEM &&279 iomem_is_exclusive(dev->resource[i].start))280 return -EINVAL;281 282 pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);283 284 /* Adjust vm_pgoff to be the offset within the resource */285 vma->vm_pgoff -= start >> PAGE_SHIFT;286 ret = pci_mmap_resource_range(dev, i, vma,287 fpriv->mmap_state, write_combine);288 if (ret < 0)289 return ret;290 291 return 0;292}293 294static int proc_bus_pci_open(struct inode *inode, struct file *file)295{296 struct pci_filp_private *fpriv = kmalloc(sizeof(*fpriv), GFP_KERNEL);297 298 if (!fpriv)299 return -ENOMEM;300 301 fpriv->mmap_state = pci_mmap_io;302 fpriv->write_combine = 0;303 304 file->private_data = fpriv;305 file->f_mapping = iomem_get_mapping();306 307 return 0;308}309 310static int proc_bus_pci_release(struct inode *inode, struct file *file)311{312 kfree(file->private_data);313 file->private_data = NULL;314 315 return 0;316}317#endif /* HAVE_PCI_MMAP */318 319static const struct proc_ops proc_bus_pci_ops = {320 .proc_lseek = proc_bus_pci_lseek,321 .proc_read = proc_bus_pci_read,322 .proc_write = proc_bus_pci_write,323 .proc_ioctl = proc_bus_pci_ioctl,324#ifdef CONFIG_COMPAT325 .proc_compat_ioctl = proc_bus_pci_ioctl,326#endif327#ifdef HAVE_PCI_MMAP328 .proc_open = proc_bus_pci_open,329 .proc_release = proc_bus_pci_release,330 .proc_mmap = proc_bus_pci_mmap,331#ifdef HAVE_ARCH_PCI_GET_UNMAPPED_AREA332 .proc_get_unmapped_area = get_pci_unmapped_area,333#endif /* HAVE_ARCH_PCI_GET_UNMAPPED_AREA */334#endif /* HAVE_PCI_MMAP */335};336 337/* iterator */338static void *pci_seq_start(struct seq_file *m, loff_t *pos)339{340 struct pci_dev *dev = NULL;341 loff_t n = *pos;342 343 for_each_pci_dev(dev) {344 if (!n--)345 break;346 }347 return dev;348}349 350static void *pci_seq_next(struct seq_file *m, void *v, loff_t *pos)351{352 struct pci_dev *dev = v;353 354 (*pos)++;355 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);356 return dev;357}358 359static void pci_seq_stop(struct seq_file *m, void *v)360{361 if (v) {362 struct pci_dev *dev = v;363 pci_dev_put(dev);364 }365}366 367static int show_device(struct seq_file *m, void *v)368{369 const struct pci_dev *dev = v;370 const struct pci_driver *drv;371 int i;372 373 if (dev == NULL)374 return 0;375 376 drv = pci_dev_driver(dev);377 seq_printf(m, "%02x%02x\t%04x%04x\t%x",378 dev->bus->number,379 dev->devfn,380 dev->vendor,381 dev->device,382 dev->irq);383 384 /* only print standard and ROM resources to preserve compatibility */385 for (i = 0; i <= PCI_ROM_RESOURCE; i++) {386 resource_size_t start, end;387 pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);388 seq_printf(m, "\t%16llx",389 (unsigned long long)(start |390 (dev->resource[i].flags & PCI_REGION_FLAG_MASK)));391 }392 for (i = 0; i <= PCI_ROM_RESOURCE; i++) {393 resource_size_t start, end;394 pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);395 seq_printf(m, "\t%16llx",396 dev->resource[i].start < dev->resource[i].end ?397 (unsigned long long)(end - start) + 1 : 0);398 }399 seq_putc(m, '\t');400 if (drv)401 seq_puts(m, drv->name);402 seq_putc(m, '\n');403 return 0;404}405 406static const struct seq_operations proc_bus_pci_devices_op = {407 .start = pci_seq_start,408 .next = pci_seq_next,409 .stop = pci_seq_stop,410 .show = show_device411};412 413static struct proc_dir_entry *proc_bus_pci_dir;414 415int pci_proc_attach_device(struct pci_dev *dev)416{417 struct pci_bus *bus = dev->bus;418 struct proc_dir_entry *e;419 char name[16];420 421 if (!proc_initialized)422 return -EACCES;423 424 if (!bus->procdir) {425 if (pci_proc_domain(bus)) {426 sprintf(name, "%04x:%02x", pci_domain_nr(bus),427 bus->number);428 } else {429 sprintf(name, "%02x", bus->number);430 }431 bus->procdir = proc_mkdir(name, proc_bus_pci_dir);432 if (!bus->procdir)433 return -ENOMEM;434 }435 436 sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));437 e = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir,438 &proc_bus_pci_ops, dev);439 if (!e)440 return -ENOMEM;441 proc_set_size(e, dev->cfg_size);442 dev->procent = e;443 444 return 0;445}446 447int pci_proc_detach_device(struct pci_dev *dev)448{449 proc_remove(dev->procent);450 dev->procent = NULL;451 return 0;452}453 454int pci_proc_detach_bus(struct pci_bus *bus)455{456 proc_remove(bus->procdir);457 return 0;458}459 460static int __init pci_proc_init(void)461{462 struct pci_dev *dev = NULL;463 proc_bus_pci_dir = proc_mkdir("bus/pci", NULL);464 proc_create_seq("devices", 0, proc_bus_pci_dir,465 &proc_bus_pci_devices_op);466 proc_initialized = 1;467 for_each_pci_dev(dev)468 pci_proc_attach_device(dev);469 470 return 0;471}472device_initcall(pci_proc_init);473