pci-sysfs.c 9.1 KB

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