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