os161-1.99
 All Data Structures
lamebus.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * Machine-independent LAMEbus code.
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 /* Register offsets within each config region */
00042 #define CFGREG_VID   0    /* Vendor ID */
00043 #define CFGREG_DID   4    /* Device ID */
00044 #define CFGREG_DRL   8    /* Device Revision Level */
00045 
00046 /* LAMEbus controller private registers (offsets within its config region) */
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 /* LAMEbus CPU control registers (offsets within each per-cpu region) */
00056 #define CTLCPU_CIRQE    0x000
00057 #define CTLCPU_CIPI     0x004
00058 #define CTLCPU_CRAM     0x300
00059 
00060 
00061 /*
00062  * Read a config register for the given slot.
00063  */
00064 static
00065 inline
00066 uint32_t
00067 read_cfg_register(struct lamebus_softc *lb, int slot, uint32_t offset)
00068 {
00069         /* Note that lb might be NULL on some platforms in some contexts. */
00070         offset += LB_CONFIG_SIZE*slot;
00071         return lamebus_read_register(lb, LB_CONTROLLER_SLOT, offset);
00072 }
00073 
00074 /*
00075  * Write a config register for a given slot.
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  * Read one of the bus controller's registers.
00089  */
00090 static
00091 inline
00092 uint32_t
00093 read_ctl_register(struct lamebus_softc *lb, uint32_t offset)
00094 {
00095         /* Note that lb might be NULL on some platforms in some contexts. */
00096         return read_cfg_register(lb, LB_CONTROLLER_SLOT, offset);
00097 }
00098 
00099 /*
00100  * Write one of the bus controller's registers.
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  * Write one of the bus controller's CPU control registers.
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  * Find and create secondary CPUs.
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          * By default, route all interrupts only to the boot cpu. We
00158          * could be arbitrarily more elaborate, up to things like
00159          * dynamic load balancing.
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  * Start up secondary CPUs.
00175  *
00176  * The first word of the CRAM area is set to the entry point for new
00177  * CPUs; the second to the (software) CPU number. Note that the logic
00178  * here assumes the boot CPU is CPU 0 and the others are 1-N as
00179  * created in the function above. This is fine if all CPUs are on
00180  * LAMEbus; if in some environment there are other CPUs about as well
00181  * this logic will have to be made more complex.
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         /* Poke in the startup address. */
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         /* Now, enable them all. */
00213         write_ctl_register(lamebus, CTLREG_CPUE, cpumask);
00214 }
00215 
00216 /*
00217  * Probe function.
00218  *
00219  * Given a LAMEbus, look for a device that's not already been marked
00220  * in use, has the specified IDs, and has a device revision level in
00221  * the specified range (which is inclusive on both ends.)
00222  *
00223  * Returns the slot number found (0-31) or -1 if nothing suitable was
00224  * found.
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          * Because the slot information in sc is used when dispatching
00237          * interrupts, disable interrupts while working with it.
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                         /* Slot already in use; skip */
00245                         continue;
00246                 }
00247 
00248                 val = read_cfg_register(sc, slot, CFGREG_VID);
00249                 if (val!=vendorid) {
00250                         /* Wrong vendor id */
00251                         continue;
00252                 }
00253 
00254                 val = read_cfg_register(sc, slot, CFGREG_DID);
00255                 if (val != deviceid) {
00256                         /* Wrong device id */
00257                         continue;
00258                 }
00259 
00260                 val = read_cfg_register(sc, slot, CFGREG_DRL);
00261                 if (val < lowver || val > highver) {
00262                         /* Unsupported device revision */
00263                         continue;
00264                 }
00265 
00266                 /* Found something */
00267 
00268                 spinlock_release(&sc->ls_lock);
00269                 return slot;
00270         }
00271 
00272         /* Found nothing */
00273 
00274         spinlock_release(&sc->ls_lock);
00275         return -1;
00276 }
00277 
00278 /*
00279  * Mark that a slot is in use.
00280  * This prevents the probe routine from returning the same device over
00281  * and over again.
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  * Mark that a slot is no longer in use.
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  * Register a function (and a device context pointer) to be called
00322  * when a particular slot signals an interrupt.
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  * Unregister a function that was being called when a particular slot
00350  * signaled an interrupt.
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  * Mask/unmask an interrupt using the global IRQE register.
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  * LAMEbus interrupt handling function. (Machine-independent!)
00405  */
00406 void
00407 lamebus_interrupt(struct lamebus_softc *lamebus)
00408 {
00409         /*
00410          * Note that despite the fact that "spl" stands for "set
00411          * priority level", we don't actually support interrupt
00412          * priorities. When an interrupt happens, we look through the
00413          * slots to find the first interrupting device and call its
00414          * interrupt routine, no matter what that device is.
00415          *
00416          * Note that the entire LAMEbus uses only one on-cpu interrupt line. 
00417          * Thus, we do not use any on-cpu interrupt priority system either.
00418          */
00419 
00420         int slot;
00421         uint32_t mask;
00422         uint32_t irqs;
00423         void (*handler)(void *);
00424         void *data;
00425 
00426         /* For keeping track of how many bogus things happen in a row. */
00427         static int duds = 0;
00428         int duds_this_time = 0;
00429 
00430         /* and we better have a valid bus instance. */
00431         KASSERT(lamebus != NULL);
00432 
00433         /* Lock the softc */
00434         spinlock_acquire(&lamebus->ls_lock);
00435 
00436         /*
00437          * Read the LAMEbus controller register that tells us which
00438          * slots are asserting an interrupt condition.
00439          */
00440         irqs = read_ctl_register(lamebus, CTLREG_IRQS);
00441 
00442         if (irqs == 0) {
00443                 /*
00444                  * Huh? None of them? Must be a glitch.
00445                  */
00446                 kprintf("lamebus: stray interrupt on cpu %u\n",
00447                         curcpu->c_number);
00448                 duds++;
00449                 duds_this_time++;
00450 
00451                 /*
00452                  * We could just return now, but instead we'll
00453                  * continue ahead. Because irqs == 0, nothing in the
00454                  * loop will execute, and passing through it gets us
00455                  * to the code that checks how many duds we've
00456                  * seen. This is important, because we just might get
00457                  * a stray interrupt that latches itself on. If that
00458                  * happens, we're pretty much toast, but it's better
00459                  * to panic and hopefully reset the system than to
00460                  * loop forever printing "stray interrupt".
00461                  */
00462         }
00463 
00464         /*
00465          * Go through the bits in the value we got back to see which
00466          * ones are set.
00467          */
00468 
00469         for (mask=1, slot=0; slot<LB_NSLOTS; mask<<=1, slot++) {
00470                 if ((irqs & mask) == 0) {
00471                         /* Nope. */
00472                         continue;
00473                 }
00474 
00475                 /*
00476                  * This slot is signalling an interrupt.
00477                  */
00478                         
00479                 if ((lamebus->ls_slotsinuse & mask)==0) {
00480                         /*
00481                          * No device driver is using this slot.
00482                          */
00483                         duds++;
00484                         duds_this_time++;
00485                         continue;
00486                 }
00487 
00488                 if (lamebus->ls_irqfuncs[slot]==NULL) {
00489                         /*
00490                          * The device driver hasn't installed an interrupt
00491                          * handler.
00492                          */
00493                         duds++;
00494                         duds_this_time++;
00495                         continue;
00496                 }
00497 
00498                 /*
00499                  * Call the interrupt handler. Release the spinlock
00500                  * while we do so, in case other CPUs are handling
00501                  * interrupts on other devices.
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                  * Reload the mask of pending IRQs - if we just called
00513                  * hardclock, we might not have come back to this
00514                  * context for some time, and it might have changed.
00515                  */
00516 
00517                 irqs = read_ctl_register(lamebus, CTLREG_IRQS);
00518         }
00519 
00520 
00521         /*
00522          * If we get interrupts for a slot with no driver or no
00523          * interrupt handler, it's fairly serious. Because LAMEbus
00524          * uses level-triggered interrupts, if we don't shut off the
00525          * condition, we'll keep getting interrupted continuously and
00526          * the system will make no progress. But we don't know how to
00527          * do that if there's no driver or no interrupt handler.
00528          *
00529          * So, if we get too many dud interrupts, panic, since it's 
00530          * better to panic and reset than to hang.
00531          *
00532          * If we get through here without seeing any duds this time,
00533          * the condition, whatever it was, has gone away. It might be
00534          * some stupid device we don't have a driver for, or it might
00535          * have been an electrical transient. In any case, warn and
00536          * clear the dud count.
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         /* Unlock the softc */
00549         spinlock_release(&lamebus->ls_lock);
00550 }
00551 
00552 /*
00553  * Have the bus controller power the system off.
00554  */
00555 void
00556 lamebus_poweroff(struct lamebus_softc *lamebus)
00557 {
00558         /*
00559          * Write 0 to the power register to shut the system off.
00560          */
00561 
00562         cpu_irqoff();
00563         write_ctl_register(lamebus, CTLREG_PWR, 0);
00564 
00565         /* The power doesn't go off instantly... so halt the cpu. */
00566         cpu_halt();
00567 }
00568 
00569 /*
00570  * Ask the bus controller how much memory we have.
00571  */
00572 uint32_t
00573 lamebus_ramsize(void)
00574 {
00575         /*
00576          * Note that this has to work before bus initialization.
00577          * On machines where lamebus_read_register doesn't work
00578          * before bus initialization, this function can't be used
00579          * for initial RAM size lookup.
00580          */
00581 
00582         return read_ctl_register(NULL, CTLREG_RAMSZ);
00583 }
00584 
00585 /*
00586  * Turn on or off the interprocessor interrupt line for a given CPU.
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  * Initial setup.
00604  * Should be called from mainbus_bootstrap().
00605  */
00606 struct lamebus_softc *
00607 lamebus_init(void)
00608 {
00609         struct lamebus_softc *lamebus;
00610         int i;
00611 
00612         /* Allocate space for lamebus data */
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          * Initialize the LAMEbus data structure.
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 }
 All Data Structures