pci-sysfs.c 9.2 KB

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