ebus.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* $Id: ebus.c,v 1.64 2001/11/08 04:41:33 davem Exp $
  2.  * ebus.c: PCI to EBus bridge device.
  3.  *
  4.  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
  5.  * Copyright (C) 1999  David S. Miller (davem@redhat.com)
  6.  */
  7. #include <linux/config.h>
  8. #include <linux/kernel.h>
  9. #include <linux/types.h>
  10. #include <linux/init.h>
  11. #include <linux/slab.h>
  12. #include <linux/string.h>
  13. #include <asm/system.h>
  14. #include <asm/page.h>
  15. #include <asm/pbm.h>
  16. #include <asm/ebus.h>
  17. #include <asm/oplib.h>
  18. #include <asm/bpp.h>
  19. #include <asm/irq.h>
  20. struct linux_ebus *ebus_chain = 0;
  21. #ifdef CONFIG_SUN_AUXIO
  22. extern void auxio_probe(void);
  23. #endif
  24. static inline void *ebus_alloc(size_t size)
  25. {
  26. void *mem;
  27. mem = kmalloc(size, GFP_ATOMIC);
  28. if (!mem)
  29. panic(__FUNCTION__ ": out of memory");
  30. memset((char *)mem, 0, size);
  31. return mem;
  32. }
  33. static void __init ebus_ranges_init(struct linux_ebus *ebus)
  34. {
  35. int success;
  36. ebus->num_ebus_ranges = 0;
  37. success = prom_getproperty(ebus->prom_node, "ranges",
  38.    (char *)ebus->ebus_ranges,
  39.    sizeof(ebus->ebus_ranges));
  40. if (success != -1)
  41. ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges));
  42. }
  43. static void __init ebus_intmap_init(struct linux_ebus *ebus)
  44. {
  45. int success;
  46. ebus->num_ebus_intmap = 0;
  47. success = prom_getproperty(ebus->prom_node, "interrupt-map",
  48.    (char *)ebus->ebus_intmap,
  49.    sizeof(ebus->ebus_intmap));
  50. if (success == -1)
  51. return;
  52. ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap));
  53. success = prom_getproperty(ebus->prom_node, "interrupt-map-mask",
  54.    (char *)&ebus->ebus_intmask,
  55.    sizeof(ebus->ebus_intmask));
  56. if (success == -1) {
  57. prom_printf("%s: can't get interrupt-map-maskn", __FUNCTION__);
  58. prom_halt();
  59. }
  60. }
  61. int __init ebus_intmap_match(struct linux_ebus *ebus,
  62.      struct linux_prom_registers *reg,
  63.      int *interrupt)
  64. {
  65. unsigned int hi, lo, irq;
  66. int i;
  67. if (!ebus->num_ebus_intmap)
  68. return 0;
  69. hi = reg->which_io & ebus->ebus_intmask.phys_hi;
  70. lo = reg->phys_addr & ebus->ebus_intmask.phys_lo;
  71. irq = *interrupt & ebus->ebus_intmask.interrupt;
  72. for (i = 0; i < ebus->num_ebus_intmap; i++) {
  73. if ((ebus->ebus_intmap[i].phys_hi == hi) &&
  74.     (ebus->ebus_intmap[i].phys_lo == lo) &&
  75.     (ebus->ebus_intmap[i].interrupt == irq)) {
  76. *interrupt = ebus->ebus_intmap[i].cinterrupt;
  77. return 0;
  78. }
  79. }
  80. return -1;
  81. }
  82. void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
  83.     struct linux_ebus_child *dev, int non_standard_regs)
  84. {
  85. int regs[PROMREG_MAX];
  86. int irqs[PROMREG_MAX];
  87. int i, len;
  88. dev->prom_node = node;
  89. prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
  90. printk(" (%s)", dev->prom_name);
  91. len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
  92. dev->num_addrs = len / sizeof(regs[0]);
  93. if (non_standard_regs) {
  94. /* This is to handle reg properties which are not
  95.  * in the parent relative format.  One example are
  96.  * children of the i2c device on CompactPCI systems.
  97.  *
  98.  * So, for such devices we just record the property
  99.  * raw in the child resources.
  100.  */
  101. for (i = 0; i < dev->num_addrs; i++)
  102. dev->resource[i].start = regs[i];
  103. } else {
  104. for (i = 0; i < dev->num_addrs; i++) {
  105. int rnum = regs[i];
  106. if (rnum >= dev->parent->num_addrs) {
  107. prom_printf("UGH: property for %s was %d, need < %dn",
  108.     dev->prom_name, len, dev->parent->num_addrs);
  109. panic(__FUNCTION__);
  110. }
  111. dev->resource[i].start = dev->parent->resource[i].start;
  112. dev->resource[i].end = dev->parent->resource[i].end;
  113. dev->resource[i].flags = IORESOURCE_MEM;
  114. dev->resource[i].name = dev->prom_name;
  115. }
  116. }
  117. for (i = 0; i < PROMINTR_MAX; i++)
  118. dev->irqs[i] = PCI_IRQ_NONE;
  119. len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
  120. if ((len == -1) || (len == 0)) {
  121. dev->num_irqs = 0;
  122. /*
  123.  * Oh, well, some PROMs don't export interrupts
  124.  * property to children of EBus devices...
  125.  *
  126.  * Be smart about PS/2 keyboard and mouse.
  127.  */
  128. if (!strcmp(dev->parent->prom_name, "8042")) {
  129. if (!strcmp(dev->prom_name, "kb_ps2")) {
  130. dev->num_irqs = 1;
  131. dev->irqs[0] = dev->parent->irqs[0];
  132. } else {
  133. dev->num_irqs = 1;
  134. dev->irqs[0] = dev->parent->irqs[1];
  135. }
  136. }
  137. } else {
  138. dev->num_irqs = len / sizeof(irqs[0]);
  139. for (i = 0; i < dev->num_irqs; i++) {
  140. struct pci_pbm_info *pbm = dev->bus->parent;
  141. struct pci_controller_info *p = pbm->parent;
  142. if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) {
  143. dev->irqs[i] = p->irq_build(pbm,
  144.     dev->bus->self,
  145.     irqs[i]);
  146. } else {
  147. /* If we get a bogus interrupt property, just
  148.  * record the raw value instead of punting.
  149.  */
  150. dev->irqs[i] = irqs[i];
  151. }
  152. }
  153. }
  154. }
  155. static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
  156. {
  157. if (!strcmp(dev->prom_name, "i2c"))
  158. return 1;
  159. return 0;
  160. }
  161. void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
  162. {
  163. struct linux_prom_registers regs[PROMREG_MAX];
  164. struct linux_ebus_child *child;
  165. int irqs[PROMINTR_MAX];
  166. int i, n, len;
  167. dev->prom_node = node;
  168. prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
  169. printk(" [%s", dev->prom_name);
  170. len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
  171. if (len == -1) {
  172. dev->num_addrs = 0;
  173. goto probe_interrupts;
  174. }
  175. if (len % sizeof(struct linux_prom_registers)) {
  176. prom_printf("UGH: proplen for %s was %d, need multiple of %dn",
  177.     dev->prom_name, len,
  178.     (int)sizeof(struct linux_prom_registers));
  179. prom_halt();
  180. }
  181. dev->num_addrs = len / sizeof(struct linux_prom_registers);
  182. for (i = 0; i < dev->num_addrs; i++) {
  183. if (dev->bus->is_rio == 0)
  184. n = (regs[i].which_io - 0x10) >> 2;
  185. else
  186. n = regs[i].which_io;
  187. dev->resource[i].start  = dev->bus->self->resource[n].start;
  188. dev->resource[i].start += (unsigned long)regs[i].phys_addr;
  189. dev->resource[i].end    =
  190. (dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL);
  191. dev->resource[i].flags  = IORESOURCE_MEM;
  192. dev->resource[i].name   = dev->prom_name;
  193. request_resource(&dev->bus->self->resource[n],
  194.  &dev->resource[i]);
  195. }
  196. probe_interrupts:
  197. for (i = 0; i < PROMINTR_MAX; i++)
  198. dev->irqs[i] = PCI_IRQ_NONE;
  199. len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
  200. if ((len == -1) || (len == 0)) {
  201. dev->num_irqs = 0;
  202. } else {
  203. dev->num_irqs = len / sizeof(irqs[0]);
  204. for (i = 0; i < dev->num_irqs; i++) {
  205. struct pci_pbm_info *pbm = dev->bus->parent;
  206. struct pci_controller_info *p = pbm->parent;
  207. if (ebus_intmap_match(dev->bus, &regs[0], &irqs[i]) != -1) {
  208. dev->irqs[i] = p->irq_build(pbm,
  209.     dev->bus->self,
  210.     irqs[i]);
  211. } else {
  212. /* If we get a bogus interrupt property, just
  213.  * record the raw value instead of punting.
  214.  */
  215. dev->irqs[i] = irqs[i];
  216. }
  217. }
  218. }
  219. if ((node = prom_getchild(node))) {
  220. printk(" ->");
  221. dev->children = ebus_alloc(sizeof(struct linux_ebus_child));
  222. child = dev->children;
  223. child->next = 0;
  224. child->parent = dev;
  225. child->bus = dev->bus;
  226. fill_ebus_child(node, &regs[0],
  227. child, child_regs_nonstandard(dev));
  228. while ((node = prom_getsibling(node))) {
  229. child->next = ebus_alloc(sizeof(struct linux_ebus_child));
  230. child = child->next;
  231. child->next = 0;
  232. child->parent = dev;
  233. child->bus = dev->bus;
  234. fill_ebus_child(node, &regs[0],
  235. child, child_regs_nonstandard(dev));
  236. }
  237. }
  238. printk("]");
  239. }
  240. void __init ebus_init(void)
  241. {
  242. struct pci_pbm_info *pbm;
  243. struct linux_ebus_device *dev;
  244. struct linux_ebus *ebus;
  245. struct pci_dev *pdev;
  246. struct pcidev_cookie *cookie;
  247. int nd, ebusnd, is_rio;
  248. int num_ebus = 0;
  249. if (!pci_present())
  250. return;
  251. is_rio = 0;
  252. pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0);
  253. if (!pdev) {
  254. pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_EBUS, 0);
  255. is_rio = 1;
  256. }
  257. if (!pdev) {
  258. printk("ebus: No EBus's found.n");
  259. return;
  260. }
  261. cookie = pdev->sysdata;
  262. ebusnd = cookie->prom_node;
  263. ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
  264. ebus->next = 0;
  265. ebus->is_rio = is_rio;
  266. while (ebusnd) {
  267. /* SUNW,pci-qfe uses four empty ebuses on it.
  268.    I think we should not consider them here,
  269.    as they have half of the properties this
  270.    code expects and once we do PCI hot-plug,
  271.    we'd have to tweak with the ebus_chain
  272.    in the runtime after initialization. -jj */
  273. if (!prom_getchild (ebusnd)) {
  274. struct pci_dev *orig_pdev = pdev;
  275. is_rio = 0;
  276. pdev = pci_find_device(PCI_VENDOR_ID_SUN, 
  277.        PCI_DEVICE_ID_SUN_EBUS, orig_pdev);
  278. if (!pdev) {
  279. pdev = pci_find_device(PCI_VENDOR_ID_SUN, 
  280.        PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev);
  281. is_rio = 1;
  282. }
  283. if (!pdev) {
  284. if (ebus == ebus_chain) {
  285. ebus_chain = NULL;
  286. printk("ebus: No EBus's found.n");
  287. return;
  288. }
  289. break;
  290. }
  291. ebus->is_rio = is_rio;
  292. cookie = pdev->sysdata;
  293. ebusnd = cookie->prom_node;
  294. continue;
  295. }
  296. printk("ebus%d:", num_ebus);
  297. prom_getstring(ebusnd, "name", ebus->prom_name, sizeof(ebus->prom_name));
  298. ebus->index = num_ebus;
  299. ebus->prom_node = ebusnd;
  300. ebus->self = pdev;
  301. ebus->parent = pbm = cookie->pbm;
  302. ebus_ranges_init(ebus);
  303. ebus_intmap_init(ebus);
  304. nd = prom_getchild(ebusnd);
  305. if (!nd)
  306. goto next_ebus;
  307. ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device));
  308. dev = ebus->devices;
  309. dev->next = 0;
  310. dev->children = 0;
  311. dev->bus = ebus;
  312. fill_ebus_device(nd, dev);
  313. while ((nd = prom_getsibling(nd))) {
  314. dev->next = ebus_alloc(sizeof(struct linux_ebus_device));
  315. dev = dev->next;
  316. dev->next = 0;
  317. dev->children = 0;
  318. dev->bus = ebus;
  319. fill_ebus_device(nd, dev);
  320. }
  321. next_ebus:
  322. printk("n");
  323. {
  324. struct pci_dev *orig_pdev = pdev;
  325. is_rio = 0;
  326. pdev = pci_find_device(PCI_VENDOR_ID_SUN,
  327.        PCI_DEVICE_ID_SUN_EBUS, orig_pdev);
  328. if (!pdev) {
  329. pdev = pci_find_device(PCI_VENDOR_ID_SUN,
  330.        PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev);
  331. is_rio = 1;
  332. }
  333. if (!pdev)
  334. break;
  335. }
  336. cookie = pdev->sysdata;
  337. ebusnd = cookie->prom_node;
  338. ebus->next = ebus_alloc(sizeof(struct linux_ebus));
  339. ebus = ebus->next;
  340. ebus->next = 0;
  341. ebus->is_rio = is_rio;
  342. ++num_ebus;
  343. }
  344. #ifdef CONFIG_SUN_AUXIO
  345. auxio_probe();
  346. #endif
  347. }