pci-sysfs.c 9.2 KB

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