/* * Initialize fixed idt vectors for use by local apic. */ void lapic_boot_init(paddr_t lapic_base) { static int clk_irq = 0; #ifdef MULTIPROCESSOR static int ipi_irq = 0; #endif lapic_map(lapic_base); #ifdef MULTIPROCESSOR idt_vec_set(LAPIC_IPI_VECTOR, Xintripi); idt_vec_set(LAPIC_IPI_INVLTLB, Xintripi_invltlb); idt_vec_set(LAPIC_IPI_INVLPG, Xintripi_invlpg); idt_vec_set(LAPIC_IPI_INVLRANGE, Xintripi_invlrange); idt_vec_set(LAPIC_IPI_RELOADCR3, Xintripi_reloadcr3); #endif idt_vec_set(LAPIC_SPURIOUS_VECTOR, Xintrspurious); idt_vec_set(LAPIC_TIMER_VECTOR, Xintrltimer); evcount_attach(&clk_count, "clock", &clk_irq); #ifdef MULTIPROCESSOR evcount_attach(&ipi_count, "ipi", &ipi_irq); #endif }
void * iof_intr_establish(void *cookie, uint dev, int level, int (*func)(void *), void *arg, char *name) { struct iof_softc *sc = cookie; struct iof_intr *ii; if (dev < 0 || dev >= IOC4_NDEVS) return NULL; if (ioc4_intrbits[dev].sio == 0 && ioc4_intrbits[dev].other == 0) return NULL; ii = (struct iof_intr *)malloc(sizeof(*ii), M_DEVBUF, M_NOWAIT); if (ii == NULL) return NULL; ii->ii_iof = sc; ii->ii_func = func; ii->ii_arg = arg; ii->ii_level = level; evcount_attach(&ii->ii_count, name, &ii->ii_level); sc->sc_intr[dev] = ii; /* enable hardware source if necessary */ bus_space_write_4(sc->sc_memt, sc->sc_memh, IOC4_SIO_IES, ioc4_intrbits[dev].sio); bus_space_write_4(sc->sc_memt, sc->sc_memh, IOC4_OTHER_IES, ioc4_intrbits[dev].other); return (ii); }
void vsaudio_attach(struct device *parent, struct device *self, void *aux) { struct vsbus_attach_args *va = aux; struct vsaudio_softc *sc = (struct vsaudio_softc *)self; if (bus_space_map(va->va_iot, va->va_paddr, AM7930_DREG_SIZE << 2, 0, &sc->sc_bh) != 0) { printf(": can't map registers\n"); return; } sc->sc_bt = va->va_iot; /* * Set up glue for MI code early; we use some of it here. */ sc->sc_am7930.sc_glue = &vsaudio_glue; am7930_init(&sc->sc_am7930, AUDIOAMD_POLL_MODE); scb_vecalloc(va->va_cvec, vsaudio_hwintr, sc, SCB_ISTACK, &sc->sc_intrcnt); sc->sc_cvec = va->va_cvec; evcount_attach(&sc->sc_intrcnt, self->dv_xname, &sc->sc_cvec); sc->sc_swintr = softintr_establish(IPL_SOFT, &vsaudio_swintr, sc); printf("\n"); audio_attach_mi(&vsaudio_hw_if, sc, &sc->sc_am7930.sc_dev); }
/* * hdc_attach() probes for all possible devices */ void hdcattach(struct device *parent, struct device *self, void *aux) { struct vsbus_attach_args *va = aux; struct hdcsoftc *sc = (void *)self; struct hdc_attach_args ha; int status, i; u = 0; /* !!! - GCC */ printf("\n"); /* * Get interrupt vector, enable instrumentation. */ scb_vecalloc(va->va_cvec, hdcintr, sc, SCB_ISTACK, &sc->sc_intrcnt); evcount_attach(&sc->sc_intrcnt, self->dv_xname, (void *)va->va_cvec); sc->sc_regs = vax_map_physmem(va->va_paddr, 1); sc->sc_dmabase = (caddr_t)va->va_dmaaddr; sc->sc_dmasize = va->va_dmasize; sc->sc_intbit = va->va_maskno; hd_dmasize = min(MAXPHYS, sc->sc_dmasize); /* Used in hd_minphys */ sc->sc_vd.vd_go = hdc_qstart; sc->sc_vd.vd_arg = sc; /* * Reset controller. */ HDC_WCMD(DKC_CMD_RESET); DELAY(1000); status = HDC_RSTAT; if (status != (DKC_ST_DONE|DKC_TC_SUCCESS)) { printf("%s: RESET failed, status 0x%x\n", sc->sc_dev.dv_xname, status); return; } /* * now probe for all possible hard drives */ for (i = 0; i < 4; i++) { if (i == 2) /* Floppy, needs special handling */ continue; HDC_WCMD(DKC_CMD_DRSELECT | i); DELAY(1000); status = HDC_RSTAT; ha.ha_drive = i; if ((status & DKC_ST_TERMCOD) == DKC_TC_SUCCESS) config_found(self, (void *)&ha, hdcprint); } }
void evcount_init(void) { #ifndef __LP64__ static struct timeout ec_to; timeout_set(&ec_to, evcount_timeout, &ec_to); timeout_add(&ec_to, hz); #endif TAILQ_INIT(&evcount_list); evcount_attach(&evcount_intr, "intr", NULL, NULL); }
void * omgpio_intr_establish(unsigned int gpio, int level, int spl, int (*func)(void *), void *arg, char *name) { int psw; struct intrhand *ih; struct omgpio_softc *sc; /* * XXX - is gpio here the pin or the interrupt number * which is 96 + gpio pin? */ if (GPIO_PIN_TO_INST(gpio) > NOMGPIO) panic("omgpio_intr_establish: bogus irqnumber %d: %s", gpio, name); sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; if (sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] != NULL) panic("omgpio_intr_establish: gpio pin busy %d old %s new %s", gpio, sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)]->ih_name, name); psw = disable_interrupts(I32_bit); /* no point in sleeping unless someone can free memory. */ ih = (struct intrhand *)malloc( sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); if (ih == NULL) panic("intr_establish: can't malloc handler info"); ih->ih_func = func; ih->ih_arg = arg; ih->ih_ipl = level; ih->ih_gpio = gpio; ih->ih_irq = gpio + INTC_NUM_IRQ; ih->ih_name = name; sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] = ih; evcount_attach(&ih->ih_count, name, &ih->ih_irq); omgpio_intr_level(gpio, level); omgpio_intr_unmask(gpio); omgpio_recalc_interrupts(sc); restore_interrupts(psw); return (ih); }
/* * Establish an interrupt handler called from the dispatcher. * The interrupt function established should return zero if there was nothing * to serve (no int) and non-zero when an interrupt was serviced. * * Interrupts are numbered from 1 and up where 1 maps to HW int 0. * XXX There is no reason to keep this... except for hardcoded interrupts * XXX in kernel configuration files... */ void * macebus_intr_establish(int irq, uint32_t mace_irqmask, int type, int level, int (*ih_fun)(void *), void *ih_arg, const char *ih_what) { struct crime_intrhand **p, *q, *ih; int s; #ifdef DIAGNOSTIC if (irq >= CRIME_NINTS || irq < 0) panic("intr_establish: illegal irq %d", irq); #endif ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT); if (ih == NULL) return NULL; ih->ih.ih_next = NULL; ih->ih.ih_fun = ih_fun; ih->ih.ih_arg = ih_arg; ih->ih.ih_level = level; ih->ih.ih_irq = irq; ih->mace_irqmask = mace_irqmask; evcount_attach(&ih->ih.ih_count, ih_what, &ih->ih.ih_irq); s = splhigh(); /* * Figure out where to put the handler. * This is O(N^2), but we want to preserve the order, and N is * generally small. */ for (p = &crime_intrhand[irq]; (q = *p) != NULL; p = (struct crime_intrhand **)&q->ih.ih_next) ; *p = ih; crime_intem |= 1UL << irq; macebus_intr_makemasks(); /* enable further MACE sources if necessary */ if (mace_irqmask != 0) { mace_intem |= mace_irqmask; bus_space_write_8(&macebus_tag, mace_h, MACE_ISA_INT_MASK, mace_intem); } splx(s); /* causes hw mask update */ return (ih); }
void clockattach(struct device *parent, struct device *self, void *aux) { printf(": int 5\n"); /* * We need to register the interrupt now, for idle_mask to * be computed correctly. */ set_intr(INTPRI_CLOCK, CR_INT_5, cp0_int5); evcount_attach(&cp0_clock_count, "clock", &cp0_clock_irq); /* try to avoid getting clock interrupts early */ cp0_set_compare(cp0_get_count() - 1); md_startclock = cp0_startclock; }
/* * Establish an interrupt handler called from the dispatcher. * The interrupt function established should return zero if there was nothing * to serve (no int) and non-zero when an interrupt was serviced. * * Interrupts are numbered from 1 and up where 1 maps to HW int 0. * XXX There is no reason to keep this... except for hardcoded interrupts * XXX in kernel configuration files... */ void * obio_intr_establish(int irq, int level, int (*ih_fun)(void *), void *ih_arg, const char *ih_what) { int cpuid = cpu_number(); struct intrhand **p, *q, *ih; int s; #ifdef DIAGNOSTIC if (irq >= OBIO_NINTS || irq < 0) panic("intr_establish: illegal irq %d", irq); #endif ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT); if (ih == NULL) return NULL; ih->ih_next = NULL; ih->ih_fun = ih_fun; ih->ih_arg = ih_arg; ih->ih_level = level; ih->ih_irq = irq; evcount_attach(&ih->ih_count, ih_what, (void *)&ih->ih_irq); s = splhigh(); /* * Figure out where to put the handler. * This is O(N^2), but we want to preserve the order, and N is * generally small. */ for (p = &obio_intrhand[irq]; (q = *p) != NULL; p = (struct intrhand **)&q->ih_next) ; *p = ih; obio_intem[cpuid] |= 1UL << irq; obio_intr_makemasks(); splx(s); /* causes hw mask update */ return (ih); }
void * voyager_intr_establish(void *cookie, int irq, int level, int (*fun)(void *), void *arg, const char *name) { struct voyager_softc *sc = (struct voyager_softc *)cookie; struct intrhand *prevh, *nh; uint32_t imr; #ifdef DIAGNOSTIC if (irq < 0 || irq >= nitems(sc->sc_intr)) return NULL; #endif nh = (struct intrhand *)malloc(sizeof *nh, M_DEVBUF, M_NOWAIT | M_ZERO); if (nh == NULL) return NULL; nh->ih_fun = fun; nh->ih_arg = arg; nh->ih_level = level; nh->ih_irq = irq + BONITO_NINTS; evcount_attach(&nh->ih_count, name, &nh->ih_irq); if (sc->sc_intr[irq] == NULL) sc->sc_intr[irq] = nh; else { /* insert at tail */ for (prevh = sc->sc_intr[irq]; prevh->ih_next != NULL; prevh = prevh->ih_next) ; prevh->ih_next = nh; } /* enable interrupt source */ imr = bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, VOYAGER_IMR); imr |= 1 << irq; bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, VOYAGER_IMR, imr); (void)bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, VOYAGER_IMR); return nh; }
/* * Register a C-bus interrupt service routine. */ int cbus_isrlink(int (*func)(void *), void *arg, int intlevel, int ipl, const char *name) { struct cbus_softc *sc = NULL; struct cbus_isr_t *ci; if (cbus_cd.cd_ndevs != 0) sc = cbus_cd.cd_devs[0]; if (sc == NULL) panic("cbus_isrlink: can't find cbus_softc"); #ifdef DIAGNOSTIC if (intlevel < 0 || intlevel >= NCBUSISR) { printf("cbus_isrlink: bad INT level %d\n", intlevel); return -1; } #endif ci = &sc->cbus_isr[intlevel]; if (ci->isr_func != NULL) { printf("cbus_isrlink: isr already assigned on INT%d\n", intlevel); return -1; } /* set the entry */ ci->isr_func = func; ci->isr_arg = arg; ci->isr_intlevel = intlevel; ci->isr_ipl = ipl; evcount_attach(&ci->isr_count, name, &ci->isr_intlevel); sc->registered |= (1 << (6 - intlevel)); #ifdef CBUS_DEBUG printf("cbus_isrlink: sc->registered = 0x%02x\n", sc->registered); #endif return 0; }
/* * Start the real-time and statistics clocks. Leave stathz 0 since there * are no other timers available. */ void cpu_initclocks() { struct clock_softc *sc = (struct clock_softc *)clock_cd.cd_devs[0]; hz = sc->sc_clock.clk_hz; stathz = sc->sc_clock.clk_stathz; profhz = sc->sc_clock.clk_profhz; evcount_attach(&clk_count, "clock", (void *)&clk_irq, &evcount_intr); /* Start the clock. */ if (sc->sc_clock.clk_init != NULL) (*sc->sc_clock.clk_init)(sc); tick = 1000000 / hz; /* number of micro-seconds between interrupts */ tickadj = 240000 / (60 * hz); /* can adjust 240ms in 60s */ cp0_timecounter.tc_frequency = sys_config.cpu[0].clock / 2; tc_init(&cp0_timecounter); clock_started++; }
int vmeintr_establish(u_int vec, struct intrhand *ih, const char *name) { struct intrhand *intr; intrhand_t *list; list = &vmeintr_handlers[vec]; intr = SLIST_FIRST(list); if (intr != NULL) { if (intr->ih_ipl != ih->ih_ipl) { #ifdef DIAGNOSTIC printf("%s: can't use ipl %d for vector %x," " it uses ipl %d\n", __func__, ih->ih_ipl, vec, intr->ih_ipl); #endif return EINVAL; } if (ISSET(intr->ih_flags, INTR_EXCLUSIVE) || ISSET(ih->ih_flags, INTR_EXCLUSIVE)) { #ifdef DIAGNOSTIC printf("%s: can't share vector %x\n", __func__, vec); #endif return EINVAL; } } evcount_attach(&ih->ih_count, name, &ih->ih_ipl); SLIST_INSERT_HEAD(list, ih, ih_link); /* * Enable VME interrupt source for this level. */ intsrc_enable(INTSRC_VME(ih->ih_ipl), ih->ih_ipl); return 0; }
/* * Establish an autovectored interrupt handler. * Called by driver attach functions. */ void isrlink_autovec(int (*func)(void *), void *arg, int ipl, int priority, const char *name) { struct isr_autovec *newisr, *curisr; isr_autovec_list_t *list; #ifdef DIAGNOSTIC if (ipl < 0 || ipl >= NISRAUTOVEC) panic("isrlink_autovec: bad ipl %d", ipl); #endif newisr = (struct isr_autovec *)malloc(sizeof(struct isr_autovec), M_DEVBUF, M_NOWAIT); if (newisr == NULL) panic("isrlink_autovec: can't allocate space for isr"); /* Fill in the new entry. */ newisr->isr_func = func; newisr->isr_arg = arg; newisr->isr_ipl = ipl; newisr->isr_priority = priority; evcount_attach(&newisr->isr_count, name, (void *)&newisr->isr_ipl, &evcount_intr); /* * Some devices are particularly sensitive to interrupt * handling latency. The SCC, for example, can lose many * characters if its interrupt isn't handled with reasonable * speed. * * To work around this problem, each device can give itself a * "priority". An unbuffered SCC would give itself a higher * priority than a SCSI device, for example. * * This solution was originally developed for the hp300, which * has a flat spl scheme (by necessity). Thankfully, the * MVME systems don't have this problem, though this may serve * a useful purpose in any case. */ /* * Get the appropriate ISR list. If the list is empty, no * additional work is necessary; we simply insert ourselves * at the head of the list. */ list = &isr_autovec[ipl]; if (list->lh_first == NULL) { LIST_INSERT_HEAD(list, newisr, isr_link); return; } /* * A little extra work is required. We traverse the list * and place ourselves after any ISRs with our current (or * higher) priority. */ for (curisr = LIST_FIRST(list); LIST_NEXT(curisr, isr_link) != NULL; curisr = LIST_NEXT(curisr, isr_link)) { if (newisr->isr_priority > curisr->isr_priority) { LIST_INSERT_BEFORE(curisr, newisr, isr_link); return; } } /* * We're the least important entry, it seems. We just go * on the end. */ LIST_INSERT_AFTER(curisr, newisr, isr_link); }
void * apic_intr_establish(void *v, pci_intr_handle_t ih, int pri, int (*handler)(void *), void *arg, const char *name) { struct elroy_softc *sc = v; volatile struct elroy_regs *r = sc->sc_regs; hppa_hpa_t hpa = cpu_gethpa(0); struct evcount *cnt; struct apic_iv *aiv, *biv; void *iv; int irq = APIC_INT_IRQ(ih); int line = APIC_INT_LINE(ih); u_int32_t ent0; /* no mapping or bogus */ if (irq <= 0 || irq > 63) return (NULL); aiv = malloc(sizeof(struct apic_iv), M_DEVBUF, M_NOWAIT); if (aiv == NULL) { free(cnt, M_DEVBUF, 0); return NULL; } aiv->sc = sc; aiv->ih = ih; aiv->handler = handler; aiv->arg = arg; aiv->next = NULL; aiv->cnt = NULL; if (apic_intr_list[irq]) { cnt = malloc(sizeof(struct evcount), M_DEVBUF, M_NOWAIT); if (!cnt) { free(aiv, M_DEVBUF, 0); return (NULL); } evcount_attach(cnt, name, NULL); biv = apic_intr_list[irq]; while (biv->next) biv = biv->next; biv->next = aiv; aiv->cnt = cnt; return (arg); } if ((iv = cpu_intr_establish(pri, irq, apic_intr, aiv, name))) { ent0 = (63 - irq) & APIC_ENT0_VEC; ent0 |= apic_get_int_ent0(sc, line); #if 0 if (cold) { sc->sc_imr |= (1 << irq); ent0 |= APIC_ENT0_MASK; } #endif apic_write(sc->sc_regs, APIC_ENT0(line), APIC_ENT0_MASK); apic_write(sc->sc_regs, APIC_ENT1(line), ((hpa & 0x0ff00000) >> 4) | ((hpa & 0x000ff000) << 12)); apic_write(sc->sc_regs, APIC_ENT0(line), ent0); /* Signal EOI. */ elroy_write32(&r->apic_eoi, htole32((63 - irq) & APIC_ENT0_VEC)); apic_intr_list[irq] = aiv; }
void amptimer_attach(struct device *parent, struct device *self, void *args) { struct amptimer_softc *sc = (struct amptimer_softc *)self; struct cortex_attach_args *ia = args; bus_space_handle_t ioh, pioh; sc->sc_iot = ia->ca_iot; if (bus_space_map(sc->sc_iot, ia->ca_periphbase + GTIMER_ADDR, GTIMER_SIZE, 0, &ioh)) panic("amptimer_attach: bus_space_map global timer failed!"); if (bus_space_map(sc->sc_iot, ia->ca_periphbase + PTIMER_ADDR, PTIMER_SIZE, 0, &pioh)) panic("amptimer_attach: bus_space_map priv timer failed!"); sc->sc_ticks_per_second = amptimer_frequency; printf(": tick rate %d KHz\n", sc->sc_ticks_per_second /1000); sc->sc_ioh = ioh; sc->sc_pioh = pioh; /* disable global timer */ bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, 0); /* XXX ??? reset counters to 0 - gives us uptime in the counter */ bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_LOW, 0); bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_HIGH, 0); /* enable global timer */ bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, GTIMER_CTRL_TIMER); #if defined(USE_GTIMER_CMP) /* clear event */ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_STATUS, 1); #else bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL, 0); bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS, PTIMER_STATUS_EVENT); #endif #ifdef AMPTIMER_DEBUG evcount_attach(&sc->sc_clk_count, "clock", NULL); evcount_attach(&sc->sc_stat_count, "stat", NULL); #endif /* * private timer and interrupts not enabled until * timer configures */ arm_clock_register(amptimer_cpu_initclocks, amptimer_delay, amptimer_setstatclockrate, amptimer_startclock); amptimer_timecounter.tc_frequency = sc->sc_ticks_per_second; amptimer_timecounter.tc_priv = sc; tc_init(&timer_timecounter); }
/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */ void qeattach(struct device *parent, struct device *self, void *aux) { struct uba_attach_args *ua = aux; struct uba_softc *ubasc = (struct uba_softc *)parent; struct qe_softc *sc = (struct qe_softc *)self; struct ifnet *ifp = (struct ifnet *)&sc->sc_if; struct qe_ring *rp; int i, error; sc->sc_iot = ua->ua_iot; sc->sc_ioh = ua->ua_ioh; sc->sc_dmat = ua->ua_dmat; /* * Allocate DMA safe memory for descriptors and setup memory. */ sc->sc_ui.ui_size = sizeof(struct qe_cdata); if ((error = ubmemalloc((struct uba_softc *)parent, &sc->sc_ui, 0))) { printf(": unable to ubmemalloc(), error = %d\n", error); return; } sc->sc_pqedata = (struct qe_cdata *)sc->sc_ui.ui_baddr; sc->sc_qedata = (struct qe_cdata *)sc->sc_ui.ui_vaddr; /* * Zero the newly allocated memory. */ bzero(sc->sc_qedata, sizeof(struct qe_cdata)); /* * Create the transmit descriptor DMA maps. We take advantage * of the fact that the Qbus address space is big, and therefore * allocate map registers for all transmit descriptors also, * so that we can avoid this each time we send a packet. */ for (i = 0; i < TXDESCS; i++) { if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &sc->sc_xmtmap[i]))) { printf(": unable to create tx DMA map %d, error = %d\n", i, error); goto fail_4; } } /* * Create receive buffer DMA maps. */ for (i = 0; i < RXDESCS; i++) { if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, BUS_DMA_NOWAIT, &sc->sc_rcvmap[i]))) { printf(": unable to create rx DMA map %d, error = %d\n", i, error); goto fail_5; } } /* * Pre-allocate the receive buffers. */ for (i = 0; i < RXDESCS; i++) { if ((error = qe_add_rxbuf(sc, i)) != 0) { printf(": unable to allocate or map rx buffer %d\n," " error = %d\n", i, error); goto fail_6; } } /* * Create ring loops of the buffer chains. * This is only done once. */ rp = sc->sc_qedata->qc_recv; rp[RXDESCS].qe_addr_lo = LOWORD(&sc->sc_pqedata->qc_recv[0]); rp[RXDESCS].qe_addr_hi = HIWORD(&sc->sc_pqedata->qc_recv[0]) | QE_VALID | QE_CHAIN; rp[RXDESCS].qe_flag = rp[RXDESCS].qe_status1 = QE_NOTYET; rp = sc->sc_qedata->qc_xmit; rp[TXDESCS].qe_addr_lo = LOWORD(&sc->sc_pqedata->qc_xmit[0]); rp[TXDESCS].qe_addr_hi = HIWORD(&sc->sc_pqedata->qc_xmit[0]) | QE_VALID | QE_CHAIN; rp[TXDESCS].qe_flag = rp[TXDESCS].qe_status1 = QE_NOTYET; /* * Get the vector that were set at match time, and remember it. */ sc->sc_intvec = ubasc->uh_lastiv; QE_WCSR(QE_CSR_CSR, QE_RESET); DELAY(1000); QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) & ~QE_RESET); /* * Read out ethernet address and tell which type this card is. */ for (i = 0; i < 6; i++) sc->sc_ac.ac_enaddr[i] = QE_RCSR(i * 2) & 0xff; QE_WCSR(QE_CSR_VECTOR, sc->sc_intvec | 1); printf(": %s, address %s\n", QE_RCSR(QE_CSR_VECTOR) & 1 ? "delqa" : "deqna", ether_sprintf(sc->sc_ac.ac_enaddr)); QE_WCSR(QE_CSR_VECTOR, QE_RCSR(QE_CSR_VECTOR) & ~1); /* ??? */ uba_intr_establish(ua->ua_icookie, ua->ua_cvec, qeintr, sc, &sc->sc_intrcnt); sc->sc_cvec = ua->ua_cvec; evcount_attach(&sc->sc_intrcnt, sc->sc_dev.dv_xname, &sc->sc_cvec); strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, sizeof ifp->if_xname); ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_start = qestart; ifp->if_ioctl = qeioctl; ifp->if_watchdog = qetimeout; IFQ_SET_READY(&ifp->if_snd); /* * Attach the interface. */ if_attach(ifp); ether_ifattach(ifp); return; /* * Free any resources we've allocated during the failed attach * attempt. Do this in reverse order and fall through. */ fail_6: for (i = 0; i < RXDESCS; i++) { if (sc->sc_rxmbuf[i] != NULL) { bus_dmamap_unload(sc->sc_dmat, sc->sc_xmtmap[i]); m_freem(sc->sc_rxmbuf[i]); } } fail_5: for (i = 0; i < RXDESCS; i++) { if (sc->sc_xmtmap[i] != NULL) bus_dmamap_destroy(sc->sc_dmat, sc->sc_xmtmap[i]); } fail_4: for (i = 0; i < TXDESCS; i++) { if (sc->sc_rcvmap[i] != NULL) bus_dmamap_destroy(sc->sc_dmat, sc->sc_rcvmap[i]); } }
void mpic_attach(struct device *parent, struct device *self, void *args) { struct mpic_softc *sc = (struct mpic_softc *)self; struct armv7_attach_args *aa = args; uint32_t main, mainsize, cpu, cpusize; struct fdt_memory mem; int i; mpic = sc; arm_init_smask(); if (fdt_get_memory_address(aa->aa_node, 0, &mem)) panic("%s: cannot extract main memory", sc->sc_dev.dv_xname); main = mem.addr; mainsize = mem.size; if (fdt_get_memory_address(aa->aa_node, 1, &mem)) panic("%s: cannot extract cpu memory", sc->sc_dev.dv_xname); cpu = mem.addr; cpusize = mem.size; if (fdt_node_property_int(aa->aa_node, "#interrupt-cells", &sc->sc_ncells) != 1) panic("%s: no #interrupt-cells property", sc->sc_dev.dv_xname); sc->sc_iot = aa->aa_iot; if (bus_space_map(sc->sc_iot, main, mainsize, 0, &sc->sc_m_ioh)) panic("%s: main bus_space_map failed!", __func__); if (bus_space_map(sc->sc_iot, cpu, cpusize, 0, &sc->sc_c_ioh)) panic("%s: cpu bus_space_map failed!", __func__); evcount_attach(&sc->sc_spur, "irq1023/spur", NULL); sc->sc_nintr = (bus_space_read_4(sc->sc_iot, sc->sc_m_ioh, MPIC_CTRL) >> 2) & 0x3ff; printf(" nirq %d\n", sc->sc_nintr); /* Disable all interrupts */ for (i = 0; i < sc->sc_nintr; i++) { bus_space_write_4(sc->sc_iot, sc->sc_m_ioh, MPIC_ICE, i); bus_space_write_4(sc->sc_iot, sc->sc_c_ioh, MPIC_ISM, i); } /* Clear pending IPIs */ bus_space_write_4(sc->sc_iot, sc->sc_c_ioh, MPIC_DOORBELL_CAUSE, 0); /* Enable hardware priorization selection */ bus_space_write_4(sc->sc_iot, sc->sc_m_ioh, MPIC_CTRL, MPIC_CTRL_PRIO_EN); sc->sc_mpic_handler = mallocarray(sc->sc_nintr, sizeof(*sc->sc_mpic_handler), M_DEVBUF, M_ZERO | M_NOWAIT); for (i = 0; i < sc->sc_nintr; i++) { TAILQ_INIT(&sc->sc_mpic_handler[i].is_list); } mpic_setipl(IPL_HIGH); /* XXX ??? */ mpic_calc_mask(); /* insert self as interrupt handler */ arm_set_intr_handler(mpic_splraise, mpic_spllower, mpic_splx, mpic_setipl, mpic_intr_establish, mpic_intr_disestablish, mpic_intr_string, mpic_irq_handler); arm_set_intr_handler_fdt(aa->aa_node, mpic_intr_establish_fdt_idx); /* enable interrupts */ intr_enable(); }
/* * Attach this instance, and then all the sub-devices */ static void asc_vsbus_attach(struct device *parent, struct device *self, void *aux) { struct vsbus_attach_args *va = aux; struct asc_vsbus_softc *asc = (void *)self; struct ncr53c9x_softc *sc = &asc->sc_ncr53c9x; int error; asc_attached = 1; /* * Set up glue for MI code early; we use some of it here. */ sc->sc_glue = &asc_vsbus_glue; asc->sc_bst = va->va_iot; asc->sc_dmat = va->va_dmat; error = bus_space_map(asc->sc_bst, va->va_paddr - ASC_REG_NCR, ASC_REG_END, 0, &asc->sc_bsh); if (error) { printf(": failed to map registers: error=%d\n", error); return; } error = bus_space_subregion(asc->sc_bst, asc->sc_bsh, ASC_REG_NCR, ASC_REG_END - ASC_REG_NCR, &asc->sc_ncrh); if (error) { printf(": failed to map ncr registers: error=%d\n", error); return; } if (vax_boardtype == VAX_BTYP_46 || vax_boardtype == VAX_BTYP_48) { error = bus_space_subregion(asc->sc_bst, asc->sc_bsh, ASC_REG_KA46_ADR, sizeof(u_int32_t), &asc->sc_adrh); if (error) { printf(": failed to map adr register: error=%d\n", error); return; } error = bus_space_subregion(asc->sc_bst, asc->sc_bsh, ASC_REG_KA46_DIR, sizeof(u_int32_t), &asc->sc_dirh); if (error) { printf(": failed to map dir register: error=%d\n", error); return; } } else { /* This is a gross and disgusting kludge but it'll * save a bunch of ugly code. Unlike the VS4000/60, * the SCSI Address and direction registers are not * near the SCSI NCR registers and are inside the * block of general VAXstation registers. So we grab * them from there and knowing the internals of the * bus_space implementation, we cast to bus_space_handles. */ struct vsbus_softc *vsc = (struct vsbus_softc *) parent; asc->sc_adrh = (bus_space_handle_t) (vsc->sc_vsregs + ASC_REG_KA49_ADR); asc->sc_dirh = (bus_space_handle_t) (vsc->sc_vsregs + ASC_REG_KA49_DIR); #if 0 printf("\n%s: adrh=0x%08lx dirh=0x%08lx", self->dv_xname, asc->sc_adrh, asc->sc_dirh); ncr53c9x_debug = NCR_SHOWDMA|NCR_SHOWINTS|NCR_SHOWCMDS|NCR_SHOWPHASE|NCR_SHOWSTART|NCR_SHOWMSGS; #endif } error = bus_dmamap_create(asc->sc_dmat, ASC_MAXXFERSIZE, 1, ASC_MAXXFERSIZE, 0, BUS_DMA_NOWAIT, &asc->sc_dmamap); switch (vax_boardtype) { #if defined(VAX46) case VAX_BTYP_46: sc->sc_id = (clk_page[0xbc/2] >> clk_tweak) & 7; break; #endif default: sc->sc_id = 6; /* XXX need to get this from VMB */ break; } sc->sc_freq = ASC_FREQUENCY; /* gimme MHz */ sc->sc_freq /= 1000000; scb_vecalloc(va->va_cvec, (void (*)(void *)) ncr53c9x_intr, &asc->sc_ncr53c9x, SCB_ISTACK, &asc->sc_intrcnt); asc->sc_cvec = va->va_cvec; evcount_attach(&asc->sc_intrcnt, self->dv_xname, (void *)&asc->sc_cvec, &evcount_intr); /* * XXX More of this should be in ncr53c9x_attach(), but * XXX should we really poke around the chip that much in * XXX the MI code? Think about this more... */ /* * Set up static configuration info. */ sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB; sc->sc_cfg2 = NCRCFG2_SCSI2; sc->sc_cfg3 = 0; sc->sc_rev = NCR_VARIANT_NCR53C94; /* * XXX minsync and maxxfer _should_ be set up in MI code, * XXX but it appears to have some dependency on what sort * XXX of DMA we're hooked up to, etc. */ /* * This is the value used to start sync negotiations * Note that the NCR register "SYNCTP" is programmed * in "clocks per byte", and has a minimum value of 4. * The SCSI period used in negotiation is one-fourth * of the time (in nanoseconds) needed to transfer one byte. * Since the chip's clock is given in MHz, we have the following * formula: 4 * period = (1000 / freq) * 4 */ sc->sc_minsync = (1000 / sc->sc_freq); sc->sc_maxxfer = 64 * 1024; /* Do the common parts of attachment. */ ncr53c9x_attach(sc, &asc_vsbus_ops, &asc_vsbus_dev); }