pci-sysfs.c 9.2 KB

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