brintos

brintos / linux-shallow public Read only

0
0
Text · 9.9 KiB · f967709 Raw
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