xref: /linux/arch/alpha/kernel/pci-sysfs.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
210a0ef39SIvan Kokshaysky /*
310a0ef39SIvan Kokshaysky  * arch/alpha/kernel/pci-sysfs.c
410a0ef39SIvan Kokshaysky  *
510a0ef39SIvan Kokshaysky  * Copyright (C) 2009 Ivan Kokshaysky
610a0ef39SIvan Kokshaysky  *
710a0ef39SIvan Kokshaysky  * Alpha PCI resource files.
810a0ef39SIvan Kokshaysky  *
910a0ef39SIvan Kokshaysky  * Loosely based on generic HAVE_PCI_MMAP implementation in
1010a0ef39SIvan Kokshaysky  * drivers/pci/pci-sysfs.c
1110a0ef39SIvan Kokshaysky  */
1210a0ef39SIvan Kokshaysky 
1310a0ef39SIvan Kokshaysky #include <linux/sched.h>
14ce7cf073SPaul Gortmaker #include <linux/stat.h>
155a0e3ad6STejun Heo #include <linux/slab.h>
1610a0ef39SIvan Kokshaysky #include <linux/pci.h>
1710a0ef39SIvan Kokshaysky 
hose_mmap_page_range(struct pci_controller * hose,struct vm_area_struct * vma,enum pci_mmap_state mmap_type,int sparse)1810a0ef39SIvan Kokshaysky static int hose_mmap_page_range(struct pci_controller *hose,
1910a0ef39SIvan Kokshaysky 				struct vm_area_struct *vma,
2010a0ef39SIvan Kokshaysky 				enum pci_mmap_state mmap_type, int sparse)
2110a0ef39SIvan Kokshaysky {
2210a0ef39SIvan Kokshaysky 	unsigned long base;
2310a0ef39SIvan Kokshaysky 
2410a0ef39SIvan Kokshaysky 	if (mmap_type == pci_mmap_mem)
2510a0ef39SIvan Kokshaysky 		base = sparse ? hose->sparse_mem_base : hose->dense_mem_base;
2610a0ef39SIvan Kokshaysky 	else
2710a0ef39SIvan Kokshaysky 		base = sparse ? hose->sparse_io_base : hose->dense_io_base;
2810a0ef39SIvan Kokshaysky 
2910a0ef39SIvan Kokshaysky 	vma->vm_pgoff += base >> PAGE_SHIFT;
3010a0ef39SIvan Kokshaysky 
3110a0ef39SIvan Kokshaysky 	return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
3210a0ef39SIvan Kokshaysky 				  vma->vm_end - vma->vm_start,
3310a0ef39SIvan Kokshaysky 				  vma->vm_page_prot);
3410a0ef39SIvan Kokshaysky }
3510a0ef39SIvan Kokshaysky 
__pci_mmap_fits(struct pci_dev * pdev,int num,struct vm_area_struct * vma,int sparse)3610a0ef39SIvan Kokshaysky static int __pci_mmap_fits(struct pci_dev *pdev, int num,
3710a0ef39SIvan Kokshaysky 			   struct vm_area_struct *vma, int sparse)
3810a0ef39SIvan Kokshaysky {
3910a0ef39SIvan Kokshaysky 	unsigned long nr, start, size;
4010a0ef39SIvan Kokshaysky 	int shift = sparse ? 5 : 0;
4110a0ef39SIvan Kokshaysky 
42236d62b0SShyam Saini 	nr = vma_pages(vma);
4310a0ef39SIvan Kokshaysky 	start = vma->vm_pgoff;
4410a0ef39SIvan Kokshaysky 	size = ((pci_resource_len(pdev, num) - 1) >> (PAGE_SHIFT - shift)) + 1;
4510a0ef39SIvan Kokshaysky 
4610a0ef39SIvan Kokshaysky 	if (start < size && size - start >= nr)
4710a0ef39SIvan Kokshaysky 		return 1;
4810a0ef39SIvan Kokshaysky 	WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on %s BAR %d "
4910a0ef39SIvan Kokshaysky 		"(size 0x%08lx)\n",
5010a0ef39SIvan Kokshaysky 		current->comm, sparse ? " sparse" : "", start, start + nr,
5110a0ef39SIvan Kokshaysky 		pci_name(pdev), num, size);
5210a0ef39SIvan Kokshaysky 	return 0;
5310a0ef39SIvan Kokshaysky }
5410a0ef39SIvan Kokshaysky 
5510a0ef39SIvan Kokshaysky /**
5610a0ef39SIvan Kokshaysky  * pci_mmap_resource - map a PCI resource into user memory space
5710a0ef39SIvan Kokshaysky  * @kobj: kobject for mapping
5810a0ef39SIvan Kokshaysky  * @attr: struct bin_attribute for the file being mapped
5910a0ef39SIvan Kokshaysky  * @vma: struct vm_area_struct passed into the mmap
6010a0ef39SIvan Kokshaysky  * @sparse: address space type
6110a0ef39SIvan Kokshaysky  *
6210a0ef39SIvan Kokshaysky  * Use the bus mapping routines to map a PCI resource into userspace.
63*0a9d991cSRandy Dunlap  *
64*0a9d991cSRandy Dunlap  * Return: %0 on success, negative error code otherwise
6510a0ef39SIvan Kokshaysky  */
pci_mmap_resource(struct kobject * kobj,struct bin_attribute * attr,struct vm_area_struct * vma,int sparse)665efa16ffSMatt Turner static int pci_mmap_resource(struct kobject *kobj,
672c3c8beaSChris Wright 			     struct bin_attribute *attr,
6810a0ef39SIvan Kokshaysky 			     struct vm_area_struct *vma, int sparse)
6910a0ef39SIvan Kokshaysky {
708c9b839cSGeliang Tang 	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
71af96f8a3Smatt mooney 	struct resource *res = attr->private;
7210a0ef39SIvan Kokshaysky 	enum pci_mmap_state mmap_type;
7310a0ef39SIvan Kokshaysky 	struct pci_bus_region bar;
7410a0ef39SIvan Kokshaysky 	int i;
7510a0ef39SIvan Kokshaysky 
76c9c13ba4SDenis Efremov 	for (i = 0; i < PCI_STD_NUM_BARS; i++)
7710a0ef39SIvan Kokshaysky 		if (res == &pdev->resource[i])
7810a0ef39SIvan Kokshaysky 			break;
79c9c13ba4SDenis Efremov 	if (i >= PCI_STD_NUM_BARS)
8010a0ef39SIvan Kokshaysky 		return -ENODEV;
8110a0ef39SIvan Kokshaysky 
82c20e1280SBjorn Helgaas 	if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start))
8310a0ef39SIvan Kokshaysky 		return -EINVAL;
8410a0ef39SIvan Kokshaysky 
85c20e1280SBjorn Helgaas 	if (!__pci_mmap_fits(pdev, i, vma, sparse))
8610a0ef39SIvan Kokshaysky 		return -EINVAL;
8710a0ef39SIvan Kokshaysky 
88fc279850SYinghai Lu 	pcibios_resource_to_bus(pdev->bus, &bar, res);
8910a0ef39SIvan Kokshaysky 	vma->vm_pgoff += bar.start >> (PAGE_SHIFT - (sparse ? 5 : 0));
9010a0ef39SIvan Kokshaysky 	mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
9110a0ef39SIvan Kokshaysky 
9210a0ef39SIvan Kokshaysky 	return hose_mmap_page_range(pdev->sysdata, vma, mmap_type, sparse);
9310a0ef39SIvan Kokshaysky }
9410a0ef39SIvan Kokshaysky 
pci_mmap_resource_sparse(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,struct vm_area_struct * vma)952c3c8beaSChris Wright static int pci_mmap_resource_sparse(struct file *filp, struct kobject *kobj,
9610a0ef39SIvan Kokshaysky 				    struct bin_attribute *attr,
9710a0ef39SIvan Kokshaysky 				    struct vm_area_struct *vma)
9810a0ef39SIvan Kokshaysky {
9910a0ef39SIvan Kokshaysky 	return pci_mmap_resource(kobj, attr, vma, 1);
10010a0ef39SIvan Kokshaysky }
10110a0ef39SIvan Kokshaysky 
pci_mmap_resource_dense(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,struct vm_area_struct * vma)1022c3c8beaSChris Wright static int pci_mmap_resource_dense(struct file *filp, struct kobject *kobj,
10310a0ef39SIvan Kokshaysky 				   struct bin_attribute *attr,
10410a0ef39SIvan Kokshaysky 				   struct vm_area_struct *vma)
10510a0ef39SIvan Kokshaysky {
10610a0ef39SIvan Kokshaysky 	return pci_mmap_resource(kobj, attr, vma, 0);
10710a0ef39SIvan Kokshaysky }
10810a0ef39SIvan Kokshaysky 
10910a0ef39SIvan Kokshaysky /**
11010a0ef39SIvan Kokshaysky  * pci_remove_resource_files - cleanup resource files
111*0a9d991cSRandy Dunlap  * @pdev: pci_dev to cleanup
11210a0ef39SIvan Kokshaysky  *
11310a0ef39SIvan Kokshaysky  * If we created resource files for @dev, remove them from sysfs and
11410a0ef39SIvan Kokshaysky  * free their resources.
11510a0ef39SIvan Kokshaysky  */
pci_remove_resource_files(struct pci_dev * pdev)11610a0ef39SIvan Kokshaysky void pci_remove_resource_files(struct pci_dev *pdev)
11710a0ef39SIvan Kokshaysky {
11810a0ef39SIvan Kokshaysky 	int i;
11910a0ef39SIvan Kokshaysky 
120c9c13ba4SDenis Efremov 	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
12110a0ef39SIvan Kokshaysky 		struct bin_attribute *res_attr;
12210a0ef39SIvan Kokshaysky 
12310a0ef39SIvan Kokshaysky 		res_attr = pdev->res_attr[i];
12410a0ef39SIvan Kokshaysky 		if (res_attr) {
12510a0ef39SIvan Kokshaysky 			sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
12610a0ef39SIvan Kokshaysky 			kfree(res_attr);
12710a0ef39SIvan Kokshaysky 		}
12810a0ef39SIvan Kokshaysky 
12910a0ef39SIvan Kokshaysky 		res_attr = pdev->res_attr_wc[i];
13010a0ef39SIvan Kokshaysky 		if (res_attr) {
13110a0ef39SIvan Kokshaysky 			sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
13210a0ef39SIvan Kokshaysky 			kfree(res_attr);
13310a0ef39SIvan Kokshaysky 		}
13410a0ef39SIvan Kokshaysky 	}
13510a0ef39SIvan Kokshaysky }
13610a0ef39SIvan Kokshaysky 
sparse_mem_mmap_fits(struct pci_dev * pdev,int num)13710a0ef39SIvan Kokshaysky static int sparse_mem_mmap_fits(struct pci_dev *pdev, int num)
13810a0ef39SIvan Kokshaysky {
13910a0ef39SIvan Kokshaysky 	struct pci_bus_region bar;
14010a0ef39SIvan Kokshaysky 	struct pci_controller *hose = pdev->sysdata;
14110a0ef39SIvan Kokshaysky 	long dense_offset;
14210a0ef39SIvan Kokshaysky 	unsigned long sparse_size;
14310a0ef39SIvan Kokshaysky 
144fc279850SYinghai Lu 	pcibios_resource_to_bus(pdev->bus, &bar, &pdev->resource[num]);
14510a0ef39SIvan Kokshaysky 
14610a0ef39SIvan Kokshaysky 	/* All core logic chips have 4G sparse address space, except
14710a0ef39SIvan Kokshaysky 	   CIA which has 16G (see xxx_SPARSE_MEM and xxx_DENSE_MEM
14810a0ef39SIvan Kokshaysky 	   definitions in asm/core_xxx.h files). This corresponds
14910a0ef39SIvan Kokshaysky 	   to 128M or 512M of the bus space. */
15010a0ef39SIvan Kokshaysky 	dense_offset = (long)(hose->dense_mem_base - hose->sparse_mem_base);
15110a0ef39SIvan Kokshaysky 	sparse_size = dense_offset >= 0x400000000UL ? 0x20000000 : 0x8000000;
15210a0ef39SIvan Kokshaysky 
15310a0ef39SIvan Kokshaysky 	return bar.end < sparse_size;
15410a0ef39SIvan Kokshaysky }
15510a0ef39SIvan Kokshaysky 
pci_create_one_attr(struct pci_dev * pdev,int num,char * name,char * suffix,struct bin_attribute * res_attr,unsigned long sparse)15610a0ef39SIvan Kokshaysky static int pci_create_one_attr(struct pci_dev *pdev, int num, char *name,
15710a0ef39SIvan Kokshaysky 			       char *suffix, struct bin_attribute *res_attr,
15810a0ef39SIvan Kokshaysky 			       unsigned long sparse)
15910a0ef39SIvan Kokshaysky {
16010a0ef39SIvan Kokshaysky 	size_t size = pci_resource_len(pdev, num);
16110a0ef39SIvan Kokshaysky 
16210a0ef39SIvan Kokshaysky 	sprintf(name, "resource%d%s", num, suffix);
16310a0ef39SIvan Kokshaysky 	res_attr->mmap = sparse ? pci_mmap_resource_sparse :
16410a0ef39SIvan Kokshaysky 				  pci_mmap_resource_dense;
16510a0ef39SIvan Kokshaysky 	res_attr->attr.name = name;
16610a0ef39SIvan Kokshaysky 	res_attr->attr.mode = S_IRUSR | S_IWUSR;
16710a0ef39SIvan Kokshaysky 	res_attr->size = sparse ? size << 5 : size;
16810a0ef39SIvan Kokshaysky 	res_attr->private = &pdev->resource[num];
16910a0ef39SIvan Kokshaysky 	return sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
17010a0ef39SIvan Kokshaysky }
17110a0ef39SIvan Kokshaysky 
pci_create_attr(struct pci_dev * pdev,int num)17210a0ef39SIvan Kokshaysky static int pci_create_attr(struct pci_dev *pdev, int num)
17310a0ef39SIvan Kokshaysky {
17410a0ef39SIvan Kokshaysky 	/* allocate attribute structure, piggyback attribute name */
17510a0ef39SIvan Kokshaysky 	int retval, nlen1, nlen2 = 0, res_count = 1;
17610a0ef39SIvan Kokshaysky 	unsigned long sparse_base, dense_base;
17710a0ef39SIvan Kokshaysky 	struct bin_attribute *attr;
17810a0ef39SIvan Kokshaysky 	struct pci_controller *hose = pdev->sysdata;
17910a0ef39SIvan Kokshaysky 	char *suffix, *attr_name;
18010a0ef39SIvan Kokshaysky 
18110a0ef39SIvan Kokshaysky 	suffix = "";	/* Assume bwx machine, normal resourceN files. */
18210a0ef39SIvan Kokshaysky 	nlen1 = 10;
18310a0ef39SIvan Kokshaysky 
18410a0ef39SIvan Kokshaysky 	if (pdev->resource[num].flags & IORESOURCE_MEM) {
18510a0ef39SIvan Kokshaysky 		sparse_base = hose->sparse_mem_base;
18610a0ef39SIvan Kokshaysky 		dense_base = hose->dense_mem_base;
18710a0ef39SIvan Kokshaysky 		if (sparse_base && !sparse_mem_mmap_fits(pdev, num)) {
18810a0ef39SIvan Kokshaysky 			sparse_base = 0;
18910a0ef39SIvan Kokshaysky 			suffix = "_dense";
19010a0ef39SIvan Kokshaysky 			nlen1 = 16;	/* resourceN_dense */
19110a0ef39SIvan Kokshaysky 		}
19210a0ef39SIvan Kokshaysky 	} else {
19310a0ef39SIvan Kokshaysky 		sparse_base = hose->sparse_io_base;
19410a0ef39SIvan Kokshaysky 		dense_base = hose->dense_io_base;
19510a0ef39SIvan Kokshaysky 	}
19610a0ef39SIvan Kokshaysky 
19710a0ef39SIvan Kokshaysky 	if (sparse_base) {
19810a0ef39SIvan Kokshaysky 		suffix = "_sparse";
19910a0ef39SIvan Kokshaysky 		nlen1 = 17;
20010a0ef39SIvan Kokshaysky 		if (dense_base) {
20110a0ef39SIvan Kokshaysky 			nlen2 = 16;	/* resourceN_dense */
20210a0ef39SIvan Kokshaysky 			res_count = 2;
20310a0ef39SIvan Kokshaysky 		}
20410a0ef39SIvan Kokshaysky 	}
20510a0ef39SIvan Kokshaysky 
20610a0ef39SIvan Kokshaysky 	attr = kzalloc(sizeof(*attr) * res_count + nlen1 + nlen2, GFP_ATOMIC);
20710a0ef39SIvan Kokshaysky 	if (!attr)
20810a0ef39SIvan Kokshaysky 		return -ENOMEM;
20910a0ef39SIvan Kokshaysky 
21010a0ef39SIvan Kokshaysky 	/* Create bwx, sparse or single dense file */
21110a0ef39SIvan Kokshaysky 	attr_name = (char *)(attr + res_count);
21210a0ef39SIvan Kokshaysky 	pdev->res_attr[num] = attr;
21310a0ef39SIvan Kokshaysky 	retval = pci_create_one_attr(pdev, num, attr_name, suffix, attr,
21410a0ef39SIvan Kokshaysky 				     sparse_base);
21510a0ef39SIvan Kokshaysky 	if (retval || res_count == 1)
21610a0ef39SIvan Kokshaysky 		return retval;
21710a0ef39SIvan Kokshaysky 
21810a0ef39SIvan Kokshaysky 	/* Create dense file */
21910a0ef39SIvan Kokshaysky 	attr_name += nlen1;
22010a0ef39SIvan Kokshaysky 	attr++;
22110a0ef39SIvan Kokshaysky 	pdev->res_attr_wc[num] = attr;
22210a0ef39SIvan Kokshaysky 	return pci_create_one_attr(pdev, num, attr_name, "_dense", attr, 0);
22310a0ef39SIvan Kokshaysky }
22410a0ef39SIvan Kokshaysky 
22510a0ef39SIvan Kokshaysky /**
226*0a9d991cSRandy Dunlap  * pci_create_resource_files - create resource files in sysfs for @pdev
227*0a9d991cSRandy Dunlap  * @pdev: pci_dev in question
22810a0ef39SIvan Kokshaysky  *
22910a0ef39SIvan Kokshaysky  * Walk the resources in @dev creating files for each resource available.
230*0a9d991cSRandy Dunlap  *
231*0a9d991cSRandy Dunlap  * Return: %0 on success, or negative error code
23210a0ef39SIvan Kokshaysky  */
pci_create_resource_files(struct pci_dev * pdev)23310a0ef39SIvan Kokshaysky int pci_create_resource_files(struct pci_dev *pdev)
23410a0ef39SIvan Kokshaysky {
23510a0ef39SIvan Kokshaysky 	int i;
23610a0ef39SIvan Kokshaysky 	int retval;
23710a0ef39SIvan Kokshaysky 
23810a0ef39SIvan Kokshaysky 	/* Expose the PCI resources from this device as files */
239c9c13ba4SDenis Efremov 	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
24010a0ef39SIvan Kokshaysky 
24110a0ef39SIvan Kokshaysky 		/* skip empty resources */
24210a0ef39SIvan Kokshaysky 		if (!pci_resource_len(pdev, i))
24310a0ef39SIvan Kokshaysky 			continue;
24410a0ef39SIvan Kokshaysky 
24510a0ef39SIvan Kokshaysky 		retval = pci_create_attr(pdev, i);
24610a0ef39SIvan Kokshaysky 		if (retval) {
24710a0ef39SIvan Kokshaysky 			pci_remove_resource_files(pdev);
24810a0ef39SIvan Kokshaysky 			return retval;
24910a0ef39SIvan Kokshaysky 		}
25010a0ef39SIvan Kokshaysky 	}
25110a0ef39SIvan Kokshaysky 	return 0;
25210a0ef39SIvan Kokshaysky }
25310a0ef39SIvan Kokshaysky 
25410a0ef39SIvan Kokshaysky /* Legacy I/O bus mapping stuff. */
25510a0ef39SIvan Kokshaysky 
__legacy_mmap_fits(struct pci_controller * hose,struct vm_area_struct * vma,unsigned long res_size,int sparse)25610a0ef39SIvan Kokshaysky static int __legacy_mmap_fits(struct pci_controller *hose,
25710a0ef39SIvan Kokshaysky 			      struct vm_area_struct *vma,
25810a0ef39SIvan Kokshaysky 			      unsigned long res_size, int sparse)
25910a0ef39SIvan Kokshaysky {
26010a0ef39SIvan Kokshaysky 	unsigned long nr, start, size;
26110a0ef39SIvan Kokshaysky 
262236d62b0SShyam Saini 	nr = vma_pages(vma);
26310a0ef39SIvan Kokshaysky 	start = vma->vm_pgoff;
26410a0ef39SIvan Kokshaysky 	size = ((res_size - 1) >> PAGE_SHIFT) + 1;
26510a0ef39SIvan Kokshaysky 
26610a0ef39SIvan Kokshaysky 	if (start < size && size - start >= nr)
26710a0ef39SIvan Kokshaysky 		return 1;
26810a0ef39SIvan Kokshaysky 	WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on hose %d "
26910a0ef39SIvan Kokshaysky 		"(size 0x%08lx)\n",
27010a0ef39SIvan Kokshaysky 		current->comm, sparse ? " sparse" : "", start, start + nr,
27110a0ef39SIvan Kokshaysky 		hose->index, size);
27210a0ef39SIvan Kokshaysky 	return 0;
27310a0ef39SIvan Kokshaysky }
27410a0ef39SIvan Kokshaysky 
has_sparse(struct pci_controller * hose,enum pci_mmap_state mmap_type)27510a0ef39SIvan Kokshaysky static inline int has_sparse(struct pci_controller *hose,
27610a0ef39SIvan Kokshaysky 			     enum pci_mmap_state mmap_type)
27710a0ef39SIvan Kokshaysky {
27810a0ef39SIvan Kokshaysky 	unsigned long base;
27910a0ef39SIvan Kokshaysky 
28010a0ef39SIvan Kokshaysky 	base = (mmap_type == pci_mmap_mem) ? hose->sparse_mem_base :
28110a0ef39SIvan Kokshaysky 					     hose->sparse_io_base;
28210a0ef39SIvan Kokshaysky 
28310a0ef39SIvan Kokshaysky 	return base != 0;
28410a0ef39SIvan Kokshaysky }
28510a0ef39SIvan Kokshaysky 
pci_mmap_legacy_page_range(struct pci_bus * bus,struct vm_area_struct * vma,enum pci_mmap_state mmap_type)28610a0ef39SIvan Kokshaysky int pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma,
28710a0ef39SIvan Kokshaysky 			       enum pci_mmap_state mmap_type)
28810a0ef39SIvan Kokshaysky {
28910a0ef39SIvan Kokshaysky 	struct pci_controller *hose = bus->sysdata;
29010a0ef39SIvan Kokshaysky 	int sparse = has_sparse(hose, mmap_type);
29110a0ef39SIvan Kokshaysky 	unsigned long res_size;
29210a0ef39SIvan Kokshaysky 
29310a0ef39SIvan Kokshaysky 	res_size = (mmap_type == pci_mmap_mem) ? bus->legacy_mem->size :
29410a0ef39SIvan Kokshaysky 						 bus->legacy_io->size;
29510a0ef39SIvan Kokshaysky 	if (!__legacy_mmap_fits(hose, vma, res_size, sparse))
29610a0ef39SIvan Kokshaysky 		return -EINVAL;
29710a0ef39SIvan Kokshaysky 
29810a0ef39SIvan Kokshaysky 	return hose_mmap_page_range(hose, vma, mmap_type, sparse);
29910a0ef39SIvan Kokshaysky }
30010a0ef39SIvan Kokshaysky 
30110a0ef39SIvan Kokshaysky /**
30210a0ef39SIvan Kokshaysky  * pci_adjust_legacy_attr - adjustment of legacy file attributes
303*0a9d991cSRandy Dunlap  * @bus: bus to create files under
30410a0ef39SIvan Kokshaysky  * @mmap_type: I/O port or memory
30510a0ef39SIvan Kokshaysky  *
30610a0ef39SIvan Kokshaysky  * Adjust file name and size for sparse mappings.
30710a0ef39SIvan Kokshaysky  */
pci_adjust_legacy_attr(struct pci_bus * bus,enum pci_mmap_state mmap_type)30810a0ef39SIvan Kokshaysky void pci_adjust_legacy_attr(struct pci_bus *bus, enum pci_mmap_state mmap_type)
30910a0ef39SIvan Kokshaysky {
31010a0ef39SIvan Kokshaysky 	struct pci_controller *hose = bus->sysdata;
31110a0ef39SIvan Kokshaysky 
31210a0ef39SIvan Kokshaysky 	if (!has_sparse(hose, mmap_type))
31310a0ef39SIvan Kokshaysky 		return;
31410a0ef39SIvan Kokshaysky 
31510a0ef39SIvan Kokshaysky 	if (mmap_type == pci_mmap_mem) {
31610a0ef39SIvan Kokshaysky 		bus->legacy_mem->attr.name = "legacy_mem_sparse";
31710a0ef39SIvan Kokshaysky 		bus->legacy_mem->size <<= 5;
31810a0ef39SIvan Kokshaysky 	} else {
31910a0ef39SIvan Kokshaysky 		bus->legacy_io->attr.name = "legacy_io_sparse";
32010a0ef39SIvan Kokshaysky 		bus->legacy_io->size <<= 5;
32110a0ef39SIvan Kokshaysky 	}
32210a0ef39SIvan Kokshaysky 	return;
32310a0ef39SIvan Kokshaysky }
32410a0ef39SIvan Kokshaysky 
32510a0ef39SIvan Kokshaysky /* Legacy I/O bus read/write functions */
pci_legacy_read(struct pci_bus * bus,loff_t port,u32 * val,size_t size)32610a0ef39SIvan Kokshaysky int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size)
32710a0ef39SIvan Kokshaysky {
32810a0ef39SIvan Kokshaysky 	struct pci_controller *hose = bus->sysdata;
32910a0ef39SIvan Kokshaysky 
33010a0ef39SIvan Kokshaysky 	port += hose->io_space->start;
33110a0ef39SIvan Kokshaysky 
33210a0ef39SIvan Kokshaysky 	switch(size) {
33310a0ef39SIvan Kokshaysky 	case 1:
33410a0ef39SIvan Kokshaysky 		*((u8 *)val) = inb(port);
33510a0ef39SIvan Kokshaysky 		return 1;
33610a0ef39SIvan Kokshaysky 	case 2:
33710a0ef39SIvan Kokshaysky 		if (port & 1)
33810a0ef39SIvan Kokshaysky 			return -EINVAL;
33910a0ef39SIvan Kokshaysky 		*((u16 *)val) = inw(port);
34010a0ef39SIvan Kokshaysky 		return 2;
34110a0ef39SIvan Kokshaysky 	case 4:
34210a0ef39SIvan Kokshaysky 		if (port & 3)
34310a0ef39SIvan Kokshaysky 			return -EINVAL;
34410a0ef39SIvan Kokshaysky 		*((u32 *)val) = inl(port);
34510a0ef39SIvan Kokshaysky 		return 4;
34610a0ef39SIvan Kokshaysky 	}
34710a0ef39SIvan Kokshaysky 	return -EINVAL;
34810a0ef39SIvan Kokshaysky }
34910a0ef39SIvan Kokshaysky 
pci_legacy_write(struct pci_bus * bus,loff_t port,u32 val,size_t size)35010a0ef39SIvan Kokshaysky int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
35110a0ef39SIvan Kokshaysky {
35210a0ef39SIvan Kokshaysky 	struct pci_controller *hose = bus->sysdata;
35310a0ef39SIvan Kokshaysky 
35410a0ef39SIvan Kokshaysky 	port += hose->io_space->start;
35510a0ef39SIvan Kokshaysky 
35610a0ef39SIvan Kokshaysky 	switch(size) {
35710a0ef39SIvan Kokshaysky 	case 1:
35810a0ef39SIvan Kokshaysky 		outb(port, val);
35910a0ef39SIvan Kokshaysky 		return 1;
36010a0ef39SIvan Kokshaysky 	case 2:
36110a0ef39SIvan Kokshaysky 		if (port & 1)
36210a0ef39SIvan Kokshaysky 			return -EINVAL;
36310a0ef39SIvan Kokshaysky 		outw(port, val);
36410a0ef39SIvan Kokshaysky 		return 2;
36510a0ef39SIvan Kokshaysky 	case 4:
36610a0ef39SIvan Kokshaysky 		if (port & 3)
36710a0ef39SIvan Kokshaysky 			return -EINVAL;
36810a0ef39SIvan Kokshaysky 		outl(port, val);
36910a0ef39SIvan Kokshaysky 		return 4;
37010a0ef39SIvan Kokshaysky 	}
37110a0ef39SIvan Kokshaysky 	return -EINVAL;
37210a0ef39SIvan Kokshaysky }
373