pci-sysfs.c 9.3 KB

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