📄 prom.c
字号:
/* * early_get_property is used to access the device tree image prepared * by BootX very early on, before the pointers in it have been relocated. */static void * __initearly_get_property(unsigned long base, unsigned long node, char *prop){ struct device_node *np = (struct device_node *)(base + node); struct property *pp; for (pp = np->properties; pp != 0; pp = pp->next) { pp = (struct property *) (base + (unsigned long)pp); if (strcmp((char *)((unsigned long)pp->name + base), prop) == 0) { return (void *)((unsigned long)pp->value + base); } } return 0;}static unsigned long __initfinish_node(struct device_node *np, unsigned long mem_start, interpret_func *ifunc, int naddrc, int nsizec){ struct device_node *child; int *ip; np->name = get_property(np, "name", 0); np->type = get_property(np, "device_type", 0); if (!np->name) np->name = "<NULL>"; if (!np->type) np->type = "<NULL>"; /* get the device addresses and interrupts */ if (ifunc != NULL) mem_start = ifunc(np, mem_start, naddrc, nsizec); if (use_of_interrupt_tree) mem_start = finish_node_interrupts(np, mem_start); /* Look for #address-cells and #size-cells properties. */ ip = (int *) get_property(np, "#address-cells", 0); if (ip != NULL) naddrc = *ip; ip = (int *) get_property(np, "#size-cells", 0); if (ip != NULL) nsizec = *ip; /* * The F50 sets the name to 'display' and 'compatible' to what we * expect for the name. -- Cort * * But sometimes you get a 'display' name for non-OF cards, and thus * no compatible property. And very rarely we won't have a name * property either. -- Tom */ if (!strcmp(np->name, "display")) np->name = get_property(np, "compatible", 0); if (!np->name) np->name = get_property(np, "name", 0); if (np->parent == NULL) ifunc = interpret_root_props; else if (np->type == 0) ifunc = NULL; else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci")) ifunc = interpret_pci_props; else if (!strcmp(np->type, "dbdma")) ifunc = interpret_dbdma_props; else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props) ifunc = interpret_macio_props; else if (!strcmp(np->type, "isa")) ifunc = interpret_isa_props; else if (!strcmp(np->name, "uni-n")) ifunc = interpret_root_props; else if (!((ifunc == interpret_dbdma_props || ifunc == interpret_macio_props) && (!strcmp(np->type, "escc") || !strcmp(np->type, "media-bay")))) ifunc = NULL; /* if we were booted from BootX, convert the full name */ if (boot_infos && strncmp(np->full_name, "Devices:device-tree", 19) == 0) { if (np->full_name[19] == 0) { strcpy(np->full_name, "/"); } else if (np->full_name[19] == ':') { char *p = np->full_name + 19; np->full_name = p; for (; *p; ++p) if (*p == ':') *p = '/'; } } for (child = np->child; child != NULL; child = child->sibling) mem_start = finish_node(child, mem_start, ifunc, naddrc, nsizec); return mem_start;}/* * Find the interrupt parent of a node. */static struct device_node * __initintr_parent(struct device_node *p){ phandle *parp; parp = (phandle *) get_property(p, "interrupt-parent", NULL); if (parp == NULL) return p->parent; p = find_phandle(*parp); if (p != NULL) return p; /* * On a powermac booted with BootX, we don't get to know the * phandles for any nodes, so find_phandle will return NULL. * Fortunately these machines only have one interrupt controller * so there isn't in fact any ambiguity. -- paulus */ if (num_interrupt_controllers == 1) p = dflt_interrupt_controller; return p;}/* * Find out the size of each entry of the interrupts property * for a node. */static int __initprom_n_intr_cells(struct device_node *np){ struct device_node *p; unsigned int *icp; for (p = np; (p = intr_parent(p)) != NULL; ) { icp = (unsigned int *) get_property(p, "#interrupt-cells", NULL); if (icp != NULL) return *icp; if (get_property(p, "interrupt-controller", NULL) != NULL || get_property(p, "interrupt-map", NULL) != NULL) { printk("oops, node %s doesn't have #interrupt-cells\n", p->full_name); return 1; } } printk("prom_n_intr_cells failed for %s\n", np->full_name); return 1;}/* * Map an interrupt from a device up to the platform interrupt * descriptor. */static int __initmap_interrupt(unsigned int **irq, struct device_node **ictrler, struct device_node *np, unsigned int *ints, int nintrc){ struct device_node *p, *ipar; unsigned int *imap, *imask, *ip; int i, imaplen, match; int newintrc, newaddrc; unsigned int *reg; int naddrc; reg = (unsigned int *) get_property(np, "reg", NULL); naddrc = prom_n_addr_cells(np); p = intr_parent(np); while (p != NULL) { if (get_property(p, "interrupt-controller", NULL) != NULL) /* this node is an interrupt controller, stop here */ break; imap = (unsigned int *) get_property(p, "interrupt-map", &imaplen); if (imap == NULL) { p = intr_parent(p); continue; } imask = (unsigned int *) get_property(p, "interrupt-map-mask", NULL); if (imask == NULL) { printk("oops, %s has interrupt-map but no mask\n", p->full_name); return 0; } imaplen /= sizeof(unsigned int); match = 0; ipar = NULL; while (imaplen > 0 && !match) { /* check the child-interrupt field */ match = 1; for (i = 0; i < naddrc && match; ++i) match = ((reg[i] ^ imap[i]) & imask[i]) == 0; for (; i < naddrc + nintrc && match; ++i) match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0; imap += naddrc + nintrc; imaplen -= naddrc + nintrc; /* grab the interrupt parent */ ipar = find_phandle((phandle) *imap++); --imaplen; if (ipar == NULL && num_interrupt_controllers == 1) /* cope with BootX not giving us phandles */ ipar = dflt_interrupt_controller; if (ipar == NULL) { printk("oops, no int parent %x in map of %s\n", imap[-1], p->full_name); return 0; } /* find the parent's # addr and intr cells */ ip = (unsigned int *) get_property(ipar, "#interrupt-cells", NULL); if (ip == NULL) { printk("oops, no #interrupt-cells on %s\n", ipar->full_name); return 0; } newintrc = *ip; ip = (unsigned int *) get_property(ipar, "#address-cells", NULL); newaddrc = (ip == NULL)? 0: *ip; imap += newaddrc + newintrc; imaplen -= newaddrc + newintrc; } if (imaplen < 0) { printk("oops, error decoding int-map on %s, len=%d\n", p->full_name, imaplen); return 0; } if (!match) { printk("oops, no match in %s int-map for %s\n", p->full_name, np->full_name); return 0; } p = ipar; naddrc = newaddrc; nintrc = newintrc; ints = imap - nintrc; reg = ints - naddrc; } if (p == NULL) printk("hmmm, int tree for %s doesn't have ctrler\n", np->full_name); *irq = ints; *ictrler = p; return nintrc;}/* * New version of finish_node_interrupts. */static unsigned long __initfinish_node_interrupts(struct device_node *np, unsigned long mem_start){ unsigned int *ints; int intlen, intrcells; int i, j, n, offset; unsigned int *irq; struct device_node *ic; ints = (unsigned int *) get_property(np, "interrupts", &intlen); if (ints == NULL) return mem_start; intrcells = prom_n_intr_cells(np); intlen /= intrcells * sizeof(unsigned int); np->n_intrs = intlen; np->intrs = (struct interrupt_info *) mem_start; mem_start += intlen * sizeof(struct interrupt_info); for (i = 0; i < intlen; ++i) { np->intrs[i].line = 0; np->intrs[i].sense = 1; n = map_interrupt(&irq, &ic, np, ints, intrcells); if (n <= 0) continue; offset = 0; /* * On a CHRP we have an 8259 which is subordinate to * the openpic in the interrupt tree, but we want the * openpic's interrupt numbers offsetted, not the 8259's. * So we apply the offset if the controller is at the * root of the interrupt tree, i.e. has no interrupt-parent. * This doesn't cope with the general case of multiple * cascaded interrupt controllers, but then neither will * irq.c at the moment either. -- paulus */ if (num_interrupt_controllers > 1 && ic != NULL && get_property(ic, "interrupt-parent", NULL) == NULL) offset = 16; np->intrs[i].line = irq[0] + offset; if (n > 1) np->intrs[i].sense = irq[1]; if (n > 2) { printk("hmmm, got %d intr cells for %s:", n, np->full_name); for (j = 0; j < n; ++j) printk(" %d", irq[j]); printk("\n"); } ints += intrcells; } return mem_start;}/* * When BootX makes a copy of the device tree from the MacOS * Name Registry, it is in the format we use but all of the pointers * are offsets from the start of the tree. * This procedure updates the pointers. */void __initrelocate_nodes(void){ unsigned long base; struct device_node *np; struct property *pp;#define ADDBASE(x) (x = (x)? ((typeof (x))((unsigned long)(x) + base)): 0) base = (unsigned long) boot_infos + boot_infos->deviceTreeOffset; allnodes = (struct device_node *)(base + 4); for (np = allnodes; np != 0; np = np->allnext) { ADDBASE(np->full_name); ADDBASE(np->properties); ADDBASE(np->parent); ADDBASE(np->child); ADDBASE(np->sibling); ADDBASE(np->allnext); for (pp = np->properties; pp != 0; pp = pp->next) { ADDBASE(pp->name); ADDBASE(pp->value); ADDBASE(pp->next); } }}intprom_n_addr_cells(struct device_node* np){ int* ip; do { if (np->parent) np = np->parent; ip = (int *) get_property(np, "#address-cells", 0); if (ip != NULL) return *ip; } while (np->parent); /* No #address-cells property for the root node, default to 1 */ return 1;}intprom_n_size_cells(struct device_node* np){ int* ip; do { if (np->parent) np = np->parent; ip = (int *) get_property(np, "#size-cells", 0); if (ip != NULL) return *ip; } while (np->parent); /* No #size-cells property for the root node, default to 1 */ return 1;}static unsigned long __initinterpret_pci_props(struct device_node *np, unsigned long mem_start, int naddrc, int nsizec){ struct address_range *adr; struct pci_reg_property *pci_addrs; int i, l, *ip; pci_addrs = (struct pci_reg_property *) get_property(np, "assigned-addresses", &l); if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) { i = 0; adr = (struct address_range *) mem_start; while ((l -= sizeof(struct pci_reg_property)) >= 0) { /* XXX assumes PCI addresses mapped 1-1 to physical */ adr[i].space = pci_addrs[i].addr.a_hi; adr[i].address = pci_addrs[i].addr.a_lo; adr[i].size = pci_addrs[i].size_lo; ++i; } np->addrs = adr; np->n_addrs = i; mem_start += i * sizeof(struct address_range); } if (use_of_interrupt_tree) return mem_start; ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip == 0 && np->parent) ip = (int *) get_property(np->parent, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { np->intrs = (struct interrupt_info *) mem_start; np->n_intrs = l / sizeof(int); mem_start += np->n_intrs * sizeof(struct interrupt_info); for (i = 0; i < np->n_intrs; ++i) { np->intrs[i].line = *ip++; np->intrs[i].sense = 1; } } return mem_start;}static unsigned long __initinterpret_dbdma_props(struct device_node *np, unsigned long mem_start, int naddrc, int nsizec){ struct reg_property *rp; struct address_range *adr; unsigned long base_address; int i, l, *ip; struct device_node *db; base_address = 0; for (db = np->parent; db != NULL; db = db->parent) { if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) { base_address = db->addrs[0].address; break; } } rp = (struct reg_property *) get_property(np, "reg", &l); if (rp != 0 && l >= sizeof(struct reg_property)) { i = 0; adr = (struct address_range *) mem_start; while ((l -= sizeof(struct reg_property)) >= 0) { adr[i].space = 2; adr[i].address = rp[i].address + base_address; adr[i].size = rp[i].size; ++i; } np->addrs = adr; np->n_addrs = i; mem_start += i * sizeof(struct address_range); } if (use_of_interrupt_tree) return mem_start; ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { np->intrs = (struct interrupt_info *) mem_start; np->n_intrs = l / sizeof(int); mem_start += np->n_intrs * sizeof(struct interrupt_info); for (i = 0; i < np->n_intrs; ++i) { np->intrs[i].line = *ip++; np->intrs[i].sense = 1; } } return mem_start;}static unsigned long __initinterpret_macio_props(struct device_node *np, unsigned long mem_start, int naddrc, int nsizec){ struct reg_property *rp; struct address_range *adr; unsigned long base_address; int i, l, *ip; struct device_node *db; base_address = 0; for (db = np->parent; db != NULL; db = db->parent) { if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) { base_address = db->addrs[0].address; break; } } rp = (struct reg_property *) get_property(np, "reg", &l); if (rp != 0 && l >= sizeof(struct reg_property)) { i = 0; adr = (struct address_range *) mem_start; while ((l -= sizeof(struct reg_property)) >= 0) { adr[i].space = 2; adr[i].address = rp[i].address + base_address; adr[i].size = rp[i].size; ++i; } np->addrs = adr; np->n_addrs = i; mem_start += i * sizeof(struct address_range); } if (use_of_interrupt_tree) return mem_start; ip = (int *) get_property(np, "interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip != 0) { np->intrs = (struct interrupt_info *) mem_start; np->n_intrs = l / sizeof(int); for (i = 0; i < np->n_intrs; ++i) { np->intrs[i].line = *ip++; np->intrs[i].sense = 1; } mem_start += np->n_intrs * sizeof(struct interrupt_info); } return mem_start;}static unsigned long __initinterpret_isa_props(struct device_node *np, unsigned long mem_start, int naddrc, int nsizec){ struct isa_reg_property *rp; struct address_range *adr; int i, l, *ip; rp = (struct isa_reg_property *) get_property(np, "reg", &l); if (rp != 0 && l >= sizeof(struct isa_reg_property)) { i = 0; adr = (struct address_range *) mem_start; while ((l -= sizeof(struct reg_property)) >= 0) { adr[i].space = rp[i].space; adr[i].address = rp[i].address + (adr[i].space? 0: _ISA_MEM_BASE); adr[i].size = rp[i].size; ++i; } np->addrs = adr; np->n_addrs = i; mem_start += i * sizeof(struct address_range);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -