Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | /* $Id: ranges.c,v 1.12 1999/08/31 06:55:05 davem Exp $ * ranges.c: Handle ranges in newer proms for obio/sbus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include <linux/config.h> #include <linux/init.h> #include <asm/openprom.h> #include <asm/oplib.h> #include <asm/sbus.h> #include <asm/fhc.h> #include <asm/system.h> #ifdef CONFIG_PCI #include <asm/pbm.h> #include <asm/ebus.h> #endif struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX]; int num_obio_ranges; /* Adjust register values based upon the ranges parameters. */ inline void prom_adjust_regs(struct linux_prom_registers *regp, int nregs, struct linux_prom_ranges *rangep, int nranges) { int regc, rngc; for(regc=0; regc < nregs; regc++) { for(rngc=0; rngc < nranges; rngc++) if(regp[regc].which_io == rangep[rngc].ot_child_space) break; /* Fount it */ if(rngc==nranges) /* oops */ prom_printf("adjust_regs: Could not find range with matching bus type...\n"); regp[regc].which_io = rangep[rngc].ot_parent_space; regp[regc].phys_addr += rangep[rngc].ot_parent_base; } } inline void prom_adjust_ranges(struct linux_prom_ranges *ranges1, int nranges1, struct linux_prom_ranges *ranges2, int nranges2) { int rng1c, rng2c; for(rng1c=0; rng1c < nranges1; rng1c++) { for(rng2c=0; rng2c < nranges2; rng2c++) if(ranges1[rng1c].ot_child_space == ranges2[rng2c].ot_child_space) break; if(rng2c == nranges2) /* oops */ prom_printf("adjust_ranges: Could not find matching bus type...\n"); ranges1[rng1c].ot_parent_space = ranges2[rng2c].ot_parent_space; ranges1[rng1c].ot_parent_base += ranges2[rng2c].ot_parent_base; } } /* Apply probed sbus ranges to registers passed, if no ranges return. */ void prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers *regs, int nregs, struct linux_sbus_device *sdev) { if(sbus->num_sbus_ranges) { if(sdev && (sdev->ranges_applied == 0)) { sdev->ranges_applied = 1; prom_adjust_regs(regs, nregs, sbus->sbus_ranges, sbus->num_sbus_ranges); } } } /* Apply probed fhc ranges to registers passed, if no ranges return. */ void prom_apply_fhc_ranges(struct linux_fhc *fhc, struct linux_prom_registers *regs, int nregs) { if(fhc->num_fhc_ranges) prom_adjust_regs(regs, nregs, fhc->fhc_ranges, fhc->num_fhc_ranges); } /* Apply probed central ranges to registers passed, if no ranges return. */ void prom_apply_central_ranges(struct linux_central *central, struct linux_prom_registers *regs, int nregs) { if(central->num_central_ranges) prom_adjust_regs(regs, nregs, central->central_ranges, central->num_central_ranges); } void __init prom_ranges_init(void) { } void __init prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus) { int success; sbus->num_sbus_ranges = 0; success = prom_getproperty(sbus->prom_node, "ranges", (char *) sbus->sbus_ranges, sizeof (sbus->sbus_ranges)); if (success != -1) sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges)); } void __init prom_central_ranges_init(int cnode, struct linux_central *central) { int success; central->num_central_ranges = 0; success = prom_getproperty(central->prom_node, "ranges", (char *) central->central_ranges, sizeof (central->central_ranges)); if (success != -1) central->num_central_ranges = (success/sizeof(struct linux_prom_ranges)); } void __init prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc) { int success; fhc->num_fhc_ranges = 0; success = prom_getproperty(fhc->prom_node, "ranges", (char *) fhc->fhc_ranges, sizeof (fhc->fhc_ranges)); if (success != -1) fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges)); } #ifdef CONFIG_PCI void __init prom_ebus_ranges_init(struct linux_ebus *ebus) { int success; ebus->num_ebus_ranges = 0; success = prom_getproperty(ebus->prom_node, "ranges", (char *)ebus->ebus_ranges, sizeof(ebus->ebus_ranges)); if (success != -1) ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges)); } void __init prom_ebus_intmap_init(struct linux_ebus *ebus) { int success; ebus->num_ebus_intmap = 0; success = prom_getproperty(ebus->prom_node, "interrupt-map", (char *)ebus->ebus_intmap, sizeof(ebus->ebus_intmap)); if (success == -1) return; ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap)); success = prom_getproperty(ebus->prom_node, "interrupt-map-mask", (char *)&ebus->ebus_intmask, sizeof(ebus->ebus_intmask)); if (success == -1) { prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__); prom_halt(); } } #endif void prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs) { int success; int num_ranges; struct linux_prom_ranges ranges[PROMREG_MAX]; success = prom_getproperty(node, "ranges", (char *) ranges, sizeof (ranges)); if (success != -1) { num_ranges = (success/sizeof(struct linux_prom_ranges)); if (parent) { struct linux_prom_ranges parent_ranges[PROMREG_MAX]; int num_parent_ranges; success = prom_getproperty(parent, "ranges", (char *) parent_ranges, sizeof (parent_ranges)); if (success != -1) { num_parent_ranges = (success/sizeof(struct linux_prom_ranges)); prom_adjust_ranges (ranges, num_ranges, parent_ranges, num_parent_ranges); } } prom_adjust_regs(regs, nregs, ranges, num_ranges); } } |