^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * arch/alpha/kernel/pci-sysfs.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2009 Ivan Kokshaysky
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Alpha PCI resource files.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Loosely based on generic HAVE_PCI_MMAP implementation in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * drivers/pci/pci-sysfs.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static int hose_mmap_page_range(struct pci_controller *hose,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct vm_area_struct *vma,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) enum pci_mmap_state mmap_type, int sparse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) unsigned long base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) if (mmap_type == pci_mmap_mem)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) base = sparse ? hose->sparse_mem_base : hose->dense_mem_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) base = sparse ? hose->sparse_io_base : hose->dense_io_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) vma->vm_pgoff += base >> PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) vma->vm_end - vma->vm_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) vma->vm_page_prot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static int __pci_mmap_fits(struct pci_dev *pdev, int num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct vm_area_struct *vma, int sparse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) unsigned long nr, start, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int shift = sparse ? 5 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) nr = vma_pages(vma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) start = vma->vm_pgoff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) size = ((pci_resource_len(pdev, num) - 1) >> (PAGE_SHIFT - shift)) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (start < size && size - start >= nr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on %s BAR %d "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) "(size 0x%08lx)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) current->comm, sparse ? " sparse" : "", start, start + nr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) pci_name(pdev), num, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * pci_mmap_resource - map a PCI resource into user memory space
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * @kobj: kobject for mapping
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * @attr: struct bin_attribute for the file being mapped
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * @vma: struct vm_area_struct passed into the mmap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * @sparse: address space type
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * Use the bus mapping routines to map a PCI resource into userspace.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int pci_mmap_resource(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct bin_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct vm_area_struct *vma, int sparse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct resource *res = attr->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) enum pci_mmap_state mmap_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct pci_bus_region bar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) for (i = 0; i < PCI_STD_NUM_BARS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (res == &pdev->resource[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (i >= PCI_STD_NUM_BARS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (!__pci_mmap_fits(pdev, i, vma, sparse))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) pcibios_resource_to_bus(pdev->bus, &bar, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) vma->vm_pgoff += bar.start >> (PAGE_SHIFT - (sparse ? 5 : 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return hose_mmap_page_range(pdev->sysdata, vma, mmap_type, sparse);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static int pci_mmap_resource_sparse(struct file *filp, struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct bin_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return pci_mmap_resource(kobj, attr, vma, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static int pci_mmap_resource_dense(struct file *filp, struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) struct bin_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return pci_mmap_resource(kobj, attr, vma, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * pci_remove_resource_files - cleanup resource files
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * @dev: dev to cleanup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * If we created resource files for @dev, remove them from sysfs and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * free their resources.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) void pci_remove_resource_files(struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) for (i = 0; i < PCI_STD_NUM_BARS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct bin_attribute *res_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) res_attr = pdev->res_attr[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (res_attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) kfree(res_attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) res_attr = pdev->res_attr_wc[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (res_attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) kfree(res_attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static int sparse_mem_mmap_fits(struct pci_dev *pdev, int num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) struct pci_bus_region bar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) struct pci_controller *hose = pdev->sysdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) long dense_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) unsigned long sparse_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) pcibios_resource_to_bus(pdev->bus, &bar, &pdev->resource[num]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* All core logic chips have 4G sparse address space, except
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) CIA which has 16G (see xxx_SPARSE_MEM and xxx_DENSE_MEM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) definitions in asm/core_xxx.h files). This corresponds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) to 128M or 512M of the bus space. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) dense_offset = (long)(hose->dense_mem_base - hose->sparse_mem_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) sparse_size = dense_offset >= 0x400000000UL ? 0x20000000 : 0x8000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return bar.end < sparse_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static int pci_create_one_attr(struct pci_dev *pdev, int num, char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) char *suffix, struct bin_attribute *res_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) unsigned long sparse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) size_t size = pci_resource_len(pdev, num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) sprintf(name, "resource%d%s", num, suffix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) res_attr->mmap = sparse ? pci_mmap_resource_sparse :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) pci_mmap_resource_dense;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) res_attr->attr.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) res_attr->attr.mode = S_IRUSR | S_IWUSR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) res_attr->size = sparse ? size << 5 : size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) res_attr->private = &pdev->resource[num];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) static int pci_create_attr(struct pci_dev *pdev, int num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) /* allocate attribute structure, piggyback attribute name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) int retval, nlen1, nlen2 = 0, res_count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) unsigned long sparse_base, dense_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) struct bin_attribute *attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) struct pci_controller *hose = pdev->sysdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) char *suffix, *attr_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) suffix = ""; /* Assume bwx machine, normal resourceN files. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) nlen1 = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (pdev->resource[num].flags & IORESOURCE_MEM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) sparse_base = hose->sparse_mem_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) dense_base = hose->dense_mem_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (sparse_base && !sparse_mem_mmap_fits(pdev, num)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) sparse_base = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) suffix = "_dense";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) nlen1 = 16; /* resourceN_dense */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) sparse_base = hose->sparse_io_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) dense_base = hose->dense_io_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (sparse_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) suffix = "_sparse";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) nlen1 = 17;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if (dense_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) nlen2 = 16; /* resourceN_dense */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) res_count = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) attr = kzalloc(sizeof(*attr) * res_count + nlen1 + nlen2, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (!attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) /* Create bwx, sparse or single dense file */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) attr_name = (char *)(attr + res_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) pdev->res_attr[num] = attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) retval = pci_create_one_attr(pdev, num, attr_name, suffix, attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) sparse_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (retval || res_count == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /* Create dense file */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) attr_name += nlen1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) attr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) pdev->res_attr_wc[num] = attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return pci_create_one_attr(pdev, num, attr_name, "_dense", attr, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * pci_create_resource_files - create resource files in sysfs for @dev
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * @dev: dev in question
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * Walk the resources in @dev creating files for each resource available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) int pci_create_resource_files(struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /* Expose the PCI resources from this device as files */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) for (i = 0; i < PCI_STD_NUM_BARS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) /* skip empty resources */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (!pci_resource_len(pdev, i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) retval = pci_create_attr(pdev, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) pci_remove_resource_files(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) /* Legacy I/O bus mapping stuff. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) static int __legacy_mmap_fits(struct pci_controller *hose,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) struct vm_area_struct *vma,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) unsigned long res_size, int sparse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) unsigned long nr, start, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) nr = vma_pages(vma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) start = vma->vm_pgoff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) size = ((res_size - 1) >> PAGE_SHIFT) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (start < size && size - start >= nr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on hose %d "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) "(size 0x%08lx)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) current->comm, sparse ? " sparse" : "", start, start + nr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) hose->index, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) static inline int has_sparse(struct pci_controller *hose,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) enum pci_mmap_state mmap_type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) unsigned long base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) base = (mmap_type == pci_mmap_mem) ? hose->sparse_mem_base :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) hose->sparse_io_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return base != 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) int pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) enum pci_mmap_state mmap_type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) struct pci_controller *hose = bus->sysdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) int sparse = has_sparse(hose, mmap_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) unsigned long res_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) res_size = (mmap_type == pci_mmap_mem) ? bus->legacy_mem->size :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) bus->legacy_io->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (!__legacy_mmap_fits(hose, vma, res_size, sparse))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return hose_mmap_page_range(hose, vma, mmap_type, sparse);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) * pci_adjust_legacy_attr - adjustment of legacy file attributes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) * @b: bus to create files under
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) * @mmap_type: I/O port or memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) * Adjust file name and size for sparse mappings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) void pci_adjust_legacy_attr(struct pci_bus *bus, enum pci_mmap_state mmap_type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) struct pci_controller *hose = bus->sysdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (!has_sparse(hose, mmap_type))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (mmap_type == pci_mmap_mem) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) bus->legacy_mem->attr.name = "legacy_mem_sparse";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) bus->legacy_mem->size <<= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) bus->legacy_io->attr.name = "legacy_io_sparse";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) bus->legacy_io->size <<= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /* Legacy I/O bus read/write functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) struct pci_controller *hose = bus->sysdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) port += hose->io_space->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) switch(size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) *((u8 *)val) = inb(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (port & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) *((u16 *)val) = inw(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) return 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (port & 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) *((u32 *)val) = inl(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) return 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) struct pci_controller *hose = bus->sysdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) port += hose->io_space->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) switch(size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) outb(port, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) if (port & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) outw(port, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) return 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (port & 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) outl(port, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }