00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 #include <types.h>
00035 #include <lib.h>
00036 #include <cpu.h>
00037 #include <spinlock.h>
00038 #include <current.h>
00039 #include <lamebus/lamebus.h>
00040 
00041 
00042 #define CFGREG_VID   0    
00043 #define CFGREG_DID   4    
00044 #define CFGREG_DRL   8    
00045 
00046 
00047 #define CTLREG_RAMSZ    0x200
00048 #define CTLREG_IRQS     0x204
00049 #define CTLREG_PWR      0x208
00050 #define CTLREG_IRQE     0x20c
00051 #define CTLREG_CPUS     0x210
00052 #define CTLREG_CPUE     0x214
00053 #define CTLREG_SELF     0x218
00054 
00055 
00056 #define CTLCPU_CIRQE    0x000
00057 #define CTLCPU_CIPI     0x004
00058 #define CTLCPU_CRAM     0x300
00059 
00060 
00061 
00062 
00063 
00064 static
00065 inline
00066 uint32_t
00067 read_cfg_register(struct lamebus_softc *lb, int slot, uint32_t offset)
00068 {
00069         
00070         offset += LB_CONFIG_SIZE*slot;
00071         return lamebus_read_register(lb, LB_CONTROLLER_SLOT, offset);
00072 }
00073 
00074 
00075 
00076 
00077 static
00078 inline
00079 void
00080 write_cfg_register(struct lamebus_softc *lb, int slot, uint32_t offset,
00081                    uint32_t val)
00082 {
00083         offset += LB_CONFIG_SIZE*slot;
00084         lamebus_write_register(lb, LB_CONTROLLER_SLOT, offset, val);
00085 }
00086 
00087 
00088 
00089 
00090 static
00091 inline
00092 uint32_t
00093 read_ctl_register(struct lamebus_softc *lb, uint32_t offset)
00094 {
00095         
00096         return read_cfg_register(lb, LB_CONTROLLER_SLOT, offset);
00097 }
00098 
00099 
00100 
00101 
00102 static
00103 inline
00104 void
00105 write_ctl_register(struct lamebus_softc *lb, uint32_t offset, uint32_t val)
00106 {
00107         write_cfg_register(lb, LB_CONTROLLER_SLOT, offset, val);
00108 }
00109 
00110 
00111 
00112 
00113 static
00114 inline
00115 void
00116 write_ctlcpu_register(struct lamebus_softc *lb, unsigned hw_cpunum,
00117                       uint32_t offset, uint32_t val)
00118 {
00119         offset += LB_CTLCPU_OFFSET + hw_cpunum * LB_CTLCPU_SIZE;
00120         lamebus_write_register(lb, LB_CONTROLLER_SLOT, offset, val);
00121 }
00122 
00123 
00124 
00125 
00126 void
00127 lamebus_find_cpus(struct lamebus_softc *lamebus)
00128 {
00129         uint32_t cpumask, self, bit, val;
00130         unsigned i, numcpus, bootcpu;
00131         unsigned hwnum[32];
00132 
00133         cpumask = read_ctl_register(lamebus, CTLREG_CPUS);
00134         self = read_ctl_register(lamebus, CTLREG_SELF);
00135 
00136         numcpus = 0;
00137         bootcpu = 0;
00138         for (i=0; i<32; i++) {
00139                 bit = (uint32_t)1 << i;
00140                 if ((cpumask & bit) != 0) {
00141                         if (self & bit) {
00142                                 bootcpu = numcpus;
00143                                 curcpu->c_hardware_number = i;
00144                         }
00145                         hwnum[numcpus] = i;
00146                         numcpus++;
00147                 }
00148         }
00149 
00150         for (i=0; i<numcpus; i++) {
00151                 if (i != bootcpu) {
00152                         cpu_create(hwnum[i]);
00153                 }
00154         }
00155 
00156         
00157 
00158 
00159 
00160 
00161 
00162         for (i=0; i<numcpus; i++) {
00163                 if (i != bootcpu) {
00164                         val = 0;
00165                 }
00166                 else {
00167                         val = 0xffffffff;
00168                 }
00169                 write_ctlcpu_register(lamebus, hwnum[i], CTLCPU_CIRQE, val);
00170         }
00171 }
00172 
00173 
00174 
00175 
00176 
00177 
00178 
00179 
00180 
00181 
00182 
00183 void
00184 lamebus_start_cpus(struct lamebus_softc *lamebus)
00185 {
00186         uint32_t cpumask, self, bit;
00187         uint32_t ctlcpuoffset;
00188         uint32_t *cram;
00189         unsigned i;
00190         unsigned cpunum;
00191 
00192         cpumask = read_ctl_register(lamebus, CTLREG_CPUS);
00193         self = read_ctl_register(lamebus, CTLREG_SELF);
00194 
00195         
00196         cpunum = 1;
00197         for (i=0; i<32; i++) {
00198                 bit = (uint32_t)1 << i;
00199                 if ((cpumask & bit) != 0) {
00200                         if (self & bit) {
00201                                 continue;
00202                         }
00203                         ctlcpuoffset = LB_CTLCPU_OFFSET + i * LB_CTLCPU_SIZE;
00204                         cram = lamebus_map_area(lamebus,
00205                                                 LB_CONTROLLER_SLOT,
00206                                                 ctlcpuoffset + CTLCPU_CRAM);
00207                         cram[0] = (uint32_t)cpu_start_secondary;
00208                         cram[1] = cpunum++;
00209                 }
00210         }
00211 
00212         
00213         write_ctl_register(lamebus, CTLREG_CPUE, cpumask);
00214 }
00215 
00216 
00217 
00218 
00219 
00220 
00221 
00222 
00223 
00224 
00225 
00226 
00227 int
00228 lamebus_probe(struct lamebus_softc *sc,
00229               uint32_t vendorid, uint32_t deviceid,
00230               uint32_t lowver, uint32_t highver)
00231 {
00232         int slot;
00233         uint32_t val;
00234 
00235         
00236 
00237 
00238 
00239 
00240         spinlock_acquire(&sc->ls_lock);
00241 
00242         for (slot=0; slot<LB_NSLOTS; slot++) {
00243                 if (sc->ls_slotsinuse & (1<<slot)) {
00244                         
00245                         continue;
00246                 }
00247 
00248                 val = read_cfg_register(sc, slot, CFGREG_VID);
00249                 if (val!=vendorid) {
00250                         
00251                         continue;
00252                 }
00253 
00254                 val = read_cfg_register(sc, slot, CFGREG_DID);
00255                 if (val != deviceid) {
00256                         
00257                         continue;
00258                 }
00259 
00260                 val = read_cfg_register(sc, slot, CFGREG_DRL);
00261                 if (val < lowver || val > highver) {
00262                         
00263                         continue;
00264                 }
00265 
00266                 
00267 
00268                 spinlock_release(&sc->ls_lock);
00269                 return slot;
00270         }
00271 
00272         
00273 
00274         spinlock_release(&sc->ls_lock);
00275         return -1;
00276 }
00277 
00278 
00279 
00280 
00281 
00282 
00283 void
00284 lamebus_mark(struct lamebus_softc *sc, int slot)
00285 {
00286         uint32_t mask = ((uint32_t)1) << slot;
00287         KASSERT(slot>=0 && slot < LB_NSLOTS);
00288 
00289         spinlock_acquire(&sc->ls_lock);
00290 
00291         if ((sc->ls_slotsinuse & mask)!=0) {
00292                 panic("lamebus_mark: slot %d already in use\n", slot);
00293         }
00294 
00295         sc->ls_slotsinuse |= mask;
00296 
00297         spinlock_release(&sc->ls_lock);
00298 }
00299 
00300 
00301 
00302 
00303 void
00304 lamebus_unmark(struct lamebus_softc *sc, int slot)
00305 {
00306         uint32_t mask = ((uint32_t)1) << slot;
00307         KASSERT(slot>=0 && slot < LB_NSLOTS);
00308 
00309         spinlock_acquire(&sc->ls_lock);
00310 
00311         if ((sc->ls_slotsinuse & mask)==0) {
00312                 panic("lamebus_mark: slot %d not marked in use\n", slot);
00313         }
00314 
00315         sc->ls_slotsinuse &= ~mask;
00316 
00317         spinlock_release(&sc->ls_lock);
00318 }
00319 
00320 
00321 
00322 
00323 
00324 void
00325 lamebus_attach_interrupt(struct lamebus_softc *sc, int slot,
00326                          void *devdata,
00327                          void (*irqfunc)(void *devdata))
00328 {
00329         uint32_t mask = ((uint32_t)1) << slot;
00330         KASSERT(slot>=0 && slot < LB_NSLOTS);
00331 
00332         spinlock_acquire(&sc->ls_lock);
00333 
00334         if ((sc->ls_slotsinuse & mask)==0) {
00335                 panic("lamebus_attach_interrupt: slot %d not marked in use\n",
00336                       slot);
00337         }
00338 
00339         KASSERT(sc->ls_devdata[slot]==NULL);
00340         KASSERT(sc->ls_irqfuncs[slot]==NULL);
00341 
00342         sc->ls_devdata[slot] = devdata;
00343         sc->ls_irqfuncs[slot] = irqfunc;
00344         
00345         spinlock_release(&sc->ls_lock);
00346 }
00347 
00348 
00349 
00350 
00351 
00352 void
00353 lamebus_detach_interrupt(struct lamebus_softc *sc, int slot)
00354 {
00355         uint32_t mask = ((uint32_t)1) << slot;
00356         KASSERT(slot>=0 && slot < LB_NSLOTS);
00357 
00358         spinlock_acquire(&sc->ls_lock);
00359 
00360         if ((sc->ls_slotsinuse & mask)==0) {
00361                 panic("lamebus_detach_interrupt: slot %d not marked in use\n",
00362                       slot);
00363         }
00364 
00365         KASSERT(sc->ls_irqfuncs[slot]!=NULL);
00366 
00367         sc->ls_devdata[slot] = NULL;
00368         sc->ls_irqfuncs[slot] = NULL;
00369         
00370         spinlock_release(&sc->ls_lock);
00371 }
00372 
00373 
00374 
00375 
00376 void
00377 lamebus_mask_interrupt(struct lamebus_softc *lamebus, int slot)
00378 {
00379         uint32_t bits, mask = ((uint32_t)1) << slot;
00380         KASSERT(slot >= 0 && slot < LB_NSLOTS);
00381 
00382         spinlock_acquire(&lamebus->ls_lock);
00383         bits = read_ctl_register(lamebus, CTLREG_IRQE);
00384         bits &= ~mask;
00385         write_ctl_register(lamebus, CTLREG_IRQE, bits);
00386         spinlock_release(&lamebus->ls_lock);
00387 }
00388 
00389 void
00390 lamebus_unmask_interrupt(struct lamebus_softc *lamebus, int slot)
00391 {
00392         uint32_t bits, mask = ((uint32_t)1) << slot;
00393         KASSERT(slot >= 0 && slot < LB_NSLOTS);
00394 
00395         spinlock_acquire(&lamebus->ls_lock);
00396         bits = read_ctl_register(lamebus, CTLREG_IRQE);
00397         bits |= mask;
00398         write_ctl_register(lamebus, CTLREG_IRQE, bits);
00399         spinlock_release(&lamebus->ls_lock);
00400 }
00401 
00402 
00403 
00404 
00405 
00406 void
00407 lamebus_interrupt(struct lamebus_softc *lamebus)
00408 {
00409         
00410 
00411 
00412 
00413 
00414 
00415 
00416 
00417 
00418 
00419 
00420         int slot;
00421         uint32_t mask;
00422         uint32_t irqs;
00423         void (*handler)(void *);
00424         void *data;
00425 
00426         
00427         static int duds = 0;
00428         int duds_this_time = 0;
00429 
00430         
00431         KASSERT(lamebus != NULL);
00432 
00433         
00434         spinlock_acquire(&lamebus->ls_lock);
00435 
00436         
00437 
00438 
00439 
00440         irqs = read_ctl_register(lamebus, CTLREG_IRQS);
00441 
00442         if (irqs == 0) {
00443                 
00444 
00445 
00446                 kprintf("lamebus: stray interrupt on cpu %u\n",
00447                         curcpu->c_number);
00448                 duds++;
00449                 duds_this_time++;
00450 
00451                 
00452 
00453 
00454 
00455 
00456 
00457 
00458 
00459 
00460 
00461 
00462         }
00463 
00464         
00465 
00466 
00467 
00468 
00469         for (mask=1, slot=0; slot<LB_NSLOTS; mask<<=1, slot++) {
00470                 if ((irqs & mask) == 0) {
00471                         
00472                         continue;
00473                 }
00474 
00475                 
00476 
00477 
00478                         
00479                 if ((lamebus->ls_slotsinuse & mask)==0) {
00480                         
00481 
00482 
00483                         duds++;
00484                         duds_this_time++;
00485                         continue;
00486                 }
00487 
00488                 if (lamebus->ls_irqfuncs[slot]==NULL) {
00489                         
00490 
00491 
00492 
00493                         duds++;
00494                         duds_this_time++;
00495                         continue;
00496                 }
00497 
00498                 
00499 
00500 
00501 
00502 
00503                 handler = lamebus->ls_irqfuncs[slot];
00504                 data = lamebus->ls_devdata[slot];
00505                 spinlock_release(&lamebus->ls_lock);
00506 
00507                 handler(data);
00508 
00509                 spinlock_acquire(&lamebus->ls_lock);
00510 
00511                 
00512 
00513 
00514 
00515 
00516 
00517                 irqs = read_ctl_register(lamebus, CTLREG_IRQS);
00518         }
00519 
00520 
00521         
00522 
00523 
00524 
00525 
00526 
00527 
00528 
00529 
00530 
00531 
00532 
00533 
00534 
00535 
00536 
00537 
00538 
00539         if (duds_this_time == 0 && duds > 0) {
00540                 kprintf("lamebus: %d dud interrupts\n", duds);
00541                 duds = 0;
00542         }
00543 
00544         if (duds > 10000) {
00545                 panic("lamebus: too many (%d) dud interrupts\n", duds);
00546         }
00547 
00548         
00549         spinlock_release(&lamebus->ls_lock);
00550 }
00551 
00552 
00553 
00554 
00555 void
00556 lamebus_poweroff(struct lamebus_softc *lamebus)
00557 {
00558         
00559 
00560 
00561 
00562         cpu_irqoff();
00563         write_ctl_register(lamebus, CTLREG_PWR, 0);
00564 
00565         
00566         cpu_halt();
00567 }
00568 
00569 
00570 
00571 
00572 uint32_t
00573 lamebus_ramsize(void)
00574 {
00575         
00576 
00577 
00578 
00579 
00580 
00581 
00582         return read_ctl_register(NULL, CTLREG_RAMSZ);
00583 }
00584 
00585 
00586 
00587 
00588 void
00589 lamebus_assert_ipi(struct lamebus_softc *lamebus, struct cpu *target)
00590 {
00591         write_ctlcpu_register(lamebus, target->c_hardware_number,
00592                               CTLCPU_CIPI, 1);
00593 }
00594 
00595 void
00596 lamebus_clear_ipi(struct lamebus_softc *lamebus, struct cpu *target)
00597 {
00598         write_ctlcpu_register(lamebus, target->c_hardware_number,
00599                               CTLCPU_CIPI, 0);
00600 }
00601 
00602 
00603 
00604 
00605 
00606 struct lamebus_softc *
00607 lamebus_init(void)
00608 {
00609         struct lamebus_softc *lamebus;
00610         int i;
00611 
00612         
00613         lamebus = kmalloc(sizeof(struct lamebus_softc));
00614         if (lamebus==NULL) {
00615                 panic("lamebus_init: Out of memory\n");
00616         }
00617 
00618         spinlock_init(&lamebus->ls_lock);
00619 
00620         
00621 
00622 
00623         lamebus->ls_slotsinuse = 1 << LB_CONTROLLER_SLOT;
00624 
00625         for (i=0; i<LB_NSLOTS; i++) {
00626                 lamebus->ls_devdata[i] = NULL;
00627                 lamebus->ls_irqfuncs[i] = NULL;
00628         }
00629 
00630         return lamebus;
00631 }