Index: stable/12/sys/mips/ingenic/jz4780_timer.c =================================================================== --- stable/12/sys/mips/ingenic/jz4780_timer.c (revision 343708) +++ stable/12/sys/mips/ingenic/jz4780_timer.c (revision 343709) @@ -1,339 +1,339 @@ /*- * Copyright 2013-2015 Alexander Kabaev * Copyright 2013-2015 John Wehle * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct jz4780_timer_softc { device_t dev; struct resource * res[4]; void * ih_cookie; struct eventtimer et; struct timecounter tc; }; static struct resource_spec jz4780_timer_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, /* OST */ { SYS_RES_IRQ, 1, RF_ACTIVE }, /* TC5 */ { SYS_RES_IRQ, 2, RF_ACTIVE }, /* TC0-4,6 */ { -1, 0 } }; /* * devclass_get_device / device_get_softc could be used * to dynamically locate this, however the timers are a * required device which can't be unloaded so there's * no need for the overhead. */ static struct jz4780_timer_softc *jz4780_timer_sc = NULL; #define CSR_WRITE_4(sc, reg, val) bus_write_4((sc)->res[0], reg, (val)) #define CSR_READ_4(sc, reg) bus_read_4((sc)->res[0], reg) static unsigned jz4780_get_timecount(struct timecounter *tc) { struct jz4780_timer_softc *sc = (struct jz4780_timer_softc *)tc->tc_priv; return CSR_READ_4(sc, JZ_OST_CNT_LO); } static int jz4780_hardclock(void *arg) { struct jz4780_timer_softc *sc = (struct jz4780_timer_softc *)arg; CSR_WRITE_4(sc, JZ_TC_TFCR, TFR_FFLAG5); CSR_WRITE_4(sc, JZ_TC_TECR, TESR_TCST5); if (sc->et.et_active) sc->et.et_event_cb(&sc->et, sc->et.et_arg); return (FILTER_HANDLED); } static int jz4780_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { struct jz4780_timer_softc *sc = (struct jz4780_timer_softc *)et->et_priv; uint32_t ticks; ticks = (first * et->et_frequency) / SBT_1S; if (ticks == 0) return (EINVAL); CSR_WRITE_4(sc, JZ_TC_TDFR(5), ticks); CSR_WRITE_4(sc, JZ_TC_TCNT(5), 0); CSR_WRITE_4(sc, JZ_TC_TESR, TESR_TCST5); return (0); } static int jz4780_timer_stop(struct eventtimer *et) { struct jz4780_timer_softc *sc = (struct jz4780_timer_softc *)et->et_priv; CSR_WRITE_4(sc, JZ_TC_TECR, TESR_TCST5); return (0); } static int jz4780_timer_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-tcu")) return (ENXIO); device_set_desc(dev, "Ingenic JZ4780 timer"); return (BUS_PROBE_DEFAULT); } static int jz4780_timer_attach(device_t dev) { struct jz4780_timer_softc *sc = device_get_softc(dev); pcell_t counter_freq; clk_t clk; /* There should be exactly one instance. */ if (jz4780_timer_sc != NULL) return (ENXIO); sc->dev = dev; if (bus_alloc_resources(dev, jz4780_timer_spec, sc->res)) { device_printf(dev, "can not allocate resources for device\n"); return (ENXIO); } counter_freq = 0; if (clk_get_by_name(dev, "ext", &clk) == 0) { uint64_t clk_freq; if (clk_get_freq(clk, &clk_freq) == 0) counter_freq = (uint32_t)clk_freq / 16; clk_release(clk); } if (counter_freq == 0) { device_printf(dev, "unable to determine ext clock frequency\n"); /* Hardcode value we 'know' is correct */ counter_freq = 48000000 / 16; } /* * Disable the timers, select the input for each timer, * clear and then start OST. */ /* Stop OST, if it happens to be running */ CSR_WRITE_4(sc, JZ_TC_TECR, TESR_OST); /* Stop all other channels as well */ CSR_WRITE_4(sc, JZ_TC_TECR, TESR_TCST0 | TESR_TCST1 | TESR_TCST2 | - TESR_TCST3 | TESR_TCST4 | TESR_TCST5 | TESR_TCST6 | TESR_TCST3); + TESR_TCST3 | TESR_TCST4 | TESR_TCST5 | TESR_TCST6 | TESR_TCST7); /* Clear detect mask flags */ CSR_WRITE_4(sc, JZ_TC_TFCR, 0xFFFFFFFF); /* Mask all interrupts */ CSR_WRITE_4(sc, JZ_TC_TMSR, 0xFFFFFFFF); /* Init counter with known data */ CSR_WRITE_4(sc, JZ_OST_CTRL, 0); CSR_WRITE_4(sc, JZ_OST_CNT_LO, 0); CSR_WRITE_4(sc, JZ_OST_CNT_HI, 0); CSR_WRITE_4(sc, JZ_OST_DATA, 0xffffffff); /* Configure counter for external clock */ CSR_WRITE_4(sc, JZ_OST_CTRL, OSTC_EXT_EN | OSTC_MODE | OSTC_DIV_16); /* Start the counter again */ CSR_WRITE_4(sc, JZ_TC_TESR, TESR_OST); /* Configure TCU channel 5 similarly to OST and leave it disabled */ CSR_WRITE_4(sc, JZ_TC_TCSR(5), TCSR_EXT_EN | TCSR_DIV_16); CSR_WRITE_4(sc, JZ_TC_TMCR, TMR_FMASK(5)); if (bus_setup_intr(dev, sc->res[2], INTR_TYPE_CLK, jz4780_hardclock, NULL, sc, &sc->ih_cookie)) { device_printf(dev, "could not setup interrupt handler\n"); bus_release_resources(dev, jz4780_timer_spec, sc->res); return (ENXIO); } sc->et.et_name = "JZ4780 TCU5"; sc->et.et_flags = ET_FLAGS_ONESHOT; sc->et.et_frequency = counter_freq; sc->et.et_quality = 1000; sc->et.et_min_period = (0x00000002LLU * SBT_1S) / sc->et.et_frequency; sc->et.et_max_period = (0x0000fffeLLU * SBT_1S) / sc->et.et_frequency; sc->et.et_start = jz4780_timer_start; sc->et.et_stop = jz4780_timer_stop; sc->et.et_priv = sc; et_register(&sc->et); sc->tc.tc_get_timecount = jz4780_get_timecount; sc->tc.tc_name = "JZ4780 OST"; sc->tc.tc_frequency = counter_freq; sc->tc.tc_counter_mask = ~0u; sc->tc.tc_quality = 1000; sc->tc.tc_priv = sc; tc_init(&sc->tc); /* Now when tc is initialized, allow DELAY to find it */ jz4780_timer_sc = sc; return (0); } static int jz4780_timer_detach(device_t dev) { return (EBUSY); } static device_method_t jz4780_timer_methods[] = { /* Device interface */ DEVMETHOD(device_probe, jz4780_timer_probe), DEVMETHOD(device_attach, jz4780_timer_attach), DEVMETHOD(device_detach, jz4780_timer_detach), DEVMETHOD_END }; static driver_t jz4780_timer_driver = { "timer", jz4780_timer_methods, sizeof(struct jz4780_timer_softc), }; static devclass_t jz4780_timer_devclass; EARLY_DRIVER_MODULE(timer, simplebus, jz4780_timer_driver, jz4780_timer_devclass, 0, 0, BUS_PASS_TIMER); void DELAY(int usec) { uint32_t counter; uint32_t delta, now, previous, remaining; /* Timer has not yet been initialized */ if (jz4780_timer_sc == NULL) { for (; usec > 0; usec--) for (counter = 200; counter > 0; counter--) { /* Prevent gcc from optimizing out the loop */ mips_rd_cause(); } return; } TSENTER(); /* * Some of the other timers in the source tree do this calculation as: * * usec * ((sc->tc.tc_frequency / 1000000) + 1) * * which gives a fairly pessimistic result when tc_frequency is an exact * multiple of 1000000. Given the data type and typical values for * tc_frequency adding 999999 shouldn't overflow. */ remaining = usec * ((jz4780_timer_sc->tc.tc_frequency + 999999) / 1000000); /* * We add one since the first iteration may catch the counter just * as it is changing. */ remaining += 1; previous = jz4780_get_timecount(&jz4780_timer_sc->tc); for ( ; ; ) { now = jz4780_get_timecount(&jz4780_timer_sc->tc); /* * If the timer has rolled over, then we have the case: * * if (previous > now) { * delta = (0 - previous) + now * } * * which is really no different then the normal case. * Both cases are simply: * * delta = now - previous. */ delta = now - previous; if (delta >= remaining) break; previous = now; remaining -= delta; } TSEXIT(); } void platform_initclocks(void) { } Index: stable/12/sys/mips/mips/tlb.c =================================================================== --- stable/12/sys/mips/mips/tlb.c (revision 343708) +++ stable/12/sys/mips/mips/tlb.c (revision 343709) @@ -1,389 +1,389 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2004-2010 Juli Mallett * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include "opt_ddb.h" #include #include #include #include #include #include #include #include #include #if defined(CPU_CNMIPS) #define MIPS_MAX_TLB_ENTRIES 128 #elif defined(CPU_NLM) #define MIPS_MAX_TLB_ENTRIES (2048 + 128) #else #define MIPS_MAX_TLB_ENTRIES 64 #endif struct tlb_state { unsigned wired; struct tlb_entry { register_t entryhi; register_t entrylo0; register_t entrylo1; register_t pagemask; } entry[MIPS_MAX_TLB_ENTRIES]; }; static struct tlb_state tlb_state[MAXCPU]; #if 0 /* * PageMask must increment in steps of 2 bits. */ COMPILE_TIME_ASSERT(POPCNT(TLBMASK_MASK) % 2 == 0); #endif static inline void tlb_probe(void) { __asm __volatile ("tlbp" : : : "memory"); mips_cp0_sync(); } static inline void tlb_read(void) { __asm __volatile ("tlbr" : : : "memory"); mips_cp0_sync(); } static inline void tlb_write_indexed(void) { __asm __volatile ("tlbwi" : : : "memory"); mips_cp0_sync(); } static void tlb_invalidate_one(unsigned); void tlb_insert_wired(unsigned i, vm_offset_t va, pt_entry_t pte0, pt_entry_t pte1) { register_t asid; register_t s; va &= ~PAGE_MASK; s = intr_disable(); asid = mips_rd_entryhi() & TLBHI_ASID_MASK; mips_wr_index(i); mips_wr_pagemask(0); mips_wr_entryhi(TLBHI_ENTRY(va, 0)); mips_wr_entrylo0(pte0); mips_wr_entrylo1(pte1); tlb_write_indexed(); mips_wr_entryhi(asid); intr_restore(s); } void tlb_invalidate_address(struct pmap *pmap, vm_offset_t va) { register_t asid; register_t s; int i; va &= ~PAGE_MASK; s = intr_disable(); asid = mips_rd_entryhi() & TLBHI_ASID_MASK; mips_wr_pagemask(0); mips_wr_entryhi(TLBHI_ENTRY(va, pmap_asid(pmap))); tlb_probe(); i = mips_rd_index(); if (i >= 0) tlb_invalidate_one(i); mips_wr_entryhi(asid); intr_restore(s); } void tlb_invalidate_all(void) { register_t asid; register_t s; unsigned i; s = intr_disable(); asid = mips_rd_entryhi() & TLBHI_ASID_MASK; for (i = mips_rd_wired(); i < num_tlbentries; i++) tlb_invalidate_one(i); mips_wr_entryhi(asid); intr_restore(s); } void tlb_invalidate_all_user(struct pmap *pmap) { register_t asid; register_t s; unsigned i; s = intr_disable(); asid = mips_rd_entryhi() & TLBHI_ASID_MASK; for (i = mips_rd_wired(); i < num_tlbentries; i++) { register_t uasid; mips_wr_index(i); tlb_read(); uasid = mips_rd_entryhi() & TLBHI_ASID_MASK; if (pmap == NULL) { /* * Invalidate all non-kernel entries. */ if (uasid == 0) continue; } else { /* * Invalidate this pmap's entries. */ if (uasid != pmap_asid(pmap)) continue; } tlb_invalidate_one(i); } mips_wr_entryhi(asid); intr_restore(s); } /* * Invalidates any TLB entries that map a virtual page from the specified * address range. If "end" is zero, then every virtual page is considered to * be within the address range's upper bound. */ void tlb_invalidate_range(pmap_t pmap, vm_offset_t start, vm_offset_t end) { register_t asid, end_hi, hi, hi_pagemask, s, save_asid, start_hi; int i; KASSERT(start < end || (end == 0 && start > 0), ("tlb_invalidate_range: invalid range")); /* * Truncate the virtual address "start" to an even page frame number, * and round the virtual address "end" to an even page frame number. */ start &= ~((1 << TLBMASK_SHIFT) - 1); end = roundup2(end, 1 << TLBMASK_SHIFT); s = intr_disable(); save_asid = mips_rd_entryhi() & TLBHI_ASID_MASK; asid = pmap_asid(pmap); start_hi = TLBHI_ENTRY(start, asid); end_hi = TLBHI_ENTRY(end, asid); /* * Select the fastest method for invalidating the TLB entries. */ if (end - start < num_tlbentries << TLBMASK_SHIFT || (end == 0 && start >= -(num_tlbentries << TLBMASK_SHIFT))) { /* * The virtual address range is small compared to the size of * the TLB. Probe the TLB for each even numbered page frame * within the virtual address range. */ for (hi = start_hi; hi != end_hi; hi += 1 << TLBMASK_SHIFT) { mips_wr_pagemask(0); mips_wr_entryhi(hi); tlb_probe(); i = mips_rd_index(); if (i >= 0) tlb_invalidate_one(i); } } else { /* * The virtual address range is large compared to the size of * the TLB. Test every non-wired TLB entry. */ for (i = mips_rd_wired(); i < num_tlbentries; i++) { mips_wr_index(i); tlb_read(); hi = mips_rd_entryhi(); if ((hi & TLBHI_ASID_MASK) == asid && (hi < end_hi || end == 0)) { /* * If "hi" is a large page that spans * "start_hi", then it must be invalidated. */ hi_pagemask = mips_rd_pagemask(); if (hi >= (start_hi & ~(hi_pagemask << TLBMASK_SHIFT))) tlb_invalidate_one(i); } } } mips_wr_entryhi(save_asid); intr_restore(s); } /* XXX Only if DDB? */ void tlb_save(void) { unsigned ntlb, i, cpu; cpu = PCPU_GET(cpuid); if (num_tlbentries > MIPS_MAX_TLB_ENTRIES) ntlb = MIPS_MAX_TLB_ENTRIES; else ntlb = num_tlbentries; tlb_state[cpu].wired = mips_rd_wired(); for (i = 0; i < ntlb; i++) { mips_wr_index(i); tlb_read(); tlb_state[cpu].entry[i].entryhi = mips_rd_entryhi(); tlb_state[cpu].entry[i].pagemask = mips_rd_pagemask(); tlb_state[cpu].entry[i].entrylo0 = mips_rd_entrylo0(); tlb_state[cpu].entry[i].entrylo1 = mips_rd_entrylo1(); } } void tlb_update(struct pmap *pmap, vm_offset_t va, pt_entry_t pte) { register_t asid; register_t s; int i; va &= ~PAGE_MASK; pte &= ~TLBLO_SWBITS_MASK; s = intr_disable(); asid = mips_rd_entryhi() & TLBHI_ASID_MASK; mips_wr_pagemask(0); mips_wr_entryhi(TLBHI_ENTRY(va, pmap_asid(pmap))); tlb_probe(); i = mips_rd_index(); if (i >= 0) { tlb_read(); if ((va & PAGE_SIZE) == 0) { mips_wr_entrylo0(pte); } else { mips_wr_entrylo1(pte); } tlb_write_indexed(); } mips_wr_entryhi(asid); intr_restore(s); } static void tlb_invalidate_one(unsigned i) { /* XXX an invalid ASID? */ mips_wr_entryhi(TLBHI_ENTRY(MIPS_KSEG0_START + (2 * i * PAGE_SIZE), 0)); mips_wr_entrylo0(0); mips_wr_entrylo1(0); mips_wr_pagemask(0); mips_wr_index(i); tlb_write_indexed(); } #ifdef DDB #include DB_SHOW_COMMAND(tlb, ddb_dump_tlb) { register_t ehi, elo0, elo1, epagemask; unsigned i, cpu, ntlb; /* * XXX * The worst conversion from hex to decimal ever. */ if (have_addr) cpu = ((addr >> 4) % 16) * 10 + (addr % 16); else cpu = PCPU_GET(cpuid); - if (cpu < 0 || cpu >= mp_ncpus) { + if (cpu >= mp_ncpus) { db_printf("Invalid CPU %u\n", cpu); return; } if (num_tlbentries > MIPS_MAX_TLB_ENTRIES) { ntlb = MIPS_MAX_TLB_ENTRIES; db_printf("Warning: Only %d of %d TLB entries saved!\n", ntlb, num_tlbentries); } else ntlb = num_tlbentries; if (cpu == PCPU_GET(cpuid)) tlb_save(); db_printf("Beginning TLB dump for CPU %u...\n", cpu); for (i = 0; i < ntlb; i++) { if (i == tlb_state[cpu].wired) { if (i != 0) db_printf("^^^ WIRED ENTRIES ^^^\n"); else db_printf("(No wired entries.)\n"); } /* XXX PageMask. */ ehi = tlb_state[cpu].entry[i].entryhi; elo0 = tlb_state[cpu].entry[i].entrylo0; elo1 = tlb_state[cpu].entry[i].entrylo1; epagemask = tlb_state[cpu].entry[i].pagemask; if (elo0 == 0 && elo1 == 0) continue; db_printf("#%u\t=> %jx (pagemask %jx)\n", i, (intmax_t)ehi, (intmax_t) epagemask); db_printf(" Lo0\t%jx\t(%#jx)\n", (intmax_t)elo0, (intmax_t)TLBLO_PTE_TO_PA(elo0)); db_printf(" Lo1\t%jx\t(%#jx)\n", (intmax_t)elo1, (intmax_t)TLBLO_PTE_TO_PA(elo1)); } db_printf("Finished.\n"); } #endif Index: stable/12/sys/mips/nlm/cms.c =================================================================== --- stable/12/sys/mips/nlm/cms.c (revision 343708) +++ stable/12/sys/mips/nlm/cms.c (revision 343709) @@ -1,498 +1,498 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 2003-2011 Netlogic Microsystems (Netlogic). All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY Netlogic Microsystems ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * NETLOGIC_BSD */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MSGRNG_NSTATIONS 1024 /* * Keep track of our message ring handler threads, each core has a * different message station. Ideally we will need to start a few * message handling threads every core, and wake them up depending on * load */ struct msgring_thread { struct thread *thread; /* msgring handler threads */ int needed; /* thread needs to wake up */ }; static struct msgring_thread msgring_threads[XLP_MAX_CORES * XLP_MAX_THREADS]; static struct proc *msgring_proc; /* all threads are under a proc */ /* * The device drivers can register a handler for the messages sent * from a station (corresponding to the device). */ struct tx_stn_handler { msgring_handler action; void *arg; }; static struct tx_stn_handler msgmap[MSGRNG_NSTATIONS]; static struct mtx msgmap_lock; uint32_t xlp_msg_thread_mask; static int xlp_msg_threads_per_core = XLP_MAX_THREADS; static void create_msgring_thread(int hwtid); static int msgring_process_fast_intr(void *arg); /* Debug counters */ static int msgring_nintr[XLP_MAX_CORES * XLP_MAX_THREADS]; static int msgring_wakeup_sleep[XLP_MAX_CORES * XLP_MAX_THREADS]; static int msgring_wakeup_nosleep[XLP_MAX_CORES * XLP_MAX_THREADS]; static int fmn_msgcount[XLP_MAX_CORES * XLP_MAX_THREADS][4]; static int fmn_loops[XLP_MAX_CORES * XLP_MAX_THREADS]; /* Whether polled driver implementation */ static int polled = 0; /* We do only i/o device credit setup here. CPU credit setup is now * moved to xlp_msgring_cpu_init() so that the credits get setup * only if the CPU exists. xlp_msgring_cpu_init() gets called from * platform_init_ap; and this makes it easy for us to setup CMS * credits for various types of XLP chips, with varying number of * cpu's and cores. */ static void xlp_cms_credit_setup(int credit) { uint64_t cmspcibase, cmsbase, pcibase; uint32_t devoffset; int dev, fn, maxqid; int src, qid, i; for (i = 0; i < XLP_MAX_NODES; i++) { cmspcibase = nlm_get_cms_pcibase(i); if (!nlm_dev_exists(XLP_IO_CMS_OFFSET(i))) continue; cmsbase = nlm_get_cms_regbase(i); maxqid = nlm_read_reg(cmspcibase, XLP_PCI_DEVINFO_REG0); for (dev = 0; dev < 8; dev++) { for (fn = 0; fn < 8; fn++) { devoffset = XLP_HDR_OFFSET(i, 0, dev, fn); if (nlm_dev_exists(devoffset) == 0) continue; pcibase = nlm_pcicfg_base(devoffset); src = nlm_qidstart(pcibase); if (src == 0) continue; #if 0 /* Debug */ printf("Setup CMS credits for queues "); printf("[%d to %d] from src %d\n", 0, maxqid, src); #endif for (qid = 0; qid < maxqid; qid++) nlm_cms_setup_credits(cmsbase, qid, src, credit); } } } } void xlp_msgring_cpu_init(int node, int cpu, int credit) { uint64_t cmspcibase = nlm_get_cms_pcibase(node); uint64_t cmsbase = nlm_get_cms_regbase(node); int qid, maxqid, src; maxqid = nlm_read_reg(cmspcibase, XLP_PCI_DEVINFO_REG0); /* cpu credit setup is done only from thread-0 of each core */ if((cpu % 4) == 0) { src = cpu << 2; /* each thread has 4 vc's */ for (qid = 0; qid < maxqid; qid++) nlm_cms_setup_credits(cmsbase, qid, src, credit); } } /* * Drain out max_messages for the buckets set in the bucket mask. * Use max_msgs = 0 to drain out all messages. */ int xlp_handle_msg_vc(u_int vcmask, int max_msgs) { struct nlm_fmn_msg msg; int srcid = 0, size = 0, code = 0; struct tx_stn_handler *he; uint32_t mflags, status; int n_msgs = 0, vc, m, hwtid; u_int msgmask; hwtid = nlm_cpuid(); for (;;) { /* check if VC empty */ mflags = nlm_save_flags_cop2(); status = nlm_read_c2_msgstatus1(); nlm_restore_flags(mflags); msgmask = ((status >> 24) & 0xf) ^ 0xf; msgmask &= vcmask; if (msgmask == 0) break; m = 0; for (vc = 0; vc < 4; vc++) { if ((msgmask & (1 << vc)) == 0) continue; mflags = nlm_save_flags_cop2(); status = nlm_fmn_msgrcv(vc, &srcid, &size, &code, &msg); nlm_restore_flags(mflags); if (status != 0) /* no msg or error */ continue; - if (srcid < 0 && srcid >= 1024) { + if (srcid < 0 || srcid >= 1024) { printf("[%s]: bad src id %d\n", __func__, srcid); continue; } he = &msgmap[srcid]; if(he->action != NULL) (he->action)(vc, size, code, srcid, &msg, he->arg); #if 0 else printf("[%s]: No Handler for msg from stn %d," " vc=%d, size=%d, msg0=%jx, droppinge\n", __func__, srcid, vc, size, (uintmax_t)msg.msg[0]); #endif fmn_msgcount[hwtid][vc] += 1; m++; /* msgs handled in this iter */ } if (m == 0) break; /* nothing done in this iter */ n_msgs += m; if (max_msgs > 0 && n_msgs >= max_msgs) break; } return (n_msgs); } static void xlp_discard_msg_vc(u_int vcmask) { struct nlm_fmn_msg msg; int srcid = 0, size = 0, code = 0, vc; uint32_t mflags, status; for (vc = 0; vc < 4; vc++) { for (;;) { mflags = nlm_save_flags_cop2(); status = nlm_fmn_msgrcv(vc, &srcid, &size, &code, &msg); nlm_restore_flags(mflags); /* break if there is no msg or error */ if (status != 0) break; } } } void xlp_cms_enable_intr(int node, int cpu, int type, int watermark) { uint64_t cmsbase; int i, qid; cmsbase = nlm_get_cms_regbase(node); for (i = 0; i < 4; i++) { qid = (i + (cpu * 4)) & 0x7f; nlm_cms_per_queue_level_intr(cmsbase, qid, type, watermark); nlm_cms_per_queue_timer_intr(cmsbase, qid, 0x1, 0); } } static int msgring_process_fast_intr(void *arg) { struct msgring_thread *mthd; struct thread *td; int cpu; cpu = nlm_cpuid(); mthd = &msgring_threads[cpu]; msgring_nintr[cpu]++; td = mthd->thread; /* clear pending interrupts */ nlm_write_c0_eirr(1ULL << IRQ_MSGRING); /* wake up the target thread */ mthd->needed = 1; thread_lock(td); if (TD_AWAITING_INTR(td)) { msgring_wakeup_sleep[cpu]++; TD_CLR_IWAIT(td); sched_add(td, SRQ_INTR); } else msgring_wakeup_nosleep[cpu]++; thread_unlock(td); return (FILTER_HANDLED); } static void msgring_process(void * arg) { volatile struct msgring_thread *mthd; struct thread *td; uint32_t mflags, msgstatus1; int hwtid, nmsgs; hwtid = (intptr_t)arg; mthd = &msgring_threads[hwtid]; td = mthd->thread; KASSERT(curthread == td, ("%s:msg_ithread and proc linkage out of sync", __func__)); /* First bind this thread to the right CPU */ thread_lock(td); sched_bind(td, xlp_hwtid_to_cpuid[hwtid]); thread_unlock(td); if (hwtid != nlm_cpuid()) printf("Misscheduled hwtid %d != cpuid %d\n", hwtid, nlm_cpuid()); xlp_discard_msg_vc(0xf); xlp_msgring_cpu_init(nlm_nodeid(), nlm_cpuid(), CMS_DEFAULT_CREDIT); if (polled == 0) { mflags = nlm_save_flags_cop2(); nlm_fmn_cpu_init(IRQ_MSGRING, 0, 0, 0, 0, 0); nlm_restore_flags(mflags); xlp_cms_enable_intr(nlm_nodeid(), nlm_cpuid(), 0x2, 0); /* clear pending interrupts. * they will get re-raised if still valid */ nlm_write_c0_eirr(1ULL << IRQ_MSGRING); } /* start processing messages */ for (;;) { atomic_store_rel_int(&mthd->needed, 0); nmsgs = xlp_handle_msg_vc(0xf, 0); /* sleep */ if (polled == 0) { /* clear VC-pend bits */ mflags = nlm_save_flags_cop2(); msgstatus1 = nlm_read_c2_msgstatus1(); msgstatus1 |= (0xf << 16); nlm_write_c2_msgstatus1(msgstatus1); nlm_restore_flags(mflags); thread_lock(td); if (mthd->needed) { thread_unlock(td); continue; } sched_class(td, PRI_ITHD); TD_SET_IWAIT(td); mi_switch(SW_VOL, NULL); thread_unlock(td); } else pause("wmsg", 1); fmn_loops[hwtid]++; } } static void create_msgring_thread(int hwtid) { struct msgring_thread *mthd; struct thread *td; int error; mthd = &msgring_threads[hwtid]; error = kproc_kthread_add(msgring_process, (void *)(uintptr_t)hwtid, &msgring_proc, &td, RFSTOPPED, 2, "msgrngproc", "msgthr%d", hwtid); if (error) panic("kproc_kthread_add() failed with %d", error); mthd->thread = td; thread_lock(td); sched_class(td, PRI_ITHD); sched_add(td, SRQ_INTR); thread_unlock(td); } int register_msgring_handler(int startb, int endb, msgring_handler action, void *arg) { int i; if (bootverbose) printf("Register handler %d-%d %p(%p)\n", startb, endb, action, arg); KASSERT(startb >= 0 && startb <= endb && endb < MSGRNG_NSTATIONS, ("Invalid value for bucket range %d,%d", startb, endb)); mtx_lock_spin(&msgmap_lock); for (i = startb; i <= endb; i++) { KASSERT(msgmap[i].action == NULL, ("Bucket %d already used [action %p]", i, msgmap[i].action)); msgmap[i].action = action; msgmap[i].arg = arg; } mtx_unlock_spin(&msgmap_lock); return (0); } /* * Initialize the messaging subsystem. * * Message Stations are shared among all threads in a cpu core, this * has to be called once from every core which is online. */ static void xlp_msgring_config(void *arg) { void *cookie; unsigned int thrmask, mask; int i; /* used polled handler for Ax silion */ if (nlm_is_xlp8xx_ax()) polled = 1; /* Don't poll on all threads, if polled */ if (polled) xlp_msg_threads_per_core -= 1; mtx_init(&msgmap_lock, "msgring", NULL, MTX_SPIN); if (xlp_threads_per_core < xlp_msg_threads_per_core) xlp_msg_threads_per_core = xlp_threads_per_core; thrmask = ((1 << xlp_msg_threads_per_core) - 1); mask = 0; for (i = 0; i < XLP_MAX_CORES; i++) { mask <<= XLP_MAX_THREADS; mask |= thrmask; } xlp_msg_thread_mask = xlp_hw_thread_mask & mask; #if 0 printf("CMS Message handler thread mask %#jx\n", (uintmax_t)xlp_msg_thread_mask); #endif xlp_cms_credit_setup(CMS_DEFAULT_CREDIT); create_msgring_thread(0); cpu_establish_hardintr("msgring", msgring_process_fast_intr, NULL, NULL, IRQ_MSGRING, INTR_TYPE_NET, &cookie); } /* * Start message ring processing threads on other CPUs, after SMP start */ static void start_msgring_threads(void *arg) { int hwt; for (hwt = 1; hwt < XLP_MAX_CORES * XLP_MAX_THREADS; hwt++) { if ((xlp_msg_thread_mask & (1 << hwt)) == 0) continue; create_msgring_thread(hwt); } } SYSINIT(xlp_msgring_config, SI_SUB_DRIVERS, SI_ORDER_FIRST, xlp_msgring_config, NULL); SYSINIT(start_msgring_threads, SI_SUB_SMP, SI_ORDER_MIDDLE, start_msgring_threads, NULL); /* * DEBUG support, XXX: static buffer, not locked */ static int sys_print_debug(SYSCTL_HANDLER_ARGS) { struct sbuf sb; int error, i; sbuf_new_for_sysctl(&sb, NULL, 64, req); sbuf_printf(&sb, "\nID vc0 vc1 vc2 vc3 loops\n"); for (i = 0; i < 32; i++) { if ((xlp_hw_thread_mask & (1 << i)) == 0) continue; sbuf_printf(&sb, "%2d: %8d %8d %8d %8d %8d\n", i, fmn_msgcount[i][0], fmn_msgcount[i][1], fmn_msgcount[i][2], fmn_msgcount[i][3], fmn_loops[i]); } error = sbuf_finish(&sb); sbuf_delete(&sb); return (error); } SYSCTL_PROC(_debug, OID_AUTO, msgring, CTLTYPE_STRING | CTLFLAG_RD, 0, 0, sys_print_debug, "A", "msgring debug info"); Index: stable/12/sys/mips/nlm/usb_init.c =================================================================== --- stable/12/sys/mips/nlm/usb_init.c (revision 343708) +++ stable/12/sys/mips/nlm/usb_init.c (revision 343709) @@ -1,93 +1,92 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 2003-2011 Netlogic Microsystems (Netlogic). All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY Netlogic Microsystems ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * NETLOGIC_BSD */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include static void nlm_usb_intr_en(int node, int port) { uint32_t val; uint64_t port_addr; port_addr = nlm_get_usb_regbase(node, port); val = nlm_read_usb_reg(port_addr, USB_INT_EN); val = USB_CTRL_INTERRUPT_EN | USB_OHCI_INTERRUPT_EN | - USB_OHCI_INTERRUPT1_EN | USB_CTRL_INTERRUPT_EN | - USB_OHCI_INTERRUPT_EN | USB_OHCI_INTERRUPT2_EN; + USB_OHCI_INTERRUPT1_EN | USB_OHCI_INTERRUPT2_EN; nlm_write_usb_reg(port_addr, USB_INT_EN, val); } static void nlm_usb_hw_reset(int node, int port) { uint64_t port_addr; uint32_t val; /* reset USB phy */ port_addr = nlm_get_usb_regbase(node, port); val = nlm_read_usb_reg(port_addr, USB_PHY_0); val &= ~(USB_PHY_RESET | USB_PHY_PORT_RESET_0 | USB_PHY_PORT_RESET_1); nlm_write_usb_reg(port_addr, USB_PHY_0, val); DELAY(100); val = nlm_read_usb_reg(port_addr, USB_CTL_0); val &= ~(USB_CONTROLLER_RESET); val |= 0x4; nlm_write_usb_reg(port_addr, USB_CTL_0, val); } static void nlm_usb_init(void) { /* XXX: should be checking if these are in Device mode here */ printf("Initialize USB Interface\n"); nlm_usb_hw_reset(0, 0); nlm_usb_hw_reset(0, 3); /* Enable PHY interrupts */ nlm_usb_intr_en(0, 0); nlm_usb_intr_en(0, 3); } SYSINIT(nlm_usb_init, SI_SUB_CPU, SI_ORDER_MIDDLE, nlm_usb_init, NULL); Index: stable/12 =================================================================== --- stable/12 (revision 343708) +++ stable/12 (revision 343709) Property changes on: stable/12 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r343443,343446,343448,343452